Skip to content

Commit d622659

Browse files
CopilotswissspidyCopilot
authored
Fix wp site empty O(n) scaling: replace per-item cache ops with wp_cache_flush() (#601)
Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Pascal Birchler <pascalb@google.com>
1 parent a8f5147 commit d622659

File tree

1 file changed

+24
-77
lines changed

1 file changed

+24
-77
lines changed

src/Site_Command.php

Lines changed: 24 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
use WP_CLI\CommandWithDBObject;
44
use WP_CLI\ExitException;
55
use WP_CLI\Fetchers\Site as SiteFetcher;
6-
use WP_CLI\Iterators\Query as QueryIterator;
76
use WP_CLI\Iterators\Table as TableIterator;
87
use WP_CLI\Utils;
98
use WP_CLI\Formatter;
@@ -49,12 +48,6 @@ public function __construct() {
4948
private function empty_comments() {
5049
global $wpdb;
5150

52-
// Empty comments and comment cache
53-
$comment_ids = $wpdb->get_col( "SELECT comment_ID FROM $wpdb->comments" );
54-
foreach ( $comment_ids as $comment_id ) {
55-
wp_cache_delete( $comment_id, 'comment' );
56-
wp_cache_delete( $comment_id, 'comment_meta' );
57-
}
5851
$wpdb->query( "TRUNCATE TABLE $wpdb->comments" );
5952
$wpdb->query( "TRUNCATE TABLE $wpdb->commentmeta" );
6053
}
@@ -65,29 +58,6 @@ private function empty_comments() {
6558
private function empty_posts() {
6659
global $wpdb;
6760

68-
// Empty posts and post cache
69-
$posts_query = "SELECT ID FROM $wpdb->posts";
70-
$posts = new QueryIterator( $posts_query, 10000 );
71-
72-
$taxonomies = get_taxonomies();
73-
74-
while ( $posts->valid() ) {
75-
/**
76-
* @var object{ID: int} $post
77-
*/
78-
$post = $posts->current();
79-
80-
$post_id = $post->ID;
81-
82-
wp_cache_delete( $post_id, 'posts' );
83-
wp_cache_delete( $post_id, 'post_meta' );
84-
foreach ( $taxonomies as $taxonomy ) {
85-
wp_cache_delete( $post_id, "{$taxonomy}_relationships" );
86-
}
87-
wp_cache_delete( $wpdb->blogid . '-' . $post_id, 'global-posts' );
88-
89-
$posts->next();
90-
}
9161
$wpdb->query( "TRUNCATE TABLE $wpdb->posts" );
9262
$wpdb->query( "TRUNCATE TABLE $wpdb->postmeta" );
9363
}
@@ -101,26 +71,25 @@ private function empty_taxonomies() {
10171
*/
10272
global $wpdb;
10373

104-
// Empty taxonomies and terms
105-
$terms = $wpdb->get_results( "SELECT term_id, taxonomy FROM $wpdb->term_taxonomy" );
106-
$taxonomies = [];
107-
foreach ( (array) $terms as $term ) {
108-
$taxonomies[] = $term->taxonomy;
109-
wp_cache_delete( $term->term_id, $term->taxonomy );
110-
}
111-
112-
$taxonomies = array_unique( $taxonomies );
113-
$cleaned = [];
114-
foreach ( $taxonomies as $taxonomy ) {
115-
if ( isset( $cleaned[ $taxonomy ] ) ) {
116-
continue;
74+
$taxonomies = $wpdb->get_col( "SELECT DISTINCT taxonomy FROM $wpdb->term_taxonomy" );
75+
if ( ! empty( $taxonomies ) ) {
76+
$option_names = array_map(
77+
static function ( $taxonomy ) {
78+
return "{$taxonomy}_children";
79+
},
80+
$taxonomies
81+
);
82+
$placeholders = implode( ', ', array_fill( 0, count( $option_names ), '%s' ) );
83+
// phpcs:disable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
84+
// @phpstan-ignore argument.type
85+
$query = $wpdb->prepare( 'DELETE FROM ' . $wpdb->options . ' WHERE option_name IN ( ' . $placeholders . ' )', $option_names );
86+
// phpcs:enable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
87+
if ( $query ) {
88+
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- $query is already prepared above.
89+
$wpdb->query( $query );
11790
}
118-
$cleaned[ $taxonomy ] = true;
119-
120-
wp_cache_delete( 'all_ids', $taxonomy );
121-
wp_cache_delete( 'get', $taxonomy );
122-
delete_option( "{$taxonomy}_children" );
12391
}
92+
12493
$wpdb->query( "TRUNCATE TABLE $wpdb->terms" );
12594
$wpdb->query( "TRUNCATE TABLE $wpdb->term_taxonomy" );
12695
$wpdb->query( "TRUNCATE TABLE $wpdb->term_relationships" );
@@ -130,35 +99,11 @@ private function empty_taxonomies() {
13099
}
131100

132101
/**
133-
* Delete all links, link_category terms, and related cache.
102+
* Delete all links by truncating the links table.
134103
*/
135104
private function empty_links() {
136105
global $wpdb;
137106

138-
// Remove links and related cached data.
139-
$links_query = "SELECT link_id FROM {$wpdb->links}";
140-
$links = new QueryIterator( $links_query, 10000 );
141-
142-
// Remove bookmarks cache group.
143-
wp_cache_delete( 'get_bookmarks', 'bookmark' );
144-
145-
while ( $links->valid() ) {
146-
/**
147-
* @var object{link_id: int} $link
148-
*/
149-
$link = $links->current();
150-
151-
$link_id = $link->link_id;
152-
153-
// Remove cache for the link.
154-
wp_delete_object_term_relationships( $link_id, 'link_category' );
155-
wp_cache_delete( $link_id, 'bookmark' );
156-
clean_object_term_cache( $link_id, 'link' );
157-
158-
$links->next();
159-
}
160-
161-
// Empty the table once link related cache and term is removed.
162107
$wpdb->query( "TRUNCATE TABLE {$wpdb->links}" );
163108
}
164109

@@ -230,13 +175,14 @@ private function reset_options() {
230175
}
231176

232177
/**
233-
* Empties a site of its content (posts, comments, terms, and meta).
178+
* Empties a site of its content (posts, comments, terms, links, and meta).
234179
*
235-
* Truncates posts, comments, and terms tables to empty a site of its
180+
* Truncates posts, comments, terms, and links tables to empty a site of its
236181
* content. Doesn't affect site configuration (options) or users.
237182
*
238-
* If running a persistent object cache, make sure to flush the cache
239-
* after emptying the site, as the cache values will be invalid otherwise.
183+
* Flushes the object cache after emptying the site to ensure stale data
184+
* is not served. On a Multisite installation, this will flush the cache
185+
* for all sites.
240186
*
241187
* To also empty custom database tables, you'll need to hook into command
242188
* execution:
@@ -282,6 +228,7 @@ public function empty_( $args, $assoc_args ) {
282228
$this->empty_taxonomies();
283229
$this->insert_default_terms();
284230
$this->reset_options();
231+
wp_cache_flush();
285232

286233
if ( ! empty( $upload_message ) ) {
287234
$upload_dir = wp_upload_dir();

0 commit comments

Comments
 (0)