From 614156842884fad0f831d7ab37454b10e0a10566 Mon Sep 17 00:00:00 2001 From: Joseph Scott Date: Fri, 9 Jan 2026 15:29:47 -0700 Subject: [PATCH 1/5] widgets: check if $wp_registered_widgets[ $widget ]['id'] exists https://core.trac.wordpress.org/ticket/57518 This includes a test for this condition. --- src/wp-includes/widgets.php | 2 +- tests/phpunit/tests/widgets.php | 41 +++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/wp-includes/widgets.php b/src/wp-includes/widgets.php index 6b216c2d3c119..799a5973611ae 100644 --- a/src/wp-includes/widgets.php +++ b/src/wp-includes/widgets.php @@ -925,7 +925,7 @@ function is_active_widget( $callback = false, $widget_id = false, $id_base = fal if ( is_array( $widgets ) ) { foreach ( $widgets as $widget ) { if ( ( $callback && isset( $wp_registered_widgets[ $widget ]['callback'] ) && $wp_registered_widgets[ $widget ]['callback'] === $callback ) || ( $id_base && _get_widget_id_base( $widget ) === $id_base ) ) { - if ( ! $widget_id || $widget_id === $wp_registered_widgets[ $widget ]['id'] ) { + if ( ! $widget_id || ( isset( $wp_registered_widgets[ $widget ]['id'] ) && $widget_id === $wp_registered_widgets[ $widget ]['id'] ) ) { return $sidebar; } } diff --git a/tests/phpunit/tests/widgets.php b/tests/phpunit/tests/widgets.php index a8ebf7aaa4d4d..71bd6b9f60e72 100644 --- a/tests/phpunit/tests/widgets.php +++ b/tests/phpunit/tests/widgets.php @@ -1412,4 +1412,45 @@ public function test_wp_map_sidebars_widgets_converts_null_sidebar_to_empty_arra $this->assertArrayHasKey( 'primary', $new_sidebars ); $this->assertSame( array(), $new_sidebars['primary'], 'Primary sidebar should be an empty array after normalization.' ); } + + /** + * Tests that is_active_widget() does not generate a PHP warning when + * a widget ID exists in sidebars_widgets but is not in $wp_registered_widgets, + * and the function is called with id_base and widget_id parameters. + * + * This can happen when a widget is saved to a sidebar but the widget class + * has not yet been registered (e.g., during early plugin/theme loading). + * + * @covers ::is_active_widget + */ + public function test_is_active_widget_with_unregistered_widget_and_id_base_match() { + global $wp_registered_widgets; + + // Set up a sidebar with a widget that is NOT registered in $wp_registered_widgets. + update_option( + 'sidebars_widgets', + array( + 'wp_inactive_widgets' => array(), + 'sidebar-1' => array( 'search-2' ), + 'array_version' => 3, + ) + ); + + // Ensure the widget is NOT in $wp_registered_widgets. + unset( $wp_registered_widgets['search-2'] ); + + /* + * Call is_active_widget() with id_base and widget_id parameters. + * This should NOT generate a PHP warning about accessing array offset on null. + * + * The bug occurs because when matching by id_base, the code checks + * _get_widget_id_base( $widget ) === $id_base without verifying + * $wp_registered_widgets[ $widget ] exists, then tries to access + * $wp_registered_widgets[ $widget ]['id'] on the next line. + */ + $result = is_active_widget( false, 'search-2', 'search', true ); + + // The widget is not registered, so the function should return false. + $this->assertFalse( $result ); + } } From f6842e1467983fde0cf38ac834da60989220329a Mon Sep 17 00:00:00 2001 From: Joseph Scott Date: Fri, 9 Jan 2026 15:44:18 -0700 Subject: [PATCH 2/5] Add ticket reference 58932 --- tests/phpunit/tests/widgets.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/phpunit/tests/widgets.php b/tests/phpunit/tests/widgets.php index 71bd6b9f60e72..237121abf3709 100644 --- a/tests/phpunit/tests/widgets.php +++ b/tests/phpunit/tests/widgets.php @@ -1421,6 +1421,7 @@ public function test_wp_map_sidebars_widgets_converts_null_sidebar_to_empty_arra * This can happen when a widget is saved to a sidebar but the widget class * has not yet been registered (e.g., during early plugin/theme loading). * + * @ticket 58932 * @covers ::is_active_widget */ public function test_is_active_widget_with_unregistered_widget_and_id_base_match() { From a1988f05d8b8bc8f1235d0e058bb6719182932c9 Mon Sep 17 00:00:00 2001 From: Joseph Scott Date: Fri, 9 Jan 2026 20:38:23 -0700 Subject: [PATCH 3/5] Register a sidebar for testing if none exist - fix tests --- .../widgets/wpBlockThemeRegisterClassicSidebar.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/phpunit/tests/widgets/wpBlockThemeRegisterClassicSidebar.php b/tests/phpunit/tests/widgets/wpBlockThemeRegisterClassicSidebar.php index f8f8c519ae639..1d65f2ac32fdd 100644 --- a/tests/phpunit/tests/widgets/wpBlockThemeRegisterClassicSidebar.php +++ b/tests/phpunit/tests/widgets/wpBlockThemeRegisterClassicSidebar.php @@ -32,6 +32,11 @@ public function tear_down() { public function test_a_sidebar_should_be_registered() { global $wp_registered_sidebars; + // Register a sidebar for testing if none exist. + if ( empty( $wp_registered_sidebars ) ) { + register_sidebar( array( 'id' => 'test-sidebar' ) ); + } + $sidebar_id = array_key_first( $wp_registered_sidebars ); $this->assertNotEmpty( $sidebar_id ); } @@ -42,6 +47,11 @@ public function test_a_sidebar_should_be_registered() { public function test_should_reregister_previous_theme_sidebar() { global $wp_registered_sidebars; + // Register a sidebar for testing if none exist. + if ( empty( $wp_registered_sidebars ) ) { + register_sidebar( array( 'id' => 'test-sidebar' ) ); + } + $sidebar_id = array_key_first( $wp_registered_sidebars ); switch_theme( 'block-theme' ); From ae25a5a0b25121fd76e9582fe01042176d958f7c Mon Sep 17 00:00:00 2001 From: Joseph Scott Date: Sat, 10 Jan 2026 10:00:50 -0700 Subject: [PATCH 4/5] Fix ticket reference --- tests/phpunit/tests/widgets.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/phpunit/tests/widgets.php b/tests/phpunit/tests/widgets.php index 237121abf3709..377f890bd271e 100644 --- a/tests/phpunit/tests/widgets.php +++ b/tests/phpunit/tests/widgets.php @@ -1421,7 +1421,7 @@ public function test_wp_map_sidebars_widgets_converts_null_sidebar_to_empty_arra * This can happen when a widget is saved to a sidebar but the widget class * has not yet been registered (e.g., during early plugin/theme loading). * - * @ticket 58932 + * @ticket 57518 * @covers ::is_active_widget */ public function test_is_active_widget_with_unregistered_widget_and_id_base_match() { From a8efe4ed40385a53f37909bfc5b7d23116d691c4 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Sat, 10 Jan 2026 10:20:16 -0800 Subject: [PATCH 5/5] Move comment into assertion message --- tests/phpunit/tests/widgets.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/phpunit/tests/widgets.php b/tests/phpunit/tests/widgets.php index 377f890bd271e..8eb5914c9400d 100644 --- a/tests/phpunit/tests/widgets.php +++ b/tests/phpunit/tests/widgets.php @@ -1451,7 +1451,6 @@ public function test_is_active_widget_with_unregistered_widget_and_id_base_match */ $result = is_active_widget( false, 'search-2', 'search', true ); - // The widget is not registered, so the function should return false. - $this->assertFalse( $result ); + $this->assertFalse( $result, 'The widget is not registered, so the function should return false.' ); } }