Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions .distignore
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
# Files that must not ship in the WordPress.org package.
# Honoured by `wp dist-archive` and the 10up/action-wordpress-plugin-deploy action.
# The single source of truth for what ships to WordPress.org.
#
# Honoured by `npm run package` (bin/package.mjs) and by the deploy workflow's
# 10up/action-wordpress-plugin-deploy step, so a local build and a published
# release contain exactly the same files. Do not add a second exclude list.

.git
.github
.gitignore
.distignore
.DS_Store
.sass-cache
node_modules
vendor
build

# Development notes, not product documentation.
# Development notes and tooling, not product documentation.
CLAUDE.md
.claude
bin
package.json
package-lock.json
composer.json
composer.lock
phpcs.xml.dist
phpcs.xml
.editorconfig

# Source maps are never shipped.
*.map
103 changes: 103 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
name: CI

on:
push:
branches: [ master ]
pull_request:
workflow_dispatch:

permissions:
contents: read

jobs:
php-lint:
name: PHP ${{ matrix.php }} syntax
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# Floor is the plugin's "Requires PHP"; ceiling is the newest release, which
# is where the PHP 8 breakage fixed in 3.4.0 would have shown up first.
php: [ '7.4', '8.0', '8.2', '8.4', '8.5' ]
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
coverage: none
- name: Lint every PHP file
run: |
find . -path ./vendor -prune -o -path ./node_modules -prune -o -name '*.php' -print \
| xargs -n1 -P4 php -l

phpcs:
name: WordPress coding standards
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
coverage: none
tools: composer
- run: composer install --prefer-dist --no-progress
- run: composer phpcs

assets:
name: Minified assets are current
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: npm
- run: npm ci
# Catches the case where fancybox.css is edited but the .min is not rebuilt -
# the minified file is what actually ships to visitors.
- run: npm run verify:assets

package:
name: Package builds cleanly
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
# Also asserts the plugin header, FBFW_VERSION, readme Stable tag and
# package.json all agree, and that no dev file leaked into the zip.
- run: npm run package
- uses: actions/upload-artifact@v4
with:
name: plugin-zip
path: build/*.zip

plugin-check:
name: WordPress.org Plugin Check
runs-on: ubuntu-latest
permissions:
contents: read
# Lets the action post its findings as a PR comment.
pull-requests: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: npm
- run: npm ci

# Check the built package, not the repository. Running it against the repo
# root judges files that never ship - phpcs.xml.dist alone fails it with
# "Application files are not permitted" - and tells you nothing about what
# users actually install. The directory name must be the plugin slug,
# because that is what the text-domain check compares against.
- name: Build the distributable
run: npm run package

- uses: wordpress/plugin-check-action@v1
with:
build-dir: ./build/fancybox-for-wordpress
# Warnings are informational; errors fail the run.
ignore-warnings: true
91 changes: 91 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
name: Deploy to WordPress.org

# Pushing a version tag publishes that exact commit to the plugin directory.
#
# This exists because the two repositories have drifted before: 3.3.7 shipped to
# WordPress.org and was never committed here, and 3.4.1 shipped while master still
# said 3.4.0. Releasing from a tag makes git the source of truth and removes the
# manual SVN step where that drift crept in.
#
# Requires two repository secrets: SVN_USERNAME and SVN_PASSWORD (a WordPress.org
# account with commit access to the plugin).

on:
push:
tags:
- '[0-9]+.[0-9]+.[0-9]+'
workflow_dispatch:
inputs:
dry_run:
description: 'Build and validate without publishing'
type: boolean
default: true

permissions:
contents: read

jobs:
verify:
name: Pre-flight
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: npm
- run: npm ci

- name: Minified assets are current
run: npm run verify:assets

- name: Versions agree and no dev files ship
run: npm run package

- name: Tag matches the plugin version
if: startsWith(github.ref, 'refs/tags/')
run: |
TAG="${GITHUB_REF#refs/tags/}"
VERSION=$(grep -m1 -oE '^\s*\*\s*Version:\s*[0-9.]+' fancybox.php | grep -oE '[0-9.]+$')
STABLE=$(grep -m1 -oE '^Stable tag:\s*[0-9.]+' readme.txt | grep -oE '[0-9.]+$')
echo "tag=$TAG header=$VERSION stable=$STABLE"
if [ "$TAG" != "$VERSION" ] || [ "$TAG" != "$STABLE" ]; then
echo "::error::Tag $TAG does not match the plugin header ($VERSION) / Stable tag ($STABLE)"
exit 1
fi

deploy:
name: Publish
needs: verify
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/') && github.event_name == 'push'
environment: wordpress-org
steps:
- uses: actions/checkout@v4

# Without this the run dies deep inside the SVN step with an authentication
# error that does not say what is actually wrong.
- name: Check WordPress.org credentials are configured
env:
SVN_USERNAME: ${{ secrets.SVN_USERNAME }}
SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }}
run: |
missing=""
[ -z "$SVN_USERNAME" ] && missing="$missing SVN_USERNAME"
[ -z "$SVN_PASSWORD" ] && missing="$missing SVN_PASSWORD"
if [ -n "$missing" ]; then
echo "::error::Missing repository secret(s):$missing"
echo "Add them under Settings → Secrets and variables → Actions."
echo "Use a WordPress.org account with commit access to the plugin."
echo "The tag is already pushed, so re-run this workflow once they exist."
exit 1
fi
echo "Credentials present for '$SVN_USERNAME'."

- name: Deploy to the plugin directory
uses: 10up/action-wordpress-plugin-deploy@stable
env:
SVN_USERNAME: ${{ secrets.SVN_USERNAME }}
SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }}
SLUG: fancybox-for-wordpress
# Honours .distignore, the same list `npm run package` uses.
17 changes: 13 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
Thumbs.db
node_modules/*
.idea/*
*.zip
.DS_Store
package-lock.json
.idea/*
.standard.json

# Dependencies. The lockfiles are committed on purpose: CI installs with
# `npm ci` and `composer install`, both of which need them to be reproducible.
node_modules/
vendor/

# Build output.
build/
*.zip

# Local development notes.
.claude/
28 changes: 24 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,32 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

`FancyBox for WordPress` — a WordPress.org plugin (slug `fancybox-for-wordpress`, text domain `mfbfw`) by Colorlib that wires fancyBox 3 into any WordPress site. Requires PHP 7.4+ / WP 5.6+.

There is **no test suite and no linter**, and PHP/CSS/JS are edited directly rather than compiled. There *is* a Grunt build — `Gruntfile.js` + `package.json` — but it lives only in the [GitHub repo](https://github.com/ColorlibHQ/fancybox-for-wordpress) and is excluded from the distributed package, so it is absent from a working copy unzipped from WordPress.org. It provides:
PHP/CSS/JS are edited directly rather than compiled, and there is no test suite. The tooling lives only in the [GitHub repo](https://github.com/ColorlibHQ/fancybox-for-wordpress) and is excluded from the distributed package, so it is absent from a working copy unzipped from WordPress.org.

- `grunt i18n` — `checktextdomain` (already configured to expect `fancybox-for-wordpress`) plus `makepot`
- `grunt build-archive` — copies to `build/`, minus dev files, and zips it
```bash
npm install && composer install

npm run build:assets # regenerate the .min files (REQUIRED after editing a source asset)
npm run verify:assets # fail if a .min file is stale — this is what CI enforces
npm run i18n # regenerate .pot, .mo and .l10n.php (needs wp-cli on PATH)
npm run package # build build/fancybox-for-wordpress-<version>.zip
npm run release:check # verify:assets + composer lint + package
composer phpcs # escaping, sanitisation, nonces, i18n, PHP 7.4–8.5 compatibility
composer lint # php -l across every file
```

`.distignore` is the **single source of truth** for what ships. `bin/package.mjs` and the deploy workflow both feed it to `rsync --exclude-from`, so a local build and a published release contain the same files. Do not introduce a second exclude list — the old `Gruntfile.js` had one and it had to be hand-synced.

Two guards worth knowing about, because both encode mistakes that actually happened:

- **`verify:assets`** rebuilds each `.min` file into a temp location and byte-compares. The minified assets are what visitors get (`mfbfw_asset_suffix()` only serves sources under `SCRIPT_DEBUG`), so editing `fancybox.css` without rebuilding silently ships the old stylesheet.
- **`package`** refuses to build unless the plugin header, `FBFW_VERSION`, the readme `Stable tag` and `package.json` all agree, and fails if a dev file lands in the zip.

### Releasing

Push a version tag and `.github/workflows/deploy.yml` publishes that commit to WordPress.org SVN. It needs the `SVN_USERNAME` / `SVN_PASSWORD` repository secrets. **Do not release by hand** — 3.3.7 shipped to WordPress.org and was never committed to git, and 3.4.1 shipped while `master` still said 3.4.0. Releasing from a tag makes git the source of truth and removes the step where that drift occurred.

Its `copy.build` exclude list is the authority on what ships when releasing from GitHub; `.distignore` covers the same ground for `wp dist-archive` and the wp.org deploy action. **Keep the two in sync** — a file excluded from one but not the other will leak into some builds and not others.
`phpcs.xml.dist` deliberately runs a **subset** of the WordPress standard. The full `WordPress` ruleset reports 293 violations here, all of them whitespace, array alignment or missing docblocks, and zero security/i18n/compatibility problems. The rules kept are the ones that catch real defects; see the file's own `<description>` for how to adopt full formatting later.

## Development workflow

Expand Down
Loading
Loading