Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: adding the --ignore-group CLI option #784

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
4515bbc
adding --exclude-group CLI option and adding comma for supporting mul…
ovidiul Oct 27, 2021
56050a2
removing empty array values from group array
ovidiul Oct 27, 2021
5cd4940
renaming EXCLUDED_GROUP_PREFIX const to EXCLUDE_GROUP_FLAG
ovidiul Oct 27, 2021
440204c
renaming exclude to ignore namings
ovidiul Oct 27, 2021
e27831f
renaming exclude to ignore namings
ovidiul Oct 27, 2021
c75caec
comments fix
ovidiul Oct 27, 2021
b4a5a52
code refactoring if statement
ovidiul Oct 27, 2021
5190367
code refactoring if statement
ovidiul Oct 27, 2021
d16c502
code refactoring if statement
ovidiul Oct 27, 2021
0b31d94
code refactoring if statement
ovidiul Oct 27, 2021
e8548dc
adding comments
ovidiul Oct 27, 2021
21de107
code refactoring
ovidiul Oct 27, 2021
9f05104
query fix group selection
ovidiul Oct 27, 2021
6685173
query fix group selection
ovidiul Oct 27, 2021
7d4bf23
cli logic fix
ovidiul Oct 27, 2021
6066d44
adding code logic where query
ovidiul Oct 28, 2021
82b8096
code refactoring
ovidiul Oct 28, 2021
2843308
code refactoring
ovidiul Oct 28, 2021
2eb6c04
Update classes/abstracts/ActionScheduler_Store.php
ovidiul Nov 24, 2022
c3b2484
Update classes/abstracts/ActionScheduler_Store.php
ovidiul Nov 24, 2022
e16a172
Update classes/abstracts/ActionScheduler_Store.php
ovidiul Nov 24, 2022
641cf31
Update classes/data-stores/ActionScheduler_DBStore.php
ovidiul Nov 24, 2022
3325571
Update classes/data-stores/ActionScheduler_DBStore.php
ovidiul Nov 24, 2022
477373b
renaming mark_group_for_exclussion method
ovidiul Nov 24, 2022
85bf9fa
esc_sql sanitize_group_name and regex addon ^
ovidiul Nov 24, 2022
8699ef1
adding --ignore-group docs
ovidiul Nov 24, 2022
0f25f07
Update wp-cli.md
ovidiul Nov 24, 2022
b9c9dd7
Update wp-cli.md
ovidiul Nov 24, 2022
b3f60cd
Merge branch 'trunk' into feature_ignore_group_cli_addon
ovidiul Nov 24, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions classes/WP_CLI/ActionScheduler_WPCLI_Scheduler_command.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ public function fix_schema( $args, $assoc_args ) {
* [--group=<group>]
* : Only run actions from the specified group. Omitting this option runs actions from all groups.
*
* [--ignore-group=<group>]
* : Run actions by omiting the specified group. Omitting this option runs actions from all groups.
*
* [--free-memory-on=<count>]
* : The number of actions to process between freeing memory. 0 disables freeing memory. Default 50.
*
Expand Down Expand Up @@ -82,13 +85,29 @@ public function run( $args, $assoc_args ) {
$sleep = \WP_CLI\Utils\get_flag_value( $assoc_args, 'pause', 0 );
$force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force', false );

$ignore_group = \WP_CLI\Utils\get_flag_value( $assoc_args, 'ignore-group', '' );

ActionScheduler_DataController::set_free_ticks( $free_on );
ActionScheduler_DataController::set_sleep_time( $sleep );

$batches_completed = 0;
$actions_completed = 0;
$unlimited = $batches === 0;

if ( ! $group && $ignore_group ) { // there is no need to proceed with the ignore code if $group is set.

$ignore_group_array = array_map(
function ( $val ) {
return ActionScheduler_DBStore::mark_group_for_exclusion( $val );
},
explode( ',', $ignore_group )
);

if ( count( $ignore_group_array ) ) {
$group .= ',' . implode( ',', $ignore_group_array );
}
}

try {
// Custom queue cleaner instance.
$cleaner = new ActionScheduler_QueueCleaner( null, $clean );
Expand Down
48 changes: 42 additions & 6 deletions classes/abstracts/ActionScheduler_Store.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@
* @codeCoverageIgnore
*/
abstract class ActionScheduler_Store extends ActionScheduler_Store_Deprecated {
const STATUS_COMPLETE = 'complete';
const STATUS_PENDING = 'pending';
const STATUS_RUNNING = 'in-progress';
const STATUS_FAILED = 'failed';
const STATUS_CANCELED = 'canceled';
const DEFAULT_CLASS = 'ActionScheduler_wpPostStore';
const STATUS_COMPLETE = 'complete';
const STATUS_PENDING = 'pending';
const STATUS_RUNNING = 'in-progress';
const STATUS_FAILED = 'failed';
const STATUS_CANCELED = 'canceled';
const DEFAULT_CLASS = 'ActionScheduler_wpPostStore';
const IGNORE_GROUP_FLAG = '--*IGNORE*--';

/** @var ActionScheduler_Store */
private static $store = NULL;
Expand Down Expand Up @@ -236,6 +237,41 @@ abstract public function get_claim_id( $action_id );
*/
abstract public function find_actions_by_claim_id( $claim_id );

/**
* Check if group name is prefixed for exclussion.
*
* @param string $slug Group slug name.
* @return boolean
*/
protected static function group_has_ignore_prefix( $slug ) {
return self::IGNORE_GROUP_FLAG === substr( $slug, 0, strlen( self::IGNORE_GROUP_FLAG ) );
}

/**
* Mark group for exclusion by applying a special prefix (by default, the value of
* the IGNORE_GROUP_FLAG property).
*
* @param string $slug Group slug name.
* @return string
*/
public static function mark_group_for_exclusion( $slug ) {
return $slug ? self::IGNORE_GROUP_FLAG . $slug : $slug;
}

/**
* Sanitize group name.
*
* @param string $slug Group slug name.
* @return string
*/
public static function sanitize_group_name( $slug ) {
// removing the ignored group prefix from slug if present.
$slug = preg_replace( '/^(' . preg_quote( self::IGNORE_GROUP_FLAG, null ) . ')?(.*)/m', '$2', esc_sql( $slug ) );

// further sanitisation here with `sanitize_title` maybe?
return $slug;
}

/**
* @param string $comparison_operator
* @return string
Expand Down
47 changes: 37 additions & 10 deletions classes/data-stores/ActionScheduler_DBStore.php
Original file line number Diff line number Diff line change
Expand Up @@ -267,11 +267,18 @@ protected function get_group_id( $slug, $create_if_not_exists = true ) {
* @param string $slug Group slug.
*
* @return int Group ID.
* @throws \InvalidArgumentException Throws exception when the group slug starts with IGNORE_GROUP_FLAG.
*/
protected function create_group( $slug ) {
/** @var \wpdb $wpdb */
global $wpdb;
$wpdb->insert( $wpdb->actionscheduler_groups, array( 'slug' => $slug ) );

if ( self::group_has_ignore_prefix( $slug ) ) {
// translators: %s: ignored group name prefix.
throw new InvalidArgumentException( sprintf( esc_html__( 'Group names cannot start with %s.', 'action-scheduler' ), self::IGNORE_GROUP_FLAG ) );
}

$wpdb->insert( $wpdb->actionscheduler_groups, array( 'slug' => $slug ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery

return (int) $wpdb->insert_id;
}
Expand Down Expand Up @@ -803,7 +810,7 @@ protected function generate_claim_id() {
* @param int $limit Number of action to include in claim.
* @param \DateTime $before_date Should use UTC timezone.
* @param array $hooks Hooks to filter for.
* @param string $group Group to filter for.
* @param string $group Comma-separated list of groups to filter by. Adding IGNORE_GROUP_FLAG in front of a group will cause it to be ignored.
*
* @return int The number of actions that were claimed.
* @throws \InvalidArgumentException Throws InvalidArgumentException if group doesn't exist.
Expand Down Expand Up @@ -834,18 +841,38 @@ protected function claim_actions( $claim_id, $limit, \DateTime $before_date = nu
$params = array_merge( $params, array_values( $hooks ) );
}

if ( ! empty( $group ) ) {
$group_array = array_filter( explode( ',', $group ) );

$ignore_group_ids = array();
$include_group_ids = array();

if ( is_array( $group_array ) && count( $group_array ) ) {

$group_id = $this->get_group_id( $group, false );
foreach ( $group_array as $group ) {

// throw exception if no matching group found, this matches ActionScheduler_wpPostStore's behaviour.
if ( empty( $group_id ) ) {
/* translators: %s: group name */
throw new InvalidArgumentException( sprintf( __( 'The group "%s" does not exist.', 'action-scheduler' ), $group ) );
$sanitized_group_name = self::sanitize_group_name( $group );
$group_id = $this->get_group_id( $sanitized_group_name, false );

// throw exception if no matching group found, this matches ActionScheduler_wpPostStore's behaviour.
if ( empty( $group_id ) ) {
/* translators: %s: group name */
throw new InvalidArgumentException( sprintf( __( 'The group "%s" does not exist.', 'action-scheduler' ), $sanitized_group_name ) );
}

if ( self::group_has_ignore_prefix( $group ) ) {
$ignore_group_ids[] = $group_id;
} else {
$include_group_ids[] = $group_id;
}
}
}

$where .= ' AND group_id = %d';
$params[] = $group_id;
if ( count( $include_group_ids ) ) {
$where .= ' AND group_id IN (%s)';
$params[] = implode( ',', $include_group_ids );
Copy link
Member

@barryhughes barryhughes Nov 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Asking this without actually testing 😅 ... but, won't the group ID arrays at this point be comma separated strings without quotation? That is, we will get:

( foo, bar, baz )

Instead of:

( 'foo', 'bar', 'baz' )

If so, we should add quoting at some suitable point.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The $include_group_ids will actually contain the numerical ID's of each group found in the DB, taken from above line

$group_id             = $this->get_group_id( $sanitized_group_name, false );

so I don't think we need to add any quotes here...

} elseif ( count( $ignore_group_ids ) ) {
$where .= ' AND group_id NOT IN (%s)';
$params[] = implode( ',', $ignore_group_ids );
}

/**
Expand Down
3 changes: 2 additions & 1 deletion docs/wp-cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ These are the commands available to use with Action Scheduler:
* `--batch-size` - This is the number of actions to run in a single batch. The default is `100`.
* `--batches` - This is the number of batches to run. Using 0 means that batches will continue running until there are no more actions to run.
* `--hooks` - Process only actions with specific hook or hooks, like `'woocommerce_scheduled_subscription_payment'`. By default, actions with any hook will be processed. Define multiple hooks as a comma separated string (without spaces), e.g. `--hooks=woocommerce_scheduled_subscription_trial_end,woocommerce_scheduled_subscription_payment,woocommerce_scheduled_subscription_expiration`
* `--group` - Process only actions in a specific group, like `'woocommerce-memberships'`. By default, actions in any group (or no group) will be processed.
* `--group` - Process only actions in a specific group, like `'woocommerce-memberships'`. By default, actions in any group (or no group) will be processed. Accepts comma-separated list of groups to filter by. Adding --*IGNORE*-- in front of a group will cause it to be ignored.
* `--ignore-group` - Ignore processing actions from groups found inside the comma separated list of values.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, thank you 👍

* `--force` - By default, Action Scheduler limits the number of concurrent batches that can be run at once to ensure the server does not get overwhelmed. Using the `--force` flag overrides this behavior to force the WP CLI queue to run.

The best way to get a full list of commands and their available options is to use WP CLI itself. This can be done by running `wp action-scheduler` to list all Action Scheduler commands, or by including the `--help` flag with any of the individual commands. This will provide all relevant parameters and flags for the command.
Expand Down