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

WordPress's `get_option()` function generally relies on making individual database requests for each option, however with the majority of options (in most cases) being autoloaded, i.e. fetched once with a single database request and then stored in (memory) cache.

As part of a greater effort to reduce the amount of options that are unnecessarily autoloaded, this changeset introduces an alternative way to retrieve multiple options in a performant manner, with a single database request. This provides a reasonable alternative for e.g. plugins that use several options which only need to be loaded in a few specific screens.

Specifically, this changeset introduces the following functions:
* `prime_options( $options )` is the foundation to load multiple specific options with a single database request. Only options that aren't already cached (in `alloptions` or an individual cache) are retrieved from the database.
* `prime_options_by_group( $option_group )` is a convenience wrapper function for the above which allows to prime all options of a specific option group (as configured via `register_setting()`).
* `get_options( $options )` is another wrapper function which first primes the requested options and then returns them in an associative array, calling `get_option()` for each of them.

Props mukesh27, joemcgill, costdev, olliejones.
Fixes #58962.

Built from https://develop.svn.wordpress.org/trunk@56445


git-svn-id: http://core.svn.wordpress.org/trunk@55957 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Felix Arntz 2023-08-24 14:42:17 +00:00
parent 6296d14857
commit cba2612b9e
2 changed files with 112 additions and 1 deletions

View File

@ -253,6 +253,117 @@ function get_option( $option, $default_value = false ) {
return apply_filters( "option_{$option}", maybe_unserialize( $value ), $option );
}
/**
* Primes specific options into the cache with a single database query.
*
* Only options that do not already exist in cache will be primed.
*
* @since 6.4.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param array $options An array of option names to be primed.
*/
function prime_options( $options ) {
$alloptions = wp_load_alloptions();
$cached_options = wp_cache_get_multiple( $options, 'options' );
// Filter options that are not in the cache.
$options_to_prime = array();
foreach ( $options as $option ) {
if ( ( ! isset( $cached_options[ $option ] ) || ! $cached_options[ $option ] ) && ! isset( $alloptions[ $option ] ) ) {
$options_to_prime[] = $option;
}
}
// Bail early if there are no options to be primed.
if ( empty( $options_to_prime ) ) {
return;
}
global $wpdb;
$results = $wpdb->get_results(
$wpdb->prepare(
sprintf(
"SELECT option_name, option_value FROM $wpdb->options WHERE option_name IN (%s)",
implode( ',', array_fill( 0, count( $options_to_prime ), '%s' ) )
),
$options_to_prime
)
);
$options_found = array();
foreach ( $results as $result ) {
$options_found[ $result->option_name ] = maybe_unserialize( $result->option_value );
}
wp_cache_set_multiple( $options_found, 'options' );
// If all options were found, no need to update `notoptions` cache.
if ( count( $options_found ) === count( $options_to_prime ) ) {
return;
}
$options_not_found = array_diff( $options_to_prime, array_keys( $options_found ) );
$notoptions = wp_cache_get( 'notoptions', 'options' );
if ( ! is_array( $notoptions ) ) {
$notoptions = array();
}
// Add the options that were not found to the cache.
$update_notoptions = false;
foreach ( $options_not_found as $option_name ) {
if ( ! isset( $notoptions[ $option_name ] ) ) {
$notoptions[ $option_name ] = true;
$update_notoptions = true;
}
}
// Only update the cache if it was modified.
if ( $update_notoptions ) {
wp_cache_set( 'notoptions', $notoptions, 'options' );
}
}
/**
* Primes all options registered with a specific option group.
*
* @since 6.4.0
*
* @global array $new_allowed_options
*
* @param string $option_group The option group to prime options for.
*/
function prime_options_by_group( $option_group ) {
global $new_allowed_options;
if ( isset( $new_allowed_options[ $option_group ] ) ) {
prime_options( $new_allowed_options[ $option_group ] );
}
}
/**
* Retrieves multiple options.
*
* Options are primed as necessary first in order to use a single database query at most.
*
* @since 6.4.0
*
* @param array $options An array of option names to retrieve.
* @return array An array of key-value pairs for the requested options.
*/
function get_options( $options ) {
prime_options( $options );
$result = array();
foreach ( $options as $option ) {
$result[ $option ] = get_option( $option );
}
return $result;
}
/**
* Protects WordPress special option from being modified.
*

View File

@ -16,7 +16,7 @@
*
* @global string $wp_version
*/
$wp_version = '6.4-alpha-56444';
$wp_version = '6.4-alpha-56445';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.