Files
2meet-data-optimizer/includes/class-tmdo-termmeta-cleaner.php
T
wpdev 76c01e44df refactor: 全部 128 個生產檔加入 declare(strict_types=1)(PR-H)
對齊 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
2026-07-31 06:13:33 +08:00

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
}