sed in the action claim query. * * @since x.x.x * * @param string $order_by_sql */ $order = apply_filters( 'action_scheduler_claim_actions_order_by', 'ORDER BY attempts ASC, scheduled_date_gmt ASC, action_id ASC' ); $params[] = $limit; $sql = $wpdb->prepare( "{$update} {$where} {$order} LIMIT %d", $params ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders $rows_affected = $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching if ( false === $rows_affected ) { throw new \RuntimeException( __( 'Unable to claim actions. Database error.', 'action-scheduler' ) ); } return (int) $rows_affected; } /** * Get the number of active claims. * * @return int */ public function get_claim_count() { global $wpdb; $sql = "SELECT COUNT(DISTINCT claim_id) FROM {$wpdb->actionscheduler_actions} WHERE claim_id != 0 AND status IN ( %s, %s)"; $sql = $wpdb->prepare( $sql, array( self::STATUS_PENDING, self::STATUS_RUNNING ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared return (int) $wpdb->get_var( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared } /** * Return an action's claim ID, as stored in the claim_id column. * * @param string $action_id Action ID. * @return mixed */ public function get_claim_id( $action_id ) { /** @var \wpdb $wpdb */ global $wpdb; $sql = "SELECT claim_id FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d"; $sql = $wpdb->prepare( $sql, $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared return (int) $wpdb->get_var( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared } /** * Retrieve the action IDs of action in a claim. * * @param int $claim_id Claim ID. * @return int[] */ public function find_actions_by_claim_id( $claim_id ) { /** @var \wpdb $wpdb */ global $wpdb; $action_ids = array(); $before_date = isset( $this->claim_before_date ) ? $this->claim_before_date : as_get_datetime_object(); $cut_off = $before_date->format( 'Y-m-d H:i:s' ); $sql = $wpdb->prepare( "SELECT action_id, scheduled_date_gmt FROM {$wpdb->actionscheduler_actions} WHERE claim_id = %d", $claim_id ); // Verify that the scheduled date for each action is within the expected bounds (in some unusual // cases, we cannot depend on MySQL to honor all of the WHERE conditions we specify). foreach ( $wpdb->get_results( $sql ) as $claimed_action ) { // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared if ( $claimed_action->scheduled_date_gmt <= $cut_off ) { $action_ids[] = absint( $claimed_action->action_id ); } } return $action_ids; } /** * Release actions from a claim and delete the claim. * * @param ActionScheduler_ActionClaim $claim Claim object. */ public function release_claim( ActionScheduler_ActionClaim $claim ) { /** @var \wpdb $wpdb */ global $wpdb; $wpdb->update( $wpdb->actionscheduler_actions, array( 'claim_id' => 0 ), array( 'claim_id' => $claim->get_id() ), array( '%d' ), array( '%d' ) ); $wpdb->delete( $wpdb->actionscheduler_claims, array( 'claim_id' => $claim->get_id() ), array( '%d' ) ); } /** * Remove the claim from an action. * * @param int $action_id Action ID. * * @return void */ public function unclaim_action( $action_id ) { /** @var \wpdb $wpdb */ global $wpdb; $wpdb->update( $wpdb->actionscheduler_actions, array( 'claim_id' => 0 ), array( 'action_id' => $action_id ), array( '%s' ), array( '%d' ) ); } /** * Mark an action as failed. * * @param int $action_id Action ID. * @throws \InvalidArgumentException Throw an exception if action was not updated. */ public function mark_failure( $action_id ) { /** @var \wpdb $wpdb */ global $wpdb; $updated = $wpdb->update( $wpdb->actionscheduler_actions, array( 'status' => self::STATUS_FAILED ), array( 'action_id' => $action_id ), array( '%s' ), array( '%d' ) ); if ( empty( $updated ) ) { throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment } } /** * Add execution message to action log. * * @param int $action_id Action ID. * * @return void */ public function log_execution( $action_id ) { /** @var \wpdb $wpdb */ global $wpdb; $sql = "UPDATE {$wpdb->actionscheduler_actions} SET attempts = attempts+1, status=%s, last_attempt_gmt = %s, last_attempt_local = %s WHERE action_id = %d"; $sql = $wpdb->prepare( $sql, self::STATUS_RUNNING, current_time( 'mysql', true ), current_time( 'mysql' ), $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared } /** * Mark an action as complete. * * @param int $action_id Action ID. * * @return void * @throws \InvalidArgumentException Throw an exception if action was not updated. */ public function mark_complete( $action_id ) { /** @var \wpdb $wpdb */ global $wpdb; $updated = $wpdb->update( $wpdb->actionscheduler_actions, array( 'status' => self::STATUS_COMPLETE, 'last_attempt_gmt' => current_time( 'mysql', true ), 'last_attempt_local' => current_time( 'mysql' ), ), array( 'action_id' => $action_id ), array( '%s' ), array( '%d' ) ); if ( empty( $updated ) ) { throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment } /** * Fires after a scheduled action has been completed. * * @since 3.4.2 * * @param int $action_id Action ID. */ do_action( 'action_scheduler_completed_action', $action_id ); } /** * Get an action's status. * * @param int $action_id Action ID. * * @return string * @throws \InvalidArgumentException Throw an exception if not status was found for action_id. * @throws \RuntimeException Throw an exception if action status could not be retrieved. */ public function get_status( $action_id ) { /** @var \wpdb $wpdb */ global $wpdb; $sql = "SELECT status FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d"; $sql = $wpdb->prepare( $sql, $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $status = $wpdb->get_var( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared if ( null === $status ) { throw new \InvalidArgumentException( __( 'Invalid action ID. No status found.', 'action-scheduler' ) ); } elseif ( empty( $status ) ) { throw new \RuntimeException( __( 'Unknown status found for action.', 'action-scheduler' ) ); } else { return $status; } } }