diff --git a/src/wp-includes/option.php b/src/wp-includes/option.php index 1ea13263a5..5b450515a4 100644 --- a/src/wp-includes/option.php +++ b/src/wp-includes/option.php @@ -186,25 +186,45 @@ function form_option( $option ) { function wp_load_alloptions() { global $wpdb; - if ( ! wp_installing() || ! is_multisite() ) + if ( ! wp_installing() || ! is_multisite() ) { $alloptions = wp_cache_get( 'alloptions', 'options' ); - else + } else { $alloptions = false; + } - if ( !$alloptions ) { + if ( ! $alloptions ) { $suppress = $wpdb->suppress_errors(); - if ( !$alloptions_db = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options WHERE autoload = 'yes'" ) ) + if ( ! $alloptions_db = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options WHERE autoload = 'yes'" ) ) { $alloptions_db = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options" ); - $wpdb->suppress_errors($suppress); + } + $wpdb->suppress_errors( $suppress ); + $alloptions = array(); foreach ( (array) $alloptions_db as $o ) { $alloptions[$o->option_name] = $o->option_value; } - if ( ! wp_installing() || ! is_multisite() ) + + if ( ! wp_installing() || ! is_multisite() ) { + /** + * Filters all options before caching them. + * + * @since 4.9.0 + * + * @param array $alloptions Array with all options. + */ + $alloptions = apply_filters( 'pre_cache_alloptions', $alloptions ); wp_cache_add( 'alloptions', $alloptions, 'options' ); + } } - return $alloptions; + /** + * Filters all options after retrieving them. + * + * @since 4.9.0 + * + * @param array $alloptions Array with all options. + */ + return apply_filters( 'alloptions', $alloptions ); } /** diff --git a/tests/phpunit/tests/option/wpLoadAllOptions.php b/tests/phpunit/tests/option/wpLoadAllOptions.php new file mode 100644 index 0000000000..12696abe7a --- /dev/null +++ b/tests/phpunit/tests/option/wpLoadAllOptions.php @@ -0,0 +1,109 @@ +alloptions = null; + parent::tearDown(); + } + + function test_if_alloptions_is_cached() { + $this->assertNotEmpty( wp_cache_get( 'alloptions', 'options' ) ); + } + + /** + * @depends test_if_alloptions_is_cached + */ + function test_if_cached_alloptions_is_deleted() { + $this->assertTrue( wp_cache_delete( 'alloptions', 'options' ) ); + } + + /** + * @depends test_if_alloptions_is_cached + */ + function test_if_alloptions_are_retrieved_from_cache() { + global $wpdb; + $before = $wpdb->num_queries; + wp_load_alloptions(); + $after = $wpdb->num_queries; + + // Database has not been hit. + $this->assertEquals( $before, $after ); + } + + /** + * @depends test_if_cached_alloptions_is_deleted + */ + function test_if_alloptions_are_retrieved_from_database() { + global $wpdb; + + // Delete the existing cache first. + wp_cache_delete( 'alloptions', 'options' ); + + $before = $wpdb->num_queries; + wp_load_alloptions(); + $after = $wpdb->num_queries; + + // Database has been hit. + $this->assertEquals( $before + 1, $after ); + } + + /** + * @depends test_if_cached_alloptions_is_deleted + */ + function test_filter_pre_cache_alloptions_is_called() { + $temp = wp_installing(); + + /** + * Set wp_installing() to false. + * + * If wp_installing is false and the cache is empty, the filter is called regardless if it's multisite or not. + */ + wp_installing( false ); + + // Delete the existing cache first. + wp_cache_delete( 'alloptions', 'options' ); + + add_filter( 'pre_cache_alloptions', array( $this, 'return_pre_cache_filter' ) ); + $all_options = wp_load_alloptions(); + + // Value could leak to other tests if not reset. + wp_installing( $temp ); + + // Filter was called. + $this->assertEquals( $this->alloptions, $all_options ); + } + + /** + * @depends test_if_alloptions_is_cached + */ + function test_filter_pre_cache_alloptions_is_not_called() { + $temp = wp_installing(); + + /** + * Set wp_installing() to true. + * + * If wp_installing is true and it's multisite, the cache and filter are not used. + * If wp_installing is true and it's not multisite, the cache is used (if not empty), and the filter not. + */ + wp_installing( true ); + + add_filter( 'pre_cache_alloptions', array( $this, 'return_pre_cache_filter' ) ); + wp_load_alloptions(); + + // Value could leak to other tests if not reset. + wp_installing( $temp ); + + // Filter was not called. + $this->assertNull( $this->alloptions ); + } + + function return_pre_cache_filter( $alloptions ) { + return $this->alloptions = $alloptions; + } +}