76c01e44df
對齊 A v3.2.0。型別強制會把隱式轉換變成 TypeError,所以一次全檔加入 並跑完整測試(unit 451 / integration 398 全綠,無迴歸)。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TbG1keQQ7XBa7qMQY16KCY
216 lines
6.4 KiB
PHP
216 lines
6.4 KiB
PHP
<?php
|
|
/**
|
|
* TMDO_Termmeta_Cleaner — wp_termmeta garbage cleanup (v2.12.0 Phase 0).
|
|
*
|
|
* Identifies and removes three classes of low-value rows from wp_termmeta
|
|
* that bloat the table without serving any business purpose:
|
|
*
|
|
* - wxr_import — `_wxr_import_*` rows left by WordPress importer (never
|
|
* read after import, pure tracking residue)
|
|
* - demo_data — `_2meet_demo_*` rows used to mark demo content
|
|
* (can be re-seeded; safe to drop)
|
|
* - transients — `_transient_*` and `_transient_timeout_*` rows
|
|
* (HivePress / WC term cache layer; auto-rebuilt)
|
|
*
|
|
* Mirrors TMDO_Postmeta_Cleaner pattern. Runs before any term Entity Bridge
|
|
* migration so subsequent ratio measurements reflect real data, not garbage.
|
|
* Pure DB layer — no Hook Bus / Entity Bridge coupling.
|
|
*
|
|
* @package WP_Data_Optimizer
|
|
* @since 2.12.0
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Wp_termmeta garbage cleanup (v2.12.0 Phase 0).
|
|
*/
|
|
class TMDO_Termmeta_Cleaner {
|
|
|
|
public const TARGET_WXR_IMPORT = 'wxr_import';
|
|
public const TARGET_DEMO_DATA = 'demo_data';
|
|
public const TARGET_TRANSIENTS = 'transients';
|
|
public const TARGET_ALL = 'all';
|
|
|
|
public const VALID_TARGETS = array(
|
|
self::TARGET_WXR_IMPORT,
|
|
self::TARGET_DEMO_DATA,
|
|
self::TARGET_TRANSIENTS,
|
|
self::TARGET_ALL,
|
|
);
|
|
|
|
/**
|
|
* Count rows that would be cleaned for the given target.
|
|
*
|
|
* @param string $target One of TARGET_* constants.
|
|
* @return array{wxr_import:int, demo_data:int, transients:int, total:int}
|
|
* @throws InvalidArgumentException When $target is not a valid target.
|
|
*/
|
|
public static function count_garbage( string $target = self::TARGET_ALL ): array {
|
|
self::assert_valid_target( $target );
|
|
|
|
$counts = array(
|
|
'wxr_import' => 0,
|
|
'demo_data' => 0,
|
|
'transients' => 0,
|
|
'total' => 0,
|
|
);
|
|
|
|
if ( self::target_includes( $target, self::TARGET_WXR_IMPORT ) ) {
|
|
$counts['wxr_import'] = self::count_wxr_import();
|
|
}
|
|
if ( self::target_includes( $target, self::TARGET_DEMO_DATA ) ) {
|
|
$counts['demo_data'] = self::count_demo_data();
|
|
}
|
|
if ( self::target_includes( $target, self::TARGET_TRANSIENTS ) ) {
|
|
$counts['transients'] = self::count_transients();
|
|
}
|
|
|
|
$counts['total'] = $counts['wxr_import'] + $counts['demo_data'] + $counts['transients'];
|
|
return $counts;
|
|
}
|
|
|
|
/**
|
|
* Delete garbage rows for the given target.
|
|
*
|
|
* @param string $target One of TARGET_* constants.
|
|
* @return array{wxr_import:int, demo_data:int, transients:int, total:int}
|
|
* @throws InvalidArgumentException When $target is not a valid target.
|
|
*/
|
|
public static function delete_garbage( string $target = self::TARGET_ALL ): array {
|
|
self::assert_valid_target( $target );
|
|
|
|
$deleted = array(
|
|
'wxr_import' => 0,
|
|
'demo_data' => 0,
|
|
'transients' => 0,
|
|
'total' => 0,
|
|
);
|
|
|
|
if ( self::target_includes( $target, self::TARGET_WXR_IMPORT ) ) {
|
|
$deleted['wxr_import'] = self::delete_wxr_import();
|
|
}
|
|
if ( self::target_includes( $target, self::TARGET_DEMO_DATA ) ) {
|
|
$deleted['demo_data'] = self::delete_demo_data();
|
|
}
|
|
if ( self::target_includes( $target, self::TARGET_TRANSIENTS ) ) {
|
|
$deleted['transients'] = self::delete_transients();
|
|
}
|
|
|
|
$deleted['total'] = $deleted['wxr_import'] + $deleted['demo_data'] + $deleted['transients'];
|
|
return $deleted;
|
|
}
|
|
|
|
/**
|
|
* Whether $target selects $bucket (i.e. target=all or target=bucket).
|
|
*
|
|
* @param string $target Selected target.
|
|
* @param string $bucket Bucket constant.
|
|
* @return bool
|
|
*/
|
|
private static function target_includes( string $target, string $bucket ): bool {
|
|
return self::TARGET_ALL === $target || $bucket === $target;
|
|
}
|
|
|
|
/**
|
|
* Validate target parameter.
|
|
*
|
|
* @param string $target Target to validate.
|
|
* @return void
|
|
* @throws InvalidArgumentException When $target is not in VALID_TARGETS.
|
|
*/
|
|
private static function assert_valid_target( string $target ): void {
|
|
if ( in_array( $target, self::VALID_TARGETS, true ) ) {
|
|
return;
|
|
}
|
|
$msg = sprintf( 'Invalid target "%s". Valid: %s', $target, implode( ', ', self::VALID_TARGETS ) );
|
|
throw new InvalidArgumentException( $msg ); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
|
|
}
|
|
|
|
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Internal cleanup class: $wpdb->termmeta is WP-managed; meta_key patterns are static class constants.
|
|
|
|
/**
|
|
* Count `_wxr_import_*` rows in wp_termmeta.
|
|
*
|
|
* @return int
|
|
*/
|
|
private static function count_wxr_import(): int {
|
|
global $wpdb;
|
|
$table = $wpdb->termmeta;
|
|
return (int) $wpdb->get_var(
|
|
"SELECT COUNT(*) FROM `{$table}` WHERE meta_key LIKE '\\_wxr\\_import\\_%'"
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Delete `_wxr_import_*` rows from wp_termmeta.
|
|
*
|
|
* @return int Affected row count.
|
|
*/
|
|
private static function delete_wxr_import(): int {
|
|
global $wpdb;
|
|
$table = $wpdb->termmeta;
|
|
return (int) $wpdb->query(
|
|
"DELETE FROM `{$table}` WHERE meta_key LIKE '\\_wxr\\_import\\_%'"
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Count `_2meet_demo_*` rows in wp_termmeta.
|
|
*
|
|
* @return int
|
|
*/
|
|
private static function count_demo_data(): int {
|
|
global $wpdb;
|
|
$table = $wpdb->termmeta;
|
|
return (int) $wpdb->get_var(
|
|
"SELECT COUNT(*) FROM `{$table}` WHERE meta_key LIKE '\\_2meet\\_demo\\_%'"
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Delete `_2meet_demo_*` rows from wp_termmeta.
|
|
*
|
|
* @return int Affected row count.
|
|
*/
|
|
private static function delete_demo_data(): int {
|
|
global $wpdb;
|
|
$table = $wpdb->termmeta;
|
|
return (int) $wpdb->query(
|
|
"DELETE FROM `{$table}` WHERE meta_key LIKE '\\_2meet\\_demo\\_%'"
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Count rows matching transient meta_key patterns in wp_termmeta.
|
|
*
|
|
* @return int
|
|
*/
|
|
private static function count_transients(): int {
|
|
global $wpdb;
|
|
$table = $wpdb->termmeta;
|
|
return (int) $wpdb->get_var(
|
|
"SELECT COUNT(*) FROM `{$table}` WHERE meta_key LIKE '\\_transient\\_%' OR meta_key LIKE '\\_transient\\_timeout\\_%'"
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Delete rows matching transient meta_key patterns from wp_termmeta.
|
|
*
|
|
* @return int Affected row count.
|
|
*/
|
|
private static function delete_transients(): int {
|
|
global $wpdb;
|
|
$table = $wpdb->termmeta;
|
|
return (int) $wpdb->query(
|
|
"DELETE FROM `{$table}` WHERE meta_key LIKE '\\_transient\\_%' OR meta_key LIKE '\\_transient\\_timeout\\_%'"
|
|
);
|
|
}
|
|
|
|
// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
|
}
|