GitHub Actions: Matrix Builds and Reusable Workflows for WordPress

A WordPress plugin that claims to support PHP 8.1–8.4 and WordPress 6.4–7.0 has a 4×4 compatibility matrix — 16 combinations to test. GitHub Actions matrix builds run all 16 in parallel without duplicating workflow YAML, catching the one PHP 8.4 + WordPress 6.4 regression before it reaches users. Reusable workflows take this further: define the test job once in a central repository and call it from every plugin repository, keeping CI configuration consistent across a team’s entire plugin portfolio.


The workflows below set up a PHP/WordPress matrix build using the shivammathur/setup-php action, define a reusable workflow for WordPress plugin testing, and call it from a plugin repository with per-repo overrides.


# .github/workflows/tests.yml — Matrix build for PHP × WordPress versions
name: Plugin Tests

on:
  push:
    branches: [ main, develop ]
  pull_request:

jobs:
  test:
    name: PHP ${{ matrix.php }} / WP ${{ matrix.wp }}
    runs-on: ubuntu-latest

    strategy:
      fail-fast: false   # run all combinations even if one fails
      matrix:
        php: [ '8.1', '8.2', '8.3', '8.4' ]
        wp:  [ '6.4', '6.5', '6.6', '7.0' ]
        exclude:
          # WP 7.0 requires PHP >= 8.1 (already satisfied here, but example syntax)
          - php: '8.0'
            wp:  '7.0'
        include:
          # Extra: test with MySQL 9.1
          - php: '8.3'
            wp:  '7.0'
            mysql: '9.1'

    services:
      mysql:
        image: mysql:${{ matrix.mysql || '8.0' }}
        env:
          MYSQL_ROOT_PASSWORD: root
          MYSQL_DATABASE: wordpress_test
        ports: [ '3306:3306' ]
        options: --health-cmd="mysqladmin ping" --health-interval=10s

    steps:
      - uses: actions/checkout@v4

      - name: Setup PHP ${{ matrix.php }}
        uses: shivammathur/setup-php@v2
        with:
          php-version: ${{ matrix.php }}
          extensions: mysqli, zip, gd
          coverage: xdebug
          tools: composer, wp-cli

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

      - name: Install Composer dependencies
        run: composer install --prefer-dist --no-progress

      - name: Run PHPUnit
        run: vendor/bin/phpunit --coverage-clover coverage.xml

      - name: Upload coverage (main PHP+WP only)
        if: matrix.php == '8.3' && matrix.wp == '7.0'
        uses: codecov/codecov-action@v4
        with:
          files: coverage.xml


# org/.github/workflows/wp-plugin-tests.yml — REUSABLE workflow
name: WordPress Plugin Tests (Reusable)

on:
  workflow_call:
    inputs:
      php-versions:
        description: 'JSON array of PHP versions'
        type: string
        default: '["8.2","8.3"]'
      wp-versions:
        description: 'JSON array of WP versions'
        type: string
        default: '["6.6","7.0"]'

jobs:
  test:
    strategy:
      matrix:
        php: ${{ fromJson( inputs.php-versions ) }}
        wp:  ${{ fromJson( inputs.wp-versions ) }}
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: shivammathur/setup-php@v2
        with:
          php-version: ${{ matrix.php }}
      - run: bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1 ${{ matrix.wp }}
      - run: composer install --prefer-dist --no-progress
      - run: vendor/bin/phpunit

---
# my-plugin/.github/workflows/ci.yml — CALLER workflow
name: CI
on: [push, pull_request]
jobs:
  tests:
    uses: my-org/.github/.github/workflows/wp-plugin-tests.yml@main
    with:
      php-versions: '["8.3","8.4"]'
      wp-versions:  '["6.6","7.0"]'


NOTE: Matrix builds multiply your CI minute usage — a 4×4 matrix of 5-minute jobs consumes 80 CI minutes per push; on GitHub Free (2000 min/month), a busy plugin with multiple daily pushes will exhaust the free allowance quickly; use fail-fast: false only when you need to see all failures at once, and use path filters (on.push.paths) to skip the matrix for documentation-only changes — these two adjustments typically cut CI usage by 40–60%.