Version Description
Download this release
Release Info
Developer | johnbillion |
Plugin | WP Crontrol |
Version | 1.8.2 |
Comparing to | |
See all releases |
Code changes from version 1.8.1 to 1.8.2
- css/wp-crontrol.css +4 -0
- js/wp-crontrol.js +24 -0
- readme.md +10 -1
- src/event-list-table.php +16 -16
- src/event.php +54 -2
- src/schedule-list-table.php +15 -1
- wp-crontrol.php +76 -11
css/wp-crontrol.css
CHANGED
@@ -50,6 +50,10 @@ table.wp-list-table {
|
|
50 |
border-color: #dc3232;
|
51 |
}
|
52 |
|
|
|
|
|
|
|
|
|
53 |
.status-crontrol-complete,
|
54 |
.wp-list-table tr.crontrol-complete td.column-status {
|
55 |
color: #080;
|
50 |
border-color: #dc3232;
|
51 |
}
|
52 |
|
53 |
+
#crontrol-hash-message {
|
54 |
+
display: none;
|
55 |
+
}
|
56 |
+
|
57 |
.status-crontrol-complete,
|
58 |
.wp-list-table tr.crontrol-complete td.column-status {
|
59 |
color: #080;
|
js/wp-crontrol.js
CHANGED
@@ -6,7 +6,31 @@
|
|
6 |
|
7 |
const header = document.getElementById( 'crontrol-header' );
|
8 |
const wpbody = document.getElementById( 'wpbody-content' );
|
|
|
9 |
|
10 |
if ( header && wpbody ) {
|
11 |
wpbody.prepend( header );
|
12 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
|
7 |
const header = document.getElementById( 'crontrol-header' );
|
8 |
const wpbody = document.getElementById( 'wpbody-content' );
|
9 |
+
let hashtimer = null;
|
10 |
|
11 |
if ( header && wpbody ) {
|
12 |
wpbody.prepend( header );
|
13 |
}
|
14 |
+
|
15 |
+
if ( window.wpCrontrol && window.wpCrontrol.eventsHash && window.wpCrontrol.eventsHashInterval ) {
|
16 |
+
hashtimer = setInterval( crontrolCheckHash, ( 1000 * window.wpCrontrol.eventsHashInterval ) );
|
17 |
+
}
|
18 |
+
|
19 |
+
function crontrolCheckHash() {
|
20 |
+
jQuery.ajax( {
|
21 |
+
url: window.ajaxurl,
|
22 |
+
type: 'post',
|
23 |
+
data: {
|
24 |
+
action: 'crontrol_checkhash',
|
25 |
+
},
|
26 |
+
dataType: 'json',
|
27 |
+
} ).done( function( response ) {
|
28 |
+
if ( response.success && response.data && response.data !== window.wpCrontrol.eventsHash ) {
|
29 |
+
jQuery( '#crontrol-hash-message' ).slideDown();
|
30 |
+
|
31 |
+
if ( hashtimer ) {
|
32 |
+
clearInterval( hashtimer );
|
33 |
+
}
|
34 |
+
}
|
35 |
+
} );
|
36 |
+
}
|
readme.md
CHANGED
@@ -4,7 +4,7 @@ Contributors: johnbillion, scompt
|
|
4 |
Tags: cron, wp-cron, crontrol, debug
|
5 |
Requires at least: 4.1
|
6 |
Tested up to: 5.4
|
7 |
-
Stable tag: 1.8.
|
8 |
Requires PHP: 5.3
|
9 |
|
10 |
WP Crontrol lets you view and control what's happening in the WP-Cron system.
|
@@ -76,6 +76,15 @@ The cron commands which were previously included in WP Crontrol are now part of
|
|
76 |
|
77 |
## Changelog ##
|
78 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
79 |
### 1.8.1 ###
|
80 |
|
81 |
* Fix the bottom bulk action menu on the event listing screen.
|
4 |
Tags: cron, wp-cron, crontrol, debug
|
5 |
Requires at least: 4.1
|
6 |
Tested up to: 5.4
|
7 |
+
Stable tag: 1.8.2
|
8 |
Requires PHP: 5.3
|
9 |
|
10 |
WP Crontrol lets you view and control what's happening in the WP-Cron system.
|
76 |
|
77 |
## Changelog ##
|
78 |
|
79 |
+
### 1.8.2 ###
|
80 |
+
|
81 |
+
* Bypass the duplicate event check when manually running an event. This allows an event to manually run even if it's due within ten minutes or if it's overdue.
|
82 |
+
* Force only one event to fire when manually running a cron event.
|
83 |
+
* Introduce polling of the events list in order to show a warning when the event listing screen is out of date.
|
84 |
+
* Add a warning for cron schedules which are shorter than `WP_CRON_LOCK_TIMEOUT`.
|
85 |
+
* Add the Site Health check event to the list of persistent core hooks.
|
86 |
+
|
87 |
+
|
88 |
### 1.8.1 ###
|
89 |
|
90 |
* Fix the bottom bulk action menu on the event listing screen.
|
src/event-list-table.php
CHANGED
@@ -5,7 +5,7 @@
|
|
5 |
* @package wp-crontrol
|
6 |
*/
|
7 |
|
8 |
-
namespace Crontrol;
|
9 |
|
10 |
use stdClass;
|
11 |
|
@@ -14,7 +14,7 @@ require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
|
|
14 |
/**
|
15 |
* Cron event list table class.
|
16 |
*/
|
17 |
-
class
|
18 |
|
19 |
/**
|
20 |
* Array of cron event hooks that are persistently added by WordPress core.
|
@@ -53,11 +53,11 @@ class Event_List_Table extends \WP_List_Table {
|
|
53 |
* Prepares the list table items and arguments.
|
54 |
*/
|
55 |
public function prepare_items() {
|
56 |
-
self::$persistent_core_hooks = get_persistent_core_hooks();
|
57 |
self::$can_edit_files = current_user_can( 'edit_files' );
|
58 |
-
self::$count_by_hook =
|
59 |
|
60 |
-
$events =
|
61 |
|
62 |
if ( ! empty( $_GET['s'] ) ) {
|
63 |
$s = sanitize_text_field( wp_unslash( $_GET['s'] ) );
|
@@ -93,7 +93,7 @@ class Event_List_Table extends \WP_List_Table {
|
|
93 |
'crontrol_next' => sprintf(
|
94 |
/* translators: %s: UTC offset */
|
95 |
__( 'Next Run (%s)', 'wp-crontrol' ),
|
96 |
-
get_utc_offset()
|
97 |
),
|
98 |
'crontrol_actions' => __( 'Action', 'wp-crontrol' ),
|
99 |
'crontrol_recurrence' => __( 'Recurrence', 'wp-crontrol' ),
|
@@ -135,17 +135,17 @@ class Event_List_Table extends \WP_List_Table {
|
|
135 |
$classes[] = 'crontrol-error';
|
136 |
}
|
137 |
|
138 |
-
$schedule_name = ( $event->interval ?
|
139 |
|
140 |
if ( is_wp_error( $schedule_name ) ) {
|
141 |
$classes[] = 'crontrol-error';
|
142 |
}
|
143 |
|
144 |
-
if ( ! get_hook_callbacks( $event->hook ) ) {
|
145 |
$classes[] = 'crontrol-warning';
|
146 |
}
|
147 |
|
148 |
-
if (
|
149 |
$classes[] = 'crontrol-warning';
|
150 |
}
|
151 |
|
@@ -284,7 +284,7 @@ class Event_List_Table extends \WP_List_Table {
|
|
284 |
*/
|
285 |
protected function column_crontrol_args( $event ) {
|
286 |
if ( ! empty( $event->args ) ) {
|
287 |
-
$args = json_output( $event->args );
|
288 |
}
|
289 |
|
290 |
if ( 'crontrol_cron_job' === $event->hook ) {
|
@@ -336,7 +336,7 @@ class Event_List_Table extends \WP_List_Table {
|
|
336 |
* @return string The cell output.
|
337 |
*/
|
338 |
protected function column_crontrol_actions( $event ) {
|
339 |
-
$hook_callbacks = get_hook_callbacks( $event->hook );
|
340 |
|
341 |
if ( 'crontrol_cron_job' === $event->hook ) {
|
342 |
return '<em>' . esc_html__( 'WP Crontrol', 'wp-crontrol' ) . '</em>';
|
@@ -344,7 +344,7 @@ class Event_List_Table extends \WP_List_Table {
|
|
344 |
$callbacks = array();
|
345 |
|
346 |
foreach ( $hook_callbacks as $callback ) {
|
347 |
-
$callbacks[] = output_callback( $callback );
|
348 |
}
|
349 |
|
350 |
return implode( '<br>', $callbacks ); // WPCS:: XSS ok.
|
@@ -373,14 +373,14 @@ class Event_List_Table extends \WP_List_Table {
|
|
373 |
);
|
374 |
|
375 |
$until = $event->time - time();
|
376 |
-
$late =
|
377 |
|
378 |
if ( $late ) {
|
379 |
// Show a warning for events that are late.
|
380 |
$ago = sprintf(
|
381 |
/* translators: %s: Time period, for example "8 minutes" */
|
382 |
__( '%s ago', 'wp-crontrol' ),
|
383 |
-
interval( abs( $until ) )
|
384 |
);
|
385 |
return sprintf(
|
386 |
'%s<br><span class="status-crontrol-warning"><span class="dashicons dashicons-warning" aria-hidden="true"></span> %s</span>',
|
@@ -392,7 +392,7 @@ class Event_List_Table extends \WP_List_Table {
|
|
392 |
return sprintf(
|
393 |
'%s<br>%s',
|
394 |
$time,
|
395 |
-
esc_html( interval( $until ) )
|
396 |
);
|
397 |
}
|
398 |
|
@@ -404,7 +404,7 @@ class Event_List_Table extends \WP_List_Table {
|
|
404 |
*/
|
405 |
protected function column_crontrol_recurrence( $event ) {
|
406 |
if ( $event->schedule ) {
|
407 |
-
$schedule_name =
|
408 |
if ( is_wp_error( $schedule_name ) ) {
|
409 |
return sprintf(
|
410 |
'<span class="status-crontrol-error"><span class="dashicons dashicons-warning" aria-hidden="true"></span> %s</span>',
|
5 |
* @package wp-crontrol
|
6 |
*/
|
7 |
|
8 |
+
namespace Crontrol\Event;
|
9 |
|
10 |
use stdClass;
|
11 |
|
14 |
/**
|
15 |
* Cron event list table class.
|
16 |
*/
|
17 |
+
class Table extends \WP_List_Table {
|
18 |
|
19 |
/**
|
20 |
* Array of cron event hooks that are persistently added by WordPress core.
|
53 |
* Prepares the list table items and arguments.
|
54 |
*/
|
55 |
public function prepare_items() {
|
56 |
+
self::$persistent_core_hooks = \Crontrol\get_persistent_core_hooks();
|
57 |
self::$can_edit_files = current_user_can( 'edit_files' );
|
58 |
+
self::$count_by_hook = count_by_hook();
|
59 |
|
60 |
+
$events = get();
|
61 |
|
62 |
if ( ! empty( $_GET['s'] ) ) {
|
63 |
$s = sanitize_text_field( wp_unslash( $_GET['s'] ) );
|
93 |
'crontrol_next' => sprintf(
|
94 |
/* translators: %s: UTC offset */
|
95 |
__( 'Next Run (%s)', 'wp-crontrol' ),
|
96 |
+
\Crontrol\get_utc_offset()
|
97 |
),
|
98 |
'crontrol_actions' => __( 'Action', 'wp-crontrol' ),
|
99 |
'crontrol_recurrence' => __( 'Recurrence', 'wp-crontrol' ),
|
135 |
$classes[] = 'crontrol-error';
|
136 |
}
|
137 |
|
138 |
+
$schedule_name = ( $event->interval ? get_schedule_name( $event ) : false );
|
139 |
|
140 |
if ( is_wp_error( $schedule_name ) ) {
|
141 |
$classes[] = 'crontrol-error';
|
142 |
}
|
143 |
|
144 |
+
if ( ! \Crontrol\get_hook_callbacks( $event->hook ) ) {
|
145 |
$classes[] = 'crontrol-warning';
|
146 |
}
|
147 |
|
148 |
+
if ( is_late( $event ) ) {
|
149 |
$classes[] = 'crontrol-warning';
|
150 |
}
|
151 |
|
284 |
*/
|
285 |
protected function column_crontrol_args( $event ) {
|
286 |
if ( ! empty( $event->args ) ) {
|
287 |
+
$args = \Crontrol\json_output( $event->args );
|
288 |
}
|
289 |
|
290 |
if ( 'crontrol_cron_job' === $event->hook ) {
|
336 |
* @return string The cell output.
|
337 |
*/
|
338 |
protected function column_crontrol_actions( $event ) {
|
339 |
+
$hook_callbacks = \Crontrol\get_hook_callbacks( $event->hook );
|
340 |
|
341 |
if ( 'crontrol_cron_job' === $event->hook ) {
|
342 |
return '<em>' . esc_html__( 'WP Crontrol', 'wp-crontrol' ) . '</em>';
|
344 |
$callbacks = array();
|
345 |
|
346 |
foreach ( $hook_callbacks as $callback ) {
|
347 |
+
$callbacks[] = \Crontrol\output_callback( $callback );
|
348 |
}
|
349 |
|
350 |
return implode( '<br>', $callbacks ); // WPCS:: XSS ok.
|
373 |
);
|
374 |
|
375 |
$until = $event->time - time();
|
376 |
+
$late = is_late( $event );
|
377 |
|
378 |
if ( $late ) {
|
379 |
// Show a warning for events that are late.
|
380 |
$ago = sprintf(
|
381 |
/* translators: %s: Time period, for example "8 minutes" */
|
382 |
__( '%s ago', 'wp-crontrol' ),
|
383 |
+
\Crontrol\interval( abs( $until ) )
|
384 |
);
|
385 |
return sprintf(
|
386 |
'%s<br><span class="status-crontrol-warning"><span class="dashicons dashicons-warning" aria-hidden="true"></span> %s</span>',
|
392 |
return sprintf(
|
393 |
'%s<br>%s',
|
394 |
$time,
|
395 |
+
esc_html( \Crontrol\interval( $until ) )
|
396 |
);
|
397 |
}
|
398 |
|
404 |
*/
|
405 |
protected function column_crontrol_recurrence( $event ) {
|
406 |
if ( $event->schedule ) {
|
407 |
+
$schedule_name = get_schedule_name( $event );
|
408 |
if ( is_wp_error( $schedule_name ) ) {
|
409 |
return sprintf(
|
410 |
'<span class="status-crontrol-error"><span class="dashicons dashicons-warning" aria-hidden="true"></span> %s</span>',
|
src/event.php
CHANGED
@@ -26,12 +26,17 @@ function run( $hookname, $sig ) {
|
|
26 |
if ( isset( $cron[ $hookname ][ $sig ] ) ) {
|
27 |
$args = $cron[ $hookname ][ $sig ]['args'];
|
28 |
delete_transient( 'doing_cron' );
|
29 |
-
$scheduled =
|
30 |
|
31 |
if ( false === $scheduled ) {
|
32 |
return $scheduled;
|
33 |
}
|
34 |
|
|
|
|
|
|
|
|
|
|
|
35 |
spawn_cron();
|
36 |
|
37 |
sleep( 1 );
|
@@ -42,6 +47,34 @@ function run( $hookname, $sig ) {
|
|
42 |
return false;
|
43 |
}
|
44 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
45 |
/**
|
46 |
* Adds a new cron event.
|
47 |
*
|
@@ -206,8 +239,27 @@ function get_schedule_name( stdClass $event ) {
|
|
206 |
* @param stdClass $event The event.
|
207 |
* @return bool Whether the event is late.
|
208 |
*/
|
209 |
-
function is_late( $event ) {
|
210 |
$until = $event->time - time();
|
211 |
|
212 |
return ( $until < ( 0 - ( 10 * MINUTE_IN_SECONDS ) ) );
|
213 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
if ( isset( $cron[ $hookname ][ $sig ] ) ) {
|
27 |
$args = $cron[ $hookname ][ $sig ]['args'];
|
28 |
delete_transient( 'doing_cron' );
|
29 |
+
$scheduled = force_schedule_single_event( $hookname, $args ); // UTC
|
30 |
|
31 |
if ( false === $scheduled ) {
|
32 |
return $scheduled;
|
33 |
}
|
34 |
|
35 |
+
add_filter( 'cron_request', function( array $cron_request_array ) {
|
36 |
+
$cron_request_array['url'] = add_query_arg( 'crontrol-single-event', 1, $cron_request_array['url'] );
|
37 |
+
return $cron_request_array;
|
38 |
+
} );
|
39 |
+
|
40 |
spawn_cron();
|
41 |
|
42 |
sleep( 1 );
|
47 |
return false;
|
48 |
}
|
49 |
|
50 |
+
/**
|
51 |
+
* Forcibly schedules a single event for the purpose of manually running it.
|
52 |
+
*
|
53 |
+
* This is used instead of `wp_schedule_single_event()` to avoid the duplicate check that's otherwise performed.
|
54 |
+
*
|
55 |
+
* @param string $hook Action hook to execute when the event is run.
|
56 |
+
* @param array $args Optional. Array containing each separate argument to pass to the hook's callback function.
|
57 |
+
* @return bool True if event successfully scheduled. False for failure.
|
58 |
+
*/
|
59 |
+
function force_schedule_single_event( $hook, $args = array() ) {
|
60 |
+
$event = (object) array(
|
61 |
+
'hook' => $hook,
|
62 |
+
'timestamp' => 1,
|
63 |
+
'schedule' => false,
|
64 |
+
'args' => $args,
|
65 |
+
);
|
66 |
+
$crons = (array) _get_cron_array();
|
67 |
+
$key = md5( serialize( $event->args ) );
|
68 |
+
|
69 |
+
$crons[ $event->timestamp ][ $event->hook ][ $key ] = array(
|
70 |
+
'schedule' => $event->schedule,
|
71 |
+
'args' => $event->args,
|
72 |
+
);
|
73 |
+
uksort( $crons, 'strnatcasecmp' );
|
74 |
+
|
75 |
+
return _set_cron_array( $crons );
|
76 |
+
}
|
77 |
+
|
78 |
/**
|
79 |
* Adds a new cron event.
|
80 |
*
|
239 |
* @param stdClass $event The event.
|
240 |
* @return bool Whether the event is late.
|
241 |
*/
|
242 |
+
function is_late( stdClass $event ) {
|
243 |
$until = $event->time - time();
|
244 |
|
245 |
return ( $until < ( 0 - ( 10 * MINUTE_IN_SECONDS ) ) );
|
246 |
}
|
247 |
+
|
248 |
+
/**
|
249 |
+
* Initialises and returns the list table for events.
|
250 |
+
*
|
251 |
+
* @return Table The list table.
|
252 |
+
*/
|
253 |
+
function get_list_table() {
|
254 |
+
static $table = null;
|
255 |
+
|
256 |
+
if ( ! $table ) {
|
257 |
+
require_once __DIR__ . '/event-list-table.php';
|
258 |
+
|
259 |
+
$table = new Table();
|
260 |
+
$table->prepare_items();
|
261 |
+
|
262 |
+
}
|
263 |
+
|
264 |
+
return $table;
|
265 |
+
}
|
src/schedule-list-table.php
CHANGED
@@ -134,11 +134,25 @@ class Schedule_List_Table extends \WP_List_Table {
|
|
134 |
* @return string The cell output.
|
135 |
*/
|
136 |
protected function column_crontrol_interval( array $schedule ) {
|
137 |
-
|
138 |
'%s (%s)',
|
139 |
esc_html( $schedule['interval'] ),
|
140 |
esc_html( interval( $schedule['interval'] ) )
|
141 |
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
142 |
}
|
143 |
|
144 |
/**
|
134 |
* @return string The cell output.
|
135 |
*/
|
136 |
protected function column_crontrol_interval( array $schedule ) {
|
137 |
+
$interval = sprintf(
|
138 |
'%s (%s)',
|
139 |
esc_html( $schedule['interval'] ),
|
140 |
esc_html( interval( $schedule['interval'] ) )
|
141 |
);
|
142 |
+
|
143 |
+
if ( $schedule['interval'] < WP_CRON_LOCK_TIMEOUT ) {
|
144 |
+
$interval .= sprintf(
|
145 |
+
'<span class="status-crontrol-warning"><br><span class="dashicons dashicons-warning" aria-hidden="true"></span> %s</span>',
|
146 |
+
sprintf(
|
147 |
+
/* translators: 1: The name of the configuration constant, 2: The value of the configuration constant */
|
148 |
+
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' ),
|
149 |
+
'<code>WP_CRON_LOCK_TIMEOUT</code>',
|
150 |
+
intval( WP_CRON_LOCK_TIMEOUT )
|
151 |
+
)
|
152 |
+
);
|
153 |
+
}
|
154 |
+
|
155 |
+
return $interval;
|
156 |
}
|
157 |
|
158 |
/**
|
wp-crontrol.php
CHANGED
@@ -5,7 +5,7 @@
|
|
5 |
* Description: WP Crontrol lets you view and control what's happening in the WP-Cron system.
|
6 |
* Author: John Blackbourn & crontributors
|
7 |
* Author URI: https://github.com/johnbillion/wp-crontrol/graphs/contributors
|
8 |
-
* Version: 1.8.
|
9 |
* Text Domain: wp-crontrol
|
10 |
* Domain Path: /languages/
|
11 |
* Requires PHP: 5.3.6
|
@@ -50,11 +50,13 @@ function init_hooks() {
|
|
50 |
add_action( 'init', __NAMESPACE__ . '\action_init' );
|
51 |
add_action( 'init', __NAMESPACE__ . '\action_handle_posts' );
|
52 |
add_action( 'admin_menu', __NAMESPACE__ . '\action_admin_menu' );
|
|
|
53 |
add_filter( "plugin_action_links_{$plugin_file}", __NAMESPACE__ . '\plugin_action_links', 10, 4 );
|
54 |
add_filter( 'removable_query_args', __NAMESPACE__ . '\filter_removable_query_args' );
|
55 |
add_filter( 'in_admin_header', __NAMESPACE__ . '\do_tabs' );
|
|
|
56 |
|
57 |
-
add_action( 'load-tools_page_crontrol_admin_manage_page', __NAMESPACE__ . '\
|
58 |
|
59 |
add_filter( 'cron_schedules', __NAMESPACE__ . '\filter_cron_schedules' );
|
60 |
add_action( 'crontrol_cron_job', __NAMESPACE__ . '\action_php_cron_event' );
|
@@ -518,6 +520,52 @@ function admin_options_page() {
|
|
518 |
<?php
|
519 |
}
|
520 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
521 |
/**
|
522 |
* Gets the status of WP-Cron functionality on the site by performing a test spawn if necessary. Cached for one hour when all is well.
|
523 |
*
|
@@ -568,7 +616,7 @@ function test_cron_spawn( $cache = true ) {
|
|
568 |
$doing_wp_cron = sprintf( '%.22F', microtime( true ) );
|
569 |
|
570 |
$cron_request = apply_filters( 'cron_request', array(
|
571 |
-
'url' => site_url( 'wp-cron.php
|
572 |
'key' => $doing_wp_cron,
|
573 |
'args' => array(
|
574 |
'timeout' => 3,
|
@@ -999,12 +1047,8 @@ function admin_manage_page() {
|
|
999 |
);
|
1000 |
}
|
1001 |
|
1002 |
-
require_once __DIR__ . '/src/event-list-table.php';
|
1003 |
-
|
1004 |
$tabs = get_tab_states();
|
1005 |
-
$table =
|
1006 |
-
|
1007 |
-
$table->prepare_items();
|
1008 |
|
1009 |
switch ( true ) {
|
1010 |
case $tabs['events']:
|
@@ -1324,9 +1368,20 @@ function interval( $since ) {
|
|
1324 |
}
|
1325 |
|
1326 |
/**
|
1327 |
-
*
|
1328 |
*/
|
1329 |
-
function
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1330 |
if ( ! function_exists( 'wp_enqueue_code_editor' ) ) {
|
1331 |
return;
|
1332 |
}
|
@@ -1368,7 +1423,14 @@ function enqueue_assets( $hook_suffix ) {
|
|
1368 |
wp_enqueue_style( 'wp-crontrol', plugin_dir_url( __FILE__ ) . 'css/wp-crontrol.css', array(), $ver );
|
1369 |
|
1370 |
$ver = filemtime( plugin_dir_path( __FILE__ ) . 'js/wp-crontrol.js' );
|
1371 |
-
wp_enqueue_script( 'wp-crontrol', plugin_dir_url( __FILE__ ) . 'js/wp-crontrol.js', array(), $ver, true );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1372 |
}
|
1373 |
|
1374 |
/**
|
@@ -1397,6 +1459,7 @@ function get_persistent_core_hooks() {
|
|
1397 |
'wp_privacy_delete_old_export_files',
|
1398 |
'wp_scheduled_auto_draft_delete',
|
1399 |
'wp_scheduled_delete',
|
|
|
1400 |
'wp_update_plugins',
|
1401 |
'wp_update_themes',
|
1402 |
'wp_version_check',
|
@@ -1461,6 +1524,8 @@ function json_output( $input ) {
|
|
1461 |
* Security: A user can only add or edit a PHP cron event if they have the `edit_files` capability. This means if a user
|
1462 |
* cannot edit files on the site (eg. through the plugin or theme editor) then they cannot edit or add a PHP cron event.
|
1463 |
*
|
|
|
|
|
1464 |
* @param string $code The PHP code to evaluate.
|
1465 |
*/
|
1466 |
function action_php_cron_event( $code ) {
|
5 |
* Description: WP Crontrol lets you view and control what's happening in the WP-Cron system.
|
6 |
* Author: John Blackbourn & crontributors
|
7 |
* Author URI: https://github.com/johnbillion/wp-crontrol/graphs/contributors
|
8 |
+
* Version: 1.8.2
|
9 |
* Text Domain: wp-crontrol
|
10 |
* Domain Path: /languages/
|
11 |
* Requires PHP: 5.3.6
|
50 |
add_action( 'init', __NAMESPACE__ . '\action_init' );
|
51 |
add_action( 'init', __NAMESPACE__ . '\action_handle_posts' );
|
52 |
add_action( 'admin_menu', __NAMESPACE__ . '\action_admin_menu' );
|
53 |
+
add_action( 'wp_ajax_crontrol_checkhash', __NAMESPACE__ . '\ajax_check_events_hash' );
|
54 |
add_filter( "plugin_action_links_{$plugin_file}", __NAMESPACE__ . '\plugin_action_links', 10, 4 );
|
55 |
add_filter( 'removable_query_args', __NAMESPACE__ . '\filter_removable_query_args' );
|
56 |
add_filter( 'in_admin_header', __NAMESPACE__ . '\do_tabs' );
|
57 |
+
add_filter( 'pre_unschedule_event', __NAMESPACE__ . '\maybe_clear_doing_cron' );
|
58 |
|
59 |
+
add_action( 'load-tools_page_crontrol_admin_manage_page', __NAMESPACE__ . '\setup_manage_page' );
|
60 |
|
61 |
add_filter( 'cron_schedules', __NAMESPACE__ . '\filter_cron_schedules' );
|
62 |
add_action( 'crontrol_cron_job', __NAMESPACE__ . '\action_php_cron_event' );
|
520 |
<?php
|
521 |
}
|
522 |
|
523 |
+
/**
|
524 |
+
* Clears the doing cron status when an event is unscheduled.
|
525 |
+
*
|
526 |
+
* What on earth does this function do, and why?
|
527 |
+
*
|
528 |
+
* Good question. The purpose of this function is to prevent other overdue cron events from firing when an event is run
|
529 |
+
* manually with the "Run Now" action. WP Crontrol works very hard to ensure that when cron event runs manually that it
|
530 |
+
* runs in the exact same way it would run as part of its schedule - via a properly spawned cron with a queued event in
|
531 |
+
* place. It does this by queueing an event at time `1` (1 second into 1st January 1970) and then immediately spawning
|
532 |
+
* cron (see the `Event\run()` function).
|
533 |
+
*
|
534 |
+
* The problem this causes is if other events are due then they will all run too, and this isn't desirable because if a
|
535 |
+
* site has a large number of stuck events due to a problem with the cron runner then it's not desirable for all those
|
536 |
+
* events to run when another is manually run. This happens because WordPress core will attempt to run all due events
|
537 |
+
* whenever cron is spawned.
|
538 |
+
*
|
539 |
+
* The code in this function prevents multiple events from running by changing the value of the `doing_cron` transient
|
540 |
+
* when an event gets unscheduled during a manual run, which prevents wp-cron.php from iterating more than one event.
|
541 |
+
*
|
542 |
+
* The `pre_unschedule_event` filter is used for this because it's just about the only hook available within this loop.
|
543 |
+
*
|
544 |
+
* Refs:
|
545 |
+
* - https://core.trac.wordpress.org/browser/trunk/src/wp-cron.php?rev=47198&marks=127,141#L122
|
546 |
+
*
|
547 |
+
* @param mixed $pre The pre-flight value of the event unschedule short-circuit. Not used.
|
548 |
+
* @return mixed Thee unaltered pre-flight value.
|
549 |
+
*/
|
550 |
+
function maybe_clear_doing_cron( $pre ) {
|
551 |
+
if ( defined( 'DOING_CRON' ) && DOING_CRON && isset( $_GET['crontrol-single-event'] ) ) {
|
552 |
+
delete_transient( 'doing_cron' );
|
553 |
+
}
|
554 |
+
|
555 |
+
return $pre;
|
556 |
+
}
|
557 |
+
|
558 |
+
/**
|
559 |
+
* Ajax handler which outputs a hash of the current list of scheduled events.
|
560 |
+
*/
|
561 |
+
function ajax_check_events_hash() {
|
562 |
+
if ( ! current_user_can( 'manage_options' ) ) {
|
563 |
+
wp_send_json_error( null, 403 );
|
564 |
+
}
|
565 |
+
|
566 |
+
wp_send_json_success( md5( json_encode( Event\get_list_table()->items ) ) );
|
567 |
+
}
|
568 |
+
|
569 |
/**
|
570 |
* Gets the status of WP-Cron functionality on the site by performing a test spawn if necessary. Cached for one hour when all is well.
|
571 |
*
|
616 |
$doing_wp_cron = sprintf( '%.22F', microtime( true ) );
|
617 |
|
618 |
$cron_request = apply_filters( 'cron_request', array(
|
619 |
+
'url' => add_query_arg( 'doing_wp_cron', $doing_wp_cron, site_url( 'wp-cron.php' ) ),
|
620 |
'key' => $doing_wp_cron,
|
621 |
'args' => array(
|
622 |
'timeout' => 3,
|
1047 |
);
|
1048 |
}
|
1049 |
|
|
|
|
|
1050 |
$tabs = get_tab_states();
|
1051 |
+
$table = Event\get_list_table();
|
|
|
|
|
1052 |
|
1053 |
switch ( true ) {
|
1054 |
case $tabs['events']:
|
1368 |
}
|
1369 |
|
1370 |
/**
|
1371 |
+
* Sets up the Events listing screen.
|
1372 |
*/
|
1373 |
+
function setup_manage_page() {
|
1374 |
+
// Initialise the list table
|
1375 |
+
Event\get_list_table();
|
1376 |
+
|
1377 |
+
// Add the initially hidden admin notice about the out of date events list
|
1378 |
+
add_action( 'admin_notices', function() {
|
1379 |
+
printf(
|
1380 |
+
'<div id="crontrol-hash-message" class="notice notice-warning"><p>%s</p></div>',
|
1381 |
+
esc_html__( 'The scheduled cron events have changed since you first opened this page. Reload the page to see the up to date list.', 'wp-crontrol' )
|
1382 |
+
);
|
1383 |
+
} );
|
1384 |
+
|
1385 |
if ( ! function_exists( 'wp_enqueue_code_editor' ) ) {
|
1386 |
return;
|
1387 |
}
|
1423 |
wp_enqueue_style( 'wp-crontrol', plugin_dir_url( __FILE__ ) . 'css/wp-crontrol.css', array(), $ver );
|
1424 |
|
1425 |
$ver = filemtime( plugin_dir_path( __FILE__ ) . 'js/wp-crontrol.js' );
|
1426 |
+
wp_enqueue_script( 'wp-crontrol', plugin_dir_url( __FILE__ ) . 'js/wp-crontrol.js', array( 'jquery' ), $ver, true );
|
1427 |
+
|
1428 |
+
if ( ! empty( $tab['events'] ) ) {
|
1429 |
+
wp_localize_script( 'wp-crontrol', 'wpCrontrol', array(
|
1430 |
+
'eventsHash' => md5( json_encode( Event\get_list_table()->items ) ),
|
1431 |
+
'eventsHashInterval' => 20,
|
1432 |
+
) );
|
1433 |
+
}
|
1434 |
}
|
1435 |
|
1436 |
/**
|
1459 |
'wp_privacy_delete_old_export_files',
|
1460 |
'wp_scheduled_auto_draft_delete',
|
1461 |
'wp_scheduled_delete',
|
1462 |
+
'wp_site_health_scheduled_check',
|
1463 |
'wp_update_plugins',
|
1464 |
'wp_update_themes',
|
1465 |
'wp_version_check',
|
1524 |
* Security: A user can only add or edit a PHP cron event if they have the `edit_files` capability. This means if a user
|
1525 |
* cannot edit files on the site (eg. through the plugin or theme editor) then they cannot edit or add a PHP cron event.
|
1526 |
*
|
1527 |
+
* Therefore, the user access level required to execute arbitrary PHP code does not change with WP Crontrol activated.
|
1528 |
+
*
|
1529 |
* @param string $code The PHP code to evaluate.
|
1530 |
*/
|
1531 |
function action_php_cron_event( $code ) {
|