Opened 10 years ago
Last modified 4 years ago
#28701 new defect (bug)
Deleted option is not deleted if value was ever null
Reported by: | rmccue | Owned by: | |
---|---|---|---|
Milestone: | Awaiting Review | Priority: | normal |
Severity: | normal | Version: | 2.2 |
Component: | Options, Meta APIs | Keywords: | has-patch needs-unit-tests |
Focuses: | Cc: |
Description
If an autoloaded option ever contains null
, it will cease to be autoloaded after this. It will then be stored in the individual option cache (wp_cache_get('optname', 'options')
), rather than the autoloaded options. The autoloaded option cache will then contain optname
with the value null
(and isset(null) === false
).
Typically, this would be fine, but delete_option
checks the database autoload value directly. It then only attempts to delete this from the autoload options cache (which again fails because of an isset check).
After deleting, the value is still stored in the object cache (!!!), causing it to return a value despite not existing in the database.
As far as I can tell, this has existed since r4855 (WP 2.2).
To reproduce (requires external object cache to be enabled):
// Add the option with initial value set to null add_option( 'testingkey', null ); // Update to real value update_option( 'testingkey', 'realvalue' ); // Delete the option completely delete_option( 'testingkey' ); // Check the value var_dump( get_option( 'testingkey', 'default' ) );
Expected result:
string(7) "default"
Actual result:
string(9) "realvalue"
Attachments (1)
Change History (9)
This ticket was mentioned in IRC in #wordpress-dev by rmccue. View the logs.
10 years ago
#3
@
10 years ago
Using https://gist.github.com/rmccue/4a0dadc68aa4e75c851f as a workaround for now. Will try and patch soon.
#5
@
9 years ago
This needs unit tests.
The change suggested in [28701.diff] seems innocuous to me, but it also doesn't seem to address the root problem. At a glance, it looks to me like we ought to fix the cache-busting logic in update_option()
. It currently does this:
if ( ! defined( 'WP_INSTALLING' ) ) { $alloptions = wp_load_alloptions(); if ( isset( $alloptions[$option] ) ) { $alloptions[ $option ] = $serialized_value; wp_cache_set( 'alloptions', $alloptions, 'options' ); } else { wp_cache_set( $option, $serialized_value, 'options' ); } }
But maybe (a) that first isset()
should be array_key_exists()
, and maybe (b) we should be more aggressive about invalidating both possible cache locations. (Though I want to careful about messing with 'alloptions' concurrency issues.)
Also occurs if you use
update_option
later rather than adding withnull
: