Make WordPress Core

Opened 3 weeks ago

Last modified 3 weeks ago

#64550 new defect (bug)

wp_update_plugins function (possibly wp_update_themes) breaks when the transient setting fails

Reported by: madhazelnut's profile madhazelnut Owned by:
Milestone: Awaiting Review Priority: normal
Severity: major Version: 6.8.3
Component: General Keywords:
Focuses: Cc:

Description

Because the result of updating the update_plugins transient is never checked at the end of the function (set_site_transient()), if the setting fails (e.g. because a plugin such as GravityView decided to use fancy emojis in their changelog) then the site becomes stuck with old versions of plugins, never displaying any updates.

To reproduce, try to make $dpdb->strip_invalid_text() return a different data array (/wp-includes/class-wpdb.php::2827). I managed to get this with [GravityView](https://www.gravitykit.com/products/gravityview/changelog), which has some new UTF emojis in the description.

Change History (4)

#1 @siliconforks
3 weeks ago

Are your MySQL tables (in particular the wp_options table) using the utf8mb4 charset? Or are they using some other charset (maybe utf8mb3 or just utf8)?

#2 @madhazelnut
3 weeks ago

I caught this issue on an utf8 table, which is, I assume how WP used to create its tables in prior versions. However, this doesn't cancel the original bug report's validity, which claims that the handling of such errors is deficient (non-existent).

#3 @siliconforks
3 weeks ago

Here's a simple plugin which demonstrates the issue.

<?php

/*
Plugin Name: Destroy All Plugin Updates
Description: This plugin might completely prevent you from getting any plugin updates.  DO NOT INSTALL THIS ON A PRODUCTION SERVER!
Version: 0.1
Update URI: https://example.test/destroy-all-plugin-updates/update
*/

add_filter(
        'update_plugins_example.test',
        static function ( $update, $plugin_data, $plugin_file, $locales ) {
                $update = [
                        'slug' => 'destroy-all-plugin-updates',
                        'version' => '0.2',
                        'url' => 'https://example.test/destroy-all-plugin-updates/details',

                        // This is U+1F680 ROCKET
                        'foobar' => "\xf0\x9f\x9a\x80",
                ];
                return $update;
        },
        10,
        4
);

To test the above plugin:

  1. You will need a utf8 database to test this - if your database is utf8mb4, you could simply change your wp_options.option_value column for testing purposes (note that this may destroy some Unicode characters in your database - do not try this on a production site):
ALTER TABLE wp_options MODIFY COLUMN option_value LONGTEXT CHARSET utf8 NOT NULL;
  1. Install an old version of some plugin - for example, Classic Editor 1.6.6.
  2. Log in to the admin section and visit the "Plugins" page. You should see "There is a new version of Classic Editor available. View version 1.6.7 details or update now."
  3. Install the above "Destroy All Plugin Updates" plugin in wp-content/plugins/destroy-all-plugin-updates/destroy-all-plugin-updates.php. Activate the plugin.
  4. Delete the old update_plugins transient. You can do this with WP-CLI:
wp transient delete --network update_plugins
  1. Now visit the "Plugins" page again. You should see there is no update available for Classic Editor (or any other plugin).
  2. Deactivate the "Destroy All Plugin Updates" plugin. You should start getting updates again.

#4 @soyebsalar01
3 weeks ago

When saying update transients fails, core appears to continue without warning and shows a misleading 'up to date' state.

Note: See TracTickets for help on using tickets.