Make WordPress Core

Changeset 61760


Ignore:
Timestamp:
02/27/2026 07:57:26 PM (8 days ago)
Author:
johnjamesjacoby
Message:

Cache API: Introduce fallback for when the wp_cache_switch_to_blog() function is missing.

This commit protects against an edge-case where a persistent object-cache drop-in plugin not including its own wp_cache_switch_to_blog() function would cause non-persistent cache groups to go missing when switching between sites, and includes the following changes:

  • A new wp_cache_switch_to_blog_fallback() function in ms-blogs.php which abstracts duplicated code from switch_to_blog() and restore_current_blog() for easier unit testing
  • A new wpCacheSwitchToBlogFallback.php file with approximately 25 new unit tests
  • Conditionally declares wp_cache_switch_to_blog() in cache-compat.php only if it does not already exist, either via core's cache.php or a drop-in plugin

With this change, WordPress no longer needs to check if the wp_cache_switch_to_blog() function exists (because it always will) so those checks have been removed.

Props ethitter, jeremyfelt, johnjamesjacoby, markjaquith, nacin, ozgursar, r1k0.

Fixes #23290.

Location:
trunk
Files:
1 added
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/cache-compat.php

    r60697 r61760  
    313313    }
    314314endif;
     315
     316if ( ! function_exists( 'wp_cache_switch_to_blog' ) ) :
     317    /**
     318     * Used when switch_to_blog() and restore_current_blog() are called, but
     319     * only when a persistent object cache drop-in plugin has omitted the
     320     * wp_cache_switch_to_blog() function that was introduced in 3.5.0.
     321     *
     322     * @link https://core.trac.wordpress.org/ticket/23290
     323     *
     324     * @since 7.0.0
     325     *
     326     * @global WP_Object_Cache $wp_object_cache Object cache global instance.
     327     *
     328     * @param int $blog_id Site ID.
     329     */
     330    function wp_cache_switch_to_blog( $blog_id ) {
     331        global $wp_object_cache;
     332
     333        // Attempt to use the drop-in object cache method if it exists.
     334        if ( method_exists( $wp_object_cache, 'switch_to_blog' ) ) {
     335            $wp_object_cache->switch_to_blog( $blog_id );
     336            return;
     337        }
     338
     339        /*
     340         * Perform a fallback blog switch, which will reinitialize the caches
     341         * for the new blog ID.
     342         */
     343        wp_cache_switch_to_blog_fallback( $blog_id );
     344    }
     345endif;
  • trunk/src/wp-includes/ms-blogs.php

    r61649 r61760  
    536536    $GLOBALS['blog_id']      = $new_blog_id;
    537537
    538     if ( function_exists( 'wp_cache_switch_to_blog' ) ) {
    539         wp_cache_switch_to_blog( $new_blog_id );
    540     } else {
    541         global $wp_object_cache;
    542 
    543         if ( is_object( $wp_object_cache ) && isset( $wp_object_cache->global_groups ) ) {
    544             $global_groups = $wp_object_cache->global_groups;
    545         } else {
    546             $global_groups = false;
    547         }
    548 
    549         wp_cache_init();
    550 
    551         if ( function_exists( 'wp_cache_add_global_groups' ) ) {
    552             if ( is_array( $global_groups ) ) {
    553                 wp_cache_add_global_groups( $global_groups );
    554             } else {
    555                 wp_cache_add_global_groups(
    556                     array(
    557                         'blog-details',
    558                         'blog-id-cache',
    559                         'blog-lookup',
    560                         'blog_meta',
    561                         'global-posts',
    562                         'image_editor',
    563                         'networks',
    564                         'network-queries',
    565                         'sites',
    566                         'site-details',
    567                         'site-options',
    568                         'site-queries',
    569                         'site-transient',
    570                         'theme_files',
    571                         'rss',
    572                         'users',
    573                         'user-queries',
    574                         'user_meta',
    575                         'useremail',
    576                         'userlogins',
    577                         'userslugs',
    578                     )
    579                 );
    580             }
    581 
    582             wp_cache_add_non_persistent_groups( array( 'counts', 'plugins', 'theme_json' ) );
    583         }
    584     }
     538    wp_cache_switch_to_blog( $new_blog_id );
    585539
    586540    /** This filter is documented in wp-includes/ms-blogs.php */
     
    631585    $GLOBALS['table_prefix'] = $wpdb->get_blog_prefix();
    632586
    633     if ( function_exists( 'wp_cache_switch_to_blog' ) ) {
    634         wp_cache_switch_to_blog( $new_blog_id );
    635     } else {
    636         global $wp_object_cache;
    637 
    638         if ( is_object( $wp_object_cache ) && isset( $wp_object_cache->global_groups ) ) {
    639             $global_groups = $wp_object_cache->global_groups;
    640         } else {
    641             $global_groups = false;
    642         }
    643 
    644         wp_cache_init();
    645 
    646         if ( function_exists( 'wp_cache_add_global_groups' ) ) {
    647             if ( is_array( $global_groups ) ) {
    648                 wp_cache_add_global_groups( $global_groups );
    649             } else {
    650                 wp_cache_add_global_groups(
    651                     array(
    652                         'blog-details',
    653                         'blog-id-cache',
    654                         'blog-lookup',
    655                         'blog_meta',
    656                         'global-posts',
    657                         'image_editor',
    658                         'networks',
    659                         'network-queries',
    660                         'sites',
    661                         'site-details',
    662                         'site-options',
    663                         'site-queries',
    664                         'site-transient',
    665                         'theme_files',
    666                         'rss',
    667                         'users',
    668                         'user-queries',
    669                         'user_meta',
    670                         'useremail',
    671                         'userlogins',
    672                         'userslugs',
    673                     )
    674                 );
    675             }
    676 
    677             wp_cache_add_non_persistent_groups( array( 'counts', 'plugins', 'theme_json' ) );
    678         }
    679     }
     587    wp_cache_switch_to_blog( $new_blog_id );
    680588
    681589    /** This filter is documented in wp-includes/ms-blogs.php */
     
    686594
    687595    return true;
     596}
     597
     598/**
     599 * Fallback logic for switching cache context when an object cache drop-in lacks
     600 * a switch_to_blog() method.
     601 *
     602 * Reinitializes the cache and restores global/non-persistent groups.
     603 *
     604 * Used by the wp_cache_switch_to_blog() compatibility function, abstracted only
     605 * to allow for unit testing outside of the drop-in plugin inclusion circus.
     606 *
     607 * @since 7.0.0
     608 *
     609 * @global WP_Object_Cache $wp_object_cache Object cache global instance.
     610 */
     611function wp_cache_switch_to_blog_fallback() {
     612    global $wp_object_cache;
     613
     614    $global_groups         = false;
     615    $non_persistent_groups = false;
     616
     617    if ( is_object( $wp_object_cache ) && isset( $wp_object_cache->global_groups ) ) {
     618        $global_groups         = array_keys( $wp_object_cache->global_groups );
     619        $all_groups            = array_fill_keys( array_keys( $wp_object_cache->cache ), true );
     620        $non_persistent_groups = array_keys( array_diff_key( $all_groups, $wp_object_cache->global_groups ) );
     621    }
     622
     623    wp_cache_init();
     624
     625    if ( function_exists( 'wp_cache_add_global_groups' ) ) {
     626        if ( ! is_array( $global_groups ) || empty( $global_groups ) ) {
     627            $global_groups = array(
     628                'blog-details',
     629                'blog-id-cache',
     630                'blog-lookup',
     631                'blog_meta',
     632                'global-posts',
     633                'image_editor',
     634                'networks',
     635                'network-queries',
     636                'sites',
     637                'site-details',
     638                'site-options',
     639                'site-queries',
     640                'site-transient',
     641                'theme_files',
     642                'translation_files',
     643                'rss',
     644                'users',
     645                'user-queries',
     646                'user_meta',
     647                'useremail',
     648                'userlogins',
     649                'userslugs',
     650            );
     651        }
     652
     653        wp_cache_add_global_groups( $global_groups );
     654    }
     655
     656    if ( function_exists( 'wp_cache_add_non_persistent_groups' ) ) {
     657        if ( ! is_array( $non_persistent_groups ) || empty( $non_persistent_groups ) ) {
     658            $non_persistent_groups = array(
     659                'counts',
     660                'plugins',
     661                'theme_json',
     662            );
     663        }
     664
     665        wp_cache_add_non_persistent_groups( $non_persistent_groups );
     666    }
    688667}
    689668
Note: See TracChangeset for help on using the changeset viewer.