diff --git a/features/cron.feature b/features/cron.feature index 946b3c5e..b51ff312 100644 --- a/features/cron.feature +++ b/features/cron.feature @@ -583,3 +583,68 @@ Feature: Manage WP-Cron events and schedules """ Error: Please either specify cron events, or use --all. """ + + Scenario: Delete a specific cron event by matching args + When I run `wp cron event schedule wp_cli_test_event_5 '+20 minutes' --0=banana` + And I run `wp cron event schedule wp_cli_test_event_5 '+20 minutes' --0=bar` + Then STDOUT should not be empty + + When I run `wp cron event list --format=csv --fields=hook,recurrence,args` + Then STDOUT should be CSV containing: + | hook | recurrence | args | + | wp_cli_test_event_5 | Non-repeating | ["banana"] | + | wp_cli_test_event_5 | Non-repeating | ["bar"] | + + When I run `wp cron event delete wp_cli_test_event_5 --match-args='["banana"]'` + Then STDOUT should be: + """ + Success: Deleted a total of 1 cron event. + """ + + When I run `wp cron event list --format=csv --fields=hook,args` + Then STDOUT should be CSV containing: + | hook | args | + | wp_cli_test_event_5 | ["bar"] | + And STDOUT should not contain: + """ + ["banana"] + """ + + When I run `wp cron event delete wp_cli_test_event_5 --match-args=bar` + Then STDOUT should be: + """ + Success: Deleted a total of 1 cron event. + """ + + When I try `wp cron event list` + Then STDOUT should not contain: + """ + wp_cli_test_event_5 + """ + + When I run `wp cron event schedule wp_cli_test_event_5 '+20 minutes' --0=banana` + Then STDOUT should not be empty + + When I try `wp cron event delete wp_cli_test_event_5 --match-args='["banana"]' --all` + Then STDERR should be: + """ + Error: The --match-args parameter cannot be combined with --all or --due-now. + """ + + When I try `wp cron event delete wp_cli_test_event_5 --match-args='["banana"]' --due-now` + Then STDERR should be: + """ + Error: The --match-args parameter cannot be combined with --all or --due-now. + """ + + When I try `wp cron event delete --match-args='["banana"]'` + Then STDERR should be: + """ + Error: The --match-args parameter requires exactly one hook name. + """ + + When I try `wp cron event delete wp_cli_test_event_5 wp_cli_test_event_5 --match-args='["banana"]'` + Then STDERR should be: + """ + Error: The --match-args parameter requires exactly one hook name. + """ diff --git a/src/Cron_Event_Command.php b/src/Cron_Event_Command.php index 263deb64..6f09df9b 100644 --- a/src/Cron_Event_Command.php +++ b/src/Cron_Event_Command.php @@ -326,19 +326,55 @@ public function unschedule( $args, $assoc_args ) { * [--all] * : Delete all hooks. * + * [--match-args=] + * : Only delete events whose arguments match the given JSON-encoded array or scalar value. Requires exactly one hook name. + * * ## EXAMPLES * * # Delete all scheduled cron events for the given hook * $ wp cron event delete cron_test * Success: Deleted a total of 2 cron events. + * + * # Delete a specific cron event by hook and arguments + * $ wp cron event delete cron_test --match-args='[123]' + * Success: Deleted a total of 1 cron event. */ public function delete( $args, $assoc_args ) { + $match_args = Utils\get_flag_value( $assoc_args, 'match-args' ); + + if ( null !== $match_args ) { + if ( 1 !== count( $args ) ) { + WP_CLI::error( 'The --match-args parameter requires exactly one hook name.' ); + } + + if ( Utils\get_flag_value( $assoc_args, 'all' ) || Utils\get_flag_value( $assoc_args, 'due-now' ) ) { + WP_CLI::error( 'The --match-args parameter cannot be combined with --all or --due-now.' ); + } + + $decoded_args = json_decode( $match_args, true ); + if ( null === $decoded_args && JSON_ERROR_NONE !== json_last_error() ) { + // Not valid JSON — treat as a single string argument wrapped in an array. + $decoded_args = array( $match_args ); + } elseif ( ! is_array( $decoded_args ) ) { + $decoded_args = array( $decoded_args ); + } + } + $events = self::get_selected_cron_events( $args, $assoc_args ); if ( is_wp_error( $events ) ) { WP_CLI::error( $events ); } + if ( null !== $match_args ) { + $events = array_filter( + $events, + function ( $event ) use ( $decoded_args ) { + return $event->args === $decoded_args; + } + ); + } + $deleted = 0; foreach ( $events as $event ) { $result = self::delete_event( $event );