From 31ec570fe002ec9014605d871aafdd1369c6f73c Mon Sep 17 00:00:00 2001 From: Wan Zulkarnain Date: Tue, 16 Jun 2026 08:07:47 +0200 Subject: [PATCH 1/3] ci(plugin-check): use wordpress/plugin-check-action@v1.1.7 Replaces the manual wp-env workaround in the plugin-check job with the upstream action. Issue #579 ('Environment not initialized') was fixed in v1.1.7 via PR #590, which drops the URL-plugin bootstrap and installs plugin-check via WP-CLI after wp-env start with a post-boot check. Behavior preserved: - ignore-codes: trademarked_term, NonPrefixedHooknameFound (newline- separated per the action's input contract) - depends on the build/php-compatibility/phpcs/phpunit jobs - uses PHP 8.2 via shivammathur/setup-php, matching the PHPCS job Refs: WordPress/plugin-check-action#579, #590 --- .github/workflows/plugin-check.yml | 93 ++++++------------------------ 1 file changed, 19 insertions(+), 74 deletions(-) diff --git a/.github/workflows/plugin-check.yml b/.github/workflows/plugin-check.yml index 3e11914..64fc7e9 100644 --- a/.github/workflows/plugin-check.yml +++ b/.github/workflows/plugin-check.yml @@ -112,7 +112,10 @@ jobs: continue-on-error: false # Tier 3: Plugin Check (needs build artifact) - # Manual wp-env approach — upstream plugin-check-action is broken (#579). + # Uses wordpress/plugin-check-action@v1.1.7, which fixes the wp-env + # "Environment not initialized" bug from upstream issue #579 + # (closed via PR #590 — drops the URL-plugin bootstrap and installs + # plugin-check via WP-CLI after wp-env start with a post-boot check). plugin-check: name: Plugin Check @@ -129,81 +132,23 @@ jobs: name: chip-for-givewp-build path: ./build - # Node 24+ breaks @wordpress/env ("Environment not initialized"). - # Node 22 is the latest version confirmed working. - - name: Setup Node.js - uses: actions/setup-node@v6 + # Setup PHP so the action can pick it up for wp-env's CLI container. + - name: Setup PHP + uses: shivammathur/setup-php@v2 with: - node-version: '22' - - - name: Install @wordpress/env - run: npm install -g @wordpress/env - - - name: Create wp-env override for CI - run: | - cat > .wp-env.override.json <<'JSONEOF' - { - "core": null, - "plugins": [ - "https://downloads.wordpress.org/plugin/give.zip", - "https://downloads.wordpress.org/plugin/plugin-check.zip" - ], - "mappings": { - "wp-content/plugins/chip-for-givewp": "./build/chip-for-givewp" - } - } - JSONEOF - cat .wp-env.override.json - - - name: Start WordPress environment - run: | - npx wp-env start --update - # Give containers time to stabilize - sleep 10 - - - name: Activate Plugin Check - run: | - npx wp-env run cli wp plugin activate plugin-check + php-version: '8.2' - name: Run Plugin Check - run: | - # Run plugin check and output JSON for parsing. - # Ignore trademarked_term: the plugin name "CHIP for GiveWP" and slug "chip-for-givewp" - # contain "wp" which is already published on WordPress.org and cannot be changed. - # Ignore NonPrefixedHooknameFound: all instances are GiveWP core hooks + uses: wordpress/plugin-check-action@v1.1.7 + with: + build-dir: ./build/chip-for-givewp + # Plugin name "CHIP for GiveWP" and slug "chip-for-givewp" + # contain "wp" which is already published on WordPress.org + # and cannot be changed, so trademarked_term is a known false positive. + # NonPrefixedHooknameFound fires on GiveWP core hooks # (give_forms_content_options_select, give_before_chip_info_fields, etc.) # that third-party gateways are expected to use. - # wp-env run cli prepends status text to stdout; filter only JSON lines. - # WP CLI may return exit code 1 even with --ignore-codes; use || true and rely on jq parsing. - npx wp-env run cli wp plugin check chip-for-givewp \ - --format=json \ - --ignore-codes=trademarked_term,WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound \ - 2>/dev/null | grep -E '^\[|^\{' > /tmp/plugin-check-results.json || true - - # Display results in a readable table format. - npx wp-env run cli wp plugin check chip-for-givewp \ - --ignore-codes=trademarked_term,WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound - - # Parse JSON to count errors and warnings. - ERRORS=$(jq '[.[] | select(.type == "ERROR")] | length' /tmp/plugin-check-results.json) - WARNINGS=$(jq '[.[] | select(.type == "WARNING")] | length' /tmp/plugin-check-results.json) - - echo "" - echo "═══════════════════════════════════════" - echo " Plugin Check Summary" - echo "═══════════════════════════════════════" - echo " Errors: ${ERRORS}" - echo " Warnings: ${WARNINGS}" - - if [ "${ERRORS}" -gt 0 ] || [ "${WARNINGS}" -gt 0 ]; then - echo "" - echo "❌ Plugin Check failed with ${ERRORS} error(s) and ${WARNINGS} warning(s)" - exit 1 - fi - - echo "" - echo "✅ Plugin Check passed (no errors or warnings)" - - - name: Stop WordPress environment - if: always() - run: npx wp-env stop + # newline-separated per the action's input contract. + ignore-codes: | + trademarked_term + WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound From 7a6f07bddd92a2a343872fee085fadf0e403bf71 Mon Sep 17 00:00:00 2001 From: Wan Zulkarnain Date: Tue, 16 Jun 2026 08:08:11 +0200 Subject: [PATCH 2/3] docs: document GitHub Actions workflows in CLAUDE.md Adds a .github/workflows/ entry to Core Components describing all five workflows (plugin-check, prepare-release, release-zip, deploy, pr-summary) with their triggers, secrets, and key behaviors. Also adds two Common Changes entries for editing ignore-codes and reproducing plugin-check locally. --- CLAUDE.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index 30b5d2d..1e10576 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -37,6 +37,12 @@ Both gateways share the same backend logic (API calls, listener, settings) but h - **`includes/js/refund.js`** — AJAX handler for the admin refund button. - **`.wp-env.json`** — Local WordPress environment config (GiveWP + plugin-check). - **`.wordpress-org/`** — WordPress.org plugin directory assets (banners, icons, screenshots). +- **`.github/workflows/`** — GitHub Actions CI/CD: + - `plugin-check.yml` — Runs the WordPress.org plugin check (PHP 8.2 + plugin-check-action@v1.1.7), PHPCS, PHPCompatibility, PHPUnit, and the plugin build. All four test jobs (`php-compatibility`, `phpcs`, `phpunit`, `plugin-check`) gate on the `build` job's artifact. The `plugin-check` job passes `ignore-codes: trademarked_term` and `…NonPrefixedHooknameFound` (both are documented false positives for this plugin — see the comments in that file). + - `prepare-release.yml` — Manual dispatch (`workflow_dispatch`, input: `version`). Validates the version, generates an AI changelog from the diff since the last tag (uses `AI_API_KEY` / `AI_MODEL` / `AI_API_URL`), runs `scripts/bump-version.sh`, then opens a `release/vX.Y.Z` PR to `main`. Tag creation is still manual after the PR merges. + - `release-zip.yml` — Fires on `release: created`. Builds a clean `dist/chip-for-givewp/` snapshot and uploads `chip-for-givewp.zip` to the GitHub release as an asset. The WordPress.org deploy workflow is responsible for the trunk/tag push. + - `deploy.yml` — Fires on `v*.*.*` or `*.*.*` tag push, or manual dispatch with `trunk`/`release` stage. Runs in the `wordpress-org` environment using `SVN_USERNAME` / `SVN_PASSWORD` secrets. For `trunk`, reverts `Stable tag` to whatever is currently live on WordPress.org so the testing build doesn't auto-update users; for `release`, commits to trunk, copies trunk → `tags/X.Y.Z`, and creates/updates the matching GitHub release. Excludes `.git*`, `.github`, `.vscode`, `ci-build`, `dist`, `node_modules`, `.wordpress-org` from the deploy. + - `pr-summary.yml` — Fires on PR `opened`/`synchronize`. Generates an AI summary of the PR diff and overwrites the PR description (idempotent — re-runs replace the previous summary). ### Settings Model CHIP settings exist at two levels: @@ -91,6 +97,8 @@ phpcs --standard=PHPCompatibilityWP --runtime-set testVersion 8.5 --extensions=p - To update version: bump in `chip-for-givewp.php` (header + `GWP_CHIP_MODULE_VERSION`), `readme.txt` (`Stable tag`), and `changelog.txt`. Alternatively, use `./scripts/bump-version.sh X.Y.Z`. - To update WordPress.org assets: place images in `.wordpress-org/` (banners, icons, screenshots). Deployed to SVN by `deploy.yml`. - To run local WordPress environment: `wp-env` reads `.wp-env.json` (GiveWP + plugin-check pre-installed). +- To add or change CI `ignore-codes` for the WordPress.org plugin check: edit `.github/workflows/plugin-check.yml` (newline-separated list per the action's `action.yml`). Always include a comment explaining why each code is being ignored — the maintainers may ask. +- To reproduce the CI `plugin-check` job locally: `npx wp-env start && npx wp-env run cli wp plugin activate plugin-check && npx wp-env run cli wp plugin check chip-for-givewp --ignore-codes=trademarked_term,WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound`. ## External Dependencies From 07149831c4e5607ea7d9822b0d28db8f3260af80 Mon Sep 17 00:00:00 2001 From: Wan Zulkarnain Date: Tue, 16 Jun 2026 08:57:54 +0200 Subject: [PATCH 3/3] feat(hooks): add gwp_chip_* prefixed hooks, deprecate give_* legacy hooks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduces two new prefixed hooks as the preferred extension points: - gwp_chip_before_info_fields - gwp_chip_after_info_fields The original hooks are kept firing for backward compatibility: - give_before_chip_info_fields (deprecated in 1.4.0, will be removed in 2.0.0) - give_after_chip_info_fields (deprecated in 1.4.0, will be removed in 2.0.0) A _deprecated_hook() notice is emitted (gated on WP_DEBUG via WordPress's standard helper) so any pre-1.4.0 consumer is told to migrate. Critical detail: billing_fields() detaches itself from the legacy hook on its first invocation there, so our own callback is invoked exactly once per request even when both hooks fire. Custom listeners on the legacy hook are not affected (we remove only our own callback). Also tightens the plugin-check workflow comment for NonPrefixedHooknameFound to reflect the new state: the ignore is now justified by both GiveWP-inherited give_* / givewp_* listeners AND the two legacy give_* hooks we still fire. The inline phpcs:ignore comments on the legacy do_action calls remain — they only go away when the old hooks do, in v2.0.0. Refs: WordPress Coding Standards PrefixAllGlobals discussion (WPCS#1940). Audit of unprefixed hooks performed 2026-06-16. --- .github/workflows/plugin-check.yml | 11 ++++++++--- chip-for-givewp.php | 16 ++++++++++++++++ includes/class-chip-givewp-purchase.php | 21 +++++++++++++++++++-- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/.github/workflows/plugin-check.yml b/.github/workflows/plugin-check.yml index 64fc7e9..fcf07da 100644 --- a/.github/workflows/plugin-check.yml +++ b/.github/workflows/plugin-check.yml @@ -145,9 +145,14 @@ jobs: # Plugin name "CHIP for GiveWP" and slug "chip-for-givewp" # contain "wp" which is already published on WordPress.org # and cannot be changed, so trademarked_term is a known false positive. - # NonPrefixedHooknameFound fires on GiveWP core hooks - # (give_forms_content_options_select, give_before_chip_info_fields, etc.) - # that third-party gateways are expected to use. + # NonPrefixedHooknameFound is unavoidable for a third-party + # GiveWP gateway: we listen to GiveWP's give_* / givewp_* hooks + # (add_action/add_filter), and until v2.0.0 we still fire two + # legacy give_before_chip_info_fields / give_after_chip_info_fields + # hooks kept for backward compatibility. See + # includes/class-chip-givewp-purchase.php and + # chip-for-givewp.php for the prefixed gwp_chip_* replacements + # introduced in 1.4.0. # newline-separated per the action's input contract. ignore-codes: | trademarked_term diff --git a/chip-for-givewp.php b/chip-for-givewp.php index a11607c..1af5051 100644 --- a/chip-for-givewp.php +++ b/chip-for-givewp.php @@ -97,6 +97,14 @@ public function add_filters() { * Adds WordPress actions. */ public function add_actions() { + // Preferred (prefixed) hook. Billing fields render on this hook. + add_action( 'gwp_chip_before_info_fields', array( $this, 'billing_fields' ) ); + + // Legacy hook — kept registered so any pre-1.4.0 listener still + // fires. Our own billing_fields callback detaches itself the + // first time the legacy hook runs (see billing_fields() below), + // so billing_fields is invoked exactly once per request even + // when both hooks fire. add_action( 'give_before_chip_info_fields', array( $this, 'billing_fields' ) ); } @@ -156,6 +164,14 @@ public function filter_gateway( $gateway_list, $form_id ) { * @param int $form_id Form ID. */ public function billing_fields( $form_id ) { + // If this is being invoked via the legacy give_before_chip_info_fields + // hook, detach ourselves from it now that the new prefixed hook + // is wired up. We remove only our own callback so any other + // listeners on the legacy hook still run. + if ( doing_action( 'give_before_chip_info_fields' ) ) { + remove_action( 'give_before_chip_info_fields', array( $this, 'billing_fields' ) ); + } + $chip_customization = give_get_meta( $form_id, '_give_customize_chip_donations', true, 'global' ); $billing_fields = give_get_meta( $form_id, '_give_chip-enable-billing-fields', true ); diff --git a/includes/class-chip-givewp-purchase.php b/includes/class-chip-givewp-purchase.php index 275d233..e46a092 100644 --- a/includes/class-chip-givewp-purchase.php +++ b/includes/class-chip-givewp-purchase.php @@ -52,7 +52,13 @@ public function cc_form( $form_id ) { ob_start(); - // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- GiveWP core hook for gateway field rendering. + // Preferred (prefixed) hook. Use this for new code. + do_action( 'gwp_chip_before_info_fields', $form_id ); + + // Legacy hook kept for backward compatibility. Deprecated in 1.4.0; + // will be removed in 2.0.0. New code should listen to + // gwp_chip_before_info_fields instead. + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Legacy hook retained for back-compat with < 1.4.0 consumers. do_action( 'give_before_chip_info_fields', $form_id ); ?>
@@ -60,9 +66,20 @@ public function cc_form( $form_id ) {