Make WordPress Core

Opened 8 years ago

Last modified 12 months ago

#40007 reopened defect (bug)

update_option function does not work if the $value argument is false on a nonexistent option

Reported by: alexvorn2's profile alexvorn2 Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version:
Component: General Keywords: has-patch
Focuses: Cc:

Description

If we specify a false argument in update_option function and if the database option does not exist then the option will not be saved.

I expect the option to be saved with false value if it does not exist.

If we look into the code of this function we can see that it will return false if the old value is false too, so if the option does not exists then it will return false.

It's a bug.

How to replicate? give a try:

<?php
update_option( 'aaa2345454', false );

Attachments (2)

40007.patch (317 bytes) - added by subrataemfluence 8 years ago.
40007.diff (1.9 KB) - added by peterwilsoncc 12 months ago.

Download all attachments as: .zip

Change History (12)

#1 @alexvorn2
8 years ago

I can't believe such a old function and very used one have a bug.

#2 follow-up: @subrataemfluence
8 years ago

  • Keywords close added
  • Resolution set to invalid
  • Status changed from new to closed

According to the structure as of now the datatype the option_name column in wp_options is of string type (varchar(191)).

The reason it does not add a record with update_option('aaa2345454', false) is you are passing a Boolean value.

To add / update a record with value true or false you either need to pass it directly as string like

update_option('aaa2345454', 'false');

or in case you are grabbing this value from somewhere else which is a Boolean then you need to create a string alternative for your value before you actually send it:

$value = true; //hard coding the $value here. You may be grabbing it from somewhere else.
$converted_value = ($value) ? 'true' : 'false';
update_option('aaa2345454', $converted_value)

The above would add / update the value in wp_options table with a value either true or false in option_value column. However, the value would not insert as a real Boolean type.

#3 in reply to: ↑ 2 @alexvorn2
8 years ago

  • Resolution invalid deleted
  • Status changed from closed to reopened

Replying to subrataemfluence:

According to the structure as of now the datatype the option_name column in wp_options is of string type (varchar(191)).

The reason it does not add a record with update_option('aaa2345454', false) is you are passing a Boolean value.

To add / update a record with value true or false you either need to pass it directly as string like

update_option('aaa2345454', 'false');

or in case you are grabbing this value from somewhere else which is a Boolean then you need to create a string alternative for your value before you actually send it:

$value = true; //hard coding the $value here. You may be grabbing it from somewhere else.
$converted_value = ($value) ? 'true' : 'false';
update_option('aaa2345454', $converted_value)

The above would add / update the value in wp_options table with a value either true or false in option_value column. However, the value would not insert as a real Boolean type.

I want to add a Boolean false value, not STRING 'false' value, these are 2 different things.

Why update_option( 'aaa2345', true ) works and update_option( 'aaa2346', false ) does not?
I think you did not understand the issue here. I will reopen this, why close so fast? Just a close keyword is enough, maybe someone has a different opinion.

Even if update_option( 'aaa2346', false ) does not work it should at least insert a new row into the database.

#4 @subrataemfluence
8 years ago

  • Keywords close removed

My apology for closing the ticket. That was not intended. I will try once again.

However, you should have been more precise. You mentioned about false but never mentioned what true did for you. This is a good practice to explain everything in detail as much as possible so that others know exactly where and what to look at.

Thank you!

Last edited 8 years ago by subrataemfluence (previous) (diff)

#5 @subrataemfluence
8 years ago

Although false is not being recognized a value 0 is actually adding / updating record in the table. So it is only Boolean false which is not working! I am under an impression that this value has a conflict somewhere in the function!

true - works. Value added is 1
1 - works. Value added is 1
false - does not work - No record added
0 - works - Value added is 0
'true' - works. Value added is 'true'
'false' - works. Value added is 'false'

#6 @subrataemfluence
8 years ago

Further inspecting the core function update_action reveals something strange!

The value false is actually being treated as an empty string, but true is not! So when I am passing false for a key which I know does not exist there yet, get_option returns an empty string ($old_value = get_option( $option );), which when being compared in the following snippet:

if ( $value === $old_value ) return false;

always returning false as both $value and $old_value are nothing but empty strings!

This is the reason update_option('_option_key_index', false), never adds a record in the database. But if I pass update_option('_option_key_index', 0) it does.

#7 @subrataemfluence
8 years ago

  • Keywords has-patch added

#8 @peterwilsoncc
8 years ago

Converting to 0(int) instead of "0"(string) will result in a database write on every call, as all options are recorded as strings. The old and new value comparison becomes 0 === "0" and evaluates to false. (related #38903).

A more robust solution would be to correctly cast the value before comparing old an new values.

It's worth noting add_option() will fail to store the value false too. ref.

#9 @boonebgorges
8 years ago

Closely related, with some background: #22192

#10 @peterwilsoncc
12 months ago

I rediscovered this while working on another ticket.

In 40007.diff, rather than checking the return value of get_option() to determine if update_option() is called with a new option, it checks if the option name appears in the notoptions cache.

If the option key is in notoptions then the option can be added to the database via the add_option function.

The attached diff is only lightly tested, a call to update_option( 'non-exisistent-option', false ) does result in the option being added to the database.

Note: See TracTickets for help on using tickets.