Opened 5 weeks ago
Last modified 4 weeks ago
#65485 new enhancement
Performance: Avoid redundant cache invalidation in wp_insert_* functions when processing meta_input
| Reported by: | spacedmonkey | Owned by: | |
|---|---|---|---|
| Priority: | normal | Milestone: | Awaiting Review |
| Component: | Cache API | Version: | |
| Severity: | normal | Keywords: | good-first-bug has-patch has-unit-tests |
| Cc: | Focuses: | performance |
Description
The Problem
Functions like wp_insert_post(), wp_insert_comment(), wp_insert_site(), and wp_insert_user() accept a meta_input parameter (or equivalent) to create or update multiple pieces of meta data at once via a foreach loop.
However, Core hooks the cache invalidation function wp_cache_set_posts_last_changed (and its equivalents for users, comments, and sites) directly to the meta action hooks:
<?php add_action( 'added_post_meta', 'wp_cache_set_posts_last_changed' ); add_action( 'updated_post_meta', 'wp_cache_set_posts_last_changed' ); add_action( 'deleted_post_meta', 'wp_cache_set_posts_last_changed' );
Because these are fired on every individual meta update, passing an array of 5 meta keys results in the cache being invalidated 5 consecutive times during a single insertion process. This is highly redundant and wasteful. Furthermore, wp_insert_post() already calls clean_post_cache() at the end of its execution, which inherently handles the necessary cache clearing.
The Proposed Solution
To optimize database and object cache performance, we should temporarily unhook the _last_changed cache invalidation callbacks before iterating through the meta_input loop, and re-hook them immediately after the loop finishes.
For example, in wp_insert_post():
<?php // Temporarily unhook to prevent redundant cache invalidation per meta key $has_action = remove_action( 'updated_post_meta', 'wp_cache_set_posts_last_changed' ); foreach ( $meta_input as $meta_key => $meta_value ) { update_post_meta( $post_id, $meta_key, $meta_value ); } // Re-hook after the loop completes if ( $has_action ) { add_action( 'updated_post_meta', 'wp_cache_set_posts_last_changed' ); }
Scope of Impact
This optimization pattern should be applied across all major wp_insert_* functions that handle bulk meta input loops:
wp_insert_post()wp_insert_comment()wp_insert_user()wp_insert_site()
By preventing these redundant internal cache sets, we can noticeably reduce object cache overhead during bulk creation/import processes.
Change History (1)
This ticket was mentioned in PR #12244 on WordPress/wordpress-develop by @micahele.
4 weeks ago
#1
- Keywords has-patch has-unit-tests added
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)
## Summary
Fixes #65485.
When inserting posts, comments, or users with multiple meta entries via
meta_inputorcomment_meta, thewp_cache_set_*_last_changed()callback (hooked toadded_*_meta/updated_*_meta) fired once per meta key, causing N redundant cache writes for N meta entries.For example, inserting a post with 5
meta_inputentries triggered 5 redundantlast_changedcache writes during the meta loop — even thoughwp_insert_post()already callsclean_post_cache()at the end, which invalidates the cache once.## The fix
Temporarily suspends the per-key
_last_changedcallback during the bulk meta loop and restores it afterward. The parent functions (clean_post_cache(), etc.) already invalidate the cache once at the end of the insertion, so no explicit re-trigger is needed.### Affected functions
wp_insert_post()—meta_inputloopwp_insert_comment()andwp_update_comment()—comment_metaloopswp_insert_user()— meta loops (both add and update branches)## Testing
### Reproduction (before fix)
### After fix
The redundant per-key invalidations during the bulk loops are eliminated. Remaining writes are from legitimate single meta operations outside the loop.
### Test suite
Tests_Cache_RedundantMetaInvalidation(5 tests) — passes with fix, fails without it## How to test