From f042981494410d3b8f498487facf30cc61823b65 Mon Sep 17 00:00:00 2001 From: Peter Wilson Date: Fri, 9 Sep 2022 02:17:33 +0000 Subject: [PATCH] Widgets: Store default options for uninitialized widgets. Prevent unnecessary database queries on page load by initializing widget options. On sites with uninitialized widgets, this prevents one or two database queries per uninitialized widget on each page load. Props Chouby, mvraghavan, costdev, peterwilsoncc, spacedmonkey, mukesh27. Fixes #54677. git-svn-id: https://develop.svn.wordpress.org/trunk@54112 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/class-wp-widget.php | 12 ++++--- tests/phpunit/tests/widgets.php | 55 +++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/src/wp-includes/class-wp-widget.php b/src/wp-includes/class-wp-widget.php index e91f5cd9f9..086e9e9ffb 100644 --- a/src/wp-includes/class-wp-widget.php +++ b/src/wp-includes/class-wp-widget.php @@ -612,12 +612,16 @@ class WP_Widget { $settings = get_option( $this->option_name ); if ( false === $settings ) { + $settings = array(); if ( isset( $this->alt_option_name ) ) { - $settings = get_option( $this->alt_option_name ); - } else { - // Save an option so it can be autoloaded next time. - $this->save_settings( array() ); + // Get settings from alternative (legacy) option. + $settings = get_option( $this->alt_option_name, array() ); + + // Delete the alternative (legacy) option as the new option will be created using `$this->option_name`. + delete_option( $this->alt_option_name ); } + // Save an option so it can be autoloaded next time. + $this->save_settings( $settings ); } if ( ! is_array( $settings ) && ! ( $settings instanceof ArrayObject || $settings instanceof ArrayIterator ) ) { diff --git a/tests/phpunit/tests/widgets.php b/tests/phpunit/tests/widgets.php index 7cfce4719b..527798f7a4 100644 --- a/tests/phpunit/tests/widgets.php +++ b/tests/phpunit/tests/widgets.php @@ -686,6 +686,61 @@ class Tests_Widgets extends WP_UnitTestCase { $this->assertArrayNotHasKey( 0, $never_used ); } + /** + * @ticket 54677 + * + * @covers WP_Widget::get_settings + */ + public function test_wp_widget_initializes_widget_with_alt_option() { + /* + * Emulate a new the recent posts widget. + * + * The widget contains an alternative (legacy) option so both the + * current and the alternative option need to be deleted. + */ + delete_option( 'widget_recent-posts' ); + delete_option( 'widget_recent_entries' ); + + $this->assertFalse( get_option( 'widget_recent-posts' ), 'The option widget_recent-posts was not deleted.' ); + $this->assertFalse( get_option( 'widget_recent_entries' ), 'The option widget_recent_entries was not deleted.' ); + + wp_widgets_init(); + $this->assertSameSetsWithIndex( array( '_multiwidget' => 1 ), get_option( 'widget_recent-posts' ), 'Option failed to be initialized.' ); + $this->assertFalse( get_option( 'widget_recent_entries' ), 'Alternative option is set.' ); + } + + /** + * @ticket 54677 + * + * @covers WP_Widget::get_settings + */ + public function test_wp_widget_migrates_widget_with_alt_option() { + $option = array( + 2 => array( + 'title' => 'Recent Posts', + 'number' => 5, + 'show_date' => false, + ), + '_multiwidget' => 1, + ); + + /* + * Emulate the recent posts widget with an alternative option. + * + * The widget contains an alternative (legacy) option so the + * current option is deleted while the alternative option is created. + */ + delete_option( 'widget_recent-posts' ); + update_option( 'widget_recent_entries', $option ); + + $this->assertFalse( get_option( 'widget_recent-posts' ), 'The option widget_recent-posts was not deleted.' ); + $this->assertSameSetsWithIndex( $option, get_option( 'widget_recent_entries' ), 'The option widget_recent_entries was not set to the default.' ); + + wp_widgets_init(); + $this->assertSameSetsWithIndex( $option, get_option( 'widget_recent-posts' ), 'Option failed to be converted to new name.' ); + $this->assertFalse( get_option( 'widget_recent_entries' ), 'Alternative option was not deleted.' ); + } + /** * @see WP_Widget::save_settings() */