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() */