Skip to content

Clear WordPress Plugin Check findings on the release ZIP (PRO-1196) - #31

Merged
pattonwebz merged 7 commits into
mainfrom
william/pro-1196-plugin-check-findings
Jul 17, 2026
Merged

Clear WordPress Plugin Check findings on the release ZIP (PRO-1196)#31
pattonwebz merged 7 commits into
mainfrom
william/pro-1196-plugin-check-findings

Conversation

@pattonwebz

@pattonwebz pattonwebz commented Jul 17, 2026

Copy link
Copy Markdown
Member

What & why

Ran the official WP.org Plugin Check (v2.0.0) against dist/boardscribe.zip on a clean, isolated WordPress 7.0.2 install, per PRO-1196.

Before: 2 warnings, 0 errors, both in the plugin_repo category. general, security, performance, and accessibility were already clean.
After: 1 warning, 0 errors — one finding fixed, one deliberately accepted (see below).

Findings

  1. missing_composer_json_file — the zip ships vendor/ (Composer's own autoloader machinery) but not composer.json. Accepted as-is, not fixed — decided not to ship dev-tooling config into the release artifact for a warning-level, non-blocking finding. Documented in the packaging skill (.claude/skills/package-plugins/SKILL.md) so it isn't rediscovered and "re-fixed" by a future Plugin Check run.

  2. DiscouragedFunctions.load_plugin_textdomainFoundfixed. Plugin::boot() called load_plugin_textdomain( 'boardscribe', ... ) manually. WordPress core has auto-loaded a plugin's translations by Text Domain header match since 4.6 (_load_textdomain_just_in_time()), regardless of wp.org hosting — the manual call is redundant. Safe here because boardscribe.php's Text Domain: boardscribe header already matches the plugin's slug/directory exactly.

Verification

  • Ran Plugin Check per-category (--categories=general|plugin_repo|security|performance|accessibility) before any changes — confirms both original findings were exactly and only in plugin_repo.
  • Rebuilt dist/boardscribe.zip with the textdomain fix (composer.json still excluded), reinstalled it fresh in the same isolated environment, reran Plugin Check: the missing_composer_json_file warning is present (expected/accepted), load_plugin_textdomainFound is gone, 0 errors.
  • i18n sanity check after removing the manual textdomain call: switched the test site to es_ES, confirmed no fatals.
  • npm run build (all three bundles), npm run lint:js, composer check-cs, PHPUnit 90/90 all clean.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Improved translation handling by relying on WordPress’s built-in textdomain detection, ensuring localized content loads as expected.
  • Documentation

    • Updated plugin packaging guidelines to clarify that when vendor/ is included without composer.json, WP.org Plugin Check will mark missing_composer_json_file as a warning (not an error), while continuing to exclude composer.json/composer.lock from release zips.
    • Refined Free/Pro packaging scripts for safer temp staging and cleanup behavior under failure conditions.

pattonwebz and others added 5 commits July 16, 2026 23:02
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
WordPress core has auto-loaded a plugin's translations by Text Domain
header match since 4.6 (_load_textdomain_just_in_time()), regardless
of wp.org hosting - manual load_plugin_textdomain() is redundant and
flagged by the official Plugin Check tool (plugin_repo category,
DiscouragedFunctions.load_plugin_textdomainFound). Safe here because
boardscribe.php's Text Domain header ("boardscribe") already matches
the plugin's slug/directory. Found running PRO-1196's Plugin Check
against the release ZIP.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Plugin Check flags a shipped vendor/ with no accompanying
composer.json as missing_composer_json_file (plugin_repo category).
The file has nothing sensitive to withhold - just the PHP version
requirement, PSR-4 autoload map, and require-dev/scripts entries - so
shipping it is free. composer.lock stays excluded; it only pins exact
dev-tooling versions, which gives a site admin nothing actionable.
Updated both plugins' recipes/manifests for consistency since rule 4
is shared, global guidance across the two. Found running PRO-1196's
Plugin Check against the release ZIP.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@linear-code

linear-code Bot commented Jul 17, 2026

Copy link
Copy Markdown
PRO-1196 Run WordPress Plugin Check against the packaged release

Problem

The official Plugin Check has not yet been run against the exact release ZIP. Local PHPCS and CI do not cover every WordPress.org repository-specific check.

Acceptance criteria

  • Run the current official Plugin Check against dist/meeting-minutes.zip.
  • All checks in the “Plugin repo” category pass.
  • Review warnings from security, performance, accessibility, and best-practice categories.
  • Fix actionable findings or document justified false positives.
  • Rebuild the ZIP after any changes and rerun Plugin Check.
  • Attach or link the final Plugin Check output to this issue.

Review in Linear

@gemini-code-assist

Copy link
Copy Markdown

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Packaging instructions document the Plugin Check warning for vendor/ without composer.json and update both archive recipes with safer temporary-directory cleanup. Plugin::boot() removes manual textdomain loading in favor of WordPress just-in-time loading.

Changes

Plugin Packaging

Layer / File(s) Summary
Plugin Check packaging guidance
.claude/skills/package-plugins/SKILL.md
Documents the warning-level missing_composer_json_file finding, preserves Composer manifest exclusions, and hardens free and pro packaging recipes with strict shell options and temporary-directory cleanup.

Translation Loading

Layer / File(s) Summary
Just-in-time textdomain loading
includes/Plugin.php
Plugin::boot() removes the explicit load_plugin_textdomain() call and documents reliance on WordPress automatic loading.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Poem

A rabbit checks the package with care,
Composer files stay out of there.
WordPress loads each translation true,
While tidy temp paths safely do.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: resolving WordPress Plugin Check findings on the release ZIP.
Linked Issues check ✅ Passed The PR addresses the linked issue by running Plugin Check on the packaged release, fixing actionable findings, documenting the accepted warning, and rerunning checks.
Out of Scope Changes check ✅ Passed The changes stay within packaging, release ZIP, and Plugin Check remediation work; no unrelated scope is evident.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

Comment @coderabbitai help to get the list of available commands.

Reverts the previous commit's fix for missing_composer_json_file.
Decided not to ship composer.json/composer.lock for a warning-level,
non-blocking Plugin Check finding rather than add dev-tooling config
to the release artifact. Documented as an explicitly accepted warning
in the packaging skill so it isn't rediscovered and 're-fixed' by a
future Plugin Check run. Re-verified: rebuilt zip still shows the
warning (expected) with 0 errors, and the load_plugin_textdomain fix
from the prior commit is unaffected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.claude/skills/package-plugins/SKILL.md (1)

27-33: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Make both packaging scripts fail closed before cleanup.

Neither block uses set -e, so a failed composer install, cp, or zip command can be ignored while the script continues. More seriously, if mktemp -d fails, STAGE can become /boardscribe or /boardscribe-pro, causing rm -rf "$(dirname "$STAGE")" to resolve to rm -rf /.

Add set -euo pipefail, validate the temporary directory, and use a guarded cleanup trap before performing recursive deletion.

🛡️ Proposed hardening
+set -euo pipefail
+
-STAGE=$(mktemp -d)/boardscribe && mkdir -p "$STAGE/assets"
+TMP_DIR=$(mktemp -d)
+STAGE="$TMP_DIR/boardscribe"
+mkdir -p "$STAGE/assets"
+trap 'rm -rf -- "$TMP_DIR"' EXIT

Apply the equivalent change to the Pro block.

Also applies to: 50-57

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.claude/skills/package-plugins/SKILL.md around lines 27 - 33, Harden both
packaging script blocks by enabling set -euo pipefail, validating that mktemp -d
successfully produces a nonempty temporary directory before assigning STAGE, and
installing a guarded cleanup trap before any recursive deletion. Ensure cleanup
only removes the expected temporary staging directory, then preserve the
existing composer install, copy, zip, and cleanup flow in both the standard and
Pro blocks.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In @.claude/skills/package-plugins/SKILL.md:
- Around line 27-33: Harden both packaging script blocks by enabling set -euo
pipefail, validating that mktemp -d successfully produces a nonempty temporary
directory before assigning STAGE, and installing a guarded cleanup trap before
any recursive deletion. Ensure cleanup only removes the expected temporary
staging directory, then preserve the existing composer install, copy, zip, and
cleanup flow in both the standard and Pro blocks.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0197de26-1c3a-40d5-b0f8-d7f4f86a74bb

📥 Commits

Reviewing files that changed from the base of the PR and between c522544 and 30a392e.

📒 Files selected for processing (2)
  • .claude/skills/package-plugins/SKILL.md
  • includes/Plugin.php

…m -rf /

Addresses CodeRabbit's Critical finding on #31. Neither recipe used
set -e, so a failed composer install/cp/zip could be silently ignored
while the script kept going and packaged a broken zip. Worse: if
mktemp -d itself failed, STAGE=$(mktemp -d)/boardscribe degraded to
the literal string /boardscribe with no error surfaced (bash doesn't
propagate the failure through string concatenation), making the old
cleanup line rm -rf "$(dirname "$STAGE")" resolve to rm -rf /.

Fixed by separating the bare TMP_DIR=$(mktemp -d) assignment (which
set -e DOES reliably catch, unlike the concatenated form - verified
empirically) from the STAGE path, adding set -euo pipefail to both
blocks, and replacing the manual rm -rf with a trap that only ever
targets the one known $TMP_DIR path.

Verified: ran both the free-plugin recipe end to end (correct zip,
temp dir actually cleaned up post-exit, dev tooling restored) and a
forced-failure case (bad cp path aborts immediately, never reaches
later steps, trap still fires) and a forced mktemp-failure case
(confirms set -e now catches it, where before it silently would not).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@pattonwebz

Copy link
Copy Markdown
Member Author

Fixed in 7f30fed — addresses CodeRabbit's Critical finding (posted outside the diff range, so replying here instead of inline).

Confirmed the failure mode empirically before fixing: a bare set -euo pipefail alone wasn't enough, since STAGE=$(mktemp -d)/boardscribe degrades silently to the literal string /boardscribe if mktemp -d fails (bash doesn't propagate the failure through string concatenation) — making the old rm -rf "$(dirname "$STAGE")" resolve to rm -rf /. Fixed exactly as suggested: separated TMP_DIR=$(mktemp -d) into its own bare assignment (which set -e does reliably catch), and replaced the manual rm -rf with a trap scoped to that one known path. Verified both the normal path and two forced-failure cases (bad cp, and a simulated mktemp failure) behave correctly now.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.claude/skills/package-plugins/SKILL.md:
- Around line 24-37: Update both packaging recipes in the skill documentation so
zip writes the archive to a path under TMP_DIR, not directly under dist. After
zip succeeds, move the completed archive into dist; preserve the existing
cleanup and final artifact names while ensuring failed zip commands cannot leave
partial release archives in dist.
- Around line 24-38: The packaging script’s trailing composer install is skipped
when staging or archiving fails, leaving development dependencies uninstalled.
Update the packaging flow around the existing TMP_DIR EXIT trap and composer
install commands so that, after a successful composer install --no-dev, an
EXIT/finally cleanup path always runs composer install to restore dev tooling
while preserving the original command’s exit status.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0a9a7741-abfd-482b-bc07-8b1db65147a3

📥 Commits

Reviewing files that changed from the base of the PR and between b3bce1f and 7f30fed.

📒 Files selected for processing (1)
  • .claude/skills/package-plugins/SKILL.md

Comment thread .claude/skills/package-plugins/SKILL.md
Comment thread .claude/skills/package-plugins/SKILL.md
@pattonwebz
pattonwebz merged commit 1efc2ab into main Jul 17, 2026
12 checks passed
@pattonwebz
pattonwebz deleted the william/pro-1196-plugin-check-findings branch July 17, 2026 20:41
@pattonwebz

Copy link
Copy Markdown
Member Author

Following up now that this is merged (CodeRabbit's review didn't finish reviewing the last two pushes in time, so noting here for the record — it'll help future reviews on this repo learn the pattern):

What changed and why, since your Critical finding on .claude/skills/package-plugins/SKILL.md:

Fixed exactly as you suggested, in commit 7f30fed:

  • Added set -euo pipefail to both the free and Pro packaging blocks.
  • Split STAGE=$(mktemp -d)/boardscribe into a bare TMP_DIR=$(mktemp -d) assignment followed by STAGE="$TMP_DIR/boardscribe". I verified empirically first that this split matters, not just stylistically: a bare TMP_DIR=$(mktemp -d) reliably aborts the script under set -e if mktemp fails, but the original concatenated form STAGE=$(mktemp -d)/boardscribe does not — bash doesn't propagate the inner command's failure through string concatenation, so STAGE silently became the literal string /boardscribe in my test, with the assignment itself reporting exit code 0.
  • Replaced the manual rm -rf "$(dirname "$STAGE")" with trap 'rm -rf -- "$TMP_DIR"' EXIT, scoped to the one known temp path rather than a computed dirname that could resolve to / in the failure case above.

Verified with three real test runs (not just reading the diff): the normal path still produces a correct zip and cleans up; a forced cp failure now aborts immediately instead of continuing to zip a partial staging dir, and the trap still fires; a forced mktemp failure now correctly aborts under set -e where before it silently would not have.

One related finding from the same PR that's since been reverted, for context if you re-review this file later: an earlier commit (30a392e) also added composer.json to both release zips to clear a separate Plugin Check warning (missing_composer_json_file) — that was intentionally reverted in b3bce1f (kept as an accepted warning, documented in the skill doc's rule 4) since it's warning-level, not blocking, and the team didn't want dev-tooling config in the release artifact. So if a future review of this file flags composer.json as excluded, that's deliberate, not an oversight.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant