From 088c04874d374ba0f9615927de973eefff6cb0df Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Mar 2026 09:53:05 +0000 Subject: [PATCH 1/6] Initial plan From 07a0508c0c229679603f6a8e56cc6a2510b3d18d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Mar 2026 10:12:14 +0000 Subject: [PATCH 2/6] feat: add --inactive flag to `wp sidebar list` and `wp widget reset` Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> --- features/sidebar.feature | 21 +++++++++++ features/widget-reset.feature | 36 +++++++++++++++++- src/Sidebar_Command.php | 42 ++++++++++++++++++++- src/Widget_Command.php | 71 +++++++++++++++++++++++++++++------ 4 files changed, 155 insertions(+), 15 deletions(-) diff --git a/features/sidebar.feature b/features/sidebar.feature index 5e5d4315..cf56f6a1 100644 --- a/features/sidebar.feature +++ b/features/sidebar.feature @@ -23,6 +23,27 @@ Feature: Manage WordPress sidebars 4 """ + Scenario: List inactive sidebars + When I run `wp sidebar list --inactive --format=count` + Then STDOUT should be: + """ + 0 + """ + + When I run `wp eval 'update_option( "sidebars_widgets", array_merge( wp_get_sidebars_widgets(), [ "orphaned-sidebar-1" => [] ] ) );'` + And I run `wp sidebar list --inactive --fields=id --format=csv` + Then STDOUT should be: + """ + id + orphaned-sidebar-1 + """ + + When I run `wp sidebar list --fields=id --format=ids` + Then STDOUT should not contain: + """ + orphaned-sidebar-1 + """ + Scenario: Get sidebar details When I run `wp sidebar get sidebar-1` Then STDOUT should contain: diff --git a/features/widget-reset.feature b/features/widget-reset.feature index 917caef8..945059d0 100644 --- a/features/widget-reset.feature +++ b/features/widget-reset.feature @@ -24,7 +24,7 @@ Feature: Reset WordPress sidebars When I try `wp widget reset` Then STDERR should be: """ - Error: Please specify one or more sidebars, or use --all. + Error: Please specify one or more sidebars, or use --all or --inactive. """ When I try `wp widget reset sidebar-1` @@ -153,3 +153,37 @@ Feature: Reset WordPress sidebars """ calendar-1 search-1 """ + + Scenario: Reset inactive sidebars + When I try `wp widget reset --inactive` + Then STDERR should be: + """ + Error: No inactive sidebars found. + """ + And the return code should be 1 + + When I run `wp widget add calendar sidebar-1 --title="Calendar"` + Then STDOUT should not be empty + + # Simulate an inactive (unregistered) sidebar by moving widget data to an orphaned key + When I run `wp eval '$w = wp_get_sidebars_widgets(); $w["orphaned-sidebar-1"] = $w["sidebar-1"]; $w["sidebar-1"] = []; update_option( "sidebars_widgets", $w );'` + + When I run `wp sidebar list --inactive --fields=id --format=ids` + Then STDOUT should be: + """ + orphaned-sidebar-1 + """ + + When I run `wp widget reset --inactive` + Then STDOUT should be: + """ + Sidebar 'orphaned-sidebar-1' reset. + Success: Reset 1 of 1 sidebars. + """ + And the return code should be 0 + + When I run `wp widget list wp_inactive_widgets --format=ids` + Then STDOUT should contain: + """ + calendar-1 + """ diff --git a/src/Sidebar_Command.php b/src/Sidebar_Command.php index 03a15b73..336c2522 100644 --- a/src/Sidebar_Command.php +++ b/src/Sidebar_Command.php @@ -29,6 +29,9 @@ class Sidebar_Command extends WP_CLI_Command { * * ## OPTIONS * + * [--inactive] + * : If set, only inactive sidebars will be listed. + * * [--fields=] * : Limit the output to specific object fields. * @@ -68,6 +71,10 @@ class Sidebar_Command extends WP_CLI_Command { * "Widget Area",sidebar-1 * "Inactive Widgets",wp_inactive_widgets * + * $ wp sidebar list --inactive --fields=id --format=csv + * id + * old-sidebar-1 + * * @subcommand list */ public function list_( $args, $assoc_args ) { @@ -75,12 +82,43 @@ public function list_( $args, $assoc_args ) { Utils\wp_register_unused_sidebar(); - if ( ! empty( $assoc_args['format'] ) && 'ids' === $assoc_args['format'] ) { - $sidebars = wp_list_pluck( $wp_registered_sidebars, 'id' ); + $inactive = Utils\get_flag_value( $assoc_args, 'inactive', false ); + + if ( $inactive ) { + $sidebars_widgets = get_option( 'sidebars_widgets', [] ); + if ( is_array( $sidebars_widgets ) && isset( $sidebars_widgets['array_version'] ) ) { + unset( $sidebars_widgets['array_version'] ); + } + $registered_ids = array_keys( $wp_registered_sidebars ); + $inactive_sidebar_ids = array_values( + array_filter( + array_diff( array_keys( $sidebars_widgets ), $registered_ids ), + static function ( $id ) { + return 'wp_inactive_widgets' !== $id; + } + ) + ); + $sidebars = []; + foreach ( $inactive_sidebar_ids as $sidebar_id ) { + $sidebars[ $sidebar_id ] = [ + 'name' => $sidebar_id, + 'id' => $sidebar_id, + 'description' => '', + 'class' => '', + 'before_widget' => '', + 'after_widget' => '', + 'before_title' => '', + 'after_title' => '', + ]; + } } else { $sidebars = $wp_registered_sidebars; } + if ( ! empty( $assoc_args['format'] ) && 'ids' === $assoc_args['format'] ) { + $sidebars = wp_list_pluck( $sidebars, 'id' ); + } + $formatter = new Formatter( $assoc_args, $this->fields ); $formatter->display_items( $sidebars ); } diff --git a/src/Widget_Command.php b/src/Widget_Command.php index 8b8619f7..748e67dc 100644 --- a/src/Widget_Command.php +++ b/src/Widget_Command.php @@ -478,6 +478,9 @@ public function delete( $args, $assoc_args ) { * [--all] * : If set, all sidebars will be reset. * + * [--inactive] + * : If set, only inactive sidebars will be reset. + * * ## EXAMPLES * * # Reset a sidebar @@ -494,37 +497,60 @@ public function delete( $args, $assoc_args ) { * Success: Sidebar 'sidebar-1' reset. * Success: Sidebar 'sidebar-2' reset. * Success: Sidebar 'sidebar-3' reset. + * + * # Reset all inactive sidebars + * $ wp widget reset --inactive + * Success: Sidebar 'old-sidebar-1' reset. */ public function reset( $args, $assoc_args ) { global $wp_registered_sidebars; - $all = Utils\get_flag_value( $assoc_args, 'all', false ); + $all = Utils\get_flag_value( $assoc_args, 'all', false ); + $inactive = Utils\get_flag_value( $assoc_args, 'inactive', false ); - // Bail if no arguments and no all flag. - if ( ! $all && empty( $args ) ) { - WP_CLI::error( 'Please specify one or more sidebars, or use --all.' ); + // Bail if no arguments and no --all or --inactive flag. + if ( ! $all && ! $inactive && empty( $args ) ) { + WP_CLI::error( 'Please specify one or more sidebars, or use --all or --inactive.' ); } - // Fetch all sidebars if all flag is set. + // Fetch all registered sidebars if --all flag is set. if ( $all ) { $args = array_keys( $wp_registered_sidebars ); } // Sidebar ID wp_inactive_widgets is reserved by WP core for inactive widgets. - if ( isset( $args['wp_inactive_widgets'] ) ) { - unset( $args['wp_inactive_widgets'] ); + $args = array_values( + array_filter( + $args, + static function ( $id ) { + return 'wp_inactive_widgets' !== $id; + } + ) + ); + + // Collect inactive (unregistered) sidebar IDs if --inactive flag is set. + $inactive_args = []; + if ( $inactive ) { + $inactive_args = $this->get_inactive_sidebar_ids(); } - // Check if no registered sidebar. - if ( empty( $args ) ) { + $all_args = array_merge( $args, $inactive_args ); + + // Check if there are no sidebars to reset. + if ( empty( $all_args ) ) { + if ( $inactive && empty( $inactive_args ) ) { + WP_CLI::error( 'No inactive sidebars found.' ); + } WP_CLI::error( 'No sidebar registered.' ); } $count = 0; $errors = 0; - foreach ( $args as $sidebar_id ) { - if ( ! array_key_exists( $sidebar_id, $wp_registered_sidebars ) ) { + foreach ( $all_args as $sidebar_id ) { + // Skip registration validation for sidebars resolved via --inactive. + if ( ! in_array( $sidebar_id, $inactive_args, true ) && + ! array_key_exists( $sidebar_id, $wp_registered_sidebars ) ) { WP_CLI::warning( sprintf( 'Invalid sidebar: %s', $sidebar_id ) ); ++$errors; continue; @@ -550,7 +576,28 @@ public function reset( $args, $assoc_args ) { } } - Utils\report_batch_operation_results( 'sidebar', 'reset', count( $args ), $count, $errors ); + Utils\report_batch_operation_results( 'sidebar', 'reset', count( $all_args ), $count, $errors ); + } + + /** + * Returns the IDs of sidebars that exist in the database but are not currently registered. + * + * @return string[] + */ + private function get_inactive_sidebar_ids() { + global $wp_registered_sidebars; + + $all_sidebar_ids = array_keys( $this->wp_get_sidebars_widgets() ); + $registered_ids = array_keys( $wp_registered_sidebars ); + + return array_values( + array_filter( + array_diff( $all_sidebar_ids, $registered_ids ), + static function ( $id ) { + return 'wp_inactive_widgets' !== $id; + } + ) + ); } /** From f9247ed5650d79d39504b2a4fb76dcfd833d5350 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Tue, 17 Mar 2026 12:27:42 +0100 Subject: [PATCH 3/6] Update features/widget-reset.feature --- features/widget-reset.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/widget-reset.feature b/features/widget-reset.feature index 945059d0..6f923dc1 100644 --- a/features/widget-reset.feature +++ b/features/widget-reset.feature @@ -168,7 +168,7 @@ Feature: Reset WordPress sidebars # Simulate an inactive (unregistered) sidebar by moving widget data to an orphaned key When I run `wp eval '$w = wp_get_sidebars_widgets(); $w["orphaned-sidebar-1"] = $w["sidebar-1"]; $w["sidebar-1"] = []; update_option( "sidebars_widgets", $w );'` - When I run `wp sidebar list --inactive --fields=id --format=ids` + And I run `wp sidebar list --inactive --fields=id --format=ids` Then STDOUT should be: """ orphaned-sidebar-1 From 4d6573b76ae5a59173e19548e330e93e21353fa0 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Tue, 17 Mar 2026 12:44:04 +0100 Subject: [PATCH 4/6] Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/Sidebar_Command.php | 5 ++++- src/Widget_Command.php | 28 ++++++++++++++++++++-------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/Sidebar_Command.php b/src/Sidebar_Command.php index 336c2522..b39a06af 100644 --- a/src/Sidebar_Command.php +++ b/src/Sidebar_Command.php @@ -86,7 +86,10 @@ public function list_( $args, $assoc_args ) { if ( $inactive ) { $sidebars_widgets = get_option( 'sidebars_widgets', [] ); - if ( is_array( $sidebars_widgets ) && isset( $sidebars_widgets['array_version'] ) ) { + if ( ! is_array( $sidebars_widgets ) ) { + $sidebars_widgets = []; + } + if ( isset( $sidebars_widgets['array_version'] ) ) { unset( $sidebars_widgets['array_version'] ); } $registered_ids = array_keys( $wp_registered_sidebars ); diff --git a/src/Widget_Command.php b/src/Widget_Command.php index 748e67dc..90388885 100644 --- a/src/Widget_Command.php +++ b/src/Widget_Command.php @@ -485,22 +485,22 @@ public function delete( $args, $assoc_args ) { * * # Reset a sidebar * $ wp widget reset sidebar-1 - * Success: Sidebar 'sidebar-1' reset. + * Sidebar 'sidebar-1' reset. * * # Reset multiple sidebars * $ wp widget reset sidebar-1 sidebar-2 - * Success: Sidebar 'sidebar-1' reset. - * Success: Sidebar 'sidebar-2' reset. + * Sidebar 'sidebar-1' reset. + * Sidebar 'sidebar-2' reset. * * # Reset all sidebars * $ wp widget reset --all - * Success: Sidebar 'sidebar-1' reset. - * Success: Sidebar 'sidebar-2' reset. - * Success: Sidebar 'sidebar-3' reset. + * Sidebar 'sidebar-1' reset. + * Sidebar 'sidebar-2' reset. + * Sidebar 'sidebar-3' reset. * * # Reset all inactive sidebars * $ wp widget reset --inactive - * Success: Sidebar 'old-sidebar-1' reset. + * Sidebar 'old-sidebar-1' reset. */ public function reset( $args, $assoc_args ) { @@ -514,6 +514,11 @@ public function reset( $args, $assoc_args ) { WP_CLI::error( 'Please specify one or more sidebars, or use --all or --inactive.' ); } + // Explicitly handle reserved sidebar ID for inactive widgets. + if ( in_array( 'wp_inactive_widgets', $args, true ) ) { + WP_CLI::error( "Sidebar 'wp_inactive_widgets' is reserved for inactive widgets. Use the --inactive flag instead." ); + } + // Fetch all registered sidebars if --all flag is set. if ( $all ) { $args = array_keys( $wp_registered_sidebars ); @@ -536,6 +541,7 @@ static function ( $id ) { } $all_args = array_merge( $args, $inactive_args ); + $all_args = array_values( array_unique( $all_args ) ); // Check if there are no sidebars to reset. if ( empty( $all_args ) ) { @@ -587,7 +593,13 @@ static function ( $id ) { private function get_inactive_sidebar_ids() { global $wp_registered_sidebars; - $all_sidebar_ids = array_keys( $this->wp_get_sidebars_widgets() ); + $sidebars_widgets = $this->wp_get_sidebars_widgets(); + + if ( ! is_array( $sidebars_widgets ) ) { + $sidebars_widgets = []; + } + + $all_sidebar_ids = array_keys( $sidebars_widgets ); $registered_ids = array_keys( $wp_registered_sidebars ); return array_values( From d140a8d58d385940f585e6ff87de581203520d96 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Tue, 17 Mar 2026 12:51:14 +0100 Subject: [PATCH 5/6] Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/Widget_Command.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Widget_Command.php b/src/Widget_Command.php index 90388885..a044101b 100644 --- a/src/Widget_Command.php +++ b/src/Widget_Command.php @@ -479,7 +479,7 @@ public function delete( $args, $assoc_args ) { * : If set, all sidebars will be reset. * * [--inactive] - * : If set, only inactive sidebars will be reset. + * : If set, all inactive sidebars will also be reset, in addition to any sidebars specified via ... or selected with --all. * * ## EXAMPLES * @@ -516,7 +516,7 @@ public function reset( $args, $assoc_args ) { // Explicitly handle reserved sidebar ID for inactive widgets. if ( in_array( 'wp_inactive_widgets', $args, true ) ) { - WP_CLI::error( "Sidebar 'wp_inactive_widgets' is reserved for inactive widgets. Use the --inactive flag instead." ); + WP_CLI::error( "Sidebar 'wp_inactive_widgets' is reserved for inactive widgets and cannot be reset with this command. The --inactive flag only targets widgets from orphaned or unregistered sidebars, not 'wp_inactive_widgets' itself." ); } // Fetch all registered sidebars if --all flag is set. From 9fd7df47fa3db2e7184c8117d9f0bbc63daa1e76 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Mar 2026 12:12:56 +0000 Subject: [PATCH 6/6] refactor: centralize get_inactive_sidebar_ids() in Sidebar_Command as public static method Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> --- src/Sidebar_Command.php | 48 +++++++++++++++++++++++++---------------- src/Widget_Command.php | 29 +------------------------ 2 files changed, 31 insertions(+), 46 deletions(-) diff --git a/src/Sidebar_Command.php b/src/Sidebar_Command.php index b39a06af..aa8439d4 100644 --- a/src/Sidebar_Command.php +++ b/src/Sidebar_Command.php @@ -85,24 +85,8 @@ public function list_( $args, $assoc_args ) { $inactive = Utils\get_flag_value( $assoc_args, 'inactive', false ); if ( $inactive ) { - $sidebars_widgets = get_option( 'sidebars_widgets', [] ); - if ( ! is_array( $sidebars_widgets ) ) { - $sidebars_widgets = []; - } - if ( isset( $sidebars_widgets['array_version'] ) ) { - unset( $sidebars_widgets['array_version'] ); - } - $registered_ids = array_keys( $wp_registered_sidebars ); - $inactive_sidebar_ids = array_values( - array_filter( - array_diff( array_keys( $sidebars_widgets ), $registered_ids ), - static function ( $id ) { - return 'wp_inactive_widgets' !== $id; - } - ) - ); - $sidebars = []; - foreach ( $inactive_sidebar_ids as $sidebar_id ) { + $sidebars = []; + foreach ( self::get_inactive_sidebar_ids() as $sidebar_id ) { $sidebars[ $sidebar_id ] = [ 'name' => $sidebar_id, 'id' => $sidebar_id, @@ -126,6 +110,34 @@ static function ( $id ) { $formatter->display_items( $sidebars ); } + /** + * Returns the IDs of sidebars that exist in the database but are not currently registered. + * + * @return string[] + */ + public static function get_inactive_sidebar_ids() { + global $wp_registered_sidebars; + + $sidebars_widgets = get_option( 'sidebars_widgets', [] ); + if ( ! is_array( $sidebars_widgets ) ) { + $sidebars_widgets = []; + } + if ( isset( $sidebars_widgets['array_version'] ) ) { + unset( $sidebars_widgets['array_version'] ); + } + + $registered_ids = array_keys( $wp_registered_sidebars ); + + return array_values( + array_filter( + array_diff( array_keys( $sidebars_widgets ), $registered_ids ), + static function ( $id ) { + return 'wp_inactive_widgets' !== $id; + } + ) + ); + } + /** * Get details about a specific sidebar. * diff --git a/src/Widget_Command.php b/src/Widget_Command.php index a044101b..4eed6ebd 100644 --- a/src/Widget_Command.php +++ b/src/Widget_Command.php @@ -537,7 +537,7 @@ static function ( $id ) { // Collect inactive (unregistered) sidebar IDs if --inactive flag is set. $inactive_args = []; if ( $inactive ) { - $inactive_args = $this->get_inactive_sidebar_ids(); + $inactive_args = Sidebar_Command::get_inactive_sidebar_ids(); } $all_args = array_merge( $args, $inactive_args ); @@ -585,33 +585,6 @@ static function ( $id ) { Utils\report_batch_operation_results( 'sidebar', 'reset', count( $all_args ), $count, $errors ); } - /** - * Returns the IDs of sidebars that exist in the database but are not currently registered. - * - * @return string[] - */ - private function get_inactive_sidebar_ids() { - global $wp_registered_sidebars; - - $sidebars_widgets = $this->wp_get_sidebars_widgets(); - - if ( ! is_array( $sidebars_widgets ) ) { - $sidebars_widgets = []; - } - - $all_sidebar_ids = array_keys( $sidebars_widgets ); - $registered_ids = array_keys( $wp_registered_sidebars ); - - return array_values( - array_filter( - array_diff( $all_sidebar_ids, $registered_ids ), - static function ( $id ) { - return 'wp_inactive_widgets' !== $id; - } - ) - ); - } - /** * Checks whether a sidebar is a valid sidebar *