Skip to content
Open
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
93 changes: 93 additions & 0 deletions .github/workflows/ci-check-iapi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
name: CI / Check Interactivity API

# WordPress 7.2 (due 2026-12-09) removes three Interactivity API behaviours deprecated since 6.8
# and 6.9: data-wp-ignore, two-hyphen unique IDs (data-wp-watch--x, data-wp-on--click--x) and `!`
# applied to a function. wp-tooling iapi-check scans the project's PHP, HTML and JS for them.

on:
workflow_call:
inputs:
runs-on:
description: "Runner for every job, as JSON: a label such as \"ubuntu-latest\" or a label list such as [\"self-hosted\"]. rtCamp private repos pass [\"self-hosted\"]."
type: string
default: '"ubuntu-latest"'
node-version:
description: "Node.js version used to run the wp-tooling CLI."
type: string
default: "22"
working-dir:
description: "Directory to scan, relative to the repo root."
type: string
default: "."
fail-on-findings:
description: "Fail the job when the scan finds a usage WordPress 7.2 breaks. Off by default: findings are warnings."
type: boolean
default: false
ignore-paths:
description: "Regex of paths to leave out of the scan. Empty uses the CLI's default (vendor, node_modules and build output)."
type: string
default: ""
wp-tooling-ref:
description: "Version or range of @rtcamp/wp-tooling to run from npm. Leave empty for ^2."
type: string
default: ""

permissions:
contents: read

jobs:
check-iapi:
name: iapi-check
runs-on: ${{ fromJSON(inputs.runs-on) }}
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false

- name: Set up Node.js
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
with:
node-version: ${{ inputs.node-version }}
# setup-node 5+ caches on its own when package.json names a packageManager, and fails
# when that lockfile is missing. This step installs no project dependencies.
package-manager-cache: false

- name: Install wp-tooling
shell: bash
env:
WP_TOOLING_VERSION: ${{ inputs.wp-tooling-ref || '^2' }}
run: |
set -euo pipefail
npm install --ignore-scripts --no-audit --no-fund --prefix "$RUNNER_TEMP/wp-tooling" "@rtcamp/wp-tooling@$WP_TOOLING_VERSION"
npm ls --prefix "$RUNNER_TEMP/wp-tooling" @rtcamp/wp-tooling
echo "$RUNNER_TEMP/wp-tooling/node_modules/.bin" >> "$GITHUB_PATH"

# Runs from the repo root with --working-dir as a scope, so annotation paths are
# repo-relative and attach to the pull request diff.
- name: Scan for Interactivity API usages WordPress 7.2 removes
shell: bash
env:
WORKING_DIR: ${{ inputs.working-dir }}
FAIL_ON_FINDINGS: ${{ inputs.fail-on-findings }}
IGNORE_PATHS: ${{ inputs.ignore-paths }}
run: |
set -euo pipefail
# A wp-tooling older than the command would fail every caller; say so and pass instead,
# unless the caller asked for a failing check.
if ! wp-tooling iapi-check --help >/dev/null 2>&1; then
if [ "$FAIL_ON_FINDINGS" = "true" ]; then
echo "::error::iapi-check-fail is set, but the installed @rtcamp/wp-tooling has no iapi-check command. Use wp-tooling 2.1.0 or later."
exit 1
fi
echo "::warning::The installed @rtcamp/wp-tooling has no iapi-check command, so the WordPress 7.2 Interactivity API scan was skipped."
exit 0
fi
args=(--working-dir "$WORKING_DIR" --output github)
if [ "$FAIL_ON_FINDINGS" != "true" ]; then
args+=(--soft-fail)
fi
if [ -n "$IGNORE_PATHS" ]; then
args+=(--ignore "$IGNORE_PATHS")
fi
wp-tooling iapi-check "${args[@]}"
38 changes: 35 additions & 3 deletions .github/workflows/wp-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ on:
description: >-
Comma-separated job ids to drop, e.g. 'a11y, test-php'. Whitespace is ignored and an
unknown id fails the run. Ids: lint-css, lint-js, lint-php, test-js, test-php, build,
build-artifact, a11y, artifact-gate.
build-artifact, a11y, artifact-gate, iapi.
type: string
default: ""
enable-phpstan:
Expand Down Expand Up @@ -156,6 +156,19 @@ on:
description: "Minimum percentage (0 to 100) of changed executable lines that must be covered. Applies only when coverage is true."
type: number
default: 80
iapi-check-fail:
description: >-
Fail the iapi job when it finds an Interactivity API usage that WordPress 7.2 removes
(data-wp-ignore, two-hyphen unique IDs, `!` on a function). Off by default: findings are
warnings.
type: boolean
default: false
iapi-ignore-paths:
description: >-
Regex of paths the iapi job leaves out of its scan, such as a block's deprecated.js that
keeps an old directive on purpose. Separate from ignore-paths, which filters detect-changes.
type: string
default: ""

# project-type and working-dir are in the group so a monorepo caller invoking this workflow
# once per unit does not have one call cancel its siblings. Uses the RAW input because
Expand Down Expand Up @@ -203,15 +216,15 @@ jobs:

# The preset as data, in one place, rather than a disjunction repeated in eight `if:`s.
case "$PROJECT_TYPE" in
plugin|theme) preset="lint-css,lint-js,lint-php,test-js,test-php,build,build-artifact,a11y,artifact-gate" ;;
plugin|theme) preset="lint-css,lint-js,lint-php,test-js,test-php,build,build-artifact,a11y,artifact-gate,iapi" ;;
package) preset="lint-php,test-php,artifact-gate" ;;
*) echo "::error::project-type must be one of: plugin, theme, package (got '$PROJECT_TYPE')"; exit 1 ;;
esac

# Whitespace is dropped, so 'a11y, test-php' skips both, and an unknown id fails here
# instead of silently running the job it was meant to drop. Skipping a job the preset
# does not run is allowed, so one skip list can serve every unit in a caller's matrix.
known=",lint-css,lint-js,lint-php,test-js,test-php,build,build-artifact,a11y,artifact-gate,"
known=",lint-css,lint-js,lint-php,test-js,test-php,build,build-artifact,a11y,artifact-gate,iapi,"
jobs=",${preset},"
IFS=',' read -r -a skip_ids <<< "$(printf '%s' "$SKIP" | tr -d '[:space:]')"
for id in "${skip_ids[@]}"; do
Expand Down Expand Up @@ -464,6 +477,24 @@ jobs:
gated-paths: ${{ inputs.gated-paths }}
working-dir: ${{ needs.validate-inputs.outputs.working-dir }}

# WordPress 7.2 (2026-12-09) drops data-wp-ignore, two-hyphen unique IDs and `!` on a
# function. The scan covers the whole unit, not only changed files, since the code that breaks
# is usually old; it reports warnings unless iapi-check-fail is set.
iapi:
name: WP 7.2 Interactivity API
needs: [validate-inputs, detect-changes]
if: >-
(needs.detect-changes.outputs.js-count > 0 || needs.detect-changes.outputs.php-count > 0
|| needs.detect-changes.outputs.gha-count > 0)
&& contains(needs.validate-inputs.outputs.jobs, ',iapi,')
uses: ./.github/workflows/ci-check-iapi.yml
with:
runs-on: ${{ inputs.runs-on }}
working-dir: ${{ needs.validate-inputs.outputs.working-dir }}
fail-on-findings: ${{ inputs.iapi-check-fail }}
ignore-paths: ${{ inputs.iapi-ignore-paths }}
wp-tooling-ref: ${{ inputs.wp-tooling-ref }}

# The one check to require in branch protection: "<caller job> / CI result". The other check
# names and their count change with project-type, skip, what changed and the PHP matrix, and a
# skipped required check counts as passing. Runs on always(), so a failed, cancelled or
Expand All @@ -482,6 +513,7 @@ jobs:
- build-artifact
- a11y
- artifact-gate
- iapi
if: always()
runs-on: ${{ fromJSON(inputs.runs-on) }}
steps:
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ you can copy as-is.
| [`ci-lint-php.yml`](.github/workflows/ci-lint-php.yml) | PHPCS with `cs2pr` annotations + optional PHPStan | [example](examples/ci-lint-php.yml) |
| [`ci-test-js.yml`](.github/workflows/ci-test-js.yml) | Jest | [example](examples/ci-test-js.yml) |
| [`ci-test-php.yml`](.github/workflows/ci-test-php.yml) | PHPUnit, via `@wordpress/env` or standalone | [example](examples/ci-test-php.yml) |
| [`ci-check-iapi.yml`](.github/workflows/ci-check-iapi.yml) | Flags Interactivity API usages that WordPress 7.2 removes | [example](examples/ci-check-iapi.yml) |
| [`ci-coverage-comment.yml`](.github/workflows/ci-coverage-comment.yml) | Posts the changed-line coverage summaries of a run as one pull request comment | [example](examples/ci-coverage-comment.yml) |
| [`ci-test-a11y.yml`](.github/workflows/ci-test-a11y.yml) | pa11y-ci WCAG2AA | [example](examples/ci-test-a11y.yml) |
| [`ci-build.yml`](.github/workflows/ci-build.yml) | Production build + optional artifact upload | [example](examples/ci-build.yml) |
Expand Down
14 changes: 14 additions & 0 deletions examples/ci-check-iapi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
name: WordPress 7.2 readiness

on:
pull_request:

permissions:
contents: read

jobs:
check-iapi:
uses: rtCamp/wp-shared-workflows/.github/workflows/ci-check-iapi.yml@v1
with:
working-dir: themes/acme-theme
fail-on-findings: true
Loading