name = $name;
}
self::$lastUse = $name;
return self::$instances[$name];
}
/**
* Joomunited Queue constructor
*
* @return void
*/
public function init($args = array())
{
if (isset($args['use_queue'])) {
self::setOption('use_queue', $args['use_queue'] ? true : false);
}
if (isset($args['plugin_prefix']) && $args['plugin_prefix'] !== '') {
self::setOption('plugin_prefix', $args['plugin_prefix']);
}
if ((isset($args['assets_url']) && $args['assets_url'] !== '')) {
self::setOption('assets_url', $args['assets_url']);
} else {
self::setOption('assets_url', $this->getAssetBaseUrl() . '/queue.js');
}
if (isset($args['plugin_domain']) && $args['plugin_domain'] !== '') {
self::setOption('plugin_domain', $args['plugin_domain']);
}
$default_options = isset($args['queue_options']) && is_array($args['queue_options']) ? $args['queue_options'] : array();
// Enable logging if needed
if (isset($default_options['mode_debug']) && !empty($default_options['mode_debug'])) {
self::setOption('debug_enabled', true);
}
self::setOption('default_options', $default_options);
$status_templates = isset($args['status_templates']) && is_array($args['status_templates']) ? $args['status_templates'] : array();
$exists_status_templates = self::$status_templates;
if (is_array($status_templates) && count($status_templates)) {
foreach ($status_templates as $key => $status) {
if (!key_exists($key, $exists_status_templates)) {
$exists_status_templates[$key] = $status;
}
}
}
self::$status_templates = $exists_status_templates;
self::runUpgrades();
if (self::getOption('plugin_prefix') === 'ju' && !has_action('admin_init', array(__CLASS__, 'addQueueSettings'))) {
add_action('admin_init', array($this, 'addQueueSettings'));
}
if (self::getOption('plugin_prefix') === 'ju' && has_action('admin_init', array($this, 'initQueueAdmin'))) {
return false;
}
add_action('admin_init', array($this, 'initQueueAdmin'));
$this->initAjax();
return true;
}
/**
* UI: Add queue setting to Settings > General
*
* @return void
*/
public function addQueueSettings()
{
// Avoid executing this function within an admin_ajax request as it can negatively impact the performance by causing a slowdown.
if (wp_doing_ajax() ) {
return;
}
register_setting('general', 'joomunited_show_queue_adminbar');
register_setting('general', 'joomunited_queue_speed');
register_setting('general', 'joomunited_queue_trigger');
register_setting('general', 'joomunited_queue_refreshment_interval');
add_settings_section('juqueue-settings', 'Joomunited Queue Settings', array($this, 'queueSettingsSection'), 'general');
add_settings_field(
'joomunited_show_queue_adminbar',
'Show queue in admin bar',
array($this, 'showQueueCheckbox'),
'general',
'juqueue-settings'
);
add_settings_field(
'joomunited_queue_speed',
'Task running speed',
array($this, 'showQueueTaskSelect'),
'general',
'juqueue-settings'
);
add_settings_field(
'joomunited_queue_trigger',
'Queue trigger method',
array($this, 'showQueueTaskTrigger'),
'general',
'juqueue-settings'
);
add_settings_field(
'joomunited_queue_refreshment_interval',
'AJAX refreshment interval',
array($this, 'showQueueTaskRefreshmentSelect'),
'general',
'juqueue-settings'
);
global $pagenow;
if ($pagenow === 'options-general.php') {
add_thickbox();
}
}
/**
* UI: Queue Settions section title
*
* @return void
*/
public function queueSettingsSection()
{
?>
hasProperty($key)) {
return $class->getStaticPropertyValue($key);
}
} catch (\ReflectionException $e) {
self::$lastError[] = $e->getMessage();
return null;
}
return false;
}
/**
* Set queue option
*
* @param string $key Option key
* @param mixed $value Option value
*
* @return void
*/
public static function setOption($key, $value)
{
if (!empty(self::$lastUse)) {
// Set options for instance
$options = self::$options;
$options[self::$lastUse][$key] = $value;
self::$options = $options;
} else {
try {
$class = new \ReflectionClass(__CLASS__);
if ($class->hasProperty($key)) {
$class->setStaticPropertyValue($key, $value);
}
} catch (\ReflectionException $e) {
self::$lastError[] = $e->getMessage();
}
}
}
/**
* Init queue for admin bar
*
* @return void
*/
public function initQueueAdmin() {
add_filter('heartbeat_received', array($this, 'heartbeat_received'), 10, 2);
// Avoid executing this function within an admin_ajax request as it can negatively impact the performance by causing a slowdown.
if (wp_doing_ajax() ){
return;
}
add_action('admin_footer', array($this, 'enqueueScript'), 10);
// Add menu bar
$show_in_adminbar = get_option('joomunited_show_queue_adminbar', 0);
if ($show_in_adminbar) {
add_action('admin_bar_menu', array($this, 'queueAdminBar'), 999);
wp_register_style(self::getOption('plugin_prefix') . '-dummy-handle', false);
wp_enqueue_style(self::getOption('plugin_prefix') . '-dummy-handle');
wp_add_inline_style(
self::getOption('plugin_prefix') . '-dummy-handle',
'#wp-admin-bar-'. self::getOption('plugin_prefix') .'-topbar a {
color: #FFF !important;
}
#wp-admin-bar-'. self::getOption('plugin_prefix') .'-topbar span.'. self::getOption('plugin_prefix') .' {
width: 10px;
height: 10px;
border-radius: 5px;
background-color: #969696;
display: inline-block;
vertical-align: baseline;
margin-right: 6px;
}
#wp-admin-bar-'. self::getOption('plugin_prefix') .'-topbar span.'. self::getOption('plugin_prefix') .'-querying {
opacity: 0.6;
}
#wp-admin-bar-'. self::getOption('plugin_prefix') .'-topbar span.'. self::getOption('plugin_prefix') .'-green {
background-color: #4caf50;
}
#wp-admin-bar-'. self::getOption('plugin_prefix') .'-topbar span.'. self::getOption('plugin_prefix') .'-orange {
background-color: #ff9800;
}
#wp-admin-bar-'. self::getOption('plugin_prefix') .'-topbar span.'. self::getOption('plugin_prefix') .'-gray {
background-color: #969696 !important;
}
.ju-status-wrap {
position: relative;
}
.ju_queue_status {
position: absolute !important;
top: 100%;
left: -10px;
background: #32373c !important;
display: none;
}
.ju_queue_status li {
color: color: rgba(240, 245, 250, 0.7) !important;
width: 300px !important;
text-overflow: ellipsis !important;
overflow: hidden;
display: inline-block;
padding: 2px 10px !important;
box-sizing: border-box !important;
border-bottom: #474747 1px solid;
}
.ju-status-wrap:hover > .ju_queue_status{
display: block;
}
.'. self::getOption('plugin_prefix') .'_clear_queue .dashicons, .'. self::getOption('plugin_prefix') .'_stop_queue .dashicons {
font-family: dashicons !important;
vertical-align: middle;
font-size: 16px !important;
line-height: 18px !important;
margin-right: 5px !important;
}
.'. self::getOption('plugin_prefix') .'_clear_queue *, .'. self::getOption('plugin_prefix') .'_stop_queue * {
vertical-align: middle;
display: inline-block;
}
@-webkit-keyframes rotating /* Safari and Chrome */ {
from {
-webkit-transform: rotate(0deg);
-o-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
-o-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes rotating {
from {
-ms-transform: rotate(0deg);
-moz-transform: rotate(0deg);
-webkit-transform: rotate(0deg);
-o-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-ms-transform: rotate(360deg);
-moz-transform: rotate(360deg);
-webkit-transform: rotate(360deg);
-o-transform: rotate(360deg);
transform: rotate(360deg);
}
}
.'. self::getOption('plugin_prefix') .'_clear_queue.queue_running .dashicons-remove {
-webkit-animation: rotating 0.2s linear infinite;
-moz-animation: rotating 0.2s linear infinite;
-ms-animation: rotating 0.2s linear infinite;
-o-animation: rotating 0.2s linear infinite;
animation: rotating 0.2s linear infinite;
}
'
);
}
}
/**
* Add queue status to admin bar
*
* @param WP_Admin_Bar $wp_admin_bar WP_Admin_Bar instance, passed by reference
*
* @return void
*/
public function queueAdminBar($wp_admin_bar)
{
$stop = self::getStopStatus();
// phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralDomain,WordPress.WP.I18n.NonSingularStringLiteralText
$stop_button = (!empty($stop)) ? '' : '';
$args = array(
'id' => self::getOption('plugin_prefix') . '-topbar',
'title' => '0- ' . $stop_button . '
',// phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralDomain,WordPress.WP.I18n.NonSingularStringLiteralText
'meta' => array(
'classname' => 'ju-queue',
),
);
$wp_admin_bar->add_node($args);
}
/**
* Get stop status
*
* @return integer
*/
public function getStopStatus()
{
global $wpdb;
$row = $wpdb->get_row($wpdb->prepare('SELECT option_value FROM '. $wpdb->options .' WHERE option_name = %s LIMIT 1', self::getOption('plugin_prefix') . '_stop_queue'));
if (is_object($row)) {
$stop = (int)$row->option_value;
} else {
$stop = 0;
}
return $stop;
}
/**
* Check queue exist
*
* @param string $value Value
* @param string $compare Compare
*
* @return array|object|void|null
*/
public function checkQueueExist($value = '', $compare = '=')
{
global $wpdb;
$table = $wpdb->prefix . self::getOption('plugin_prefix') . '_queue';
$data_hash = md5($value);
// phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- Params has prepared
switch ($compare) {
case 'LIKE':
$row = $wpdb->get_row($wpdb->prepare('SELECT id, status, responses FROM ' . $table . ' WHERE datas LIKE BINARY %s ORDER BY date_added DESC', array('%' . $value . '%')));
break;
default:
$row = $wpdb->get_row($wpdb->prepare('SELECT id, status, responses FROM ' . $table . ' WHERE data_hash = %s ORDER BY date_added DESC', $data_hash));
}
// phpcs:enable
return $row;
}
/**
* Add to the queue
*
* @param array $datas Datas details
* @param array $responses Responses details
*
* @return void
*/
public function addToQueue($datas = array(), $responses = array())
{
global $wpdb;
$action = $datas['action'];
$datas = json_encode($datas);
$wpdb->insert(
$wpdb->prefix . self::getOption('plugin_prefix') . '_queue',
array(
'action' => $action,
'datas' => $datas,
'data_hash' => md5($datas),
'responses' => stripslashes(json_encode($responses)),
'date_added' => round(microtime(true) * 1000),
'date_done' => null,
'status' => 0
),
array(
'%s',
'%s',
'%s',
'%d',
'%d',
'%d'
)
);
}
/**
* Proceed queue asynchronously
*
* @return void
*/
public function proceedQueueAsync()
{
global $wpdb;
$stop = $this->getStopStatus();
// run if no stop
if (empty($stop)) {
$row = $wpdb->get_row($wpdb->prepare('SELECT option_value FROM '. $wpdb->options .' WHERE option_name = %s LIMIT 1', self::getOption('plugin_prefix') . '_queue_running'));
if (is_object($row)) {
$queue_running = (int)$row->option_value;
} else {
$queue_running = 0;
}
//$queue_running = get_option(self::getOption('plugin_prefix' . '_queue_running');
$queue_length = $this->getQueueLength();
// Check if queue is currently running for less than 30 seconds
if (($queue_running + 300) < time()) {
delete_option(self::getOption('plugin_prefix') . '_queue_id_running');
}
if ($queue_length && $queue_running + 30 < time()) {
update_option(self::getOption('plugin_prefix') . '_queue_running', time());
switch ((int)self::getTasksSpeed()) {
case 75:
sleep(4);
break;
case 25:
sleep(10);
break;
}
$remoteUrl = admin_url('admin-ajax.php').'?action='. self::getOption('plugin_prefix') .'_proceed&'. self::getOption('plugin_prefix') .'_token='.get_option(self::getOption('plugin_prefix') . '_token') . '&speed=' . self::getTasksSpeed();
/**
* Filter to add Basic Authentication for queue can work on protected site.
*
* @param array
*/
$basicAuthentication = apply_filters('ju_queue_basic_authentication_info', array('username' => '', 'password' => ''));
$protocol = 'http';
if (strpos($remoteUrl, 'https') === 0) {
$protocol = 'https';
}
if ($basicAuthentication['username'] !== '' && $basicAuthentication['password'] !== '') {
$basicAuthentication['password'] = urlencode($basicAuthentication['password']);
$remoteUrl = str_replace($protocol . '://', $protocol . '://' . $basicAuthentication['username'] . ':' . $basicAuthentication['password'] . '@', $remoteUrl);
}
$result = wp_remote_head($remoteUrl, array('sslverify' => false));
self::log('Info : Proceed queue asynchronously ' . (is_wp_error($result)?$result->get_error_message():'success'));
} elseif ($queue_length) {
self::log('Info : Queue already running (queue_running: ' . $queue_running .', time: ' . time());
}
}
}
/**
* Update responses
*
* @param integer $id Item ID
* @param array $responses Responses
*
* @return void
*/
public function updateResponses($id, $responses = array())
{
global $wpdb;
$wpdb->update(
$wpdb->prefix . self::getOption('plugin_prefix') . '_queue',
array(
'responses' => json_encode($responses)
),
array('id' => $id),
array('%s'),
array('%d')
);
}
/**
* Update datas
*
* @param integer $id Item ID
* @param array $datas Datas
*
* @return void
*/
public function updateDatas($id, $datas = array())
{
global $wpdb;
$wpdb->update(
$wpdb->prefix . self::getOption('plugin_prefix') . '_queue',
array(
'datas' => json_encode($datas)
),
array('id' => $id),
array('%s'),
array('%d')
);
}
/**
* Roll back queue
*
* @param integer $id Queue ID
* @param array $datas Queue datas
*
* @return void
*/
public function rollBackQueue($id, $datas = array())
{
global $wpdb;
$wpdb->update(
$wpdb->prefix . self::getOption('plugin_prefix') . '_queue',
array(
'datas' => json_encode($datas),
'retries' => 0,
'status' => 0
),
array('id' => $id),
array('%s', '%d', '%d'),
array('%d')
);
}
/**
* Delete a queue by id
*
* @param integer $id ID of queue
*
* @return void
*/
public function deleteQueue($id)
{
global $wpdb;
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Params has prepared
$wpdb->query($wpdb->prepare('DELETE FROM ' . $wpdb->prefix . self::getOption('plugin_prefix') . '_queue WHERE id = %d', (int)$id));
}
/**
* Proceed elements in the queue
*
* @return integer
*/
private function proceedQueue()
{
self::log('Info : Proceed queue synchronously');
global $wpdb;
$done = 0;
$max_execution_time = $this->getMaximumExecutionTime();
self::log('Info : Max execution time is ' . $max_execution_time);
// Update last queue time value
update_option(self::getOption('plugin_prefix') . '_queue_running', time());
// Remove last week elements
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Params has prepared
$wpdb->query('DELETE FROM ' . $wpdb->prefix . self::getOption('plugin_prefix') . '_queue WHERE date_done < (UNIX_TIMESTAMP()*1000 - 1 * 24 * 60 * 60 * 1000)');
// Retrieve all elements in the queue
do {
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Params has prepared
$elements = $wpdb->get_results('SELECT id, datas, retries, date_added FROM ' . $wpdb->prefix . self::getOption('plugin_prefix') . '_queue WHERE status=0 ORDER BY date_added ASC LIMIT 50');
foreach ($elements as $element) {
// check if a queue is running
$row = $wpdb->get_row($wpdb->prepare('SELECT option_value FROM '. $wpdb->options .' WHERE option_name = %s LIMIT 1', self::getOption('plugin_prefix') . '_queue_id_running'));
if (is_object($row)) {
$queue_id_running = (int)$row->option_value;
} else {
$queue_id_running = 0;
}
if (!empty($queue_id_running) && (int)$queue_id_running === $element->id) {
return $done;
}
update_option(self::getOption('plugin_prefix') . '_queue_id_running', $element->id);
set_time_limit(0);
// Actually move the file
$datas = json_decode($element->datas, true);
$retries = (int) $element->retries + 1;
if ($retries > self::getOption('retries')) {
$result = true;
$wpdb->update(
$wpdb->prefix . self::getOption('plugin_prefix') . '_queue',
array(
'date_done' => round(microtime(true) * 1000),
'retries' => (int)$retries,
'status' => 2
),
array('id' => $element->id),
array('%d', '%d', '%d'),
array('%d')
);
} else {
$result = apply_filters($datas['action'], -1, $datas, $element->id);
if ($result) {
$wpdb->update(
$wpdb->prefix . self::$plugin_prefix . '_queue',
array(
'date_done' => round(microtime(true) * 1000),
'retries' => (int)$retries,
'status' => 1
),
array('id' => $element->id),
array('%d', '%d', '%d'),
array('%d')
);
} else {
$wpdb->update(
$wpdb->prefix . self::$plugin_prefix . '_queue',
array(
'retries' => (int)$retries
),
array('id' => $element->id),
array('%d'),
array('%d')
);
}
}
// Update last queue time value
update_option(self::getOption('plugin_prefix') . '_queue_running', time());
delete_option(self::getOption('plugin_prefix') . '_queue_id_running');
if ($result) {
$done++;
}
}
$current_time = microtime(true);
} while ($elements && $current_time < $max_execution_time);
self::log('Info : Synchronous queue finished');
return $done;
}
/**
* Retrieve microtime at which the script should stop
*
* @return float
*/
private function getMaximumExecutionTime()
{
$max_execution_time = (int)ini_get('max_execution_time');
if (!$max_execution_time) {
$max_execution_time = 30;
} elseif ($max_execution_time > 60) {
$max_execution_time = 60;
}
if (isset($_SERVER['REQUEST_TIME_FLOAT'])) {
$time = $_SERVER['REQUEST_TIME_FLOAT'];
} else {
// Consider script started 3 seconds ago
$time = microtime(true) - 3 * 1000 * 1000;
}
// We should stop the script 3 seconds before it reach max execution limit
return $time + $max_execution_time * 1000 * 1000 - 3 * 1000 * 1000;
}
/**
* Get number of items in the queue waiting
*
* @return integer
*/
public function getQueueLength()
{
global $wpdb;
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Params has prepared
return (int)$wpdb->get_var('SELECT COUNT(*) FROM ' . $wpdb->prefix . self::getOption('plugin_prefix') . '_queue WHERE status=0');
}
/**
* Get status list
*
* @return array|object|null
*/
public function getStatus()
{
global $wpdb;
// phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- Params has prepared
$results = $wpdb->get_results('SELECT COUNT(action) as count, action FROM ' . $wpdb->prefix . self::getOption('plugin_prefix') . '_queue WHERE status=0 GROUP BY action');
return $results;
}
/**
* Get remain count by actions
*
* @param array $actions Actions
*
* @return integer
*/
public function getRemainCountByActions($actions = array())
{
global $wpdb;
if (count($actions) === 0) {
return -1;
}
$inActionArr = array_map(function($action) {
return '"' . $action . '"';
}, $actions);
return (int)$wpdb->get_var('SELECT COUNT(*) FROM ' . $wpdb->prefix . self::getOption('plugin_prefix') . '_queue WHERE status=0 AND action in ('.implode(',', $inActionArr).')');
}
/**
* Enqueue background task script
*
* @return void
*/
public function enqueueScript()
{
global $wpdb;
$queue_length = (int)$wpdb->get_var('SELECT COUNT(*) FROM ' . $wpdb->prefix . self::getOption('plugin_prefix') . '_queue');
if ($queue_length > 0 || self::getOption('use_queue')) {
$queue_trigger = get_option('joomunited_queue_trigger', 'heartbeat');
$joomunited_queue_refreshment_interval = get_option('joomunited_queue_refreshment_interval', 15);
wp_enqueue_script(self::getOption('plugin_prefix') . '_queue', self::getOption('assets_url'), array('jquery'), null, true);
wp_localize_script(self::getOption('plugin_prefix') . '_queue', self::getOption('plugin_prefix') . '_object_queue', array(
'ajaxurl' => admin_url('admin-ajax.php'),
'prefix' => self::getOption('plugin_prefix'),
'trigger' => $queue_trigger,
'queue_ajax_interval' => $joomunited_queue_refreshment_interval,
'stop_label' => esc_html__('Pause queue', self::getOption('plugin_domain')),// phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralDomain,WordPress.WP.I18n.NonSingularStringLiteralText
'start_label' => esc_html__('Start queue', self::getOption('plugin_domain')),// phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralDomain,WordPress.WP.I18n.NonSingularStringLiteralText
));
}
}
/**
* Heartbeat received
*
* @return array
*/
public function heartbeat_received($response, $data)
{
// Make sure we only run our query if the edd_heartbeat key is present
if (isset($data['ju_queue_heartbeat']) && $data['ju_queue_heartbeat'] === 'run_queue') {
/**
* Action fire to sync
*
* @internal
*/
$this->proceedQueueAsync();
// Send back the number of timestamp
$response['ju_queue_result'] = $this->ajaxQueue();
}
return $response;
}
/**
* Ajax request
*
* @return void
*/
public function initAjax()
{
add_action('wp_ajax_'. self::getOption('plugin_prefix') .'_clear_queue', function () {
global $wpdb;
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Params has prepared
$wpdb->query('DELETE FROM ' . $wpdb->prefix . self::getOption('plugin_prefix') . '_queue');
wp_send_json(array('status' => true));
});
add_action('wp_ajax_'. self::getOption('plugin_prefix') .'_stop_queue', function () {
global $wpdb;
$row = $wpdb->get_row($wpdb->prepare('SELECT option_value FROM '. $wpdb->options .' WHERE option_name = %s LIMIT 1', self::getOption('plugin_prefix') . '_stop_queue'));
if (is_object($row)) {
$stop = ((int)$row->option_value === 0) ? 1 : 0;
} else {
$stop = 1;
}
update_option(self::getOption('plugin_prefix') . '_stop_queue', $stop);
});
add_action('wp_ajax_'. self::getOption('plugin_prefix') .'_queue', function () {
$result = $this->ajaxQueue();
if ($result) {
header('Content-Type: application/json');
echo $result;
}
self::proceedQueueAsync();
exit(0);
});
add_action('wp_ajax_nopriv_'. self::getOption('plugin_prefix') .'_proceed', function () {
error_reporting(0);
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No action and a custom token is used
if (!isset($_REQUEST[self::getOption('plugin_prefix') . '_token']) || $_REQUEST[self::getOption('plugin_prefix') . '_token'] !== get_option(self::getOption('plugin_prefix') . '_token')) {
self::log('Info : Proceed queue ajax stopped, wrong token');
exit(0);
}
self::log('Info : Proceed queue ajax');
if (ob_get_length()) {
ob_end_clean();
}
header('Connection: close');
header('Content-Encoding: none');
ignore_user_abort(true);
header('Content-Length: 0');
ob_end_flush();
flush();
if (ob_get_length()) {
ob_end_clean();
}
$this->proceedQueue();
switch ((int)self::getTasksSpeed()) {
case 100:
case 75:
if ($this->getQueueLength()) {
$this->proceedQueueAsync();
}
break;
}
});
}
/**
* Get queue status on ajax call
*
* @return false|string
*/
public function ajaxQueue()
{
$stop = $this->getStopStatus();
$queue_length = $this->getQueueLength();
$statuss = $this->getStatus();
$status_html = '';
$status_templates = self::$status_templates;
foreach ($statuss as $status) {
if (isset($status_templates[$status->action])) {
$status_html .= '- '. str_replace('%d', $status->count, $status_templates[$status->action]) .'
';
}
}
$status_html .= '
';
return json_encode(array(
'queue_length' => $queue_length,
'status_html' => $status_html,
'stop' => $stop,
'title' => sprintf(__('%s actions queued', self::getOption('plugin_domain')), $queue_length) // phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralDomain,WordPress.WP.I18n.NonSingularStringLiteralText
));
}
/**
* Get table charset and collation.
*
* @return string
*/
public function getWpCharsetCollate() {
global $wpdb;
$charset_collate = '';
if ( ! empty ( $wpdb->charset ) )
$charset_collate = 'CHARACTER SET ' . $wpdb->charset;
if (!empty ($wpdb->collate)) {
$charset_collate .= ' COLLATE ' . $wpdb->collate;
}
return $charset_collate;
}
/**
* Check if the plugin need to run an update of db or options
*
* @return void
*/
public function runUpgrades()
{
global $wpdb;
$pluginPrefix = self::getOption('plugin_prefix');
$charset_collate = $this->getWpCharsetCollate();
// phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- Params has prepared
$createTable = "CREATE TABLE `" . $wpdb->prefix . $pluginPrefix . "_queue` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`datas` LONGTEXT NOT NULL,
`data_hash` VARCHAR(32) NOT NULL DEFAULT '',
`action` LONGTEXT NOT NULL,
`responses` LONGTEXT DEFAULT NULL,
`date_added` BIGINT UNSIGNED DEFAULT 0,
`date_done` BIGINT UNSIGNED DEFAULT 0,
`retries` int(11) UNSIGNED NOT NULL DEFAULT 0,
`status` tinyint(1) UNSIGNED NOT NULL,
PRIMARY KEY (`id`),
KEY idx_data_hash (data_hash(32)),
KEY idx_status (status)
) " . $charset_collate . " ENGINE=InnoDB";
// phpcs:enable
// Create table if not exists. Return true on table exists or success.
require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
$result = \maybe_create_table($wpdb->prefix . $pluginPrefix . '_queue', $createTable);
// Update
$queueVersion = get_option($pluginPrefix . '_queue', false);
// Update for version 1.0.1
if ($result && $queueVersion && version_compare($queueVersion, '1.0.1', '<')) {
$alterQuery = 'ALTER TABLE `' . $wpdb->prefix . $pluginPrefix . '_queue` MODIFY COLUMN `date_added` BIGINT UNSIGNED DEFAULT 0;';
$wpdb->query($alterQuery);
$alterQuery = 'ALTER TABLE `' . $wpdb->prefix . $pluginPrefix . '_queue` MODIFY COLUMN `date_done` BIGINT UNSIGNED DEFAULT 0;';
$wpdb->query($alterQuery);
$alterQuery = 'ALTER TABLE `' . $wpdb->prefix . $pluginPrefix . '_queue` ADD COLUMN `data_hash` VARCHAR(32) NOT NULL AFTER `datas`;';
$wpdb->query($alterQuery);
// Drop old index
$alterQuery = 'ALTER TABLE `' . $wpdb->prefix . $pluginPrefix . '_queue` DROP INDEX idx_datas;';
$wpdb->query($alterQuery);
// Create new index
$alterQuery = 'CREATE INDEX idx_data_hash ON `' . $wpdb->prefix . $pluginPrefix . '_queue` (data_hash(32));';
$wpdb->query($alterQuery);
}
if ($queueVersion && version_compare($queueVersion, self::$version, '>=')) {
return;
}
update_option($pluginPrefix . '_queue', self::$version);
update_option($pluginPrefix . '_token', self::getRandomString());
}
/**
* Generate a random string
*
* @param integer $length Length of the returned string
*
* @author https://stackoverflow.com/questions/4356289/php-random-string-generator#answer-4356295
*
* @return string
*/
private function getRandomString($length = 20)
{
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$charactersLength = strlen($characters);
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[rand(0, $charactersLength - 1)];
}
return $randomString;
}
/**
* Log into a debug file
*
* @param string $msg Message
*
* @return void
*/
public static function log($msg = '')
{
// Do nothing if not enabled
if (!self::getOption('debug_enabled')) {
return;
}
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Log if enable debug
error_log($msg);
}
/**
* Get asset URL
*
* @return string
*/
private function getAssetBaseUrl()
{
$currentPath = plugin_dir_url(__FILE__) . DIRECTORY_SEPARATOR . 'assets';
$url = str_replace(
wp_normalize_path(untrailingslashit(ABSPATH)),
site_url(),
wp_normalize_path($currentPath)
);
return esc_url_raw($url);
}
/**
* Update queue meta
*
* @param integer $attachment_id Attachment ID
* @param integer $queue_id Queue ID
*
* @return void
*/
public function updateQueuePostMeta($attachment_id, $queue_id)
{
$queue_meta = get_post_meta($attachment_id, 'wpmf_sync_queue', true);
if (!empty($queue_meta) && is_array($queue_meta)) {
$queue_ids = array_merge($queue_meta, array($queue_id));
} else {
$queue_ids = array((int)$queue_id);
}
update_post_meta($attachment_id, 'wpmf_sync_queue', array_unique($queue_ids));
}
/**
* Update queue meta
*
* @param integer $term_id Term ID
* @param integer $queue_id Queue ID
*
* @return void
*/
public function updateQueueTermMeta($term_id, $queue_id)
{
$queue_meta = get_term_meta($term_id, 'wpmf_sync_queue', true);
if (!empty($queue_meta) && is_array($queue_meta)) {
$queue_ids = array_merge($queue_meta, array($queue_id));
} else {
$queue_ids = array((int)$queue_id);
}
update_term_meta($term_id, 'wpmf_sync_queue', array_unique($queue_ids));
}
}