Skip to content

Commit

Permalink
Options, Meta APIs: Prevent Single Site installs using network notopt…
Browse files Browse the repository at this point in the history
…ions cache.

Modifies the caching of `notoptions` in `delete_network_option()` to ensure that the network cache is bypassed on single site installs.

On single site installs the incorrect caching was causing the `notoptions` cache to remain populated once a deleted option was subsequently added or updated.

Follow up to [58782].

Props bjorsch, pbearne.
Fixes #61730.
See #61484.



git-svn-id: https://develop.svn.wordpress.org/trunk@58811 602fd350-edb4-49c9-b593-d223f7449a82
  • Loading branch information
peterwilsoncc committed Jul 25, 2024
1 parent 4de5282 commit b38541d
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 9 deletions.
20 changes: 11 additions & 9 deletions src/wp-includes/option.php
Original file line number Diff line number Diff line change
Expand Up @@ -2264,6 +2264,17 @@ function delete_network_option( $network_id, $option ) {
'site_id' => $network_id,
)
);

if ( $result ) {
$notoptions_key = "$network_id:notoptions";
$notoptions = wp_cache_get( $notoptions_key, 'site-options' );

if ( ! is_array( $notoptions ) ) {
$notoptions = array();
}
$notoptions[ $option ] = true;
wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
}
}

if ( $result ) {
Expand Down Expand Up @@ -2293,15 +2304,6 @@ function delete_network_option( $network_id, $option ) {
*/
do_action( 'delete_site_option', $option, $network_id );

$notoptions_key = "$network_id:notoptions";
$notoptions = wp_cache_get( $notoptions_key, 'site-options' );

if ( ! is_array( $notoptions ) ) {
$notoptions = array();
}
$notoptions[ $option ] = true;
wp_cache_set( $notoptions_key, $notoptions, 'site-options' );

return true;
}

Expand Down
110 changes: 110 additions & 0 deletions tests/phpunit/tests/option/networkOption.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public function test_delete_network_option_on_only_one_network() {
* Tests that calling delete_network_option() updates nooptions when option deleted.
*
* @ticket 61484
* @ticket 61730
*
* @covers ::delete_network_option
*/
Expand All @@ -73,6 +74,11 @@ public function test_check_delete_network_option_updates_notoptions() {
$this->assertIsArray( $notoptions, 'The notoptions cache is expected to be an array.' );
$this->assertTrue( $notoptions['foo'], 'The deleted options is expected to be in notoptions.' );

if ( ! is_multisite() ) {
$network_notoptions = wp_cache_get( '1:notoptions', 'site-options' );
$this->assertTrue( empty( $network_notoptions['foo'] ), 'The deleted option is not expected to be in network notoptions on a non-multisite.' );
}

$before = get_num_queries();
get_network_option( 1, 'foo' );
$queries = get_num_queries() - $before;
Expand Down Expand Up @@ -302,4 +308,108 @@ public function test_add_network_option_clears_the_notoptions_cache() {
$updated_notoptions = wp_cache_get( $cache_key, $cache_group );
$this->assertArrayNotHasKey( $option_name, $updated_notoptions, 'The "foobar" option should not be in the notoptions cache after updating it.' );
}

/**
* Test adding a previously known notoption returns the correct value.
*
* @ticket 61730
*
* @covers ::add_network_option
* @covers ::delete_network_option
*/
public function test_adding_previous_notoption_returns_correct_value() {
$option_name = 'ticket_61730_option_to_be_created';

add_network_option( 1, $option_name, 'baz' );
delete_network_option( 1, $option_name );

$this->assertFalse( get_network_option( 1, $option_name ), 'The option should not be found.' );

add_network_option( 1, $option_name, 'foo' );
$this->assertSame( 'foo', get_network_option( 1, $option_name ), 'The option should return the newly set value.' );
}

/**
* Test `get_network_option()` does not use network notoptions cache for single sites.
*
* @ticket 61730
*
* @group ms-excluded
*
* @covers ::get_network_option
*/
public function test_get_network_option_does_not_use_network_notoptions_cache_for_single_sites() {
get_network_option( 1, 'ticket_61730_notoption' );

$network_notoptions_cache = wp_cache_get( '1:notoptions', 'site-options' );
$single_site_notoptions_cache = wp_cache_get( 'notoptions', 'options' );

$this->assertEmpty( $network_notoptions_cache, 'Network notoptions cache should not be set for single site installs.' );
$this->assertIsArray( $single_site_notoptions_cache, 'Single site notoptions cache should be set.' );
$this->assertArrayHasKey( 'ticket_61730_notoption', $single_site_notoptions_cache, 'The option should be in the notoptions cache.' );
}

/**
* Test `delete_network_option()` does not use network notoptions cache for single sites.
*
* @ticket 61730
* @ticket 61484
*
* @group ms-excluded
*
* @covers ::delete_network_option
*/
public function test_delete_network_option_does_not_use_network_notoptions_cache_for_single_sites() {
add_network_option( 1, 'ticket_61730_notoption', 'value' );
delete_network_option( 1, 'ticket_61730_notoption' );

$network_notoptions_cache = wp_cache_get( '1:notoptions', 'site-options' );
$single_site_notoptions_cache = wp_cache_get( 'notoptions', 'options' );

$this->assertEmpty( $network_notoptions_cache, 'Network notoptions cache should not be set for single site installs.' );
$this->assertIsArray( $single_site_notoptions_cache, 'Single site notoptions cache should be set.' );
$this->assertArrayHasKey( 'ticket_61730_notoption', $single_site_notoptions_cache, 'The option should be in the notoptions cache.' );
}

/**
* Test `get_network_option()` does not use single site notoptions cache for networks.
*
* @ticket 61730
*
* @group ms-required
*
* @covers ::get_network_option
*/
public function test_get_network_option_does_not_use_single_site_notoptions_cache_for_networks() {
get_network_option( 1, 'ticket_61730_notoption' );

$network_notoptions_cache = wp_cache_get( '1:notoptions', 'site-options' );
$single_site_notoptions_cache = wp_cache_get( 'notoptions', 'options' );

$this->assertEmpty( $single_site_notoptions_cache, 'Single site notoptions cache should not be set for multisite installs.' );
$this->assertIsArray( $network_notoptions_cache, 'Multisite notoptions cache should be set.' );
$this->assertArrayHasKey( 'ticket_61730_notoption', $network_notoptions_cache, 'The option should be in the notoptions cache.' );
}

/**
* Test `delete_network_option()` does not use single site notoptions cache for networks.
*
* @ticket 61730
* @ticket 61484
*
* @group ms-required
*
* @covers ::delete_network_option
*/
public function test_delete_network_option_does_not_use_single_site_notoptions_cache_for_networks() {
add_network_option( 1, 'ticket_61730_notoption', 'value' );
delete_network_option( 1, 'ticket_61730_notoption' );

$network_notoptions_cache = wp_cache_get( '1:notoptions', 'site-options' );
$single_site_notoptions_cache = wp_cache_get( 'notoptions', 'options' );

$this->assertEmpty( $single_site_notoptions_cache, 'Single site notoptions cache should not be set for multisite installs.' );
$this->assertIsArray( $network_notoptions_cache, 'Multisite notoptions cache should be set.' );
$this->assertArrayHasKey( 'ticket_61730_notoption', $network_notoptions_cache, 'The option should be in the notoptions cache.' );
}
}

0 comments on commit b38541d

Please sign in to comment.