chore(2meet-data-optimizer): clean HivePress transients left in wp_options

- `wp tmdo cleanup-hp-transients --options [--dry-run|--confirm] [--batch=<n>]` removes the rows the HivePress AddOn wrote to wp_options (`_transient_wpdo_hp_pm_*` and their timeouts) before AddOn 0.3.0 kept them in the object cache, deleting in batches (default 5000). It works without the AddOn active; the namespace is repeated in core for that.
- Verify: CleanupHpTransientsTest (RED before; only the AddOn's rows go, look-alike names stay); dev36 --dry-run counts 2,314,750 rows in 3.2 s. The --confirm run belongs after the AddOn change is deployed.
- PR: PR-080
This commit is contained in:
2026-09-27 09:06:19 +08:00
parent 84f6e32913
commit 07955192d4
2 changed files with 107 additions and 0 deletions
+49
View File
@@ -430,6 +430,10 @@ class TMDO_CLI_Post {
* Safe to run with the filter enabled; the filter prevents new postmeta
* writes from re-bloating the table.
*
* With --options it removes instead the rows the filter wrote to wp_options
* (`_transient_wpdo_hp_pm_*`) before 1.2.0 / AddOn 0.3.0 kept them in the
* object cache; works without the AddOn active.
*
* ## OPTIONS
*
* [--dry-run]
@@ -438,10 +442,17 @@ class TMDO_CLI_Post {
* [--confirm]
* : Required to actually DELETE rows.
*
* [--options]
* : Clean the AddOn's rows in wp_options instead of wp_postmeta.
*
* [--batch=<n>]
* : Rows per DELETE with --options. Default 5000.
*
* ## EXAMPLES
*
* wp wpdo cleanup-hp-transients --dry-run
* wp wpdo cleanup-hp-transients --confirm
* wp wpdo cleanup-hp-transients --options --dry-run
*
* @param array $args Positional arguments (unused).
* @param array $assoc_args Named arguments.
@@ -461,6 +472,11 @@ class TMDO_CLI_Post {
);
}
if ( isset( $assoc_args['options'] ) ) {
self::cleanup_hp_transient_options( $dry_run, max( 1, (int) ( $assoc_args['batch'] ?? 5000 ) ) );
return;
}
if ( ! class_exists( 'TMDO_Hivepress_Transient_Filter' ) ) {
WP_CLI::error( 'TMDO_Hivepress_Transient_Filter not loaded.' );
}
@@ -494,6 +510,39 @@ class TMDO_CLI_Post {
);
}
/**
* Count or delete the HivePress AddOn's transient rows in wp_options, in
* batches (dev36 held 1.15 M of them).
*
* @param bool $dry_run Count only.
* @param int $batch Rows per DELETE.
* @return void
*/
private static function cleanup_hp_transient_options( bool $dry_run, int $batch ): void {
global $wpdb;
// TMDO_Hivepress_Transient_Filter::TRANSLATED_NAMESPACE (AddOn), repeated
// here so the leftovers can be removed with the AddOn gone.
$ns = $wpdb->esc_like( 'wpdo_hp_pm_' );
$where = $wpdb->prepare( 'option_name LIKE %s OR option_name LIKE %s', '\_transient\_' . $ns . '%', '\_transient\_timeout\_' . $ns . '%' );
if ( $dry_run ) {
$count = (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->options} WHERE {$where}" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
WP_CLI::success( sprintf( '[dry-run] %d HivePress transient row(s) in wp_options would be deleted. Re-run with --confirm.', $count ) );
return;
}
$deleted = 0;
do {
$rows = (int) $wpdb->query( "DELETE FROM {$wpdb->options} WHERE {$where} LIMIT {$batch}" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
$deleted += $rows;
} while ( $rows === $batch );
if ( class_exists( 'TMDO_Logger' ) ) {
TMDO_Logger::info( 'cleanup_hp_transient_options', array( 'deleted' => $deleted ) );
}
WP_CLI::success( sprintf( 'Deleted %d HivePress transient row(s) from wp_options.', $deleted ) );
}
// ── post-cutover-legacy (v2.9.5) ──────────────────────────────────────────
/**