[wp-trac] [WordPress Trac] #25883: get_site_option cache logic for notoptions is incorrect
WordPress Trac
noreply at wordpress.org
Fri Nov 8 16:23:05 UTC 2013
#25883: get_site_option cache logic for notoptions is incorrect
--------------------------+-----------------------------
Reporter: broveloper | Owner:
Type: defect (bug) | Status: new
Priority: normal | Milestone: Awaiting Review
Component: Multisite | Version: 3.7.1
Severity: major | Keywords: needs-patch
--------------------------+-----------------------------
The core function get_site_option has incorrect logic for
wp_cache_get(set) for "notoptions".
**Note: This is a multisite bug**
Example is if you have 2 networks (A,B) and network(A) has a sitemeta
record "testmetakey" and network(B) does not. If network(B) should happen
to be requested first, then it save the "testmetakey" into the
"notoptions" array cache. Then when network(A) makes a request for
"testmetakey", it will find that "testmetakey" is in the "notoptions"
cached array, and thus return nothing even though it does have a meta
value for "testmetakey". Case and point is "active_sitewide_plugins"
{{{
#!php
function get_site_option( $option, $default = false, $use_cache = true ) {
global $wpdb;
// Allow plugins to short-circuit site options.
$pre = apply_filters( 'pre_site_option_' . $option, false );
if ( false !== $pre )
return $pre;
// prevent non-existent options from triggering multiple queries
$notoptions = wp_cache_get( 'notoptions', 'site-options' );
if ( isset( $notoptions[$option] ) )
return apply_filters( 'default_site_option_' . $option,
$default );
if ( ! is_multisite() ) {
$default = apply_filters( 'default_site_option_' .
$option, $default );
$value = get_option($option, $default);
} else {
$cache_key = "{$wpdb->siteid}:$option";
if ( $use_cache )
$value = wp_cache_get($cache_key, 'site-options');
if ( !isset($value) || (false === $value) ) {
$row = $wpdb->get_row( $wpdb->prepare("SELECT
meta_value FROM $wpdb->sitemeta WHERE meta_key = %s AND site_id = %d",
$option, $wpdb->siteid ) );
// Has to be get_row instead of get_var because of
funkiness with 0, false, null values
if ( is_object( $row ) ) {
$value = $row->meta_value;
$value = maybe_unserialize( $value );
wp_cache_set( $cache_key, $value, 'site-
options' );
} else {
$notoptions[$option] = true;
wp_cache_set( 'notoptions', $notoptions,
'site-options' );
$value = apply_filters(
'default_site_option_' . $option, $default );
}
}
}
return apply_filters( 'site_option_' . $option, $value );
}
}}}
The cache_key should be using the same logic for options that are not in
"notoptions":
{{{
#!php
$cache_key = "{$wpdb->siteid}:notoptions";
}}}
Patch would be:
line 760:
{{{
#!php
$notoptions = wp_cache_get( "{$wpdb->siteid}:notoptions", 'site-options'
);
}}}
line 782:
{{{
#!php
wp_cache_set( "{$wpdb->siteid}:notoptions", $notoptions, 'site-options' );
}}}
Or set the notoption's cache key in some variable.
--
Ticket URL: <http://core.trac.wordpress.org/ticket/25883>
WordPress Trac <http://core.trac.wordpress.org/>
WordPress blogging software
More information about the wp-trac
mailing list