settings = $settings; $this->sync_service = $sync_service; add_filter( 'cron_schedules', array( $this, 'add_schedule' ) ); add_action( self::CRON_HOOK, array( $this, 'run_sync' ) ); add_action( 'rest_api_init', array( $this, 'register_rest_routes' ) ); } /** * Adds the custom sync interval based on plugin settings. * * @param array> $schedules Existing schedules. * @return array> */ public function add_schedule( $schedules ) { $minutes = max( 5, absint( $this->settings->get( 'sync_frequency', 30 ) ) ); $schedules['aibp_custom_interval'] = array( 'interval' => $minutes * MINUTE_IN_SECONDS, 'display' => sprintf( /* translators: %d: number of minutes */ __( 'Every %d minutes (AI Blog Poster)', 'ai-blog-poster' ), $minutes ), ); return $schedules; } /** * Re-registers the plugin cron event using the latest interval. */ public function register_schedule() { $this->clear_schedule(); if ( ! $this->is_wp_cron_enabled() ) { return; } if ( ! wp_next_scheduled( self::CRON_HOOK ) ) { wp_schedule_event( time() + MINUTE_IN_SECONDS, 'aibp_custom_interval', self::CRON_HOOK ); } } /** * Removes all scheduled plugin cron events. */ public function clear_schedule() { $timestamp = wp_next_scheduled( self::CRON_HOOK ); while ( $timestamp ) { wp_unschedule_event( $timestamp, self::CRON_HOOK ); $timestamp = wp_next_scheduled( self::CRON_HOOK ); } } /** * Runs the shared sync routine for cron. */ public function run_sync() { $this->sync_service->sync( 'wp_cron' ); } /** * Registers a token-protected REST route for server cron usage. */ public function register_rest_routes() { register_rest_route( self::REST_NAMESPACE, self::REST_ROUTE, array( 'methods' => 'GET', 'callback' => array( $this, 'handle_manual_cron_request' ), 'permission_callback' => array( $this, 'can_run_manual_cron_request' ), ) ); } /** * Validates the token sent to the manual cron endpoint. * * @param \WP_REST_Request $request Incoming request. * @return bool */ public function can_run_manual_cron_request( \WP_REST_Request $request ) { $token = (string) $request->get_param( 'token' ); return ! empty( $token ) && hash_equals( (string) $this->settings->get( 'cron_token', '' ), $token ); } /** * Executes sync from the manual cron REST endpoint. * * @param \WP_REST_Request $request Incoming request. * @return \WP_REST_Response */ public function handle_manual_cron_request( \WP_REST_Request $request ) { $result = $this->sync_service->sync( 'manual_cron' ); if ( is_wp_error( $result ) ) { return new \WP_REST_Response( array( 'success' => false, 'message' => $result->get_error_message(), ), 500 ); } return new \WP_REST_Response( array( 'success' => true, 'result' => $result, ), 200 ); } /** * Returns whether WP-Cron scheduling is enabled in plugin settings. * * @return bool */ public function is_wp_cron_enabled() { return 'wp_cron' === $this->settings->get( 'sync_mode', 'wp_cron' ); } /** * Returns the full manual cron URL with token. * * @return string */ public function get_manual_cron_url() { $url = add_query_arg( array( 'token' => (string) $this->settings->get( 'cron_token', '' ), ), rest_url( self::REST_NAMESPACE . self::REST_ROUTE ) ); // Keep the REST route readable when WordPress uses the plain permalink fallback. return str_replace( array( '%2F', '%2f' ), '/', $url ); } }