use InvalidArgumentException;
use UnexpectedValueException;
* This task is async (runs asap).
const TYPE_ASYNC = 'async';
* This task is a recurring.
const TYPE_RECURRING = 'scheduled';
const TYPE_ONCE = 'once';
* Action that will be used as a hook.
* All the params that should be passed to the hook.
* When the first instance of the job will run.
* Used for ONCE ane RECURRING tasks.
* How long to wait between runs.
* Used for RECURRING tasks.
protected $log_title = 'Task';
* @param string $action Action of the task.
* @throws InvalidArgumentException When action is not a string.
* @throws UnexpectedValueException When action is empty.
public function __construct( $action ) {
if ( ! is_string( $action ) ) {
throw new InvalidArgumentException( 'Task action should be a string.' );
$this->action = sanitize_key( $action );
$this->meta = new Meta();
if ( empty( $this->action ) ) {
throw new UnexpectedValueException( 'Task action cannot be empty.' );
* Define the type of the task as async.
public function async() {
$this->type = self::TYPE_ASYNC;
* Define the type of the task as recurring.
* @param int $timestamp When the first instance of the job will run.
* @param int $interval How long to wait between runs.
public function recurring( $timestamp, $interval ) {
$this->type = self::TYPE_RECURRING;
$this->timestamp = (int) $timestamp;
$this->interval = (int) $interval;
* Define the type of the task as one-time.
* @param int $timestamp When the first instance of the job will run.
public function once( $timestamp ) {
$this->type = self::TYPE_ONCE;
$this->timestamp = (int) $timestamp;
* Pass any number of params that should be saved to Meta table.
public function params() {
$this->params = func_get_args();
* Should be the final call in a chain.
* @return null|string Action ID.
public function register() {
// No processing if ActionScheduler is not usable.
if ( ! wpforms()->obj( 'tasks' )->is_usable() ) {
// Save data to tasks meta table.
if ( $this->params !== null ) {
$this->meta_id = $this->meta->add(
'action' => $this->action,
if ( empty( $this->meta_id ) ) {
// Prevent 500 errors when Action Scheduler tables don't exist.
$action_id = $this->register_async();
case self::TYPE_RECURRING:
$action_id = $this->register_recurring();
$action_id = $this->register_once();
} catch ( \RuntimeException $exception ) {
* Register the async task.
* @return null|string Action ID.
* @noinspection PhpUndefinedFunctionInspection
protected function register_async() {
if ( ! function_exists( 'as_enqueue_async_action' ) ) {
return as_enqueue_async_action(
* Filter arguments passed to the async task.
* @param array $args Arguments passed to the async task.
'wpforms_tasks_task_register_async_args',
'tasks_meta_id' => $this->meta_id,
* Register the recurring task.
* @return null|string Action ID.
* @noinspection PhpUndefinedFunctionInspection
protected function register_recurring() {
if ( ! function_exists( 'as_schedule_recurring_action' ) ) {
return as_schedule_recurring_action(
[ 'tasks_meta_id' => $this->meta_id ],
* Register the one-time task.
* @return null|string Action ID.
* @noinspection PhpUndefinedFunctionInspection
protected function register_once() {
if ( ! function_exists( 'as_schedule_single_action' ) ) {
return as_schedule_single_action(
[ 'tasks_meta_id' => $this->meta_id ],
* Cancel all occurrences of this task.
* @return null|bool|string Null if no matching action found,
* false if AS library is missing,
* true if scheduled task has no params,
* string of the scheduled action ID if a scheduled action was found and unscheduled.
* @noinspection PhpUndefinedFunctionInspection
public function cancel() {
if ( ! function_exists( 'as_unschedule_all_actions' ) ) {
if ( $this->params === null ) {
as_unschedule_all_actions( $this->action );
$this->meta_id = $this->meta->get_meta_id( $this->action, $this->params );
if ( $this->meta_id === null ) {
return as_unschedule_action( $this->action, [ 'tasks_meta_id' => $this->meta_id ], Tasks::GROUP );
* Log message to WPForms logger and standard debug.log file.
* @param string $message The error message that should be logged.
protected function log( $message ) {
wpforms_log( $this->log_title, $message, [ 'type' => 'log' ] );