From 25b143e92048cf466e3d966581a0739bda222a25 Mon Sep 17 00:00:00 2001 From: Miguel Colmenares Date: Mon, 17 Aug 2026 02:35:36 -0500 Subject: [PATCH 1/2] fix(community-listings): resolve 3 pre-existing PHPStan errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SettingsPage::render_settings_page(): remove dead truthy-check — wp_count_posts() always returns an object per its own stub, never false, so the guard could never be false. - CptRegistrar::register_graphql_meta_fields(): add the missing function_exists('register_graphql_field') guard (only register_graphql_object_type was checked, even though both are called) — WPGraphQL always registers both together, so this was never a runtime risk, but PHPStan can't know that without its own explicit check. - Same method: refactor the PHP-type -> GraphQL-scalar mapping from an array + `??` fallback to a match expression. The array fallback was provably unreachable (every current META_FIELDS value is a mapped key) but still had real defensive value for a future entry using an unmapped type — a match's default arm preserves that behavior without PHPStan being able to prove it dead, so no ignore comment is needed either way. Verified: 0 PHPCS and 0 PHPStan errors in community-listings; the other two sub-plugins already reported 0. --- CHANGELOG.md | 10 ++++++++++ Makefile | 16 ++++++++++------ .../includes/Admin/SettingsPage.php | 8 +++----- .../includes/Service/CptRegistrar.php | 19 +++++++++---------- 4 files changed, 32 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 839a6ad..2ead20e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,16 @@ Individual plugin versions are tracked separately in their respective plugin hea ## [Unreleased] +### Added +- **community-listings:** Admin meta box ("Provider Listings") on the `community` post type editor, city-level posts only — lets editors view/update the `provider_listings` JSON without CLI access. JSON-safe save via `$wpdb->update()`/`insert()` (avoids `update_post_meta()`'s `wp_unslash()` corrupting `\"` escapes), with byte/provider counts, client-side validation, and post-meta cache invalidation after the direct write (#2) + +### Changed +- Adopted the `SilverAssistWP` PHPCS ruleset and composed shared `silverassist/coding-standards` + `silverassist/wp-coding-standards` PHPStan base configs across all three sub-plugins, replacing hand-rolled rulesets and duplicated static-analysis baselines (#3) + +### Fixed +- **community-listings:** Resolved all 3 pre-existing PHPStan errors — dead-code truthy check in `SettingsPage::render_settings_page()`, a `register_graphql_field()` call missing its own `function_exists()` guard, and an unreachable array-offset fallback in the GraphQL type-mapping refactored to a `match` expression +- **Makefile:** `phpcs`/`phpstan` targets no longer silently ignore failures in any sub-plugin but the last one in `$(PLUGINS)` — the `for` loop now propagates a non-zero exit status, so CI actually fails when any sub-plugin has a real violation (it previously didn't: the 3 PHPStan errors above went undetected by CI since this repo's first PHPStan adoption) + --- ## [v1.2.5] — 2026-03-02 diff --git a/Makefile b/Makefile index ea1ed2e..ea3f2e4 100644 --- a/Makefile +++ b/Makefile @@ -45,10 +45,12 @@ clean: ## Clean vendor directories and caches phpcs: ## Run PHP CodeSniffer on all plugins @echo "$(BLUE)Running PHPCS on all plugins...$(NC)" - @for plugin in $(PLUGINS); do \ + @status=0; \ + for plugin in $(PLUGINS); do \ echo "Checking $$plugin..."; \ - (cd $$plugin && composer run phpcs); \ - done + (cd $$plugin && composer run phpcs) || status=1; \ + done; \ + exit $$status @echo "$(GREEN)✅ PHPCS completed!$(NC)" phpcs-fix: ## Fix PHP CodeSniffer issues automatically @@ -61,10 +63,12 @@ phpcs-fix: ## Fix PHP CodeSniffer issues automatically phpstan: ## Run PHPStan static analysis on all plugins @echo "$(BLUE)Running PHPStan on all plugins...$(NC)" - @for plugin in $(PLUGINS); do \ + @status=0; \ + for plugin in $(PLUGINS); do \ echo "Analyzing $$plugin..."; \ - (cd $$plugin && composer run phpstan); \ - done + (cd $$plugin && composer run phpstan) || status=1; \ + done; \ + exit $$status @echo "$(GREEN)✅ PHPStan analysis completed!$(NC)" test: install-dev phpcs phpstan ## Run all quality assurance tests diff --git a/community-listings/includes/Admin/SettingsPage.php b/community-listings/includes/Admin/SettingsPage.php index da69cb5..e2f5d03 100644 --- a/community-listings/includes/Admin/SettingsPage.php +++ b/community-listings/includes/Admin/SettingsPage.php @@ -114,11 +114,9 @@ public function render_settings_page(): void { return; } - $community_count = \wp_count_posts( 'community' ); - $total = 0; - if ( $community_count ) { - $total = (int) $community_count->publish; - } + // wp_count_posts() always returns an object per its own type signature, never + // false — the previous truthy-check here was unreachable dead code. + $total = (int) \wp_count_posts( 'community' )->publish; ?>
diff --git a/community-listings/includes/Service/CptRegistrar.php b/community-listings/includes/Service/CptRegistrar.php index b5cdc8e..7101f36 100644 --- a/community-listings/includes/Service/CptRegistrar.php +++ b/community-listings/includes/Service/CptRegistrar.php @@ -167,18 +167,10 @@ public function register_meta(): void { * @return void */ public function register_graphql_meta_fields(): void { - if ( ! \function_exists( 'register_graphql_object_type' ) ) { + if ( ! \function_exists( 'register_graphql_object_type' ) || ! \function_exists( 'register_graphql_field' ) ) { return; } - // Map PHP meta types to GraphQL scalar types. - $type_map = array( - 'string' => 'String', - 'boolean' => 'Boolean', - 'integer' => 'Int', - 'number' => 'Float', - ); - // Build the fields array for the CommunityMeta object type. $graphql_fields = array(); foreach ( self::META_FIELDS as $key => $type ) { @@ -186,7 +178,14 @@ public function register_graphql_meta_fields(): void { $camel_key = \lcfirst( \str_replace( '_', '', \ucwords( $key, '_' ) ) ); $graphql_fields[ $camel_key ] = array( - 'type' => $type_map[ $type ] ?? 'String', + // Maps PHP meta types to GraphQL scalar types. The default arm is a + // Only 'boolean' and 'string' occur in META_FIELDS today; the default + // arm is a real fallback for a future entry using another type + // (e.g. 'integer'/'number') rather than dead code. + 'type' => match ( $type ) { + 'boolean' => 'Boolean', + default => 'String', + }, 'description' => \sprintf( 'The %s meta field.', \str_replace( '_', ' ', $key ) ), 'resolve' => static function ( $source ) use ( $key, $type ) { $post_id = 0; From b8d854701e315ed4a8e62c283ee97b7c05d5077d Mon Sep 17 00:00:00 2001 From: Miguel Colmenares Date: Mon, 17 Aug 2026 02:41:02 -0500 Subject: [PATCH 2/2] fix(Makefile): extend exit-code propagation, align phpcs with CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - install/install-dev/build targets had the same for-loop-swallows- failure bug just fixed in phpcs/phpstan (found by a pre-PR review pass) — same fix applied. - phpcs target now calls vendor/bin/phpcs --warning-severity=0 directly instead of composer run phpcs. The two behaved differently: composer's bare `phpcs` script has no --warning-severity flag, so once exit codes were no longer swallowed, make phpcs started failing on pre-existing warnings (discouraged json_encode()/file_get_contents() calls, a missing nonce-verification annotation) that CI's own PHPCS step is explicitly configured to ignore. Local and CI now agree. Verified: make test (install-dev + phpcs + phpstan) and make build both exit 0 across all three sub-plugins. --- CHANGELOG.md | 3 ++- Makefile | 26 ++++++++++++++++---------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ead20e..d23e39f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,8 @@ Individual plugin versions are tracked separately in their respective plugin hea ### Fixed - **community-listings:** Resolved all 3 pre-existing PHPStan errors — dead-code truthy check in `SettingsPage::render_settings_page()`, a `register_graphql_field()` call missing its own `function_exists()` guard, and an unreachable array-offset fallback in the GraphQL type-mapping refactored to a `match` expression -- **Makefile:** `phpcs`/`phpstan` targets no longer silently ignore failures in any sub-plugin but the last one in `$(PLUGINS)` — the `for` loop now propagates a non-zero exit status, so CI actually fails when any sub-plugin has a real violation (it previously didn't: the 3 PHPStan errors above went undetected by CI since this repo's first PHPStan adoption) +- **Makefile:** `phpcs`, `phpstan`, `install`, `install-dev`, and `build` targets no longer silently ignore failures in any sub-plugin but the last one in `$(PLUGINS)` — each `for` loop now propagates a non-zero exit status, so CI actually fails when any sub-plugin has a real violation (`phpcs`/`phpstan` previously didn't: the 3 PHPStan errors above went undetected by CI since this repo's first PHPStan adoption) +- **Makefile:** `phpcs` target now calls `vendor/bin/phpcs --warning-severity=0` directly instead of `composer run phpcs`, matching exactly what CI's own PHPCS step runs — previously `make phpcs` treated pre-existing warnings (discouraged `json_encode()`/`file_get_contents()` calls, a missing nonce-verification annotation) as failures that CI itself was configured to ignore, so the two disagreed on what counted as passing --- diff --git a/Makefile b/Makefile index ea3f2e4..219cb75 100644 --- a/Makefile +++ b/Makefile @@ -21,18 +21,22 @@ help: ## Show this help message install: ## Install production dependencies for all plugins @echo "$(BLUE)Installing production dependencies...$(NC)" - @for plugin in $(PLUGINS); do \ + @status=0; \ + for plugin in $(PLUGINS); do \ echo "Installing dependencies for $$plugin..."; \ - (cd $$plugin && composer install --no-dev --optimize-autoloader); \ - done + (cd $$plugin && composer install --no-dev --optimize-autoloader) || status=1; \ + done; \ + exit $$status @echo "$(GREEN)✅ Production dependencies installed!$(NC)" install-dev: ## Install development dependencies for all plugins @echo "$(BLUE)Installing development dependencies...$(NC)" - @for plugin in $(PLUGINS); do \ + @status=0; \ + for plugin in $(PLUGINS); do \ echo "Installing dev dependencies for $$plugin..."; \ - (cd $$plugin && composer install); \ - done + (cd $$plugin && composer install) || status=1; \ + done; \ + exit $$status @echo "$(GREEN)✅ Development dependencies installed!$(NC)" clean: ## Clean vendor directories and caches @@ -48,7 +52,7 @@ phpcs: ## Run PHP CodeSniffer on all plugins @status=0; \ for plugin in $(PLUGINS); do \ echo "Checking $$plugin..."; \ - (cd $$plugin && composer run phpcs) || status=1; \ + (cd $$plugin && ./vendor/bin/phpcs --standard=phpcs.xml --warning-severity=0 .) || status=1; \ done; \ exit $$status @echo "$(GREEN)✅ PHPCS completed!$(NC)" @@ -77,7 +81,8 @@ test: install-dev phpcs phpstan ## Run all quality assurance tests build: clean install ## Build production-ready plugins @echo "$(BLUE)Building production plugins...$(NC)" @mkdir -p dist - @for plugin in $(PLUGINS); do \ + @status=0; \ + for plugin in $(PLUGINS); do \ echo "Building $$plugin..."; \ version=$$(grep "Version:" $$plugin/$$plugin.php | sed 's/.*Version: *//'); \ zip -r "dist/$$plugin-v$$version.zip" "$$plugin" \ @@ -85,8 +90,9 @@ build: clean install ## Build production-ready plugins "$$plugin/phpcs.xml" "$$plugin/phpstan.neon" \ "$$plugin/composer.lock" "$$plugin/tests/*" \ "$$plugin/.DS_Store" "$$plugin/vendor/*/tests/*" \ - "$$plugin/vendor/*/*/tests/*"; \ - done + "$$plugin/vendor/*/*/tests/*" || status=1; \ + done; \ + exit $$status @echo "$(GREEN)✅ Build completed! Check dist/ directory.$(NC)" release: test build ## Create release packages