Skip to main content
Adzbyte
TutorialsWordPress

WordPress Plugin PHP Testing with GitHub Actions

Adrian Saycon
Adrian Saycon
September 29, 20264 min read
WordPress Plugin PHP Testing with GitHub Actions

A WordPress plugin compatibility matrix should answer two questions on every pull request: does the plugin work on the oldest environment it promises, and does it work on the current environment users are likely to run? GitHub Actions can also test upcoming combinations, but an exhaustive Cartesian product wastes time and makes failures noisy. This tutorial creates a small, intentional PHP and WordPress matrix, installs the core test suite, caches dependencies safely, and keeps experimental failures visible without blocking every release.

Publish a support policy first

CI cannot choose supported versions for you. Define a minimum PHP version, a minimum WordPress version, and the current stable targets in the plugin header, Composer constraints, documentation, and tests. Those declarations must agree.

A practical required matrix covers the minimum/minimum pair, minimum PHP with current WordPress, current PHP with minimum WordPress when supported, and current/current. Add one allowed-failure job for the next PHP or WordPress version only when it provides actionable early warning.

Trigger checks at useful boundaries

name: Plugin tests
on:
  pull_request:
  push:
    branches: [ main ]
  workflow_dispatch:

Pull requests protect changes before merge; main-branch runs detect environment drift; manual dispatch helps maintainers retest after external updates. Avoid scheduled runs unless someone owns their failures.

Define an explicit matrix

Use include entries rather than every combination. The example names the role each job plays.

jobs:
  phpunit:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        include:
          - php: '8.1'
            wordpress: '6.8'
            label: minimum
          - php: '8.1'
            wordpress: 'latest'
            label: minimum-php
          - php: '8.4'
            wordpress: '6.8'
            label: minimum-wordpress
          - php: '8.4'
            wordpress: 'latest'
            label: current

Replace example versions with the plugin’s real policy. Version promises age, so review them during every release cycle rather than copying this matrix indefinitely.

Set up PHP and dependency caching

Use a maintained PHP setup action, disable unnecessary coverage for ordinary jobs, validate Composer files, and cache Composer downloads rather than blindly caching vendor across incompatible environments.

- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
  with:
    php-version: ${{ matrix.php }}
    coverage: none
    tools: composer:v2
- run: composer validate --strict
- run: composer install --no-interaction --prefer-dist

Pin actions to reviewed major or commit versions according to your supply-chain policy. Dependabot can propose action updates for review.

Install a database and WordPress tests

Start MySQL as a service or use the runner’s available database, wait until it responds, then call the plugin’s test installer with the selected WordPress version. Keep credentials local to CI and use a dedicated disposable database.

- name: Install WordPress tests
  run: bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1 ${{ matrix.wordpress }}
- name: Run PHPUnit
  run: composer test

The installer script should fail on download, checksum, database, or bootstrap errors. Do not convert setup failures into skipped tests, because a green job that ran nothing is worse than a visible failure.

Handle dependency constraints per PHP version

When development tools require newer PHP than the plugin supports, use compatible tool versions through Composer constraints or a separate static-analysis job. Do not claim runtime support for PHP 8.1 while making the PHP 8.1 test impossible to install.

Use composer update --prefer-lowest in one targeted job if the plugin promises compatibility with minimum dependency versions. Regular jobs should test the locked or normally resolved dependency set.

Add linting without multiplying work

Run PHP syntax checks, coding standards, and static analysis once on a current PHP version unless their results genuinely differ across the matrix. PHPUnit belongs in each runtime pair; repository-wide formatting checks do not.

Browser tests and end-to-end WordPress installation checks can run as separate jobs after fast tests pass. Clear separation lets maintainers understand whether a failure is code style, unit behavior, WordPress integration, or browser infrastructure.

Treat experimental versions honestly

For an upcoming PHP or WordPress version, set continue-on-error only on that specific matrix entry and label it clearly. Allowed failure should still appear in pull-request output and issue tracking. Once the version becomes supported, make the job required.

Never mark the minimum supported combination as optional. That job is the evidence behind the compatibility promise.

Protect secrets and permissions

Most plugin test workflows need no repository secrets. Set workflow permissions to read-only by default, avoid executing untrusted pull-request code with privileged pull_request_target, and do not upload database dumps containing secrets. Artifacts should contain test reports or coverage only when maintainers need them.

Make failures diagnosable

  • Name jobs with PHP, WordPress, and matrix purpose.
  • Print tool and runtime versions before tests.
  • Keep fail-fast: false so one failure does not hide the rest.
  • Upload logs only on failure and exclude credentials.
  • Use dependency caches keyed by lockfile and runtime.
  • Set reasonable timeouts so hung installs terminate.

A matrix is valuable only if a maintainer can see which compatibility boundary broke.

Test promises, not every permutation

Four meaningful required jobs usually provide more evidence than dozens of redundant combinations. Cover both ends of support, isolate tooling checks, and keep future versions visible as advisory signals. GitHub’s matrix documentation explains workflow syntax, while the WordPress PHPUnit environment supplies the product behavior. Revisit the matrix whenever support declarations change so CI remains an enforceable contract instead of historical decoration.

Photo by Pixabay on Pexels.

Adrian Saycon

Written by

Adrian Saycon

A developer with a passion for emerging technologies, Adrian Saycon focuses on transforming the latest tech trends into great, functional products.

Discussion (0)

Sign in to join the discussion

No comments yet. Be the first to share your thoughts.

Latest Articles

From the Blog

View all articles