Initial commit

This commit is contained in:
Felix Förtsch
2020-10-20 14:39:50 +02:00
commit 648ded8896
1225 changed files with 216511 additions and 0 deletions
@@ -0,0 +1,428 @@
<?php
/**
* List table for cron events.
*
* @package wp-crontrol
*/
namespace Crontrol\Event;
use stdClass;
require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
/**
* Cron event list table class.
*/
class Table extends \WP_List_Table {
/**
* Array of cron event hooks that are persistently added by WordPress core.
*
* @var string[] Array of hook names.
*/
protected static $persistent_core_hooks;
/**
* Whether the current user has the capability to edit files.
*
* @var bool Whether the user can edit files.
*/
protected static $can_edit_files;
/**
* Array of the count of each hook.
*
* @var int[] Array of count of each hooked, keyed by hook name.
*/
protected static $count_by_hook;
/**
* Constructor.
*/
public function __construct() {
parent::__construct( array(
'singular' => 'crontrol-event',
'plural' => 'crontrol-events',
'ajax' => false,
'screen' => 'crontrol-events',
) );
}
/**
* Prepares the list table items and arguments.
*/
public function prepare_items() {
self::$persistent_core_hooks = \Crontrol\get_persistent_core_hooks();
self::$can_edit_files = current_user_can( 'edit_files' );
self::$count_by_hook = count_by_hook();
$events = get();
if ( ! empty( $_GET['s'] ) ) {
$s = sanitize_text_field( wp_unslash( $_GET['s'] ) );
$events = array_filter( $events, function( $event ) use ( $s ) {
return ( false !== strpos( $event->hook, $s ) );
} );
}
$count = count( $events );
$per_page = 50;
$offset = ( $this->get_pagenum() - 1 ) * $per_page;
$this->items = array_slice( $events, $offset, $per_page );
$this->set_pagination_args( array(
'total_items' => $count,
'per_page' => $per_page,
'total_pages' => ceil( $count / $per_page ),
) );
}
/**
* Returns an array of column names for the table.
*
* @return string[] Array of column names keyed by their ID.
*/
public function get_columns() {
return array(
'cb' => '<input type="checkbox" />',
'crontrol_hook' => __( 'Hook', 'wp-crontrol' ),
'crontrol_args' => __( 'Arguments', 'wp-crontrol' ),
'crontrol_next' => sprintf(
/* translators: %s: UTC offset */
__( 'Next Run (%s)', 'wp-crontrol' ),
\Crontrol\get_utc_offset()
),
'crontrol_actions' => __( 'Action', 'wp-crontrol' ),
'crontrol_recurrence' => __( 'Recurrence', 'wp-crontrol' ),
);
}
/**
* Returns an array of CSS class names for the table.
*
* @return string[] Array of class names.
*/
protected function get_table_classes() {
return array( 'widefat', 'striped', $this->_args['plural'] );
}
/**
* Get an associative array ( option_name => option_title ) with the list
* of bulk actions available on this table.
*
* @since 3.1.0
*
* @return array
*/
protected function get_bulk_actions() {
return array(
'delete_crons' => esc_html__( 'Delete', 'wp-crontrol' ),
);
}
/**
* Generates content for a single row of the table.
*
* @param object $event The current event.
*/
public function single_row( $event ) {
$classes = array();
if ( ( 'crontrol_cron_job' === $event->hook ) && ! empty( $event->args['syntax_error_message'] ) ) {
$classes[] = 'crontrol-error';
}
$schedule_name = ( $event->interval ? get_schedule_name( $event ) : false );
if ( is_wp_error( $schedule_name ) ) {
$classes[] = 'crontrol-error';
}
if ( ! \Crontrol\get_hook_callbacks( $event->hook ) ) {
$classes[] = 'crontrol-warning';
}
if ( is_late( $event ) ) {
$classes[] = 'crontrol-warning';
}
printf(
'<tr class="%s">',
esc_attr( implode( ' ', $classes ) )
);
$this->single_row_columns( $event );
echo '</tr>';
}
/**
* Generates and displays row action links for the table.
*
* @param stdClass $event The cron event for the current row.
* @param string $column_name Current column name.
* @param string $primary Primary column name.
* @return string The row actions HTML.
*/
protected function handle_row_actions( $event, $column_name, $primary ) {
if ( $primary !== $column_name ) {
return '';
}
$links = array();
if ( ( 'crontrol_cron_job' !== $event->hook ) || self::$can_edit_files ) {
$link = array(
'page' => 'crontrol_admin_manage_page',
'action' => 'edit-cron',
'id' => rawurlencode( $event->hook ),
'sig' => rawurlencode( $event->sig ),
'next_run_utc' => rawurlencode( $event->time ),
);
$link = add_query_arg( $link, admin_url( 'tools.php' ) );
$links[] = "<a href='" . esc_url( $link ) . "'>" . esc_html__( 'Edit', 'wp-crontrol' ) . '</a>';
}
$link = array(
'page' => 'crontrol_admin_manage_page',
'action' => 'run-cron',
'id' => rawurlencode( $event->hook ),
'sig' => rawurlencode( $event->sig ),
'next_run_utc' => rawurlencode( $event->time ),
);
$link = add_query_arg( $link, admin_url( 'tools.php' ) );
$link = wp_nonce_url( $link, "run-cron_{$event->hook}_{$event->sig}" );
$links[] = "<a href='" . esc_url( $link ) . "'>" . esc_html__( 'Run Now', 'wp-crontrol' ) . '</a>';
if ( ! in_array( $event->hook, self::$persistent_core_hooks, true ) && ( ( 'crontrol_cron_job' !== $event->hook ) || self::$can_edit_files ) ) {
$link = array(
'page' => 'crontrol_admin_manage_page',
'action' => 'delete-cron',
'id' => rawurlencode( $event->hook ),
'sig' => rawurlencode( $event->sig ),
'next_run_utc' => rawurlencode( $event->time ),
);
$link = add_query_arg( $link, admin_url( 'tools.php' ) );
$link = wp_nonce_url( $link, "delete-cron_{$event->hook}_{$event->sig}_{$event->time}" );
$links[] = "<span class='delete'><a href='" . esc_url( $link ) . "'>" . esc_html__( 'Delete', 'wp-crontrol' ) . '</a></span>';
}
if ( function_exists( 'wp_unschedule_hook' ) && ! in_array( $event->hook, self::$persistent_core_hooks, true ) && ( 'crontrol_cron_job' !== $event->hook ) ) {
if ( self::$count_by_hook[ $event->hook ] > 1 ) {
$link = array(
'page' => 'crontrol_admin_manage_page',
'action' => 'delete-hook',
'id' => rawurlencode( $event->hook ),
);
$link = add_query_arg( $link, admin_url( 'tools.php' ) );
$link = wp_nonce_url( $link, "delete-hook_{$event->hook}" );
$text = sprintf(
/* translators: %s: Number of events with a given name */
_n( 'Delete All %s', 'Delete All %s', self::$count_by_hook[ $event->hook ], 'wp-crontrol' ),
number_format_i18n( self::$count_by_hook[ $event->hook ] )
);
$links[] = "<span class='delete'><a href='" . esc_url( $link ) . "'>" . esc_html( $text ) . '</a></span>';
}
}
return $this->row_actions( $links );
}
/**
* Outputs the checkbox cell of a table row.
*
* @param stdClass $event The cron event for the current row.
*/
protected function column_cb( $event ) {
if ( ! in_array( $event->hook, self::$persistent_core_hooks, true ) && ( ( 'crontrol_cron_job' !== $event->hook ) || self::$can_edit_files ) ) {
?>
<label class="screen-reader-text" for="">
<?php printf( esc_html__( 'Select this row', 'wp-crontrol' ) ); ?>
</label>
<?php
printf(
'<input type="checkbox" name="delete[%1$s][%2$s]" value="%3$s">',
esc_attr( $event->time ),
esc_attr( rawurlencode( $event->hook ) ),
esc_attr( $event->sig )
);
?>
<?php
}
}
/**
* Returns the output for the hook name cell of a table row.
*
* @param stdClass $event The cron event for the current row.
* @return string The cell output.
*/
protected function column_crontrol_hook( $event ) {
if ( 'crontrol_cron_job' === $event->hook ) {
if ( ! empty( $event->args['name'] ) ) {
/* translators: 1: The name of the PHP cron event. */
return '<em>' . esc_html( sprintf( __( 'PHP Cron (%s)', 'wp-crontrol' ), $event->args['name'] ) ) . '</em>';
} else {
return '<em>' . esc_html__( 'PHP Cron', 'wp-crontrol' ) . '</em>';
}
}
return esc_html( $event->hook );
}
/**
* Returns the output for the arguments cell of a table row.
*
* @param stdClass $event The cron event for the current row.
* @return string The cell output.
*/
protected function column_crontrol_args( $event ) {
if ( ! empty( $event->args ) ) {
$args = \Crontrol\json_output( $event->args );
}
if ( 'crontrol_cron_job' === $event->hook ) {
$return = '<em>' . esc_html__( 'PHP Code', 'wp-crontrol' ) . '</em>';
if ( ! empty( $event->args['syntax_error_message'] ) ) {
$return .= '<br><span class="status-crontrol-error"><span class="dashicons dashicons-warning" aria-hidden="true"></span> ';
$return .= sprintf(
/* translators: 1: Line number, 2: Error message text */
esc_html__( 'Line %1$s: %2$s', 'wp-crontrol' ),
esc_html( number_format_i18n( $event->args['syntax_error_line'] ) ),
esc_html( $event->args['syntax_error_message'] )
);
$return .= '</span>';
}
if ( ! empty( $event->args['code'] ) ) {
$lines = explode( "\n", trim( $event->args['code'] ) );
$code = reset( $lines );
$code = substr( $code, 0, 50 );
$return .= '<br>';
$return .= sprintf(
'<code>%s</code>&hellip;',
esc_html( $code )
);
}
return $return;
} else {
if ( empty( $event->args ) ) {
return sprintf(
'<em>%s</em>',
esc_html__( 'None', 'wp-crontrol' )
);
} else {
return sprintf(
'<pre>%s</pre>',
esc_html( $args )
);
}
}
}
/**
* Returns the output for the actions cell of a table row.
*
* @param stdClass $event The cron event for the current row.
* @return string The cell output.
*/
protected function column_crontrol_actions( $event ) {
$hook_callbacks = \Crontrol\get_hook_callbacks( $event->hook );
if ( 'crontrol_cron_job' === $event->hook ) {
return '<em>' . esc_html__( 'WP Crontrol', 'wp-crontrol' ) . '</em>';
} elseif ( ! empty( $hook_callbacks ) ) {
$callbacks = array();
foreach ( $hook_callbacks as $callback ) {
$callbacks[] = \Crontrol\output_callback( $callback );
}
return implode( '<br>', $callbacks ); // WPCS:: XSS ok.
} else {
return sprintf(
'<span class="status-crontrol-warning"><span class="dashicons dashicons-warning" aria-hidden="true"></span> %s</span>',
esc_html__( 'None', 'wp-crontrol' )
);
}
}
/**
* Returns the output for the next run cell of a table row.
*
* @param stdClass $event The cron event for the current row.
* @return string The cell output.
*/
protected function column_crontrol_next( $event ) {
$date_utc = gmdate( 'Y-m-d\TH:i:s+00:00', $event->time );
$date_local = get_date_from_gmt( date( 'Y-m-d H:i:s', $event->time ), 'Y-m-d H:i:s' );
$time = sprintf(
'<time datetime="%1$s">%2$s</time>',
esc_attr( $date_utc ),
esc_html( $date_local )
);
$until = $event->time - time();
$late = is_late( $event );
if ( $late ) {
// Show a warning for events that are late.
$ago = sprintf(
/* translators: %s: Time period, for example "8 minutes" */
__( '%s ago', 'wp-crontrol' ),
\Crontrol\interval( abs( $until ) )
);
return sprintf(
'%s<br><span class="status-crontrol-warning"><span class="dashicons dashicons-warning" aria-hidden="true"></span> %s</span>',
$time,
esc_html( $ago )
);
}
return sprintf(
'%s<br>%s',
$time,
esc_html( \Crontrol\interval( $until ) )
);
}
/**
* Returns the output for the recurrence cell of a table row.
*
* @param stdClass $event The cron event for the current row.
* @return string The cell output.
*/
protected function column_crontrol_recurrence( $event ) {
if ( $event->schedule ) {
$schedule_name = get_schedule_name( $event );
if ( is_wp_error( $schedule_name ) ) {
return sprintf(
'<span class="status-crontrol-error"><span class="dashicons dashicons-warning" aria-hidden="true"></span> %s</span>',
esc_html( $schedule_name->get_error_message() )
);
} else {
return esc_html( $schedule_name );
}
} else {
return esc_html__( 'Non-repeating', 'wp-crontrol' );
}
}
/**
* Outputs a message when there are no items to show in the table.
*/
public function no_items() {
esc_html_e( 'There are currently no scheduled cron events.', 'wp-crontrol' );
}
}
+265
View File
@@ -0,0 +1,265 @@
<?php
/**
* Functions related to cron events.
*
* @package wp-crontrol
*/
namespace Crontrol\Event;
use stdClass;
use Crontrol\Schedule;
use WP_Error;
/**
* Executes a cron event immediately.
*
* Executes an event by scheduling a new single event with the same arguments.
*
* @param string $hookname The hook name of the cron event to run.
* @param string $sig The cron event signature.
* @return bool Whether the execution was successful.
*/
function run( $hookname, $sig ) {
$crons = _get_cron_array();
foreach ( $crons as $time => $cron ) {
if ( isset( $cron[ $hookname ][ $sig ] ) ) {
$args = $cron[ $hookname ][ $sig ]['args'];
delete_transient( 'doing_cron' );
$scheduled = force_schedule_single_event( $hookname, $args ); // UTC
if ( false === $scheduled ) {
return $scheduled;
}
add_filter( 'cron_request', function( array $cron_request_array ) {
$cron_request_array['url'] = add_query_arg( 'crontrol-single-event', 1, $cron_request_array['url'] );
return $cron_request_array;
} );
spawn_cron();
sleep( 1 );
return true;
}
}
return false;
}
/**
* Forcibly schedules a single event for the purpose of manually running it.
*
* This is used instead of `wp_schedule_single_event()` to avoid the duplicate check that's otherwise performed.
*
* @param string $hook Action hook to execute when the event is run.
* @param array $args Optional. Array containing each separate argument to pass to the hook's callback function.
* @return bool True if event successfully scheduled. False for failure.
*/
function force_schedule_single_event( $hook, $args = array() ) {
$event = (object) array(
'hook' => $hook,
'timestamp' => 1,
'schedule' => false,
'args' => $args,
);
$crons = (array) _get_cron_array();
$key = md5( serialize( $event->args ) );
$crons[ $event->timestamp ][ $event->hook ][ $key ] = array(
'schedule' => $event->schedule,
'args' => $event->args,
);
uksort( $crons, 'strnatcasecmp' );
return _set_cron_array( $crons );
}
/**
* Adds a new cron event.
*
* @param string $next_run_local The time that the event should be run at, in the site's timezone.
* @param string $schedule The recurrence of the cron event.
* @param string $hookname The name of the hook to execute.
* @param array $args Arguments to add to the cron event.
* @return bool Whether the addition was successful.
*/
function add( $next_run_local, $schedule, $hookname, array $args ) {
$next_run_local = strtotime( $next_run_local, current_time( 'timestamp' ) );
if ( false === $next_run_local ) {
return false;
}
$next_run_utc = get_gmt_from_date( gmdate( 'Y-m-d H:i:s', $next_run_local ), 'U' );
if ( ! is_array( $args ) ) {
$args = array();
}
if ( 'crontrol_cron_job' === $hookname && ! empty( $args['code'] ) && class_exists( '\ParseError' ) ) {
try {
// phpcs:ignore Squiz.PHP.Eval.Discouraged
eval( sprintf(
'return true; %s',
$args['code']
) );
// phpcs:ignore PHPCompatibility.Classes.NewClasses.parseerrorFound
} catch ( \ParseError $e ) {
$args['syntax_error_message'] = $e->getMessage();
$args['syntax_error_line'] = $e->getLine();
}
}
if ( '_oneoff' === $schedule ) {
return ( false !== wp_schedule_single_event( $next_run_utc, $hookname, $args ) );
} else {
return ( false !== wp_schedule_event( $next_run_utc, $schedule, $hookname, $args ) );
}
}
/**
* Deletes a cron event.
*
* @param string $to_delete The hook name of the event to delete.
* @param string $sig The cron event signature.
* @param string $next_run_utc The UTC time that the event would be run at.
* @return bool Whether the deletion was successful.
*/
function delete( $to_delete, $sig, $next_run_utc ) {
$crons = _get_cron_array();
if ( isset( $crons[ $next_run_utc ][ $to_delete ][ $sig ] ) ) {
$args = $crons[ $next_run_utc ][ $to_delete ][ $sig ]['args'];
$unscheduled = wp_unschedule_event( $next_run_utc, $to_delete, $args );
if ( false === $unscheduled ) {
return $unscheduled;
}
return true;
}
return false;
}
/**
* Returns a flattened array of cron events.
*
* @return object[] An array of cron event objects.
*/
function get() {
$crons = _get_cron_array();
$events = array();
if ( empty( $crons ) ) {
return array();
}
foreach ( $crons as $time => $cron ) {
foreach ( $cron as $hook => $dings ) {
foreach ( $dings as $sig => $data ) {
// This is a prime candidate for a Crontrol_Event class but I'm not bothering currently.
$events[ "$hook-$sig-$time" ] = (object) array(
'hook' => $hook,
'time' => $time, // UTC
'sig' => $sig,
'args' => $data['args'],
'schedule' => $data['schedule'],
'interval' => isset( $data['interval'] ) ? $data['interval'] : null,
);
}
}
}
// Ensure events are always returned in date descending order.
// External cron runners such as Cavalcade don't guarantee events are returned in order of time.
uasort( $events, function( $a, $b ) {
if ( $a->time === $b->time ) {
return 0;
} else {
return ( $a->time > $b->time ) ? 1 : -1;
}
} );
return $events;
}
/**
* Returns an array of the number of events for each hook.
*
* @return int[] Array of number of events for each hook, keyed by the hook name.
*/
function count_by_hook() {
$crons = _get_cron_array();
$events = array();
if ( empty( $crons ) ) {
return array();
}
foreach ( $crons as $time => $cron ) {
foreach ( $cron as $hook => $dings ) {
if ( ! isset( $events[ $hook ] ) ) {
$events[ $hook ] = 0;
}
$events[ $hook ] += count( $dings );
}
}
return $events;
}
/**
* Returns the schedule display name for a given event.
*
* @param stdClass $event A WP-Cron event.
* @return string|WP_Error The interval display name, or a WP_Error object if no such schedule exists.
*/
function get_schedule_name( stdClass $event ) {
$schedules = Schedule\get();
if ( isset( $schedules[ $event->schedule ] ) ) {
return $schedules[ $event->schedule ]['display'];
}
return new WP_Error( 'unknown_schedule', sprintf(
/* translators: %s: Schedule name */
__( 'Unknown (%s)', 'wp-crontrol' ),
$event->schedule
) );
}
/**
* Determines whether an event is late.
*
* An event which has missed its schedule by more than 10 minutes is considered late.
*
* @param stdClass $event The event.
* @return bool Whether the event is late.
*/
function is_late( stdClass $event ) {
$until = $event->time - time();
return ( $until < ( 0 - ( 10 * MINUTE_IN_SECONDS ) ) );
}
/**
* Initialises and returns the list table for events.
*
* @return Table The list table.
*/
function get_list_table() {
static $table = null;
if ( ! $table ) {
require_once __DIR__ . '/event-list-table.php';
$table = new Table();
$table->prepare_items();
}
return $table;
}
@@ -0,0 +1,175 @@
<?php
/**
* List table for cron schedules.
*
* @package wp-crontrol
*/
namespace Crontrol;
require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
/**
* Cron schedule list table class.
*/
class Schedule_List_Table extends \WP_List_Table {
/**
* Array of cron event schedules that are added by WordPress core.
*
* @var string[] Array of schedule names.
*/
protected static $core_schedules;
/**
* Array of cron event schedule names that are in use by events.
*
* @var string[] Array of schedule names.
*/
protected static $used_schedules;
/**
* Constructor.
*/
public function __construct() {
parent::__construct( array(
'singular' => 'crontrol-schedule',
'plural' => 'crontrol-schedules',
'ajax' => false,
'screen' => 'crontrol-schedules',
) );
}
/**
* Prepares the list table items and arguments.
*/
public function prepare_items() {
$schedules = Schedule\get();
$count = count( $schedules );
self::$core_schedules = get_core_schedules();
self::$used_schedules = array_unique( wp_list_pluck( Event\get(), 'schedule' ) );
$this->items = $schedules;
$this->set_pagination_args( array(
'total_items' => $count,
'per_page' => -1,
'total_pages' => 1,
) );
}
/**
* Returns an array of column names for the table.
*
* @return string[] Array of column names keyed by their ID.
*/
public function get_columns() {
return array(
'crontrol_name' => __( 'Name', 'wp-crontrol' ),
'crontrol_interval' => __( 'Interval', 'wp-crontrol' ),
'crontrol_display' => __( 'Display Name', 'wp-crontrol' ),
);
}
/**
* Returns an array of CSS class names for the table.
*
* @return string[] Array of class names.
*/
protected function get_table_classes() {
return array( 'widefat', 'striped', $this->_args['plural'] );
}
/**
* Generates and displays row action links for the table.
*
* @param array $schedule The schedule for the current row.
* @param string $column_name Current column name.
* @param string $primary Primary column name.
* @return string The row actions HTML.
*/
protected function handle_row_actions( $schedule, $column_name, $primary ) {
if ( $primary !== $column_name ) {
return '';
}
$links = array();
$new_scheds = get_option( 'crontrol_schedules', array() );
if ( in_array( $schedule['name'], self::$core_schedules, true ) ) {
$links[] = "<span class='in-use'>" . esc_html__( 'This is a WordPress core schedule and cannot be deleted', 'wp-crontrol' ) . '</span>';
} elseif ( ! isset( $new_scheds[ $schedule['name'] ] ) ) {
$links[] = "<span class='in-use'>" . esc_html__( 'This schedule is added by another plugin and cannot be deleted', 'wp-crontrol' ) . '</span>';
} elseif ( in_array( $schedule['name'], self::$used_schedules, true ) ) {
$links[] = "<span class='in-use'>" . esc_html__( 'This custom schedule is in use and cannot be deleted', 'wp-crontrol' ) . '</span>';
} else {
$link = add_query_arg( array(
'page' => 'crontrol_admin_options_page',
'action' => 'delete-sched',
'id' => rawurlencode( $schedule['name'] ),
), admin_url( 'options-general.php' ) );
$link = wp_nonce_url( $link, 'delete-sched_' . $schedule['name'] );
$links[] = "<span class='delete'><a href='" . esc_url( $link ) . "'>" . esc_html__( 'Delete', 'wp-crontrol' ) . '</a></span>';
}
return $this->row_actions( $links );
}
/**
* Returns the output for the schdule name cell of a table row.
*
* @param array $schedule The schedule for the current row.
* @return string The cell output.
*/
protected function column_crontrol_name( array $schedule ) {
return esc_html( $schedule['name'] );
}
/**
* Returns the output for the interval cell of a table row.
*
* @param array $schedule The schedule for the current row.
* @return string The cell output.
*/
protected function column_crontrol_interval( array $schedule ) {
$interval = sprintf(
'%s (%s)',
esc_html( $schedule['interval'] ),
esc_html( interval( $schedule['interval'] ) )
);
if ( $schedule['interval'] < WP_CRON_LOCK_TIMEOUT ) {
$interval .= sprintf(
'<span class="status-crontrol-warning"><br><span class="dashicons dashicons-warning" aria-hidden="true"></span> %s</span>',
sprintf(
/* translators: 1: The name of the configuration constant, 2: The value of the configuration constant */
esc_html__( 'This interval is less than the %1$s constant which is set to %2$s. Events that use it may not run on time.', 'wp-crontrol' ),
'<code>WP_CRON_LOCK_TIMEOUT</code>',
intval( WP_CRON_LOCK_TIMEOUT )
)
);
}
return $interval;
}
/**
* Returns the output for the display name cell of a table row.
*
* @param array $schedule The schedule for the current row.
* @return string The cell output.
*/
protected function column_crontrol_display( array $schedule ) {
return esc_html( $schedule['display'] );
}
/**
* Outputs a message when there are no items to show in the table.
*/
public function no_items() {
esc_html_e( 'There are no schedules.', 'wp-crontrol' );
}
}
@@ -0,0 +1,79 @@
<?php
/**
* Functions related to schedules.
*
* @package wp-crontrol
*/
namespace Crontrol\Schedule;
/**
* Adds a new custom cron schedule.
*
* @param string $name The internal name of the schedule.
* @param int $interval The interval between executions of the new schedule.
* @param string $display The display name of the schedule.
*/
function add( $name, $interval, $display ) {
$old_scheds = get_option( 'crontrol_schedules', array() );
$old_scheds[ $name ] = array(
'interval' => $interval,
'display' => $display,
);
update_option( 'crontrol_schedules', $old_scheds );
}
/**
* Deletes a custom cron schedule.
*
* @param string $name The internal_name of the schedule to delete.
*/
function delete( $name ) {
$scheds = get_option( 'crontrol_schedules', array() );
unset( $scheds[ $name ] );
update_option( 'crontrol_schedules', $scheds );
}
/**
* Gets a sorted (according to interval) list of the cron schedules
*
* @return array[] Array of cron schedule arrays.
*/
function get() {
$schedules = wp_get_schedules();
uasort( $schedules, function( array $a, array $b ) {
return ( $a['interval'] - $b['interval'] );
} );
array_walk( $schedules, function( array &$schedule, $name ) {
$schedule['name'] = $name;
} );
return $schedules;
}
/**
* Displays a dropdown filled with the possible schedules, including non-repeating.
*
* @param bool $current The currently selected schedule.
*/
function dropdown( $current = false ) {
$schedules = get();
?>
<select class="postform" name="schedule" id="schedule" required>
<option <?php selected( $current, '_oneoff' ); ?> value="_oneoff"><?php esc_html_e( 'Non-repeating', 'wp-crontrol' ); ?></option>
<?php foreach ( $schedules as $sched_name => $sched_data ) { ?>
<option <?php selected( $current, $sched_name ); ?> value="<?php echo esc_attr( $sched_name ); ?>">
<?php
printf(
'%s (%s)',
esc_html( $sched_data['display'] ),
esc_html( $sched_name )
);
?>
</option>
<?php } ?>
</select>
<?php
}