0

I have a tricky bug in a plugin and I'm trying to figure out who's fault it is.

The plugin uses in its init method a check if the DB has to be updated. And the child theme I'm using has set a custom local with setlocal(). As a result get_option() return a string instead of a float value.

Here is the basic setup how to reproduce the error:

// set custom local
setlocale(LC_ALL, 'de_DE.UTF-8');

// set current DB version
update_option("db_version", 5.39);

// get DB version
$db_version = get_option("db_version"); // (string) 5,39

// Update DB if necessary
if(!empty($db_version) and $db_version < 5.13) {
    $wpdb->query("ALTER TABLE example CHANGE `cat_id` `cat_ids` VARCHAR(255) NOT NULL DEFAULT ''");
}

As the update is already in the system it throws an error as ((string) "5,39" < 5.13) === true.

Test the PHP behavior

I wrote a little check up for me to see what causes the error:

<?php
setlocale(LC_ALL, 'de_DE.UTF-8');
echo '<pre>';
$locale_info = localeconv();
echo 'decimal_point=' . $locale_info['decimal_point'] . "\n"; // decimal_point=,
// Test like the DB update check in WP
$db_version = floatval('5.39');
if(!empty($db_version) and $db_version < 5.13) // <==
    echo "ERROR $db_version is not smaller than 5.13";
else 
    echo "SUCCESS $db_version > 5.13";
?>

I was surprised by the output:

SUCCESS 5,39 > 5.13


If I interpreted my testing correct, PHP reads the decimal values correct and compares them correctly even after the locale has changed. But as WP seems to ignore the case that the decimal point has been set to a comma value and returns just a string value when using get_option("db_version").

Question

  1. Is DB update check if(!empty($db_version) and $db_version < 5.13) of the plugin wrong or is it wrong to use setlocale() for a WP project?

  2. Any good recommendation how to solve this issue?

1 Answer 1

1

get_option() always returns a string. That has nothing to do with whether setlocale() has been used. Options are all stored in the option_value column of wp_options, which is a text column. Your float is likely being formatted for your locale when it tries to insert a float into the text column.

Your problem is that you're treating version numbers as floats, which is incorrect. They might look like floats, but version numbers are strings. For example, a float 5.2 is higher than 5.15, but 5.15 is a higher version number than 5.2.

So you can't compare version numbers by using < or > on floats. You need to use strings, and version_compare() to compare them. So first make sure to set the value as a string:

update_option( 'my_db_version', '5.13' );

Also note that db_version is an option already used by WordPress core, you need to prefix your options with something unique to your project.

Then you can compare the values like this:

$current_version = get_option( 'my_db_version' );
$new_version     = '5.39'; // String

// If the current version is lower than the new version...
if ( version_compare( $current_version, $new_version ) < 0 ) { 
    // ...update to the new version.
    update_option( 'my_db_version', $new_version );
}
1
  • Thx for the answer, you were right, the problem is when writing the value. As I mentioned in the question I'm only the maintainer of the code either the plugin nor the theme is written from me. Just have to make sure that the updates goes through and right now they only do with a little help ;) I'll inform the plugin author to fix his code.
    – wittich
    Commented Feb 25, 2020 at 0:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.