Commit inicial - WordPress Análisis de Precios Unitarios

- WordPress core y plugins
- Tema Twenty Twenty-Four configurado
- Plugin allow-unfiltered-html.php simplificado
- .gitignore configurado para excluir wp-config.php y uploads

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root
2025-11-03 21:04:30 -06:00
commit a22573bf0b
24068 changed files with 4993111 additions and 0 deletions

View File

@@ -0,0 +1,713 @@
<?php
if ( ! class_exists( 'BWF_AS_Action_Store' ) ) {
#[AllowDynamicProperties]
class BWF_AS_Action_Store extends ActionScheduler_Store {
public $bwf_action_data = [];
public $action_table = '';
public $claim_table = '';
public $p_key = '';
public function init() {
global $wpdb;
$this->action_table = BWF_AS_Actions_Crud::_table();
$this->claim_table = $wpdb->bwf_action_claim;
$this->p_key = BWF_AS_Actions_Crud::$primary_key;
}
public function save_action( ActionScheduler_Action $action, ?DateTime $date = null ) {
/** Not scheduling any new action while processing our requests */
}
public function fetch_action( $action_id ) {
global $wpdb;
if ( empty( $action_id ) ) {
return $this->get_null_action();
}
$this->log( 'fetch running action id: ' . $action_id );
if ( class_exists( 'BWFAN_Merge_Tag_Loader' ) ) {
BWFAN_Merge_Tag_Loader::reset_data();
}
/**
* Below code will run between these 2 hooks action_scheduler_begin_execute and action_scheduler_after_execute
*/
if ( true === BWF_AS::is_execution_started() ) {
/** Changing status to running i.e. 1 on action */
$wpdb->update( $this->action_table, [ 'status' => 1 ], [ $this->p_key => $action_id ], [ '%s' ], [ '%d' ] ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
}
$data = $this->get_action_data( $action_id );
if ( empty( $data ) || ! ( $data instanceof StdClass ) ) {
return $this->get_null_action();
}
if ( true === BWF_AS::is_execution_started() ) {
/** Scheduling recurring action if possible */
$this->schedule_recurring_action( $action_id );
}
/** Fetching action data again as status may be altered */
$data = $this->get_action_data( $action_id );
/** If hook not present, return null action */
if ( empty( $data->hook ) || ! ( $data instanceof StdClass ) ) {
return $this->get_null_action();
}
return $this->make_action_from_db_record( $data );
}
protected function get_null_action() {
return new ActionScheduler_NullAction();
}
public function log( $msg ) {
BWF_Logger::get_instance()->log( WooFunnels_AS_DS::$unique . ' - ' . $msg, 'woofunnel-as' );
}
protected function get_action_data( $action_id ) {
$cache_key = 'bwf_fetch_action_' . $action_id;
if ( isset( $this->bwf_action_data[ $action_id ] ) ) {
return $this->bwf_action_data[ $action_id ];
}
$data = wp_cache_get( $cache_key, __CLASS__ );
if ( false === $data ) {
$data = BWF_AS_Actions_Crud::get_single_action( $action_id );
/** Saving data to local scope and cache */
if ( is_object( $data ) ) {
$this->bwf_action_data[ $action_id ] = $data;
wp_cache_set( $cache_key, $data, __CLASS__, ( 60 ) );
}
}
return $data;
}
/**
* Helper method to schedule recurring action before execution itself.
* This make sure recurring action should be scheduled.
*
* @param $action_id
*/
protected function schedule_recurring_action( $action_id ) {
global $wpdb;
$data = $this->get_action_data( $action_id );
/** Checking if recurring action */
if ( ! ( $data instanceof StdClass ) || false === $this->action_is_recurring( $data ) ) {
return;
}
$args = ( is_array( $data->args ) && count( $data->args ) > 0 ) ? $data->args : array();
$group = ( ! empty( $data->group_slug ) ) ? $data->group_slug : '';
/** Checking if already running then change the status to failed and schedule new action */
$count = bwf_scheduled_action_count( $data->hook, $args, $group, '1', 'recurring' );
if ( false === $count || 1 < $count ) {
$this->log( __FUNCTION__ . ' id ' . $action_id . ', recurring action already running count: ' . $count );
/** Changing status to failed i.e. 2 on action */
$wpdb->update( $this->action_table, [ 'status' => 2 ], [ $this->p_key => $action_id ], [ '%s' ], [ '%d' ] ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
/** Modify action object cache data status */
if ( isset( $this->bwf_action_data[ $action_id ] ) ) {
$this->bwf_action_data[ $action_id ]->status = '2';
}
}
/** Validate non-running actions */
$count = bwf_scheduled_action_count( $data->hook, $args, $group, '0', 'recurring' );
if ( 1 === $count ) {
/** if one current and one more action non-running found then no need to schedule */
return;
}
if ( 1 < $count ) {
/** delete all non running actions i.e. 0 except current action */
bwf_delete_scheduled_recurring_action( $data->hook, 0, $action_id );
}
/** Scheduling new action */
$curr_time = current_time( 'mysql', 1 );
$exec_time = time() + (int) $data->recurring_interval;
$exec_time = apply_filters( 'bwf_recurring_action_' . $data->hook . '_execution_time', $exec_time, $data );
$new_data = array(
'c_date' => $curr_time,
'e_time' => $exec_time,
'hook' => $data->hook,
'recurring_interval' => (int) $data->recurring_interval,
'claim_id' => 0
);
if ( is_array( $data->args ) && count( $data->args ) > 0 ) {
$new_data['args'] = wp_json_encode( $data->args );
}
if ( ! empty( $data->group_slug ) ) {
$new_data['group_slug'] = $data->group_slug;
}
BWF_AS_Actions_Crud::insert( $new_data );
}
/**
* Helper method that checks if an action is recurring.
*
* @param $data
*
* @return bool
*/
protected function action_is_recurring( $data ) {
if ( ! is_object( $data ) ) {
return false;
}
if ( (int) $data->recurring_interval < 1 ) {
return false;
}
return true;
}
/**
* Initiate action class object with needful data
*
* @param $data
*
* @return ActionScheduler_Action|ActionScheduler_FinishedAction
*/
protected function make_action_from_db_record( $data ) {
$hook = $data->hook;
$args = ( is_array( $data->args ) && count( $data->args ) > 0 ) ? $data->args : [];
/** creating fresh schedule */
$schedule = new ActionScheduler_NullSchedule();
$group = ( ! empty( $data->group_slug ) ) ? $data->group_slug : '';
if ( $this->verify_status( $data->status ) ) {
$action = new ActionScheduler_Action( $hook, $args, $schedule, $group );
} else {
/** status not 0 - finishing AS action (status won't occur as we are fetching 0 status actions only) */
$action = new ActionScheduler_FinishedAction( $hook, $args, $schedule, $group );
}
return $action;
}
/**
* Helper method: If pending action then bool true otherwise false
*
* @param $status
*
* @return bool
*/
protected function verify_status( $status ) {
return ( 0 == $status || 1 == $status ) ? true : false;
}
/**
* @param string $hook
* @param array $params
*
* @return string
*/
public function find_action( $hook, $params = [] ) {
/** This is invoked during unscheduled or next schedule, we are not doing anything, so blank */
return '';
}
/**
* @param array $query
* @param string $query_type
*
* @return array|string ids array or count
*/
public function query_actions( $query = [], $query_type = 'select' ) {
global $wpdb;
/** cleanup call handling */
if ( ! isset( $query['status'] ) || in_array( $query['status'], array( 'complete', 'canceled', 'failed' ), true ) || is_array( $query['status'] ) ) {
return array();
}
if ( 'pending' === $query['status'] ) {
$query['status'] = '0';
} elseif ( 'in-progress' === $query['status'] ) {
$query['status'] = '1';
}
/** Code will through in case of pending status i.e. 0 */
$sql = $this->get_query_actions_sql( $query, $query_type );
$value = ( 'count' === $query_type ) ? $wpdb->get_var( $sql ) : $wpdb->get_col( $sql ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL
if ( empty( $value ) ) {
return array();
}
$this->log( __FUNCTION__ . ': status ' . $query['status'] . ' - (' . $this->get_as_defined_status_val( $query['status'] ) . ')' . ' query result: ' . implode( ',', $value ) );
return $value;
}
/**
* Returns the SQL statement to query (or count) actions.
*
* @param array $query Filtering options
* @param string $select_or_count Whether the SQL should select and return the IDs or just the row count
*
* @return string SQL statement. The returned SQL is already properly escaped.
* 'status' => ActionScheduler_Store::STATUS_PENDING,
* 'modified' => $cutoff,
* 'modified_compare' => '<=',
* 'claimed' => true,
* 'per_page' => $this->get_batch_size(),
*/
protected function get_query_actions_sql( array $query, $select_or_count = 'select' ) {
if ( ! in_array( $select_or_count, array( 'select', 'count' ), true ) ) {
throw new InvalidArgumentException( esc_html__( 'Invalid value for select or count parameter. Cannot query actions.', 'action-scheduler' ) ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
}
$query = wp_parse_args( $query, [
'hook' => '',
'args' => null,
'date' => null,
'date_compare' => '<=',
'modified' => null,
'modified_compare' => '<=',
'group' => '',
'status' => '0',
'claimed' => null,
'per_page' => 5,
'offset' => 0,
'orderby' => 'date',
'order' => 'ASC',
] );
global $wpdb;
$sql = 'SELECT ';
$sql .= ( 'count' === $select_or_count ) ? "count({$this->p_key})" : "{$this->p_key} ";
$sql .= "FROM {$this->action_table}";
$sql_params = [];
$sql .= ' WHERE 1=1';
if ( ! empty( $query['group'] ) ) {
$sql .= ' AND group_slug=%s';
$sql_params[] = $query['group'];
}
if ( $query['hook'] ) {
$sql .= ' AND hook=%s';
$sql_params[] = $query['hook'];
}
if ( ! is_null( $query['args'] ) ) {
$sql .= ' AND args=%s';
$sql_params[] = wp_json_encode( $query['args'] );
}
/** 0 or 1 in our case */
if ( '' !== $query['status'] ) {
$sql .= ' AND status=%s';
$sql_params[] = $query['status'];
}
if ( $query['date'] instanceof DateTime ) {
$date = clone $query['date'];
$date->setTimezone( new DateTimeZone( 'UTC' ) );
$date_string = $date->format( 'Y-m-d H:i:s' );
$comparator = $this->validate_sql_comparator( $query['date_compare'] );
$sql .= " AND e_time $comparator %s";
$sql_params[] = $date_string;
}
if ( $query['claimed'] === true ) {
$sql .= ' AND claim_id != 0';
} elseif ( $query['claimed'] === false ) {
$sql .= ' AND claim_id = 0';
} elseif ( ! is_null( $query['claimed'] ) ) {
$sql .= ' AND claim_id = %d';
$sql_params[] = $query['claimed'];
}
if ( $query['modified'] instanceof DateTime ) {
$modified = clone $query['modified'];
$modified->setTimezone( new DateTimeZone( 'UTC' ) );
$date_string = $modified->getTimestamp();
$comparator = $this->validate_sql_comparator( $query['modified_compare'] );
$sql .= " AND e_time $comparator %s";
$sql_params[] = $date_string;
}
if ( 'select' === $select_or_count ) {
switch ( $query['orderby'] ) {
case 'date':
default:
$orderby = 'e_time';
break;
}
$order = ( strtoupper( $query['order'] ) === 'ASC' ) ? 'ASC' : 'DESC';
$sql .= " ORDER BY $orderby $order";
if ( $query['per_page'] > 0 ) {
$sql .= ' LIMIT %d, %d';
$sql_params[] = $query['offset'];
$sql_params[] = $query['per_page'];
}
}
if ( ! empty( $sql_params ) ) {
$sql = $wpdb->prepare( $sql, $sql_params ); //phpcs:ignore WordPress.DB.PreparedSQL
}
return $sql;
}
protected function get_as_defined_status_val( $status ) {
switch ( $status ) {
case '0':
return 'pending';
case '1':
return 'in-progress';
case '2':
return 'canceled';
}
return $status;
}
/**
* Get a count of all actions in the store, grouped by status; used in native actions listing. Not used in our scope.
*/
public function action_counts() {
return [];
}
/**
* @param string $action_id
*
* @return void
* @throws InvalidArgumentException
*/
public function cancel_action( $action_id ) {
$this->log( __FUNCTION__ . ' id ' . $action_id );
return;
}
/**
* @param string $action_id
*/
public function delete_action( $action_id ) {
$this->log( __FUNCTION__ . ' id ' . $action_id );
return;
}
/**
* don't know where using
*
* @param string $action_id
*
* @return DateTime The local date the action is scheduled to run, or the date that it ran.
* @throws InvalidArgumentException
*/
public function get_date( $action_id ) {
$date = $this->get_date_gmt( $action_id );
ActionScheduler_TimezoneHelper::set_local_timezone( $date );
return $date;
}
/**
* @param string $action_id
*
* @return DateTime The GMT date the action is scheduled to run, or the date that it ran.
* @throws InvalidArgumentException
*/
protected function get_date_gmt( $action_id ) {
$record = BWF_AS_Actions_Crud::get_single_action( $action_id );
if ( empty( $record ) ) {
throw new InvalidArgumentException( esc_html( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ) ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch, WordPress.WP.I18n.MissingTranslatorsComment
}
if ( $this->verify_status( $record->status ) ) {
return as_get_datetime_object( $record->e_time );
}
}
/**
* @param int $max_actions
* @param DateTime $before_date Jobs must be schedule before this date. Defaults to now.
*
* @return ActionScheduler_ActionClaim
*/
public function stake_claim( $max_actions = 10, ?DateTime $before_date = null, $hooks = array(), $group = '' ) {
$claim_id = $this->generate_claim_id();
$this->log( __FUNCTION__ . ' claim id: ' . $claim_id );
$this->claim_actions( $claim_id, $max_actions, $before_date, $hooks, $group );
$action_ids = $this->find_actions_by_claim_id( $claim_id );
return new ActionScheduler_ActionClaim( $claim_id, $action_ids );
}
/**
* Generate claim id of current date time
*
* @return int
*/
protected function generate_claim_id() {
global $wpdb;
$now = as_get_datetime_object();
//phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
$wpdb->insert( $this->claim_table, [
'date' => $now->format( 'Y-m-d H:i:s' ),
] );
return $wpdb->insert_id;
}
/**
* Claim actions which are executable based on given inputs
*
* @param string $claim_id
* @param int $limit
* @param DateTime $before_date Should use UTC timezone.
*
* @return int The number of actions that were claimed
* @throws RuntimeException
*
*/
protected function claim_actions( $claim_id, $limit, ?DateTime $before_date = null, $hooks = array(), $group = '' ) {
global $wpdb;
/** can't use $wpdb->update() because of the <= condition */
$update = "SELECT {$this->p_key} FROM {$this->action_table}";
$params = [];
$where = 'WHERE `claim_id` = 0 AND `e_time` <= %s AND `status` = 0';
$params[] = time();
if ( ! empty( $group ) ) {
$where .= ' AND `group` = %s';
$params[] = $group;
}
$order = 'ORDER BY `e_time` ASC LIMIT %d';
$params[] = $limit;
$sql = $wpdb->prepare( "{$update} {$where} {$order}", $params ); //phpcs:ignore WordPress.DB.PreparedSQL
$action_ids = $wpdb->get_results( $sql, ARRAY_A ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL
if ( ! is_array( $action_ids ) || count( $action_ids ) == 0 ) {
return 0;
}
$action_ids = array_column( $action_ids, $this->p_key );
/** Update call */
$type = array_fill( 0, count( $action_ids ), '%d' );
$format = implode( ', ', $type );
$query = "UPDATE {$this->action_table} SET `claim_id` = %d WHERE {$this->p_key} IN ({$format})";
$params = array( $claim_id );
$params = array_merge( $params, $action_ids );
$sql = $wpdb->prepare( $query, $params ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL
$rows_affected = $wpdb->query( $sql ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL
if ( $rows_affected === false ) {
throw new RuntimeException( esc_html__( 'Unable to claim actions. Database error.', 'action-scheduler' ) ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
}
return (int) $rows_affected;
}
/**
* Get Actions against a claim_id
*
* @param string $claim_id
*
* @return $array
*/
public function find_actions_by_claim_id( $claim_id ) {
global $wpdb;
$cache_key = 'bwf_action_ids_for_claim_id_' . $claim_id;
$cache_available = wp_cache_get( $cache_key, __CLASS__ );
if ( false !== $cache_available ) {
return $cache_available;
}
$sql = "SELECT `{$this->p_key}` FROM {$this->action_table} WHERE claim_id=%d ORDER BY e_time ASC";
$sql = $wpdb->prepare( $sql, $claim_id ); //phpcs:ignore WordPress.DB.PreparedSQL
$action_ids = $wpdb->get_col( $sql ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL
$return = array_map( 'intval', $action_ids );
wp_cache_set( $cache_key, $return, __CLASS__, ( HOUR_IN_SECONDS / 4 ) );
$this->log( 'Found ids: ' . implode( ', ', $return ) );
return $return;
}
/**
* Return unique claim id counts
*
* @return int
*/
public function get_claim_count() {
global $wpdb;
/** status 0 have actions which are executable */
$sql = "SELECT COUNT(DISTINCT claim_id) FROM {$this->action_table} WHERE claim_id != 0 AND status = 0";
return (int) $wpdb->get_var( $sql ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL
}
/**
* Return an action's claim ID, as stored in the claim_id column
*
* @param string $action_id
*
* @return mixed
*/
public function get_claim_id( $action_id ) {
$this->log( __FUNCTION__ . ' ' . $action_id );
$claim_id = BWF_AS_Actions_Crud::get_single_action( $action_id, 'claim_id' );
return (int) $claim_id;
}
/**
* Releasing the claim
*
* @param ActionScheduler_ActionClaim $claim
*/
public function release_claim( ActionScheduler_ActionClaim $claim ) {
$this->log( __FUNCTION__ . ' id ' . $claim->get_id() );
global $wpdb;
$wpdb->update( $this->action_table, [ 'claim_id' => 0 ], [ 'claim_id' => $claim->get_id() ], [ '%d' ], [ '%d' ] ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
$wpdb->delete( $this->claim_table, [ 'id' => $claim->get_id() ], [ '%d' ] ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
}
/**
* Unclaim pending actions that have not been run within a given time limit.
* Default 300
* Called inside reset_timeouts method
*
* @param string $action_id
*
* @return void
*/
public function unclaim_action( $action_id ) {
$this->log( __FUNCTION__ . ' id ' . $action_id );
global $wpdb;
$wpdb->update( $this->action_table, [ 'claim_id' => 0 ], [ $this->p_key => $action_id ], [ '%s' ], [ '%d' ] ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
}
/**
* @param string $action_id
* @param null $e
*/
public function mark_failure( $action_id, $e = null ) {
$this->log( __FUNCTION__ . ' for action id ' . $action_id );
/** Log failure data */
$this->log_failure_data( $action_id );
/** Deleting existing action */
BWF_AS_Actions_Crud::delete( $action_id );
}
/**
* Helper method
* Log failure action data in bwf logs
*
* @param $action_id
*/
protected function log_failure_data( $action_id ) {
$data = $this->get_action_data( $action_id );
if ( $data instanceof StdClass ) {
$log_arr = array(
'action_id' => $action_id,
'creation_date' => $data->c_date,
'execution_time' => $data->e_time,
'hook' => $data->hook,
'arguments' => $data->args,
'group' => $data->group_slug,
'recurring' => $data->recurring_interval,
'error' => error_get_last(),
);
/** updating logs force */
add_filter( 'bwf_logs_allowed', array( $this, 'overriding_bwf_logging' ), 99999, 2 );
BWF_Logger::get_instance()->log( print_r( $log_arr, true ), 'woofunnel-failed-actions' );
remove_filter( 'bwf_logs_allowed', array( $this, 'overriding_bwf_logging' ), 99999, 2 );
}
}
/**
* @param string $action_id
*
* @return void
*/
public function log_execution( $action_id ) {
/** no need to log as we are managing logs differently, even attempts */
}
/**
* @param string $action_id
*/
public function mark_complete( $action_id ) {
$this->log( __FUNCTION__ . ' for action id ' . $action_id );
/** Deleting existing action */
BWF_AS_Actions_Crud::delete( $action_id );
}
public function get_status( $action_id ) {
$this->log( __FUNCTION__ . ' of action id ' . $action_id );
$status = BWF_AS_Actions_Crud::get_action_status( $action_id );
if ( null === $status ) {
throw new InvalidArgumentException( esc_html__( 'Invalid action ID. No status found.', 'action-scheduler' ) ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
} else {
return $this->get_as_defined_status_val( $status );
}
}
public function overriding_bwf_logging( $value, $filename ) {
return true;
}
/**
* Cancel pending actions by hook.
*
* @param string $hook
*
* @since 3.0.0 Action Scheduler and 1.9.15 Core
*/
public function cancel_actions_by_hook( $hook ) {
return;
}
/**
* Cancel pending actions by group.
*
* @param string $group
*
* @since 3.0.0 Action Scheduler and 1.9.15 Core
*/
public function cancel_actions_by_group( $group ) {
return;
}
}
}

View File

@@ -0,0 +1,107 @@
<?php
use WP_CLI\ExitException;
use function WP_CLI\Utils\get_flag_value;
if ( ! class_exists( 'BWF_AS_CLI' ) ) {
/**
* Commands for the Custom Action Scheduler
*/
#[AllowDynamicProperties]
class BWF_AS_CLI extends WP_CLI_Command {
/**
* Run the Autonami tasks
*
* ## OPTIONS
*
* [--size=<size>]
* : The maximum number of tasks to run. Defaults to 50.
*
* @param array $args Positional arguments.
* @param array $assoc_args Keyed arguments.
*
* @throws ExitException When an error occurs.
*/
public function run( $args, $assoc_args ) {
// Handle passed arguments.
$size = absint( get_flag_value( $assoc_args, 'size', 50 ) );
$tasks_completed = 0;
try {
if ( ! class_exists( 'ActionScheduler_QueueRunner' ) ) {
$this->print_custom_error( '1' );
}
$global_settings = BWFAN_Common::get_global_settings();
if ( 1 == $global_settings['bwfan_sandbox_mode'] || ( defined( 'BWFAN_SANDBOX_MODE' ) && true === BWFAN_SANDBOX_MODE ) ) {
$this->print_custom_error( '2' );
}
/** Custom queue cleaner instance */
$cleaner = new ActionScheduler_QueueCleaner( null, $size );
/** Queue runner instance */
$runner = new ActionScheduler_WPCLI_QueueRunner( null, null, $cleaner );
/** Run Action Scheduler worker */
// Determine how many tasks will be run in the first batch.
$total = $runner->setup( $size );
WP_CLI::log( "Current batch size is: " . $size );
$this->print_total_tasks( $total );
$tasks_completed = $runner->run();
} catch ( Exception $e ) {
$this->print_error( $e );
}
$this->print_success( $tasks_completed );
}
protected function print_custom_error( $type ) {
switch ( $type ) {
case '1':
$msg = 'ActionScheduler_QueueRunner class not found.';
break;
case '2':
$msg = 'FunnelKit Automations Sandbox mode is ON.';
break;
default:
$msg = 'Some error occurred';
}
WP_CLI::error( sprintf( /* translators: %s refers to the exception error message. */ $msg ) );
}
/**
* Print WP CLI message about how many tasks are about to be processed.
*
* @param int $total
*/
protected function print_total_tasks( $total ) {
WP_CLI::log( sprintf( /* translators: %d refers to how many scheduled tasks were found to run */ _n( 'Found %d scheduled task', 'Found %d scheduled tasks', $total, 'action-scheduler' ), number_format_i18n( $total ) ) ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch, WordPress.WP.I18n.MissingTranslatorsComment
}
/**
* Convert an exception into a WP CLI error.
*
* @param Exception $e The error object.
*
* @throws ExitException
*/
protected function print_error( Exception $e ) {
WP_CLI::error( sprintf( /* translators: %s refers to the exception error message. */ __( 'There was an error running the action scheduler: %s', 'action-scheduler' ), $e->getMessage() ) ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch, WordPress.WP.I18n.MissingTranslatorsComment
}
/**
* Print a success message with the number of completed tasks.
*
* @param int $tasks_completed
*/
protected function print_success( $tasks_completed ) {
WP_CLI::success( sprintf( /* translators: %d refers to the total number of tasks completed */ _n( '%d scheduled task completed.', '%d scheduled tasks completed.', $tasks_completed, 'action-scheduler' ), number_format_i18n( $tasks_completed ) ) ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch, WordPress.WP.I18n.MissingTranslatorsComment
}
}
}

View File

@@ -0,0 +1,30 @@
<?php
if ( ! class_exists( 'BWF_AS_Log_Store' ) ) {
/**
* Not saving any log as no do_action left in action data store
*
* Class BWFAN_AS_CT_Log_Store
*/
#[AllowDynamicProperties]
class BWF_AS_Log_Store extends ActionScheduler_Logger {
public function log( $action_id, $message, ?DateTime $date = null ) {
return;
}
public function get_entry( $entry_id ) {
return new ActionScheduler_NullLogEntry();
}
public function get_logs( $action_id ) {
return array();
}
public function init() {
}
public function clear_deleted_action_logs( $action_id ) {
}
}
}

View File

@@ -0,0 +1,192 @@
<?php
if ( ! class_exists( 'BWF_AS' ) ) {
#[AllowDynamicProperties]
class BWF_AS {
private static $instance;
protected $start_time = 0;
public static $execution_started = 0;
public function __construct() {
global $wpdb;
$wpdb->bwf_actions = $wpdb->prefix . 'bwf_actions';
$wpdb->bwf_action_claim = $wpdb->prefix . 'bwf_action_claim';
$this->start_time = time();
}
public static function instance() {
if ( ! isset( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Change the data store
*/
public function change_data_store() {
/** Hook late so that functionalities can be hooked in */
add_action( 'plugins_loaded', [ $this, 'bwf_data_store_set' ], 1000 );
/** Removing all action data store change filter and then assign ours */
remove_all_filters( 'action_scheduler_store_class' );
add_filter( 'action_scheduler_store_class', [ $this, 'set_store_class' ], 1000000, 1 );
/** Removing all log data store change filter and then assign ours */
remove_all_filters( 'action_scheduler_logger_class' );
add_filter( 'action_scheduler_logger_class', [ $this, 'set_logger_class' ], 1000000, 1 );
/** Removing all AS memory exceeds filter */
remove_all_filters( 'action_scheduler_memory_exceeded' );
add_filter( 'action_scheduler_memory_exceeded', [ $this, 'check_memory_exceeded' ], 1000000, 1 );
add_action( 'action_scheduler_begin_execute', [ $this, 'attach_flag' ] );
add_action( 'action_scheduler_after_execute', [ $this, 'detach_flag' ] );
add_action( 'action_scheduler_failed_execution', [ $this, 'detach_flag' ] );
add_action( 'action_scheduler_failed_validation', [ $this, 'detach_flag' ] );
}
public function bwf_data_store_set() {
do_action( 'bwf_as_data_store_set' );
}
/**
* Override the action store with our own
*
* @param string $class
*
* @return string
*/
public function set_store_class( $class ) {
return BWF_AS_Action_Store::class;
}
/**
* Override the logger with our own
*
* @param string $class
*
* @return string
*/
public function set_logger_class( $class ) {
return BWF_AS_Log_Store::class;
}
/**
* Override memory exceeded filter value
*
* @param $memory_exceeded
*
* @return bool
*/
public function check_memory_exceeded( $memory_exceeded ) {
if ( true === $memory_exceeded ) {
return $memory_exceeded;
}
return $this->validate_time_breach();
}
/**
* Validate if call input time reached
*
* @return bool
*/
public function validate_time_breach() {
$per_call_time = apply_filters( 'bwfan_as_per_call_time', 30 );
if ( ( time() - $this->start_time ) >= $per_call_time || $this->memory_exceeded() ) {
return true;
}
return false;
}
/**
* Check server memory limit.
* Using 75% max
*
* @return bool
*/
public function memory_exceeded() {
$memory_limit = $this->get_memory_limit() * 0.9;
$current_memory = memory_get_usage( true );
return ( $current_memory >= $memory_limit );
}
/**
* Get Server memory limit value
*
* @return int|mixed
*/
public function get_memory_limit() {
if ( function_exists( 'ini_get' ) ) {
$memory_limit = ini_get( 'memory_limit' );
} else {
$memory_limit = '128M'; // Sensible default, and minimum required by WooCommerce
}
if ( ! $memory_limit || - 1 === $memory_limit || '-1' === $memory_limit ) {
// Unlimited, set to 32GB.
$memory_limit = '32G';
}
return $this->convert_hr_to_bytes( $memory_limit );
}
/**
* Convert memory to bytes
*
* @param $value
*
* @return int|mixed
*/
public function convert_hr_to_bytes( $value ) {
if ( function_exists( 'wp_convert_hr_to_bytes' ) ) {
return wp_convert_hr_to_bytes( $value );
}
$value = strtolower( trim( $value ) );
$bytes = (int) $value;
if ( false !== strpos( $value, 'g' ) ) {
$bytes *= GB_IN_BYTES;
} elseif ( false !== strpos( $value, 'm' ) ) {
$bytes *= MB_IN_BYTES;
} elseif ( false !== strpos( $value, 'k' ) ) {
$bytes *= KB_IN_BYTES;
}
// Deal with large (float) values which run into the maximum integer size.
return min( $bytes, PHP_INT_MAX );
}
/**
* Attach flag before starting execution of the action
*
* @return void
*/
public function attach_flag() {
self::$execution_started = 1;
}
/**
* Detach flag after finishing the execution of the action
*
* @return void
*/
public function detach_flag() {
self::$execution_started = 0;
}
/**
* Check if action execution started
*
* @return bool
*/
public static function is_execution_started() {
return ( self::$execution_started === 1 );
}
}
}

View File

@@ -0,0 +1,2 @@
<?php
// Silence is golden.