File "ActionScheduler_wpPostStore.php"
Full path: /home/kosmetik/public_html/wp-content/plugins/woocommerce/packages/action-scheduler/classes/data-stores/ActionScheduler_wpPostStore.php
File
size: 23.09 B
MIME-type: text/x-php
Charset: utf-8
Download Open Edit Advanced Editor Back
<?php
class ActionScheduler_wpPostStore extends ActionScheduler_Store
{
const POST_TYPE = 'scheduled-action';
const GROUP_TAXONOMY = 'action-group';
const SCHEDULE_META_KEY = '_action_manager_schedule';
const DEPENDENCIES_MET = 'as-post-store-dependencies-met';
private $claim_before_date = null;
protected $local_timezone = NULL;
public function save_action(ActionScheduler_Action $action, DateTime $scheduled_date = NULL)
{
try {
$this->validate_action($action);
$post_array = $this->create_post_array($action, $scheduled_date);
$post_id = $this->save_post_array($post_array);
$this->save_post_schedule($post_id, $action->get_schedule());
$this->save_action_group($post_id, $action->get_group());
do_action('action_scheduler_stored_action', $post_id);
return $post_id;
} catch (Exception $e) {
throw new RuntimeException(sprintf(__('Error saving action: %s', 'woocommerce'), $e->getMessage()), 0);
}
}
protected function create_post_array(ActionScheduler_Action $action, DateTime $scheduled_date = NULL)
{
$post = array('post_type' => self::POST_TYPE, 'post_title' => $action->get_hook(), 'post_content' => json_encode($action->get_args()), 'post_status' => $action->is_finished() ? 'publish' : 'pending', 'post_date_gmt' => $this->get_scheduled_date_string($action, $scheduled_date), 'post_date' => $this->get_scheduled_date_string_local($action, $scheduled_date));
return $post;
}
protected function save_post_array($post_array)
{
add_filter('wp_insert_post_data', array($this, 'filter_insert_post_data'), 10, 1);
add_filter('pre_wp_unique_post_slug', array($this, 'set_unique_post_slug'), 10, 5);
$has_kses = false !== has_filter('content_save_pre', 'wp_filter_post_kses');
if ($has_kses) {
kses_remove_filters();
}
$post_id = wp_insert_post($post_array);
if ($has_kses) {
kses_init_filters();
}
remove_filter('wp_insert_post_data', array($this, 'filter_insert_post_data'), 10);
remove_filter('pre_wp_unique_post_slug', array($this, 'set_unique_post_slug'), 10);
if (is_wp_error($post_id) || empty($post_id)) {
throw new RuntimeException(__('Unable to save action.', 'woocommerce'));
}
return $post_id;
}
public function filter_insert_post_data($postdata)
{
if ($postdata['post_type'] == self::POST_TYPE) {
$postdata['post_author'] = 0;
if ($postdata['post_status'] == 'future') {
$postdata['post_status'] = 'publish';
}
}
return $postdata;
}
public function set_unique_post_slug($override_slug, $slug, $post_ID, $post_status, $post_type)
{
if (self::POST_TYPE == $post_type) {
$override_slug = uniqid(self::POST_TYPE . '-', true) . '-' . wp_generate_password(32, false);
}
return $override_slug;
}
protected function save_post_schedule($post_id, $schedule)
{
update_post_meta($post_id, self::SCHEDULE_META_KEY, $schedule);
}
protected function save_action_group($post_id, $group)
{
if (empty($group)) {
wp_set_object_terms($post_id, array(), self::GROUP_TAXONOMY, FALSE);
} else {
wp_set_object_terms($post_id, array($group), self::GROUP_TAXONOMY, FALSE);
}
}
public function fetch_action($action_id)
{
$post = $this->get_post($action_id);
if (empty($post) || $post->post_type != self::POST_TYPE) {
return $this->get_null_action();
}
try {
$action = $this->make_action_from_post($post);
} catch (ActionScheduler_InvalidActionException $exception) {
do_action('action_scheduler_failed_fetch_action', $post->ID, $exception);
return $this->get_null_action();
}
return $action;
}
protected function get_post($action_id)
{
if (empty($action_id)) {
return NULL;
}
return get_post($action_id);
}
protected function get_null_action()
{
return new ActionScheduler_NullAction();
}
protected function make_action_from_post($post)
{
$hook = $post->post_title;
$args = json_decode($post->post_content, true);
$this->validate_args($args, $post->ID);
$schedule = get_post_meta($post->ID, self::SCHEDULE_META_KEY, true);
$this->validate_schedule($schedule, $post->ID);
$group = wp_get_object_terms($post->ID, self::GROUP_TAXONOMY, array('fields' => 'names'));
$group = empty($group) ? '' : reset($group);
return ActionScheduler::factory()->get_stored_action($this->get_action_status_by_post_status($post->post_status), $hook, $args, $schedule, $group);
}
protected function get_action_status_by_post_status($post_status)
{
switch ($post_status) {
case 'publish':
$action_status = self::STATUS_COMPLETE;
break;
case 'trash':
$action_status = self::STATUS_CANCELED;
break;
default:
if (!array_key_exists($post_status, $this->get_status_labels())) {
throw new InvalidArgumentException(sprintf('Invalid post status: "%s". No matching action status available.', $post_status));
}
$action_status = $post_status;
break;
}
return $action_status;
}
protected function get_post_status_by_action_status($action_status)
{
switch ($action_status) {
case self::STATUS_COMPLETE:
$post_status = 'publish';
break;
case self::STATUS_CANCELED:
$post_status = 'trash';
break;
default:
if (!array_key_exists($action_status, $this->get_status_labels())) {
throw new InvalidArgumentException(sprintf('Invalid action status: "%s".', $action_status));
}
$post_status = $action_status;
break;
}
return $post_status;
}
protected function get_query_actions_sql(array $query, $select_or_count = 'select')
{
if (!in_array($select_or_count, array('select', 'count'))) {
throw new InvalidArgumentException(__('Invalid schedule. Cannot save action.', 'woocommerce'));
}
$query = wp_parse_args($query, array('hook' => '', 'args' => NULL, 'date' => NULL, 'date_compare' => '<=', 'modified' => NULL, 'modified_compare' => '<=', 'group' => '', 'status' => '', 'claimed' => NULL, 'per_page' => 5, 'offset' => 0, 'orderby' => 'date', 'order' => 'ASC', 'search' => ''));
global $wpdb;
$sql = 'count' === $select_or_count ? 'SELECT count(p.ID)' : 'SELECT p.ID ';
$sql .= "FROM {$wpdb->posts} p";
$sql_params = array();
if (empty($query['group']) && 'group' === $query['orderby']) {
$sql .= " LEFT JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID";
$sql .= " LEFT JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id";
$sql .= " LEFT JOIN {$wpdb->terms} t ON tt.term_id=t.term_id";
} elseif (!empty($query['group'])) {
$sql .= " INNER JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID";
$sql .= " INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id";
$sql .= " INNER JOIN {$wpdb->terms} t ON tt.term_id=t.term_id";
$sql .= " AND t.slug=%s";
$sql_params[] = $query['group'];
}
$sql .= " WHERE post_type=%s";
$sql_params[] = self::POST_TYPE;
if ($query['hook']) {
$sql .= " AND p.post_title=%s";
$sql_params[] = $query['hook'];
}
if (!is_null($query['args'])) {
$sql .= " AND p.post_content=%s";
$sql_params[] = json_encode($query['args']);
}
if ($query['status']) {
$post_statuses = array_map(array($this, 'get_post_status_by_action_status'), (array) $query['status']);
$placeholders = array_fill(0, count($post_statuses), '%s');
$sql .= ' AND p.post_status IN (' . join(', ', $placeholders) . ')';
$sql_params = array_merge($sql_params, array_values($post_statuses));
}
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 p.post_date_gmt {$comparator} %s";
$sql_params[] = $date_string;
}
if ($query['modified'] instanceof DateTime) {
$modified = clone $query['modified'];
$modified->setTimezone(new DateTimeZone('UTC'));
$date_string = $modified->format('Y-m-d H:i:s');
$comparator = $this->validate_sql_comparator($query['modified_compare']);
$sql .= " AND p.post_modified_gmt {$comparator} %s";
$sql_params[] = $date_string;
}
if ($query['claimed'] === TRUE) {
$sql .= " AND p.post_password != ''";
} elseif ($query['claimed'] === FALSE) {
$sql .= " AND p.post_password = ''";
} elseif (!is_null($query['claimed'])) {
$sql .= " AND p.post_password = %s";
$sql_params[] = $query['claimed'];
}
if (!empty($query['search'])) {
$sql .= " AND (p.post_title LIKE %s OR p.post_content LIKE %s OR p.post_password LIKE %s)";
for ($i = 0; $i < 3; $i++) {
$sql_params[] = sprintf('%%%s%%', $query['search']);
}
}
if ('select' === $select_or_count) {
switch ($query['orderby']) {
case 'hook':
$orderby = 'p.post_title';
break;
case 'group':
$orderby = 't.name';
break;
case 'status':
$orderby = 'p.post_status';
break;
case 'modified':
$orderby = 'p.post_modified';
break;
case 'claim_id':
$orderby = 'p.post_password';
break;
case 'schedule':
case 'date':
default:
$orderby = 'p.post_date_gmt';
break;
}
if ('ASC' === strtoupper($query['order'])) {
$order = 'ASC';
} else {
$order = 'DESC';
}
$sql .= " ORDER BY {$orderby} {$order}";
if ($query['per_page'] > 0) {
$sql .= " LIMIT %d, %d";
$sql_params[] = $query['offset'];
$sql_params[] = $query['per_page'];
}
}
return $wpdb->prepare($sql, $sql_params);
}
public function query_actions($query = array(), $query_type = 'select')
{
global $wpdb;
$sql = $this->get_query_actions_sql($query, $query_type);
return 'count' === $query_type ? $wpdb->get_var($sql) : $wpdb->get_col($sql);
}
public function action_counts()
{
$action_counts_by_status = array();
$action_stati_and_labels = $this->get_status_labels();
$posts_count_by_status = (array) wp_count_posts(self::POST_TYPE, 'readable');
foreach ($posts_count_by_status as $post_status_name => $count) {
try {
$action_status_name = $this->get_action_status_by_post_status($post_status_name);
} catch (Exception $e) {
continue;
}
if (array_key_exists($action_status_name, $action_stati_and_labels)) {
$action_counts_by_status[$action_status_name] = $count;
}
}
return $action_counts_by_status;
}
public function cancel_action($action_id)
{
$post = get_post($action_id);
if (empty($post) || $post->post_type != self::POST_TYPE) {
throw new InvalidArgumentException(sprintf(__('Unidentified action %s', 'woocommerce'), $action_id));
}
do_action('action_scheduler_canceled_action', $action_id);
add_filter('pre_wp_unique_post_slug', array($this, 'set_unique_post_slug'), 10, 5);
wp_trash_post($action_id);
remove_filter('pre_wp_unique_post_slug', array($this, 'set_unique_post_slug'), 10);
}
public function delete_action($action_id)
{
$post = get_post($action_id);
if (empty($post) || $post->post_type != self::POST_TYPE) {
throw new InvalidArgumentException(sprintf(__('Unidentified action %s', 'woocommerce'), $action_id));
}
do_action('action_scheduler_deleted_action', $action_id);
wp_delete_post($action_id, TRUE);
}
public function get_date($action_id)
{
$next = $this->get_date_gmt($action_id);
return ActionScheduler_TimezoneHelper::set_local_timezone($next);
}
public function get_date_gmt($action_id)
{
$post = get_post($action_id);
if (empty($post) || $post->post_type != self::POST_TYPE) {
throw new InvalidArgumentException(sprintf(__('Unidentified action %s', 'woocommerce'), $action_id));
}
if ($post->post_status == 'publish') {
return as_get_datetime_object($post->post_modified_gmt);
} else {
return as_get_datetime_object($post->post_date_gmt);
}
}
public function stake_claim($max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '')
{
$this->claim_before_date = $before_date;
$claim_id = $this->generate_claim_id();
$this->claim_actions($claim_id, $max_actions, $before_date, $hooks, $group);
$action_ids = $this->find_actions_by_claim_id($claim_id);
$this->claim_before_date = null;
return new ActionScheduler_ActionClaim($claim_id, $action_ids);
}
public function get_claim_count()
{
global $wpdb;
$sql = "SELECT COUNT(DISTINCT post_password) FROM {$wpdb->posts} WHERE post_password != '' AND post_type = %s AND post_status IN ('in-progress','pending')";
$sql = $wpdb->prepare($sql, array(self::POST_TYPE));
return $wpdb->get_var($sql);
}
protected function generate_claim_id()
{
$claim_id = md5(microtime(true) . rand(0, 1000));
return substr($claim_id, 0, 20);
}
protected function claim_actions($claim_id, $limit, DateTime $before_date = null, $hooks = array(), $group = '')
{
$date = null === $before_date ? as_get_datetime_object() : clone $before_date;
$limit_ids = !empty($group);
$ids = $limit_ids ? $this->get_actions_by_group($group, $limit, $date) : array();
if ($limit_ids && 0 === count($ids)) {
return 0;
}
global $wpdb;
$update = "UPDATE {$wpdb->posts} SET post_password = %s, post_modified_gmt = %s, post_modified = %s";
$params = array($claim_id, current_time('mysql', true), current_time('mysql'));
$where = "WHERE post_type = %s AND post_status = %s AND post_password = ''";
$params[] = self::POST_TYPE;
$params[] = ActionScheduler_Store::STATUS_PENDING;
if (!empty($hooks)) {
$placeholders = array_fill(0, count($hooks), '%s');
$where .= ' AND post_title IN (' . join(', ', $placeholders) . ')';
$params = array_merge($params, array_values($hooks));
}
if ($limit_ids) {
$where .= ' AND ID IN (' . join(',', $ids) . ')';
} else {
$where .= ' AND post_date_gmt <= %s';
$params[] = $date->format('Y-m-d H:i:s');
}
$order = 'ORDER BY menu_order ASC, post_date_gmt ASC, ID ASC LIMIT %d';
$params[] = $limit;
$rows_affected = $wpdb->query($wpdb->prepare("{$update} {$where} {$order}", $params));
if ($rows_affected === false) {
throw new RuntimeException(__('Unable to claim actions. Database error.', 'woocommerce'));
}
return (int) $rows_affected;
}
protected function get_actions_by_group($group, $limit, DateTime $date)
{
if (!term_exists($group, self::GROUP_TAXONOMY)) {
throw new InvalidArgumentException(sprintf(__('The group "%s" does not exist.', 'woocommerce'), $group));
}
$query = new WP_Query();
$query_args = array('fields' => 'ids', 'post_type' => self::POST_TYPE, 'post_status' => ActionScheduler_Store::STATUS_PENDING, 'has_password' => false, 'posts_per_page' => $limit * 3, 'suppress_filters' => true, 'no_found_rows' => true, 'orderby' => array('menu_order' => 'ASC', 'date' => 'ASC', 'ID' => 'ASC'), 'date_query' => array('column' => 'post_date_gmt', 'before' => $date->format('Y-m-d H:i'), 'inclusive' => true), 'tax_query' => array(array('taxonomy' => self::GROUP_TAXONOMY, 'field' => 'slug', 'terms' => $group, 'include_children' => false)));
return $query->query($query_args);
}
public function find_actions_by_claim_id($claim_id)
{
global $wpdb;
$sql = "SELECT ID, post_date_gmt FROM {$wpdb->posts} WHERE post_type = %s AND post_password = %s";
$sql = $wpdb->prepare($sql, array(self::POST_TYPE, $claim_id));
$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');
foreach ($wpdb->get_results($sql) as $claimed_action) {
if ($claimed_action->post_date_gmt <= $cut_off) {
$action_ids[] = absint($claimed_action->ID);
}
}
return $action_ids;
}
public function release_claim(ActionScheduler_ActionClaim $claim)
{
$action_ids = $this->find_actions_by_claim_id($claim->get_id());
if (empty($action_ids)) {
return;
}
$action_id_string = implode(',', array_map('intval', $action_ids));
global $wpdb;
$sql = "UPDATE {$wpdb->posts} SET post_password = '' WHERE ID IN ({$action_id_string}) AND post_password = %s";
$sql = $wpdb->prepare($sql, array($claim->get_id()));
$result = $wpdb->query($sql);
if ($result === false) {
throw new RuntimeException(sprintf(__('Unable to unlock claim %s. Database error.', 'woocommerce'), $claim->get_id()));
}
}
public function unclaim_action($action_id)
{
global $wpdb;
$sql = "UPDATE {$wpdb->posts} SET post_password = '' WHERE ID = %d AND post_type = %s";
$sql = $wpdb->prepare($sql, $action_id, self::POST_TYPE);
$result = $wpdb->query($sql);
if ($result === false) {
throw new RuntimeException(sprintf(__('Unable to unlock claim on action %s. Database error.', 'woocommerce'), $action_id));
}
}
public function mark_failure($action_id)
{
global $wpdb;
$sql = "UPDATE {$wpdb->posts} SET post_status = %s WHERE ID = %d AND post_type = %s";
$sql = $wpdb->prepare($sql, self::STATUS_FAILED, $action_id, self::POST_TYPE);
$result = $wpdb->query($sql);
if ($result === false) {
throw new RuntimeException(sprintf(__('Unable to mark failure on action %s. Database error.', 'woocommerce'), $action_id));
}
}
public function get_claim_id($action_id)
{
return $this->get_post_column($action_id, 'post_password');
}
public function get_status($action_id)
{
$status = $this->get_post_column($action_id, 'post_status');
if ($status === null) {
throw new InvalidArgumentException(__('Invalid action ID. No status found.', 'woocommerce'));
}
return $this->get_action_status_by_post_status($status);
}
private function get_post_column($action_id, $column_name)
{
global $wpdb;
return $wpdb->get_var($wpdb->prepare("SELECT {$column_name} FROM {$wpdb->posts} WHERE ID=%d AND post_type=%s", $action_id, self::POST_TYPE));
}
public function log_execution($action_id)
{
global $wpdb;
$sql = "UPDATE {$wpdb->posts} SET menu_order = menu_order+1, post_status=%s, post_modified_gmt = %s, post_modified = %s WHERE ID = %d AND post_type = %s";
$sql = $wpdb->prepare($sql, self::STATUS_RUNNING, current_time('mysql', true), current_time('mysql'), $action_id, self::POST_TYPE);
$wpdb->query($sql);
}
public function mark_complete($action_id)
{
$post = get_post($action_id);
if (empty($post) || $post->post_type != self::POST_TYPE) {
throw new InvalidArgumentException(sprintf(__('Unidentified action %s', 'woocommerce'), $action_id));
}
add_filter('wp_insert_post_data', array($this, 'filter_insert_post_data'), 10, 1);
add_filter('pre_wp_unique_post_slug', array($this, 'set_unique_post_slug'), 10, 5);
$result = wp_update_post(array('ID' => $action_id, 'post_status' => 'publish'), TRUE);
remove_filter('wp_insert_post_data', array($this, 'filter_insert_post_data'), 10);
remove_filter('pre_wp_unique_post_slug', array($this, 'set_unique_post_slug'), 10);
if (is_wp_error($result)) {
throw new RuntimeException($result->get_error_message());
}
}
public function mark_migrated($action_id)
{
wp_update_post(array('ID' => $action_id, 'post_status' => 'migrated'));
}
public function migration_dependencies_met($setting)
{
global $wpdb;
$dependencies_met = get_transient(self::DEPENDENCIES_MET);
if (empty($dependencies_met)) {
$maximum_args_length = apply_filters('action_scheduler_maximum_args_length', 191);
$found_action = $wpdb->get_var($wpdb->prepare("SELECT ID FROM {$wpdb->posts} WHERE post_type = %s AND CHAR_LENGTH(post_content) > %d LIMIT 1", $maximum_args_length, self::POST_TYPE));
$dependencies_met = $found_action ? 'no' : 'yes';
set_transient(self::DEPENDENCIES_MET, $dependencies_met, DAY_IN_SECONDS);
}
return 'yes' == $dependencies_met ? $setting : false;
}
protected function validate_action(ActionScheduler_Action $action)
{
try {
parent::validate_action($action);
} catch (Exception $e) {
$message = sprintf(__('%s Support for strings longer than this will be removed in a future version.', 'woocommerce'), $e->getMessage());
_doing_it_wrong('ActionScheduler_Action::$args', $message, '2.1.0');
}
}
public function init()
{
add_filter('action_scheduler_migration_dependencies_met', array($this, 'migration_dependencies_met'));
$post_type_registrar = new ActionScheduler_wpPostStore_PostTypeRegistrar();
$post_type_registrar->register();
$post_status_registrar = new ActionScheduler_wpPostStore_PostStatusRegistrar();
$post_status_registrar->register();
$taxonomy_registrar = new ActionScheduler_wpPostStore_TaxonomyRegistrar();
$taxonomy_registrar->register();
}
}