Skip to content
Snippets Groups Projects
functions.php 3.32 KiB
Newer Older
Erick Hitter's avatar
Erick Hitter committed
/**
 * Common plugin functions
 *
 * @package WP_CLI_Cron_Control_Offload
 */

namespace Automattic\WP\WP_CLI_Cron_Control_Offload;
use WP_Error;
/**
 * Create cron event for a given WP-CLI command
 *
Erick Hitter's avatar
Erick Hitter committed
 * @param string $command WP-CLI command to schedule.
 * @param int    $timestamp Optional. Unix timestamp to schedule command to run at.
 * @return int|WP_Error
function schedule_cli_command( $command, $timestamp = null ) {
	$command = validate_command( $command );
	if ( is_wp_error( $command ) ) {
		return $command;
	if ( ! is_int( $timestamp ) ) {
		$timestamp = strtotime( '+30 seconds' );
	}

	if ( $timestamp <= time() ) {
		return new WP_Error( 'invalid-timestamp', __( 'Timestamp is in the past.', 'wp-cli-cron-control-offload' ) );
	}

Erick Hitter's avatar
Erick Hitter committed
	$event_args = array(
		'command' => $command,
	);

	$scheduled = wp_schedule_single_event( $timestamp, ACTION, $event_args );
	if ( false === $scheduled ) {
		return new WP_Error( 'not-scheduled', __( 'Command may already be scheduled, or it was blocked via the `schedule_event` filter.', 'wp-cli-cron-control-offload' ) );
	}

	return $timestamp;
}

/**
 * Validate WP-CLI command to be scheduled
 *
Erick Hitter's avatar
Erick Hitter committed
 * @param string $command WP-CLI command to validate.
 * @return array|WP_Error
function validate_command( $command ) {
Erick Hitter's avatar
Erick Hitter committed
	$command = trim( $command );

Erick Hitter's avatar
Erick Hitter committed
	// Strip `wp` if included.
	if ( 0 === stripos( $command, 'wp' ) ) {
		$command = trim( substr( $command, 2 ) );
Erick Hitter's avatar
Erick Hitter committed
	// Block disallowed commands.
	$first_command = explode( ' ', $command );
	$first_command = array_shift( $first_command );
	if ( ! is_command_allowed( $first_command ) ) {
Erick Hitter's avatar
Erick Hitter committed
		/* translators: 1: Disallowed command */
		return new WP_Error( 'blocked-command', sprintf( __( '`%1$s` not allowed', 'wp-cli-cron-control-offload' ), $first_command ) );
Erick Hitter's avatar
Erick Hitter committed
	// Don't worry about the user WP-CLI runs as.
	if ( false === stripos( $command, '--allow-root' ) ) {
Erick Hitter's avatar
Erick Hitter committed
		$command .= ' --allow-root';
Erick Hitter's avatar
Erick Hitter committed
	// TODO: validate further // @codingStandardsIgnoreLine

Erick Hitter's avatar
Erick Hitter committed
	// Nothing to run.
	if ( empty( $command ) ) {
		return new WP_Error( 'invalid-command', 'Invalid command provided' );
 * Check if command is allowed
Erick Hitter's avatar
Erick Hitter committed
 * @param string $command Top-level WP-CLI command to check against blacklist and whitelist.
function is_command_allowed( $command ) {
	// Command explicitly disallowed.
	if ( in_array( $command, get_command_blacklist(), true ) ) {
		return false;
	}

	return in_array( $command, get_command_whitelist(), true );
}

/**
 * Most commands must be whitelisted
 *
 * @return array
 */
function get_command_whitelist() {
Erick Hitter's avatar
Erick Hitter committed
	// TODO: constant!
Erick Hitter's avatar
Erick Hitter committed
	// Supported built-in commands.
	$whitelist = array(
		'cache',
		'cap',
		'comment',
		'media',
		'menu',
		'network',
		'option',
		'plugin',
		'post',
		'post-type',
		'rewrite',
		'role',
		'sidebar',
		'site',
		'super-admin',
		'taxonomy',
		'term',
		'theme',
		'transient',
		'user',
		'widget',
	);

	return apply_filters( 'wp_cli_cron_control_offload_command_whitelist', $whitelist );
 * Certain commands should never be allowed
function get_command_blacklist() {
Erick Hitter's avatar
Erick Hitter committed
	// TODO: constant!
Erick Hitter's avatar
Erick Hitter committed
		CLI_NAMESPACE, // Don't support scheduling loops.
Erick Hitter's avatar
Erick Hitter committed
		'cron-control',
		'cron-control-fixers',
Erick Hitter's avatar
Erick Hitter committed
		'export',
		'package',