From 98f18af8b90340cbdad1222c98edbc39bfeca1bb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Mar 2026 14:58:03 +0000 Subject: [PATCH 1/6] Initial plan From d297857759810ec9c6f0ea82cb9b14b6e02d915a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Mar 2026 15:06:09 +0000 Subject: [PATCH 2/6] Fix wp site empty scaling: replace per-item cache ops with wp_cache_flush() Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> --- src/Site_Command.php | 79 ++++---------------------------------------- 1 file changed, 6 insertions(+), 73 deletions(-) diff --git a/src/Site_Command.php b/src/Site_Command.php index 114bf1446..f00d6fbd2 100644 --- a/src/Site_Command.php +++ b/src/Site_Command.php @@ -3,7 +3,6 @@ use WP_CLI\CommandWithDBObject; use WP_CLI\ExitException; use WP_CLI\Fetchers\Site as SiteFetcher; -use WP_CLI\Iterators\Query as QueryIterator; use WP_CLI\Iterators\Table as TableIterator; use WP_CLI\Utils; use WP_CLI\Formatter; @@ -49,12 +48,6 @@ public function __construct() { private function empty_comments() { global $wpdb; - // Empty comments and comment cache - $comment_ids = $wpdb->get_col( "SELECT comment_ID FROM $wpdb->comments" ); - foreach ( $comment_ids as $comment_id ) { - wp_cache_delete( $comment_id, 'comment' ); - wp_cache_delete( $comment_id, 'comment_meta' ); - } $wpdb->query( "TRUNCATE TABLE $wpdb->comments" ); $wpdb->query( "TRUNCATE TABLE $wpdb->commentmeta" ); } @@ -65,29 +58,6 @@ private function empty_comments() { private function empty_posts() { global $wpdb; - // Empty posts and post cache - $posts_query = "SELECT ID FROM $wpdb->posts"; - $posts = new QueryIterator( $posts_query, 10000 ); - - $taxonomies = get_taxonomies(); - - while ( $posts->valid() ) { - /** - * @var object{ID: int} $post - */ - $post = $posts->current(); - - $post_id = $post->ID; - - wp_cache_delete( $post_id, 'posts' ); - wp_cache_delete( $post_id, 'post_meta' ); - foreach ( $taxonomies as $taxonomy ) { - wp_cache_delete( $post_id, "{$taxonomy}_relationships" ); - } - wp_cache_delete( $wpdb->blogid . '-' . $post_id, 'global-posts' ); - - $posts->next(); - } $wpdb->query( "TRUNCATE TABLE $wpdb->posts" ); $wpdb->query( "TRUNCATE TABLE $wpdb->postmeta" ); } @@ -101,26 +71,11 @@ private function empty_taxonomies() { */ global $wpdb; - // Empty taxonomies and terms - $terms = $wpdb->get_results( "SELECT term_id, taxonomy FROM $wpdb->term_taxonomy" ); - $taxonomies = []; - foreach ( (array) $terms as $term ) { - $taxonomies[] = $term->taxonomy; - wp_cache_delete( $term->term_id, $term->taxonomy ); - } - - $taxonomies = array_unique( $taxonomies ); - $cleaned = []; + $taxonomies = $wpdb->get_col( "SELECT DISTINCT taxonomy FROM $wpdb->term_taxonomy" ); foreach ( $taxonomies as $taxonomy ) { - if ( isset( $cleaned[ $taxonomy ] ) ) { - continue; - } - $cleaned[ $taxonomy ] = true; - - wp_cache_delete( 'all_ids', $taxonomy ); - wp_cache_delete( 'get', $taxonomy ); delete_option( "{$taxonomy}_children" ); } + $wpdb->query( "TRUNCATE TABLE $wpdb->terms" ); $wpdb->query( "TRUNCATE TABLE $wpdb->term_taxonomy" ); $wpdb->query( "TRUNCATE TABLE $wpdb->term_relationships" ); @@ -135,30 +90,6 @@ private function empty_taxonomies() { private function empty_links() { global $wpdb; - // Remove links and related cached data. - $links_query = "SELECT link_id FROM {$wpdb->links}"; - $links = new QueryIterator( $links_query, 10000 ); - - // Remove bookmarks cache group. - wp_cache_delete( 'get_bookmarks', 'bookmark' ); - - while ( $links->valid() ) { - /** - * @var object{link_id: int} $link - */ - $link = $links->current(); - - $link_id = $link->link_id; - - // Remove cache for the link. - wp_delete_object_term_relationships( $link_id, 'link_category' ); - wp_cache_delete( $link_id, 'bookmark' ); - clean_object_term_cache( $link_id, 'link' ); - - $links->next(); - } - - // Empty the table once link related cache and term is removed. $wpdb->query( "TRUNCATE TABLE {$wpdb->links}" ); } @@ -235,8 +166,9 @@ private function reset_options() { * Truncates posts, comments, and terms tables to empty a site of its * content. Doesn't affect site configuration (options) or users. * - * If running a persistent object cache, make sure to flush the cache - * after emptying the site, as the cache values will be invalid otherwise. + * Flushes the object cache after emptying the site to ensure stale data + * is not served. On a Multisite installation, this will flush the cache + * for all sites. * * To also empty custom database tables, you'll need to hook into command * execution: @@ -282,6 +214,7 @@ public function empty_( $args, $assoc_args ) { $this->empty_taxonomies(); $this->insert_default_terms(); $this->reset_options(); + wp_cache_flush(); if ( ! empty( $upload_message ) ) { $upload_dir = wp_upload_dir(); From af549d43bf7b9e147bdd1aaa8798a2a24d5be7bc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Mar 2026 17:55:00 +0000 Subject: [PATCH 3/6] Improve empty_taxonomies: use get_taxonomies() and bulk DELETE for _children options Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> --- src/Site_Command.php | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/Site_Command.php b/src/Site_Command.php index f00d6fbd2..4db8c802a 100644 --- a/src/Site_Command.php +++ b/src/Site_Command.php @@ -71,9 +71,23 @@ private function empty_taxonomies() { */ global $wpdb; - $taxonomies = $wpdb->get_col( "SELECT DISTINCT taxonomy FROM $wpdb->term_taxonomy" ); - foreach ( $taxonomies as $taxonomy ) { - delete_option( "{$taxonomy}_children" ); + $taxonomies = array_keys( get_taxonomies() ); + if ( ! empty( $taxonomies ) ) { + $option_names = array_map( + static function ( $taxonomy ) { + return "{$taxonomy}_children"; + }, + $taxonomies + ); + $placeholders = implode( ', ', array_fill( 0, count( $option_names ), '%s' ) ); + // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare + // @phpstan-ignore argument.type + $query = $wpdb->prepare( 'DELETE FROM ' . $wpdb->options . ' WHERE option_name IN ( ' . $placeholders . ' )', $option_names ); + // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare + if ( $query ) { + // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- $query is already prepared above. + $wpdb->query( $query ); + } } $wpdb->query( "TRUNCATE TABLE $wpdb->terms" ); From 453de4dc8bb3b5b73c62cb6f9b4b17c1ad9153a3 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Tue, 17 Mar 2026 22:02:41 +0100 Subject: [PATCH 4/6] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/Site_Command.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Site_Command.php b/src/Site_Command.php index 4db8c802a..3c783a5c0 100644 --- a/src/Site_Command.php +++ b/src/Site_Command.php @@ -99,7 +99,7 @@ static function ( $taxonomy ) { } /** - * Delete all links, link_category terms, and related cache. + * Delete all links by truncating the links table. */ private function empty_links() { global $wpdb; From ed1c3959b9d3302f860663e4afd7ee99b3bbbaab Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Wed, 18 Mar 2026 10:06:34 +0100 Subject: [PATCH 5/6] Use db query after all --- src/Site_Command.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Site_Command.php b/src/Site_Command.php index 3c783a5c0..f1b4baf38 100644 --- a/src/Site_Command.php +++ b/src/Site_Command.php @@ -71,7 +71,7 @@ private function empty_taxonomies() { */ global $wpdb; - $taxonomies = array_keys( get_taxonomies() ); + $taxonomies = $wpdb->get_col( "SELECT DISTINCT taxonomy FROM $wpdb->term_taxonomy" ); if ( ! empty( $taxonomies ) ) { $option_names = array_map( static function ( $taxonomy ) { From bde696bcadf3f0ce55d567b194cc9a557c3523f0 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Wed, 18 Mar 2026 14:04:26 +0100 Subject: [PATCH 6/6] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/Site_Command.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Site_Command.php b/src/Site_Command.php index f1b4baf38..4874f43cb 100644 --- a/src/Site_Command.php +++ b/src/Site_Command.php @@ -175,9 +175,9 @@ private function reset_options() { } /** - * Empties a site of its content (posts, comments, terms, and meta). + * Empties a site of its content (posts, comments, terms, links, and meta). * - * Truncates posts, comments, and terms tables to empty a site of its + * Truncates posts, comments, terms, and links tables to empty a site of its * content. Doesn't affect site configuration (options) or users. * * Flushes the object cache after emptying the site to ensure stale data