Plugin Directory

Changeset 2622865


Ignore:
Timestamp:
11/01/2021 03:21:13 PM (4 years ago)
Author:
peterfabian1000
Message:

Tagging version 3.4.0

Location:
action-scheduler
Files:
24 edited
1 copied

Legend:

Unmodified
Added
Removed
  • action-scheduler/tags/3.4.0/action-scheduler.php

    r2599552 r2622865  
    66 * Author: Automattic
    77 * Author URI: https://automattic.com/
    8  * Version: 3.3.0
     8 * Version: 3.4.0
    99 * License: GPLv3
    1010 *
     
    2727 */
    2828
    29 if ( ! function_exists( 'action_scheduler_register_3_dot_3_dot_0' ) && function_exists( 'add_action' ) ) {
     29if ( ! function_exists( 'action_scheduler_register_3_dot_4_dot_0' ) && function_exists( 'add_action' ) ) {
    3030
    31     if ( ! class_exists( 'ActionScheduler_Versions' ) ) {
     31    if ( ! class_exists( 'ActionScheduler_Versions', false ) ) {
    3232        require_once __DIR__ . '/classes/ActionScheduler_Versions.php';
    3333        add_action( 'plugins_loaded', array( 'ActionScheduler_Versions', 'initialize_latest_version' ), 1, 0 );
    3434    }
    3535
    36     add_action( 'plugins_loaded', 'action_scheduler_register_3_dot_3_dot_0', 0, 0 );
     36    add_action( 'plugins_loaded', 'action_scheduler_register_3_dot_4_dot_0', 0, 0 );
    3737
    3838    /**
    3939     * Registers this version of Action Scheduler.
    4040     */
    41     function action_scheduler_register_3_dot_3_dot_0() {
     41    function action_scheduler_register_3_dot_4_dot_0() {
    4242        $versions = ActionScheduler_Versions::instance();
    43         $versions->register( '3.3.0', 'action_scheduler_initialize_3_dot_3_dot_0' );
     43        $versions->register( '3.4.0', 'action_scheduler_initialize_3_dot_4_dot_0' );
    4444    }
    4545
     
    4747     * Initializes this version of Action Scheduler.
    4848     */
    49     function action_scheduler_initialize_3_dot_3_dot_0() {
     49    function action_scheduler_initialize_3_dot_4_dot_0() {
    5050        // A final safety check is required even here, because historic versions of Action Scheduler
    5151        // followed a different pattern (in some unusual cases, we could reach this point and the
    5252        // ActionScheduler class is already defined—so we need to guard against that).
    53         if ( ! class_exists( 'ActionScheduler' ) ) {
     53        if ( ! class_exists( 'ActionScheduler', false ) ) {
    5454            require_once __DIR__ . '/classes/abstracts/ActionScheduler.php';
    5555            ActionScheduler::init( __FILE__ );
     
    5858
    5959    // Support usage in themes - load this version if no plugin has loaded a version yet.
    60     if ( did_action( 'plugins_loaded' ) && ! doing_action( 'plugins_loaded' ) && ! class_exists( 'ActionScheduler' ) ) {
    61         action_scheduler_initialize_3_dot_3_dot_0();
     60    if ( did_action( 'plugins_loaded' ) && ! doing_action( 'plugins_loaded' ) && ! class_exists( 'ActionScheduler', false ) ) {
     61        action_scheduler_initialize_3_dot_4_dot_0();
    6262        do_action( 'action_scheduler_pre_theme_init' );
    6363        ActionScheduler_Versions::initialize_latest_version();
  • action-scheduler/tags/3.4.0/changelog.txt

    r2599552 r2622865  
    11*** Changelog ***
     2
     3= 3.4.0 - 2021-10-29 =
     4* Enhancement - Number of items per page can now be set for the Scheduled Actions view (props @ovidiul). #771
     5* Fix - Do not lower the max_execution_time if it is already set to 0 (unlimited) (props @barryhughes). #755
     6* Fix - Avoid triggering autoloaders during the version resolution process (props @olegabr). #731 & #776
     7* Dev - ActionScheduler_wcSystemStatus PHPCS fixes (props @ovidiul). #761
     8* Dev - ActionScheduler_DBLogger.php PHPCS fixes (props @ovidiul). #768
     9* Dev - Fixed phpcs for ActionScheduler_Schedule_Deprecated (props @ovidiul). #762
     10* Dev - Improve actions table indicies (props @glagonikas). #774 & #777
     11* Dev - PHPCS fixes for ActionScheduler_DBStore.php (props @ovidiul). #769 & #778
     12* Dev - PHPCS Fixes for ActionScheduler_Abstract_ListTable (props @ovidiul). #763 & #779
     13* Dev - Adds new filter action_scheduler_claim_actions_order_by to allow tuning of the claim query (props @glagonikas). #773
     14* Dev - PHPCS fixes for ActionScheduler_WpPostStore class (props @ovidiul). #780
    215
    316= 3.3.0 - 2021-09-15 =
  • action-scheduler/tags/3.4.0/classes/ActionScheduler_Compatibility.php

    r2599552 r2622865  
    8484     * Only allows raising the existing limit and prevents lowering it. Wrapper for wc_set_time_limit(), when available.
    8585     *
    86      * @param int The time limit in seconds.
     86     * @param int $limit The time limit in seconds.
    8787     */
    8888    public static function raise_time_limit( $limit = 0 ) {
    89         if ( $limit < ini_get( 'max_execution_time' ) ) {
     89        $limit = (int) $limit;
     90        $max_execution_time = (int) ini_get( 'max_execution_time' );
     91
     92        /*
     93         * If the max execution time is already unlimited (zero), or if it exceeds or is equal to the proposed
     94         * limit, there is no reason for us to make further changes (we never want to lower it).
     95         */
     96        if (
     97            0 === $max_execution_time
     98            || ( $max_execution_time >= $limit && $limit !== 0 )
     99        ) {
    90100            return;
    91101        }
     
    94104            wc_set_time_limit( $limit );
    95105        } elseif ( function_exists( 'set_time_limit' ) && false === strpos( ini_get( 'disable_functions' ), 'set_time_limit' ) && ! ini_get( 'safe_mode' ) ) { // phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.safe_modeDeprecatedRemoved
    96             @set_time_limit( $limit );
     106            @set_time_limit( $limit ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
    97107        }
    98108    }
  • action-scheduler/tags/3.4.0/classes/ActionScheduler_ListTable.php

    r2340383 r2622865  
    176176        );
    177177
    178         parent::__construct( array(
    179             'singular' => 'action-scheduler',
    180             'plural'   => 'action-scheduler',
    181             'ajax'     => false,
    182         ) );
    183     }
    184 
     178        parent::__construct(
     179            array(
     180                'singular' => 'action-scheduler',
     181                'plural'   => 'action-scheduler',
     182                'ajax'     => false,
     183            )
     184        );
     185
     186        add_screen_option(
     187            'per_page',
     188            array(
     189                'default' => $this->items_per_page,
     190            )
     191        );
     192
     193        add_filter( 'set_screen_option_' . $this->get_per_page_option_name(), array( $this, 'set_items_per_page_option' ), 10, 3 );
     194        set_screen_options();
     195    }
     196
     197    /**
     198     * Handles setting the items_per_page option for this screen.
     199     *
     200     * @param mixed  $status Default false (to skip saving the current option).
     201     * @param string $option Screen option name.
     202     * @param int    $value  Screen option value.
     203     * @return int
     204     */
     205    public function set_items_per_page_option( $status, $option, $value ) {
     206        return $value;
     207    }
    185208    /**
    186209     * Convert an interval of seconds into a two part human friendly string.
     
    550573        $this->prepare_column_headers();
    551574
    552         $per_page = $this->get_items_per_page( $this->package . '_items_per_page', $this->items_per_page );
     575        $per_page = $this->get_items_per_page( $this->get_per_page_option_name(), $this->items_per_page );
     576
    553577        $query = array(
    554578            'per_page' => $per_page,
     
    610634        return __( 'Search hook, args and claim ID', 'action-scheduler' );
    611635    }
     636
     637    /**
     638     * {@inheritDoc}
     639     */
     640    protected function get_per_page_option_name() {
     641        return str_replace( '-', '_', $this->screen->id ) . '_per_page';
     642    }
    612643}
  • action-scheduler/tags/3.4.0/classes/ActionScheduler_wcSystemStatus.php

    r2542151 r2622865  
    1313    protected $store;
    1414
    15     function __construct( $store ) {
     15    /**
     16     * Constructor method for ActionScheduler_wcSystemStatus.
     17     *
     18     * @param ActionScheduler_Store $store Active store object.
     19     *
     20     * @return void
     21     */
     22    public function __construct( $store ) {
    1623        $this->store = $store;
    1724    }
     
    6875        $order = 'oldest' === $date_type ? 'ASC' : 'DESC';
    6976
    70         $action = $this->store->query_actions( array(
    71             'claimed'  => false,
    72             'status'   => $status,
    73             'per_page' => 1,
    74             'order'    => $order,
    75         ) );
     77        $action = $this->store->query_actions(
     78            array(
     79                'claimed'  => false,
     80                'status'   => $status,
     81                'per_page' => 1,
     82                'order'    => $order,
     83            )
     84        );
    7685
    7786        if ( ! empty( $action ) ) {
     
    93102     */
    94103    protected function get_template( $status_labels, $action_counts, $oldest_and_newest ) {
    95         $as_version = ActionScheduler_Versions::instance()->latest_version();
     104        $as_version   = ActionScheduler_Versions::instance()->latest_version();
    96105        $as_datastore = get_class( ActionScheduler_Store::instance() );
    97106        ?>
     
    125134                        '<tr><td>%1$s</td><td>&nbsp;</td><td>%2$s<span style="display: none;">, Oldest: %3$s, Newest: %4$s</span></td><td>%3$s</td><td>%4$s</td></tr>',
    126135                        esc_html( $status_labels[ $status ] ),
    127                         number_format_i18n( $count ),
    128                         $oldest_and_newest[ $status ]['oldest'],
    129                         $oldest_and_newest[ $status ]['newest']
     136                        esc_html( number_format_i18n( $count ) ),
     137                        esc_html( $oldest_and_newest[ $status ]['oldest'] ),
     138                        esc_html( $oldest_and_newest[ $status ]['newest'] )
    130139                    );
    131140                }
     
    138147
    139148    /**
    140      * is triggered when invoking inaccessible methods in an object context.
     149     * Is triggered when invoking inaccessible methods in an object context.
    141150     *
    142      * @param string $name
    143      * @param array  $arguments
     151     * @param string $name Name of method called.
     152     * @param array  $arguments Parameters to invoke the method with.
    144153     *
    145154     * @return mixed
  • action-scheduler/tags/3.4.0/classes/abstracts/ActionScheduler_Abstract_ListTable.php

    r2551612 r2622865  
    22
    33if ( ! class_exists( 'WP_List_Table' ) ) {
    4     require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
     4    require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
    55}
    66
     
    1414 *
    1515 * This class supports:
    16  *  - Bulk actions
    17  *  - Search
     16 *  - Bulk actions
     17 *  - Search
    1818 *  - Sortable columns
    1919 *  - Automatic translations of the columns
     
    2626    /**
    2727     * The table name
     28     *
     29     * @var string
    2830     */
    2931    protected $table_name;
     
    3133    /**
    3234     * Package name, used to get options from WP_List_Table::get_items_per_page.
     35     *
     36     * @var string
    3337     */
    3438    protected $package;
     
    3640    /**
    3741     * How many items do we render per page?
     42     *
     43     * @var int
    3844     */
    3945    protected $items_per_page = 10;
     
    4248     * Enables search in this table listing. If this array
    4349     * is empty it means the listing is not searchable.
     50     *
     51     * @var array
    4452     */
    4553    protected $search_by = array();
     
    4957     * key must much the table column name and the value is the label, which is
    5058     * automatically translated.
     59     *
     60     * @var array
    5161     */
    5262    protected $columns = array();
     
    5969     * (with the prefix row_action_<key>) and the value is the label
    6070     * and title.
     71     *
     72     * @var array
    6173     */
    6274    protected $row_actions = array();
     
    6476    /**
    6577     * The Primary key of our table
     78     *
     79     * @var string
    6680     */
    6781    protected $ID = 'ID';
     
    7084     * Enables sorting, it expects an array
    7185     * of columns (the column names are the values)
     86     *
     87     * @var array
    7288     */
    7389    protected $sort_by = array();
    7490
     91    /**
     92     * The default sort order
     93     *
     94     * @var string
     95     */
    7596    protected $filter_by = array();
    7697
    7798    /**
    78      * @var array The status name => count combinations for this table's items. Used to display status filters.
     99     * The status name => count combinations for this table's items. Used to display status filters.
     100     *
     101     * @var array
    79102     */
    80103    protected $status_counts = array();
    81104
    82105    /**
    83      * @var array Notices to display when loading the table. Array of arrays of form array( 'class' => {updated|error}, 'message' => 'This is the notice text display.' ).
     106     * Notices to display when loading the table. Array of arrays of form array( 'class' => {updated|error}, 'message' => 'This is the notice text display.' ).
     107     *
     108     * @var array
    84109     */
    85110    protected $admin_notices = array();
    86111
    87112    /**
    88      * @var string Localised string displayed in the <h1> element above the able.
     113     * Localised string displayed in the <h1> element above the able.
     114     *
     115     * @var string
    89116     */
    90117    protected $table_header;
     
    100127     * is the array with primary keys, the second argument is a string with a list of the primary keys,
    101128     * escaped and ready to use (with `IN`).
     129     *
     130     * @var array
    102131     */
    103132    protected $bulk_actions = array();
     
    107136     * `_x` with some default (the package name).
    108137     *
    109      * @deprecated 3.0.0
     138     * @param string $text The new text to translate.
     139     * @param string $context The context of the text.
     140     * @return string|void The translated text.
     141     *
     142     * @deprecated 3.0.0 Use `_x()` instead.
    110143     */
    111144    protected function translate( $text, $context = '' ) {
     
    117150     * also validates that the bulk method handler exists. It throws an exception because
    118151     * this is a library meant for developers and missing a bulk method is a development-time error.
     152     *
     153     * @return array
     154     *
     155     * @throws RuntimeException Throws RuntimeException when the bulk action does not have a callback method.
    119156     */
    120157    protected function get_bulk_actions() {
     
    147184        check_admin_referer( 'bulk-' . $this->_args['plural'] );
    148185
    149         $method   = 'bulk_' . $action;
     186        $method = 'bulk_' . $action;
    150187        if ( array_key_exists( $action, $this->bulk_actions ) && is_callable( array( $this, $method ) ) && ! empty( $_GET['ID'] ) && is_array( $_GET['ID'] ) ) {
    151188            $ids_sql = '(' . implode( ',', array_fill( 0, count( $_GET['ID'] ), '%s' ) ) . ')';
    152             $this->$method( $_GET['ID'], $wpdb->prepare( $ids_sql, $_GET['ID'] ) );
    153         }
    154 
    155         wp_redirect( remove_query_arg(
    156             array( '_wp_http_referer', '_wpnonce', 'ID', 'action', 'action2' ),
    157             wp_unslash( $_SERVER['REQUEST_URI'] )
    158         ) );
    159         exit;
     189            $id      = array_map( 'absint', $_GET['ID'] );
     190            $this->$method( $id, $wpdb->prepare( $ids_sql, $id ) ); //phpcs:ignore WordPress.DB.PreparedSQL
     191        }
     192
     193        if ( isset( $_SERVER['REQUEST_URI'] ) ) {
     194            wp_safe_redirect(
     195                remove_query_arg(
     196                    array( '_wp_http_referer', '_wpnonce', 'ID', 'action', 'action2' ),
     197                    esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) )
     198                )
     199            );
     200            exit;
     201        }
    160202    }
    161203
     
    163205     * Default code for deleting entries.
    164206     * validated already by process_bulk_action()
     207     *
     208     * @param array  $ids ids of the items to delete.
     209     * @param string $ids_sql the sql for the ids.
     210     * @return void
    165211     */
    166212    protected function bulk_delete( array $ids, $ids_sql ) {
     
    218264        global $wpdb;
    219265
    220         $per_page = $this->get_items_per_page( $this->package . '_items_per_page', $this->items_per_page );
     266        $per_page = $this->get_items_per_page( $this->get_per_page_option_name(), $this->items_per_page );
    221267        return $wpdb->prepare( 'LIMIT %d', $per_page );
    222268    }
     
    228274     */
    229275    protected function get_items_offset() {
    230         $per_page = $this->get_items_per_page( $this->package . '_items_per_page', $this->items_per_page );
     276        $per_page     = $this->get_items_per_page( $this->get_per_page_option_name(), $this->items_per_page );
    231277        $current_page = $this->get_pagenum();
    232278        if ( 1 < $current_page ) {
     
    277323        $valid_sortable_columns = array_values( $this->sort_by );
    278324
    279         if ( ! empty( $_GET['orderby'] ) && in_array( $_GET['orderby'], $valid_sortable_columns ) ) {
    280             $orderby = sanitize_text_field( $_GET['orderby'] );
     325        if ( ! empty( $_GET['orderby'] ) && in_array( $_GET['orderby'], $valid_sortable_columns, true ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
     326            $orderby = sanitize_text_field( wp_unslash( $_GET['orderby'] ) ); //phpcs:ignore WordPress.Security.NonceVerification.Recommended
    281327        } else {
    282328            $orderby = $valid_sortable_columns[0];
     
    293339    protected function get_request_order() {
    294340
    295         if ( ! empty( $_GET['order'] ) && 'desc' === strtolower( $_GET['order'] ) ) {
     341        if ( ! empty( $_GET['order'] ) && 'desc' === strtolower( sanitize_text_field( wp_unslash( $_GET['order'] ) ) ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
    296342            $order = 'DESC';
    297343        } else {
     
    308354     */
    309355    protected function get_request_status() {
    310         $status = ( ! empty( $_GET['status'] ) ) ? $_GET['status'] : '';
     356        $status = ( ! empty( $_GET['status'] ) ) ? sanitize_text_field( wp_unslash( $_GET['status'] ) ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Recommended
    311357        return $status;
    312358    }
     
    318364     */
    319365    protected function get_request_search_query() {
    320         $search_query = ( ! empty( $_GET['s'] ) ) ? $_GET['s'] : '';
     366        $search_query = ( ! empty( $_GET['s'] ) ) ? sanitize_text_field( wp_unslash( $_GET['s'] ) ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Recommended
    321367        return $search_query;
    322368    }
     
    330376    protected function get_table_columns() {
    331377        $columns = array_keys( $this->columns );
    332         if ( ! in_array( $this->ID, $columns ) ) {
     378        if ( ! in_array( $this->ID, $columns, true ) ) {
    333379            $columns[] = $this->ID;
    334380        }
     
    344390     * that feature it will return an empty string.
    345391     *
    346      * TODO:
    347      *   - Improve search doing LIKE by word rather than by phrases.
    348      *
    349392     * @return string
    350393     */
     
    352395        global $wpdb;
    353396
    354         if ( empty( $_GET['s'] ) || empty( $this->search_by ) ) {
     397        if ( empty( $_GET['s'] ) || empty( $this->search_by ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
    355398            return '';
    356399        }
    357400
    358         $filter  = array();
     401        $search_string = sanitize_text_field( wp_unslash( $_GET['s'] ) ); //phpcs:ignore WordPress.Security.NonceVerification.Recommended
     402
     403        $filter = array();
    359404        foreach ( $this->search_by as $column ) {
    360             $filter[] = $wpdb->prepare('`' . $column . '` like "%%s%"', $wpdb->esc_like( $_GET['s'] ));
     405            $wild     = '%';
     406            $sql_like = $wild . $wpdb->esc_like( $search_string ) . $wild;
     407            $filter[] = $wpdb->prepare( '`' . $column . '` LIKE %s', $sql_like ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.DB.PreparedSQL.NotPrepared
    361408        }
    362409        return implode( ' OR ', $filter );
     
    370417        global $wpdb;
    371418
    372         if ( ! $this->filter_by || empty( $_GET['filter_by'] ) || ! is_array( $_GET['filter_by'] ) ) {
     419        if ( ! $this->filter_by || empty( $_GET['filter_by'] ) || ! is_array( $_GET['filter_by'] ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
    373420            return '';
    374421        }
     
    377424
    378425        foreach ( $this->filter_by as $column => $options ) {
    379             if ( empty( $_GET['filter_by'][ $column ] ) || empty( $options[ $_GET['filter_by'][ $column ] ] ) ) {
     426            if ( empty( $_GET['filter_by'][ $column ] ) || empty( $options[ $_GET['filter_by'][ $column ] ] ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
    380427                continue;
    381428            }
    382429
    383             $filter[] = $wpdb->prepare( "`$column` = %s", $_GET['filter_by'][ $column ] );
     430            $filter[] = $wpdb->prepare( "`$column` = %s", sanitize_text_field( wp_unslash( $_GET['filter_by'][ $column ] ) ) ); //phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
    384431        }
    385432
     
    404451        $this->process_row_actions();
    405452
    406         if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) {
     453        if ( ! empty( $_REQUEST['_wp_http_referer'] && ! empty( $_SERVER['REQUEST_URI'] ) ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
    407454            // _wp_http_referer is used only on bulk actions, we remove it to keep the $_GET shorter
    408             wp_redirect( remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
     455            wp_safe_redirect( remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) ) );
    409456            exit;
    410457        }
     
    415462        $offset  = $this->get_items_query_offset();
    416463        $order   = $this->get_items_query_order();
    417         $where   = array_filter(array(
    418             $this->get_items_query_search(),
    419             $this->get_items_query_filters(),
    420         ));
     464        $where   = array_filter(
     465            array(
     466                $this->get_items_query_search(),
     467                $this->get_items_query_filters(),
     468            )
     469        );
    421470        $columns = '`' . implode( '`, `', $this->get_table_columns() ) . '`';
    422471
    423472        if ( ! empty( $where ) ) {
    424             $where = 'WHERE ('. implode( ') AND (', $where ) . ')';
     473            $where = 'WHERE (' . implode( ') AND (', $where ) . ')';
    425474        } else {
    426475            $where = '';
     
    429478        $sql = "SELECT $columns FROM {$this->table_name} {$where} {$order} {$limit} {$offset}";
    430479
    431         $this->set_items( $wpdb->get_results( $sql, ARRAY_A ) );
     480        $this->set_items( $wpdb->get_results( $sql, ARRAY_A ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
    432481
    433482        $query_count = "SELECT COUNT({$this->ID}) FROM {$this->table_name} {$where}";
    434         $total_items = $wpdb->get_var( $query_count );
    435         $per_page    = $this->get_items_per_page( $this->package . '_items_per_page', $this->items_per_page );
    436         $this->set_pagination_args( array(
    437             'total_items' => $total_items,
    438             'per_page'    => $per_page,
    439             'total_pages' => ceil( $total_items / $per_page ),
    440         ) );
    441     }
    442 
     483        $total_items = $wpdb->get_var( $query_count ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
     484        $per_page    = $this->get_items_per_page( $this->get_per_page_option_name(), $this->items_per_page );
     485        $this->set_pagination_args(
     486            array(
     487                'total_items' => $total_items,
     488                'per_page'    => $per_page,
     489                'total_pages' => ceil( $total_items / $per_page ),
     490            )
     491        );
     492    }
     493
     494    /**
     495     * Display the table.
     496     *
     497     * @param string $which The name of the table.
     498     */
    443499    public function extra_tablenav( $which ) {
    444500        if ( ! $this->filter_by || 'top' !== $which ) {
     
    449505
    450506        foreach ( $this->filter_by as $id => $options ) {
    451             $default = ! empty( $_GET['filter_by'][ $id ] ) ? $_GET['filter_by'][ $id ] : '';
     507            $default = ! empty( $_GET['filter_by'][ $id ] ) ? sanitize_text_field( wp_unslash( $_GET['filter_by'][ $id ] ) ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Recommended
    452508            if ( empty( $options[ $default ] ) ) {
    453509                $default = '';
     
    457513
    458514            foreach ( $options as $value => $label ) {
    459                 echo '<option value="' . esc_attr( $value ) . '" ' . esc_html( $value == $default ? 'selected' : '' )  .'>'
     515                echo '<option value="' . esc_attr( $value ) . '" ' . esc_html( $value === $default ? 'selected' : '' ) . '>'
    460516                    . esc_html( $label )
    461517                . '</option>';
     
    472528     * Set the data for displaying. It will attempt to unserialize (There is a chance that some columns
    473529     * are serialized). This can be override in child classes for futher data transformation.
     530     *
     531     * @param array $items Items array.
    474532     */
    475533    protected function set_items( array $items ) {
     
    484542     * of how the primary key is named (to keep the code simpler). The bulk actions will do the proper
    485543     * name transformation though using `$this->ID`.
     544     *
     545     * @param array $row The row to render.
    486546     */
    487547    public function column_cb( $row ) {
    488         return '<input name="ID[]" type="checkbox" value="' . esc_attr( $row[ $this->ID ] ) .'" />';
     548        return '<input name="ID[]" type="checkbox" value="' . esc_attr( $row[ $this->ID ] ) . '" />';
    489549    }
    490550
     
    495555     * and it checks that the row action method exists before rendering it.
    496556     *
    497      * @param array $row     Row to render
    498      * @param $column_name   Current row
    499      * @return
     557     * @param array  $row Row to be rendered.
     558     * @param string $column_name Column name.
     559     * @return string
    500560     */
    501561    protected function maybe_render_actions( $row, $column_name ) {
     
    506566        $row_id = $row[ $this->ID ];
    507567
    508         $actions = '<div class="row-actions">';
     568        $actions      = '<div class="row-actions">';
    509569        $action_count = 0;
    510570        foreach ( $this->row_actions[ $column_name ] as $action_key => $action ) {
     
    516576            }
    517577
    518             $action_link = ! empty( $action['link'] ) ? $action['link'] : add_query_arg( array( 'row_action' => $action_key, 'row_id' => $row_id, 'nonce'  => wp_create_nonce( $action_key . '::' . $row_id ) ) );
     578            $action_link = ! empty( $action['link'] ) ? $action['link'] : add_query_arg(
     579                array(
     580                    'row_action' => $action_key,
     581                    'row_id'     => $row_id,
     582                    'nonce'      => wp_create_nonce( $action_key . '::' . $row_id ),
     583                )
     584            );
    519585            $span_class  = ! empty( $action['class'] ) ? $action['class'] : $action_key;
    520586            $separator   = ( $action_count < count( $this->row_actions[ $column_name ] ) ) ? ' | ' : '';
     
    528594    }
    529595
     596    /**
     597     * Process the bulk actions.
     598     *
     599     * @return void
     600     */
    530601    protected function process_row_actions() {
    531602        $parameters = array( 'row_action', 'row_id', 'nonce' );
    532603        foreach ( $parameters as $parameter ) {
    533             if ( empty( $_REQUEST[ $parameter ] ) ) {
     604            if ( empty( $_REQUEST[ $parameter ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
    534605                return;
    535606            }
    536607        }
    537608
    538         $method = 'row_action_' . $_REQUEST['row_action'];
    539 
    540         if ( $_REQUEST['nonce'] === wp_create_nonce( $_REQUEST[ 'row_action' ] . '::' . $_REQUEST[ 'row_id' ] ) && method_exists( $this, $method ) ) {
    541             $this->$method( $_REQUEST['row_id'] );
    542         }
    543 
    544         wp_redirect( remove_query_arg(
    545             array( 'row_id', 'row_action', 'nonce' ),
    546             wp_unslash( $_SERVER['REQUEST_URI'] )
    547         ) );
    548         exit;
     609        $action = sanitize_text_field( wp_unslash( $_REQUEST['row_action'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotValidated
     610        $row_id = sanitize_text_field( wp_unslash( $_REQUEST['row_id'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotValidated
     611        $nonce  = sanitize_text_field( wp_unslash( $_REQUEST['nonce'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotValidated
     612        $method = 'row_action_' . $action; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
     613
     614        if ( wp_verify_nonce( $nonce, $action . '::' . $row_id ) && method_exists( $this, $method ) ) {
     615            $this->$method( sanitize_text_field( wp_unslash( $row_id ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
     616        }
     617
     618        if ( isset( $_SERVER['REQUEST_URI'] ) ) {
     619            wp_safe_redirect(
     620                remove_query_arg(
     621                    array( 'row_id', 'row_action', 'nonce' ),
     622                    esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) )
     623                )
     624            );
     625            exit;
     626        }
    549627    }
    550628
    551629    /**
    552630     * Default column formatting, it will escape everythig for security.
     631     *
     632     * @param array  $item The item array.
     633     * @param string $column_name Column name to display.
     634     *
     635     * @return string
    553636     */
    554637    public function column_default( $item, $column_name ) {
    555         $column_html = esc_html( $item[ $column_name ] );
     638        $column_html  = esc_html( $item[ $column_name ] );
    556639        $column_html .= $this->maybe_render_actions( $item, $column_name );
    557640        return $column_html;
     
    575658    protected function display_admin_notices() {
    576659        foreach ( $this->admin_notices as $notice ) {
    577             echo '<div id="message" class="' . $notice['class'] . '">';
     660            echo '<div id="message" class="' . esc_attr( $notice['class'] ) . '">';
    578661            echo '  <p>' . wp_kses_post( $notice['message'] ) . '</p>';
    579662            echo '</div>';
     
    589672        $request_status    = $this->get_request_status();
    590673
    591         // Helper to set 'all' filter when not set on status counts passed in
     674        // Helper to set 'all' filter when not set on status counts passed in.
    592675        if ( ! isset( $this->status_counts['all'] ) ) {
    593676            $this->status_counts = array( 'all' => array_sum( $this->status_counts ) ) + $this->status_counts;
     
    613696        if ( $status_list_items ) {
    614697            echo '<ul class="subsubsub">';
    615             echo implode( " | \n", $status_list_items );
     698            echo implode( " | \n", $status_list_items ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
    616699            echo '</ul>';
    617700        }
     
    625708    protected function display_table() {
    626709        echo '<form id="' . esc_attr( $this->_args['plural'] ) . '-filter" method="get">';
    627         foreach ( $_GET as $key => $value ) {
     710        foreach ( $_GET as $key => $value ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
    628711            if ( '_' === $key[0] || 'paged' === $key || 'ID' === $key ) {
    629712                continue;
     
    632715        }
    633716        if ( ! empty( $this->search_by ) ) {
    634             echo $this->search_box( $this->get_search_box_button_text(), 'plugin' ); // WPCS: XSS OK
     717            echo $this->search_box( $this->get_search_box_button_text(), 'plugin' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
    635718        }
    636719        parent::display();
     
    645728        $this->process_row_actions();
    646729
    647         if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) {
     730        if ( ! empty( $_REQUEST['_wp_http_referer'] ) && ! empty( $_SERVER['REQUEST_URI'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
    648731            // _wp_http_referer is used only on bulk actions, we remove it to keep the $_GET shorter
    649             wp_redirect( remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
     732            wp_safe_redirect( remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) ) );
    650733            exit;
    651734        }
     
    672755        return esc_html__( 'Search', 'action-scheduler' );
    673756    }
     757
     758    /**
     759     * Gets the screen per_page option name.
     760     *
     761     * @return string
     762     */
     763    protected function get_per_page_option_name() {
     764        return $this->package . '_items_per_page';
     765    }
    674766}
  • action-scheduler/tags/3.4.0/classes/data-stores/ActionScheduler_DBLogger.php

    r2599552 r2622865  
    3030        $date_local = $date->format( 'Y-m-d H:i:s' );
    3131
    32         /** @var \wpdb $wpdb */
     32        /** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort
    3333        global $wpdb;
    34         $wpdb->insert( $wpdb->actionscheduler_logs, [
    35             'action_id'      => $action_id,
    36             'message'        => $message,
    37             'log_date_gmt'   => $date_gmt,
    38             'log_date_local' => $date_local,
    39         ], [ '%d', '%s', '%s', '%s' ] );
     34        $wpdb->insert(
     35            $wpdb->actionscheduler_logs,
     36            array(
     37                'action_id'      => $action_id,
     38                'message'        => $message,
     39                'log_date_gmt'   => $date_gmt,
     40                'log_date_local' => $date_local,
     41            ),
     42            array( '%d', '%s', '%s', '%s' )
     43        );
    4044
    4145        return $wpdb->insert_id;
     
    5054     */
    5155    public function get_entry( $entry_id ) {
    52         /** @var \wpdb $wpdb */
     56        /** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort
    5357        global $wpdb;
    5458        $entry = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_logs} WHERE log_id=%d", $entry_id ) );
     
    8690     */
    8791    public function get_logs( $action_id ) {
    88         /** @var \wpdb $wpdb */
     92        /** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort
    8993        global $wpdb;
    9094
    9195        $records = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_logs} WHERE action_id=%d", $action_id ) );
    9296
    93         return array_map( [ $this, 'create_entry_from_db_record' ], $records );
     97        return array_map( array( $this, 'create_entry_from_db_record' ), $records );
    9498    }
    9599
     
    106110        parent::init();
    107111
    108         add_action( 'action_scheduler_deleted_action', [ $this, 'clear_deleted_action_logs' ], 10, 1 );
     112        add_action( 'action_scheduler_deleted_action', array( $this, 'clear_deleted_action_logs' ), 10, 1 );
    109113    }
    110114
     
    115119     */
    116120    public function clear_deleted_action_logs( $action_id ) {
    117         /** @var \wpdb $wpdb */
     121        /** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort
    118122        global $wpdb;
    119         $wpdb->delete( $wpdb->actionscheduler_logs, [ 'action_id' => $action_id, ], [ '%d' ] );
     123        $wpdb->delete( $wpdb->actionscheduler_logs, array( 'action_id' => $action_id ), array( '%d' ) );
    120124    }
    121125
     
    130134        }
    131135
    132         /** @var \wpdb $wpdb */
     136        /** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort
    133137        global $wpdb;
    134138        $date     = as_get_datetime_object();
     
    139143        $format     = '(%d, ' . $wpdb->prepare( '%s, %s, %s', $message, $date_gmt, $date_local ) . ')';
    140144        $sql_query  = "INSERT {$wpdb->actionscheduler_logs} (action_id, message, log_date_gmt, log_date_local) VALUES ";
    141         $value_rows = [];
     145        $value_rows = array();
    142146
    143147        foreach ( $action_ids as $action_id ) {
    144             $value_rows[] = $wpdb->prepare( $format, $action_id );
     148            $value_rows[] = $wpdb->prepare( $format, $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
    145149        }
    146150        $sql_query .= implode( ',', $value_rows );
    147151
    148         $wpdb->query( $sql_query );
     152        $wpdb->query( $sql_query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
    149153    }
    150154}
  • action-scheduler/tags/3.4.0/classes/data-stores/ActionScheduler_DBStore.php

    r2599552 r2622865  
    4141     *
    4242     * @param ActionScheduler_Action $action Action object.
    43      * @param DateTime               $date Optional schedule date. Default null.
     43     * @param DateTime              $date Optional schedule date. Default null.
    4444     *
    4545     * @return int Action ID.
     46     * @throws RuntimeException     Throws exception when saving the action fails.
    4647     */
    4748    public function save_action( ActionScheduler_Action $action, \DateTime $date = null ) {
     
    5253            /** @var \wpdb $wpdb */
    5354            global $wpdb;
    54             $data = [
     55            $data = array(
    5556                'hook'                 => $action->get_hook(),
    5657                'status'               => ( $action->is_finished() ? self::STATUS_COMPLETE : self::STATUS_PENDING ),
    5758                'scheduled_date_gmt'   => $this->get_scheduled_date_string( $action, $date ),
    5859                'scheduled_date_local' => $this->get_scheduled_date_string_local( $action, $date ),
    59                 'schedule'             => serialize( $action->get_schedule() ),
     60                'schedule'             => serialize( $action->get_schedule() ), // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
    6061                'group_id'             => $this->get_group_id( $action->get_group() ),
    61             ];
     62            );
    6263            $args = wp_json_encode( $action->get_args() );
    6364            if ( strlen( $args ) <= static::$max_index_length ) {
     
    7374
    7475            if ( is_wp_error( $action_id ) ) {
    75                 throw new RuntimeException( $action_id->get_error_message() );
    76             }
    77             elseif ( empty( $action_id ) ) {
    78                 throw new RuntimeException( $wpdb->last_error ? $wpdb->last_error : __( 'Database error.', 'action-scheduler' ) );
     76                throw new \RuntimeException( $action_id->get_error_message() );
     77            } elseif ( empty( $action_id ) ) {
     78                throw new \RuntimeException( $wpdb->last_error ? $wpdb->last_error : __( 'Database error.', 'action-scheduler' ) );
    7979            }
    8080
     
    115115     *
    116116     * @param string $slug The string name of a group.
    117      * @param bool $create_if_not_exists Whether to create the group if it does not already exist. Default, true - create the group.
     117     * @param bool   $create_if_not_exists Whether to create the group if it does not already exist. Default, true - create the group.
    118118     *
    119119     * @return int The group's ID, if it exists or is created, or 0 if it does not exist and is not created.
     
    143143        /** @var \wpdb $wpdb */
    144144        global $wpdb;
    145         $wpdb->insert( $wpdb->actionscheduler_groups, [ 'slug' => $slug ] );
     145        $wpdb->insert( $wpdb->actionscheduler_groups, array( 'slug' => $slug ) );
    146146
    147147        return (int) $wpdb->insert_id;
     
    158158        /** @var \wpdb $wpdb */
    159159        global $wpdb;
    160         $data = $wpdb->get_row( $wpdb->prepare(
    161             "SELECT a.*, g.slug AS `group` FROM {$wpdb->actionscheduler_actions} a LEFT JOIN {$wpdb->actionscheduler_groups} g ON a.group_id=g.group_id WHERE a.action_id=%d",
    162             $action_id
    163         ) );
     160        $data = $wpdb->get_row(
     161            $wpdb->prepare(
     162                "SELECT a.*, g.slug AS `group` FROM {$wpdb->actionscheduler_actions} a LEFT JOIN {$wpdb->actionscheduler_groups} g ON a.group_id=g.group_id WHERE a.action_id=%d",
     163                $action_id
     164            )
     165        );
    164166
    165167        if ( empty( $data ) ) {
     
    173175
    174176        // Convert NULL dates to zero dates.
    175         $date_fields = [
     177        $date_fields = array(
    176178            'scheduled_date_gmt',
    177179            'scheduled_date_local',
    178180            'last_attempt_gmt',
    179             'last_attempt_gmt'
    180         ];
    181         foreach( $date_fields as $date_field ) {
     181            'last_attempt_gmt',
     182        );
     183        foreach ( $date_fields as $date_field ) {
    182184            if ( is_null( $data->$date_field ) ) {
    183185                $data->$date_field = ActionScheduler_StoreSchema::DEFAULT_DATE;
     
    215217        $hook     = $data->hook;
    216218        $args     = json_decode( $data->args, true );
    217         $schedule = unserialize( $data->schedule );
     219        $schedule = unserialize( $data->schedule ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_unserialize
    218220
    219221        $this->validate_args( $args, $data->action_id );
     
    237239     *
    238240     * @return string SQL statement already properly escaped.
     241     * @throws InvalidArgumentException If the query is invalid.
    239242     */
    240243    protected function get_query_actions_sql( array $query, $select_or_count = 'select' ) {
    241244
    242         if ( ! in_array( $select_or_count, array( 'select', 'count' ) ) ) {
     245        if ( ! in_array( $select_or_count, array( 'select', 'count' ), true ) ) {
    243246            throw new InvalidArgumentException( __( 'Invalid value for select or count parameter. Cannot query actions.', 'action-scheduler' ) );
    244247        }
    245248
    246         $query = wp_parse_args( $query, [
    247             'hook'             => '',
    248             'args'             => null,
    249             'date'             => null,
    250             'date_compare'     => '<=',
    251             'modified'         => null,
    252             'modified_compare' => '<=',
    253             'group'            => '',
    254             'status'           => '',
    255             'claimed'          => null,
    256             'per_page'         => 5,
    257             'offset'           => 0,
    258             'orderby'          => 'date',
    259             'order'            => 'ASC',
    260         ] );
    261 
    262         /** @var \wpdb $wpdb */
    263         global $wpdb;
    264         $sql  = ( 'count' === $select_or_count ) ? 'SELECT count(a.action_id)' : 'SELECT a.action_id';
    265         $sql .= " FROM {$wpdb->actionscheduler_actions} a";
    266         $sql_params = [];
    267 
    268         if ( ! empty( $query[ 'group' ] ) || 'group' === $query[ 'orderby' ] ) {
     249        $query = wp_parse_args(
     250            $query,
     251            array(
     252                'hook'             => '',
     253                'args'             => null,
     254                'date'             => null,
     255                'date_compare'     => '<=',
     256                'modified'         => null,
     257                'modified_compare' => '<=',
     258                'group'            => '',
     259                'status'           => '',
     260                'claimed'          => null,
     261                'per_page'         => 5,
     262                'offset'           => 0,
     263                'orderby'          => 'date',
     264                'order'            => 'ASC',
     265            )
     266        );
     267
     268        /** @var \wpdb $wpdb */
     269        global $wpdb;
     270        $sql        = ( 'count' === $select_or_count ) ? 'SELECT count(a.action_id)' : 'SELECT a.action_id';
     271        $sql       .= " FROM {$wpdb->actionscheduler_actions} a";
     272        $sql_params = array();
     273
     274        if ( ! empty( $query['group'] ) || 'group' === $query['orderby'] ) {
    269275            $sql .= " LEFT JOIN {$wpdb->actionscheduler_groups} g ON g.group_id=a.group_id";
    270276        }
    271277
    272         $sql .= " WHERE 1=1";
    273 
    274         if ( ! empty( $query[ 'group' ] ) ) {
    275             $sql          .= " AND g.slug=%s";
    276             $sql_params[] = $query[ 'group' ];
    277         }
    278 
    279         if ( $query[ 'hook' ] ) {
    280             $sql          .= " AND a.hook=%s";
    281             $sql_params[] = $query[ 'hook' ];
    282         }
    283         if ( ! is_null( $query[ 'args' ] ) ) {
    284             $sql          .= " AND a.args=%s";
    285             $sql_params[] = $this->get_args_for_query( $query[ 'args' ] );
     278        $sql .= ' WHERE 1=1';
     279
     280        if ( ! empty( $query['group'] ) ) {
     281            $sql         .= ' AND g.slug=%s';
     282            $sql_params[] = $query['group'];
     283        }
     284
     285        if ( $query['hook'] ) {
     286            $sql         .= ' AND a.hook=%s';
     287            $sql_params[] = $query['hook'];
     288        }
     289        if ( ! is_null( $query['args'] ) ) {
     290            $sql         .= ' AND a.args=%s';
     291            $sql_params[] = $this->get_args_for_query( $query['args'] );
    286292        }
    287293
     
    293299        }
    294300
    295         if ( $query[ 'date' ] instanceof \DateTime ) {
    296             $date = clone $query[ 'date' ];
     301        if ( $query['date'] instanceof \DateTime ) {
     302            $date = clone $query['date'];
    297303            $date->setTimezone( new \DateTimeZone( 'UTC' ) );
    298304            $date_string  = $date->format( 'Y-m-d H:i:s' );
    299             $comparator   = $this->validate_sql_comparator( $query[ 'date_compare' ] );
    300             $sql          .= " AND a.scheduled_date_gmt $comparator %s";
     305            $comparator   = $this->validate_sql_comparator( $query['date_compare'] );
     306            $sql         .= " AND a.scheduled_date_gmt $comparator %s";
    301307            $sql_params[] = $date_string;
    302308        }
    303309
    304         if ( $query[ 'modified' ] instanceof \DateTime ) {
    305             $modified = clone $query[ 'modified' ];
     310        if ( $query['modified'] instanceof \DateTime ) {
     311            $modified = clone $query['modified'];
    306312            $modified->setTimezone( new \DateTimeZone( 'UTC' ) );
    307313            $date_string  = $modified->format( 'Y-m-d H:i:s' );
    308             $comparator   = $this->validate_sql_comparator( $query[ 'modified_compare' ] );
    309             $sql          .= " AND a.last_attempt_gmt $comparator %s";
     314            $comparator   = $this->validate_sql_comparator( $query['modified_compare'] );
     315            $sql         .= " AND a.last_attempt_gmt $comparator %s";
    310316            $sql_params[] = $date_string;
    311317        }
    312318
    313         if ( $query[ 'claimed' ] === true ) {
    314             $sql .= " AND a.claim_id != 0";
    315         } elseif ( $query[ 'claimed' ] === false ) {
    316             $sql .= " AND a.claim_id = 0";
    317         } elseif ( ! is_null( $query[ 'claimed' ] ) ) {
    318             $sql          .= " AND a.claim_id = %d";
    319             $sql_params[] = $query[ 'claimed' ];
     319        if ( true === $query['claimed'] ) {
     320            $sql .= ' AND a.claim_id != 0';
     321        } elseif ( false === $query['claimed'] ) {
     322            $sql .= ' AND a.claim_id = 0';
     323        } elseif ( ! is_null( $query['claimed'] ) ) {
     324            $sql         .= ' AND a.claim_id = %d';
     325            $sql_params[] = $query['claimed'];
    320326        }
    321327
    322328        if ( ! empty( $query['search'] ) ) {
    323             $sql .= " AND (a.hook LIKE %s OR (a.extended_args IS NULL AND a.args LIKE %s) OR a.extended_args LIKE %s";
    324             for( $i = 0; $i < 3; $i++ ) {
     329            $sql .= ' AND (a.hook LIKE %s OR (a.extended_args IS NULL AND a.args LIKE %s) OR a.extended_args LIKE %s';
     330            for ( $i = 0; $i < 3; $i++ ) {
    325331                $sql_params[] = sprintf( '%%%s%%', $query['search'] );
    326332            }
     
    328334            $search_claim_id = (int) $query['search'];
    329335            if ( $search_claim_id ) {
    330                 $sql .= ' OR a.claim_id = %d';
     336                $sql         .= ' OR a.claim_id = %d';
    331337                $sql_params[] = $search_claim_id;
    332338            }
     
    362368            }
    363369
    364             if ( $query[ 'per_page' ] > 0 ) {
    365                 $sql          .= " LIMIT %d, %d";
    366                 $sql_params[] = $query[ 'offset' ];
    367                 $sql_params[] = $query[ 'per_page' ];
     370            if ( $query['per_page'] > 0 ) {
     371                $sql         .= ' LIMIT %d, %d';
     372                $sql_params[] = $query['offset'];
     373                $sql_params[] = $query['per_page'];
    368374            }
    369375        }
    370376
    371377        if ( ! empty( $sql_params ) ) {
    372             $sql = $wpdb->prepare( $sql, $sql_params );
     378            $sql = $wpdb->prepare( $sql, $sql_params ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
    373379        }
    374380
     
    388394     * @return string|array|null The IDs of actions matching the query. Null on failure.
    389395     */
    390     public function query_actions( $query = [], $query_type = 'select' ) {
     396    public function query_actions( $query = array(), $query_type = 'select' ) {
    391397        /** @var wpdb $wpdb */
    392398        global $wpdb;
     
    394400        $sql = $this->get_query_actions_sql( $query, $query_type );
    395401
    396         return ( 'count' === $query_type ) ? $wpdb->get_var( $sql ) : $wpdb->get_col( $sql );
     402        return ( 'count' === $query_type ) ? $wpdb->get_var( $sql ) : $wpdb->get_col( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.NoSql, WordPress.DB.DirectDatabaseQuery.NoCaching
    397403    }
    398404
     
    407413        $sql  = "SELECT a.status, count(a.status) as 'count'";
    408414        $sql .= " FROM {$wpdb->actionscheduler_actions} a";
    409         $sql .= " GROUP BY a.status";
     415        $sql .= ' GROUP BY a.status';
    410416
    411417        $actions_count_by_status = array();
    412418        $action_stati_and_labels = $this->get_status_labels();
    413419
    414         foreach ( $wpdb->get_results( $sql ) as $action_data ) {
    415             // Ignore any actions with invalid status
     420        foreach ( $wpdb->get_results( $sql ) as $action_data ) { // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
     421            // Ignore any actions with invalid status.
    416422            if ( array_key_exists( $action_data->status, $action_stati_and_labels ) ) {
    417423                $actions_count_by_status[ $action_data->status ] = $action_data->count;
     
    428434     *
    429435     * @return void
     436     * @throws \InvalidArgumentException If the action update failed.
    430437     */
    431438    public function cancel_action( $action_id ) {
     
    435442        $updated = $wpdb->update(
    436443            $wpdb->actionscheduler_actions,
    437             [ 'status' => self::STATUS_CANCELED ],
    438             [ 'action_id' => $action_id ],
    439             [ '%s' ],
    440             [ '%d' ]
     444            array( 'status' => self::STATUS_CANCELED ),
     445            array( 'action_id' => $action_id ),
     446            array( '%s' ),
     447            array( '%d' )
    441448        );
    442449        if ( empty( $updated ) ) {
     
    457464     */
    458465    public function cancel_actions_by_hook( $hook ) {
    459         $this->bulk_cancel_actions( [ 'hook' => $hook ] );
     466        $this->bulk_cancel_actions( array( 'hook' => $hook ) );
    460467    }
    461468
     
    468475     */
    469476    public function cancel_actions_by_group( $group ) {
    470         $this->bulk_cancel_actions( [ 'group' => $group ] );
     477        $this->bulk_cancel_actions( array( 'group' => $group ) );
    471478    }
    472479
     
    487494
    488495        // Don't cancel actions that are already canceled.
    489         if ( isset( $query_args['status'] ) && $query_args['status'] == self::STATUS_CANCELED ) {
     496        if ( isset( $query_args['status'] ) && self::STATUS_CANCELED === $query_args['status'] ) {
    490497            return;
    491498        }
     
    494501        $query_args = wp_parse_args(
    495502            $query_args,
    496             [
     503            array(
    497504                'per_page' => 1000,
    498505                'status'   => self::STATUS_PENDING,
    499506                'orderby'  => 'action_id',
    500             ]
     507            )
    501508        );
    502509
     
    513520
    514521            $wpdb->query(
    515                 $wpdb->prepare( // wpcs: PreparedSQLPlaceholders replacement count ok.
    516                     "UPDATE {$wpdb->actionscheduler_actions} SET status = %s WHERE action_id IN {$query_in}",
     522                $wpdb->prepare(
     523                    "UPDATE {$wpdb->actionscheduler_actions} SET status = %s WHERE action_id IN {$query_in}", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
    517524                    $parameters
    518525                )
     
    527534     *
    528535     * @param int $action_id Action ID.
     536     * @throws \InvalidArgumentException If the action deletion failed.
    529537     */
    530538    public function delete_action( $action_id ) {
    531539        /** @var \wpdb $wpdb */
    532540        global $wpdb;
    533         $deleted = $wpdb->delete( $wpdb->actionscheduler_actions, [ 'action_id' => $action_id ], [ '%d' ] );
     541        $deleted = $wpdb->delete( $wpdb->actionscheduler_actions, array( 'action_id' => $action_id ), array( '%d' ) );
    534542        if ( empty( $deleted ) ) {
    535             throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
     543            throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
    536544        }
    537545        do_action( 'action_scheduler_deleted_action', $action_id );
     
    543551     * @param string $action_id Action ID.
    544552     *
    545      * @throws \InvalidArgumentException
    546553     * @return \DateTime The local date the action is scheduled to run, or the date that it ran.
    547554     */
     
    557564     * @param int $action_id Action ID.
    558565     *
    559      * @throws \InvalidArgumentException
     566     * @throws \InvalidArgumentException If action cannot be identified.
    560567     * @return \DateTime The GMT date the action is scheduled to run, or the date that it ran.
    561568     */
     
    565572        $record = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d", $action_id ) );
    566573        if ( empty( $record ) ) {
    567             throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
    568         }
    569         if ( $record->status == self::STATUS_PENDING ) {
     574            throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
     575        }
     576        if ( self::STATUS_PENDING === $record->status ) {
    570577            return as_get_datetime_object( $record->scheduled_date_gmt );
    571578        } else {
     
    579586     * @param int       $max_actions Maximum number of action to include in claim.
    580587     * @param \DateTime $before_date Jobs must be schedule before this date. Defaults to now.
     588     * @param array     $hooks Hooks to filter for.
     589     * @param string    $group Group to filter for.
    581590     *
    582591     * @return ActionScheduler_ActionClaim
     
    587596        $this->claim_before_date = $before_date;
    588597        $this->claim_actions( $claim_id, $max_actions, $before_date, $hooks, $group );
    589         $action_ids = $this->find_actions_by_claim_id( $claim_id );
     598        $action_ids              = $this->find_actions_by_claim_id( $claim_id );
    590599        $this->claim_before_date = null;
    591600
     
    602611        global $wpdb;
    603612        $now = as_get_datetime_object();
    604         $wpdb->insert( $wpdb->actionscheduler_claims, [ 'date_created_gmt' => $now->format( 'Y-m-d H:i:s' ) ] );
     613        $wpdb->insert( $wpdb->actionscheduler_claims, array( 'date_created_gmt' => $now->format( 'Y-m-d H:i:s' ) ) );
    605614
    606615        return $wpdb->insert_id;
     
    613622     * @param int       $limit Number of action to include in claim.
    614623     * @param \DateTime $before_date Should use UTC timezone.
     624     * @param array     $hooks Hooks to filter for.
     625     * @param string    $group Group to filter for.
    615626     *
    616627     * @return int The number of actions that were claimed.
    617      * @throws \RuntimeException
     628     * @throws \InvalidArgumentException Throws InvalidArgumentException if group doesn't exist.
     629     * @throws \RuntimeException Throws RuntimeException if unable to claim action.
    618630     */
    619631    protected function claim_actions( $claim_id, $limit, \DateTime $before_date = null, $hooks = array(), $group = '' ) {
     
    624636        $date = is_null( $before_date ) ? $now : clone $before_date;
    625637
    626         // can't use $wpdb->update() because of the <= condition
     638        // can't use $wpdb->update() because of the <= condition.
    627639        $update = "UPDATE {$wpdb->actionscheduler_actions} SET claim_id=%d, last_attempt_gmt=%s, last_attempt_local=%s";
    628640        $params = array(
     
    632644        );
    633645
    634         $where    = "WHERE claim_id = 0 AND scheduled_date_gmt <= %s AND status=%s";
     646        $where    = 'WHERE claim_id = 0 AND scheduled_date_gmt <= %s AND status=%s';
    635647        $params[] = $date->format( 'Y-m-d H:i:s' );
    636648        $params[] = self::STATUS_PENDING;
     
    646658            $group_id = $this->get_group_id( $group, false );
    647659
    648             // throw exception if no matching group found, this matches ActionScheduler_wpPostStore's behaviour
     660            // throw exception if no matching group found, this matches ActionScheduler_wpPostStore's behaviour.
    649661            if ( empty( $group_id ) ) {
    650662                /* translators: %s: group name */
     
    656668        }
    657669
    658         $order    = "ORDER BY attempts ASC, scheduled_date_gmt ASC, action_id ASC LIMIT %d";
     670        /**
     671         * Sets the order-by clause used in the action claim query.
     672         *
     673         * @since x.x.x
     674         *
     675         * @param string $order_by_sql
     676         */
     677        $order    = apply_filters( 'action_scheduler_claim_actions_order_by', 'ORDER BY attempts ASC, scheduled_date_gmt ASC, action_id ASC' );
    659678        $params[] = $limit;
    660679
    661         $sql = $wpdb->prepare( "{$update} {$where} {$order}", $params );
    662 
    663         $rows_affected = $wpdb->query( $sql );
    664         if ( $rows_affected === false ) {
     680        $sql           = $wpdb->prepare( "{$update} {$where} {$order} LIMIT %d", $params ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders
     681        $rows_affected = $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
     682        if ( false === $rows_affected ) {
    665683            throw new \RuntimeException( __( 'Unable to claim actions. Database error.', 'action-scheduler' ) );
    666684        }
     
    678696
    679697        $sql = "SELECT COUNT(DISTINCT claim_id) FROM {$wpdb->actionscheduler_actions} WHERE claim_id != 0 AND status IN ( %s, %s)";
    680         $sql = $wpdb->prepare( $sql, [ self::STATUS_PENDING, self::STATUS_RUNNING ] );
    681 
    682         return (int) $wpdb->get_var( $sql );
     698        $sql = $wpdb->prepare( $sql, array( self::STATUS_PENDING, self::STATUS_RUNNING ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
     699
     700        return (int) $wpdb->get_var( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
    683701    }
    684702
     
    694712
    695713        $sql = "SELECT claim_id FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d";
    696         $sql = $wpdb->prepare( $sql, $action_id );
    697 
    698         return (int) $wpdb->get_var( $sql );
     714        $sql = $wpdb->prepare( $sql, $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
     715
     716        return (int) $wpdb->get_var( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
    699717    }
    700718
     
    702720     * Retrieve the action IDs of action in a claim.
    703721     *
     722     * @param  int $claim_id Claim ID.
    704723     * @return int[]
    705724     */
     
    719738        // Verify that the scheduled date for each action is within the expected bounds (in some unusual
    720739        // cases, we cannot depend on MySQL to honor all of the WHERE conditions we specify).
    721         foreach ( $wpdb->get_results( $sql ) as $claimed_action ) {
     740        foreach ( $wpdb->get_results( $sql ) as $claimed_action ) { // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
    722741            if ( $claimed_action->scheduled_date_gmt <= $cut_off ) {
    723742                $action_ids[] = absint( $claimed_action->action_id );
     
    736755        /** @var \wpdb $wpdb */
    737756        global $wpdb;
    738         $wpdb->update( $wpdb->actionscheduler_actions, [ 'claim_id' => 0 ], [ 'claim_id' => $claim->get_id() ], [ '%d' ], [ '%d' ] );
    739         $wpdb->delete( $wpdb->actionscheduler_claims, [ 'claim_id' => $claim->get_id() ], [ '%d' ] );
     757        $wpdb->update( $wpdb->actionscheduler_actions, array( 'claim_id' => 0 ), array( 'claim_id' => $claim->get_id() ), array( '%d' ), array( '%d' ) );
     758        $wpdb->delete( $wpdb->actionscheduler_claims, array( 'claim_id' => $claim->get_id() ), array( '%d' ) );
    740759    }
    741760
     
    752771        $wpdb->update(
    753772            $wpdb->actionscheduler_actions,
    754             [ 'claim_id' => 0 ],
    755             [ 'action_id' => $action_id ],
    756             [ '%s' ],
    757             [ '%d' ]
     773            array( 'claim_id' => 0 ),
     774            array( 'action_id' => $action_id ),
     775            array( '%s' ),
     776            array( '%d' )
    758777        );
    759778    }
     
    763782     *
    764783     * @param int $action_id Action ID.
     784     * @throws \InvalidArgumentException Throw an exception if action was not updated.
    765785     */
    766786    public function mark_failure( $action_id ) {
     
    769789        $updated = $wpdb->update(
    770790            $wpdb->actionscheduler_actions,
    771             [ 'status' => self::STATUS_FAILED ],
    772             [ 'action_id' => $action_id ],
    773             [ '%s' ],
    774             [ '%d' ]
     791            array( 'status' => self::STATUS_FAILED ),
     792            array( 'action_id' => $action_id ),
     793            array( '%s' ),
     794            array( '%d' )
    775795        );
    776796        if ( empty( $updated ) ) {
    777             throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
     797            throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
    778798        }
    779799    }
     
    791811
    792812        $sql = "UPDATE {$wpdb->actionscheduler_actions} SET attempts = attempts+1, status=%s, last_attempt_gmt = %s, last_attempt_local = %s WHERE action_id = %d";
    793         $sql = $wpdb->prepare( $sql, self::STATUS_RUNNING, current_time( 'mysql', true ), current_time( 'mysql' ), $action_id );
    794         $wpdb->query( $sql );
     813        $sql = $wpdb->prepare( $sql, self::STATUS_RUNNING, current_time( 'mysql', true ), current_time( 'mysql' ), $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
     814        $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
    795815    }
    796816
     
    801821     *
    802822     * @return void
     823     * @throws \InvalidArgumentException Throw an exception if action was not updated.
    803824     */
    804825    public function mark_complete( $action_id ) {
     
    807828        $updated = $wpdb->update(
    808829            $wpdb->actionscheduler_actions,
    809             [
     830            array(
    810831                'status'             => self::STATUS_COMPLETE,
    811832                'last_attempt_gmt'   => current_time( 'mysql', true ),
    812833                'last_attempt_local' => current_time( 'mysql' ),
    813             ],
    814             [ 'action_id' => $action_id ],
    815             [ '%s' ],
    816             [ '%d' ]
     834            ),
     835            array( 'action_id' => $action_id ),
     836            array( '%s' ),
     837            array( '%d' )
    817838        );
    818839        if ( empty( $updated ) ) {
    819             throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
     840            throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
    820841        }
    821842    }
     
    827848     *
    828849     * @return string
     850     * @throws \InvalidArgumentException Throw an exception if not status was found for action_id.
     851     * @throws \RuntimeException Throw an exception if action status could not be retrieved.
    829852     */
    830853    public function get_status( $action_id ) {
     
    832855        global $wpdb;
    833856        $sql    = "SELECT status FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d";
    834         $sql    = $wpdb->prepare( $sql, $action_id );
    835         $status = $wpdb->get_var( $sql );
    836 
    837         if ( $status === null ) {
     857        $sql    = $wpdb->prepare( $sql, $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
     858        $status = $wpdb->get_var( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
     859
     860        if ( null === $status ) {
    838861            throw new \InvalidArgumentException( __( 'Invalid action ID. No status found.', 'action-scheduler' ) );
    839862        } elseif ( empty( $status ) ) {
  • action-scheduler/tags/3.4.0/classes/data-stores/ActionScheduler_wpPostStore.php

    r2599552 r2622865  
    55 */
    66class ActionScheduler_wpPostStore extends ActionScheduler_Store {
    7     const POST_TYPE = 'scheduled-action';
    8     const GROUP_TAXONOMY = 'action-group';
     7    const POST_TYPE         = 'scheduled-action';
     8    const GROUP_TAXONOMY    = 'action-group';
    99    const SCHEDULE_META_KEY = '_action_manager_schedule';
    10     const DEPENDENCIES_MET = 'as-post-store-dependencies-met';
     10    const DEPENDENCIES_MET  = 'as-post-store-dependencies-met';
    1111
    1212    /**
     
    2020    private $claim_before_date = null;
    2121
    22     /** @var DateTimeZone */
    23     protected $local_timezone = NULL;
    24 
    25     public function save_action( ActionScheduler_Action $action, DateTime $scheduled_date = NULL ){
     22    /**
     23     * Local Timezone.
     24     *
     25     * @var DateTimeZone
     26     */
     27    protected $local_timezone = null;
     28
     29    /**
     30     * Save action.
     31     *
     32     * @param ActionScheduler_Action $action Scheduled Action.
     33     * @param DateTime               $scheduled_date Scheduled Date.
     34     *
     35     * @throws RuntimeException Throws an exception if the action could not be saved.
     36     * @return int
     37     */
     38    public function save_action( ActionScheduler_Action $action, DateTime $scheduled_date = null ) {
    2639        try {
    2740            $this->validate_action( $action );
    2841            $post_array = $this->create_post_array( $action, $scheduled_date );
    29             $post_id = $this->save_post_array( $post_array );
     42            $post_id    = $this->save_post_array( $post_array );
    3043            $this->save_post_schedule( $post_id, $action->get_schedule() );
    3144            $this->save_action_group( $post_id, $action->get_group() );
     
    3346            return $post_id;
    3447        } catch ( Exception $e ) {
     48            /* translators: %s: action error message */
    3549            throw new RuntimeException( sprintf( __( 'Error saving action: %s', 'action-scheduler' ), $e->getMessage() ), 0 );
    3650        }
    3751    }
    3852
    39     protected function create_post_array( ActionScheduler_Action $action, DateTime $scheduled_date = NULL ) {
     53    /**
     54     * Create post array.
     55     *
     56     * @param ActionScheduler_Action $action Scheduled Action.
     57     * @param DateTime               $scheduled_date Scheduled Date.
     58     *
     59     * @return array Returns an array of post data.
     60     */
     61    protected function create_post_array( ActionScheduler_Action $action, DateTime $scheduled_date = null ) {
    4062        $post = array(
    41             'post_type' => self::POST_TYPE,
    42             'post_title' => $action->get_hook(),
    43             'post_content' => json_encode($action->get_args()),
    44             'post_status' => ( $action->is_finished() ? 'publish' : 'pending' ),
     63            'post_type'     => self::POST_TYPE,
     64            'post_title'    => $action->get_hook(),
     65            'post_content'  => wp_json_encode( $action->get_args() ),
     66            'post_status'   => ( $action->is_finished() ? 'publish' : 'pending' ),
    4567            'post_date_gmt' => $this->get_scheduled_date_string( $action, $scheduled_date ),
    4668            'post_date'     => $this->get_scheduled_date_string_local( $action, $scheduled_date ),
     
    4971    }
    5072
     73    /**
     74     * Save post array.
     75     *
     76     * @param array $post_array Post array.
     77     * @return int Returns the post ID.
     78     * @throws RuntimeException Throws an exception if the action could not be saved.
     79     */
    5180    protected function save_post_array( $post_array ) {
    5281        add_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10, 1 );
     
    6089        }
    6190
    62         $post_id = wp_insert_post($post_array);
     91        $post_id = wp_insert_post( $post_array );
    6392
    6493        if ( $has_kses ) {
     
    6998        remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 );
    7099
    71         if ( is_wp_error($post_id) || empty($post_id) ) {
     100        if ( is_wp_error( $post_id ) || empty( $post_id ) ) {
    72101            throw new RuntimeException( __( 'Unable to save action.', 'action-scheduler' ) );
    73102        }
     
    75104    }
    76105
     106    /**
     107     * Filter insert post data.
     108     *
     109     * @param array $postdata Post data to filter.
     110     *
     111     * @return array
     112     */
    77113    public function filter_insert_post_data( $postdata ) {
    78         if ( $postdata['post_type'] == self::POST_TYPE ) {
     114        if ( self::POST_TYPE === $postdata['post_type'] ) {
    79115            $postdata['post_author'] = 0;
    80             if ( $postdata['post_status'] == 'future' ) {
     116            if ( 'future' === $postdata['post_status'] ) {
    81117                $postdata['post_status'] = 'publish';
    82118            }
     
    114150     */
    115151    public function set_unique_post_slug( $override_slug, $slug, $post_ID, $post_status, $post_type ) {
    116         if ( self::POST_TYPE == $post_type ) {
     152        if ( self::POST_TYPE === $post_type ) {
    117153            $override_slug = uniqid( self::POST_TYPE . '-', true ) . '-' . wp_generate_password( 32, false );
    118154        }
     
    120156    }
    121157
     158    /**
     159     * Save post schedule.
     160     *
     161     * @param int    $post_id  Post ID of the scheduled action.
     162     * @param string $schedule Schedule to save.
     163     *
     164     * @return void
     165     */
    122166    protected function save_post_schedule( $post_id, $schedule ) {
    123167        update_post_meta( $post_id, self::SCHEDULE_META_KEY, $schedule );
    124168    }
    125169
     170    /**
     171     * Save action group.
     172     *
     173     * @param int    $post_id Post ID.
     174     * @param string $group   Group to save.
     175     * @return void
     176     */
    126177    protected function save_action_group( $post_id, $group ) {
    127         if ( empty($group) ) {
    128             wp_set_object_terms( $post_id, array(), self::GROUP_TAXONOMY, FALSE );
     178        if ( empty( $group ) ) {
     179            wp_set_object_terms( $post_id, array(), self::GROUP_TAXONOMY, false );
    129180        } else {
    130             wp_set_object_terms( $post_id, array($group), self::GROUP_TAXONOMY, FALSE );
    131         }
    132     }
    133 
     181            wp_set_object_terms( $post_id, array( $group ), self::GROUP_TAXONOMY, false );
     182        }
     183    }
     184
     185    /**
     186     * Fetch actions.
     187     *
     188     * @param int $action_id Action ID.
     189     * @return object
     190     */
    134191    public function fetch_action( $action_id ) {
    135192        $post = $this->get_post( $action_id );
    136         if ( empty($post) || $post->post_type != self::POST_TYPE ) {
     193        if ( empty( $post ) || self::POST_TYPE !== $post->post_type ) {
    137194            return $this->get_null_action();
    138195        }
     
    148205    }
    149206
     207    /**
     208     * Get post.
     209     *
     210     * @param string $action_id - Action ID.
     211     * @return WP_Post|null
     212     */
    150213    protected function get_post( $action_id ) {
    151         if ( empty($action_id) ) {
    152             return NULL;
    153         }
    154         return get_post($action_id);
    155     }
    156 
     214        if ( empty( $action_id ) ) {
     215            return null;
     216        }
     217        return get_post( $action_id );
     218    }
     219
     220    /**
     221     * Get NULL action.
     222     *
     223     * @return ActionScheduler_NullAction
     224     */
    157225    protected function get_null_action() {
    158226        return new ActionScheduler_NullAction();
    159227    }
    160228
     229    /**
     230     * Make action from post.
     231     *
     232     * @param WP_Post $post Post object.
     233     * @return WP_Post
     234     */
    161235    protected function make_action_from_post( $post ) {
    162236        $hook = $post->post_title;
     
    168242        $this->validate_schedule( $schedule, $post->ID );
    169243
    170         $group = wp_get_object_terms( $post->ID, self::GROUP_TAXONOMY, array('fields' => 'names') );
    171         $group = empty( $group ) ? '' : reset($group);
     244        $group = wp_get_object_terms( $post->ID, self::GROUP_TAXONOMY, array( 'fields' => 'names' ) );
     245        $group = empty( $group ) ? '' : reset( $group );
    172246
    173247        return ActionScheduler::factory()->get_stored_action( $this->get_action_status_by_post_status( $post->post_status ), $hook, $args, $schedule, $group );
     
    175249
    176250    /**
    177      * @param string $post_status
    178      *
    179      * @throws InvalidArgumentException if $post_status not in known status fields returned by $this->get_status_labels()
     251     * Get action status by post status.
     252     *
     253     * @param string $post_status Post status.
     254     *
     255     * @throws InvalidArgumentException Throw InvalidArgumentException if $post_status not in known status fields returned by $this->get_status_labels().
    180256     * @return string
    181257     */
     
    183259
    184260        switch ( $post_status ) {
    185             case 'publish' :
     261            case 'publish':
    186262                $action_status = self::STATUS_COMPLETE;
    187263                break;
    188             case 'trash' :
     264            case 'trash':
    189265                $action_status = self::STATUS_CANCELED;
    190266                break;
    191             default :
     267            default:
    192268                if ( ! array_key_exists( $post_status, $this->get_status_labels() ) ) {
    193269                    throw new InvalidArgumentException( sprintf( 'Invalid post status: "%s". No matching action status available.', $post_status ) );
     
    201277
    202278    /**
    203      * @param string $action_status
    204      * @throws InvalidArgumentException if $post_status not in known status fields returned by $this->get_status_labels()
     279     * Get post status by action status.
     280     *
     281     * @param string $action_status Action status.
     282     *
     283     * @throws InvalidArgumentException Throws InvalidArgumentException if $post_status not in known status fields returned by $this->get_status_labels().
    205284     * @return string
    206285     */
     
    208287
    209288        switch ( $action_status ) {
    210             case self::STATUS_COMPLETE :
     289            case self::STATUS_COMPLETE:
    211290                $post_status = 'publish';
    212291                break;
    213             case self::STATUS_CANCELED :
     292            case self::STATUS_CANCELED:
    214293                $post_status = 'trash';
    215294                break;
    216             default :
     295            default:
    217296                if ( ! array_key_exists( $action_status, $this->get_status_labels() ) ) {
    218297                    throw new InvalidArgumentException( sprintf( 'Invalid action status: "%s".', $action_status ) );
     
    228307     * Returns the SQL statement to query (or count) actions.
    229308     *
    230      * @param array $query Filtering options
    231      * @param string $select_or_count  Whether the SQL should select and return the IDs or just the row count
    232      * @throws InvalidArgumentException if $select_or_count not count or select
     309     * @param array  $query            - Filtering options.
     310     * @param string $select_or_count  - Whether the SQL should select and return the IDs or just the row count.
     311     *
     312     * @throws InvalidArgumentException - Throw InvalidArgumentException if $select_or_count not count or select.
    233313     * @return string SQL statement. The returned SQL is already properly escaped.
    234314     */
    235315    protected function get_query_actions_sql( array $query, $select_or_count = 'select' ) {
    236316
    237         if ( ! in_array( $select_or_count, array( 'select', 'count' ) ) ) {
     317        if ( ! in_array( $select_or_count, array( 'select', 'count' ), true ) ) {
    238318            throw new InvalidArgumentException( __( 'Invalid schedule. Cannot save action.', 'action-scheduler' ) );
    239319        }
    240320
    241         $query = wp_parse_args( $query, array(
    242             'hook' => '',
    243             'args' => NULL,
    244             'date' => NULL,
    245             'date_compare' => '<=',
    246             'modified' => NULL,
    247             'modified_compare' => '<=',
    248             'group' => '',
    249             'status' => '',
    250             'claimed' => NULL,
    251             'per_page' => 5,
    252             'offset' => 0,
    253             'orderby' => 'date',
    254             'order' => 'ASC',
    255             'search' => '',
    256         ) );
    257 
    258         /** @var wpdb $wpdb */
     321        $query = wp_parse_args(
     322            $query,
     323            array(
     324                'hook'             => '',
     325                'args'             => null,
     326                'date'             => null,
     327                'date_compare'     => '<=',
     328                'modified'         => null,
     329                'modified_compare' => '<=',
     330                'group'            => '',
     331                'status'           => '',
     332                'claimed'          => null,
     333                'per_page'         => 5,
     334                'offset'           => 0,
     335                'orderby'          => 'date',
     336                'order'            => 'ASC',
     337                'search'           => '',
     338            )
     339        );
     340
     341        /**
     342         * Global wpdb object.
     343         *
     344         * @var wpdb $wpdb
     345         */
    259346        global $wpdb;
    260         $sql  = ( 'count' === $select_or_count ) ? 'SELECT count(p.ID)' : 'SELECT p.ID ';
    261         $sql .= "FROM {$wpdb->posts} p";
     347        $sql        = ( 'count' === $select_or_count ) ? 'SELECT count(p.ID)' : 'SELECT p.ID ';
     348        $sql       .= "FROM {$wpdb->posts} p";
    262349        $sql_params = array();
    263350        if ( empty( $query['group'] ) && 'group' === $query['orderby'] ) {
     
    266353            $sql .= " LEFT JOIN {$wpdb->terms} t ON tt.term_id=t.term_id";
    267354        } elseif ( ! empty( $query['group'] ) ) {
    268             $sql .= " INNER JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID";
    269             $sql .= " INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id";
    270             $sql .= " INNER JOIN {$wpdb->terms} t ON tt.term_id=t.term_id";
    271             $sql .= " AND t.slug=%s";
     355            $sql         .= " INNER JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID";
     356            $sql         .= " INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id";
     357            $sql         .= " INNER JOIN {$wpdb->terms} t ON tt.term_id=t.term_id";
     358            $sql         .= ' AND t.slug=%s';
    272359            $sql_params[] = $query['group'];
    273360        }
    274         $sql .= " WHERE post_type=%s";
     361        $sql         .= ' WHERE post_type=%s';
    275362        $sql_params[] = self::POST_TYPE;
    276363        if ( $query['hook'] ) {
    277             $sql .= " AND p.post_title=%s";
     364            $sql         .= ' AND p.post_title=%s';
    278365            $sql_params[] = $query['hook'];
    279366        }
    280         if ( !is_null($query['args']) ) {
    281             $sql .= " AND p.post_content=%s";
    282             $sql_params[] = json_encode($query['args']);
     367        if ( ! is_null( $query['args'] ) ) {
     368            $sql         .= ' AND p.post_content=%s';
     369            $sql_params[] = wp_json_encode( $query['args'] );
    283370        }
    284371
     
    292379        if ( $query['date'] instanceof DateTime ) {
    293380            $date = clone $query['date'];
    294             $date->setTimezone( new DateTimeZone('UTC') );
    295             $date_string = $date->format('Y-m-d H:i:s');
    296             $comparator = $this->validate_sql_comparator($query['date_compare']);
    297             $sql .= " AND p.post_date_gmt $comparator %s";
     381            $date->setTimezone( new DateTimeZone( 'UTC' ) );
     382            $date_string  = $date->format( 'Y-m-d H:i:s' );
     383            $comparator   = $this->validate_sql_comparator( $query['date_compare'] );
     384            $sql         .= " AND p.post_date_gmt $comparator %s";
    298385            $sql_params[] = $date_string;
    299386        }
     
    301388        if ( $query['modified'] instanceof DateTime ) {
    302389            $modified = clone $query['modified'];
    303             $modified->setTimezone( new DateTimeZone('UTC') );
    304             $date_string = $modified->format('Y-m-d H:i:s');
    305             $comparator = $this->validate_sql_comparator($query['modified_compare']);
    306             $sql .= " AND p.post_modified_gmt $comparator %s";
     390            $modified->setTimezone( new DateTimeZone( 'UTC' ) );
     391            $date_string  = $modified->format( 'Y-m-d H:i:s' );
     392            $comparator   = $this->validate_sql_comparator( $query['modified_compare'] );
     393            $sql         .= " AND p.post_modified_gmt $comparator %s";
    307394            $sql_params[] = $date_string;
    308395        }
    309396
    310         if ( $query['claimed'] === TRUE ) {
     397        if ( true === $query['claimed'] ) {
    311398            $sql .= " AND p.post_password != ''";
    312         } elseif ( $query['claimed'] === FALSE ) {
     399        } elseif ( false === $query['claimed'] ) {
    313400            $sql .= " AND p.post_password = ''";
    314         } elseif ( !is_null($query['claimed']) ) {
    315             $sql .= " AND p.post_password = %s";
     401        } elseif ( ! is_null( $query['claimed'] ) ) {
     402            $sql         .= ' AND p.post_password = %s';
    316403            $sql_params[] = $query['claimed'];
    317404        }
    318405
    319406        if ( ! empty( $query['search'] ) ) {
    320             $sql .= " AND (p.post_title LIKE %s OR p.post_content LIKE %s OR p.post_password LIKE %s)";
    321             for( $i = 0; $i < 3; $i++ ) {
     407            $sql .= ' AND (p.post_title LIKE %s OR p.post_content LIKE %s OR p.post_password LIKE %s)';
     408            for ( $i = 0; $i < 3; $i++ ) {
    322409                $sql_params[] = sprintf( '%%%s%%', $query['search'] );
    323410            }
     
    354441            $sql .= " ORDER BY $orderby $order";
    355442            if ( $query['per_page'] > 0 ) {
    356                 $sql .= " LIMIT %d, %d";
     443                $sql         .= ' LIMIT %d, %d';
    357444                $sql_params[] = $query['offset'];
    358445                $sql_params[] = $query['per_page'];
     
    360447        }
    361448
    362         return $wpdb->prepare( $sql, $sql_params );
     449        return $wpdb->prepare( $sql, $sql_params ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
    363450    }
    364451
     
    376463     */
    377464    public function query_actions( $query = array(), $query_type = 'select' ) {
    378         /** @var wpdb $wpdb */
     465        /**
     466         * Global $wpdb object.
     467         *
     468         * @var wpdb $wpdb
     469         */
    379470        global $wpdb;
    380471
    381472        $sql = $this->get_query_actions_sql( $query, $query_type );
    382473
    383         return ( 'count' === $query_type ) ? $wpdb->get_var( $sql ) : $wpdb->get_col( $sql );
     474        return ( 'count' === $query_type ) ? $wpdb->get_var( $sql ) : $wpdb->get_col( $sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared
    384475    }
    385476
     
    400491                $action_status_name = $this->get_action_status_by_post_status( $post_status_name );
    401492            } catch ( Exception $e ) {
    402                 // Ignore any post statuses that aren't for actions
     493                // Ignore any post statuses that aren't for actions.
    403494                continue;
    404495            }
     
    412503
    413504    /**
    414      * @param string $action_id
    415      *
    416      * @throws InvalidArgumentException
     505     * Cancel action.
     506     *
     507     * @param int $action_id Action ID.
     508     *
     509     * @throws InvalidArgumentException If $action_id is not identified.
    417510     */
    418511    public function cancel_action( $action_id ) {
    419512        $post = get_post( $action_id );
    420         if ( empty( $post ) || ( $post->post_type != self::POST_TYPE ) ) {
     513        if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) {
     514            /* translators: %s is the action ID */
    421515            throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
    422516        }
     
    427521    }
    428522
     523    /**
     524     * Delete action.
     525     *
     526     * @param int $action_id Action ID.
     527     * @return void
     528     * @throws InvalidArgumentException If action is not identified.
     529     */
    429530    public function delete_action( $action_id ) {
    430531        $post = get_post( $action_id );
    431         if ( empty( $post ) || ( $post->post_type != self::POST_TYPE ) ) {
     532        if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) {
     533            /* translators: %s is the action ID */
    432534            throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
    433535        }
    434536        do_action( 'action_scheduler_deleted_action', $action_id );
    435537
    436         wp_delete_post( $action_id, TRUE );
    437     }
    438 
    439     /**
    440      * @param string $action_id
    441      *
    442      * @throws InvalidArgumentException
     538        wp_delete_post( $action_id, true );
     539    }
     540
     541    /**
     542     * Get date for claim id.
     543     *
     544     * @param int $action_id Action ID.
    443545     * @return ActionScheduler_DateTime The date the action is schedule to run, or the date that it ran.
    444546     */
     
    449551
    450552    /**
    451      * @param string $action_id
    452      *
    453      * @throws InvalidArgumentException
     553     * Get Date GMT.
     554     *
     555     * @param int $action_id Action ID.
     556     *
     557     * @throws InvalidArgumentException If $action_id is not identified.
    454558     * @return ActionScheduler_DateTime The date the action is schedule to run, or the date that it ran.
    455559     */
    456560    public function get_date_gmt( $action_id ) {
    457561        $post = get_post( $action_id );
    458         if ( empty( $post ) || ( $post->post_type != self::POST_TYPE ) ) {
     562        if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) {
     563            /* translators: %s is the action ID */
    459564            throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
    460565        }
    461         if ( $post->post_status == 'publish' ) {
     566        if ( 'publish' === $post->post_status ) {
    462567            return as_get_datetime_object( $post->post_modified_gmt );
    463568        } else {
     
    467572
    468573    /**
    469      * @param int      $max_actions
     574     * Stake claim.
     575     *
     576     * @param int      $max_actions Maximum number of actions.
    470577     * @param DateTime $before_date Jobs must be schedule before this date. Defaults to now.
    471578     * @param array    $hooks       Claim only actions with a hook or hooks.
     
    478585    public function stake_claim( $max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '' ) {
    479586        $this->claim_before_date = $before_date;
    480         $claim_id = $this->generate_claim_id();
     587        $claim_id                = $this->generate_claim_id();
    481588        $this->claim_actions( $claim_id, $max_actions, $before_date, $hooks, $group );
    482         $action_ids = $this->find_actions_by_claim_id( $claim_id );
     589        $action_ids              = $this->find_actions_by_claim_id( $claim_id );
    483590        $this->claim_before_date = null;
    484591
     
    487594
    488595    /**
     596     * Get claim count.
     597     *
    489598     * @return int
    490599     */
    491     public function get_claim_count(){
     600    public function get_claim_count() {
    492601        global $wpdb;
    493602
    494         $sql = "SELECT COUNT(DISTINCT post_password) FROM {$wpdb->posts} WHERE post_password != '' AND post_type = %s AND post_status IN ('in-progress','pending')";
    495         $sql = $wpdb->prepare( $sql, array( self::POST_TYPE ) );
    496 
    497         return $wpdb->get_var( $sql );
    498     }
    499 
     603        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
     604        return $wpdb->get_var(
     605            $wpdb->prepare(
     606                "SELECT COUNT(DISTINCT post_password) FROM {$wpdb->posts} WHERE post_password != '' AND post_type = %s AND post_status IN ('in-progress','pending')",
     607                array( self::POST_TYPE )
     608            )
     609        );
     610    }
     611
     612    /**
     613     * Generate claim id.
     614     *
     615     * @return string
     616     */
    500617    protected function generate_claim_id() {
    501         $claim_id = md5(microtime(true) . rand(0,1000));
    502         return substr($claim_id, 0, 20); // to fit in db field with 20 char limit
    503     }
    504 
    505     /**
    506      * @param string   $claim_id
    507      * @param int      $limit
     618        $claim_id = md5( microtime( true ) . wp_rand( 0, 1000 ) );
     619        return substr( $claim_id, 0, 20 ); // to fit in db field with 20 char limit.
     620    }
     621
     622    /**
     623     * Claim actions.
     624     *
     625     * @param string   $claim_id    Claim ID.
     626     * @param int      $limit       Limit.
    508627     * @param DateTime $before_date Should use UTC timezone.
    509628     * @param array    $hooks       Claim only actions with a hook or hooks.
    510629     * @param string   $group       Claim only actions in the given group.
    511630     *
    512      * @return int The number of actions that were claimed
    513      * @throws RuntimeException When there is a database error.
    514      * @throws InvalidArgumentException When the group is invalid.
     631     * @return int The number of actions that were claimed.
     632     * @throws RuntimeException  When there is a database error.
    515633     */
    516634    protected function claim_actions( $claim_id, $limit, DateTime $before_date = null, $hooks = array(), $group = '' ) {
     
    525643        }
    526644
    527         /** @var wpdb $wpdb */
     645        /**
     646         * Global wpdb object.
     647         *
     648         * @var wpdb $wpdb
     649         */
    528650        global $wpdb;
    529651
     
    560682            $where .= ' AND ID IN (' . join( ',', $ids ) . ')';
    561683        } else {
    562             $where .= ' AND post_date_gmt <= %s';
     684            $where   .= ' AND post_date_gmt <= %s';
    563685            $params[] = $date->format( 'Y-m-d H:i:s' );
    564686        }
     
    569691
    570692        // Run the query and gather results.
    571         $rows_affected = $wpdb->query( $wpdb->prepare( "{$update} {$where} {$order}", $params ) );
    572         if ( $rows_affected === false ) {
     693        $rows_affected = $wpdb->query( $wpdb->prepare( "{$update} {$where} {$order}", $params ) ); // phpcs:ignore // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
     694
     695        if ( false === $rows_affected ) {
    573696            throw new RuntimeException( __( 'Unable to claim actions. Database error.', 'action-scheduler' ) );
    574697        }
     
    590713    protected function get_actions_by_group( $group, $limit, DateTime $date ) {
    591714        // Ensure the group exists before continuing.
    592         if ( ! term_exists( $group, self::GROUP_TAXONOMY )) {
     715        if ( ! term_exists( $group, self::GROUP_TAXONOMY ) ) {
     716            /* translators: %s is the group name */
    593717            throw new InvalidArgumentException( sprintf( __( 'The group "%s" does not exist.', 'action-scheduler' ), $group ) );
    594718        }
     
    610734            ),
    611735            'date_query'       => array(
    612                 'column' => 'post_date_gmt',
    613                 'before' => $date->format( 'Y-m-d H:i' ),
     736                'column'    => 'post_date_gmt',
     737                'before'    => $date->format( 'Y-m-d H:i' ),
    614738                'inclusive' => true,
    615739            ),
    616             'tax_query' => array(
     740            'tax_query'        => array( // phpcs:ignore WordPress.DB.SlowDBQuery
    617741                array(
    618742                    'taxonomy'         => self::GROUP_TAXONOMY,
     
    628752
    629753    /**
    630      * @param string $claim_id
     754     * Find actions by claim ID.
     755     *
     756     * @param string $claim_id Claim ID.
    631757     * @return array
    632758     */
    633759    public function find_actions_by_claim_id( $claim_id ) {
    634         /** @var wpdb $wpdb */
     760        /**
     761         * Global wpdb object.
     762         *
     763         * @var wpdb $wpdb
     764         */
    635765        global $wpdb;
    636 
    637         $sql = "SELECT ID, post_date_gmt FROM {$wpdb->posts} WHERE post_type = %s AND post_password = %s";
    638         $sql = $wpdb->prepare( $sql, array( self::POST_TYPE, $claim_id ) );
    639766
    640767        $action_ids  = array();
     
    642769        $cut_off     = $before_date->format( 'Y-m-d H:i:s' );
    643770
     771        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
     772        $results = $wpdb->get_results(
     773            $wpdb->prepare(
     774                "SELECT ID, post_date_gmt FROM {$wpdb->posts} WHERE post_type = %s AND post_password = %s",
     775                array(
     776                    self::POST_TYPE,
     777                    $claim_id,
     778                )
     779            )
     780        );
     781
    644782        // Verify that the scheduled date for each action is within the expected bounds (in some unusual
    645783        // cases, we cannot depend on MySQL to honor all of the WHERE conditions we specify).
    646         foreach ( $wpdb->get_results( $sql ) as $claimed_action ) {
     784        foreach ( $results as $claimed_action ) {
    647785            if ( $claimed_action->post_date_gmt <= $cut_off ) {
    648786                $action_ids[] = absint( $claimed_action->ID );
     
    653791    }
    654792
     793    /**
     794     * Release claim.
     795     *
     796     * @param ActionScheduler_ActionClaim $claim Claim object to release.
     797     * @return void
     798     * @throws RuntimeException When the claim is not unlocked.
     799     */
    655800    public function release_claim( ActionScheduler_ActionClaim $claim ) {
    656801        $action_ids = $this->find_actions_by_claim_id( $claim->get_id() );
    657802        if ( empty( $action_ids ) ) {
    658             return; // nothing to do
     803            return; // nothing to do.
    659804        }
    660805        $action_id_string = implode( ',', array_map( 'intval', $action_ids ) );
    661         /** @var wpdb $wpdb */
     806        /**
     807         * Global wpdb object.
     808         *
     809         * @var wpdb $wpdb
     810         */
    662811        global $wpdb;
    663         $sql = "UPDATE {$wpdb->posts} SET post_password = '' WHERE ID IN ($action_id_string) AND post_password = %s";
    664         $sql = $wpdb->prepare( $sql, array( $claim->get_id() ) );
    665         $result = $wpdb->query( $sql );
    666         if ( $result === false ) {
     812
     813        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
     814        $result = $wpdb->query(
     815            $wpdb->prepare(
     816                "UPDATE {$wpdb->posts} SET post_password = '' WHERE ID IN ($action_id_string) AND post_password = %s", //phpcs:ignore
     817                array(
     818                    $claim->get_id(),
     819                )
     820            )
     821        );
     822        if ( false === $result ) {
    667823            /* translators: %s: claim ID */
    668824            throw new RuntimeException( sprintf( __( 'Unable to unlock claim %s. Database error.', 'action-scheduler' ), $claim->get_id() ) );
     
    671827
    672828    /**
    673      * @param string $action_id
     829     * Unclaim action.
     830     *
     831     * @param string $action_id Action ID.
     832     * @throws RuntimeException When unable to unlock claim on action ID.
    674833     */
    675834    public function unclaim_action( $action_id ) {
    676         /** @var wpdb $wpdb */
     835        /**
     836         * Global wpdb object.
     837         *
     838         * @var wpdb $wpdb
     839         */
    677840        global $wpdb;
    678         $sql = "UPDATE {$wpdb->posts} SET post_password = '' WHERE ID = %d AND post_type = %s";
    679         $sql = $wpdb->prepare( $sql, $action_id, self::POST_TYPE );
    680         $result = $wpdb->query( $sql );
    681         if ( $result === false ) {
     841
     842        //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
     843        $result = $wpdb->query(
     844            $wpdb->prepare(
     845                "UPDATE {$wpdb->posts} SET post_password = '' WHERE ID = %d AND post_type = %s",
     846                $action_id,
     847                self::POST_TYPE
     848            )
     849        );
     850        if ( false === $result ) {
    682851            /* translators: %s: action ID */
    683852            throw new RuntimeException( sprintf( __( 'Unable to unlock claim on action %s. Database error.', 'action-scheduler' ), $action_id ) );
     
    685854    }
    686855
     856    /**
     857     * Mark failure on action.
     858     *
     859     * @param int $action_id Action ID.
     860     *
     861     * @return void
     862     * @throws RuntimeException When unable to mark failure on action ID.
     863     */
    687864    public function mark_failure( $action_id ) {
    688         /** @var wpdb $wpdb */
     865        /**
     866         * Global wpdb object.
     867         *
     868         * @var wpdb $wpdb
     869         */
    689870        global $wpdb;
    690         $sql = "UPDATE {$wpdb->posts} SET post_status = %s WHERE ID = %d AND post_type = %s";
    691         $sql = $wpdb->prepare( $sql, self::STATUS_FAILED, $action_id, self::POST_TYPE );
    692         $result = $wpdb->query( $sql );
    693         if ( $result === false ) {
     871
     872        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
     873        $result = $wpdb->query(
     874            $wpdb->prepare( "UPDATE {$wpdb->posts} SET post_status = %s WHERE ID = %d AND post_type = %s", self::STATUS_FAILED, $action_id, self::POST_TYPE )
     875        );
     876        if ( false === $result ) {
    694877            /* translators: %s: action ID */
    695878            throw new RuntimeException( sprintf( __( 'Unable to mark failure on action %s. Database error.', 'action-scheduler' ), $action_id ) );
     
    700883     * Return an action's claim ID, as stored in the post password column
    701884     *
    702      * @param string $action_id
     885     * @param int $action_id Action ID.
    703886     * @return mixed
    704887     */
     
    710893     * Return an action's status, as stored in the post status column
    711894     *
    712      * @param string $action_id
     895     * @param int $action_id Action ID.
     896     *
    713897     * @return mixed
     898     * @throws InvalidArgumentException When the action ID is invalid.
    714899     */
    715900    public function get_status( $action_id ) {
    716901        $status = $this->get_post_column( $action_id, 'post_status' );
    717902
    718         if ( $status === null ) {
     903        if ( null === $status ) {
    719904            throw new InvalidArgumentException( __( 'Invalid action ID. No status found.', 'action-scheduler' ) );
    720905        }
     
    723908    }
    724909
     910    /**
     911     * Get post column
     912     *
     913     * @param string $action_id Action ID.
     914     * @param string $column_name Column Name.
     915     *
     916     * @return string|null
     917     */
    725918    private function get_post_column( $action_id, $column_name ) {
    726         /** @var \wpdb $wpdb */
     919        /**
     920         * Global wpdb object.
     921         *
     922         * @var wpdb $wpdb
     923         */
    727924        global $wpdb;
    728         return $wpdb->get_var( $wpdb->prepare( "SELECT {$column_name} FROM {$wpdb->posts} WHERE ID=%d AND post_type=%s", $action_id, self::POST_TYPE ) );
    729     }
    730 
    731     /**
    732      * @param string $action_id
     925
     926        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
     927        return $wpdb->get_var(
     928            $wpdb->prepare(
     929                "SELECT {$column_name} FROM {$wpdb->posts} WHERE ID=%d AND post_type=%s", // phpcs:ignore
     930                $action_id,
     931                self::POST_TYPE
     932            )
     933        );
     934    }
     935
     936    /**
     937     * Log Execution.
     938     *
     939     * @param string $action_id Action ID.
    733940     */
    734941    public function log_execution( $action_id ) {
    735         /** @var wpdb $wpdb */
     942        /**
     943         * Global wpdb object.
     944         *
     945         * @var wpdb $wpdb
     946         */
    736947        global $wpdb;
    737948
    738         $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";
    739         $sql = $wpdb->prepare( $sql, self::STATUS_RUNNING, current_time('mysql', true), current_time('mysql'), $action_id, self::POST_TYPE );
    740         $wpdb->query($sql);
     949        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
     950        $wpdb->query(
     951            $wpdb->prepare(
     952                "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",
     953                self::STATUS_RUNNING,
     954                current_time( 'mysql', true ),
     955                current_time( 'mysql' ),
     956                $action_id,
     957                self::POST_TYPE
     958            )
     959        );
    741960    }
    742961
     
    744963     * Record that an action was completed.
    745964     *
    746      * @param int $action_id ID of the completed action.
    747      * @throws InvalidArgumentException|RuntimeException
     965     * @param string $action_id ID of the completed action.
     966     *
     967     * @throws InvalidArgumentException When the action ID is invalid.
     968     * @throws RuntimeException         When there was an error executing the action.
    748969     */
    749970    public function mark_complete( $action_id ) {
    750971        $post = get_post( $action_id );
    751         if ( empty( $post ) || ( $post->post_type != self::POST_TYPE ) ) {
     972        if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) {
     973            /* translators: %s is the action ID */
    752974            throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
    753975        }
    754976        add_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10, 1 );
    755977        add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 );
    756         $result = wp_update_post(array(
    757             'ID' => $action_id,
    758             'post_status' => 'publish',
    759         ), TRUE);
     978        $result = wp_update_post(
     979            array(
     980                'ID'          => $action_id,
     981                'post_status' => 'publish',
     982            ),
     983            true
     984        );
    760985        remove_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10 );
    761986        remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 );
     
    774999            array(
    7751000                'ID'          => $action_id,
    776                 'post_status' => 'migrated'
     1001                'post_status' => 'migrated',
    7771002            )
    7781003        );
     
    7821007     * Determine whether the post store can be migrated.
    7831008     *
     1009     * @param [type] $setting - Setting value.
    7841010     * @return bool
    7851011     */
     
    7901016        if ( empty( $dependencies_met ) ) {
    7911017            $maximum_args_length = apply_filters( 'action_scheduler_maximum_args_length', 191 );
    792             $found_action        = $wpdb->get_var(
     1018            $found_action        = $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    7931019                $wpdb->prepare(
    7941020                    "SELECT ID FROM {$wpdb->posts} WHERE post_type = %s AND CHAR_LENGTH(post_content) > %d LIMIT 1",
     
    7971023                )
    7981024            );
    799             $dependencies_met = $found_action ? 'no' : 'yes';
     1025            $dependencies_met    = $found_action ? 'no' : 'yes';
    8001026            set_transient( self::DEPENDENCIES_MET, $dependencies_met, DAY_IN_SECONDS );
    8011027        }
    8021028
    803         return 'yes' == $dependencies_met ? $setting : false;
     1029        return 'yes' === $dependencies_met ? $setting : false;
    8041030    }
    8051031
     
    8111037     * developers of this impending requirement.
    8121038     *
    813      * @param ActionScheduler_Action $action
     1039     * @param ActionScheduler_Action $action Action object.
    8141040     */
    8151041    protected function validate_action( ActionScheduler_Action $action ) {
     
    8171043            parent::validate_action( $action );
    8181044        } catch ( Exception $e ) {
     1045            /* translators: %s is the error message */
    8191046            $message = sprintf( __( '%s Support for strings longer than this will be removed in a future version.', 'action-scheduler' ), $e->getMessage() );
    820             _doing_it_wrong( 'ActionScheduler_Action::$args', $message, '2.1.0' );
    821         }
    822     }
    823 
    824     /**
    825      * @codeCoverageIgnore
     1047            _doing_it_wrong( 'ActionScheduler_Action::$args', esc_html( $message ), '2.1.0' );
     1048        }
     1049    }
     1050
     1051    /**
     1052     * (@codeCoverageIgnore)
    8261053     */
    8271054    public function init() {
  • action-scheduler/tags/3.4.0/classes/schema/ActionScheduler_StoreSchema.php

    r2599552 r2622865  
    1717     * @var int Increment this value to trigger a schema update.
    1818     */
    19     protected $schema_version = 5;
     19    protected $schema_version = 6;
    2020
    2121    public function __construct() {
     
    6565                        KEY group_id (group_id),
    6666                        KEY last_attempt_gmt (last_attempt_gmt),
    67                         KEY claim_id (claim_id),
    6867                        KEY `claim_id_status_scheduled_date_gmt` (`claim_id`, `status`, `scheduled_date_gmt`)
    6968                        ) $charset_collate";
  • action-scheduler/tags/3.4.0/deprecated/ActionScheduler_Schedule_Deprecated.php

    r2340383 r2622865  
    1010     * after a given date & time.
    1111     *
    12      * @param DateTime $after
     12     * @param DateTime $after DateTime to calculate against.
    1313     *
    1414     * @return DateTime|null
    1515     */
    16     public function next( DateTime $after = NULL ) {
     16    public function next( DateTime $after = null ) {
    1717        if ( empty( $after ) ) {
    1818            $return_value       = $this->get_date();
     
    2323        }
    2424
    25         _deprecated_function( __METHOD__, '3.0.0', __CLASS__ . '::' . $replacement_method );
     25        _deprecated_function( __METHOD__, '3.0.0', __CLASS__ . '::' . $replacement_method ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
    2626
    2727        return $return_value;
  • action-scheduler/tags/3.4.0/readme.txt

    r2599552 r2622865  
    44Requires at least: 5.2
    55Tested up to: 5.7
    6 Stable tag: 3.3.0
     6Stable tag: 3.4.0
    77License: GPLv3
    88Requires PHP: 5.6
     
    4848== Changelog ==
    4949
     50= 3.4.0 - 2021-10-29 =
     51* Enhancement - Number of items per page can now be set for the Scheduled Actions view (props @ovidiul). #771
     52* Fix - Do not lower the max_execution_time if it is already set to 0 (unlimited) (props @barryhughes). #755
     53* Fix - Avoid triggering autoloaders during the version resolution process (props @olegabr). #731 & #776
     54* Dev - ActionScheduler_wcSystemStatus PHPCS fixes (props @ovidiul). #761
     55* Dev - ActionScheduler_DBLogger.php PHPCS fixes (props @ovidiul). #768
     56* Dev - Fixed phpcs for ActionScheduler_Schedule_Deprecated (props @ovidiul). #762
     57* Dev - Improve actions table indicies (props @glagonikas). #774 & #777
     58* Dev - PHPCS fixes for ActionScheduler_DBStore.php (props @ovidiul). #769 & #778
     59* Dev - PHPCS Fixes for ActionScheduler_Abstract_ListTable (props @ovidiul). #763 & #779
     60* Dev - Adds new filter action_scheduler_claim_actions_order_by to allow tuning of the claim query (props @glagonikas). #773
     61* Dev - PHPCS fixes for ActionScheduler_WpPostStore class (props @ovidiul). #780
     62
    5063= 3.3.0 - 2021-09-15 =
    5164* Enhancement - Adds as_has_scheduled_action() to provide a performant way to test for existing actions. #645
  • action-scheduler/trunk/action-scheduler.php

    r2599552 r2622865  
    66 * Author: Automattic
    77 * Author URI: https://automattic.com/
    8  * Version: 3.3.0
     8 * Version: 3.4.0
    99 * License: GPLv3
    1010 *
     
    2727 */
    2828
    29 if ( ! function_exists( 'action_scheduler_register_3_dot_3_dot_0' ) && function_exists( 'add_action' ) ) {
     29if ( ! function_exists( 'action_scheduler_register_3_dot_4_dot_0' ) && function_exists( 'add_action' ) ) {
    3030
    31     if ( ! class_exists( 'ActionScheduler_Versions' ) ) {
     31    if ( ! class_exists( 'ActionScheduler_Versions', false ) ) {
    3232        require_once __DIR__ . '/classes/ActionScheduler_Versions.php';
    3333        add_action( 'plugins_loaded', array( 'ActionScheduler_Versions', 'initialize_latest_version' ), 1, 0 );
    3434    }
    3535
    36     add_action( 'plugins_loaded', 'action_scheduler_register_3_dot_3_dot_0', 0, 0 );
     36    add_action( 'plugins_loaded', 'action_scheduler_register_3_dot_4_dot_0', 0, 0 );
    3737
    3838    /**
    3939     * Registers this version of Action Scheduler.
    4040     */
    41     function action_scheduler_register_3_dot_3_dot_0() {
     41    function action_scheduler_register_3_dot_4_dot_0() {
    4242        $versions = ActionScheduler_Versions::instance();
    43         $versions->register( '3.3.0', 'action_scheduler_initialize_3_dot_3_dot_0' );
     43        $versions->register( '3.4.0', 'action_scheduler_initialize_3_dot_4_dot_0' );
    4444    }
    4545
     
    4747     * Initializes this version of Action Scheduler.
    4848     */
    49     function action_scheduler_initialize_3_dot_3_dot_0() {
     49    function action_scheduler_initialize_3_dot_4_dot_0() {
    5050        // A final safety check is required even here, because historic versions of Action Scheduler
    5151        // followed a different pattern (in some unusual cases, we could reach this point and the
    5252        // ActionScheduler class is already defined—so we need to guard against that).
    53         if ( ! class_exists( 'ActionScheduler' ) ) {
     53        if ( ! class_exists( 'ActionScheduler', false ) ) {
    5454            require_once __DIR__ . '/classes/abstracts/ActionScheduler.php';
    5555            ActionScheduler::init( __FILE__ );
     
    5858
    5959    // Support usage in themes - load this version if no plugin has loaded a version yet.
    60     if ( did_action( 'plugins_loaded' ) && ! doing_action( 'plugins_loaded' ) && ! class_exists( 'ActionScheduler' ) ) {
    61         action_scheduler_initialize_3_dot_3_dot_0();
     60    if ( did_action( 'plugins_loaded' ) && ! doing_action( 'plugins_loaded' ) && ! class_exists( 'ActionScheduler', false ) ) {
     61        action_scheduler_initialize_3_dot_4_dot_0();
    6262        do_action( 'action_scheduler_pre_theme_init' );
    6363        ActionScheduler_Versions::initialize_latest_version();
  • action-scheduler/trunk/changelog.txt

    r2599552 r2622865  
    11*** Changelog ***
     2
     3= 3.4.0 - 2021-10-29 =
     4* Enhancement - Number of items per page can now be set for the Scheduled Actions view (props @ovidiul). #771
     5* Fix - Do not lower the max_execution_time if it is already set to 0 (unlimited) (props @barryhughes). #755
     6* Fix - Avoid triggering autoloaders during the version resolution process (props @olegabr). #731 & #776
     7* Dev - ActionScheduler_wcSystemStatus PHPCS fixes (props @ovidiul). #761
     8* Dev - ActionScheduler_DBLogger.php PHPCS fixes (props @ovidiul). #768
     9* Dev - Fixed phpcs for ActionScheduler_Schedule_Deprecated (props @ovidiul). #762
     10* Dev - Improve actions table indicies (props @glagonikas). #774 & #777
     11* Dev - PHPCS fixes for ActionScheduler_DBStore.php (props @ovidiul). #769 & #778
     12* Dev - PHPCS Fixes for ActionScheduler_Abstract_ListTable (props @ovidiul). #763 & #779
     13* Dev - Adds new filter action_scheduler_claim_actions_order_by to allow tuning of the claim query (props @glagonikas). #773
     14* Dev - PHPCS fixes for ActionScheduler_WpPostStore class (props @ovidiul). #780
    215
    316= 3.3.0 - 2021-09-15 =
  • action-scheduler/trunk/classes/ActionScheduler_Compatibility.php

    r2599552 r2622865  
    8484     * Only allows raising the existing limit and prevents lowering it. Wrapper for wc_set_time_limit(), when available.
    8585     *
    86      * @param int The time limit in seconds.
     86     * @param int $limit The time limit in seconds.
    8787     */
    8888    public static function raise_time_limit( $limit = 0 ) {
    89         if ( $limit < ini_get( 'max_execution_time' ) ) {
     89        $limit = (int) $limit;
     90        $max_execution_time = (int) ini_get( 'max_execution_time' );
     91
     92        /*
     93         * If the max execution time is already unlimited (zero), or if it exceeds or is equal to the proposed
     94         * limit, there is no reason for us to make further changes (we never want to lower it).
     95         */
     96        if (
     97            0 === $max_execution_time
     98            || ( $max_execution_time >= $limit && $limit !== 0 )
     99        ) {
    90100            return;
    91101        }
     
    94104            wc_set_time_limit( $limit );
    95105        } elseif ( function_exists( 'set_time_limit' ) && false === strpos( ini_get( 'disable_functions' ), 'set_time_limit' ) && ! ini_get( 'safe_mode' ) ) { // phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.safe_modeDeprecatedRemoved
    96             @set_time_limit( $limit );
     106            @set_time_limit( $limit ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
    97107        }
    98108    }
  • action-scheduler/trunk/classes/ActionScheduler_ListTable.php

    r2340383 r2622865  
    176176        );
    177177
    178         parent::__construct( array(
    179             'singular' => 'action-scheduler',
    180             'plural'   => 'action-scheduler',
    181             'ajax'     => false,
    182         ) );
    183     }
    184 
     178        parent::__construct(
     179            array(
     180                'singular' => 'action-scheduler',
     181                'plural'   => 'action-scheduler',
     182                'ajax'     => false,
     183            )
     184        );
     185
     186        add_screen_option(
     187            'per_page',
     188            array(
     189                'default' => $this->items_per_page,
     190            )
     191        );
     192
     193        add_filter( 'set_screen_option_' . $this->get_per_page_option_name(), array( $this, 'set_items_per_page_option' ), 10, 3 );
     194        set_screen_options();
     195    }
     196
     197    /**
     198     * Handles setting the items_per_page option for this screen.
     199     *
     200     * @param mixed  $status Default false (to skip saving the current option).
     201     * @param string $option Screen option name.
     202     * @param int    $value  Screen option value.
     203     * @return int
     204     */
     205    public function set_items_per_page_option( $status, $option, $value ) {
     206        return $value;
     207    }
    185208    /**
    186209     * Convert an interval of seconds into a two part human friendly string.
     
    550573        $this->prepare_column_headers();
    551574
    552         $per_page = $this->get_items_per_page( $this->package . '_items_per_page', $this->items_per_page );
     575        $per_page = $this->get_items_per_page( $this->get_per_page_option_name(), $this->items_per_page );
     576
    553577        $query = array(
    554578            'per_page' => $per_page,
     
    610634        return __( 'Search hook, args and claim ID', 'action-scheduler' );
    611635    }
     636
     637    /**
     638     * {@inheritDoc}
     639     */
     640    protected function get_per_page_option_name() {
     641        return str_replace( '-', '_', $this->screen->id ) . '_per_page';
     642    }
    612643}
  • action-scheduler/trunk/classes/ActionScheduler_wcSystemStatus.php

    r2542151 r2622865  
    1313    protected $store;
    1414
    15     function __construct( $store ) {
     15    /**
     16     * Constructor method for ActionScheduler_wcSystemStatus.
     17     *
     18     * @param ActionScheduler_Store $store Active store object.
     19     *
     20     * @return void
     21     */
     22    public function __construct( $store ) {
    1623        $this->store = $store;
    1724    }
     
    6875        $order = 'oldest' === $date_type ? 'ASC' : 'DESC';
    6976
    70         $action = $this->store->query_actions( array(
    71             'claimed'  => false,
    72             'status'   => $status,
    73             'per_page' => 1,
    74             'order'    => $order,
    75         ) );
     77        $action = $this->store->query_actions(
     78            array(
     79                'claimed'  => false,
     80                'status'   => $status,
     81                'per_page' => 1,
     82                'order'    => $order,
     83            )
     84        );
    7685
    7786        if ( ! empty( $action ) ) {
     
    93102     */
    94103    protected function get_template( $status_labels, $action_counts, $oldest_and_newest ) {
    95         $as_version = ActionScheduler_Versions::instance()->latest_version();
     104        $as_version   = ActionScheduler_Versions::instance()->latest_version();
    96105        $as_datastore = get_class( ActionScheduler_Store::instance() );
    97106        ?>
     
    125134                        '<tr><td>%1$s</td><td>&nbsp;</td><td>%2$s<span style="display: none;">, Oldest: %3$s, Newest: %4$s</span></td><td>%3$s</td><td>%4$s</td></tr>',
    126135                        esc_html( $status_labels[ $status ] ),
    127                         number_format_i18n( $count ),
    128                         $oldest_and_newest[ $status ]['oldest'],
    129                         $oldest_and_newest[ $status ]['newest']
     136                        esc_html( number_format_i18n( $count ) ),
     137                        esc_html( $oldest_and_newest[ $status ]['oldest'] ),
     138                        esc_html( $oldest_and_newest[ $status ]['newest'] )
    130139                    );
    131140                }
     
    138147
    139148    /**
    140      * is triggered when invoking inaccessible methods in an object context.
     149     * Is triggered when invoking inaccessible methods in an object context.
    141150     *
    142      * @param string $name
    143      * @param array  $arguments
     151     * @param string $name Name of method called.
     152     * @param array  $arguments Parameters to invoke the method with.
    144153     *
    145154     * @return mixed
  • action-scheduler/trunk/classes/abstracts/ActionScheduler_Abstract_ListTable.php

    r2551612 r2622865  
    22
    33if ( ! class_exists( 'WP_List_Table' ) ) {
    4     require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
     4    require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
    55}
    66
     
    1414 *
    1515 * This class supports:
    16  *  - Bulk actions
    17  *  - Search
     16 *  - Bulk actions
     17 *  - Search
    1818 *  - Sortable columns
    1919 *  - Automatic translations of the columns
     
    2626    /**
    2727     * The table name
     28     *
     29     * @var string
    2830     */
    2931    protected $table_name;
     
    3133    /**
    3234     * Package name, used to get options from WP_List_Table::get_items_per_page.
     35     *
     36     * @var string
    3337     */
    3438    protected $package;
     
    3640    /**
    3741     * How many items do we render per page?
     42     *
     43     * @var int
    3844     */
    3945    protected $items_per_page = 10;
     
    4248     * Enables search in this table listing. If this array
    4349     * is empty it means the listing is not searchable.
     50     *
     51     * @var array
    4452     */
    4553    protected $search_by = array();
     
    4957     * key must much the table column name and the value is the label, which is
    5058     * automatically translated.
     59     *
     60     * @var array
    5161     */
    5262    protected $columns = array();
     
    5969     * (with the prefix row_action_<key>) and the value is the label
    6070     * and title.
     71     *
     72     * @var array
    6173     */
    6274    protected $row_actions = array();
     
    6476    /**
    6577     * The Primary key of our table
     78     *
     79     * @var string
    6680     */
    6781    protected $ID = 'ID';
     
    7084     * Enables sorting, it expects an array
    7185     * of columns (the column names are the values)
     86     *
     87     * @var array
    7288     */
    7389    protected $sort_by = array();
    7490
     91    /**
     92     * The default sort order
     93     *
     94     * @var string
     95     */
    7596    protected $filter_by = array();
    7697
    7798    /**
    78      * @var array The status name => count combinations for this table's items. Used to display status filters.
     99     * The status name => count combinations for this table's items. Used to display status filters.
     100     *
     101     * @var array
    79102     */
    80103    protected $status_counts = array();
    81104
    82105    /**
    83      * @var array Notices to display when loading the table. Array of arrays of form array( 'class' => {updated|error}, 'message' => 'This is the notice text display.' ).
     106     * Notices to display when loading the table. Array of arrays of form array( 'class' => {updated|error}, 'message' => 'This is the notice text display.' ).
     107     *
     108     * @var array
    84109     */
    85110    protected $admin_notices = array();
    86111
    87112    /**
    88      * @var string Localised string displayed in the <h1> element above the able.
     113     * Localised string displayed in the <h1> element above the able.
     114     *
     115     * @var string
    89116     */
    90117    protected $table_header;
     
    100127     * is the array with primary keys, the second argument is a string with a list of the primary keys,
    101128     * escaped and ready to use (with `IN`).
     129     *
     130     * @var array
    102131     */
    103132    protected $bulk_actions = array();
     
    107136     * `_x` with some default (the package name).
    108137     *
    109      * @deprecated 3.0.0
     138     * @param string $text The new text to translate.
     139     * @param string $context The context of the text.
     140     * @return string|void The translated text.
     141     *
     142     * @deprecated 3.0.0 Use `_x()` instead.
    110143     */
    111144    protected function translate( $text, $context = '' ) {
     
    117150     * also validates that the bulk method handler exists. It throws an exception because
    118151     * this is a library meant for developers and missing a bulk method is a development-time error.
     152     *
     153     * @return array
     154     *
     155     * @throws RuntimeException Throws RuntimeException when the bulk action does not have a callback method.
    119156     */
    120157    protected function get_bulk_actions() {
     
    147184        check_admin_referer( 'bulk-' . $this->_args['plural'] );
    148185
    149         $method   = 'bulk_' . $action;
     186        $method = 'bulk_' . $action;
    150187        if ( array_key_exists( $action, $this->bulk_actions ) && is_callable( array( $this, $method ) ) && ! empty( $_GET['ID'] ) && is_array( $_GET['ID'] ) ) {
    151188            $ids_sql = '(' . implode( ',', array_fill( 0, count( $_GET['ID'] ), '%s' ) ) . ')';
    152             $this->$method( $_GET['ID'], $wpdb->prepare( $ids_sql, $_GET['ID'] ) );
    153         }
    154 
    155         wp_redirect( remove_query_arg(
    156             array( '_wp_http_referer', '_wpnonce', 'ID', 'action', 'action2' ),
    157             wp_unslash( $_SERVER['REQUEST_URI'] )
    158         ) );
    159         exit;
     189            $id      = array_map( 'absint', $_GET['ID'] );
     190            $this->$method( $id, $wpdb->prepare( $ids_sql, $id ) ); //phpcs:ignore WordPress.DB.PreparedSQL
     191        }
     192
     193        if ( isset( $_SERVER['REQUEST_URI'] ) ) {
     194            wp_safe_redirect(
     195                remove_query_arg(
     196                    array( '_wp_http_referer', '_wpnonce', 'ID', 'action', 'action2' ),
     197                    esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) )
     198                )
     199            );
     200            exit;
     201        }
    160202    }
    161203
     
    163205     * Default code for deleting entries.
    164206     * validated already by process_bulk_action()
     207     *
     208     * @param array  $ids ids of the items to delete.
     209     * @param string $ids_sql the sql for the ids.
     210     * @return void
    165211     */
    166212    protected function bulk_delete( array $ids, $ids_sql ) {
     
    218264        global $wpdb;
    219265
    220         $per_page = $this->get_items_per_page( $this->package . '_items_per_page', $this->items_per_page );
     266        $per_page = $this->get_items_per_page( $this->get_per_page_option_name(), $this->items_per_page );
    221267        return $wpdb->prepare( 'LIMIT %d', $per_page );
    222268    }
     
    228274     */
    229275    protected function get_items_offset() {
    230         $per_page = $this->get_items_per_page( $this->package . '_items_per_page', $this->items_per_page );
     276        $per_page     = $this->get_items_per_page( $this->get_per_page_option_name(), $this->items_per_page );
    231277        $current_page = $this->get_pagenum();
    232278        if ( 1 < $current_page ) {
     
    277323        $valid_sortable_columns = array_values( $this->sort_by );
    278324
    279         if ( ! empty( $_GET['orderby'] ) && in_array( $_GET['orderby'], $valid_sortable_columns ) ) {
    280             $orderby = sanitize_text_field( $_GET['orderby'] );
     325        if ( ! empty( $_GET['orderby'] ) && in_array( $_GET['orderby'], $valid_sortable_columns, true ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
     326            $orderby = sanitize_text_field( wp_unslash( $_GET['orderby'] ) ); //phpcs:ignore WordPress.Security.NonceVerification.Recommended
    281327        } else {
    282328            $orderby = $valid_sortable_columns[0];
     
    293339    protected function get_request_order() {
    294340
    295         if ( ! empty( $_GET['order'] ) && 'desc' === strtolower( $_GET['order'] ) ) {
     341        if ( ! empty( $_GET['order'] ) && 'desc' === strtolower( sanitize_text_field( wp_unslash( $_GET['order'] ) ) ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
    296342            $order = 'DESC';
    297343        } else {
     
    308354     */
    309355    protected function get_request_status() {
    310         $status = ( ! empty( $_GET['status'] ) ) ? $_GET['status'] : '';
     356        $status = ( ! empty( $_GET['status'] ) ) ? sanitize_text_field( wp_unslash( $_GET['status'] ) ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Recommended
    311357        return $status;
    312358    }
     
    318364     */
    319365    protected function get_request_search_query() {
    320         $search_query = ( ! empty( $_GET['s'] ) ) ? $_GET['s'] : '';
     366        $search_query = ( ! empty( $_GET['s'] ) ) ? sanitize_text_field( wp_unslash( $_GET['s'] ) ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Recommended
    321367        return $search_query;
    322368    }
     
    330376    protected function get_table_columns() {
    331377        $columns = array_keys( $this->columns );
    332         if ( ! in_array( $this->ID, $columns ) ) {
     378        if ( ! in_array( $this->ID, $columns, true ) ) {
    333379            $columns[] = $this->ID;
    334380        }
     
    344390     * that feature it will return an empty string.
    345391     *
    346      * TODO:
    347      *   - Improve search doing LIKE by word rather than by phrases.
    348      *
    349392     * @return string
    350393     */
     
    352395        global $wpdb;
    353396
    354         if ( empty( $_GET['s'] ) || empty( $this->search_by ) ) {
     397        if ( empty( $_GET['s'] ) || empty( $this->search_by ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
    355398            return '';
    356399        }
    357400
    358         $filter  = array();
     401        $search_string = sanitize_text_field( wp_unslash( $_GET['s'] ) ); //phpcs:ignore WordPress.Security.NonceVerification.Recommended
     402
     403        $filter = array();
    359404        foreach ( $this->search_by as $column ) {
    360             $filter[] = $wpdb->prepare('`' . $column . '` like "%%s%"', $wpdb->esc_like( $_GET['s'] ));
     405            $wild     = '%';
     406            $sql_like = $wild . $wpdb->esc_like( $search_string ) . $wild;
     407            $filter[] = $wpdb->prepare( '`' . $column . '` LIKE %s', $sql_like ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.DB.PreparedSQL.NotPrepared
    361408        }
    362409        return implode( ' OR ', $filter );
     
    370417        global $wpdb;
    371418
    372         if ( ! $this->filter_by || empty( $_GET['filter_by'] ) || ! is_array( $_GET['filter_by'] ) ) {
     419        if ( ! $this->filter_by || empty( $_GET['filter_by'] ) || ! is_array( $_GET['filter_by'] ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
    373420            return '';
    374421        }
     
    377424
    378425        foreach ( $this->filter_by as $column => $options ) {
    379             if ( empty( $_GET['filter_by'][ $column ] ) || empty( $options[ $_GET['filter_by'][ $column ] ] ) ) {
     426            if ( empty( $_GET['filter_by'][ $column ] ) || empty( $options[ $_GET['filter_by'][ $column ] ] ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
    380427                continue;
    381428            }
    382429
    383             $filter[] = $wpdb->prepare( "`$column` = %s", $_GET['filter_by'][ $column ] );
     430            $filter[] = $wpdb->prepare( "`$column` = %s", sanitize_text_field( wp_unslash( $_GET['filter_by'][ $column ] ) ) ); //phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
    384431        }
    385432
     
    404451        $this->process_row_actions();
    405452
    406         if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) {
     453        if ( ! empty( $_REQUEST['_wp_http_referer'] && ! empty( $_SERVER['REQUEST_URI'] ) ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
    407454            // _wp_http_referer is used only on bulk actions, we remove it to keep the $_GET shorter
    408             wp_redirect( remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
     455            wp_safe_redirect( remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) ) );
    409456            exit;
    410457        }
     
    415462        $offset  = $this->get_items_query_offset();
    416463        $order   = $this->get_items_query_order();
    417         $where   = array_filter(array(
    418             $this->get_items_query_search(),
    419             $this->get_items_query_filters(),
    420         ));
     464        $where   = array_filter(
     465            array(
     466                $this->get_items_query_search(),
     467                $this->get_items_query_filters(),
     468            )
     469        );
    421470        $columns = '`' . implode( '`, `', $this->get_table_columns() ) . '`';
    422471
    423472        if ( ! empty( $where ) ) {
    424             $where = 'WHERE ('. implode( ') AND (', $where ) . ')';
     473            $where = 'WHERE (' . implode( ') AND (', $where ) . ')';
    425474        } else {
    426475            $where = '';
     
    429478        $sql = "SELECT $columns FROM {$this->table_name} {$where} {$order} {$limit} {$offset}";
    430479
    431         $this->set_items( $wpdb->get_results( $sql, ARRAY_A ) );
     480        $this->set_items( $wpdb->get_results( $sql, ARRAY_A ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
    432481
    433482        $query_count = "SELECT COUNT({$this->ID}) FROM {$this->table_name} {$where}";
    434         $total_items = $wpdb->get_var( $query_count );
    435         $per_page    = $this->get_items_per_page( $this->package . '_items_per_page', $this->items_per_page );
    436         $this->set_pagination_args( array(
    437             'total_items' => $total_items,
    438             'per_page'    => $per_page,
    439             'total_pages' => ceil( $total_items / $per_page ),
    440         ) );
    441     }
    442 
     483        $total_items = $wpdb->get_var( $query_count ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
     484        $per_page    = $this->get_items_per_page( $this->get_per_page_option_name(), $this->items_per_page );
     485        $this->set_pagination_args(
     486            array(
     487                'total_items' => $total_items,
     488                'per_page'    => $per_page,
     489                'total_pages' => ceil( $total_items / $per_page ),
     490            )
     491        );
     492    }
     493
     494    /**
     495     * Display the table.
     496     *
     497     * @param string $which The name of the table.
     498     */
    443499    public function extra_tablenav( $which ) {
    444500        if ( ! $this->filter_by || 'top' !== $which ) {
     
    449505
    450506        foreach ( $this->filter_by as $id => $options ) {
    451             $default = ! empty( $_GET['filter_by'][ $id ] ) ? $_GET['filter_by'][ $id ] : '';
     507            $default = ! empty( $_GET['filter_by'][ $id ] ) ? sanitize_text_field( wp_unslash( $_GET['filter_by'][ $id ] ) ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Recommended
    452508            if ( empty( $options[ $default ] ) ) {
    453509                $default = '';
     
    457513
    458514            foreach ( $options as $value => $label ) {
    459                 echo '<option value="' . esc_attr( $value ) . '" ' . esc_html( $value == $default ? 'selected' : '' )  .'>'
     515                echo '<option value="' . esc_attr( $value ) . '" ' . esc_html( $value === $default ? 'selected' : '' ) . '>'
    460516                    . esc_html( $label )
    461517                . '</option>';
     
    472528     * Set the data for displaying. It will attempt to unserialize (There is a chance that some columns
    473529     * are serialized). This can be override in child classes for futher data transformation.
     530     *
     531     * @param array $items Items array.
    474532     */
    475533    protected function set_items( array $items ) {
     
    484542     * of how the primary key is named (to keep the code simpler). The bulk actions will do the proper
    485543     * name transformation though using `$this->ID`.
     544     *
     545     * @param array $row The row to render.
    486546     */
    487547    public function column_cb( $row ) {
    488         return '<input name="ID[]" type="checkbox" value="' . esc_attr( $row[ $this->ID ] ) .'" />';
     548        return '<input name="ID[]" type="checkbox" value="' . esc_attr( $row[ $this->ID ] ) . '" />';
    489549    }
    490550
     
    495555     * and it checks that the row action method exists before rendering it.
    496556     *
    497      * @param array $row     Row to render
    498      * @param $column_name   Current row
    499      * @return
     557     * @param array  $row Row to be rendered.
     558     * @param string $column_name Column name.
     559     * @return string
    500560     */
    501561    protected function maybe_render_actions( $row, $column_name ) {
     
    506566        $row_id = $row[ $this->ID ];
    507567
    508         $actions = '<div class="row-actions">';
     568        $actions      = '<div class="row-actions">';
    509569        $action_count = 0;
    510570        foreach ( $this->row_actions[ $column_name ] as $action_key => $action ) {
     
    516576            }
    517577
    518             $action_link = ! empty( $action['link'] ) ? $action['link'] : add_query_arg( array( 'row_action' => $action_key, 'row_id' => $row_id, 'nonce'  => wp_create_nonce( $action_key . '::' . $row_id ) ) );
     578            $action_link = ! empty( $action['link'] ) ? $action['link'] : add_query_arg(
     579                array(
     580                    'row_action' => $action_key,
     581                    'row_id'     => $row_id,
     582                    'nonce'      => wp_create_nonce( $action_key . '::' . $row_id ),
     583                )
     584            );
    519585            $span_class  = ! empty( $action['class'] ) ? $action['class'] : $action_key;
    520586            $separator   = ( $action_count < count( $this->row_actions[ $column_name ] ) ) ? ' | ' : '';
     
    528594    }
    529595
     596    /**
     597     * Process the bulk actions.
     598     *
     599     * @return void
     600     */
    530601    protected function process_row_actions() {
    531602        $parameters = array( 'row_action', 'row_id', 'nonce' );
    532603        foreach ( $parameters as $parameter ) {
    533             if ( empty( $_REQUEST[ $parameter ] ) ) {
     604            if ( empty( $_REQUEST[ $parameter ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
    534605                return;
    535606            }
    536607        }
    537608
    538         $method = 'row_action_' . $_REQUEST['row_action'];
    539 
    540         if ( $_REQUEST['nonce'] === wp_create_nonce( $_REQUEST[ 'row_action' ] . '::' . $_REQUEST[ 'row_id' ] ) && method_exists( $this, $method ) ) {
    541             $this->$method( $_REQUEST['row_id'] );
    542         }
    543 
    544         wp_redirect( remove_query_arg(
    545             array( 'row_id', 'row_action', 'nonce' ),
    546             wp_unslash( $_SERVER['REQUEST_URI'] )
    547         ) );
    548         exit;
     609        $action = sanitize_text_field( wp_unslash( $_REQUEST['row_action'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotValidated
     610        $row_id = sanitize_text_field( wp_unslash( $_REQUEST['row_id'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotValidated
     611        $nonce  = sanitize_text_field( wp_unslash( $_REQUEST['nonce'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotValidated
     612        $method = 'row_action_' . $action; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
     613
     614        if ( wp_verify_nonce( $nonce, $action . '::' . $row_id ) && method_exists( $this, $method ) ) {
     615            $this->$method( sanitize_text_field( wp_unslash( $row_id ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
     616        }
     617
     618        if ( isset( $_SERVER['REQUEST_URI'] ) ) {
     619            wp_safe_redirect(
     620                remove_query_arg(
     621                    array( 'row_id', 'row_action', 'nonce' ),
     622                    esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) )
     623                )
     624            );
     625            exit;
     626        }
    549627    }
    550628
    551629    /**
    552630     * Default column formatting, it will escape everythig for security.
     631     *
     632     * @param array  $item The item array.
     633     * @param string $column_name Column name to display.
     634     *
     635     * @return string
    553636     */
    554637    public function column_default( $item, $column_name ) {
    555         $column_html = esc_html( $item[ $column_name ] );
     638        $column_html  = esc_html( $item[ $column_name ] );
    556639        $column_html .= $this->maybe_render_actions( $item, $column_name );
    557640        return $column_html;
     
    575658    protected function display_admin_notices() {
    576659        foreach ( $this->admin_notices as $notice ) {
    577             echo '<div id="message" class="' . $notice['class'] . '">';
     660            echo '<div id="message" class="' . esc_attr( $notice['class'] ) . '">';
    578661            echo '  <p>' . wp_kses_post( $notice['message'] ) . '</p>';
    579662            echo '</div>';
     
    589672        $request_status    = $this->get_request_status();
    590673
    591         // Helper to set 'all' filter when not set on status counts passed in
     674        // Helper to set 'all' filter when not set on status counts passed in.
    592675        if ( ! isset( $this->status_counts['all'] ) ) {
    593676            $this->status_counts = array( 'all' => array_sum( $this->status_counts ) ) + $this->status_counts;
     
    613696        if ( $status_list_items ) {
    614697            echo '<ul class="subsubsub">';
    615             echo implode( " | \n", $status_list_items );
     698            echo implode( " | \n", $status_list_items ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
    616699            echo '</ul>';
    617700        }
     
    625708    protected function display_table() {
    626709        echo '<form id="' . esc_attr( $this->_args['plural'] ) . '-filter" method="get">';
    627         foreach ( $_GET as $key => $value ) {
     710        foreach ( $_GET as $key => $value ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
    628711            if ( '_' === $key[0] || 'paged' === $key || 'ID' === $key ) {
    629712                continue;
     
    632715        }
    633716        if ( ! empty( $this->search_by ) ) {
    634             echo $this->search_box( $this->get_search_box_button_text(), 'plugin' ); // WPCS: XSS OK
     717            echo $this->search_box( $this->get_search_box_button_text(), 'plugin' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
    635718        }
    636719        parent::display();
     
    645728        $this->process_row_actions();
    646729
    647         if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) {
     730        if ( ! empty( $_REQUEST['_wp_http_referer'] ) && ! empty( $_SERVER['REQUEST_URI'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
    648731            // _wp_http_referer is used only on bulk actions, we remove it to keep the $_GET shorter
    649             wp_redirect( remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
     732            wp_safe_redirect( remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) ) );
    650733            exit;
    651734        }
     
    672755        return esc_html__( 'Search', 'action-scheduler' );
    673756    }
     757
     758    /**
     759     * Gets the screen per_page option name.
     760     *
     761     * @return string
     762     */
     763    protected function get_per_page_option_name() {
     764        return $this->package . '_items_per_page';
     765    }
    674766}
  • action-scheduler/trunk/classes/data-stores/ActionScheduler_DBLogger.php

    r2599552 r2622865  
    3030        $date_local = $date->format( 'Y-m-d H:i:s' );
    3131
    32         /** @var \wpdb $wpdb */
     32        /** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort
    3333        global $wpdb;
    34         $wpdb->insert( $wpdb->actionscheduler_logs, [
    35             'action_id'      => $action_id,
    36             'message'        => $message,
    37             'log_date_gmt'   => $date_gmt,
    38             'log_date_local' => $date_local,
    39         ], [ '%d', '%s', '%s', '%s' ] );
     34        $wpdb->insert(
     35            $wpdb->actionscheduler_logs,
     36            array(
     37                'action_id'      => $action_id,
     38                'message'        => $message,
     39                'log_date_gmt'   => $date_gmt,
     40                'log_date_local' => $date_local,
     41            ),
     42            array( '%d', '%s', '%s', '%s' )
     43        );
    4044
    4145        return $wpdb->insert_id;
     
    5054     */
    5155    public function get_entry( $entry_id ) {
    52         /** @var \wpdb $wpdb */
     56        /** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort
    5357        global $wpdb;
    5458        $entry = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_logs} WHERE log_id=%d", $entry_id ) );
     
    8690     */
    8791    public function get_logs( $action_id ) {
    88         /** @var \wpdb $wpdb */
     92        /** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort
    8993        global $wpdb;
    9094
    9195        $records = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_logs} WHERE action_id=%d", $action_id ) );
    9296
    93         return array_map( [ $this, 'create_entry_from_db_record' ], $records );
     97        return array_map( array( $this, 'create_entry_from_db_record' ), $records );
    9498    }
    9599
     
    106110        parent::init();
    107111
    108         add_action( 'action_scheduler_deleted_action', [ $this, 'clear_deleted_action_logs' ], 10, 1 );
     112        add_action( 'action_scheduler_deleted_action', array( $this, 'clear_deleted_action_logs' ), 10, 1 );
    109113    }
    110114
     
    115119     */
    116120    public function clear_deleted_action_logs( $action_id ) {
    117         /** @var \wpdb $wpdb */
     121        /** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort
    118122        global $wpdb;
    119         $wpdb->delete( $wpdb->actionscheduler_logs, [ 'action_id' => $action_id, ], [ '%d' ] );
     123        $wpdb->delete( $wpdb->actionscheduler_logs, array( 'action_id' => $action_id ), array( '%d' ) );
    120124    }
    121125
     
    130134        }
    131135
    132         /** @var \wpdb $wpdb */
     136        /** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort
    133137        global $wpdb;
    134138        $date     = as_get_datetime_object();
     
    139143        $format     = '(%d, ' . $wpdb->prepare( '%s, %s, %s', $message, $date_gmt, $date_local ) . ')';
    140144        $sql_query  = "INSERT {$wpdb->actionscheduler_logs} (action_id, message, log_date_gmt, log_date_local) VALUES ";
    141         $value_rows = [];
     145        $value_rows = array();
    142146
    143147        foreach ( $action_ids as $action_id ) {
    144             $value_rows[] = $wpdb->prepare( $format, $action_id );
     148            $value_rows[] = $wpdb->prepare( $format, $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
    145149        }
    146150        $sql_query .= implode( ',', $value_rows );
    147151
    148         $wpdb->query( $sql_query );
     152        $wpdb->query( $sql_query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
    149153    }
    150154}
  • action-scheduler/trunk/classes/data-stores/ActionScheduler_DBStore.php

    r2599552 r2622865  
    4141     *
    4242     * @param ActionScheduler_Action $action Action object.
    43      * @param DateTime               $date Optional schedule date. Default null.
     43     * @param DateTime              $date Optional schedule date. Default null.
    4444     *
    4545     * @return int Action ID.
     46     * @throws RuntimeException     Throws exception when saving the action fails.
    4647     */
    4748    public function save_action( ActionScheduler_Action $action, \DateTime $date = null ) {
     
    5253            /** @var \wpdb $wpdb */
    5354            global $wpdb;
    54             $data = [
     55            $data = array(
    5556                'hook'                 => $action->get_hook(),
    5657                'status'               => ( $action->is_finished() ? self::STATUS_COMPLETE : self::STATUS_PENDING ),
    5758                'scheduled_date_gmt'   => $this->get_scheduled_date_string( $action, $date ),
    5859                'scheduled_date_local' => $this->get_scheduled_date_string_local( $action, $date ),
    59                 'schedule'             => serialize( $action->get_schedule() ),
     60                'schedule'             => serialize( $action->get_schedule() ), // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
    6061                'group_id'             => $this->get_group_id( $action->get_group() ),
    61             ];
     62            );
    6263            $args = wp_json_encode( $action->get_args() );
    6364            if ( strlen( $args ) <= static::$max_index_length ) {
     
    7374
    7475            if ( is_wp_error( $action_id ) ) {
    75                 throw new RuntimeException( $action_id->get_error_message() );
    76             }
    77             elseif ( empty( $action_id ) ) {
    78                 throw new RuntimeException( $wpdb->last_error ? $wpdb->last_error : __( 'Database error.', 'action-scheduler' ) );
     76                throw new \RuntimeException( $action_id->get_error_message() );
     77            } elseif ( empty( $action_id ) ) {
     78                throw new \RuntimeException( $wpdb->last_error ? $wpdb->last_error : __( 'Database error.', 'action-scheduler' ) );
    7979            }
    8080
     
    115115     *
    116116     * @param string $slug The string name of a group.
    117      * @param bool $create_if_not_exists Whether to create the group if it does not already exist. Default, true - create the group.
     117     * @param bool   $create_if_not_exists Whether to create the group if it does not already exist. Default, true - create the group.
    118118     *
    119119     * @return int The group's ID, if it exists or is created, or 0 if it does not exist and is not created.
     
    143143        /** @var \wpdb $wpdb */
    144144        global $wpdb;
    145         $wpdb->insert( $wpdb->actionscheduler_groups, [ 'slug' => $slug ] );
     145        $wpdb->insert( $wpdb->actionscheduler_groups, array( 'slug' => $slug ) );
    146146
    147147        return (int) $wpdb->insert_id;
     
    158158        /** @var \wpdb $wpdb */
    159159        global $wpdb;
    160         $data = $wpdb->get_row( $wpdb->prepare(
    161             "SELECT a.*, g.slug AS `group` FROM {$wpdb->actionscheduler_actions} a LEFT JOIN {$wpdb->actionscheduler_groups} g ON a.group_id=g.group_id WHERE a.action_id=%d",
    162             $action_id
    163         ) );
     160        $data = $wpdb->get_row(
     161            $wpdb->prepare(
     162                "SELECT a.*, g.slug AS `group` FROM {$wpdb->actionscheduler_actions} a LEFT JOIN {$wpdb->actionscheduler_groups} g ON a.group_id=g.group_id WHERE a.action_id=%d",
     163                $action_id
     164            )
     165        );
    164166
    165167        if ( empty( $data ) ) {
     
    173175
    174176        // Convert NULL dates to zero dates.
    175         $date_fields = [
     177        $date_fields = array(
    176178            'scheduled_date_gmt',
    177179            'scheduled_date_local',
    178180            'last_attempt_gmt',
    179             'last_attempt_gmt'
    180         ];
    181         foreach( $date_fields as $date_field ) {
     181            'last_attempt_gmt',
     182        );
     183        foreach ( $date_fields as $date_field ) {
    182184            if ( is_null( $data->$date_field ) ) {
    183185                $data->$date_field = ActionScheduler_StoreSchema::DEFAULT_DATE;
     
    215217        $hook     = $data->hook;
    216218        $args     = json_decode( $data->args, true );
    217         $schedule = unserialize( $data->schedule );
     219        $schedule = unserialize( $data->schedule ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_unserialize
    218220
    219221        $this->validate_args( $args, $data->action_id );
     
    237239     *
    238240     * @return string SQL statement already properly escaped.
     241     * @throws InvalidArgumentException If the query is invalid.
    239242     */
    240243    protected function get_query_actions_sql( array $query, $select_or_count = 'select' ) {
    241244
    242         if ( ! in_array( $select_or_count, array( 'select', 'count' ) ) ) {
     245        if ( ! in_array( $select_or_count, array( 'select', 'count' ), true ) ) {
    243246            throw new InvalidArgumentException( __( 'Invalid value for select or count parameter. Cannot query actions.', 'action-scheduler' ) );
    244247        }
    245248
    246         $query = wp_parse_args( $query, [
    247             'hook'             => '',
    248             'args'             => null,
    249             'date'             => null,
    250             'date_compare'     => '<=',
    251             'modified'         => null,
    252             'modified_compare' => '<=',
    253             'group'            => '',
    254             'status'           => '',
    255             'claimed'          => null,
    256             'per_page'         => 5,
    257             'offset'           => 0,
    258             'orderby'          => 'date',
    259             'order'            => 'ASC',
    260         ] );
    261 
    262         /** @var \wpdb $wpdb */
    263         global $wpdb;
    264         $sql  = ( 'count' === $select_or_count ) ? 'SELECT count(a.action_id)' : 'SELECT a.action_id';
    265         $sql .= " FROM {$wpdb->actionscheduler_actions} a";
    266         $sql_params = [];
    267 
    268         if ( ! empty( $query[ 'group' ] ) || 'group' === $query[ 'orderby' ] ) {
     249        $query = wp_parse_args(
     250            $query,
     251            array(
     252                'hook'             => '',
     253                'args'             => null,
     254                'date'             => null,
     255                'date_compare'     => '<=',
     256                'modified'         => null,
     257                'modified_compare' => '<=',
     258                'group'            => '',
     259                'status'           => '',
     260                'claimed'          => null,
     261                'per_page'         => 5,
     262                'offset'           => 0,
     263                'orderby'          => 'date',
     264                'order'            => 'ASC',
     265            )
     266        );
     267
     268        /** @var \wpdb $wpdb */
     269        global $wpdb;
     270        $sql        = ( 'count' === $select_or_count ) ? 'SELECT count(a.action_id)' : 'SELECT a.action_id';
     271        $sql       .= " FROM {$wpdb->actionscheduler_actions} a";
     272        $sql_params = array();
     273
     274        if ( ! empty( $query['group'] ) || 'group' === $query['orderby'] ) {
    269275            $sql .= " LEFT JOIN {$wpdb->actionscheduler_groups} g ON g.group_id=a.group_id";
    270276        }
    271277
    272         $sql .= " WHERE 1=1";
    273 
    274         if ( ! empty( $query[ 'group' ] ) ) {
    275             $sql          .= " AND g.slug=%s";
    276             $sql_params[] = $query[ 'group' ];
    277         }
    278 
    279         if ( $query[ 'hook' ] ) {
    280             $sql          .= " AND a.hook=%s";
    281             $sql_params[] = $query[ 'hook' ];
    282         }
    283         if ( ! is_null( $query[ 'args' ] ) ) {
    284             $sql          .= " AND a.args=%s";
    285             $sql_params[] = $this->get_args_for_query( $query[ 'args' ] );
     278        $sql .= ' WHERE 1=1';
     279
     280        if ( ! empty( $query['group'] ) ) {
     281            $sql         .= ' AND g.slug=%s';
     282            $sql_params[] = $query['group'];
     283        }
     284
     285        if ( $query['hook'] ) {
     286            $sql         .= ' AND a.hook=%s';
     287            $sql_params[] = $query['hook'];
     288        }
     289        if ( ! is_null( $query['args'] ) ) {
     290            $sql         .= ' AND a.args=%s';
     291            $sql_params[] = $this->get_args_for_query( $query['args'] );
    286292        }
    287293
     
    293299        }
    294300
    295         if ( $query[ 'date' ] instanceof \DateTime ) {
    296             $date = clone $query[ 'date' ];
     301        if ( $query['date'] instanceof \DateTime ) {
     302            $date = clone $query['date'];
    297303            $date->setTimezone( new \DateTimeZone( 'UTC' ) );
    298304            $date_string  = $date->format( 'Y-m-d H:i:s' );
    299             $comparator   = $this->validate_sql_comparator( $query[ 'date_compare' ] );
    300             $sql          .= " AND a.scheduled_date_gmt $comparator %s";
     305            $comparator   = $this->validate_sql_comparator( $query['date_compare'] );
     306            $sql         .= " AND a.scheduled_date_gmt $comparator %s";
    301307            $sql_params[] = $date_string;
    302308        }
    303309
    304         if ( $query[ 'modified' ] instanceof \DateTime ) {
    305             $modified = clone $query[ 'modified' ];
     310        if ( $query['modified'] instanceof \DateTime ) {
     311            $modified = clone $query['modified'];
    306312            $modified->setTimezone( new \DateTimeZone( 'UTC' ) );
    307313            $date_string  = $modified->format( 'Y-m-d H:i:s' );
    308             $comparator   = $this->validate_sql_comparator( $query[ 'modified_compare' ] );
    309             $sql          .= " AND a.last_attempt_gmt $comparator %s";
     314            $comparator   = $this->validate_sql_comparator( $query['modified_compare'] );
     315            $sql         .= " AND a.last_attempt_gmt $comparator %s";
    310316            $sql_params[] = $date_string;
    311317        }
    312318
    313         if ( $query[ 'claimed' ] === true ) {
    314             $sql .= " AND a.claim_id != 0";
    315         } elseif ( $query[ 'claimed' ] === false ) {
    316             $sql .= " AND a.claim_id = 0";
    317         } elseif ( ! is_null( $query[ 'claimed' ] ) ) {
    318             $sql          .= " AND a.claim_id = %d";
    319             $sql_params[] = $query[ 'claimed' ];
     319        if ( true === $query['claimed'] ) {
     320            $sql .= ' AND a.claim_id != 0';
     321        } elseif ( false === $query['claimed'] ) {
     322            $sql .= ' AND a.claim_id = 0';
     323        } elseif ( ! is_null( $query['claimed'] ) ) {
     324            $sql         .= ' AND a.claim_id = %d';
     325            $sql_params[] = $query['claimed'];
    320326        }
    321327
    322328        if ( ! empty( $query['search'] ) ) {
    323             $sql .= " AND (a.hook LIKE %s OR (a.extended_args IS NULL AND a.args LIKE %s) OR a.extended_args LIKE %s";
    324             for( $i = 0; $i < 3; $i++ ) {
     329            $sql .= ' AND (a.hook LIKE %s OR (a.extended_args IS NULL AND a.args LIKE %s) OR a.extended_args LIKE %s';
     330            for ( $i = 0; $i < 3; $i++ ) {
    325331                $sql_params[] = sprintf( '%%%s%%', $query['search'] );
    326332            }
     
    328334            $search_claim_id = (int) $query['search'];
    329335            if ( $search_claim_id ) {
    330                 $sql .= ' OR a.claim_id = %d';
     336                $sql         .= ' OR a.claim_id = %d';
    331337                $sql_params[] = $search_claim_id;
    332338            }
     
    362368            }
    363369
    364             if ( $query[ 'per_page' ] > 0 ) {
    365                 $sql          .= " LIMIT %d, %d";
    366                 $sql_params[] = $query[ 'offset' ];
    367                 $sql_params[] = $query[ 'per_page' ];
     370            if ( $query['per_page'] > 0 ) {
     371                $sql         .= ' LIMIT %d, %d';
     372                $sql_params[] = $query['offset'];
     373                $sql_params[] = $query['per_page'];
    368374            }
    369375        }
    370376
    371377        if ( ! empty( $sql_params ) ) {
    372             $sql = $wpdb->prepare( $sql, $sql_params );
     378            $sql = $wpdb->prepare( $sql, $sql_params ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
    373379        }
    374380
     
    388394     * @return string|array|null The IDs of actions matching the query. Null on failure.
    389395     */
    390     public function query_actions( $query = [], $query_type = 'select' ) {
     396    public function query_actions( $query = array(), $query_type = 'select' ) {
    391397        /** @var wpdb $wpdb */
    392398        global $wpdb;
     
    394400        $sql = $this->get_query_actions_sql( $query, $query_type );
    395401
    396         return ( 'count' === $query_type ) ? $wpdb->get_var( $sql ) : $wpdb->get_col( $sql );
     402        return ( 'count' === $query_type ) ? $wpdb->get_var( $sql ) : $wpdb->get_col( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.NoSql, WordPress.DB.DirectDatabaseQuery.NoCaching
    397403    }
    398404
     
    407413        $sql  = "SELECT a.status, count(a.status) as 'count'";
    408414        $sql .= " FROM {$wpdb->actionscheduler_actions} a";
    409         $sql .= " GROUP BY a.status";
     415        $sql .= ' GROUP BY a.status';
    410416
    411417        $actions_count_by_status = array();
    412418        $action_stati_and_labels = $this->get_status_labels();
    413419
    414         foreach ( $wpdb->get_results( $sql ) as $action_data ) {
    415             // Ignore any actions with invalid status
     420        foreach ( $wpdb->get_results( $sql ) as $action_data ) { // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
     421            // Ignore any actions with invalid status.
    416422            if ( array_key_exists( $action_data->status, $action_stati_and_labels ) ) {
    417423                $actions_count_by_status[ $action_data->status ] = $action_data->count;
     
    428434     *
    429435     * @return void
     436     * @throws \InvalidArgumentException If the action update failed.
    430437     */
    431438    public function cancel_action( $action_id ) {
     
    435442        $updated = $wpdb->update(
    436443            $wpdb->actionscheduler_actions,
    437             [ 'status' => self::STATUS_CANCELED ],
    438             [ 'action_id' => $action_id ],
    439             [ '%s' ],
    440             [ '%d' ]
     444            array( 'status' => self::STATUS_CANCELED ),
     445            array( 'action_id' => $action_id ),
     446            array( '%s' ),
     447            array( '%d' )
    441448        );
    442449        if ( empty( $updated ) ) {
     
    457464     */
    458465    public function cancel_actions_by_hook( $hook ) {
    459         $this->bulk_cancel_actions( [ 'hook' => $hook ] );
     466        $this->bulk_cancel_actions( array( 'hook' => $hook ) );
    460467    }
    461468
     
    468475     */
    469476    public function cancel_actions_by_group( $group ) {
    470         $this->bulk_cancel_actions( [ 'group' => $group ] );
     477        $this->bulk_cancel_actions( array( 'group' => $group ) );
    471478    }
    472479
     
    487494
    488495        // Don't cancel actions that are already canceled.
    489         if ( isset( $query_args['status'] ) && $query_args['status'] == self::STATUS_CANCELED ) {
     496        if ( isset( $query_args['status'] ) && self::STATUS_CANCELED === $query_args['status'] ) {
    490497            return;
    491498        }
     
    494501        $query_args = wp_parse_args(
    495502            $query_args,
    496             [
     503            array(
    497504                'per_page' => 1000,
    498505                'status'   => self::STATUS_PENDING,
    499506                'orderby'  => 'action_id',
    500             ]
     507            )
    501508        );
    502509
     
    513520
    514521            $wpdb->query(
    515                 $wpdb->prepare( // wpcs: PreparedSQLPlaceholders replacement count ok.
    516                     "UPDATE {$wpdb->actionscheduler_actions} SET status = %s WHERE action_id IN {$query_in}",
     522                $wpdb->prepare(
     523                    "UPDATE {$wpdb->actionscheduler_actions} SET status = %s WHERE action_id IN {$query_in}", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
    517524                    $parameters
    518525                )
     
    527534     *
    528535     * @param int $action_id Action ID.
     536     * @throws \InvalidArgumentException If the action deletion failed.
    529537     */
    530538    public function delete_action( $action_id ) {
    531539        /** @var \wpdb $wpdb */
    532540        global $wpdb;
    533         $deleted = $wpdb->delete( $wpdb->actionscheduler_actions, [ 'action_id' => $action_id ], [ '%d' ] );
     541        $deleted = $wpdb->delete( $wpdb->actionscheduler_actions, array( 'action_id' => $action_id ), array( '%d' ) );
    534542        if ( empty( $deleted ) ) {
    535             throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
     543            throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
    536544        }
    537545        do_action( 'action_scheduler_deleted_action', $action_id );
     
    543551     * @param string $action_id Action ID.
    544552     *
    545      * @throws \InvalidArgumentException
    546553     * @return \DateTime The local date the action is scheduled to run, or the date that it ran.
    547554     */
     
    557564     * @param int $action_id Action ID.
    558565     *
    559      * @throws \InvalidArgumentException
     566     * @throws \InvalidArgumentException If action cannot be identified.
    560567     * @return \DateTime The GMT date the action is scheduled to run, or the date that it ran.
    561568     */
     
    565572        $record = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d", $action_id ) );
    566573        if ( empty( $record ) ) {
    567             throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
    568         }
    569         if ( $record->status == self::STATUS_PENDING ) {
     574            throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
     575        }
     576        if ( self::STATUS_PENDING === $record->status ) {
    570577            return as_get_datetime_object( $record->scheduled_date_gmt );
    571578        } else {
     
    579586     * @param int       $max_actions Maximum number of action to include in claim.
    580587     * @param \DateTime $before_date Jobs must be schedule before this date. Defaults to now.
     588     * @param array     $hooks Hooks to filter for.
     589     * @param string    $group Group to filter for.
    581590     *
    582591     * @return ActionScheduler_ActionClaim
     
    587596        $this->claim_before_date = $before_date;
    588597        $this->claim_actions( $claim_id, $max_actions, $before_date, $hooks, $group );
    589         $action_ids = $this->find_actions_by_claim_id( $claim_id );
     598        $action_ids              = $this->find_actions_by_claim_id( $claim_id );
    590599        $this->claim_before_date = null;
    591600
     
    602611        global $wpdb;
    603612        $now = as_get_datetime_object();
    604         $wpdb->insert( $wpdb->actionscheduler_claims, [ 'date_created_gmt' => $now->format( 'Y-m-d H:i:s' ) ] );
     613        $wpdb->insert( $wpdb->actionscheduler_claims, array( 'date_created_gmt' => $now->format( 'Y-m-d H:i:s' ) ) );
    605614
    606615        return $wpdb->insert_id;
     
    613622     * @param int       $limit Number of action to include in claim.
    614623     * @param \DateTime $before_date Should use UTC timezone.
     624     * @param array     $hooks Hooks to filter for.
     625     * @param string    $group Group to filter for.
    615626     *
    616627     * @return int The number of actions that were claimed.
    617      * @throws \RuntimeException
     628     * @throws \InvalidArgumentException Throws InvalidArgumentException if group doesn't exist.
     629     * @throws \RuntimeException Throws RuntimeException if unable to claim action.
    618630     */
    619631    protected function claim_actions( $claim_id, $limit, \DateTime $before_date = null, $hooks = array(), $group = '' ) {
     
    624636        $date = is_null( $before_date ) ? $now : clone $before_date;
    625637
    626         // can't use $wpdb->update() because of the <= condition
     638        // can't use $wpdb->update() because of the <= condition.
    627639        $update = "UPDATE {$wpdb->actionscheduler_actions} SET claim_id=%d, last_attempt_gmt=%s, last_attempt_local=%s";
    628640        $params = array(
     
    632644        );
    633645
    634         $where    = "WHERE claim_id = 0 AND scheduled_date_gmt <= %s AND status=%s";
     646        $where    = 'WHERE claim_id = 0 AND scheduled_date_gmt <= %s AND status=%s';
    635647        $params[] = $date->format( 'Y-m-d H:i:s' );
    636648        $params[] = self::STATUS_PENDING;
     
    646658            $group_id = $this->get_group_id( $group, false );
    647659
    648             // throw exception if no matching group found, this matches ActionScheduler_wpPostStore's behaviour
     660            // throw exception if no matching group found, this matches ActionScheduler_wpPostStore's behaviour.
    649661            if ( empty( $group_id ) ) {
    650662                /* translators: %s: group name */
     
    656668        }
    657669
    658         $order    = "ORDER BY attempts ASC, scheduled_date_gmt ASC, action_id ASC LIMIT %d";
     670        /**
     671         * Sets the order-by clause used in the action claim query.
     672         *
     673         * @since x.x.x
     674         *
     675         * @param string $order_by_sql
     676         */
     677        $order    = apply_filters( 'action_scheduler_claim_actions_order_by', 'ORDER BY attempts ASC, scheduled_date_gmt ASC, action_id ASC' );
    659678        $params[] = $limit;
    660679
    661         $sql = $wpdb->prepare( "{$update} {$where} {$order}", $params );
    662 
    663         $rows_affected = $wpdb->query( $sql );
    664         if ( $rows_affected === false ) {
     680        $sql           = $wpdb->prepare( "{$update} {$where} {$order} LIMIT %d", $params ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders
     681        $rows_affected = $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
     682        if ( false === $rows_affected ) {
    665683            throw new \RuntimeException( __( 'Unable to claim actions. Database error.', 'action-scheduler' ) );
    666684        }
     
    678696
    679697        $sql = "SELECT COUNT(DISTINCT claim_id) FROM {$wpdb->actionscheduler_actions} WHERE claim_id != 0 AND status IN ( %s, %s)";
    680         $sql = $wpdb->prepare( $sql, [ self::STATUS_PENDING, self::STATUS_RUNNING ] );
    681 
    682         return (int) $wpdb->get_var( $sql );
     698        $sql = $wpdb->prepare( $sql, array( self::STATUS_PENDING, self::STATUS_RUNNING ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
     699
     700        return (int) $wpdb->get_var( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
    683701    }
    684702
     
    694712
    695713        $sql = "SELECT claim_id FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d";
    696         $sql = $wpdb->prepare( $sql, $action_id );
    697 
    698         return (int) $wpdb->get_var( $sql );
     714        $sql = $wpdb->prepare( $sql, $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
     715
     716        return (int) $wpdb->get_var( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
    699717    }
    700718
     
    702720     * Retrieve the action IDs of action in a claim.
    703721     *
     722     * @param  int $claim_id Claim ID.
    704723     * @return int[]
    705724     */
     
    719738        // Verify that the scheduled date for each action is within the expected bounds (in some unusual
    720739        // cases, we cannot depend on MySQL to honor all of the WHERE conditions we specify).
    721         foreach ( $wpdb->get_results( $sql ) as $claimed_action ) {
     740        foreach ( $wpdb->get_results( $sql ) as $claimed_action ) { // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
    722741            if ( $claimed_action->scheduled_date_gmt <= $cut_off ) {
    723742                $action_ids[] = absint( $claimed_action->action_id );
     
    736755        /** @var \wpdb $wpdb */
    737756        global $wpdb;
    738         $wpdb->update( $wpdb->actionscheduler_actions, [ 'claim_id' => 0 ], [ 'claim_id' => $claim->get_id() ], [ '%d' ], [ '%d' ] );
    739         $wpdb->delete( $wpdb->actionscheduler_claims, [ 'claim_id' => $claim->get_id() ], [ '%d' ] );
     757        $wpdb->update( $wpdb->actionscheduler_actions, array( 'claim_id' => 0 ), array( 'claim_id' => $claim->get_id() ), array( '%d' ), array( '%d' ) );
     758        $wpdb->delete( $wpdb->actionscheduler_claims, array( 'claim_id' => $claim->get_id() ), array( '%d' ) );
    740759    }
    741760
     
    752771        $wpdb->update(
    753772            $wpdb->actionscheduler_actions,
    754             [ 'claim_id' => 0 ],
    755             [ 'action_id' => $action_id ],
    756             [ '%s' ],
    757             [ '%d' ]
     773            array( 'claim_id' => 0 ),
     774            array( 'action_id' => $action_id ),
     775            array( '%s' ),
     776            array( '%d' )
    758777        );
    759778    }
     
    763782     *
    764783     * @param int $action_id Action ID.
     784     * @throws \InvalidArgumentException Throw an exception if action was not updated.
    765785     */
    766786    public function mark_failure( $action_id ) {
     
    769789        $updated = $wpdb->update(
    770790            $wpdb->actionscheduler_actions,
    771             [ 'status' => self::STATUS_FAILED ],
    772             [ 'action_id' => $action_id ],
    773             [ '%s' ],
    774             [ '%d' ]
     791            array( 'status' => self::STATUS_FAILED ),
     792            array( 'action_id' => $action_id ),
     793            array( '%s' ),
     794            array( '%d' )
    775795        );
    776796        if ( empty( $updated ) ) {
    777             throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
     797            throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
    778798        }
    779799    }
     
    791811
    792812        $sql = "UPDATE {$wpdb->actionscheduler_actions} SET attempts = attempts+1, status=%s, last_attempt_gmt = %s, last_attempt_local = %s WHERE action_id = %d";
    793         $sql = $wpdb->prepare( $sql, self::STATUS_RUNNING, current_time( 'mysql', true ), current_time( 'mysql' ), $action_id );
    794         $wpdb->query( $sql );
     813        $sql = $wpdb->prepare( $sql, self::STATUS_RUNNING, current_time( 'mysql', true ), current_time( 'mysql' ), $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
     814        $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
    795815    }
    796816
     
    801821     *
    802822     * @return void
     823     * @throws \InvalidArgumentException Throw an exception if action was not updated.
    803824     */
    804825    public function mark_complete( $action_id ) {
     
    807828        $updated = $wpdb->update(
    808829            $wpdb->actionscheduler_actions,
    809             [
     830            array(
    810831                'status'             => self::STATUS_COMPLETE,
    811832                'last_attempt_gmt'   => current_time( 'mysql', true ),
    812833                'last_attempt_local' => current_time( 'mysql' ),
    813             ],
    814             [ 'action_id' => $action_id ],
    815             [ '%s' ],
    816             [ '%d' ]
     834            ),
     835            array( 'action_id' => $action_id ),
     836            array( '%s' ),
     837            array( '%d' )
    817838        );
    818839        if ( empty( $updated ) ) {
    819             throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
     840            throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
    820841        }
    821842    }
     
    827848     *
    828849     * @return string
     850     * @throws \InvalidArgumentException Throw an exception if not status was found for action_id.
     851     * @throws \RuntimeException Throw an exception if action status could not be retrieved.
    829852     */
    830853    public function get_status( $action_id ) {
     
    832855        global $wpdb;
    833856        $sql    = "SELECT status FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d";
    834         $sql    = $wpdb->prepare( $sql, $action_id );
    835         $status = $wpdb->get_var( $sql );
    836 
    837         if ( $status === null ) {
     857        $sql    = $wpdb->prepare( $sql, $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
     858        $status = $wpdb->get_var( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
     859
     860        if ( null === $status ) {
    838861            throw new \InvalidArgumentException( __( 'Invalid action ID. No status found.', 'action-scheduler' ) );
    839862        } elseif ( empty( $status ) ) {
  • action-scheduler/trunk/classes/data-stores/ActionScheduler_wpPostStore.php

    r2599552 r2622865  
    55 */
    66class ActionScheduler_wpPostStore extends ActionScheduler_Store {
    7     const POST_TYPE = 'scheduled-action';
    8     const GROUP_TAXONOMY = 'action-group';
     7    const POST_TYPE         = 'scheduled-action';
     8    const GROUP_TAXONOMY    = 'action-group';
    99    const SCHEDULE_META_KEY = '_action_manager_schedule';
    10     const DEPENDENCIES_MET = 'as-post-store-dependencies-met';
     10    const DEPENDENCIES_MET  = 'as-post-store-dependencies-met';
    1111
    1212    /**
     
    2020    private $claim_before_date = null;
    2121
    22     /** @var DateTimeZone */
    23     protected $local_timezone = NULL;
    24 
    25     public function save_action( ActionScheduler_Action $action, DateTime $scheduled_date = NULL ){
     22    /**
     23     * Local Timezone.
     24     *
     25     * @var DateTimeZone
     26     */
     27    protected $local_timezone = null;
     28
     29    /**
     30     * Save action.
     31     *
     32     * @param ActionScheduler_Action $action Scheduled Action.
     33     * @param DateTime               $scheduled_date Scheduled Date.
     34     *
     35     * @throws RuntimeException Throws an exception if the action could not be saved.
     36     * @return int
     37     */
     38    public function save_action( ActionScheduler_Action $action, DateTime $scheduled_date = null ) {
    2639        try {
    2740            $this->validate_action( $action );
    2841            $post_array = $this->create_post_array( $action, $scheduled_date );
    29             $post_id = $this->save_post_array( $post_array );
     42            $post_id    = $this->save_post_array( $post_array );
    3043            $this->save_post_schedule( $post_id, $action->get_schedule() );
    3144            $this->save_action_group( $post_id, $action->get_group() );
     
    3346            return $post_id;
    3447        } catch ( Exception $e ) {
     48            /* translators: %s: action error message */
    3549            throw new RuntimeException( sprintf( __( 'Error saving action: %s', 'action-scheduler' ), $e->getMessage() ), 0 );
    3650        }
    3751    }
    3852
    39     protected function create_post_array( ActionScheduler_Action $action, DateTime $scheduled_date = NULL ) {
     53    /**
     54     * Create post array.
     55     *
     56     * @param ActionScheduler_Action $action Scheduled Action.
     57     * @param DateTime               $scheduled_date Scheduled Date.
     58     *
     59     * @return array Returns an array of post data.
     60     */
     61    protected function create_post_array( ActionScheduler_Action $action, DateTime $scheduled_date = null ) {
    4062        $post = array(
    41             'post_type' => self::POST_TYPE,
    42             'post_title' => $action->get_hook(),
    43             'post_content' => json_encode($action->get_args()),
    44             'post_status' => ( $action->is_finished() ? 'publish' : 'pending' ),
     63            'post_type'     => self::POST_TYPE,
     64            'post_title'    => $action->get_hook(),
     65            'post_content'  => wp_json_encode( $action->get_args() ),
     66            'post_status'   => ( $action->is_finished() ? 'publish' : 'pending' ),
    4567            'post_date_gmt' => $this->get_scheduled_date_string( $action, $scheduled_date ),
    4668            'post_date'     => $this->get_scheduled_date_string_local( $action, $scheduled_date ),
     
    4971    }
    5072
     73    /**
     74     * Save post array.
     75     *
     76     * @param array $post_array Post array.
     77     * @return int Returns the post ID.
     78     * @throws RuntimeException Throws an exception if the action could not be saved.
     79     */
    5180    protected function save_post_array( $post_array ) {
    5281        add_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10, 1 );
     
    6089        }
    6190
    62         $post_id = wp_insert_post($post_array);
     91        $post_id = wp_insert_post( $post_array );
    6392
    6493        if ( $has_kses ) {
     
    6998        remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 );
    7099
    71         if ( is_wp_error($post_id) || empty($post_id) ) {
     100        if ( is_wp_error( $post_id ) || empty( $post_id ) ) {
    72101            throw new RuntimeException( __( 'Unable to save action.', 'action-scheduler' ) );
    73102        }
     
    75104    }
    76105
     106    /**
     107     * Filter insert post data.
     108     *
     109     * @param array $postdata Post data to filter.
     110     *
     111     * @return array
     112     */
    77113    public function filter_insert_post_data( $postdata ) {
    78         if ( $postdata['post_type'] == self::POST_TYPE ) {
     114        if ( self::POST_TYPE === $postdata['post_type'] ) {
    79115            $postdata['post_author'] = 0;
    80             if ( $postdata['post_status'] == 'future' ) {
     116            if ( 'future' === $postdata['post_status'] ) {
    81117                $postdata['post_status'] = 'publish';
    82118            }
     
    114150     */
    115151    public function set_unique_post_slug( $override_slug, $slug, $post_ID, $post_status, $post_type ) {
    116         if ( self::POST_TYPE == $post_type ) {
     152        if ( self::POST_TYPE === $post_type ) {
    117153            $override_slug = uniqid( self::POST_TYPE . '-', true ) . '-' . wp_generate_password( 32, false );
    118154        }
     
    120156    }
    121157
     158    /**
     159     * Save post schedule.
     160     *
     161     * @param int    $post_id  Post ID of the scheduled action.
     162     * @param string $schedule Schedule to save.
     163     *
     164     * @return void
     165     */
    122166    protected function save_post_schedule( $post_id, $schedule ) {
    123167        update_post_meta( $post_id, self::SCHEDULE_META_KEY, $schedule );
    124168    }
    125169
     170    /**
     171     * Save action group.
     172     *
     173     * @param int    $post_id Post ID.
     174     * @param string $group   Group to save.
     175     * @return void
     176     */
    126177    protected function save_action_group( $post_id, $group ) {
    127         if ( empty($group) ) {
    128             wp_set_object_terms( $post_id, array(), self::GROUP_TAXONOMY, FALSE );
     178        if ( empty( $group ) ) {
     179            wp_set_object_terms( $post_id, array(), self::GROUP_TAXONOMY, false );
    129180        } else {
    130             wp_set_object_terms( $post_id, array($group), self::GROUP_TAXONOMY, FALSE );
    131         }
    132     }
    133 
     181            wp_set_object_terms( $post_id, array( $group ), self::GROUP_TAXONOMY, false );
     182        }
     183    }
     184
     185    /**
     186     * Fetch actions.
     187     *
     188     * @param int $action_id Action ID.
     189     * @return object
     190     */
    134191    public function fetch_action( $action_id ) {
    135192        $post = $this->get_post( $action_id );
    136         if ( empty($post) || $post->post_type != self::POST_TYPE ) {
     193        if ( empty( $post ) || self::POST_TYPE !== $post->post_type ) {
    137194            return $this->get_null_action();
    138195        }
     
    148205    }
    149206
     207    /**
     208     * Get post.
     209     *
     210     * @param string $action_id - Action ID.
     211     * @return WP_Post|null
     212     */
    150213    protected function get_post( $action_id ) {
    151         if ( empty($action_id) ) {
    152             return NULL;
    153         }
    154         return get_post($action_id);
    155     }
    156 
     214        if ( empty( $action_id ) ) {
     215            return null;
     216        }
     217        return get_post( $action_id );
     218    }
     219
     220    /**
     221     * Get NULL action.
     222     *
     223     * @return ActionScheduler_NullAction
     224     */
    157225    protected function get_null_action() {
    158226        return new ActionScheduler_NullAction();
    159227    }
    160228
     229    /**
     230     * Make action from post.
     231     *
     232     * @param WP_Post $post Post object.
     233     * @return WP_Post
     234     */
    161235    protected function make_action_from_post( $post ) {
    162236        $hook = $post->post_title;
     
    168242        $this->validate_schedule( $schedule, $post->ID );
    169243
    170         $group = wp_get_object_terms( $post->ID, self::GROUP_TAXONOMY, array('fields' => 'names') );
    171         $group = empty( $group ) ? '' : reset($group);
     244        $group = wp_get_object_terms( $post->ID, self::GROUP_TAXONOMY, array( 'fields' => 'names' ) );
     245        $group = empty( $group ) ? '' : reset( $group );
    172246
    173247        return ActionScheduler::factory()->get_stored_action( $this->get_action_status_by_post_status( $post->post_status ), $hook, $args, $schedule, $group );
     
    175249
    176250    /**
    177      * @param string $post_status
    178      *
    179      * @throws InvalidArgumentException if $post_status not in known status fields returned by $this->get_status_labels()
     251     * Get action status by post status.
     252     *
     253     * @param string $post_status Post status.
     254     *
     255     * @throws InvalidArgumentException Throw InvalidArgumentException if $post_status not in known status fields returned by $this->get_status_labels().
    180256     * @return string
    181257     */
     
    183259
    184260        switch ( $post_status ) {
    185             case 'publish' :
     261            case 'publish':
    186262                $action_status = self::STATUS_COMPLETE;
    187263                break;
    188             case 'trash' :
     264            case 'trash':
    189265                $action_status = self::STATUS_CANCELED;
    190266                break;
    191             default :
     267            default:
    192268                if ( ! array_key_exists( $post_status, $this->get_status_labels() ) ) {
    193269                    throw new InvalidArgumentException( sprintf( 'Invalid post status: "%s". No matching action status available.', $post_status ) );
     
    201277
    202278    /**
    203      * @param string $action_status
    204      * @throws InvalidArgumentException if $post_status not in known status fields returned by $this->get_status_labels()
     279     * Get post status by action status.
     280     *
     281     * @param string $action_status Action status.
     282     *
     283     * @throws InvalidArgumentException Throws InvalidArgumentException if $post_status not in known status fields returned by $this->get_status_labels().
    205284     * @return string
    206285     */
     
    208287
    209288        switch ( $action_status ) {
    210             case self::STATUS_COMPLETE :
     289            case self::STATUS_COMPLETE:
    211290                $post_status = 'publish';
    212291                break;
    213             case self::STATUS_CANCELED :
     292            case self::STATUS_CANCELED:
    214293                $post_status = 'trash';
    215294                break;
    216             default :
     295            default:
    217296                if ( ! array_key_exists( $action_status, $this->get_status_labels() ) ) {
    218297                    throw new InvalidArgumentException( sprintf( 'Invalid action status: "%s".', $action_status ) );
     
    228307     * Returns the SQL statement to query (or count) actions.
    229308     *
    230      * @param array $query Filtering options
    231      * @param string $select_or_count  Whether the SQL should select and return the IDs or just the row count
    232      * @throws InvalidArgumentException if $select_or_count not count or select
     309     * @param array  $query            - Filtering options.
     310     * @param string $select_or_count  - Whether the SQL should select and return the IDs or just the row count.
     311     *
     312     * @throws InvalidArgumentException - Throw InvalidArgumentException if $select_or_count not count or select.
    233313     * @return string SQL statement. The returned SQL is already properly escaped.
    234314     */
    235315    protected function get_query_actions_sql( array $query, $select_or_count = 'select' ) {
    236316
    237         if ( ! in_array( $select_or_count, array( 'select', 'count' ) ) ) {
     317        if ( ! in_array( $select_or_count, array( 'select', 'count' ), true ) ) {
    238318            throw new InvalidArgumentException( __( 'Invalid schedule. Cannot save action.', 'action-scheduler' ) );
    239319        }
    240320
    241         $query = wp_parse_args( $query, array(
    242             'hook' => '',
    243             'args' => NULL,
    244             'date' => NULL,
    245             'date_compare' => '<=',
    246             'modified' => NULL,
    247             'modified_compare' => '<=',
    248             'group' => '',
    249             'status' => '',
    250             'claimed' => NULL,
    251             'per_page' => 5,
    252             'offset' => 0,
    253             'orderby' => 'date',
    254             'order' => 'ASC',
    255             'search' => '',
    256         ) );
    257 
    258         /** @var wpdb $wpdb */
     321        $query = wp_parse_args(
     322            $query,
     323            array(
     324                'hook'             => '',
     325                'args'             => null,
     326                'date'             => null,
     327                'date_compare'     => '<=',
     328                'modified'         => null,
     329                'modified_compare' => '<=',
     330                'group'            => '',
     331                'status'           => '',
     332                'claimed'          => null,
     333                'per_page'         => 5,
     334                'offset'           => 0,
     335                'orderby'          => 'date',
     336                'order'            => 'ASC',
     337                'search'           => '',
     338            )
     339        );
     340
     341        /**
     342         * Global wpdb object.
     343         *
     344         * @var wpdb $wpdb
     345         */
    259346        global $wpdb;
    260         $sql  = ( 'count' === $select_or_count ) ? 'SELECT count(p.ID)' : 'SELECT p.ID ';
    261         $sql .= "FROM {$wpdb->posts} p";
     347        $sql        = ( 'count' === $select_or_count ) ? 'SELECT count(p.ID)' : 'SELECT p.ID ';
     348        $sql       .= "FROM {$wpdb->posts} p";
    262349        $sql_params = array();
    263350        if ( empty( $query['group'] ) && 'group' === $query['orderby'] ) {
     
    266353            $sql .= " LEFT JOIN {$wpdb->terms} t ON tt.term_id=t.term_id";
    267354        } elseif ( ! empty( $query['group'] ) ) {
    268             $sql .= " INNER JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID";
    269             $sql .= " INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id";
    270             $sql .= " INNER JOIN {$wpdb->terms} t ON tt.term_id=t.term_id";
    271             $sql .= " AND t.slug=%s";
     355            $sql         .= " INNER JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID";
     356            $sql         .= " INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id";
     357            $sql         .= " INNER JOIN {$wpdb->terms} t ON tt.term_id=t.term_id";
     358            $sql         .= ' AND t.slug=%s';
    272359            $sql_params[] = $query['group'];
    273360        }
    274         $sql .= " WHERE post_type=%s";
     361        $sql         .= ' WHERE post_type=%s';
    275362        $sql_params[] = self::POST_TYPE;
    276363        if ( $query['hook'] ) {
    277             $sql .= " AND p.post_title=%s";
     364            $sql         .= ' AND p.post_title=%s';
    278365            $sql_params[] = $query['hook'];
    279366        }
    280         if ( !is_null($query['args']) ) {
    281             $sql .= " AND p.post_content=%s";
    282             $sql_params[] = json_encode($query['args']);
     367        if ( ! is_null( $query['args'] ) ) {
     368            $sql         .= ' AND p.post_content=%s';
     369            $sql_params[] = wp_json_encode( $query['args'] );
    283370        }
    284371
     
    292379        if ( $query['date'] instanceof DateTime ) {
    293380            $date = clone $query['date'];
    294             $date->setTimezone( new DateTimeZone('UTC') );
    295             $date_string = $date->format('Y-m-d H:i:s');
    296             $comparator = $this->validate_sql_comparator($query['date_compare']);
    297             $sql .= " AND p.post_date_gmt $comparator %s";
     381            $date->setTimezone( new DateTimeZone( 'UTC' ) );
     382            $date_string  = $date->format( 'Y-m-d H:i:s' );
     383            $comparator   = $this->validate_sql_comparator( $query['date_compare'] );
     384            $sql         .= " AND p.post_date_gmt $comparator %s";
    298385            $sql_params[] = $date_string;
    299386        }
     
    301388        if ( $query['modified'] instanceof DateTime ) {
    302389            $modified = clone $query['modified'];
    303             $modified->setTimezone( new DateTimeZone('UTC') );
    304             $date_string = $modified->format('Y-m-d H:i:s');
    305             $comparator = $this->validate_sql_comparator($query['modified_compare']);
    306             $sql .= " AND p.post_modified_gmt $comparator %s";
     390            $modified->setTimezone( new DateTimeZone( 'UTC' ) );
     391            $date_string  = $modified->format( 'Y-m-d H:i:s' );
     392            $comparator   = $this->validate_sql_comparator( $query['modified_compare'] );
     393            $sql         .= " AND p.post_modified_gmt $comparator %s";
    307394            $sql_params[] = $date_string;
    308395        }
    309396
    310         if ( $query['claimed'] === TRUE ) {
     397        if ( true === $query['claimed'] ) {
    311398            $sql .= " AND p.post_password != ''";
    312         } elseif ( $query['claimed'] === FALSE ) {
     399        } elseif ( false === $query['claimed'] ) {
    313400            $sql .= " AND p.post_password = ''";
    314         } elseif ( !is_null($query['claimed']) ) {
    315             $sql .= " AND p.post_password = %s";
     401        } elseif ( ! is_null( $query['claimed'] ) ) {
     402            $sql         .= ' AND p.post_password = %s';
    316403            $sql_params[] = $query['claimed'];
    317404        }
    318405
    319406        if ( ! empty( $query['search'] ) ) {
    320             $sql .= " AND (p.post_title LIKE %s OR p.post_content LIKE %s OR p.post_password LIKE %s)";
    321             for( $i = 0; $i < 3; $i++ ) {
     407            $sql .= ' AND (p.post_title LIKE %s OR p.post_content LIKE %s OR p.post_password LIKE %s)';
     408            for ( $i = 0; $i < 3; $i++ ) {
    322409                $sql_params[] = sprintf( '%%%s%%', $query['search'] );
    323410            }
     
    354441            $sql .= " ORDER BY $orderby $order";
    355442            if ( $query['per_page'] > 0 ) {
    356                 $sql .= " LIMIT %d, %d";
     443                $sql         .= ' LIMIT %d, %d';
    357444                $sql_params[] = $query['offset'];
    358445                $sql_params[] = $query['per_page'];
     
    360447        }
    361448
    362         return $wpdb->prepare( $sql, $sql_params );
     449        return $wpdb->prepare( $sql, $sql_params ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
    363450    }
    364451
     
    376463     */
    377464    public function query_actions( $query = array(), $query_type = 'select' ) {
    378         /** @var wpdb $wpdb */
     465        /**
     466         * Global $wpdb object.
     467         *
     468         * @var wpdb $wpdb
     469         */
    379470        global $wpdb;
    380471
    381472        $sql = $this->get_query_actions_sql( $query, $query_type );
    382473
    383         return ( 'count' === $query_type ) ? $wpdb->get_var( $sql ) : $wpdb->get_col( $sql );
     474        return ( 'count' === $query_type ) ? $wpdb->get_var( $sql ) : $wpdb->get_col( $sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared
    384475    }
    385476
     
    400491                $action_status_name = $this->get_action_status_by_post_status( $post_status_name );
    401492            } catch ( Exception $e ) {
    402                 // Ignore any post statuses that aren't for actions
     493                // Ignore any post statuses that aren't for actions.
    403494                continue;
    404495            }
     
    412503
    413504    /**
    414      * @param string $action_id
    415      *
    416      * @throws InvalidArgumentException
     505     * Cancel action.
     506     *
     507     * @param int $action_id Action ID.
     508     *
     509     * @throws InvalidArgumentException If $action_id is not identified.
    417510     */
    418511    public function cancel_action( $action_id ) {
    419512        $post = get_post( $action_id );
    420         if ( empty( $post ) || ( $post->post_type != self::POST_TYPE ) ) {
     513        if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) {
     514            /* translators: %s is the action ID */
    421515            throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
    422516        }
     
    427521    }
    428522
     523    /**
     524     * Delete action.
     525     *
     526     * @param int $action_id Action ID.
     527     * @return void
     528     * @throws InvalidArgumentException If action is not identified.
     529     */
    429530    public function delete_action( $action_id ) {
    430531        $post = get_post( $action_id );
    431         if ( empty( $post ) || ( $post->post_type != self::POST_TYPE ) ) {
     532        if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) {
     533            /* translators: %s is the action ID */
    432534            throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
    433535        }
    434536        do_action( 'action_scheduler_deleted_action', $action_id );
    435537
    436         wp_delete_post( $action_id, TRUE );
    437     }
    438 
    439     /**
    440      * @param string $action_id
    441      *
    442      * @throws InvalidArgumentException
     538        wp_delete_post( $action_id, true );
     539    }
     540
     541    /**
     542     * Get date for claim id.
     543     *
     544     * @param int $action_id Action ID.
    443545     * @return ActionScheduler_DateTime The date the action is schedule to run, or the date that it ran.
    444546     */
     
    449551
    450552    /**
    451      * @param string $action_id
    452      *
    453      * @throws InvalidArgumentException
     553     * Get Date GMT.
     554     *
     555     * @param int $action_id Action ID.
     556     *
     557     * @throws InvalidArgumentException If $action_id is not identified.
    454558     * @return ActionScheduler_DateTime The date the action is schedule to run, or the date that it ran.
    455559     */
    456560    public function get_date_gmt( $action_id ) {
    457561        $post = get_post( $action_id );
    458         if ( empty( $post ) || ( $post->post_type != self::POST_TYPE ) ) {
     562        if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) {
     563            /* translators: %s is the action ID */
    459564            throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
    460565        }
    461         if ( $post->post_status == 'publish' ) {
     566        if ( 'publish' === $post->post_status ) {
    462567            return as_get_datetime_object( $post->post_modified_gmt );
    463568        } else {
     
    467572
    468573    /**
    469      * @param int      $max_actions
     574     * Stake claim.
     575     *
     576     * @param int      $max_actions Maximum number of actions.
    470577     * @param DateTime $before_date Jobs must be schedule before this date. Defaults to now.
    471578     * @param array    $hooks       Claim only actions with a hook or hooks.
     
    478585    public function stake_claim( $max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '' ) {
    479586        $this->claim_before_date = $before_date;
    480         $claim_id = $this->generate_claim_id();
     587        $claim_id                = $this->generate_claim_id();
    481588        $this->claim_actions( $claim_id, $max_actions, $before_date, $hooks, $group );
    482         $action_ids = $this->find_actions_by_claim_id( $claim_id );
     589        $action_ids              = $this->find_actions_by_claim_id( $claim_id );
    483590        $this->claim_before_date = null;
    484591
     
    487594
    488595    /**
     596     * Get claim count.
     597     *
    489598     * @return int
    490599     */
    491     public function get_claim_count(){
     600    public function get_claim_count() {
    492601        global $wpdb;
    493602
    494         $sql = "SELECT COUNT(DISTINCT post_password) FROM {$wpdb->posts} WHERE post_password != '' AND post_type = %s AND post_status IN ('in-progress','pending')";
    495         $sql = $wpdb->prepare( $sql, array( self::POST_TYPE ) );
    496 
    497         return $wpdb->get_var( $sql );
    498     }
    499 
     603        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
     604        return $wpdb->get_var(
     605            $wpdb->prepare(
     606                "SELECT COUNT(DISTINCT post_password) FROM {$wpdb->posts} WHERE post_password != '' AND post_type = %s AND post_status IN ('in-progress','pending')",
     607                array( self::POST_TYPE )
     608            )
     609        );
     610    }
     611
     612    /**
     613     * Generate claim id.
     614     *
     615     * @return string
     616     */
    500617    protected function generate_claim_id() {
    501         $claim_id = md5(microtime(true) . rand(0,1000));
    502         return substr($claim_id, 0, 20); // to fit in db field with 20 char limit
    503     }
    504 
    505     /**
    506      * @param string   $claim_id
    507      * @param int      $limit
     618        $claim_id = md5( microtime( true ) . wp_rand( 0, 1000 ) );
     619        return substr( $claim_id, 0, 20 ); // to fit in db field with 20 char limit.
     620    }
     621
     622    /**
     623     * Claim actions.
     624     *
     625     * @param string   $claim_id    Claim ID.
     626     * @param int      $limit       Limit.
    508627     * @param DateTime $before_date Should use UTC timezone.
    509628     * @param array    $hooks       Claim only actions with a hook or hooks.
    510629     * @param string   $group       Claim only actions in the given group.
    511630     *
    512      * @return int The number of actions that were claimed
    513      * @throws RuntimeException When there is a database error.
    514      * @throws InvalidArgumentException When the group is invalid.
     631     * @return int The number of actions that were claimed.
     632     * @throws RuntimeException  When there is a database error.
    515633     */
    516634    protected function claim_actions( $claim_id, $limit, DateTime $before_date = null, $hooks = array(), $group = '' ) {
     
    525643        }
    526644
    527         /** @var wpdb $wpdb */
     645        /**
     646         * Global wpdb object.
     647         *
     648         * @var wpdb $wpdb
     649         */
    528650        global $wpdb;
    529651
     
    560682            $where .= ' AND ID IN (' . join( ',', $ids ) . ')';
    561683        } else {
    562             $where .= ' AND post_date_gmt <= %s';
     684            $where   .= ' AND post_date_gmt <= %s';
    563685            $params[] = $date->format( 'Y-m-d H:i:s' );
    564686        }
     
    569691
    570692        // Run the query and gather results.
    571         $rows_affected = $wpdb->query( $wpdb->prepare( "{$update} {$where} {$order}", $params ) );
    572         if ( $rows_affected === false ) {
     693        $rows_affected = $wpdb->query( $wpdb->prepare( "{$update} {$where} {$order}", $params ) ); // phpcs:ignore // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
     694
     695        if ( false === $rows_affected ) {
    573696            throw new RuntimeException( __( 'Unable to claim actions. Database error.', 'action-scheduler' ) );
    574697        }
     
    590713    protected function get_actions_by_group( $group, $limit, DateTime $date ) {
    591714        // Ensure the group exists before continuing.
    592         if ( ! term_exists( $group, self::GROUP_TAXONOMY )) {
     715        if ( ! term_exists( $group, self::GROUP_TAXONOMY ) ) {
     716            /* translators: %s is the group name */
    593717            throw new InvalidArgumentException( sprintf( __( 'The group "%s" does not exist.', 'action-scheduler' ), $group ) );
    594718        }
     
    610734            ),
    611735            'date_query'       => array(
    612                 'column' => 'post_date_gmt',
    613                 'before' => $date->format( 'Y-m-d H:i' ),
     736                'column'    => 'post_date_gmt',
     737                'before'    => $date->format( 'Y-m-d H:i' ),
    614738                'inclusive' => true,
    615739            ),
    616             'tax_query' => array(
     740            'tax_query'        => array( // phpcs:ignore WordPress.DB.SlowDBQuery
    617741                array(
    618742                    'taxonomy'         => self::GROUP_TAXONOMY,
     
    628752
    629753    /**
    630      * @param string $claim_id
     754     * Find actions by claim ID.
     755     *
     756     * @param string $claim_id Claim ID.
    631757     * @return array
    632758     */
    633759    public function find_actions_by_claim_id( $claim_id ) {
    634         /** @var wpdb $wpdb */
     760        /**
     761         * Global wpdb object.
     762         *
     763         * @var wpdb $wpdb
     764         */
    635765        global $wpdb;
    636 
    637         $sql = "SELECT ID, post_date_gmt FROM {$wpdb->posts} WHERE post_type = %s AND post_password = %s";
    638         $sql = $wpdb->prepare( $sql, array( self::POST_TYPE, $claim_id ) );
    639766
    640767        $action_ids  = array();
     
    642769        $cut_off     = $before_date->format( 'Y-m-d H:i:s' );
    643770
     771        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
     772        $results = $wpdb->get_results(
     773            $wpdb->prepare(
     774                "SELECT ID, post_date_gmt FROM {$wpdb->posts} WHERE post_type = %s AND post_password = %s",
     775                array(
     776                    self::POST_TYPE,
     777                    $claim_id,
     778                )
     779            )
     780        );
     781
    644782        // Verify that the scheduled date for each action is within the expected bounds (in some unusual
    645783        // cases, we cannot depend on MySQL to honor all of the WHERE conditions we specify).
    646         foreach ( $wpdb->get_results( $sql ) as $claimed_action ) {
     784        foreach ( $results as $claimed_action ) {
    647785            if ( $claimed_action->post_date_gmt <= $cut_off ) {
    648786                $action_ids[] = absint( $claimed_action->ID );
     
    653791    }
    654792
     793    /**
     794     * Release claim.
     795     *
     796     * @param ActionScheduler_ActionClaim $claim Claim object to release.
     797     * @return void
     798     * @throws RuntimeException When the claim is not unlocked.
     799     */
    655800    public function release_claim( ActionScheduler_ActionClaim $claim ) {
    656801        $action_ids = $this->find_actions_by_claim_id( $claim->get_id() );
    657802        if ( empty( $action_ids ) ) {
    658             return; // nothing to do
     803            return; // nothing to do.
    659804        }
    660805        $action_id_string = implode( ',', array_map( 'intval', $action_ids ) );
    661         /** @var wpdb $wpdb */
     806        /**
     807         * Global wpdb object.
     808         *
     809         * @var wpdb $wpdb
     810         */
    662811        global $wpdb;
    663         $sql = "UPDATE {$wpdb->posts} SET post_password = '' WHERE ID IN ($action_id_string) AND post_password = %s";
    664         $sql = $wpdb->prepare( $sql, array( $claim->get_id() ) );
    665         $result = $wpdb->query( $sql );
    666         if ( $result === false ) {
     812
     813        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
     814        $result = $wpdb->query(
     815            $wpdb->prepare(
     816                "UPDATE {$wpdb->posts} SET post_password = '' WHERE ID IN ($action_id_string) AND post_password = %s", //phpcs:ignore
     817                array(
     818                    $claim->get_id(),
     819                )
     820            )
     821        );
     822        if ( false === $result ) {
    667823            /* translators: %s: claim ID */
    668824            throw new RuntimeException( sprintf( __( 'Unable to unlock claim %s. Database error.', 'action-scheduler' ), $claim->get_id() ) );
     
    671827
    672828    /**
    673      * @param string $action_id
     829     * Unclaim action.
     830     *
     831     * @param string $action_id Action ID.
     832     * @throws RuntimeException When unable to unlock claim on action ID.
    674833     */
    675834    public function unclaim_action( $action_id ) {
    676         /** @var wpdb $wpdb */
     835        /**
     836         * Global wpdb object.
     837         *
     838         * @var wpdb $wpdb
     839         */
    677840        global $wpdb;
    678         $sql = "UPDATE {$wpdb->posts} SET post_password = '' WHERE ID = %d AND post_type = %s";
    679         $sql = $wpdb->prepare( $sql, $action_id, self::POST_TYPE );
    680         $result = $wpdb->query( $sql );
    681         if ( $result === false ) {
     841
     842        //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
     843        $result = $wpdb->query(
     844            $wpdb->prepare(
     845                "UPDATE {$wpdb->posts} SET post_password = '' WHERE ID = %d AND post_type = %s",
     846                $action_id,
     847                self::POST_TYPE
     848            )
     849        );
     850        if ( false === $result ) {
    682851            /* translators: %s: action ID */
    683852            throw new RuntimeException( sprintf( __( 'Unable to unlock claim on action %s. Database error.', 'action-scheduler' ), $action_id ) );
     
    685854    }
    686855
     856    /**
     857     * Mark failure on action.
     858     *
     859     * @param int $action_id Action ID.
     860     *
     861     * @return void
     862     * @throws RuntimeException When unable to mark failure on action ID.
     863     */
    687864    public function mark_failure( $action_id ) {
    688         /** @var wpdb $wpdb */
     865        /**
     866         * Global wpdb object.
     867         *
     868         * @var wpdb $wpdb
     869         */
    689870        global $wpdb;
    690         $sql = "UPDATE {$wpdb->posts} SET post_status = %s WHERE ID = %d AND post_type = %s";
    691         $sql = $wpdb->prepare( $sql, self::STATUS_FAILED, $action_id, self::POST_TYPE );
    692         $result = $wpdb->query( $sql );
    693         if ( $result === false ) {
     871
     872        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
     873        $result = $wpdb->query(
     874            $wpdb->prepare( "UPDATE {$wpdb->posts} SET post_status = %s WHERE ID = %d AND post_type = %s", self::STATUS_FAILED, $action_id, self::POST_TYPE )
     875        );
     876        if ( false === $result ) {
    694877            /* translators: %s: action ID */
    695878            throw new RuntimeException( sprintf( __( 'Unable to mark failure on action %s. Database error.', 'action-scheduler' ), $action_id ) );
     
    700883     * Return an action's claim ID, as stored in the post password column
    701884     *
    702      * @param string $action_id
     885     * @param int $action_id Action ID.
    703886     * @return mixed
    704887     */
     
    710893     * Return an action's status, as stored in the post status column
    711894     *
    712      * @param string $action_id
     895     * @param int $action_id Action ID.
     896     *
    713897     * @return mixed
     898     * @throws InvalidArgumentException When the action ID is invalid.
    714899     */
    715900    public function get_status( $action_id ) {
    716901        $status = $this->get_post_column( $action_id, 'post_status' );
    717902
    718         if ( $status === null ) {
     903        if ( null === $status ) {
    719904            throw new InvalidArgumentException( __( 'Invalid action ID. No status found.', 'action-scheduler' ) );
    720905        }
     
    723908    }
    724909
     910    /**
     911     * Get post column
     912     *
     913     * @param string $action_id Action ID.
     914     * @param string $column_name Column Name.
     915     *
     916     * @return string|null
     917     */
    725918    private function get_post_column( $action_id, $column_name ) {
    726         /** @var \wpdb $wpdb */
     919        /**
     920         * Global wpdb object.
     921         *
     922         * @var wpdb $wpdb
     923         */
    727924        global $wpdb;
    728         return $wpdb->get_var( $wpdb->prepare( "SELECT {$column_name} FROM {$wpdb->posts} WHERE ID=%d AND post_type=%s", $action_id, self::POST_TYPE ) );
    729     }
    730 
    731     /**
    732      * @param string $action_id
     925
     926        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
     927        return $wpdb->get_var(
     928            $wpdb->prepare(
     929                "SELECT {$column_name} FROM {$wpdb->posts} WHERE ID=%d AND post_type=%s", // phpcs:ignore
     930                $action_id,
     931                self::POST_TYPE
     932            )
     933        );
     934    }
     935
     936    /**
     937     * Log Execution.
     938     *
     939     * @param string $action_id Action ID.
    733940     */
    734941    public function log_execution( $action_id ) {
    735         /** @var wpdb $wpdb */
     942        /**
     943         * Global wpdb object.
     944         *
     945         * @var wpdb $wpdb
     946         */
    736947        global $wpdb;
    737948
    738         $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";
    739         $sql = $wpdb->prepare( $sql, self::STATUS_RUNNING, current_time('mysql', true), current_time('mysql'), $action_id, self::POST_TYPE );
    740         $wpdb->query($sql);
     949        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
     950        $wpdb->query(
     951            $wpdb->prepare(
     952                "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",
     953                self::STATUS_RUNNING,
     954                current_time( 'mysql', true ),
     955                current_time( 'mysql' ),
     956                $action_id,
     957                self::POST_TYPE
     958            )
     959        );
    741960    }
    742961
     
    744963     * Record that an action was completed.
    745964     *
    746      * @param int $action_id ID of the completed action.
    747      * @throws InvalidArgumentException|RuntimeException
     965     * @param string $action_id ID of the completed action.
     966     *
     967     * @throws InvalidArgumentException When the action ID is invalid.
     968     * @throws RuntimeException         When there was an error executing the action.
    748969     */
    749970    public function mark_complete( $action_id ) {
    750971        $post = get_post( $action_id );
    751         if ( empty( $post ) || ( $post->post_type != self::POST_TYPE ) ) {
     972        if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) {
     973            /* translators: %s is the action ID */
    752974            throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
    753975        }
    754976        add_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10, 1 );
    755977        add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 );
    756         $result = wp_update_post(array(
    757             'ID' => $action_id,
    758             'post_status' => 'publish',
    759         ), TRUE);
     978        $result = wp_update_post(
     979            array(
     980                'ID'          => $action_id,
     981                'post_status' => 'publish',
     982            ),
     983            true
     984        );
    760985        remove_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10 );
    761986        remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 );
     
    774999            array(
    7751000                'ID'          => $action_id,
    776                 'post_status' => 'migrated'
     1001                'post_status' => 'migrated',
    7771002            )
    7781003        );
     
    7821007     * Determine whether the post store can be migrated.
    7831008     *
     1009     * @param [type] $setting - Setting value.
    7841010     * @return bool
    7851011     */
     
    7901016        if ( empty( $dependencies_met ) ) {
    7911017            $maximum_args_length = apply_filters( 'action_scheduler_maximum_args_length', 191 );
    792             $found_action        = $wpdb->get_var(
     1018            $found_action        = $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    7931019                $wpdb->prepare(
    7941020                    "SELECT ID FROM {$wpdb->posts} WHERE post_type = %s AND CHAR_LENGTH(post_content) > %d LIMIT 1",
     
    7971023                )
    7981024            );
    799             $dependencies_met = $found_action ? 'no' : 'yes';
     1025            $dependencies_met    = $found_action ? 'no' : 'yes';
    8001026            set_transient( self::DEPENDENCIES_MET, $dependencies_met, DAY_IN_SECONDS );
    8011027        }
    8021028
    803         return 'yes' == $dependencies_met ? $setting : false;
     1029        return 'yes' === $dependencies_met ? $setting : false;
    8041030    }
    8051031
     
    8111037     * developers of this impending requirement.
    8121038     *
    813      * @param ActionScheduler_Action $action
     1039     * @param ActionScheduler_Action $action Action object.
    8141040     */
    8151041    protected function validate_action( ActionScheduler_Action $action ) {
     
    8171043            parent::validate_action( $action );
    8181044        } catch ( Exception $e ) {
     1045            /* translators: %s is the error message */
    8191046            $message = sprintf( __( '%s Support for strings longer than this will be removed in a future version.', 'action-scheduler' ), $e->getMessage() );
    820             _doing_it_wrong( 'ActionScheduler_Action::$args', $message, '2.1.0' );
    821         }
    822     }
    823 
    824     /**
    825      * @codeCoverageIgnore
     1047            _doing_it_wrong( 'ActionScheduler_Action::$args', esc_html( $message ), '2.1.0' );
     1048        }
     1049    }
     1050
     1051    /**
     1052     * (@codeCoverageIgnore)
    8261053     */
    8271054    public function init() {
  • action-scheduler/trunk/classes/schema/ActionScheduler_StoreSchema.php

    r2599552 r2622865  
    1717     * @var int Increment this value to trigger a schema update.
    1818     */
    19     protected $schema_version = 5;
     19    protected $schema_version = 6;
    2020
    2121    public function __construct() {
     
    6565                        KEY group_id (group_id),
    6666                        KEY last_attempt_gmt (last_attempt_gmt),
    67                         KEY claim_id (claim_id),
    6867                        KEY `claim_id_status_scheduled_date_gmt` (`claim_id`, `status`, `scheduled_date_gmt`)
    6968                        ) $charset_collate";
  • action-scheduler/trunk/deprecated/ActionScheduler_Schedule_Deprecated.php

    r2340383 r2622865  
    1010     * after a given date & time.
    1111     *
    12      * @param DateTime $after
     12     * @param DateTime $after DateTime to calculate against.
    1313     *
    1414     * @return DateTime|null
    1515     */
    16     public function next( DateTime $after = NULL ) {
     16    public function next( DateTime $after = null ) {
    1717        if ( empty( $after ) ) {
    1818            $return_value       = $this->get_date();
     
    2323        }
    2424
    25         _deprecated_function( __METHOD__, '3.0.0', __CLASS__ . '::' . $replacement_method );
     25        _deprecated_function( __METHOD__, '3.0.0', __CLASS__ . '::' . $replacement_method ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
    2626
    2727        return $return_value;
  • action-scheduler/trunk/readme.txt

    r2599552 r2622865  
    44Requires at least: 5.2
    55Tested up to: 5.7
    6 Stable tag: 3.3.0
     6Stable tag: 3.4.0
    77License: GPLv3
    88Requires PHP: 5.6
     
    4848== Changelog ==
    4949
     50= 3.4.0 - 2021-10-29 =
     51* Enhancement - Number of items per page can now be set for the Scheduled Actions view (props @ovidiul). #771
     52* Fix - Do not lower the max_execution_time if it is already set to 0 (unlimited) (props @barryhughes). #755
     53* Fix - Avoid triggering autoloaders during the version resolution process (props @olegabr). #731 & #776
     54* Dev - ActionScheduler_wcSystemStatus PHPCS fixes (props @ovidiul). #761
     55* Dev - ActionScheduler_DBLogger.php PHPCS fixes (props @ovidiul). #768
     56* Dev - Fixed phpcs for ActionScheduler_Schedule_Deprecated (props @ovidiul). #762
     57* Dev - Improve actions table indicies (props @glagonikas). #774 & #777
     58* Dev - PHPCS fixes for ActionScheduler_DBStore.php (props @ovidiul). #769 & #778
     59* Dev - PHPCS Fixes for ActionScheduler_Abstract_ListTable (props @ovidiul). #763 & #779
     60* Dev - Adds new filter action_scheduler_claim_actions_order_by to allow tuning of the claim query (props @glagonikas). #773
     61* Dev - PHPCS fixes for ActionScheduler_WpPostStore class (props @ovidiul). #780
     62
    5063= 3.3.0 - 2021-09-15 =
    5164* Enhancement - Adds as_has_scheduled_action() to provide a performant way to test for existing actions. #645
Note: See TracChangeset for help on using the changeset viewer.