WordPress.org

Make WordPress Core

Opened 9 months ago

Last modified 8 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 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 (1)

40007.patch (317 bytes) - added by subrataemfluence 9 months ago.

Download all attachments as: .zip

Change History (10)

#1 @alexvorn2
9 months ago

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

#2 follow-up: @subrataemfluence
9 months 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
9 months 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
9 months 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 9 months ago by subrataemfluence (previous) (diff)

#5 @subrataemfluence
9 months 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
9 months 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
9 months ago

  • Keywords has-patch added

#8 @peterwilsoncc
9 months 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 months ago

Closely related, with some background: #22192

Note: See TracTickets for help on using tickets.