diff --git a/src/wp-includes/widgets.php b/src/wp-includes/widgets.php index 6bc1ffc6f7724..5bf9d16b31393 100644 --- a/src/wp-includes/widgets.php +++ b/src/wp-includes/widgets.php @@ -1350,6 +1350,13 @@ function retrieve_widgets( $theme_changed = false ) { $sidebars_widgets = _wp_remove_unregistered_widgets( $sidebars_widgets, $registered_widgets_ids ); $sidebars_widgets = wp_map_sidebars_widgets( $sidebars_widgets ); + // Replace non-array values inside the array with an empty array. + foreach ( $sidebars_widgets as $key => $value ) { + if ( ! is_array( $value ) ) { + $sidebars_widgets[ $key ] = array(); + } + } + // Find hidden/lost multi-widget instances. $shown_widgets = array_merge( ...array_values( $sidebars_widgets ) ); $lost_widgets = array_diff( $registered_widgets_ids, $shown_widgets ); @@ -1511,6 +1518,13 @@ function wp_map_sidebars_widgets( $existing_sidebars_widgets ) { $old_sidebars_widgets = _wp_remove_unregistered_widgets( $old_sidebars_widgets ); + // Replace non-array values inside the array with an empty array. + foreach ( $new_sidebars_widgets as $key => $value ) { + if ( ! is_array( $value ) ) { + $new_sidebars_widgets[ $key ] = array(); + } + } + if ( ! empty( $old_sidebars_widgets ) ) { // Go through each remaining sidebar... diff --git a/tests/phpunit/tests/widgets.php b/tests/phpunit/tests/widgets.php index ab4115cff2e26..a8ebf7aaa4d4d 100644 --- a/tests/phpunit/tests/widgets.php +++ b/tests/phpunit/tests/widgets.php @@ -1359,4 +1359,57 @@ public function test_sidebar_guessing_one_menu_per_sidebar() { ); $this->assertSameSetsWithIndex( $expected_sidebars, $new_next_theme_sidebars ); } + + /** + * Ensures null sidebar values are converted to empty arrays in retrieve_widgets(). + * + * @covers ::retrieve_widgets + * @ticket 57469 + */ + public function test_retrieve_widgets_converts_null_sidebar_to_empty_array() { + global $sidebars_widgets; + wp_widgets_init(); + $this->register_sidebars( array( 'primary', 'secondary', 'wp_inactive_widgets' ) ); + + $sidebars_widgets = array( + 'primary' => null, + 'secondary' => array( 'text-1' ), + 'extra_sidebar' => array( 'unregistered_widget-1' ), + 'wp_inactive_widgets' => array(), + ); + + $result = retrieve_widgets( true ); + $this->assertArrayHasKey( 'primary', $result ); + $this->assertSame( array(), $result['primary'], 'Primary sidebar should be an empty array after normalization.' ); + $this->assertArrayNotHasKey( 'extra_sidebar', $result, 'Unregistered sidebar should be removed.' ); + } + + /** + * Ensures wp_map_sidebars_widgets() normalizes null sidebar widget arrays. + * + * @covers ::wp_map_sidebars_widgets + * @ticket 57469 + */ + public function test_wp_map_sidebars_widgets_converts_null_sidebar_to_empty_array() { + $this->register_sidebars( array( 'primary', 'wp_inactive_widgets' ) ); + // Theme data containing a null so the normalization loop runs. + set_theme_mod( + 'sidebars_widgets', + array( + 'time' => time(), + 'data' => array( + 'primary' => null, + ), + ) + ); + + $prev_theme_sidebars = array( + 'primary' => null, + 'wp_inactive_widgets' => array(), + ); + + $new_sidebars = wp_map_sidebars_widgets( $prev_theme_sidebars ); + $this->assertArrayHasKey( 'primary', $new_sidebars ); + $this->assertSame( array(), $new_sidebars['primary'], 'Primary sidebar should be an empty array after normalization.' ); + } }