Make WordPress Core

Changeset 58182


Ignore:
Timestamp:
05/21/2024 09:36:43 PM (6 months ago)
Author:
spacedmonkey
Message:

Options, Meta APIs: Introduce wp_prime_network_option_caches() to load multiple network options with a single database request.

WordPress's get_network_option function generally makes individual database requests for each network option. While some options are preloaded in wp_load_core_site_options, many still require single database calls to the network options table.

Building on the work done in [56445], [56990], and [57013], which introduced the wp_prime_option_caches function, this commit adds two new functions: wp_prime_network_option_caches and wp_prime_site_option_caches. These functions enable developers to pass an array of option names, allowing caches for these options to be primed in a single object cache or database request. If an option is not found, the notoptions cache key is refreshed, preventing unnecessary repeated requests.

The function wp_prime_site_option_caches is similar to get_site_option, enabling developers to retrieve network options on the current network without needing to know the current network ID. If these functions are called in a non-multisite environment, they fall back to using wp_prime_option_caches.

These functions have been implemented in wp_load_core_site_options, get_site_transient, and set_site_transient.

Props to spacedmonkey, peterwilsoncc, mukesh27, joemcgill.
Fixes #61053.

Location:
trunk
Files:
1 added
1 edited

Legend:

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

    r58134 r58182  
    644644
    645645/**
     646 * Primes specific network options for the current network into the cache with a single database query.
     647 *
     648 * Only network options that do not already exist in cache will be loaded.
     649 *
     650 * If site is not multisite, then call wp_prime_option_caches().
     651 *
     652 * @since 6.6.0
     653 *
     654 * @see wp_prime_network_option_caches()
     655 *
     656 * @param string[] $options An array of option names to be loaded.
     657 */
     658function wp_prime_site_option_caches( array $options ) {
     659    wp_prime_network_option_caches( null, $options );
     660}
     661
     662/**
     663 * Primes specific network options into the cache with a single database query.
     664 *
     665 * Only network options that do not already exist in cache will be loaded.
     666 *
     667 * If site is not multisite, then call wp_prime_option_caches().
     668 *
     669 * @since 6.6.0
     670 *
     671 * @global wpdb $wpdb WordPress database abstraction object.
     672 *
     673 * @param int      $network_id ID of the network. Can be null to default to the current network ID.
     674 * @param string[] $options    An array of option names to be loaded.
     675 */
     676function wp_prime_network_option_caches( $network_id, array $options ) {
     677    global $wpdb;
     678
     679    if ( wp_installing() ) {
     680        return;
     681    }
     682
     683    if ( ! is_multisite() ) {
     684        wp_prime_option_caches( $options );
     685        return;
     686    }
     687
     688    if ( $network_id && ! is_numeric( $network_id ) ) {
     689        return;
     690    }
     691
     692    $network_id = (int) $network_id;
     693
     694    // Fallback to the current network if a network ID is not specified.
     695    if ( ! $network_id ) {
     696        $network_id = get_current_network_id();
     697    }
     698
     699    $cache_keys = array();
     700    foreach ( $options as $option ) {
     701        $cache_keys[ $option ] = "{$network_id}:{$option}";
     702    }
     703
     704    $cache_group    = 'site-options';
     705    $cached_options = wp_cache_get_multiple( array_values( $cache_keys ), $cache_group );
     706
     707    $notoptions_key = "$network_id:notoptions";
     708    $notoptions     = wp_cache_get( $notoptions_key, $cache_group );
     709
     710    if ( ! is_array( $notoptions ) ) {
     711        $notoptions = array();
     712    }
     713
     714    // Filter options that are not in the cache.
     715    $options_to_prime = array();
     716    foreach ( $cache_keys as $option => $cache_key ) {
     717        if (
     718            ( ! isset( $cached_options[ $cache_key ] ) || false === $cached_options[ $cache_key ] )
     719            && ! isset( $notoptions[ $option ] )
     720        ) {
     721            $options_to_prime[] = $option;
     722        }
     723    }
     724
     725    // Bail early if there are no options to be loaded.
     726    if ( empty( $options_to_prime ) ) {
     727        return;
     728    }
     729
     730    $query_args   = $options_to_prime;
     731    $query_args[] = $network_id;
     732    $results      = $wpdb->get_results(
     733        $wpdb->prepare(
     734            sprintf(
     735                "SELECT meta_key, meta_value FROM $wpdb->sitemeta WHERE meta_key IN (%s) AND site_id = %s",
     736                implode( ',', array_fill( 0, count( $options_to_prime ), '%s' ) ),
     737                '%d'
     738            ),
     739            $query_args
     740        )
     741    );
     742
     743    $data          = array();
     744    $options_found = array();
     745    foreach ( $results as $result ) {
     746        $key                = $result->meta_key;
     747        $cache_key          = $cache_keys[ $key ];
     748        $data[ $cache_key ] = maybe_unserialize( $result->meta_value );
     749        $options_found[]    = $key;
     750    }
     751    wp_cache_set_multiple( $data, $cache_group );
     752    // If all options were found, no need to update `notoptions` cache.
     753    if ( count( $options_found ) === count( $options_to_prime ) ) {
     754        return;
     755    }
     756
     757    $options_not_found = array_diff( $options_to_prime, $options_found );
     758
     759    // Add the options that were not found to the cache.
     760    $update_notoptions = false;
     761    foreach ( $options_not_found as $option_name ) {
     762        if ( ! isset( $notoptions[ $option_name ] ) ) {
     763            $notoptions[ $option_name ] = true;
     764            $update_notoptions          = true;
     765        }
     766    }
     767
     768    // Only update the cache if it was modified.
     769    if ( $update_notoptions ) {
     770        wp_cache_set( $notoptions_key, $notoptions, $cache_group );
     771    }
     772}
     773
     774/**
    646775 * Loads and primes caches of certain often requested network options if is_multisite().
    647776 *
    648777 * @since 3.0.0
    649778 * @since 6.3.0 Also prime caches for network options when persistent object cache is enabled.
    650  *
    651  * @global wpdb $wpdb WordPress database abstraction object.
     779 * @since 6.6.0 Uses wp_prime_network_option_caches().
    652780 *
    653781 * @param int $network_id Optional. Network ID of network for which to prime network options cache. Defaults to current network.
    654782 */
    655783function wp_load_core_site_options( $network_id = null ) {
    656     global $wpdb;
    657 
    658784    if ( ! is_multisite() || wp_installing() ) {
    659785        return;
    660786    }
    661 
    662     if ( empty( $network_id ) ) {
    663         $network_id = get_current_network_id();
    664     }
    665 
    666     $core_options = array( 'site_name', 'siteurl', 'active_sitewide_plugins', '_site_transient_timeout_theme_roots', '_site_transient_theme_roots', 'site_admins', 'can_compress_scripts', 'global_terms_enabled', 'ms_files_rewriting' );
    667 
    668     if ( wp_using_ext_object_cache() ) {
    669         $cache_keys = array();
    670         foreach ( $core_options as $option ) {
    671             $cache_keys[] = "{$network_id}:{$option}";
    672         }
    673         wp_cache_get_multiple( $cache_keys, 'site-options' );
    674 
    675         return;
    676     }
    677 
    678     $core_options_in = "'" . implode( "', '", $core_options ) . "'";
    679     $options         = $wpdb->get_results( $wpdb->prepare( "SELECT meta_key, meta_value FROM $wpdb->sitemeta WHERE meta_key IN ($core_options_in) AND site_id = %d", $network_id ) );
    680 
    681     $data = array();
    682     foreach ( $options as $option ) {
    683         $key                = $option->meta_key;
    684         $cache_key          = "{$network_id}:$key";
    685         $option->meta_value = maybe_unserialize( $option->meta_value );
    686 
    687         $data[ $cache_key ] = $option->meta_value;
    688     }
    689     wp_cache_set_multiple( $data, 'site-options' );
     787    $core_options = array( 'site_name', 'siteurl', 'active_sitewide_plugins', '_site_transient_timeout_theme_roots', '_site_transient_theme_roots', 'site_admins', 'can_compress_scripts', 'global_terms_enabled', 'ms_files_rewriting', 'WPLANG' );
     788
     789    wp_prime_network_option_caches( $network_id, $core_options );
    690790}
    691791
     
    24162516        if ( ! in_array( $transient, $no_timeout, true ) ) {
    24172517            $transient_timeout = '_site_transient_timeout_' . $transient;
    2418             $timeout           = get_site_option( $transient_timeout );
     2518            wp_prime_site_option_caches( array( $transient_option, $transient_timeout ) );
     2519
     2520            $timeout = get_site_option( $transient_timeout );
    24192521            if ( false !== $timeout && $timeout < time() ) {
    24202522                delete_site_option( $transient_option );
     
    24942596        $transient_timeout = '_site_transient_timeout_' . $transient;
    24952597        $option            = '_site_transient_' . $transient;
     2598        wp_prime_site_option_caches( array( $option, $transient_timeout ) );
    24962599
    24972600        if ( false === get_site_option( $option ) ) {
Note: See TracChangeset for help on using the changeset viewer.