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:
@@ -430,6 +430,10 @@ class TMDO_CLI_Post {
|
|||||||
* Safe to run with the filter enabled; the filter prevents new postmeta
|
* Safe to run with the filter enabled; the filter prevents new postmeta
|
||||||
* writes from re-bloating the table.
|
* 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
|
* ## OPTIONS
|
||||||
*
|
*
|
||||||
* [--dry-run]
|
* [--dry-run]
|
||||||
@@ -438,10 +442,17 @@ class TMDO_CLI_Post {
|
|||||||
* [--confirm]
|
* [--confirm]
|
||||||
* : Required to actually DELETE rows.
|
* : 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
|
* ## EXAMPLES
|
||||||
*
|
*
|
||||||
* wp wpdo cleanup-hp-transients --dry-run
|
* wp wpdo cleanup-hp-transients --dry-run
|
||||||
* wp wpdo cleanup-hp-transients --confirm
|
* wp wpdo cleanup-hp-transients --confirm
|
||||||
|
* wp wpdo cleanup-hp-transients --options --dry-run
|
||||||
*
|
*
|
||||||
* @param array $args Positional arguments (unused).
|
* @param array $args Positional arguments (unused).
|
||||||
* @param array $assoc_args Named arguments.
|
* @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' ) ) {
|
if ( ! class_exists( 'TMDO_Hivepress_Transient_Filter' ) ) {
|
||||||
WP_CLI::error( 'TMDO_Hivepress_Transient_Filter not loaded.' );
|
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) ──────────────────────────────────────────
|
// ── post-cutover-legacy (v2.9.5) ──────────────────────────────────────────
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `wp tmdo cleanup-hp-transients --options` (2.2 PR-080): the HivePress AddOn
|
||||||
|
* moved HivePress's per-post transients out of wp_postmeta into wp_options
|
||||||
|
* (`_transient_wpdo_hp_pm_*`), where they piled up — 1.15 M rows on dev36. Since
|
||||||
|
* PR-081 they live in the object cache when there is one; this removes the
|
||||||
|
* rows left behind. Works without the AddOn loaded (as in core CI).
|
||||||
|
*/
|
||||||
|
class CleanupHpTransientsTest extends TestCase {
|
||||||
|
|
||||||
|
private const OPTIONS = 'wp_itest_options';
|
||||||
|
|
||||||
|
public static function setUpBeforeClass(): void {
|
||||||
|
require_once WPDO_PLUGIN_DIR . 'cli/class-tmdo-cli-post.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function setUp(): void {
|
||||||
|
global $wpdb;
|
||||||
|
$wpdb->query( 'DROP TABLE IF EXISTS `' . self::OPTIONS . '`' );
|
||||||
|
$wpdb->query( 'CREATE TABLE `' . self::OPTIONS . "` ( option_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, option_name VARCHAR(191) NOT NULL DEFAULT '', option_value LONGTEXT NOT NULL, autoload VARCHAR(20) NOT NULL DEFAULT 'yes', PRIMARY KEY (option_id), UNIQUE KEY option_name (option_name) ) ENGINE=InnoDB" );
|
||||||
|
for ( $i = 1; $i <= 5; $i++ ) {
|
||||||
|
$wpdb->insert( self::OPTIONS, array( 'option_name' => "_transient_wpdo_hp_pm_{$i}_abc", 'option_value' => 'v', 'autoload' => 'no' ) );
|
||||||
|
$wpdb->insert( self::OPTIONS, array( 'option_name' => "_transient_timeout_wpdo_hp_pm_{$i}_abc", 'option_value' => '1', 'autoload' => 'no' ) );
|
||||||
|
}
|
||||||
|
foreach ( array( 'siteurl', '_transient_other_plugin', '_transient_wpdo_hp_pmx', 'wpdo_hp_pm_1_abc' ) as $name ) {
|
||||||
|
$wpdb->insert( self::OPTIONS, array( 'option_name' => $name, 'option_value' => 'keep' ) );
|
||||||
|
}
|
||||||
|
$GLOBALS['_wp_cli_output'] = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function tearDown(): void {
|
||||||
|
global $wpdb;
|
||||||
|
$wpdb->query( 'DROP TABLE IF EXISTS `' . self::OPTIONS . '`' );
|
||||||
|
}
|
||||||
|
|
||||||
|
private function remaining(): array {
|
||||||
|
global $wpdb;
|
||||||
|
return $wpdb->get_col( 'SELECT option_name FROM `' . self::OPTIONS . '` ORDER BY option_name' );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_dry_run_counts_the_rows_and_deletes_nothing(): void {
|
||||||
|
( new TMDO_CLI_Post() )->cleanup_hp_transients( array(), array( 'options' => true, 'dry-run' => true ) );
|
||||||
|
|
||||||
|
$this->assertCount( 14, $this->remaining() );
|
||||||
|
$this->assertStringContainsString( '10 HivePress transient row(s) in wp_options', implode( "\n", $GLOBALS['_wp_cli_output'] ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_confirm_deletes_only_the_hivepress_rows_in_batches(): void {
|
||||||
|
( new TMDO_CLI_Post() )->cleanup_hp_transients( array(), array( 'options' => true, 'confirm' => true, 'batch' => '3' ) );
|
||||||
|
|
||||||
|
$this->assertSame( array( '_transient_other_plugin', '_transient_wpdo_hp_pmx', 'siteurl', 'wpdo_hp_pm_1_abc' ), $this->remaining() );
|
||||||
|
$this->assertStringContainsString( 'Deleted 10 HivePress transient row(s) from wp_options', implode( "\n", $GLOBALS['_wp_cli_output'] ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user