build: 移植 PHPCS + PHPStan L6 品質 gate(PR-I 前半)

- phpcs.xml(自 A 移植):ruleset 改名、*/tools/* 例外換成 */back-compat/*、
  中文註解全域排除 Squiz.Commenting.InlineComment.InvalidEndChar、
  interface 別名檔排除 OneObjectStructurePerFile
- 檔頭正規化:16 個檔案的 declare(strict_types=1) 與前導 // 註解移到
  file docblock 之後,並移除 <?php 後多餘空行(phpcbf 另自動修 190 處)
- phpstan.neon + .phpstan/stubs.php(TMDO_ 與 WPDO_ 兩套常數)+
  重新產生的 phpstan-baseline.neon(710 errors,A 的 3877 行 baseline
  因前綴與路徑不同無法沿用)

現況:PHPCS 0 errors / 0 warnings、PHPStan L6 No errors、
unit 451 / integration 398 GREEN

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TbG1keQQ7XBa7qMQY16KCY
This commit is contained in:
2026-07-31 06:22:00 +08:00
parent 76c01e44df
commit f524ea3f16
23 changed files with 4356 additions and 340 deletions
+1
View File
@@ -14,3 +14,4 @@ Thumbs.db
.playwright-mcp/ .playwright-mcp/
.claude/ .claude/
dist/ dist/
.phpcs-cache
+34
View File
@@ -0,0 +1,34 @@
<?php
/**
* PHPStan bootstrap stubs — plugin constants defined at runtime.
*
* PHPStan cannot see define()'d constants, so it reports "undefined constant"
* for every one of them. Stubbing them here keeps level 6 signal-to-noise high.
*
* TMDO_IS_SQLITE / TMDO_IS_MYSQL (and their WPDO_ aliases) are intentionally
* NOT stubbed to avoid literal-narrowing "always true/false" false positives
* on runtime-dynamic values.
*
* @package TMDO
*/
declare(strict_types=1);
define( 'TMDO_VERSION', '0.0.0' );
define( 'TMDO_DB_VERSION', '0.0.0' );
define( 'TMDO_PATH', '/' );
define( 'TMDO_URL', 'https://example.test/wp-content/plugins/2meet-data-optimizer/' );
define( 'TMDO_FILE', '/2meet-data-optimizer.php' );
define( 'TMDO_TABLE_PREFIX', 'wpdo_' );
define( 'TMDO_CACHE_GROUP', 'wpdo' );
define( 'TMDO_MIN_PHP', '8.1' );
define( 'TMDO_MIN_WP', '6.0' );
// Back-compat aliases exposed by class-tmdo-back-compat.php.
define( 'WPDO_VERSION', '0.0.0' );
define( 'WPDO_DB_VERSION', '0.0.0' );
define( 'WPDO_PLUGIN_DIR', '/' );
define( 'WPDO_PLUGIN_URL', 'https://example.test/wp-content/plugins/2meet-data-optimizer/' );
define( 'WPDO_PLUGIN_FILE', '/2meet-data-optimizer.php' );
define( 'WPDO_TABLE_PREFIX', 'wpdo_' );
define( 'WPDO_CACHE_GROUP', 'wpdo' );
+4 -3
View File
@@ -1,13 +1,14 @@
<?php <?php
declare(strict_types=1);
// phpcs:ignore WPDO.AntiEAV -- platform admin UI: native meta queries for management dashboard
/** /**
* WP Data Optimizer admin UI class. * WP Data Optimizer admin UI class.
* *
* @package WP_Data_Optimizer * @package WP_Data_Optimizer
*/ */
// phpcs:ignore WPDO.AntiEAV -- platform admin UI: native meta queries for management dashboard
declare(strict_types=1);
if ( ! defined( 'ABSPATH' ) ) { if ( ! defined( 'ABSPATH' ) ) {
exit; exit;
} }
+4 -3
View File
@@ -1,7 +1,4 @@
<?php <?php
declare(strict_types=1);
// phpcs:ignore WPDO.AntiEAV -- platform admin UI: native postmeta count for dashboard widget
/** /**
* TMDO_Dashboard_Widget — wp-admin home dashboard widget (v2.4.0 M9). * TMDO_Dashboard_Widget — wp-admin home dashboard widget (v2.4.0 M9).
* *
@@ -17,6 +14,10 @@ declare(strict_types=1);
* @package WP_Data_Optimizer * @package WP_Data_Optimizer
*/ */
// phpcs:ignore WPDO.AntiEAV -- platform admin UI: native postmeta count for dashboard widget
declare(strict_types=1);
if ( ! defined( 'ABSPATH' ) ) { if ( ! defined( 'ABSPATH' ) ) {
exit; exit;
} }
+4 -3
View File
@@ -1,7 +1,4 @@
<?php <?php
declare(strict_types=1);
// phpcs:ignore WPDO.AntiEAV -- platform admin UI: postmeta inventory for setup wizard
/** /**
* TMDO_Setup_Wizard — First-run onboarding wizard (v2.3.0 M5). * TMDO_Setup_Wizard — First-run onboarding wizard (v2.3.0 M5).
* *
@@ -22,6 +19,10 @@ declare(strict_types=1);
* @package WP_Data_Optimizer * @package WP_Data_Optimizer
*/ */
// phpcs:ignore WPDO.AntiEAV -- platform admin UI: postmeta inventory for setup wizard
declare(strict_types=1);
if ( ! defined( 'ABSPATH' ) ) { if ( ! defined( 'ABSPATH' ) ) {
exit; exit;
} }
+4 -3
View File
@@ -1,7 +1,4 @@
<?php <?php
declare(strict_types=1);
// phpcs:ignore WPDO.AntiEAV -- platform admin UI: stress test SQL example display
/** /**
* Comment Stress Test template (v2.13.1). * Comment Stress Test template (v2.13.1).
* *
@@ -18,6 +15,10 @@ declare(strict_types=1);
* @package WP_Data_Optimizer * @package WP_Data_Optimizer
*/ */
// phpcs:ignore WPDO.AntiEAV -- platform admin UI: stress test SQL example display
declare(strict_types=1);
if ( ! defined( 'ABSPATH' ) ) { if ( ! defined( 'ABSPATH' ) ) {
exit; exit;
} }
+4 -3
View File
@@ -1,7 +1,4 @@
<?php <?php
declare(strict_types=1);
// phpcs:ignore WPDO.AntiEAV -- platform admin UI: stress test SQL example display
/** /**
* Term Stress Test template (v2.13.0). * Term Stress Test template (v2.13.0).
* *
@@ -18,6 +15,10 @@ declare(strict_types=1);
* @package WP_Data_Optimizer * @package WP_Data_Optimizer
*/ */
// phpcs:ignore WPDO.AntiEAV -- platform admin UI: stress test SQL example display
declare(strict_types=1);
if ( ! defined( 'ABSPATH' ) ) { if ( ! defined( 'ABSPATH' ) ) {
exit; exit;
} }
+4 -3
View File
@@ -1,7 +1,4 @@
<?php <?php
declare(strict_types=1);
// phpcs:ignore WPDO.AntiEAV -- platform CLI inspector tool: raw meta queries needed for diagnostics
/** /**
* TMDO_CLI_Member — Member flat-table CLI subcommands. * TMDO_CLI_Member — Member flat-table CLI subcommands.
* *
@@ -19,6 +16,10 @@ declare(strict_types=1);
* @since 2.5.5 * @since 2.5.5
*/ */
// phpcs:ignore WPDO.AntiEAV -- platform CLI inspector tool: raw meta queries needed for diagnostics
declare(strict_types=1);
if ( ! defined( 'ABSPATH' ) ) { if ( ! defined( 'ABSPATH' ) ) {
exit; exit;
} }
+4 -3
View File
@@ -1,7 +1,4 @@
<?php <?php
declare(strict_types=1);
// phpcs:ignore WPDO.AntiEAV -- platform CLI inspector tool: raw meta queries needed for diagnostics
/** /**
* TMDO_CLI_Post — Post entity CLI subcommands (v2.9.0+). * TMDO_CLI_Post — Post entity CLI subcommands (v2.9.0+).
* *
@@ -18,6 +15,10 @@ declare(strict_types=1);
* @since 2.9.0 * @since 2.9.0
*/ */
// phpcs:ignore WPDO.AntiEAV -- platform CLI inspector tool: raw meta queries needed for diagnostics
declare(strict_types=1);
if ( ! defined( 'ABSPATH' ) ) { if ( ! defined( 'ABSPATH' ) ) {
exit; exit;
} }
+4 -3
View File
@@ -1,7 +1,4 @@
<?php <?php
declare(strict_types=1);
// phpcs:ignore WPDO.AntiEAV -- platform CLI inspector tool: raw meta queries needed for diagnostics
/** /**
* TMDO_CLI_Term_Comment — Term + Comment entity CLI subcommands (v2.12.0+). * TMDO_CLI_Term_Comment — Term + Comment entity CLI subcommands (v2.12.0+).
* *
@@ -21,6 +18,10 @@ declare(strict_types=1);
* @since 2.12.0 * @since 2.12.0
*/ */
// phpcs:ignore WPDO.AntiEAV -- platform CLI inspector tool: raw meta queries needed for diagnostics
declare(strict_types=1);
if ( ! defined( 'ABSPATH' ) ) { if ( ! defined( 'ABSPATH' ) ) {
exit; exit;
} }
+4 -3
View File
@@ -1,7 +1,4 @@
<?php <?php
declare(strict_types=1);
// phpcs:ignore WPDO.AntiEAV -- platform diagnostic: raw meta inspection for FSM state advisor
/** /**
* TMDO_FSM_Advisor — Recommends the next FSM state per module (v2.4.0 M12). * TMDO_FSM_Advisor — Recommends the next FSM state per module (v2.4.0 M12).
* *
@@ -24,6 +21,10 @@ declare(strict_types=1);
* @package WP_Data_Optimizer * @package WP_Data_Optimizer
*/ */
// phpcs:ignore WPDO.AntiEAV -- platform diagnostic: raw meta inspection for FSM state advisor
declare(strict_types=1);
if ( ! defined( 'ABSPATH' ) ) { if ( ! defined( 'ABSPATH' ) ) {
exit; exit;
} }
@@ -1,7 +1,4 @@
<?php <?php
declare(strict_types=1);
// phpcs:ignore WPDO.AntiEAV -- platform stress tester: intentional raw meta SQL for baseline comparison
/** /**
* TMDO_Comment_Stress_Tester — Async stress fixture generator for comment entity (v2.13.1). * TMDO_Comment_Stress_Tester — Async stress fixture generator for comment entity (v2.13.1).
* *
@@ -23,6 +20,10 @@ declare(strict_types=1);
* @since 2.13.1 * @since 2.13.1
*/ */
// phpcs:ignore WPDO.AntiEAV -- platform stress tester: intentional raw meta SQL for baseline comparison
declare(strict_types=1);
if ( ! defined( 'ABSPATH' ) ) { if ( ! defined( 'ABSPATH' ) ) {
exit; exit;
} }
+4 -3
View File
@@ -1,7 +1,4 @@
<?php <?php
declare(strict_types=1);
// phpcs:ignore WPDO.AntiEAV -- platform shadow verifier: must read raw meta to verify zone correctness
/** /**
* TMDO_Post_Shadow_Verifier — Sample-and-compare flat vs wp_postmeta (v2.10.3). * TMDO_Post_Shadow_Verifier — Sample-and-compare flat vs wp_postmeta (v2.10.3).
* *
@@ -24,6 +21,10 @@ declare(strict_types=1);
* @since 2.10.3 * @since 2.10.3
*/ */
// phpcs:ignore WPDO.AntiEAV -- platform shadow verifier: must read raw meta to verify zone correctness
declare(strict_types=1);
if ( ! defined( 'ABSPATH' ) ) { if ( ! defined( 'ABSPATH' ) ) {
exit; exit;
} }
+4 -3
View File
@@ -1,7 +1,4 @@
<?php <?php
declare(strict_types=1);
// phpcs:ignore WPDO.AntiEAV -- platform stress tester: intentional raw meta SQL for baseline comparison
/** /**
* TMDO_Post_Stress_Tester — Bulk fixture generator for post entity migration (v2.9.4). * TMDO_Post_Stress_Tester — Bulk fixture generator for post entity migration (v2.9.4).
* *
@@ -28,6 +25,10 @@ declare(strict_types=1);
* @since 2.9.4 * @since 2.9.4
*/ */
// phpcs:ignore WPDO.AntiEAV -- platform stress tester: intentional raw meta SQL for baseline comparison
declare(strict_types=1);
if ( ! defined( 'ABSPATH' ) ) { if ( ! defined( 'ABSPATH' ) ) {
exit; exit;
} }
+4 -3
View File
@@ -1,7 +1,4 @@
<?php <?php
declare(strict_types=1);
// phpcs:ignore WPDO.AntiEAV -- platform stress tester: intentional raw meta SQL for baseline comparison
/** /**
* TMDO_Term_Stress_Tester — Async stress fixture generator for term entity (v2.13.0). * TMDO_Term_Stress_Tester — Async stress fixture generator for term entity (v2.13.0).
* *
@@ -24,6 +21,10 @@ declare(strict_types=1);
* @since 2.13.0 * @since 2.13.0
*/ */
// phpcs:ignore WPDO.AntiEAV -- platform stress tester: intentional raw meta SQL for baseline comparison
declare(strict_types=1);
if ( ! defined( 'ABSPATH' ) ) { if ( ! defined( 'ABSPATH' ) ) {
exit; exit;
} }
+4 -3
View File
@@ -1,7 +1,4 @@
<?php <?php
declare(strict_types=1);
// phpcs:ignore WPDO.AntiEAV -- platform stress tester: intentional raw meta SQL for baseline comparison
/** /**
* TMDO_User_Stress_Tester — User entity 壓力測試 / Benchmark 工具 * TMDO_User_Stress_Tester — User entity 壓力測試 / Benchmark 工具
* *
@@ -18,6 +15,10 @@ declare(strict_types=1);
* @since 2.6.7 * @since 2.6.7
*/ */
// phpcs:ignore WPDO.AntiEAV -- platform stress tester: intentional raw meta SQL for baseline comparison
declare(strict_types=1);
// phpcs:disable Squiz.Commenting,Generic.Commenting,WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber,WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare,Generic.CodeAnalysis.UnusedFunctionParameter,WordPress.WP.I18n.MissingTranslatorsComment,WordPress.PHP.NoSilencedErrors,WordPress.PHP.YodaConditions,WordPress.WP.AlternativeFunctions.rand_mt_rand,WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize -- 測試工具:mt_rand 用於杜撰測試資料;serialize() 為 WP capabilities 標準格式 // phpcs:disable Squiz.Commenting,Generic.Commenting,WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber,WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare,Generic.CodeAnalysis.UnusedFunctionParameter,WordPress.WP.I18n.MissingTranslatorsComment,WordPress.PHP.NoSilencedErrors,WordPress.PHP.YodaConditions,WordPress.WP.AlternativeFunctions.rand_mt_rand,WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize -- 測試工具:mt_rand 用於杜撰測試資料;serialize() 為 WP capabilities 標準格式
defined( 'ABSPATH' ) || exit; defined( 'ABSPATH' ) || exit;
@@ -1,7 +1,4 @@
<?php <?php
declare(strict_types=1);
// phpcs:ignore WPDO.AntiEAV -- platform diagnostic: raw meta inspection for site health
/** /**
* TMDO_Site_Health — WordPress Site Health integration (v2.2.0 M3). * TMDO_Site_Health — WordPress Site Health integration (v2.2.0 M3).
* *
@@ -19,6 +16,10 @@ declare(strict_types=1);
* @package WP_Data_Optimizer * @package WP_Data_Optimizer
*/ */
// phpcs:ignore WPDO.AntiEAV -- platform diagnostic: raw meta inspection for site health
declare(strict_types=1);
if ( ! defined( 'ABSPATH' ) ) { if ( ! defined( 'ABSPATH' ) ) {
exit; exit;
} }
@@ -1,7 +1,4 @@
<?php <?php
declare(strict_types=1);
// phpcs:ignore WPDO.AntiEAV -- platform migration tool: WPDO v1->v2 legacy post meta migration
/** /**
* TMDO_Post_Migration — Post entity migration core (v2.9.3). * TMDO_Post_Migration — Post entity migration core (v2.9.3).
* *
@@ -35,6 +32,10 @@ declare(strict_types=1);
* @since 2.9.3 * @since 2.9.3
*/ */
// phpcs:ignore WPDO.AntiEAV -- platform migration tool: WPDO v1->v2 legacy post meta migration
declare(strict_types=1);
if ( ! defined( 'ABSPATH' ) ) { if ( ! defined( 'ABSPATH' ) ) {
exit; exit;
} }
+2 -2
View File
@@ -31,7 +31,7 @@ if ( ! defined( 'ABSPATH' ) ) {
// the same trait body in memory. // the same trait body in memory.
if ( ! trait_exists( 'TMDO_Anti_EAV_Aware' ) ) { if ( ! trait_exists( 'TMDO_Anti_EAV_Aware' ) ) {
trait TMDO_Anti_EAV_Aware { trait TMDO_Anti_EAV_Aware {
/** /**
* Plugin slug used as provider identifier when registering fields/tables. * Plugin slug used as provider identifier when registering fields/tables.
@@ -208,6 +208,6 @@ trait TMDO_Anti_EAV_Aware {
public static function register_custom_tables(): void { public static function register_custom_tables(): void {
// No-op default. // No-op default.
} }
} }
} // end if ( ! trait_exists ) } // end if ( ! trait_exists )
+245
View File
@@ -0,0 +1,245 @@
<?xml version="1.0"?>
<ruleset name="2meet Data Optimizer">
<description>WPCS ruleset for WP Data Optimizer plugin.</description>
<!-- Scan these files/directories -->
<file>.</file>
<!-- Exclude vendor and test directories -->
<exclude-pattern>*/vendor/*</exclude-pattern>
<exclude-pattern>*/tests/*</exclude-pattern>
<exclude-pattern>*/back-compat/*</exclude-pattern>
<exclude-pattern>*/node_modules/*</exclude-pattern>
<!-- v2.13.4: JS files are out of PHPCS scope (use ESLint instead) -->
<exclude-pattern>*/admin/assets/*.js</exclude-pattern>
<!-- Only lint PHP files -->
<arg name="extensions" value="php"/>
<!--
UAE-ported files: includes/adapters/ and includes/engine/ were ported wholesale
from UAE in PR-1. File-level phpcs:disable comments have been replaced with these
sniff-level directory exclusions. Auto-fixable violations (7) were fixed with phpcbf.
Rules already globally excluded (NotPrepared, NoSilencedErrors, file_get_contents,
UnusedFunctionParameter) are not repeated here.
-->
<!-- Doc-comment style sniffs: FunctionComment, ClassComment, InlineComment, etc. -->
<rule ref="Squiz.Commenting.FunctionComment">
<exclude-pattern>*/includes/adapters/*</exclude-pattern>
<exclude-pattern>*/includes/engine/*</exclude-pattern>
</rule>
<rule ref="Squiz.Commenting.ClassComment">
<exclude-pattern>*/includes/adapters/*</exclude-pattern>
<exclude-pattern>*/includes/engine/*</exclude-pattern>
</rule>
<rule ref="Squiz.Commenting.FileComment">
<exclude-pattern>*/includes/adapters/*</exclude-pattern>
<exclude-pattern>*/includes/engine/*</exclude-pattern>
</rule>
<rule ref="Squiz.Commenting.InlineComment">
<exclude-pattern>*/includes/adapters/*</exclude-pattern>
<exclude-pattern>*/includes/engine/*</exclude-pattern>
<!-- Comments in this codebase are predominantly Chinese; the sniff only
accepts . ! ? as terminators, so 。 always trips it. -->
<exclude name="Squiz.Commenting.InlineComment.InvalidEndChar"/>
</rule>
<!-- interface-entity-adapter.php declares the WPDO_ alias interface next to
the real one on purpose, so `instanceof WPDO_Entity_Adapter_Interface`
works for classes implementing the TMDO_ name. -->
<rule ref="Generic.Files.OneObjectStructurePerFile">
<exclude-pattern>*/includes/adapters/interface-entity-adapter.php</exclude-pattern>
<exclude-pattern>*/includes/back-compat/*</exclude-pattern>
</rule>
<rule ref="Squiz.Commenting.VariableComment">
<exclude-pattern>*/includes/adapters/*</exclude-pattern>
<exclude-pattern>*/includes/engine/*</exclude-pattern>
</rule>
<rule ref="Generic.Commenting.DocComment">
<exclude-pattern>*/includes/adapters/*</exclude-pattern>
<exclude-pattern>*/includes/engine/*</exclude-pattern>
</rule>
<!-- PHP style / structure sniffs -->
<rule ref="Squiz.PHP.DisallowMultipleAssignments">
<exclude-pattern>*/includes/adapters/*</exclude-pattern>
<exclude-pattern>*/includes/engine/*</exclude-pattern>
</rule>
<rule ref="Squiz.PHP.DisallowSizeFunctionsInLoops">
<exclude-pattern>*/includes/adapters/*</exclude-pattern>
<exclude-pattern>*/includes/engine/*</exclude-pattern>
</rule>
<rule ref="Squiz.PHP.CommentedOutCode">
<exclude-pattern>*/includes/adapters/*</exclude-pattern>
<exclude-pattern>*/includes/engine/*</exclude-pattern>
</rule>
<!-- WordPress-specific sniffs -->
<rule ref="WordPress.DB.PreparedSQL.InterpolatedNotPrepared">
<exclude-pattern>*/includes/adapters/*</exclude-pattern>
<exclude-pattern>*/includes/engine/*</exclude-pattern>
</rule>
<rule ref="WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber">
<exclude-pattern>*/includes/adapters/*</exclude-pattern>
<exclude-pattern>*/includes/engine/*</exclude-pattern>
</rule>
<rule ref="WordPress.PHP.YodaConditions">
<exclude-pattern>*/includes/adapters/*</exclude-pattern>
<exclude-pattern>*/includes/engine/*</exclude-pattern>
</rule>
<rule ref="WordPress.WP.I18n.MissingTranslatorsComment">
<exclude-pattern>*/includes/adapters/*</exclude-pattern>
<exclude-pattern>*/includes/engine/*</exclude-pattern>
</rule>
<!-- Universal naming: avoids PHP reserved words as param names -->
<rule ref="Universal.NamingConventions.NoReservedKeywordParameterNames">
<exclude-pattern>*/includes/adapters/*</exclude-pattern>
<exclude-pattern>*/includes/engine/*</exclude-pattern>
</rule>
<!--
Migration phase objects: throw new \RuntimeException(...) is never echoed to
the browser — it is caught by WPDO_Migration_Orchestrator and turned into a
structured array. EscapeOutput fires on the raw string inside the throw expression.
-->
<rule ref="WordPress.Security.EscapeOutput">
<exclude-pattern>*/migration/phases/*</exclude-pattern>
</rule>
<!--
Migration phase SQL: table names come from WPDO_DB::table() / $wpdb core
properties and are sanitized by Schema_Manager::sanitize_column_name().
User-controlled values always go through $wpdb->prepare() placeholders.
-->
<rule ref="WordPress.DB.PreparedSQL.InterpolatedNotPrepared">
<exclude-pattern>*/migration/phases/*</exclude-pattern>
</rule>
<!--
WP-CLI callbacks must accept ($args, $assoc_args) by framework contract.
MissingParamTag fires when only one of the two is used.
ShortNotCapital fires on WP-CLI-style imperative command descriptions.
-->
<rule ref="Squiz.Commenting.FunctionComment.MissingParamTag">
<exclude-pattern>*/cli/*</exclude-pattern>
</rule>
<rule ref="Generic.Commenting.DocComment.ShortNotCapital">
<exclude-pattern>*/cli/*</exclude-pattern>
</rule>
<!-- Use WordPress Coding Standards -->
<rule ref="WordPress">
<!--
This plugin IS the database optimization layer.
Direct DB queries are intentional and by design.
-->
<exclude name="WordPress.DB.DirectDatabaseQuery.DirectQuery" />
<exclude name="WordPress.DB.DirectDatabaseQuery.NoCaching" />
<exclude name="WordPress.DB.DirectDatabaseQuery.SchemaChange" />
<!--
Slow DB queries (meta_key / meta_value) are intentional —
the plugin migrates data AWAY from these patterns.
-->
<exclude name="WordPress.DB.SlowDBQuery.slow_db_query_meta_key" />
<exclude name="WordPress.DB.SlowDBQuery.slow_db_query_meta_value" />
<!--
error_log() usage is intentional in WPDO_Logger for dev environments.
The production build suppresses it via feature flag.
-->
<exclude name="WordPress.PHP.DevelopmentFunctions.error_log_error_log" />
<!--
base64_encode/decode used for gzip archive compression in Zone D.
This is data storage, not obfuscation.
-->
<exclude name="WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode" />
<exclude name="WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode" />
<!-- rand() → wp_rand() not applicable for benchmark timing -->
<exclude name="WordPress.WP.AlternativeFunctions.rand_rand" />
<!--
Slash-separated hook names (wpdo/health_alert_critical, wpdo/fsm_guard/bypass, etc.)
are intentional — they follow the WP Core convention for scoped action namespaces
(e.g. 'customize_save_{$id}', 'heartbeat_received', 'rest_api_init').
Partner plugins subscribe to these hooks; renaming would be a breaking API change.
-->
<exclude name="WordPress.NamingConventions.ValidHookName.UseUnderscores" />
<!--
File system operations (fopen/fwrite/fclose/file_put_contents/file_get_contents/unlink)
are intentional in snapshot/backup code and CLI benchmark/export handlers.
WP_Filesystem is not available outside wp-admin context and introduces state
that complicates CLI and cron use-cases. The backup directory is created with
wp_mkdir_p and access-controlled via .htaccess / direct_filesystem fallback.
-->
<exclude name="WordPress.WP.AlternativeFunctions.file_system_operations_fopen" />
<exclude name="WordPress.WP.AlternativeFunctions.file_system_operations_fwrite" />
<exclude name="WordPress.WP.AlternativeFunctions.file_system_operations_fclose" />
<exclude name="WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents" />
<exclude name="WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents" />
<exclude name="WordPress.WP.AlternativeFunctions.unlink_unlink" />
<exclude name="WordPress.WP.AlternativeFunctions.file_system_operations_is_writable" />
<!--
manage_woocommerce is a standard WooCommerce capability, not a custom one.
WPCS cannot know third-party capabilities; this is a known false-positive.
-->
<exclude name="WordPress.WP.Capabilities.Unknown" />
<!--
REST API callbacks must accept WP_REST_Request $request even when not used
(e.g. /status endpoints). Removing the param breaks WP REST contract.
-->
<exclude name="Generic.CodeAnalysis.UnusedFunctionParameter.Found" />
<exclude name="Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed" />
<!--
Snapshot / migration backup paths use @chmod on freshly-created files
inside admin-only context. Failure-to-chmod is non-fatal (we still
have .htaccess deny + dir-level guards) and surfacing the notice
would mask other diagnostics. Documented in
class-wpdo-migration-orchestrator.php / class-wpdo-snapshot-*.
-->
<exclude name="WordPress.PHP.NoSilencedErrors.Discouraged" />
<!--
chmod() / mkdir() / rename() / fseek() / etc are intentional in
snapshot/backup write paths. WP_Filesystem is unavailable outside
wp-admin context (we run in CLI + cron + admin) and introduces
unwanted state. The fopen/fwrite/file_put_contents/unlink rules
are already excluded above; chmod / mkdir need their own excludes.
-->
<exclude name="WordPress.WP.AlternativeFunctions.file_system_operations_chmod" />
<exclude name="WordPress.WP.AlternativeFunctions.file_system_operations_mkdir" />
<exclude name="WordPress.WP.AlternativeFunctions.rename_rename" />
<!--
Dynamic SQL with $wpdb->prepare() flagged "Replacement variables found,
but no valid placeholders found" when placeholders live in interpolated
sub-strings (e.g. table names from sanitize_key, IN-list expansion).
Each call site has phpcs:ignore comments documenting why; project-wide
silence avoids cluttering every call.
-->
<exclude name="WordPress.DB.PreparedSQL.NotPrepared" />
<exclude name="WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare" />
</rule>
<!--
Slash-separated hook name delimiter (wpdo/zone/event pattern).
Redundant with the UseUnderscores exclude above, but belt-and-suspenders.
-->
<rule ref="WordPress.NamingConventions.ValidHookName">
<properties>
<property name="additionalWordDelimiters" value="/"/>
</properties>
</rule>
<!-- Allow short ternary (?:) — used extensively in this codebase -->
<rule ref="Universal.Operators.DisallowShortTernary">
<severity>0</severity>
</rule>
<!-- PHP minimum version -->
<config name="minimum_supported_wp_version" value="6.0" />
<config name="testVersion" value="8.1-" />
</ruleset>
File diff suppressed because it is too large Load Diff
+29
View File
@@ -0,0 +1,29 @@
includes:
- vendor/szepeviktor/phpstan-wordpress/extension.neon
# Baseline: existing type-completeness debt (mostly missing iterable value
# types + WP template-scope variables). New code is checked clean at L6.
# Burn down incrementally; regenerate with `composer stan:baseline`.
- phpstan-baseline.neon
parameters:
level: 6
paths:
- includes
- admin
- cli
- modules
- 2meet-data-optimizer.php
- uninstall.php
bootstrapFiles:
# Plugin constants (define()'d at runtime; PHPStan can't see them).
- .phpstan/stubs.php
scanFiles:
# WP-CLI classes/functions (runtime-injected by wp-cli; use official stubs).
- vendor/php-stubs/wp-cli-stubs/wp-cli-stubs.php
excludePaths:
- vendor
- tests
- .phpstan
# interface wrappers: PHPStan sees WPDO_X extends TMDO_X as circular
- includes/back-compat
reportUnmatchedIgnoredErrors: false
treatPhpDocTypesAsCertain: false