File "class-process.php"
Full path: /home/dora/public_html/wp-content/plugins/wp-grid-builder/includes/cron/class-process.php
File size: 9.05 KB
MIME-type: --
Charset: utf-8
<?php
/**
* Background process (Modified version)
*
* @package WP-Background-Processing
* https://github.com/A5hleyRich/wp-background-processing
*/
namespace WP_Grid_Builder\Includes\Cron;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Abstract Process
*
* @abstract WP_Grid_Builder\Includes\Cron\Process
* @since 1.0.0
*/
abstract class Process extends Async {
/**
* Action
*
* @var string
* @access protected
*/
protected $prefix = 'wpgb';
/**
* Start time of current process.
*
* @var int
* @access protected
*/
protected $start_time = 0;
/**
* Cron identifier
*
* @var mixed
* @access protected
*/
protected $cron_hook_id;
/**
* Cron interval identifier
*
* @var mixed
* @access protected
*/
protected $cron_interval_id;
/**
* Constructor
*
* @since 1.0.0
* @access public
*/
public function __construct() {
parent::__construct();
$this->queue = new Queue();
$this->cron_hook_id = $this->prefix . '_cron';
$this->cron_interval_id = $this->prefix . '_cron_interval';
if ( is_admin() ) {
add_action( $this->cron_hook_id, [ $this, 'handle_cron_healthcheck' ] );
// phpcs:ignore WordPress.WP.CronInterval.ChangeDetected
add_filter( 'cron_schedules', [ $this, 'schedule_cron_healthcheck' ] );
}
}
/**
* Dispatch
*
* @since 1.0.0
* @access public
*/
public function dispatch() {
// Schedule the cron healthcheck.
$this->schedule_event();
// Perform remote post.
parent::dispatch();
}
/**
* Push to item queue
*
* @since 1.0.0
* @access public
*
* @param string $key Item key.
* @param mixed $data Item data.
*
* @return boolean
*/
public function add_to_queue( $key, $data ) {
$cancel = $this->queue->cancel_item( $key );
$queue = $this->queue->get();
$length = count( (array) $queue );
$this->queue->add_item( $key, $data );
return $cancel || ! $length;
}
/**
* Check if we need to handle current request and start queue.
*
* @since 1.0.0
* @access public
*/
public function maybe_handle() {
// Don't lock up other requests while processing.
session_write_close();
if ( $this->is_processing() ) {
wp_die();
}
if ( $this->queue->is_empty() ) {
wp_die();
}
check_ajax_referer( $this->action, 'nonce' );
$this->handle();
wp_die();
}
/**
* Process items in queue
*
* @since 1.0.0
* @access protected
*/
protected function handle() {
$this->run_process();
// Because the queue can change when processing.
do {
$queue = $this->queue->get();
foreach ( $queue as $key => $item ) {
$success = true;
if ( ! $this->queue->is_canceled( $key ) ) {
$success = $this->task( $item['data'], $key );
}
if ( ! $success ) {
break;
}
if ( $this->time_exceeded() || $this->memory_exceeded() ) {
break;
}
$this->queue->delete_item( $key );
}
} while (
! $this->time_exceeded() &&
! $this->memory_exceeded() &&
! $this->queue->is_empty()
);
$this->stop_process();
// Start again or complete process.
if ( ! $this->queue->is_empty() ) {
$this->dispatch();
} else {
$this->complete();
}
wp_die();
}
/**
* Run process before to process queue
* Define start_time
*
* @since 1.0.0
* @access protected
*/
protected function run_process() {
// Set start time of current process.
$this->start_time = time();
$lock_duration = $this->get_max_execution_time();
wp_using_ext_object_cache( false );
set_site_transient( $this->prefix . '_process_lock', microtime(), $lock_duration );
}
/**
* Stop process by dleeting transient process
*
* @since 1.0.0
* @access protected
*/
protected function stop_process() {
wp_using_ext_object_cache( false );
delete_site_transient( $this->prefix . '_process_lock' );
}
/**
* Check if we are currently processing the queue
*
* @since 1.0.0
* @access protected
*
* @return boolean
*/
protected function is_processing() {
// Delete transient option cache before to get.
// Prevent issue with multiple instances.
wp_using_ext_object_cache( false );
if ( get_site_transient( $this->prefix . '_process_lock' ) ) {
return true;
}
return false;
}
/**
* Memory exceeded
*
* Ensures the batch process never exceeds 90%
* of the maximum WordPress memory.
*
* @since 1.0.0
* @access protected
*
* @return boolean
*/
protected function memory_exceeded() {
// Set 80% of memory limit.
$limit = $this->get_memory_limit() * 0.8;
$memory = (int) memory_get_usage( true );
return $memory >= $limit;
}
/**
* Get memory limit
*
* @since 1.0.0
* @access protected
*
* @return integer
*/
protected function get_memory_limit() {
// Set a default limit.
$memory_limit = '128M';
if ( function_exists( 'ini_get' ) ) {
$memory_limit = ini_get( 'memory_limit' );
}
// If unlimited memory.
if ( ! $memory_limit || -1 === (int) $memory_limit ) {
$memory_limit = '32G';
}
$memory_limit = $this->let_to_num( $memory_limit );
return $memory_limit;
}
/**
* Convert number notation (e.g.: '2M') to an integer
*
* @since 1.0.0
* @access protected
*
* @param string $size Size value.
* @return integer
*/
protected function let_to_num( $size ) {
$let = substr( $size, -1 );
$ret = substr( $size, 0, -1 );
switch ( strtoupper( $let ) ) {
case 'P':
$ret *= 1024;
// no break.
case 'T':
$ret *= 1024;
// no break.
case 'G':
$ret *= 1024;
// no break.
case 'M':
$ret *= 1024;
// no break.
case 'K':
$ret *= 1024;
}
return $ret;
}
/**
* Time exceeded.
*
* Ensures the batch never exceeds a sensible time limit.
* A timeout limit of 30s is common on shared hosting.
*
* @since 1.0.0
* @access protected
*
* @return boolean
*/
protected function time_exceeded() {
// Set 80% of max execution limit.
$limit = $this->get_max_execution_time() * 0.8;
$finish = $this->start_time + $limit;
return time() >= $finish;
}
/**
* Get PHP max execution time
*
* @since 1.0.0
* @access protected
*
* @return integer
*/
protected function get_max_execution_time() {
$max_execution_time = 0;
if ( function_exists( 'ini_get' ) ) {
$max_execution_time = (int) ini_get( 'max_execution_time' );
}
if ( $max_execution_time <= 0 ) {
$max_execution_time = 30;
}
// A maximum of 60s to prevent to be stalled a long time.
$max_execution_time = min( 60, $max_execution_time );
$max_execution_time = apply_filters( 'wp_grid_builder/cron/max_execution_time', $max_execution_time );
return $max_execution_time;
}
/**
* Schedule cron healthcheck
*
* @since 1.0.0
* @access public
*
* @param mixed $schedules Schedules.
* @return mixed
*/
public function schedule_cron_healthcheck( $schedules ) {
$interval = apply_filters( 'wp_grid_builder/cron/interval', 60 );
// Adds every 30 seconds to the existing schedules.
$schedules[ $this->prefix . '_cron_interval' ] = [
'interval' => $interval,
/* translators: %d: time in minutes */
'display' => __( 'Every %d minutes', 'wp-grid-builder' ),
];
return $schedules;
}
/**
* Handle cron healthcheck
*
* Restart the background process if not already running
* and data exists in the queue.
*
* @since 1.0.0
* @access public
*/
public function handle_cron_healthcheck() {
// Process already running.
if ( $this->is_processing() ) {
exit;
}
// No data to process.
if ( $this->queue->is_empty() ) {
$this->clear_scheduled_event();
exit;
}
$this->handle();
exit;
}
/**
* Schedule event
*
* @since 1.0.0
* @access protected
*/
protected function schedule_event() {
if ( ! wp_next_scheduled( $this->cron_hook_id ) ) {
wp_schedule_event( time(), $this->cron_interval_id, $this->cron_hook_id );
}
}
/**
* Clear scheduled event
*
* @since 1.0.0
* @access protected
*/
protected function clear_scheduled_event() {
$timestamp = wp_next_scheduled( $this->cron_hook_id );
if ( $timestamp ) {
wp_unschedule_event( $timestamp, $this->cron_hook_id );
}
}
/**
* Cancel Process (Clear all items in queue)
*
* Stop processing queue items, clear cronjob and delete batch.
*
* @since 1.0.0
* @access public
*/
public function cancel() {
if ( $this->queue->is_empty() ) {
return;
}
$this->queue->delete();
$this->stop_process();
wp_clear_scheduled_hook( $this->cron_hook_id );
}
/**
* Complete.
*
* Override if applicable, but ensure that the below actions are
* performed, or, call parent::complete().
*
* @since 1.0.0
* @access protected
*/
protected function complete() {
$this->queue->delete();
$this->stop_process();
// Unschedule the cron healthcheck.
$this->clear_scheduled_event();
}
/**
* Task
*
* Override this method to perform any actions on each queued item.
*
* @since 1.0.0
* @access protected
*
* @param mixed $item Queue item to iterate over.
* @param mixed $key Item key in queue.
* @return mixed
*/
abstract protected function task( $item, $key );
}