Make WordPress Core

Timestamp:
04/03/2024 09:29:13 PM (4 months ago)
Author:
flixos90
Message:

Options, Meta APIs: Use more sensible default for autoloading options which allows WordPress core to make a decision.

An excessive amount of autoloaded options is a common cause for slow database responses, sometimes caused by very large individual autoloaded options. As it is not mandatory to provide an autoload value when adding an option to the database, it tends to be ignored, which in combination with a default value of "yes" and lack of documentation can lead to the aforementioned problem.

This changeset enhances the option autoloading behavior in several ways:

  • Update the function documentation to encourage the use of boolean true or false to explicitly provide an autoload value for an option.
  • Use new string values on and off for explicitly provided values stored in the database, to distinguish them from yes and no, since yes does not allow determining whether it was set intentionally by the developer or only as a default.
  • Effectively deprecate the values yes and no. They are still supported for backward compatibility, but now discouraged.
  • Use null as new default autoload value for add_option(). If the developer does not provide an explicit value, this will now trigger WordPress logic to determine an autoload value to use:
    • If WordPress determines that the option should not be autoloaded, it is stored in the database as auto-off. As part of this changeset, the single heuristic introduced for that is to check whether the option size is larger than a threshold of 150k bytes. This threshold is filterable via a new wp_max_autoloaded_option_size filter.
    • If WordPress determines that the option should be autoloaded, it is stored in the database as auto-on. No logic to make such a decision is introduced as part of this changeset, but a new filter wp_default_autoload_value can be used to define such heuristics, e.g. by optimization plugins.
    • If WordPress cannot determine whether or not to autoload the option, it is stored in the database as auto.
    • This effectively means that any option without an explicit autoload value provided by the developer will be stored with an autoload value of auto, unless the option's size exceeds the aforementioned threshold. Options with a value of auto are still autoloaded as of today, most importantly for backward compatibility. A new function wp_autoload_values_to_autoload() returns the list of autolaod values that dictate for an option to be autoloaded, and a new filter wp_autoload_values_to_autoload can be used to alter that list.

These behavioral changes encourage developers to be more mindful of autoloading, while providing WordPress core and optimization plugins with additional control over heuristics for autoloading options where no explicit autoload value was provided.

At the same time, the changes are fully backward compatible from a functionality perspective, with the only exception being that very large options will now no longer be autoloaded if the developer did not explicitly request for them to be autoloaded. Neither WordPress core nor plugins are able to override an explicitly provided value, which is intentional to continue giving developers full control over their own options.

Props pbearne, flixos90, joemcgill, azaozz, spacedmonkey, swissspidy, mukesh27, markjaquith.
Fixes #42441.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/tests/phpunit/tests/option/wpSetOptionsAutoload.php

    r56508 r57920  
    3131        $this->assertSame( $expected, wp_set_options_autoload( array_keys( $options ), 'yes' ), 'Function did not succeed' );
    3232        $this->assertSame( $num_queries + 2, get_num_queries(), 'Updating options autoload value ran too many queries' );
    33         $this->assertSame( array( 'yes', 'yes' ), $wpdb->get_col( $wpdb->prepare( "SELECT autoload FROM $wpdb->options WHERE option_name IN (" . implode( ',', array_fill( 0, count( $options ), '%s' ) ) . ')', ...array_keys( $options ) ) ), 'Option autoload values not updated in database' );
     33        $this->assertSame( array( '' ), $wpdb->get_col( $wpdb->prepare( "SELECT autoload FROM $wpdb->options WHERE option_name IN (" . implode( ',', array_fill( 0, count( $options ), '%s' ) ) . ')', ...array_keys( $options ) ) ), 'Option autoload values not updated in database' );
    3434        foreach ( $options as $option => $value ) {
    3535            $this->assertFalse( wp_cache_get( $option, 'options' ), sprintf( 'Option %s not deleted from individual cache', $option ) );
     
    6060        $this->assertSame( $expected, wp_set_options_autoload( array_keys( $options ), 'no' ), 'Function did not succeed' );
    6161        $this->assertSame( $num_queries + 2, get_num_queries(), 'Updating options autoload value ran too many queries' );
    62         $this->assertSame( array( 'no', 'no' ), $wpdb->get_col( $wpdb->prepare( "SELECT autoload FROM $wpdb->options WHERE option_name IN (" . implode( ',', array_fill( 0, count( $options ), '%s' ) ) . ')', ...array_keys( $options ) ) ), 'Option autoload values not updated in database' );
     62        $this->assertSame( array( '' ), $wpdb->get_col( $wpdb->prepare( "SELECT autoload FROM $wpdb->options WHERE option_name IN (" . implode( ',', array_fill( 0, count( $options ), '%s' ) ) . ')', ...array_keys( $options ) ) ), 'Option autoload values not updated in database' );
    6363        foreach ( $options as $option => $value ) {
    6464            $this->assertArrayNotHasKey( $option, wp_cache_get( 'alloptions', 'options' ), sprintf( 'Option %s not deleted from alloptions cache', $option ) );
     
    8888        $this->assertSame( $expected, wp_set_options_autoload( array_keys( $options ), 'yes' ), 'Function did unexpectedly succeed' );
    8989        $this->assertSame( $num_queries + 1, get_num_queries(), 'Function attempted to update options autoload value in database' );
    90         $this->assertSame( array( 'yes', 'yes' ), $wpdb->get_col( $wpdb->prepare( "SELECT autoload FROM $wpdb->options WHERE option_name IN (" . implode( ',', array_fill( 0, count( $options ), '%s' ) ) . ')', ...array_keys( $options ) ) ), 'Options autoload value unexpectedly updated in database' );
     90        $this->assertSame( array( '' ), $wpdb->get_col( $wpdb->prepare( "SELECT autoload FROM $wpdb->options WHERE option_name IN (" . implode( ',', array_fill( 0, count( $options ), '%s' ) ) . ')', ...array_keys( $options ) ) ), 'Options autoload value unexpectedly updated in database' );
    9191    }
    9292
     
    134134
    135135        $this->assertSame( $expected, wp_set_options_autoload( array_keys( $options ), 'yes' ), 'Function produced unexpected result' );
    136         $this->assertSame( array( 'yes', 'yes' ), $wpdb->get_col( $wpdb->prepare( "SELECT autoload FROM $wpdb->options WHERE option_name IN (" . implode( ',', array_fill( 0, count( $options ), '%s' ) ) . ')', ...array_keys( $options ) ) ), 'Option autoload values not updated in database' );
     136        $this->assertSame( array( '' ), $wpdb->get_col( $wpdb->prepare( "SELECT autoload FROM $wpdb->options WHERE option_name IN (" . implode( ',', array_fill( 0, count( $options ), '%s' ) ) . ')', ...array_keys( $options ) ) ), 'Option autoload values not updated in database' );
    137137        foreach ( $options as $option => $value ) {
    138138            $this->assertFalse( wp_cache_get( $option, 'options' ), sprintf( 'Option %s not deleted from individual cache', $option ) );
     
    162162
    163163        $this->assertSame( $expected, wp_set_options_autoload( array_keys( $options ), true ), 'Function produced unexpected result' );
    164         $this->assertSame( array( 'yes', 'yes' ), $wpdb->get_col( $wpdb->prepare( "SELECT autoload FROM $wpdb->options WHERE option_name IN (" . implode( ',', array_fill( 0, count( $options ), '%s' ) ) . ')', ...array_keys( $options ) ) ), 'Option autoload values not updated in database' );
     164        $this->assertSame( array( '' ), $wpdb->get_col( $wpdb->prepare( "SELECT autoload FROM $wpdb->options WHERE option_name IN (" . implode( ',', array_fill( 0, count( $options ), '%s' ) ) . ')', ...array_keys( $options ) ) ), 'Option autoload values not updated in database' );
    165165    }
    166166
     
    186186
    187187        $this->assertSame( $expected, wp_set_options_autoload( array_keys( $options ), false ), 'Function produced unexpected result' );
    188         $this->assertSame( array( 'no', 'no' ), $wpdb->get_col( $wpdb->prepare( "SELECT autoload FROM $wpdb->options WHERE option_name IN (" . implode( ',', array_fill( 0, count( $options ), '%s' ) ) . ')', ...array_keys( $options ) ) ), 'Option autoload values not updated in database' );
     188        $this->assertSame( array( '' ), $wpdb->get_col( $wpdb->prepare( "SELECT autoload FROM $wpdb->options WHERE option_name IN (" . implode( ',', array_fill( 0, count( $options ), '%s' ) ) . ')', ...array_keys( $options ) ) ), 'Option autoload values not updated in database' );
    189189    }
    190190}
Note: See TracChangeset for help on using the changeset viewer.