Technote

Development workflow Advanced

Series From local to production Part 7 of 8

CI for WordPress projects: what you can realistically check

CI earns its keep without a full test suite. Syntax, coding standards, a build check and a boot smoke test are a realistic starting point.

Attempts to add CI to a WordPress project usually stall on “we have no tests, so what would it run?”. In fact there is a good deal you can catch automatically without a test suite, and what it catches tends to be the most embarrassing class of incident: a syntax error reaching production, a deploy without a rebuild, a plugin that stops the site booting.

A realistic four-stage pipeline — the first two finish in seconds, the last two in minutes

1. Syntax — the cheapest and surest check

php -l only parses, so it is very fast. It does, however, accept one file at a time — hand it several and it checks the first and stops. That is why xargs -n1 is required.

find wp-content/themes wp-content/plugins -name '*.php' -not -path '*/vendor/*' -print0 | xargs -0 -n1 -P4 php -l

That single line prevents a large share of white-screen incidents. A parse error fires the moment the file is loaded, so a file used on exactly one admin screen is no exception.

2. Coding standards — so reviews are not arguments

With PHPCS and the WordPress standard in place, indentation, missing escaping and prefix conventions are raised by a tool rather than by a colleague.

composer require --dev squizlabs/php_codesniffer wp-coding-standards/wpcs dealerdirect/phpcodesniffer-composer-installer
vendor/bin/phpcs --standard=phpcs.xml.dist

Committing the ruleset itself matters. Declaring your text domain and function prefixes in phpcs.xml.dist means a mistyped translation domain or an unprefixed global function is caught automatically. Turning every rule on at once buries you in thousands of warnings, so start by checking changed files only and widen from there — that version actually survives.

3. Build check — “I forgot to rebuild”

If part two led you to commit build output, verifying that the output still matches the source is CI’s job, not a person’s. The omission will happen, and the symptom is somebody asking why the styles have not changed.

npm ci
npm run build
git diff --exit-code assets/dist

--exit-code fails the step when a difference exists, so a rebuild that does not match what was committed stops the pipeline right there.

4. Boot smoke test — does the site actually come up?

The most valuable check of the four. Install WordPress against a throwaway database, activate your theme and plugins, and confirm the home page answers 200.

wp core install --url=http://127.0.0.1:8080 --title=CI --admin_user=ci --admin_password=ci --admin_email=ci@example.com --skip-email
wp theme activate our-theme
wp plugin activate --all
test "$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8080/)" = "200"

Simply getting wp plugin activate --all to pass filters out fatal errors at activation time — redeclared functions and references to classes that do not exist surface here.

What CI will not tell you

What CI catches and what it does not — a green build means "not broken", not "works well"

One final rule: keep secrets out of CI logs. Inject deploy keys and database passwords as masked secrets, and never leave behind a debugging step that dumps the whole environment. The conclusion from part three applies here unchanged.

Automation continues in the development workflow archive, and the order in which we verify and deploy in practice is published on our process page.

Next part

The final part is rollback. It rests on one fact — putting the old code back does not put the old data back — and that is why the order has to be decided in advance.

More on this topic

All technotes

Development workflow Advanced

The design QA checklist to run before release

Most design problems found after release are catchable before it, in order. Here is the pass, in three stages: rules, states and real devices.

Designers 6 min read

Development workflow Advanced

Never deploy without a way back

A rollback is not one button. It is two tracks — code and database — with an order to reverse them in, written down before you deploy.

Designers 9 min read

Development workflow Advanced

Adding your own hooks: extension points instead of edits

Code with no extension points gets forked or edited in place. Where you put do_action and apply_filters — and how many — decides how long that code survives.

Developers 7 min read

₩270,000 · Join the program