Run the shared local validation entrypoint first:
bash .wp-plugin-base/scripts/ci/validate_project.shIf that fails before any repo checks run, the most common causes are:
- a missing command such as
ruby,jq,rsync,zip, orunzip - an invalid
.wp-plugin-base.envvalue - a missing
MAIN_PLUGIN_FILEorREADME_FILE - an invalid
POT_FILEpath or parent directory when POT generation is configured - forbidden repository files such as
.DS_Store,Thumbs.db,.idea/,.vscode/, or transient debug logs
The validation scripts now fail fast and identify the missing tool or invalid config key directly. Unknown .wp-plugin-base.env keys are rejected so typos do not silently degrade behavior.
If foundation validation passes in fast-local mode but you want CI-like tool enforcement locally, rerun:
bash scripts/foundation/bootstrap_strict_local.sh "$PWD/.wp-plugin-base-tools"
export PATH="$PWD/.wp-plugin-base-tools:$PATH"
bash scripts/foundation/validate.sh --mode strict-localgh, svn, and similar tools are still required for release, update, or deploy flows, but they are not baseline prerequisites for validate_project.sh.
If you are bootstrapping a blank repo, create the plugin main file and readme.txt before the first sync. The foundation expects those files to exist before validation can pass.
Some foundation automation flows create change requests automatically, including:
prepare-releaseprepare-foundation-releaseupdate-foundation
Use the troubleshooting path that matches the selected automation host.
If GitHub-hosted workflows fail when they try to open a pull request, check the GitHub Actions repository setting named Allow GitHub Actions to create and approve pull requests.
- Open your repository on GitHub.
- Go to
Settings->Actions->General. - Under
Workflow permissions, selectRead and write permissions. - Enable
Allow GitHub Actions to create and approve pull requests. - Save the change and rerun the failed workflow.
Without that setting, workflows can still run, but workflows that use the foundation's gh pr automation cannot open or update GitHub pull requests.
If the setting is greyed out, the repository is usually inheriting an organization-level restriction.
In that case, an organization owner must allow it first:
- Open the organization on GitHub.
- Go to
Settings->Actions->General. - Allow repositories in the organization to let GitHub Actions create and approve pull requests.
- Return to the repository settings and enable the repository-level setting if GitHub still requires it there.
If you do not have organization admin access, ask an organization owner to make that change.
If the error mentions workflow-file permissions, the automation token likely cannot push or open a PR that includes .github/workflows/* changes. Grant the token workflow scope or remove the workflow-file edits from that change request.
Preferred recovery path:
- create a narrowly scoped GitHub token that can update workflow files
- store it as the repository secret
WP_PLUGIN_BASE_PR_TOKEN - rerun the failed
update-foundationorupdate-external-dependenciesworkflow
The managed GitHub update workflows prefer WP_PLUGIN_BASE_PR_TOKEN for PR creation when it is configured and otherwise fall back to github.token.
If GitLab-hosted automation fails to open a merge request:
- confirm
GITLAB_TOKENorCI_JOB_TOKENis available to the job - confirm that token can push branches and create merge requests in the project
- confirm
AUTOMATION_API_BASEpoints at the correct GitLab API base for the selected instance - if you use a self-managed instance, add the Git host to
TRUSTED_GIT_HOSTS
When WP_ORG_DEPLOY_ENABLED=true, CI/release readiness now enforces deployment environment protection in strict mode.
If readiness fails with reviewer-protection errors:
- on GitHub: confirm the environment named by
PRODUCTION_ENVIRONMENTexists in the repository, require at least one reviewer, and ensure the readiness step hasGH_TOKEN - on GitLab: confirm the environment named by
PRODUCTION_ENVIRONMENTexists, protect it, require reviewer approval, and rerun only withWP_PLUGIN_BASE_GITLAB_DEPLOY_ENV_ACKNOWLEDGED=trueonce that review is complete
If the generated ZIP drops files from packages/ or routes/, check the package include and exclude settings first.
PACKAGE_INCLUDEandPACKAGE_EXCLUDEare repo-relative paths- absolute paths in
PACKAGE_INCLUDE,PACKAGE_EXCLUDE, orDISTIGNORE_FILEare rejected DISTIGNORE_FILEmust point to a*.distignorefile, not another managed project filepackages/androutes/are excluded by default- include those directories explicitly only if they are part of the shipped plugin
If the ZIP root looks flattened, check that file entries in PACKAGE_INCLUDE are being preserved as repo-relative paths.
If update-foundation detects a newer version but fails during pull request creation, check both of these:
Allow GitHub Actions to create and approve pull requestsis enabled for the repository- automation on the selected host can read releases from
FOUNDATION_RELEASE_SOURCE_REFERENCE
Both conditions are required for the automated update PR flow to work.
If the change request includes .github/workflows/* updates, also configure WP_PLUGIN_BASE_PR_TOKEN so the workflow can push those changes with a token that has workflow-write permission.
The managed update-foundation workflow now bootstraps release security tools (cosign, syft, companion binaries) before provenance verification. If you run scripts/update/verify_foundation_release.sh directly, install those tools first (for example via scripts/release/install_release_security_tools.sh).
If CI starts failing after sync_child_repo.sh with errors such as Class not found or missing test bootstrap support classes, check whether child-specific PHPUnit preload logic was stored in tests/bootstrap.php.
tests/bootstrap.php is managed by wp-plugin-base and can be overwritten on sync. Child-specific PHPUnit preloads belong in tests/wp-plugin-base/bootstrap-child.php, which is child-owned.
Recovery:
- Move project-specific
requirestatements and preload hooks fromtests/bootstrap.phpintotests/wp-plugin-base/bootstrap-child.php. - Rerun
bash .wp-plugin-base/scripts/update/sync_child_repo.sh. - Rerun
bash .wp-plugin-base/scripts/ci/validate_project.sh.
For public endpoint failures, rerun the scanner directly so you can copy the exact suppression tuple:
bash .wp-plugin-base/scripts/ci/scan_wordpress_authorization_patterns.shUse the reported kind, identifier, and repo-relative path exactly in the configured suppressions file. Add a non-empty justification that explains why the endpoint is intentionally public and what guard makes it safe. If the endpoint mutates state or exposes private data, fix the permission callback instead of suppressing the finding.
For Semgrep failures, rerun the security pass and inspect the SARIF:
bash .wp-plugin-base/scripts/ci/run_semgrep_security.shThe CI workflow uploads Semgrep SARIF to the host security surface when the scan runs there. Local failures usually mean either semgrep is missing or a rule found code that needs a scoped fix; do not bypass the scan for release branches.
For Plugin Check failures, validate the package and rerun the checker:
bash .wp-plugin-base/scripts/ci/build_zip.sh
bash .wp-plugin-base/scripts/ci/run_plugin_check.shDocker must be running because Plugin Check uses @wordpress/env. If RELEASE_READINESS_MODE=security-sensitive, remove narrowed Plugin Check filters and keep strict warning mode enabled; that profile intentionally fails closed when coverage is weakened.
The foundation's external dependency updater lives at .github/workflows/update-plugin-check.yml (display name: update-external-dependencies).
If it fails:
- confirm the failing
dependency_idfrom the matrix job title - rerun the workflow once to rule out transient network failures
- validate local contracts:
bash scripts/ci/validate_dependency_inventory.shbash scripts/foundation/test_dependency_inventory.shbash scripts/ci/audit_workflows.sh
- if only one dependency handler fails, inspect
scripts/update/prepare_external_dependency_update.shbranch logic for thatdependency_id - confirm expected hosts are allowlisted if a new upstream endpoint was introduced
The selected host release flow publishes the Git tag/release first, then runs downstream channel deploy steps (WordPress.org and WooCommerce.com when enabled). A channel failure can therefore happen after host-release publication; the workflow still ends failed.
Repair path:
- on GitHub stable releases, run
release.ymlfor the existing release tag - on GitHub prereleases, rerun the trusted prerelease tag through
publish-tag-release.yml - on GitLab, rerun the tagged
releasejob from the managed.gitlab-ci.yml - review WordPress.org/WooCommerce.com channel logs
- on GitHub, run
woocommerce-status.ymlwhen Woo is enabled - rerun the same host-specific repair path until the failed channel succeeds or reports already-live state
If a tag with the release version exists on a different commit, stop and resolve the mismatch manually before retrying automated release flows.
Common WooCommerce.com-specific failures and actions:
Woo:header mismatch or missing in packaged plugin file: fix the plugin header toWoo: <product_id>:<hash>and ensure<product_id>matchesWOOCOMMERCE_COM_PRODUCT_ID.- Credential or auth errors:
regenerate the Woo WordPress application password and update
WOO_COM_APP_PASSWORDin deployment-environment secrets. - API timeout or transport error:
rerun release repair and, if needed, increase
WOOCOMMERCE_COM_ENDPOINT_TIMEOUT_SECONDS. - QIT rejection after queue acceptance: inspect Woo vendor/QIT diagnostics, fix package issues, then rerun the same host-specific release repair path for the same tag.
See: