diff --git a/features/cron-event.feature b/features/cron-event.feature index 06644e02..e07ecf45 100644 --- a/features/cron-event.feature +++ b/features/cron-event.feature @@ -159,6 +159,45 @@ Feature: Manage WP Cron events Debug: Arguments: """ + Scenario: Run cron events with --network flag on non-multisite + When I try `wp cron event run --due-now --network` + Then STDERR should be: + """ + Error: This is not a multisite installation. + """ + And the return code should be 1 + + Scenario: Run cron events with --network flag on multisite + Given a WP multisite subdirectory install + And I run `wp site create --slug=site2` + And I run `wp site create --slug=site3` + + When I run `wp cron event schedule wp_cli_network_test now` + Then STDOUT should contain: + """ + Success: Scheduled event with hook 'wp_cli_network_test' + """ + + When I run `wp --url=example.com/site2 cron event schedule wp_cli_network_test_site2 now` + Then STDOUT should contain: + """ + Success: Scheduled event with hook 'wp_cli_network_test_site2' + """ + + When I run `wp cron event run --due-now --network --exclude=wp_privacy_delete_old_export_files,wp_version_check,wp_update_plugins,wp_update_themes,wp_site_health_scheduled_check,wp_update_user_counts,wp_scheduled_delete,wp_scheduled_auto_draft_delete` + Then STDOUT should contain: + """ + Executed the cron event 'wp_cli_network_test' + """ + And STDOUT should contain: + """ + Executed the cron event 'wp_cli_network_test_site2' + """ + And STDOUT should contain: + """ + Success: Executed a total of 2 cron events across 3 sites. + """ + Scenario: Confirm that cron event run in debug mode shows the start of events When I try `wp cron event run wp_version_check --debug=cron` Then STDOUT should contain: diff --git a/src/Cron_Event_Command.php b/src/Cron_Event_Command.php index 7896396a..bb7452d7 100644 --- a/src/Cron_Event_Command.php +++ b/src/Cron_Event_Command.php @@ -225,6 +225,9 @@ public function schedule( $args, $assoc_args ) { * [--all] * : Run all hooks. * + * [--network] + * : Run hooks across all sites in a multisite installation. + * * ## EXAMPLES * * # Run all cron events due right now @@ -232,27 +235,72 @@ public function schedule( $args, $assoc_args ) { * Executed the cron event 'cron_test_1' in 0.01s. * Executed the cron event 'cron_test_2' in 0.006s. * Success: Executed a total of 2 cron events. + * + * # Run all cron events due right now across all sites in a multisite + * $ wp cron event run --due-now --network + * Executed the cron event 'cron_test_1' in 0.01s. + * Executed the cron event 'cron_test_2' in 0.006s. + * Success: Executed a total of 2 cron events across 3 sites. */ public function run( $args, $assoc_args ) { + $network = Utils\get_flag_value( $assoc_args, 'network' ); + + if ( $network ) { + if ( ! is_multisite() ) { + WP_CLI::error( 'This is not a multisite installation.' ); + } + + $sites = get_sites( + array( + 'fields' => 'ids', + 'number' => 0, + ) + ); + + if ( empty( $sites ) ) { + WP_CLI::error( 'No sites found in the network.' ); + } + + // Remove network flag before passing to get_selected_cron_events. + $network_assoc_args = $assoc_args; + unset( $network_assoc_args['network'] ); + + $total_executed = 0; + $site_count = count( $sites ); + + foreach ( $sites as $site_id ) { + switch_to_blog( $site_id ); + + $events = self::get_selected_cron_events( $args, $network_assoc_args ); + + if ( ! is_wp_error( $events ) ) { + $total_executed += self::run_events( $events ); + } else { + WP_CLI::debug( sprintf( 'No events found for site %d: %s', $site_id, $events->get_error_message() ), 'cron' ); + } + + restore_current_blog(); + } + + $message = sprintf( + 'Executed a total of %d %s across %d %s.', + $total_executed, + Utils\pluralize( 'cron event', $total_executed ), + $site_count, + Utils\pluralize( 'site', $site_count ) + ); + WP_CLI::success( $message ); + return; + } + $events = self::get_selected_cron_events( $args, $assoc_args ); if ( is_wp_error( $events ) ) { WP_CLI::error( $events ); } - $executed = 0; - foreach ( $events as $event ) { - WP_CLI::debug( sprintf( "Beginning execution of cron event '%s'.", $event->hook ), 'cron' ); - $start = microtime( true ); - $result = self::run_event( $event ); - $total = round( microtime( true ) - $start, 3 ); - ++$executed; - WP_CLI::log( sprintf( "Executed the cron event '%s' in %ss.", $event->hook, $total ) ); - if ( ! empty( $event->args ) ) { - WP_CLI::debug( sprintf( 'Arguments: %s', wp_json_encode( $event->args ) ), 'cron' ); - } - } + $executed = self::run_events( $events ); $message = ( 1 === $executed ) ? 'Executed a total of %d cron event.' : 'Executed a total of %d cron events.'; WP_CLI::success( sprintf( $message, $executed ) ); @@ -344,6 +392,30 @@ public function delete( $args, $assoc_args ) { WP_CLI::success( sprintf( $message, $deleted ) ); } + /** + * Runs multiple cron events and logs their execution. + * + * @param array $events Array of event objects to run. + * @return int The number of events executed. + */ + private static function run_events( array $events ) { + $executed = 0; + + foreach ( $events as $event ) { + WP_CLI::debug( sprintf( "Beginning execution of cron event '%s'.", $event->hook ), 'cron' ); + $start = microtime( true ); + self::run_event( $event ); + $total = round( microtime( true ) - $start, 3 ); + ++$executed; + WP_CLI::log( sprintf( "Executed the cron event '%s' in %ss.", $event->hook, $total ) ); + if ( ! empty( $event->args ) ) { + WP_CLI::debug( sprintf( 'Arguments: %s', wp_json_encode( $event->args ) ), 'cron' ); + } + } + + return $executed; + } + /** * Executes an event immediately. *