Version Description
Download this release
Release Info
Developer | johnbillion |
Plugin | WP Crontrol |
Version | 1.11.0 |
Comparing to | |
See all releases |
Code changes from version 1.10.0 to 1.11.0
- .editorconfig +19 -0
- phpstan.neon.dist +15 -0
- readme.md +24 -1
- src/event-list-table.php +94 -29
- src/event.php +54 -25
- src/request.php +108 -0
- src/schedule-list-table.php +16 -12
- src/schedule.php +10 -1
- wp-crontrol.php +365 -168
.editorconfig
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
root = true
|
2 |
+
|
3 |
+
[*]
|
4 |
+
charset = utf-8
|
5 |
+
end_of_line = lf
|
6 |
+
insert_final_newline = true
|
7 |
+
trim_trailing_whitespace = true
|
8 |
+
indent_style = tab
|
9 |
+
|
10 |
+
[*.yml]
|
11 |
+
indent_style = space
|
12 |
+
indent_size = 2
|
13 |
+
|
14 |
+
[{*.neon,*.neon.dist}]
|
15 |
+
indent_style = space
|
16 |
+
indent_size = 4
|
17 |
+
|
18 |
+
[*.md]
|
19 |
+
trim_trailing_whitespace = false
|
phpstan.neon.dist
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
includes:
|
2 |
+
- vendor/szepeviktor/phpstan-wordpress/extension.neon
|
3 |
+
parameters:
|
4 |
+
level: 8
|
5 |
+
inferPrivatePropertyTypeFromConstructor: true
|
6 |
+
paths:
|
7 |
+
- wp-crontrol.php
|
8 |
+
- src/
|
9 |
+
bootstrapFiles:
|
10 |
+
- tests/stubs.php
|
11 |
+
ignoreErrors:
|
12 |
+
# Uses func_get_args()
|
13 |
+
- '#^Function apply_filters invoked with [34567] parameters, 2 required\.$#'
|
14 |
+
# External plugin
|
15 |
+
- '#QM_Util#'
|
readme.md
CHANGED
@@ -4,7 +4,7 @@ Contributors: johnbillion, scompt
|
|
4 |
Tags: cron, wp-cron, crontrol, debug
|
5 |
Requires at least: 4.2
|
6 |
Tested up to: 5.8
|
7 |
-
Stable tag: 1.
|
8 |
Requires PHP: 5.3
|
9 |
Donate link: https://github.com/sponsors/johnbillion
|
10 |
|
@@ -19,6 +19,7 @@ WP Crontrol enables you to view and control what's happening in the WP-Cron syst
|
|
19 |
* Add new cron events.
|
20 |
* Bulk delete cron events.
|
21 |
* Add and remove custom cron schedules.
|
|
|
22 |
|
23 |
WP Crontrol is aware of timezones, will alert you to events that have no actions or that have missed their schedule, and will show you a warning message if your cron system doesn't appear to be working (for example if your server can't connect to itself to fire scheduled cron events).
|
24 |
|
@@ -84,10 +85,18 @@ Please see the "Which users can manage PHP cron events?" FAQ for information abo
|
|
84 |
|
85 |
[You can read all about problems with editing cron events here](https://github.com/johnbillion/wp-crontrol/wiki/Problems-adding-or-editing-WP-Cron-events).
|
86 |
|
|
|
|
|
|
|
|
|
87 |
### Can I see a historical log of all the cron events that ran on my site?
|
88 |
|
89 |
Not yet, but I hope to add this functionality soon.
|
90 |
|
|
|
|
|
|
|
|
|
91 |
### What's the use of adding new cron schedules?
|
92 |
|
93 |
Cron schedules are used by WordPress and plugins for scheduling events to be executed at regular intervals. Intervals must be provided by the WordPress core or a plugin in order to be used. As an example, many backup plugins provide support for periodic backups. In order to do a weekly backup, a weekly cron schedule must be entered into WP Crontrol first and then a backup plugin can take advantage of it as an interval.
|
@@ -116,6 +125,8 @@ The next step is to write your function. Here's a simple example:
|
|
116 |
|
117 |
In the Tools → Cron Events admin panel, click on "Add New". In the form that appears, select "PHP Cron Event" and enter the schedule and next run time. The event schedule is how often your event will be executed. If you don't see a good interval, then add one in the Settings → Cron Schedules admin panel. In the "Hook code" area, enter the PHP code that should be run when your cron event is executed. You don't need to provide the PHP opening tag (`<?php`).
|
118 |
|
|
|
|
|
119 |
### Which users can manage cron events and schedules?
|
120 |
|
121 |
Only users with the `manage_options` capability can manage cron events and schedules. By default, only Administrators have this capability.
|
@@ -132,6 +143,10 @@ Therefore, the user access level required to execute arbitrary PHP code does not
|
|
132 |
|
133 |
The cron commands which were previously included in WP Crontrol are now part of WP-CLI (since 0.16), so this plugin no longer provides any WP-CLI commands. See `wp help cron` for more info.
|
134 |
|
|
|
|
|
|
|
|
|
135 |
## Screenshots
|
136 |
|
137 |
1. Cron events can be modified, deleted, and executed<br>![](.wordpress-org/screenshot-1.png)
|
@@ -142,6 +157,14 @@ The cron commands which were previously included in WP Crontrol are now part of
|
|
142 |
|
143 |
## Changelog ##
|
144 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
145 |
### 1.10.0 ###
|
146 |
|
147 |
* Support for more granular cron-related error messages in WordPress 5.7
|
4 |
Tags: cron, wp-cron, crontrol, debug
|
5 |
Requires at least: 4.2
|
6 |
Tested up to: 5.8
|
7 |
+
Stable tag: 1.11.0
|
8 |
Requires PHP: 5.3
|
9 |
Donate link: https://github.com/sponsors/johnbillion
|
10 |
|
19 |
* Add new cron events.
|
20 |
* Bulk delete cron events.
|
21 |
* Add and remove custom cron schedules.
|
22 |
+
* Export cron event lists as a CSV file.
|
23 |
|
24 |
WP Crontrol is aware of timezones, will alert you to events that have no actions or that have missed their schedule, and will show you a warning message if your cron system doesn't appear to be working (for example if your server can't connect to itself to fire scheduled cron events).
|
25 |
|
85 |
|
86 |
[You can read all about problems with editing cron events here](https://github.com/johnbillion/wp-crontrol/wiki/Problems-adding-or-editing-WP-Cron-events).
|
87 |
|
88 |
+
### Can I export a list of cron events?
|
89 |
+
|
90 |
+
Yes, a CSV file of the event list can be exported via the "Export" button on the cron event listing screen. This file can be opened in any spreadsheet application.
|
91 |
+
|
92 |
### Can I see a historical log of all the cron events that ran on my site?
|
93 |
|
94 |
Not yet, but I hope to add this functionality soon.
|
95 |
|
96 |
+
### Can I see a historical log of edits, additions, and deletions of cron events and schedules?
|
97 |
+
|
98 |
+
Yes. The excellent <a href="https://wordpress.org/plugins/simple-history/">Simple History plugin</a> has built-in support for logging actions performed via WP Crontrol.
|
99 |
+
|
100 |
### What's the use of adding new cron schedules?
|
101 |
|
102 |
Cron schedules are used by WordPress and plugins for scheduling events to be executed at regular intervals. Intervals must be provided by the WordPress core or a plugin in order to be used. As an example, many backup plugins provide support for periodic backups. In order to do a weekly backup, a weekly cron schedule must be entered into WP Crontrol first and then a backup plugin can take advantage of it as an interval.
|
125 |
|
126 |
In the Tools → Cron Events admin panel, click on "Add New". In the form that appears, select "PHP Cron Event" and enter the schedule and next run time. The event schedule is how often your event will be executed. If you don't see a good interval, then add one in the Settings → Cron Schedules admin panel. In the "Hook code" area, enter the PHP code that should be run when your cron event is executed. You don't need to provide the PHP opening tag (`<?php`).
|
127 |
|
128 |
+
Please see the "Which users can manage PHP cron events?" FAQ for information about which users can create PHP cron events.
|
129 |
+
|
130 |
### Which users can manage cron events and schedules?
|
131 |
|
132 |
Only users with the `manage_options` capability can manage cron events and schedules. By default, only Administrators have this capability.
|
143 |
|
144 |
The cron commands which were previously included in WP Crontrol are now part of WP-CLI (since 0.16), so this plugin no longer provides any WP-CLI commands. See `wp help cron` for more info.
|
145 |
|
146 |
+
### Who took the photo in the plugin header image?
|
147 |
+
|
148 |
+
The photo was taken by <a href="https://www.flickr.com/photos/michaelpardo/21453119315">Michael Pardo</a> and is in the public domain.
|
149 |
+
|
150 |
## Screenshots
|
151 |
|
152 |
1. Cron events can be modified, deleted, and executed<br>![](.wordpress-org/screenshot-1.png)
|
157 |
|
158 |
## Changelog ##
|
159 |
|
160 |
+
### 1.11.0 ###
|
161 |
+
|
162 |
+
* Introduced an `Export` feature to the event listing screen for exporting the list of events as a CSV file.
|
163 |
+
* Added the timezone offset to the date displayed for events that are due to run after the next DST change, for extra clarity.
|
164 |
+
* Introduced the `crontrol/filter-types` and `crontrol/filtered-events` filters for adjusting the available event filters on the event listing screen.
|
165 |
+
* Lots of code quality improvements (thanks, PHPStan!).
|
166 |
+
|
167 |
+
|
168 |
### 1.10.0 ###
|
169 |
|
170 |
* Support for more granular cron-related error messages in WordPress 5.7
|
src/event-list-table.php
CHANGED
@@ -40,7 +40,7 @@ class Table extends \WP_List_Table {
|
|
40 |
/**
|
41 |
* Array of all cron events.
|
42 |
*
|
43 |
-
* @var
|
44 |
*/
|
45 |
protected $all_events = array();
|
46 |
|
@@ -58,6 +58,8 @@ class Table extends \WP_List_Table {
|
|
58 |
|
59 |
/**
|
60 |
* Prepares the list table items and arguments.
|
|
|
|
|
61 |
*/
|
62 |
public function prepare_items() {
|
63 |
self::$persistent_core_hooks = \Crontrol\get_persistent_core_hooks();
|
@@ -77,7 +79,7 @@ class Table extends \WP_List_Table {
|
|
77 |
|
78 |
if ( ! empty( $_GET['hooks_type'] ) ) {
|
79 |
$hooks_type = sanitize_text_field( $_GET['hooks_type'] );
|
80 |
-
$filtered =
|
81 |
|
82 |
if ( isset( $filtered[ $hooks_type ] ) ) {
|
83 |
$events = $filtered[ $hooks_type ];
|
@@ -114,10 +116,10 @@ class Table extends \WP_List_Table {
|
|
114 |
/**
|
115 |
* Returns events filtered by various parameters
|
116 |
*
|
117 |
-
* @param
|
118 |
-
* @return
|
119 |
*/
|
120 |
-
|
121 |
$all_core_hooks = \Crontrol\get_all_core_hooks();
|
122 |
$filtered = array(
|
123 |
'all' => $events,
|
@@ -136,6 +138,18 @@ class Table extends \WP_List_Table {
|
|
136 |
return ( ! in_array( $event->hook, $all_core_hooks, true ) );
|
137 |
} );
|
138 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
139 |
return $filtered;
|
140 |
}
|
141 |
|
@@ -162,7 +176,7 @@ class Table extends \WP_List_Table {
|
|
162 |
/**
|
163 |
* Columns to make sortable.
|
164 |
*
|
165 |
-
* @return array
|
166 |
*/
|
167 |
public function get_sortable_columns() {
|
168 |
return array(
|
@@ -174,7 +188,7 @@ class Table extends \WP_List_Table {
|
|
174 |
/**
|
175 |
* Returns an array of CSS class names for the table.
|
176 |
*
|
177 |
-
* @return string
|
178 |
*/
|
179 |
protected function get_table_classes() {
|
180 |
return array( 'widefat', 'striped', $this->_args['plural'] );
|
@@ -186,21 +200,21 @@ class Table extends \WP_List_Table {
|
|
186 |
*
|
187 |
* @since 3.1.0
|
188 |
*
|
189 |
-
* @return array
|
190 |
*/
|
191 |
protected function get_bulk_actions() {
|
192 |
return array(
|
193 |
-
'
|
194 |
);
|
195 |
}
|
196 |
|
197 |
/**
|
198 |
* Display the list of hook types.
|
199 |
*
|
200 |
-
* @return string
|
201 |
*/
|
202 |
public function get_views() {
|
203 |
-
$filtered =
|
204 |
|
205 |
$views = array();
|
206 |
$hooks_type = ( ! empty( $_GET['hooks_type'] ) ? $_GET['hooks_type'] : 'all' );
|
@@ -212,25 +226,70 @@ class Table extends \WP_List_Table {
|
|
212 |
'custom' => __( 'Custom events', 'wp-crontrol' ),
|
213 |
);
|
214 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
215 |
$url = admin_url( 'tools.php?page=crontrol_admin_manage_page' );
|
216 |
|
|
|
|
|
|
|
217 |
foreach ( $types as $key => $type ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
218 |
$views[ $key ] = sprintf(
|
219 |
'<a href="%1$s"%2$s>%3$s <span class="count">(%4$s)</span></a>',
|
220 |
-
|
221 |
$hooks_type === $key ? ' class="current"' : '',
|
222 |
-
$type,
|
223 |
-
count( $filtered[ $key ] )
|
224 |
);
|
225 |
}
|
226 |
|
227 |
return $views;
|
228 |
}
|
229 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
230 |
/**
|
231 |
* Generates content for a single row of the table.
|
232 |
*
|
233 |
-
* @param
|
|
|
234 |
*/
|
235 |
public function single_row( $event ) {
|
236 |
$classes = array();
|
@@ -289,7 +348,7 @@ class Table extends \WP_List_Table {
|
|
289 |
if ( ( 'crontrol_cron_job' !== $event->hook ) || self::$can_edit_files ) {
|
290 |
$link = array(
|
291 |
'page' => 'crontrol_admin_manage_page',
|
292 |
-
'action' => 'edit-cron',
|
293 |
'id' => rawurlencode( $event->hook ),
|
294 |
'sig' => rawurlencode( $event->sig ),
|
295 |
'next_run_utc' => rawurlencode( $event->time ),
|
@@ -301,26 +360,26 @@ class Table extends \WP_List_Table {
|
|
301 |
|
302 |
$link = array(
|
303 |
'page' => 'crontrol_admin_manage_page',
|
304 |
-
'action' => 'run-cron',
|
305 |
'id' => rawurlencode( $event->hook ),
|
306 |
'sig' => rawurlencode( $event->sig ),
|
307 |
'next_run_utc' => rawurlencode( $event->time ),
|
308 |
);
|
309 |
$link = add_query_arg( $link, admin_url( 'tools.php' ) );
|
310 |
-
$link = wp_nonce_url( $link, "run-cron_{$event->hook}_{$event->sig}" );
|
311 |
|
312 |
$links[] = "<a href='" . esc_url( $link ) . "'>" . esc_html__( 'Run Now', 'wp-crontrol' ) . '</a>';
|
313 |
|
314 |
if ( ! in_array( $event->hook, self::$persistent_core_hooks, true ) && ( ( 'crontrol_cron_job' !== $event->hook ) || self::$can_edit_files ) ) {
|
315 |
$link = array(
|
316 |
'page' => 'crontrol_admin_manage_page',
|
317 |
-
'action' => 'delete-cron',
|
318 |
'id' => rawurlencode( $event->hook ),
|
319 |
'sig' => rawurlencode( $event->sig ),
|
320 |
'next_run_utc' => rawurlencode( $event->time ),
|
321 |
);
|
322 |
$link = add_query_arg( $link, admin_url( 'tools.php' ) );
|
323 |
-
$link = wp_nonce_url( $link, "delete-cron_{$event->hook}_{$event->sig}_{$event->time}" );
|
324 |
|
325 |
$links[] = "<span class='delete'><a href='" . esc_url( $link ) . "'>" . esc_html__( 'Delete', 'wp-crontrol' ) . '</a></span>';
|
326 |
}
|
@@ -329,11 +388,11 @@ class Table extends \WP_List_Table {
|
|
329 |
if ( self::$count_by_hook[ $event->hook ] > 1 ) {
|
330 |
$link = array(
|
331 |
'page' => 'crontrol_admin_manage_page',
|
332 |
-
'action' => 'delete-hook',
|
333 |
'id' => rawurlencode( $event->hook ),
|
334 |
);
|
335 |
$link = add_query_arg( $link, admin_url( 'tools.php' ) );
|
336 |
-
$link = wp_nonce_url( $link, "delete-hook_{$event->hook}" );
|
337 |
|
338 |
$text = sprintf(
|
339 |
/* translators: %s: Number of events with a given name */
|
@@ -408,10 +467,6 @@ class Table extends \WP_List_Table {
|
|
408 |
* @return string The cell output.
|
409 |
*/
|
410 |
protected function column_crontrol_args( $event ) {
|
411 |
-
if ( ! empty( $event->args ) ) {
|
412 |
-
$args = \Crontrol\json_output( $event->args );
|
413 |
-
}
|
414 |
-
|
415 |
if ( 'crontrol_cron_job' === $event->hook ) {
|
416 |
$return = '<em>' . esc_html__( 'PHP Code', 'wp-crontrol' ) . '</em>';
|
417 |
|
@@ -448,7 +503,7 @@ class Table extends \WP_List_Table {
|
|
448 |
} else {
|
449 |
return sprintf(
|
450 |
'<pre>%s</pre>',
|
451 |
-
esc_html( $args )
|
452 |
);
|
453 |
}
|
454 |
}
|
@@ -488,8 +543,16 @@ class Table extends \WP_List_Table {
|
|
488 |
* @return string The cell output.
|
489 |
*/
|
490 |
protected function column_crontrol_next( $event ) {
|
491 |
-
$
|
492 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
493 |
|
494 |
$time = sprintf(
|
495 |
'<time datetime="%1$s">%2$s</time>',
|
@@ -556,6 +619,8 @@ class Table extends \WP_List_Table {
|
|
556 |
|
557 |
/**
|
558 |
* Outputs a message when there are no items to show in the table.
|
|
|
|
|
559 |
*/
|
560 |
public function no_items() {
|
561 |
if ( empty( $_GET['s'] ) && empty( $_GET['hooks_type'] ) ) {
|
40 |
/**
|
41 |
* Array of all cron events.
|
42 |
*
|
43 |
+
* @var stdClass[] Array of event objects.
|
44 |
*/
|
45 |
protected $all_events = array();
|
46 |
|
58 |
|
59 |
/**
|
60 |
* Prepares the list table items and arguments.
|
61 |
+
*
|
62 |
+
* @return void
|
63 |
*/
|
64 |
public function prepare_items() {
|
65 |
self::$persistent_core_hooks = \Crontrol\get_persistent_core_hooks();
|
79 |
|
80 |
if ( ! empty( $_GET['hooks_type'] ) ) {
|
81 |
$hooks_type = sanitize_text_field( $_GET['hooks_type'] );
|
82 |
+
$filtered = self::get_filtered_events( $events );
|
83 |
|
84 |
if ( isset( $filtered[ $hooks_type ] ) ) {
|
85 |
$events = $filtered[ $hooks_type ];
|
116 |
/**
|
117 |
* Returns events filtered by various parameters
|
118 |
*
|
119 |
+
* @param stdClass[] $events The list of all events.
|
120 |
+
* @return stdClass[][] Array of filtered events keyed by filter name.
|
121 |
*/
|
122 |
+
public static function get_filtered_events( array $events ) {
|
123 |
$all_core_hooks = \Crontrol\get_all_core_hooks();
|
124 |
$filtered = array(
|
125 |
'all' => $events,
|
138 |
return ( ! in_array( $event->hook, $all_core_hooks, true ) );
|
139 |
} );
|
140 |
|
141 |
+
/**
|
142 |
+
* Filters the available filtered events on the cron event listing screen.
|
143 |
+
*
|
144 |
+
* See the corresponding `crontrol/filter-types` filter to adjust the list of filter types.
|
145 |
+
*
|
146 |
+
* @since 1.11.0
|
147 |
+
*
|
148 |
+
* @param array[] $filtered Array of filtered event arrays keyed by filter name.
|
149 |
+
* @param stdClass[] $events Array of all events.
|
150 |
+
*/
|
151 |
+
$filtered = apply_filters( 'crontrol/filtered-events', $filtered, $events );
|
152 |
+
|
153 |
return $filtered;
|
154 |
}
|
155 |
|
176 |
/**
|
177 |
* Columns to make sortable.
|
178 |
*
|
179 |
+
* @return array<string,array<int,(string|bool)>>
|
180 |
*/
|
181 |
public function get_sortable_columns() {
|
182 |
return array(
|
188 |
/**
|
189 |
* Returns an array of CSS class names for the table.
|
190 |
*
|
191 |
+
* @return array<int,string> Array of class names.
|
192 |
*/
|
193 |
protected function get_table_classes() {
|
194 |
return array( 'widefat', 'striped', $this->_args['plural'] );
|
200 |
*
|
201 |
* @since 3.1.0
|
202 |
*
|
203 |
+
* @return array<string,string>
|
204 |
*/
|
205 |
protected function get_bulk_actions() {
|
206 |
return array(
|
207 |
+
'crontrol_delete_crons' => esc_html__( 'Delete', 'wp-crontrol' ),
|
208 |
);
|
209 |
}
|
210 |
|
211 |
/**
|
212 |
* Display the list of hook types.
|
213 |
*
|
214 |
+
* @return array<string,string>
|
215 |
*/
|
216 |
public function get_views() {
|
217 |
+
$filtered = self::get_filtered_events( $this->all_events );
|
218 |
|
219 |
$views = array();
|
220 |
$hooks_type = ( ! empty( $_GET['hooks_type'] ) ? $_GET['hooks_type'] : 'all' );
|
226 |
'custom' => __( 'Custom events', 'wp-crontrol' ),
|
227 |
);
|
228 |
|
229 |
+
/**
|
230 |
+
* Filters the filter types on the cron event listing screen.
|
231 |
+
*
|
232 |
+
* See the corresponding `crontrol/filtered-events` filter to adjust the filtered events.
|
233 |
+
*
|
234 |
+
* @since 1.11.0
|
235 |
+
*
|
236 |
+
* @param string[] $types Array of filter names keyed by filter name.
|
237 |
+
* @param string $hooks_type The current filter name.
|
238 |
+
*/
|
239 |
+
$types = apply_filters( 'crontrol/filter-types', $types, $hooks_type );
|
240 |
+
|
241 |
$url = admin_url( 'tools.php?page=crontrol_admin_manage_page' );
|
242 |
|
243 |
+
/**
|
244 |
+
* @var array<string,string> $types
|
245 |
+
*/
|
246 |
foreach ( $types as $key => $type ) {
|
247 |
+
if ( ! isset( $filtered[ $key ] ) ) {
|
248 |
+
continue;
|
249 |
+
}
|
250 |
+
|
251 |
+
$link = ( 'all' === $key ) ? $url : add_query_arg( 'hooks_type', $key, $url );
|
252 |
+
|
253 |
$views[ $key ] = sprintf(
|
254 |
'<a href="%1$s"%2$s>%3$s <span class="count">(%4$s)</span></a>',
|
255 |
+
esc_url( $link ),
|
256 |
$hooks_type === $key ? ' class="current"' : '',
|
257 |
+
esc_html( $type ),
|
258 |
+
number_format_i18n( count( $filtered[ $key ] ) )
|
259 |
);
|
260 |
}
|
261 |
|
262 |
return $views;
|
263 |
}
|
264 |
|
265 |
+
/**
|
266 |
+
* Extra controls to be displayed between bulk actions and pagination.
|
267 |
+
*
|
268 |
+
* @param string $which One of 'top' or 'bottom' to indicate the position on the screen.
|
269 |
+
*
|
270 |
+
* @return void
|
271 |
+
*/
|
272 |
+
protected function extra_tablenav( $which ) {
|
273 |
+
wp_nonce_field( 'crontrol-export-event-csv', 'crontrol_nonce' );
|
274 |
+
printf(
|
275 |
+
'<input type="hidden" name="hooks_type" value="%s"/>',
|
276 |
+
esc_attr( isset( $_GET['hooks_type'] ) ? sanitize_text_field( wp_unslash( $_GET['hooks_type'] ) ) : 'all' )
|
277 |
+
);
|
278 |
+
printf(
|
279 |
+
'<input type="hidden" name="s" value="%s"/>',
|
280 |
+
esc_attr( isset( $_GET['s'] ) ? sanitize_text_field( wp_unslash( $_GET['s'] ) ) : '' )
|
281 |
+
);
|
282 |
+
printf(
|
283 |
+
'<button class="button" type="submit" name="action" value="crontrol-export-event-csv">%s</button>',
|
284 |
+
esc_html__( 'Export', 'wp-crontrol' )
|
285 |
+
);
|
286 |
+
}
|
287 |
+
|
288 |
/**
|
289 |
* Generates content for a single row of the table.
|
290 |
*
|
291 |
+
* @param stdClass $event The current event.
|
292 |
+
* @return void
|
293 |
*/
|
294 |
public function single_row( $event ) {
|
295 |
$classes = array();
|
348 |
if ( ( 'crontrol_cron_job' !== $event->hook ) || self::$can_edit_files ) {
|
349 |
$link = array(
|
350 |
'page' => 'crontrol_admin_manage_page',
|
351 |
+
'action' => 'crontrol-edit-cron',
|
352 |
'id' => rawurlencode( $event->hook ),
|
353 |
'sig' => rawurlencode( $event->sig ),
|
354 |
'next_run_utc' => rawurlencode( $event->time ),
|
360 |
|
361 |
$link = array(
|
362 |
'page' => 'crontrol_admin_manage_page',
|
363 |
+
'action' => 'crontrol-run-cron',
|
364 |
'id' => rawurlencode( $event->hook ),
|
365 |
'sig' => rawurlencode( $event->sig ),
|
366 |
'next_run_utc' => rawurlencode( $event->time ),
|
367 |
);
|
368 |
$link = add_query_arg( $link, admin_url( 'tools.php' ) );
|
369 |
+
$link = wp_nonce_url( $link, "crontrol-run-cron_{$event->hook}_{$event->sig}" );
|
370 |
|
371 |
$links[] = "<a href='" . esc_url( $link ) . "'>" . esc_html__( 'Run Now', 'wp-crontrol' ) . '</a>';
|
372 |
|
373 |
if ( ! in_array( $event->hook, self::$persistent_core_hooks, true ) && ( ( 'crontrol_cron_job' !== $event->hook ) || self::$can_edit_files ) ) {
|
374 |
$link = array(
|
375 |
'page' => 'crontrol_admin_manage_page',
|
376 |
+
'action' => 'crontrol-delete-cron',
|
377 |
'id' => rawurlencode( $event->hook ),
|
378 |
'sig' => rawurlencode( $event->sig ),
|
379 |
'next_run_utc' => rawurlencode( $event->time ),
|
380 |
);
|
381 |
$link = add_query_arg( $link, admin_url( 'tools.php' ) );
|
382 |
+
$link = wp_nonce_url( $link, "crontrol-delete-cron_{$event->hook}_{$event->sig}_{$event->time}" );
|
383 |
|
384 |
$links[] = "<span class='delete'><a href='" . esc_url( $link ) . "'>" . esc_html__( 'Delete', 'wp-crontrol' ) . '</a></span>';
|
385 |
}
|
388 |
if ( self::$count_by_hook[ $event->hook ] > 1 ) {
|
389 |
$link = array(
|
390 |
'page' => 'crontrol_admin_manage_page',
|
391 |
+
'action' => 'crontrol-delete-hook',
|
392 |
'id' => rawurlencode( $event->hook ),
|
393 |
);
|
394 |
$link = add_query_arg( $link, admin_url( 'tools.php' ) );
|
395 |
+
$link = wp_nonce_url( $link, "crontrol-delete-hook_{$event->hook}" );
|
396 |
|
397 |
$text = sprintf(
|
398 |
/* translators: %s: Number of events with a given name */
|
467 |
* @return string The cell output.
|
468 |
*/
|
469 |
protected function column_crontrol_args( $event ) {
|
|
|
|
|
|
|
|
|
470 |
if ( 'crontrol_cron_job' === $event->hook ) {
|
471 |
$return = '<em>' . esc_html__( 'PHP Code', 'wp-crontrol' ) . '</em>';
|
472 |
|
503 |
} else {
|
504 |
return sprintf(
|
505 |
'<pre>%s</pre>',
|
506 |
+
esc_html( \Crontrol\json_output( $event->args ) )
|
507 |
);
|
508 |
}
|
509 |
}
|
543 |
* @return string The cell output.
|
544 |
*/
|
545 |
protected function column_crontrol_next( $event ) {
|
546 |
+
$date_local_format = 'Y-m-d H:i:s';
|
547 |
+
$offset_site = get_date_from_gmt( 'now', 'P' );
|
548 |
+
$offset_event = get_date_from_gmt( gmdate( 'Y-m-d H:i:s', $event->time ), 'P' );
|
549 |
+
|
550 |
+
if ( $offset_site !== $offset_event ) {
|
551 |
+
$date_local_format .= ' P';
|
552 |
+
}
|
553 |
+
|
554 |
+
$date_utc = gmdate( 'c', $event->time );
|
555 |
+
$date_local = get_date_from_gmt( gmdate( 'Y-m-d H:i:s', $event->time ), $date_local_format );
|
556 |
|
557 |
$time = sprintf(
|
558 |
'<time datetime="%1$s">%2$s</time>',
|
619 |
|
620 |
/**
|
621 |
* Outputs a message when there are no items to show in the table.
|
622 |
+
*
|
623 |
+
* @return void
|
624 |
*/
|
625 |
public function no_items() {
|
626 |
if ( empty( $_GET['s'] ) && empty( $_GET['hooks_type'] ) ) {
|
src/event.php
CHANGED
@@ -21,7 +21,8 @@ use WP_Error;
|
|
21 |
* @return true|WP_Error True if the execution was successful, WP_Error if not.
|
22 |
*/
|
23 |
function run( $hookname, $sig ) {
|
24 |
-
$crons =
|
|
|
25 |
foreach ( $crons as $time => $cron ) {
|
26 |
if ( isset( $cron[ $hookname ][ $sig ] ) ) {
|
27 |
$event = $cron[ $hookname ][ $sig ];
|
@@ -50,7 +51,7 @@ function run( $hookname, $sig ) {
|
|
50 |
/**
|
51 |
* Fires after a cron event is scheduled to run manually.
|
52 |
*
|
53 |
-
* @param
|
54 |
* An object containing the event's data.
|
55 |
*
|
56 |
* @type string $hook Action hook to execute when the event is run.
|
@@ -81,8 +82,8 @@ function run( $hookname, $sig ) {
|
|
81 |
*
|
82 |
* This is used instead of `wp_schedule_single_event()` to avoid the duplicate check that's otherwise performed.
|
83 |
*
|
84 |
-
* @param string
|
85 |
-
* @param
|
86 |
* @return true|WP_Error True if event successfully scheduled. WP_Error on failure.
|
87 |
*/
|
88 |
function force_schedule_single_event( $hook, $args = array() ) {
|
@@ -92,7 +93,7 @@ function force_schedule_single_event( $hook, $args = array() ) {
|
|
92 |
'schedule' => false,
|
93 |
'args' => $args,
|
94 |
);
|
95 |
-
$crons = (
|
96 |
$key = md5( serialize( $event->args ) );
|
97 |
|
98 |
$crons[ $event->timestamp ][ $event->hook ][ $key ] = array(
|
@@ -121,14 +122,18 @@ function force_schedule_single_event( $hook, $args = array() ) {
|
|
121 |
/**
|
122 |
* Adds a new cron event.
|
123 |
*
|
124 |
-
* @param string
|
125 |
-
* @param string
|
126 |
-
* @param string
|
127 |
-
* @param
|
128 |
* @return true|WP_error True if the addition was successful, WP_Error otherwise.
|
129 |
*/
|
130 |
function add( $next_run_local, $schedule, $hook, array $args ) {
|
131 |
-
|
|
|
|
|
|
|
|
|
132 |
|
133 |
if ( false === $next_run_local ) {
|
134 |
return new WP_Error(
|
@@ -137,7 +142,7 @@ function add( $next_run_local, $schedule, $hook, array $args ) {
|
|
137 |
);
|
138 |
}
|
139 |
|
140 |
-
$next_run_utc = get_gmt_from_date( gmdate( 'Y-m-d H:i:s', $next_run_local ), 'U' );
|
141 |
|
142 |
if ( ! is_array( $args ) ) {
|
143 |
$args = array();
|
@@ -157,7 +162,7 @@ function add( $next_run_local, $schedule, $hook, array $args ) {
|
|
157 |
}
|
158 |
}
|
159 |
|
160 |
-
if ( '_oneoff' === $schedule ) {
|
161 |
$result = wp_schedule_single_event( $next_run_utc, $hook, $args, true );
|
162 |
} else {
|
163 |
$result = wp_schedule_event( $next_run_utc, $schedule, $hook, $args, true );
|
@@ -235,10 +240,10 @@ function delete( $hook, $sig, $next_run_utc ) {
|
|
235 |
/**
|
236 |
* Returns a flattened array of cron events.
|
237 |
*
|
238 |
-
* @return
|
239 |
*/
|
240 |
function get() {
|
241 |
-
$crons =
|
242 |
$events = array();
|
243 |
|
244 |
if ( empty( $crons ) ) {
|
@@ -276,10 +281,11 @@ function get() {
|
|
276 |
* @param string $hook The hook name of the event.
|
277 |
* @param string $sig The event signature.
|
278 |
* @param string $next_run_utc The UTC time that the event would be run at.
|
279 |
-
* @return
|
280 |
*/
|
281 |
function get_single( $hook, $sig, $next_run_utc ) {
|
282 |
-
$crons =
|
|
|
283 |
if ( isset( $crons[ $next_run_utc ][ $hook ][ $sig ] ) ) {
|
284 |
$event = $crons[ $next_run_utc ][ $hook ][ $sig ];
|
285 |
|
@@ -304,10 +310,10 @@ function get_single( $hook, $sig, $next_run_utc ) {
|
|
304 |
/**
|
305 |
* Returns an array of the number of events for each hook.
|
306 |
*
|
307 |
-
* @return int
|
308 |
*/
|
309 |
function count_by_hook() {
|
310 |
-
$crons =
|
311 |
$events = array();
|
312 |
|
313 |
if ( empty( $crons ) ) {
|
@@ -402,32 +408,55 @@ function get_list_table() {
|
|
402 |
* The comparison function returns an integer less than, equal to, or greater than zero if the first argument is
|
403 |
* considered to be respectively less than, equal to, or greater than the second.
|
404 |
*
|
405 |
-
* @param
|
406 |
-
* @param
|
407 |
* @return int
|
408 |
*/
|
409 |
function uasort_order_events( $a, $b ) {
|
410 |
$orderby = ( ! empty( $_GET['orderby'] ) ) ? sanitize_text_field( $_GET['orderby'] ) : 'crontrol_next';
|
411 |
$order = ( ! empty( $_GET['order'] ) ) ? sanitize_text_field( $_GET['order'] ) : 'desc';
|
|
|
412 |
|
413 |
switch ( $orderby ) {
|
414 |
case 'crontrol_hook':
|
415 |
if ( 'desc' === $order ) {
|
416 |
-
|
417 |
} else {
|
418 |
-
|
419 |
}
|
420 |
break;
|
421 |
default:
|
422 |
if ( $a->time === $b->time ) {
|
423 |
-
|
424 |
} else {
|
425 |
if ( 'desc' === $order ) {
|
426 |
-
|
427 |
} else {
|
428 |
-
|
429 |
}
|
430 |
}
|
431 |
break;
|
432 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
433 |
}
|
21 |
* @return true|WP_Error True if the execution was successful, WP_Error if not.
|
22 |
*/
|
23 |
function run( $hookname, $sig ) {
|
24 |
+
$crons = get_core_cron_array();
|
25 |
+
|
26 |
foreach ( $crons as $time => $cron ) {
|
27 |
if ( isset( $cron[ $hookname ][ $sig ] ) ) {
|
28 |
$event = $cron[ $hookname ][ $sig ];
|
51 |
/**
|
52 |
* Fires after a cron event is scheduled to run manually.
|
53 |
*
|
54 |
+
* @param stdClass $event {
|
55 |
* An object containing the event's data.
|
56 |
*
|
57 |
* @type string $hook Action hook to execute when the event is run.
|
82 |
*
|
83 |
* This is used instead of `wp_schedule_single_event()` to avoid the duplicate check that's otherwise performed.
|
84 |
*
|
85 |
+
* @param string $hook Action hook to execute when the event is run.
|
86 |
+
* @param mixed[] $args Optional. Array containing each separate argument to pass to the hook's callback function.
|
87 |
* @return true|WP_Error True if event successfully scheduled. WP_Error on failure.
|
88 |
*/
|
89 |
function force_schedule_single_event( $hook, $args = array() ) {
|
93 |
'schedule' => false,
|
94 |
'args' => $args,
|
95 |
);
|
96 |
+
$crons = get_core_cron_array();
|
97 |
$key = md5( serialize( $event->args ) );
|
98 |
|
99 |
$crons[ $event->timestamp ][ $event->hook ][ $key ] = array(
|
122 |
/**
|
123 |
* Adds a new cron event.
|
124 |
*
|
125 |
+
* @param string $next_run_local The time that the event should be run at, in the site's timezone.
|
126 |
+
* @param string $schedule The recurrence of the cron event.
|
127 |
+
* @param string $hook The name of the hook to execute.
|
128 |
+
* @param mixed[] $args Arguments to add to the cron event.
|
129 |
* @return true|WP_error True if the addition was successful, WP_Error otherwise.
|
130 |
*/
|
131 |
function add( $next_run_local, $schedule, $hook, array $args ) {
|
132 |
+
/**
|
133 |
+
* @var int
|
134 |
+
*/
|
135 |
+
$current_time = current_time( 'timestamp' );
|
136 |
+
$next_run_local = strtotime( $next_run_local, $current_time );
|
137 |
|
138 |
if ( false === $next_run_local ) {
|
139 |
return new WP_Error(
|
142 |
);
|
143 |
}
|
144 |
|
145 |
+
$next_run_utc = (int) get_gmt_from_date( gmdate( 'Y-m-d H:i:s', $next_run_local ), 'U' );
|
146 |
|
147 |
if ( ! is_array( $args ) ) {
|
148 |
$args = array();
|
162 |
}
|
163 |
}
|
164 |
|
165 |
+
if ( '_oneoff' === $schedule || '' === $schedule ) {
|
166 |
$result = wp_schedule_single_event( $next_run_utc, $hook, $args, true );
|
167 |
} else {
|
168 |
$result = wp_schedule_event( $next_run_utc, $schedule, $hook, $args, true );
|
240 |
/**
|
241 |
* Returns a flattened array of cron events.
|
242 |
*
|
243 |
+
* @return stdClass[] An array of cron event objects.
|
244 |
*/
|
245 |
function get() {
|
246 |
+
$crons = get_core_cron_array();
|
247 |
$events = array();
|
248 |
|
249 |
if ( empty( $crons ) ) {
|
281 |
* @param string $hook The hook name of the event.
|
282 |
* @param string $sig The event signature.
|
283 |
* @param string $next_run_utc The UTC time that the event would be run at.
|
284 |
+
* @return stdClass|WP_Error A cron event object, or a WP_Error if it's not found.
|
285 |
*/
|
286 |
function get_single( $hook, $sig, $next_run_utc ) {
|
287 |
+
$crons = get_core_cron_array();
|
288 |
+
|
289 |
if ( isset( $crons[ $next_run_utc ][ $hook ][ $sig ] ) ) {
|
290 |
$event = $crons[ $next_run_utc ][ $hook ][ $sig ];
|
291 |
|
310 |
/**
|
311 |
* Returns an array of the number of events for each hook.
|
312 |
*
|
313 |
+
* @return array<string,int> Array of number of events for each hook, keyed by the hook name.
|
314 |
*/
|
315 |
function count_by_hook() {
|
316 |
+
$crons = get_core_cron_array();
|
317 |
$events = array();
|
318 |
|
319 |
if ( empty( $crons ) ) {
|
408 |
* The comparison function returns an integer less than, equal to, or greater than zero if the first argument is
|
409 |
* considered to be respectively less than, equal to, or greater than the second.
|
410 |
*
|
411 |
+
* @param stdClass $a The first event to compare.
|
412 |
+
* @param stdClass $b The second event to compare.
|
413 |
* @return int
|
414 |
*/
|
415 |
function uasort_order_events( $a, $b ) {
|
416 |
$orderby = ( ! empty( $_GET['orderby'] ) ) ? sanitize_text_field( $_GET['orderby'] ) : 'crontrol_next';
|
417 |
$order = ( ! empty( $_GET['order'] ) ) ? sanitize_text_field( $_GET['order'] ) : 'desc';
|
418 |
+
$compare = 0;
|
419 |
|
420 |
switch ( $orderby ) {
|
421 |
case 'crontrol_hook':
|
422 |
if ( 'desc' === $order ) {
|
423 |
+
$compare = strcmp( $a->hook, $b->hook );
|
424 |
} else {
|
425 |
+
$compare = strcmp( $b->hook, $a->hook );
|
426 |
}
|
427 |
break;
|
428 |
default:
|
429 |
if ( $a->time === $b->time ) {
|
430 |
+
$compare = 0;
|
431 |
} else {
|
432 |
if ( 'desc' === $order ) {
|
433 |
+
$compare = ( $a->time > $b->time ) ? 1 : -1;
|
434 |
} else {
|
435 |
+
$compare = ( $a->time < $b->time ) ? 1 : -1;
|
436 |
}
|
437 |
}
|
438 |
break;
|
439 |
}
|
440 |
+
|
441 |
+
return $compare;
|
442 |
+
}
|
443 |
+
|
444 |
+
/**
|
445 |
+
* Fetches the list of cron events from WordPress core.
|
446 |
+
*
|
447 |
+
* @return array<int,array<string,array<string,array<string,mixed[]>>>>
|
448 |
+
* @phpstan-return array<int,array<string,array<string,array<string,array{
|
449 |
+
* args: mixed[],
|
450 |
+
* schedule: string|false,
|
451 |
+
* interval?: int,
|
452 |
+
* }>>>>
|
453 |
+
*/
|
454 |
+
function get_core_cron_array() {
|
455 |
+
$crons = _get_cron_array();
|
456 |
+
|
457 |
+
if ( empty( $crons ) ) {
|
458 |
+
$crons = array();
|
459 |
+
}
|
460 |
+
|
461 |
+
return $crons;
|
462 |
}
|
src/request.php
ADDED
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Request handler.
|
4 |
+
*
|
5 |
+
* @package wp-crontrol
|
6 |
+
*/
|
7 |
+
|
8 |
+
namespace Crontrol;
|
9 |
+
|
10 |
+
/**
|
11 |
+
* Class Request
|
12 |
+
*/
|
13 |
+
class Request {
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Description.
|
17 |
+
*
|
18 |
+
* @var string
|
19 |
+
*/
|
20 |
+
public $args = '';
|
21 |
+
|
22 |
+
/**
|
23 |
+
* Description.
|
24 |
+
*
|
25 |
+
* @var string
|
26 |
+
*/
|
27 |
+
public $next_run_date_local = '';
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Description.
|
31 |
+
*
|
32 |
+
* @var string
|
33 |
+
*/
|
34 |
+
public $next_run_date_local_custom_date = '';
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Description.
|
38 |
+
*
|
39 |
+
* @var string
|
40 |
+
*/
|
41 |
+
public $next_run_date_local_custom_time = '';
|
42 |
+
|
43 |
+
/**
|
44 |
+
* Description.
|
45 |
+
*
|
46 |
+
* @var string
|
47 |
+
*/
|
48 |
+
public $schedule = '';
|
49 |
+
|
50 |
+
/**
|
51 |
+
* Description.
|
52 |
+
*
|
53 |
+
* @var string
|
54 |
+
*/
|
55 |
+
public $hookname = '';
|
56 |
+
|
57 |
+
/**
|
58 |
+
* Description.
|
59 |
+
*
|
60 |
+
* @var string
|
61 |
+
*/
|
62 |
+
public $hookcode = '';
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Description.
|
66 |
+
*
|
67 |
+
* @var string
|
68 |
+
*/
|
69 |
+
public $eventname = '';
|
70 |
+
|
71 |
+
/**
|
72 |
+
* Description.
|
73 |
+
*
|
74 |
+
* @var string
|
75 |
+
*/
|
76 |
+
public $original_hookname = '';
|
77 |
+
|
78 |
+
/**
|
79 |
+
* Description.
|
80 |
+
*
|
81 |
+
* @var string
|
82 |
+
*/
|
83 |
+
public $original_sig = '';
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Description.
|
87 |
+
*
|
88 |
+
* @var string
|
89 |
+
*/
|
90 |
+
public $original_next_run_utc = '';
|
91 |
+
|
92 |
+
/**
|
93 |
+
* Crontrol_Request constructor.
|
94 |
+
*
|
95 |
+
* @param array<string,mixed> $props Properties.
|
96 |
+
* @return Request This object.
|
97 |
+
*/
|
98 |
+
public function init( array $props ) {
|
99 |
+
foreach ( $props as $name => $value ) {
|
100 |
+
if ( property_exists( $this, $name ) ) {
|
101 |
+
$this->$name = $value;
|
102 |
+
}
|
103 |
+
}
|
104 |
+
|
105 |
+
return $this;
|
106 |
+
}
|
107 |
+
|
108 |
+
}
|
src/schedule-list-table.php
CHANGED
@@ -17,14 +17,14 @@ class Schedule_List_Table extends \WP_List_Table {
|
|
17 |
/**
|
18 |
* Array of cron event schedules that are added by WordPress core.
|
19 |
*
|
20 |
-
* @var string
|
21 |
*/
|
22 |
protected static $core_schedules;
|
23 |
|
24 |
/**
|
25 |
* Array of cron event schedule names that are in use by events.
|
26 |
*
|
27 |
-
* @var string
|
28 |
*/
|
29 |
protected static $used_schedules;
|
30 |
|
@@ -51,6 +51,8 @@ class Schedule_List_Table extends \WP_List_Table {
|
|
51 |
|
52 |
/**
|
53 |
* Prepares the list table items and arguments.
|
|
|
|
|
54 |
*/
|
55 |
public function prepare_items() {
|
56 |
$schedules = Schedule\get();
|
@@ -71,7 +73,7 @@ class Schedule_List_Table extends \WP_List_Table {
|
|
71 |
/**
|
72 |
* Returns an array of column names for the table.
|
73 |
*
|
74 |
-
* @return string
|
75 |
*/
|
76 |
public function get_columns() {
|
77 |
return array(
|
@@ -94,9 +96,9 @@ class Schedule_List_Table extends \WP_List_Table {
|
|
94 |
/**
|
95 |
* Generates and displays row action links for the table.
|
96 |
*
|
97 |
-
* @param
|
98 |
-
* @param string
|
99 |
-
* @param string
|
100 |
* @return string The row actions HTML.
|
101 |
*/
|
102 |
protected function handle_row_actions( $schedule, $column_name, $primary ) {
|
@@ -116,10 +118,10 @@ class Schedule_List_Table extends \WP_List_Table {
|
|
116 |
} else {
|
117 |
$link = add_query_arg( array(
|
118 |
'page' => 'crontrol_admin_options_page',
|
119 |
-
'action' => 'delete-
|
120 |
'id' => rawurlencode( $schedule['name'] ),
|
121 |
), admin_url( 'options-general.php' ) );
|
122 |
-
$link = wp_nonce_url( $link, 'delete-
|
123 |
|
124 |
$links[] = "<span class='delete'><a href='" . esc_url( $link ) . "'>" . esc_html__( 'Delete', 'wp-crontrol' ) . '</a></span>';
|
125 |
}
|
@@ -130,7 +132,7 @@ class Schedule_List_Table extends \WP_List_Table {
|
|
130 |
/**
|
131 |
* Returns the output for the icon cell of a table row.
|
132 |
*
|
133 |
-
* @param
|
134 |
* @return string The cell output.
|
135 |
*/
|
136 |
protected function column_crontrol_icon( array $schedule ) {
|
@@ -148,7 +150,7 @@ class Schedule_List_Table extends \WP_List_Table {
|
|
148 |
/**
|
149 |
* Returns the output for the schdule name cell of a table row.
|
150 |
*
|
151 |
-
* @param
|
152 |
* @return string The cell output.
|
153 |
*/
|
154 |
protected function column_crontrol_name( array $schedule ) {
|
@@ -158,7 +160,7 @@ class Schedule_List_Table extends \WP_List_Table {
|
|
158 |
/**
|
159 |
* Returns the output for the interval cell of a table row.
|
160 |
*
|
161 |
-
* @param
|
162 |
* @return string The cell output.
|
163 |
*/
|
164 |
protected function column_crontrol_interval( array $schedule ) {
|
@@ -186,7 +188,7 @@ class Schedule_List_Table extends \WP_List_Table {
|
|
186 |
/**
|
187 |
* Returns the output for the display name cell of a table row.
|
188 |
*
|
189 |
-
* @param
|
190 |
* @return string The cell output.
|
191 |
*/
|
192 |
protected function column_crontrol_display( array $schedule ) {
|
@@ -195,6 +197,8 @@ class Schedule_List_Table extends \WP_List_Table {
|
|
195 |
|
196 |
/**
|
197 |
* Outputs a message when there are no items to show in the table.
|
|
|
|
|
198 |
*/
|
199 |
public function no_items() {
|
200 |
esc_html_e( 'There are no schedules.', 'wp-crontrol' );
|
17 |
/**
|
18 |
* Array of cron event schedules that are added by WordPress core.
|
19 |
*
|
20 |
+
* @var array<int,string> Array of schedule names.
|
21 |
*/
|
22 |
protected static $core_schedules;
|
23 |
|
24 |
/**
|
25 |
* Array of cron event schedule names that are in use by events.
|
26 |
*
|
27 |
+
* @var array<int,string> Array of schedule names.
|
28 |
*/
|
29 |
protected static $used_schedules;
|
30 |
|
51 |
|
52 |
/**
|
53 |
* Prepares the list table items and arguments.
|
54 |
+
*
|
55 |
+
* @return void
|
56 |
*/
|
57 |
public function prepare_items() {
|
58 |
$schedules = Schedule\get();
|
73 |
/**
|
74 |
* Returns an array of column names for the table.
|
75 |
*
|
76 |
+
* @return array<string,string> Array of column names keyed by their ID.
|
77 |
*/
|
78 |
public function get_columns() {
|
79 |
return array(
|
96 |
/**
|
97 |
* Generates and displays row action links for the table.
|
98 |
*
|
99 |
+
* @param mixed[] $schedule The schedule for the current row.
|
100 |
+
* @param string $column_name Current column name.
|
101 |
+
* @param string $primary Primary column name.
|
102 |
* @return string The row actions HTML.
|
103 |
*/
|
104 |
protected function handle_row_actions( $schedule, $column_name, $primary ) {
|
118 |
} else {
|
119 |
$link = add_query_arg( array(
|
120 |
'page' => 'crontrol_admin_options_page',
|
121 |
+
'action' => 'crontrol-delete-schedule',
|
122 |
'id' => rawurlencode( $schedule['name'] ),
|
123 |
), admin_url( 'options-general.php' ) );
|
124 |
+
$link = wp_nonce_url( $link, 'crontrol-delete-schedule_' . $schedule['name'] );
|
125 |
|
126 |
$links[] = "<span class='delete'><a href='" . esc_url( $link ) . "'>" . esc_html__( 'Delete', 'wp-crontrol' ) . '</a></span>';
|
127 |
}
|
132 |
/**
|
133 |
* Returns the output for the icon cell of a table row.
|
134 |
*
|
135 |
+
* @param mixed[] $schedule The schedule for the current row.
|
136 |
* @return string The cell output.
|
137 |
*/
|
138 |
protected function column_crontrol_icon( array $schedule ) {
|
150 |
/**
|
151 |
* Returns the output for the schdule name cell of a table row.
|
152 |
*
|
153 |
+
* @param mixed[] $schedule The schedule for the current row.
|
154 |
* @return string The cell output.
|
155 |
*/
|
156 |
protected function column_crontrol_name( array $schedule ) {
|
160 |
/**
|
161 |
* Returns the output for the interval cell of a table row.
|
162 |
*
|
163 |
+
* @param mixed[] $schedule The schedule for the current row.
|
164 |
* @return string The cell output.
|
165 |
*/
|
166 |
protected function column_crontrol_interval( array $schedule ) {
|
188 |
/**
|
189 |
* Returns the output for the display name cell of a table row.
|
190 |
*
|
191 |
+
* @param mixed[] $schedule The schedule for the current row.
|
192 |
* @return string The cell output.
|
193 |
*/
|
194 |
protected function column_crontrol_display( array $schedule ) {
|
197 |
|
198 |
/**
|
199 |
* Outputs a message when there are no items to show in the table.
|
200 |
+
*
|
201 |
+
* @return void
|
202 |
*/
|
203 |
public function no_items() {
|
204 |
esc_html_e( 'There are no schedules.', 'wp-crontrol' );
|
src/schedule.php
CHANGED
@@ -13,6 +13,7 @@ namespace Crontrol\Schedule;
|
|
13 |
* @param string $name The internal name of the schedule.
|
14 |
* @param int $interval The interval between executions of the new schedule.
|
15 |
* @param string $display The display name of the schedule.
|
|
|
16 |
*/
|
17 |
function add( $name, $interval, $display ) {
|
18 |
$old_scheds = get_option( 'crontrol_schedules', array() );
|
@@ -37,6 +38,7 @@ function add( $name, $interval, $display ) {
|
|
37 |
* Deletes a custom cron schedule.
|
38 |
*
|
39 |
* @param string $name The internal name of the schedule to delete.
|
|
|
40 |
*/
|
41 |
function delete( $name ) {
|
42 |
$scheds = get_option( 'crontrol_schedules', array() );
|
@@ -54,7 +56,13 @@ function delete( $name ) {
|
|
54 |
/**
|
55 |
* Gets a sorted (according to interval) list of the cron schedules
|
56 |
*
|
57 |
-
* @return array
|
|
|
|
|
|
|
|
|
|
|
|
|
58 |
*/
|
59 |
function get() {
|
60 |
$schedules = wp_get_schedules();
|
@@ -74,6 +82,7 @@ function get() {
|
|
74 |
* Displays a dropdown filled with the possible schedules, including non-repeating.
|
75 |
*
|
76 |
* @param string|false $current The currently selected schedule, or false for none.
|
|
|
77 |
*/
|
78 |
function dropdown( $current = false ) {
|
79 |
$schedules = get();
|
13 |
* @param string $name The internal name of the schedule.
|
14 |
* @param int $interval The interval between executions of the new schedule.
|
15 |
* @param string $display The display name of the schedule.
|
16 |
+
* @return void
|
17 |
*/
|
18 |
function add( $name, $interval, $display ) {
|
19 |
$old_scheds = get_option( 'crontrol_schedules', array() );
|
38 |
* Deletes a custom cron schedule.
|
39 |
*
|
40 |
* @param string $name The internal name of the schedule to delete.
|
41 |
+
* @return void
|
42 |
*/
|
43 |
function delete( $name ) {
|
44 |
$scheds = get_option( 'crontrol_schedules', array() );
|
56 |
/**
|
57 |
* Gets a sorted (according to interval) list of the cron schedules
|
58 |
*
|
59 |
+
* @return array<string,array<string,(int|string)>> Array of cron schedule arrays.
|
60 |
+
* @phpstan-return array<string,array{
|
61 |
+
* interval: int,
|
62 |
+
* display: string,
|
63 |
+
* name: string,
|
64 |
+
* is_too_frequent: bool,
|
65 |
+
* }>
|
66 |
*/
|
67 |
function get() {
|
68 |
$schedules = wp_get_schedules();
|
82 |
* Displays a dropdown filled with the possible schedules, including non-repeating.
|
83 |
*
|
84 |
* @param string|false $current The currently selected schedule, or false for none.
|
85 |
+
* @return void
|
86 |
*/
|
87 |
function dropdown( $current = false ) {
|
88 |
$schedules = get();
|
wp-crontrol.php
CHANGED
@@ -5,7 +5,7 @@
|
|
5 |
* Description: WP Crontrol enables you to 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.
|
9 |
* Text Domain: wp-crontrol
|
10 |
* Domain Path: /languages/
|
11 |
* Requires PHP: 5.3.6
|
@@ -34,17 +34,24 @@
|
|
34 |
|
35 |
namespace Crontrol;
|
36 |
|
|
|
|
|
37 |
use WP_Error;
|
38 |
|
39 |
-
defined( 'ABSPATH' )
|
|
|
|
|
40 |
|
41 |
require_once __DIR__ . '/src/event.php';
|
|
|
42 |
require_once __DIR__ . '/src/schedule.php';
|
43 |
|
44 |
const TRANSIENT = 'crontrol-message-%d';
|
45 |
|
46 |
/**
|
47 |
* Hook onto all of the actions and filters needed by the plugin.
|
|
|
|
|
48 |
*/
|
49 |
function init_hooks() {
|
50 |
$plugin_file = plugin_basename( __FILE__ );
|
@@ -96,9 +103,9 @@ function get_message() {
|
|
96 |
/**
|
97 |
* Filters the array of row meta for each plugin in the Plugins list table.
|
98 |
*
|
99 |
-
* @param string
|
100 |
-
* @param string
|
101 |
-
* @return string
|
102 |
*/
|
103 |
function filter_plugin_row_meta( array $plugin_meta, $plugin_file ) {
|
104 |
if ( 'wp-crontrol/wp-crontrol.php' !== $plugin_file ) {
|
@@ -116,6 +123,8 @@ function filter_plugin_row_meta( array $plugin_meta, $plugin_file ) {
|
|
116 |
|
117 |
/**
|
118 |
* Run using the 'init' action.
|
|
|
|
|
119 |
*/
|
120 |
function action_init() {
|
121 |
load_plugin_textdomain( 'wp-crontrol', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
|
@@ -123,24 +132,30 @@ function action_init() {
|
|
123 |
|
124 |
/**
|
125 |
* Handles any POSTs made by the plugin. Run using the 'init' action.
|
|
|
|
|
126 |
*/
|
127 |
function action_handle_posts() {
|
128 |
-
|
|
|
|
|
129 |
if ( ! current_user_can( 'manage_options' ) ) {
|
130 |
wp_die( esc_html__( 'You are not allowed to add new cron events.', 'wp-crontrol' ), 401 );
|
131 |
}
|
132 |
-
check_admin_referer( 'new-cron' );
|
133 |
-
|
134 |
-
|
|
|
|
|
135 |
wp_die( esc_html__( 'You are not allowed to add new PHP cron events.', 'wp-crontrol' ), 401 );
|
136 |
}
|
137 |
-
$
|
138 |
|
139 |
-
if ( empty( $
|
140 |
-
$
|
141 |
}
|
142 |
|
143 |
-
$next_run_local = ( 'custom' === $
|
144 |
|
145 |
add_filter( 'schedule_event', function( $event ) {
|
146 |
if ( ! $event ) {
|
@@ -150,13 +165,13 @@ function action_handle_posts() {
|
|
150 |
/**
|
151 |
* Fires after a new cron event is added.
|
152 |
*
|
153 |
-
* @param
|
154 |
* An object containing the event's data.
|
155 |
*
|
156 |
* @type string $hook Action hook to execute when the event is run.
|
157 |
* @type int $timestamp Unix timestamp (UTC) for when to next run the event.
|
158 |
* @type string|false $schedule How often the event should subsequently recur.
|
159 |
-
* @type
|
160 |
* @type int $interval The interval time in seconds for the schedule. Only present for recurring events.
|
161 |
* }
|
162 |
*/
|
@@ -165,12 +180,12 @@ function action_handle_posts() {
|
|
165 |
return $event;
|
166 |
}, 99 );
|
167 |
|
168 |
-
$added = Event\add( $next_run_local, $
|
169 |
|
170 |
$redirect = array(
|
171 |
'page' => 'crontrol_admin_manage_page',
|
172 |
'crontrol_message' => '5',
|
173 |
-
'crontrol_name' => rawurlencode( $
|
174 |
);
|
175 |
|
176 |
if ( is_wp_error( $added ) ) {
|
@@ -181,16 +196,18 @@ function action_handle_posts() {
|
|
181 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
182 |
exit;
|
183 |
|
184 |
-
} elseif ( isset( $_POST['action'] ) && ( '
|
185 |
if ( ! current_user_can( 'edit_files' ) ) {
|
186 |
wp_die( esc_html__( 'You are not allowed to add new PHP cron events.', 'wp-crontrol' ), 401 );
|
187 |
}
|
188 |
-
check_admin_referer( 'new-cron' );
|
189 |
-
|
190 |
-
$
|
|
|
|
|
191 |
$args = array(
|
192 |
-
'code' => $
|
193 |
-
'name' => $
|
194 |
);
|
195 |
|
196 |
add_filter( 'schedule_event', function( $event ) {
|
@@ -201,13 +218,13 @@ function action_handle_posts() {
|
|
201 |
/**
|
202 |
* Fires after a new PHP cron event is added.
|
203 |
*
|
204 |
-
* @param
|
205 |
* An object containing the event's data.
|
206 |
*
|
207 |
* @type string $hook Action hook to execute when the event is run.
|
208 |
* @type int $timestamp Unix timestamp (UTC) for when to next run the event.
|
209 |
* @type string|false $schedule How often the event should subsequently recur.
|
210 |
-
* @type
|
211 |
* @type int $interval The interval time in seconds for the schedule. Only present for recurring events.
|
212 |
* }
|
213 |
*/
|
@@ -216,9 +233,9 @@ function action_handle_posts() {
|
|
216 |
return $event;
|
217 |
}, 99 );
|
218 |
|
219 |
-
$added = Event\add( $next_run_local, $
|
220 |
|
221 |
-
$hookname = ( ! empty( $
|
222 |
$redirect = array(
|
223 |
'page' => 'crontrol_admin_manage_page',
|
224 |
'crontrol_message' => '5',
|
@@ -233,31 +250,32 @@ function action_handle_posts() {
|
|
233 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
234 |
exit;
|
235 |
|
236 |
-
} elseif ( isset( $_POST['action'] ) && ( '
|
237 |
if ( ! current_user_can( 'manage_options' ) ) {
|
238 |
wp_die( esc_html__( 'You are not allowed to edit cron events.', 'wp-crontrol' ), 401 );
|
239 |
}
|
240 |
|
241 |
-
|
242 |
-
|
|
|
243 |
|
244 |
-
if ( 'crontrol_cron_job' === $
|
245 |
wp_die( esc_html__( 'You are not allowed to edit PHP cron events.', 'wp-crontrol' ), 401 );
|
246 |
}
|
247 |
|
248 |
-
$
|
249 |
|
250 |
-
if ( empty( $
|
251 |
-
$
|
252 |
}
|
253 |
|
254 |
$redirect = array(
|
255 |
'page' => 'crontrol_admin_manage_page',
|
256 |
'crontrol_message' => '4',
|
257 |
-
'crontrol_name' => rawurlencode( $
|
258 |
);
|
259 |
|
260 |
-
$original = Event\get_single( $
|
261 |
|
262 |
if ( is_wp_error( $original ) ) {
|
263 |
set_message( $original->get_error_message() );
|
@@ -266,7 +284,7 @@ function action_handle_posts() {
|
|
266 |
exit;
|
267 |
}
|
268 |
|
269 |
-
$deleted = Event\delete( $
|
270 |
|
271 |
if ( is_wp_error( $deleted ) ) {
|
272 |
set_message( $deleted->get_error_message() );
|
@@ -275,32 +293,37 @@ function action_handle_posts() {
|
|
275 |
exit;
|
276 |
}
|
277 |
|
278 |
-
$next_run_local = ( 'custom' === $
|
279 |
|
|
|
|
|
|
|
|
|
|
|
280 |
add_filter( 'schedule_event', function( $event ) use ( $original ) {
|
281 |
-
if ( ! $event
|
282 |
return $event;
|
283 |
}
|
284 |
|
285 |
/**
|
286 |
* Fires after a cron event is edited.
|
287 |
*
|
288 |
-
* @param
|
289 |
* An object containing the new event's data.
|
290 |
*
|
291 |
* @type string $hook Action hook to execute when the event is run.
|
292 |
* @type int $timestamp Unix timestamp (UTC) for when to next run the event.
|
293 |
* @type string|false $schedule How often the event should subsequently recur.
|
294 |
-
* @type
|
295 |
* @type int $interval The interval time in seconds for the schedule. Only present for recurring events.
|
296 |
* }
|
297 |
-
* @param
|
298 |
* An object containing the original event's data.
|
299 |
*
|
300 |
* @type string $hook Action hook to execute when the event is run.
|
301 |
* @type int $timestamp Unix timestamp (UTC) for when to next run the event.
|
302 |
* @type string|false $schedule How often the event should subsequently recur.
|
303 |
-
* @type
|
304 |
* @type int $interval The interval time in seconds for the schedule. Only present for recurring events.
|
305 |
* }
|
306 |
*/
|
@@ -309,7 +332,7 @@ function action_handle_posts() {
|
|
309 |
return $event;
|
310 |
}, 99 );
|
311 |
|
312 |
-
$added = Event\add( $next_run_local, $
|
313 |
|
314 |
if ( is_wp_error( $added ) ) {
|
315 |
set_message( $added->get_error_message() );
|
@@ -319,25 +342,26 @@ function action_handle_posts() {
|
|
319 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
320 |
exit;
|
321 |
|
322 |
-
} elseif ( isset( $_POST['action'] ) && ( '
|
323 |
if ( ! current_user_can( 'edit_files' ) ) {
|
324 |
wp_die( esc_html__( 'You are not allowed to edit PHP cron events.', 'wp-crontrol' ), 401 );
|
325 |
}
|
326 |
|
327 |
-
|
328 |
-
|
|
|
329 |
$args = array(
|
330 |
-
'code' => $
|
331 |
-
'name' => $
|
332 |
);
|
333 |
-
$hookname = ( ! empty( $
|
334 |
$redirect = array(
|
335 |
'page' => 'crontrol_admin_manage_page',
|
336 |
'crontrol_message' => '4',
|
337 |
'crontrol_name' => rawurlencode( $hookname ),
|
338 |
);
|
339 |
|
340 |
-
$original = Event\get_single( $
|
341 |
|
342 |
if ( is_wp_error( $original ) ) {
|
343 |
set_message( $original->get_error_message() );
|
@@ -346,7 +370,7 @@ function action_handle_posts() {
|
|
346 |
exit;
|
347 |
}
|
348 |
|
349 |
-
$deleted = Event\delete( $
|
350 |
|
351 |
if ( is_wp_error( $deleted ) ) {
|
352 |
set_message( $deleted->get_error_message() );
|
@@ -355,32 +379,37 @@ function action_handle_posts() {
|
|
355 |
exit;
|
356 |
}
|
357 |
|
358 |
-
$next_run_local = ( 'custom' === $
|
359 |
|
|
|
|
|
|
|
|
|
|
|
360 |
add_filter( 'schedule_event', function( $event ) use ( $original ) {
|
361 |
-
if ( ! $event
|
362 |
return $event;
|
363 |
}
|
364 |
|
365 |
/**
|
366 |
* Fires after a PHP cron event is edited.
|
367 |
*
|
368 |
-
* @param
|
369 |
* An object containing the new event's data.
|
370 |
*
|
371 |
* @type string $hook Action hook to execute when the event is run.
|
372 |
* @type int $timestamp Unix timestamp (UTC) for when to next run the event.
|
373 |
* @type string|false $schedule How often the event should subsequently recur.
|
374 |
-
* @type
|
375 |
* @type int $interval The interval time in seconds for the schedule. Only present for recurring events.
|
376 |
* }
|
377 |
-
* @param
|
378 |
* An object containing the original event's data.
|
379 |
*
|
380 |
* @type string $hook Action hook to execute when the event is run.
|
381 |
* @type int $timestamp Unix timestamp (UTC) for when to next run the event.
|
382 |
* @type string|false $schedule How often the event should subsequently recur.
|
383 |
-
* @type
|
384 |
* @type int $interval The interval time in seconds for the schedule. Only present for recurring events.
|
385 |
* }
|
386 |
*/
|
@@ -389,7 +418,7 @@ function action_handle_posts() {
|
|
389 |
return $event;
|
390 |
}, 99 );
|
391 |
|
392 |
-
$added = Event\add( $next_run_local, $
|
393 |
|
394 |
if ( is_wp_error( $added ) ) {
|
395 |
set_message( $added->get_error_message() );
|
@@ -399,11 +428,11 @@ function action_handle_posts() {
|
|
399 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
400 |
exit;
|
401 |
|
402 |
-
} elseif ( isset( $_POST['
|
403 |
if ( ! current_user_can( 'manage_options' ) ) {
|
404 |
wp_die( esc_html__( 'You are not allowed to add new cron schedules.', 'wp-crontrol' ), 401 );
|
405 |
}
|
406 |
-
check_admin_referer( 'new-
|
407 |
$name = wp_unslash( $_POST['internal_name'] );
|
408 |
$interval = absint( $_POST['interval'] );
|
409 |
$display = wp_unslash( $_POST['display_name'] );
|
@@ -417,12 +446,12 @@ function action_handle_posts() {
|
|
417 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'options-general.php' ) ) );
|
418 |
exit;
|
419 |
|
420 |
-
} elseif ( isset( $_GET['action'] ) && 'delete-
|
421 |
if ( ! current_user_can( 'manage_options' ) ) {
|
422 |
wp_die( esc_html__( 'You are not allowed to delete cron schedules.', 'wp-crontrol' ), 401 );
|
423 |
}
|
424 |
$schedule = wp_unslash( $_GET['id'] );
|
425 |
-
check_admin_referer( "delete-
|
426 |
Schedule\delete( $schedule );
|
427 |
$redirect = array(
|
428 |
'page' => 'crontrol_admin_options_page',
|
@@ -432,7 +461,7 @@ function action_handle_posts() {
|
|
432 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'options-general.php' ) ) );
|
433 |
exit;
|
434 |
|
435 |
-
} elseif ( ( isset( $_POST['action'] ) && '
|
436 |
if ( ! current_user_can( 'manage_options' ) ) {
|
437 |
wp_die( esc_html__( 'You are not allowed to delete cron events.', 'wp-crontrol' ), 401 );
|
438 |
}
|
@@ -442,11 +471,14 @@ function action_handle_posts() {
|
|
442 |
return;
|
443 |
}
|
444 |
|
445 |
-
|
|
|
|
|
|
|
446 |
$deleted = 0;
|
447 |
|
448 |
foreach ( $delete as $next_run_utc => $events ) {
|
449 |
-
foreach ( $events as $hook => $sig ) {
|
450 |
if ( 'crontrol_cron_job' === $hook && ! current_user_can( 'edit_files' ) ) {
|
451 |
continue;
|
452 |
}
|
@@ -471,14 +503,14 @@ function action_handle_posts() {
|
|
471 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
472 |
exit;
|
473 |
|
474 |
-
} elseif ( isset( $_GET['action'] ) && 'delete-cron' === $_GET['action'] ) {
|
475 |
if ( ! current_user_can( 'manage_options' ) ) {
|
476 |
wp_die( esc_html__( 'You are not allowed to delete cron events.', 'wp-crontrol' ), 401 );
|
477 |
}
|
478 |
$hook = wp_unslash( $_GET['id'] );
|
479 |
$sig = wp_unslash( $_GET['sig'] );
|
480 |
-
$next_run_utc =
|
481 |
-
check_admin_referer( "delete-cron_{$hook}_{$sig}_{$next_run_utc}" );
|
482 |
|
483 |
if ( 'crontrol_cron_job' === $hook && ! current_user_can( 'edit_files' ) ) {
|
484 |
wp_die( esc_html__( 'You are not allowed to delete PHP cron events.', 'wp-crontrol' ), 401 );
|
@@ -508,13 +540,13 @@ function action_handle_posts() {
|
|
508 |
/**
|
509 |
* Fires after a cron event is deleted.
|
510 |
*
|
511 |
-
* @param
|
512 |
* An object containing the event's data.
|
513 |
*
|
514 |
* @type string $hook Action hook to execute when the event is run.
|
515 |
* @type int $timestamp Unix timestamp (UTC) for when to next run the event.
|
516 |
* @type string|false $schedule How often the event should subsequently recur.
|
517 |
-
* @type
|
518 |
* @type int $interval The interval time in seconds for the schedule. Only present for recurring events.
|
519 |
* }
|
520 |
*/
|
@@ -524,13 +556,13 @@ function action_handle_posts() {
|
|
524 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
525 |
exit;
|
526 |
|
527 |
-
} elseif ( isset( $_GET['action'] ) && 'delete-hook' === $_GET['action'] ) {
|
528 |
if ( ! current_user_can( 'manage_options' ) ) {
|
529 |
wp_die( esc_html__( 'You are not allowed to delete cron events.', 'wp-crontrol' ), 401 );
|
530 |
}
|
531 |
$hook = wp_unslash( $_GET['id'] );
|
532 |
$deleted = false;
|
533 |
-
check_admin_referer( "delete-hook_{$hook}" );
|
534 |
|
535 |
if ( 'crontrol_cron_job' === $hook ) {
|
536 |
wp_die( esc_html__( 'You are not allowed to delete PHP cron events.', 'wp-crontrol' ), 401 );
|
@@ -573,13 +605,13 @@ function action_handle_posts() {
|
|
573 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
574 |
exit;
|
575 |
}
|
576 |
-
} elseif ( isset( $_GET['action'] ) && 'run-cron' === $_GET['action'] ) {
|
577 |
if ( ! current_user_can( 'manage_options' ) ) {
|
578 |
wp_die( esc_html__( 'You are not allowed to run cron events.', 'wp-crontrol' ), 401 );
|
579 |
}
|
580 |
$hook = wp_unslash( $_GET['id'] );
|
581 |
$sig = wp_unslash( $_GET['sig'] );
|
582 |
-
check_admin_referer( "run-cron_{$hook}_{$sig}" );
|
583 |
|
584 |
$ran = Event\run( $hook, $sig );
|
585 |
|
@@ -590,11 +622,112 @@ function action_handle_posts() {
|
|
590 |
);
|
591 |
|
592 |
if ( is_wp_error( $ran ) ) {
|
593 |
-
set_message( $ran->get_error_message() );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
594 |
$redirect['crontrol_message'] = 'error';
|
595 |
}
|
596 |
|
597 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
598 |
exit;
|
599 |
}
|
600 |
}
|
@@ -603,21 +736,41 @@ function action_handle_posts() {
|
|
603 |
* Adds options & management pages to the admin menu.
|
604 |
*
|
605 |
* Run using the 'admin_menu' action.
|
|
|
|
|
606 |
*/
|
607 |
function action_admin_menu() {
|
608 |
-
$schedules = add_options_page(
|
609 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
610 |
|
611 |
add_action( "load-{$schedules}", __NAMESPACE__ . '\admin_help_tab' );
|
612 |
add_action( "load-{$events}", __NAMESPACE__ . '\admin_help_tab' );
|
613 |
}
|
614 |
|
615 |
/**
|
616 |
-
* Adds a Help tab with links to help resources
|
|
|
|
|
617 |
*/
|
618 |
function admin_help_tab() {
|
619 |
$screen = get_current_screen();
|
620 |
|
|
|
|
|
|
|
|
|
621 |
$content = '<p>' . __( 'There are several places to get help with issues relating to WP-Cron:', 'wp-crontrol' ) . '</p>';
|
622 |
$content .= '<ul>';
|
623 |
$content .= '<li>';
|
@@ -654,11 +807,11 @@ function admin_help_tab() {
|
|
654 |
/**
|
655 |
* Adds items to the plugin's action links on the Plugins listing screen.
|
656 |
*
|
657 |
-
* @param string
|
658 |
-
* @param string
|
659 |
-
* @param
|
660 |
-
* @param string
|
661 |
-
* @return string
|
662 |
*/
|
663 |
function plugin_action_links( $actions, $plugin_file, $plugin_data, $context ) {
|
664 |
$new = array(
|
@@ -687,8 +840,8 @@ function plugin_action_links( $actions, $plugin_file, $plugin_data, $context ) {
|
|
687 |
*
|
688 |
* Called by the `cron_schedules` filter.
|
689 |
*
|
690 |
-
* @param array
|
691 |
-
* @return array
|
692 |
*/
|
693 |
function filter_cron_schedules( array $scheds ) {
|
694 |
$new_scheds = get_option( 'crontrol_schedules', array() );
|
@@ -702,6 +855,8 @@ function filter_cron_schedules( array $scheds ) {
|
|
702 |
|
703 |
/**
|
704 |
* Displays the options page for the plugin.
|
|
|
|
|
705 |
*/
|
706 |
function admin_options_page() {
|
707 |
$messages = array(
|
@@ -771,9 +926,9 @@ function admin_options_page() {
|
|
771 |
<input type="text" value="" id="cron_display_name" name="display_name" required/>
|
772 |
</div>
|
773 |
<p class="submit">
|
774 |
-
<input id="schedadd-submit" type="submit" class="button button-primary" value="<?php esc_attr_e( 'Add Cron Schedule', 'wp-crontrol' ); ?>" name="
|
775 |
</p>
|
776 |
-
<?php wp_nonce_field( 'new-
|
777 |
</form>
|
778 |
</div>
|
779 |
</div>
|
@@ -812,7 +967,7 @@ function admin_options_page() {
|
|
812 |
* - https://core.trac.wordpress.org/browser/trunk/src/wp-cron.php?rev=47198&marks=127,141#L122
|
813 |
*
|
814 |
* @param mixed $pre The pre-flight value of the event unschedule short-circuit. Not used.
|
815 |
-
* @return mixed
|
816 |
*/
|
817 |
function maybe_clear_doing_cron( $pre ) {
|
818 |
if ( defined( 'DOING_CRON' ) && DOING_CRON && isset( $_GET['crontrol-single-event'] ) ) {
|
@@ -824,13 +979,21 @@ function maybe_clear_doing_cron( $pre ) {
|
|
824 |
|
825 |
/**
|
826 |
* Ajax handler which outputs a hash of the current list of scheduled events.
|
|
|
|
|
827 |
*/
|
828 |
function ajax_check_events_hash() {
|
829 |
if ( ! current_user_can( 'manage_options' ) ) {
|
830 |
wp_send_json_error( null, 403 );
|
831 |
}
|
832 |
|
833 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
834 |
}
|
835 |
|
836 |
/**
|
@@ -879,7 +1042,7 @@ function test_cron_spawn( $cache = true ) {
|
|
879 |
return true;
|
880 |
}
|
881 |
|
882 |
-
$sslverify = version_compare( $wp_version, 4.0, '<' );
|
883 |
$doing_wp_cron = sprintf( '%.22F', microtime( true ) );
|
884 |
|
885 |
$cron_request = apply_filters( 'cron_request', array(
|
@@ -911,30 +1074,13 @@ function test_cron_spawn( $cache = true ) {
|
|
911 |
|
912 |
}
|
913 |
|
914 |
-
/**
|
915 |
-
* Determines whether the given feature is enabled.
|
916 |
-
*
|
917 |
-
* The feature directly corresponds to one of WP Crontrol's tabs. Currently the only feature
|
918 |
-
* that's not enabled by default is "logs" which are provided by WP Crontrol Pro.
|
919 |
-
*
|
920 |
-
* @param string $feature The feature name.
|
921 |
-
* @return bool Whether the specified tab is active.
|
922 |
-
*/
|
923 |
-
function is_feature_enabled( $feature ) {
|
924 |
-
$enabled = ( 'logs' !== $feature );
|
925 |
-
return apply_filters( "crontrol/enabled/{$feature}", $enabled );
|
926 |
-
}
|
927 |
-
|
928 |
/**
|
929 |
* Shows the status of WP-Cron functionality on the site. Only displays a message when there's a problem.
|
930 |
*
|
931 |
* @param string $tab The tab name.
|
|
|
932 |
*/
|
933 |
function show_cron_status( $tab ) {
|
934 |
-
if ( ! is_feature_enabled( $tab ) ) {
|
935 |
-
return;
|
936 |
-
}
|
937 |
-
|
938 |
if ( 'UTC' !== date_default_timezone_get() ) {
|
939 |
?>
|
940 |
<div id="crontrol-timezone-warning" class="notice notice-warning">
|
@@ -1090,7 +1236,7 @@ function show_cron_form( $editing ) {
|
|
1090 |
}
|
1091 |
|
1092 |
if ( is_array( $existing ) ) {
|
1093 |
-
$other_fields = wp_nonce_field( "edit-cron_{$existing['hookname']}_{$existing['sig']}_{$existing['next_run']}", '_wpnonce', true, false );
|
1094 |
$other_fields .= sprintf( '<input name="original_hookname" type="hidden" value="%s" />',
|
1095 |
esc_attr( $existing['hookname'] )
|
1096 |
);
|
@@ -1098,18 +1244,21 @@ function show_cron_form( $editing ) {
|
|
1098 |
esc_attr( $existing['sig'] )
|
1099 |
);
|
1100 |
$other_fields .= sprintf( '<input name="original_next_run_utc" type="hidden" value="%s" />',
|
1101 |
-
esc_attr( $existing['next_run'] )
|
1102 |
);
|
1103 |
if ( ! empty( $existing['args'] ) ) {
|
1104 |
$display_args = wp_json_encode( $existing['args'] );
|
|
|
|
|
|
|
|
|
1105 |
}
|
1106 |
-
$action = $is_editing_php ? 'edit_php_cron' : 'edit_cron';
|
1107 |
$button = __( 'Update Event', 'wp-crontrol' );
|
1108 |
$next_run_gmt = gmdate( 'Y-m-d H:i:s', $existing['next_run'] );
|
1109 |
$next_run_date_local = get_date_from_gmt( $next_run_gmt, 'Y-m-d' );
|
1110 |
$next_run_time_local = get_date_from_gmt( $next_run_gmt, 'H:i:s' );
|
1111 |
} else {
|
1112 |
-
$other_fields = wp_nonce_field( 'new-cron', '_wpnonce', true, false );
|
1113 |
$existing = array(
|
1114 |
'hookname' => '',
|
1115 |
'args' => array(),
|
@@ -1163,6 +1312,7 @@ function show_cron_form( $editing ) {
|
|
1163 |
<table class="form-table"><tbody>
|
1164 |
<?php
|
1165 |
if ( $editing ) {
|
|
|
1166 |
printf(
|
1167 |
'<input type="hidden" name="action" value="%s"/>',
|
1168 |
esc_attr( $action )
|
@@ -1174,14 +1324,14 @@ function show_cron_form( $editing ) {
|
|
1174 |
<?php esc_html_e( 'Event Type', 'wp-crontrol' ); ?>
|
1175 |
</th>
|
1176 |
<td>
|
1177 |
-
<p><label><input type="radio" name="action" value="
|
1178 |
-
<p><label><input type="radio" name="action" value="
|
1179 |
</td>
|
1180 |
</tr>
|
1181 |
<?php
|
1182 |
} else {
|
1183 |
?>
|
1184 |
-
<input type="hidden" name="action" value="
|
1185 |
<?php
|
1186 |
}
|
1187 |
|
@@ -1204,6 +1354,7 @@ function show_cron_form( $editing ) {
|
|
1204 |
?>
|
1205 |
</p>
|
1206 |
<p><textarea class="large-text code" rows="10" cols="50" id="hookcode" name="hookcode"><?php echo esc_textarea( $editing ? $existing['args']['code'] : '' ); ?></textarea></p>
|
|
|
1207 |
</td>
|
1208 |
</tr>
|
1209 |
<tr class="crontrol-event-php">
|
@@ -1214,6 +1365,7 @@ function show_cron_form( $editing ) {
|
|
1214 |
</th>
|
1215 |
<td>
|
1216 |
<input type="text" class="regular-text" id="eventname" name="eventname" value="<?php echo esc_attr( $editing ? $existing['args']['name'] : '' ); ?>"/>
|
|
|
1217 |
</td>
|
1218 |
</tr>
|
1219 |
<?php
|
@@ -1229,6 +1381,7 @@ function show_cron_form( $editing ) {
|
|
1229 |
</th>
|
1230 |
<td>
|
1231 |
<input type="text" autocorrect="off" autocapitalize="off" spellcheck="false" class="regular-text" id="hookname" name="hookname" value="<?php echo esc_attr( $existing['hookname'] ); ?>" required />
|
|
|
1232 |
</td>
|
1233 |
</tr>
|
1234 |
<tr class="crontrol-event-standard">
|
@@ -1239,6 +1392,7 @@ function show_cron_form( $editing ) {
|
|
1239 |
</th>
|
1240 |
<td>
|
1241 |
<input type="text" autocorrect="off" autocapitalize="off" spellcheck="false" class="regular-text code" id="args" name="args" value="<?php echo esc_attr( $display_args ); ?>"/>
|
|
|
1242 |
<p class="description">
|
1243 |
<?php
|
1244 |
printf(
|
@@ -1295,6 +1449,8 @@ function show_cron_form( $editing ) {
|
|
1295 |
</li>
|
1296 |
</ul>
|
1297 |
|
|
|
|
|
1298 |
<p class="description">
|
1299 |
<?php
|
1300 |
printf(
|
@@ -1314,6 +1470,7 @@ function show_cron_form( $editing ) {
|
|
1314 |
</th>
|
1315 |
<td>
|
1316 |
<?php Schedule\dropdown( $existing['schedule'] ); ?>
|
|
|
1317 |
</td>
|
1318 |
</tr>
|
1319 |
</tbody></table>
|
@@ -1332,6 +1489,8 @@ function show_cron_form( $editing ) {
|
|
1332 |
|
1333 |
/**
|
1334 |
* Displays the manage page for the plugin.
|
|
|
|
|
1335 |
*/
|
1336 |
function admin_manage_page() {
|
1337 |
$messages = array(
|
@@ -1384,7 +1543,10 @@ function admin_manage_page() {
|
|
1384 |
__( 'Failed to save the cron event %s.', 'wp-crontrol' ),
|
1385 |
'error',
|
1386 |
),
|
1387 |
-
'error' => array(
|
|
|
|
|
|
|
1388 |
);
|
1389 |
|
1390 |
if ( isset( $_GET['crontrol_name'] ) && isset( $_GET['crontrol_message'] ) && isset( $messages[ $_GET['crontrol_message'] ] ) ) {
|
@@ -1393,10 +1555,11 @@ function admin_manage_page() {
|
|
1393 |
$link = '';
|
1394 |
|
1395 |
if ( 'error' === $message ) {
|
1396 |
-
$
|
1397 |
-
|
1398 |
-
|
1399 |
-
|
|
|
1400 |
}
|
1401 |
|
1402 |
printf(
|
@@ -1422,7 +1585,7 @@ function admin_manage_page() {
|
|
1422 |
|
1423 |
<h1 class="wp-heading-inline"><?php esc_html_e( 'Cron Events', 'wp-crontrol' ); ?></h1>
|
1424 |
|
1425 |
-
<?php echo '<a href="' . esc_url( admin_url( 'tools.php?page=crontrol_admin_manage_page&action=new-cron' ) ) . '" class="page-title-action">' . esc_html__( 'Add New', 'wp-crontrol' ) . '</a>'; ?>
|
1426 |
|
1427 |
<hr class="wp-header-end">
|
1428 |
|
@@ -1469,19 +1632,25 @@ function admin_manage_page() {
|
|
1469 |
/**
|
1470 |
* Get the states of the various cron-related tabs.
|
1471 |
*
|
1472 |
-
* @return bool
|
1473 |
*/
|
1474 |
function get_tab_states() {
|
1475 |
-
|
1476 |
'events' => ( ! empty( $_GET['page'] ) && 'crontrol_admin_manage_page' === $_GET['page'] && empty( $_GET['action'] ) ),
|
1477 |
'schedules' => ( ! empty( $_GET['page'] ) && 'crontrol_admin_options_page' === $_GET['page'] ),
|
1478 |
-
'add-event' => ( ! empty( $_GET['action'] ) && 'new-cron' === $_GET['action'] ),
|
1479 |
-
'edit-event' => ( ! empty( $_GET['action'] ) && 'edit-cron' === $_GET['action'] ),
|
1480 |
);
|
|
|
|
|
|
|
|
|
1481 |
}
|
1482 |
|
1483 |
/**
|
1484 |
* Output the cron-related tabs if we're on a cron-related admin screen.
|
|
|
|
|
1485 |
*/
|
1486 |
function do_tabs() {
|
1487 |
$tabs = get_tab_states();
|
@@ -1509,7 +1678,7 @@ function do_tabs() {
|
|
1509 |
<nav class="nav-tab-wrapper">
|
1510 |
<?php
|
1511 |
foreach ( $links as $id => $link ) {
|
1512 |
-
if ( $tabs[ $id ] ) {
|
1513 |
printf(
|
1514 |
'<a href="%s" class="nav-tab nav-tab-active">%s</a>',
|
1515 |
esc_url( $link[0] ),
|
@@ -1548,7 +1717,11 @@ function do_tabs() {
|
|
1548 |
* Returns an array of the callback functions that are attached to the given hook name.
|
1549 |
*
|
1550 |
* @param string $name The hook name.
|
1551 |
-
* @return array
|
|
|
|
|
|
|
|
|
1552 |
*/
|
1553 |
function get_hook_callbacks( $name ) {
|
1554 |
global $wp_filter;
|
@@ -1559,6 +1732,9 @@ function get_hook_callbacks( $name ) {
|
|
1559 |
// See http://core.trac.wordpress.org/ticket/17817.
|
1560 |
$action = $wp_filter[ $name ];
|
1561 |
|
|
|
|
|
|
|
1562 |
foreach ( $action as $priority => $callbacks ) {
|
1563 |
foreach ( $callbacks as $callback ) {
|
1564 |
$callback = populate_callback( $callback );
|
@@ -1577,8 +1753,12 @@ function get_hook_callbacks( $name ) {
|
|
1577 |
/**
|
1578 |
* Populates the details of the given callback function.
|
1579 |
*
|
1580 |
-
* @param array $callback A callback entry.
|
1581 |
-
* @
|
|
|
|
|
|
|
|
|
1582 |
*/
|
1583 |
function populate_callback( array $callback ) {
|
1584 |
// If Query Monitor is installed, use its rich callback analysis.
|
@@ -1618,7 +1798,7 @@ function populate_callback( array $callback ) {
|
|
1618 |
/**
|
1619 |
* Returns a user-friendly representation of the callback function.
|
1620 |
*
|
1621 |
-
* @param
|
1622 |
* @return string The displayable version of the callback name.
|
1623 |
*/
|
1624 |
function output_callback( array $callback ) {
|
@@ -1669,7 +1849,7 @@ function time_since( $older_date, $newer_date ) {
|
|
1669 |
* echo \Crontrol\interval( 90 );
|
1670 |
* // 1 minute 30 seconds
|
1671 |
*
|
1672 |
-
* @param int $since A period of time in seconds.
|
1673 |
* @return string An interval represented as a string.
|
1674 |
*/
|
1675 |
function interval( $since ) {
|
@@ -1701,15 +1881,14 @@ function interval( $since ) {
|
|
1701 |
* x days, xx hours
|
1702 |
* so there's only two bits of calculation below:
|
1703 |
*/
|
1704 |
-
$j = count( $chunks );
|
1705 |
|
1706 |
// Step one: the first chunk.
|
1707 |
-
|
1708 |
$seconds = $chunks[ $i ][0];
|
1709 |
$name = $chunks[ $i ][1];
|
1710 |
|
1711 |
// Finding the biggest chunk (if the chunk fits, break).
|
1712 |
-
$count = floor( $since / $seconds );
|
1713 |
if ( $count ) {
|
1714 |
break;
|
1715 |
}
|
@@ -1719,10 +1898,10 @@ function interval( $since ) {
|
|
1719 |
$output = sprintf( translate_nooped_plural( $name, $count, 'wp-crontrol' ), $count );
|
1720 |
|
1721 |
// Step two: the second chunk.
|
1722 |
-
if ( $i + 1 < $
|
1723 |
$seconds2 = $chunks[ $i + 1 ][0];
|
1724 |
$name2 = $chunks[ $i + 1 ][1];
|
1725 |
-
$count2 = floor( ( $since - ( $seconds * $count ) ) / $seconds2 );
|
1726 |
if ( $count2 ) {
|
1727 |
// Add to output var.
|
1728 |
$output .= ' ' . sprintf( translate_nooped_plural( $name2, $count2, 'wp-crontrol' ), $count2 );
|
@@ -1734,6 +1913,8 @@ function interval( $since ) {
|
|
1734 |
|
1735 |
/**
|
1736 |
* Sets up the Events listing screen.
|
|
|
|
|
1737 |
*/
|
1738 |
function setup_manage_page() {
|
1739 |
// Initialise the list table
|
@@ -1752,6 +1933,7 @@ function setup_manage_page() {
|
|
1752 |
* Registers the stylesheet and JavaScript for the admin areas.
|
1753 |
*
|
1754 |
* @param string $hook_suffix The admin screen ID.
|
|
|
1755 |
*/
|
1756 |
function enqueue_assets( $hook_suffix ) {
|
1757 |
$tab = get_tab_states();
|
@@ -1760,17 +1942,21 @@ function enqueue_assets( $hook_suffix ) {
|
|
1760 |
return;
|
1761 |
}
|
1762 |
|
1763 |
-
$ver = filemtime( plugin_dir_path( __FILE__ ) . 'css/wp-crontrol.css' );
|
1764 |
wp_enqueue_style( 'wp-crontrol', plugin_dir_url( __FILE__ ) . 'css/wp-crontrol.css', array( 'dashicons' ), $ver );
|
1765 |
|
1766 |
-
$ver = filemtime( plugin_dir_path( __FILE__ ) . 'js/wp-crontrol.js' );
|
1767 |
wp_enqueue_script( 'wp-crontrol', plugin_dir_url( __FILE__ ) . 'js/wp-crontrol.js', array( 'jquery', 'wp-a11y' ), $ver, true );
|
1768 |
|
1769 |
$vars = array();
|
1770 |
|
1771 |
if ( ! empty( $tab['events'] ) ) {
|
1772 |
-
$
|
1773 |
-
|
|
|
|
|
|
|
|
|
1774 |
}
|
1775 |
|
1776 |
if ( ! empty( $tab['add-event'] ) || ! empty( $tab['edit-event'] ) ) {
|
@@ -1791,8 +1977,8 @@ function enqueue_assets( $hook_suffix ) {
|
|
1791 |
/**
|
1792 |
* Filters the list of query arguments which get removed from admin area URLs in WordPress.
|
1793 |
*
|
1794 |
-
* @param string
|
1795 |
-
* @return string
|
1796 |
*/
|
1797 |
function filter_removable_query_args( array $args ) {
|
1798 |
return array_merge( $args, array(
|
@@ -1804,40 +1990,42 @@ function filter_removable_query_args( array $args ) {
|
|
1804 |
/**
|
1805 |
* Returns an array of cron event hooks that are persistently added by WordPress core.
|
1806 |
*
|
1807 |
-
* @return string
|
1808 |
*/
|
1809 |
function get_persistent_core_hooks() {
|
1810 |
return array(
|
1811 |
-
'
|
1812 |
-
'
|
1813 |
-
'
|
1814 |
-
'
|
1815 |
-
'
|
1816 |
-
'wp_scheduled_auto_draft_delete',
|
1817 |
-
'
|
1818 |
-
'
|
1819 |
-
'
|
1820 |
-
'
|
1821 |
-
'
|
1822 |
);
|
1823 |
}
|
1824 |
|
1825 |
/**
|
1826 |
* Returns an array of all cron event hooks that are added by WordPress core.
|
1827 |
*
|
1828 |
-
* @return string
|
1829 |
*/
|
1830 |
function get_all_core_hooks() {
|
1831 |
return array_merge(
|
1832 |
get_persistent_core_hooks(),
|
1833 |
array(
|
1834 |
-
'do_pings',
|
1835 |
-
'
|
1836 |
-
'
|
1837 |
-
'upgrader_scheduled_cleanup',
|
1838 |
-
'wp_maybe_auto_update',
|
1839 |
-
'wp_split_shared_term_batch',
|
1840 |
-
'wp_update_comment_type_batch',
|
|
|
|
|
1841 |
)
|
1842 |
);
|
1843 |
}
|
@@ -1845,7 +2033,7 @@ function get_all_core_hooks() {
|
|
1845 |
/**
|
1846 |
* Returns an array of cron schedules that are added by WordPress core.
|
1847 |
*
|
1848 |
-
* @return string
|
1849 |
*/
|
1850 |
function get_core_schedules() {
|
1851 |
return array(
|
@@ -1859,21 +2047,29 @@ function get_core_schedules() {
|
|
1859 |
/**
|
1860 |
* Encodes some input as JSON for output.
|
1861 |
*
|
1862 |
-
* @param mixed $input
|
|
|
1863 |
* @return string The JSON-encoded output.
|
1864 |
*/
|
1865 |
-
function json_output( $input ) {
|
1866 |
$json_options = 0;
|
1867 |
|
1868 |
if ( defined( 'JSON_UNESCAPED_SLASHES' ) ) {
|
1869 |
// phpcs:ignore PHPCompatibility.Constants.NewConstants.json_unescaped_slashesFound
|
1870 |
$json_options |= JSON_UNESCAPED_SLASHES;
|
1871 |
}
|
1872 |
-
|
|
|
1873 |
$json_options |= JSON_PRETTY_PRINT;
|
1874 |
}
|
1875 |
|
1876 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
1877 |
}
|
1878 |
|
1879 |
/**
|
@@ -1889,6 +2085,7 @@ function json_output( $input ) {
|
|
1889 |
* Therefore, the user access level required to execute arbitrary PHP code does not change with WP Crontrol activated.
|
1890 |
*
|
1891 |
* @param string $code The PHP code to evaluate.
|
|
|
1892 |
*/
|
1893 |
function action_php_cron_event( $code ) {
|
1894 |
// phpcs:ignore Squiz.PHP.Eval.Discouraged
|
5 |
* Description: WP Crontrol enables you to 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.11.0
|
9 |
* Text Domain: wp-crontrol
|
10 |
* Domain Path: /languages/
|
11 |
* Requires PHP: 5.3.6
|
34 |
|
35 |
namespace Crontrol;
|
36 |
|
37 |
+
use Crontrol\Event\Table;
|
38 |
+
use stdClass;
|
39 |
use WP_Error;
|
40 |
|
41 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
42 |
+
exit;
|
43 |
+
}
|
44 |
|
45 |
require_once __DIR__ . '/src/event.php';
|
46 |
+
require_once __DIR__ . '/src/request.php';
|
47 |
require_once __DIR__ . '/src/schedule.php';
|
48 |
|
49 |
const TRANSIENT = 'crontrol-message-%d';
|
50 |
|
51 |
/**
|
52 |
* Hook onto all of the actions and filters needed by the plugin.
|
53 |
+
*
|
54 |
+
* @return void
|
55 |
*/
|
56 |
function init_hooks() {
|
57 |
$plugin_file = plugin_basename( __FILE__ );
|
103 |
/**
|
104 |
* Filters the array of row meta for each plugin in the Plugins list table.
|
105 |
*
|
106 |
+
* @param array<int,string> $plugin_meta An array of the plugin row's meta data.
|
107 |
+
* @param string $plugin_file Path to the plugin file relative to the plugins directory.
|
108 |
+
* @return array<int,string> An array of the plugin row's meta data.
|
109 |
*/
|
110 |
function filter_plugin_row_meta( array $plugin_meta, $plugin_file ) {
|
111 |
if ( 'wp-crontrol/wp-crontrol.php' !== $plugin_file ) {
|
123 |
|
124 |
/**
|
125 |
* Run using the 'init' action.
|
126 |
+
*
|
127 |
+
* @return void
|
128 |
*/
|
129 |
function action_init() {
|
130 |
load_plugin_textdomain( 'wp-crontrol', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
|
132 |
|
133 |
/**
|
134 |
* Handles any POSTs made by the plugin. Run using the 'init' action.
|
135 |
+
*
|
136 |
+
* @return void
|
137 |
*/
|
138 |
function action_handle_posts() {
|
139 |
+
$request = new Request();
|
140 |
+
|
141 |
+
if ( isset( $_POST['action'] ) && ( 'crontrol_new_cron' === $_POST['action'] ) ) {
|
142 |
if ( ! current_user_can( 'manage_options' ) ) {
|
143 |
wp_die( esc_html__( 'You are not allowed to add new cron events.', 'wp-crontrol' ), 401 );
|
144 |
}
|
145 |
+
check_admin_referer( 'crontrol-new-cron' );
|
146 |
+
|
147 |
+
$cr = $request->init( wp_unslash( $_POST ) );
|
148 |
+
|
149 |
+
if ( 'crontrol_cron_job' === $cr->hookname && ! current_user_can( 'edit_files' ) ) {
|
150 |
wp_die( esc_html__( 'You are not allowed to add new PHP cron events.', 'wp-crontrol' ), 401 );
|
151 |
}
|
152 |
+
$args = json_decode( $cr->args, true );
|
153 |
|
154 |
+
if ( empty( $args ) ) {
|
155 |
+
$args = array();
|
156 |
}
|
157 |
|
158 |
+
$next_run_local = ( 'custom' === $cr->next_run_date_local ) ? $cr->next_run_date_local_custom_date . ' ' . $cr->next_run_date_local_custom_time : $cr->next_run_date_local;
|
159 |
|
160 |
add_filter( 'schedule_event', function( $event ) {
|
161 |
if ( ! $event ) {
|
165 |
/**
|
166 |
* Fires after a new cron event is added.
|
167 |
*
|
168 |
+
* @param stdClass $event {
|
169 |
* An object containing the event's data.
|
170 |
*
|
171 |
* @type string $hook Action hook to execute when the event is run.
|
172 |
* @type int $timestamp Unix timestamp (UTC) for when to next run the event.
|
173 |
* @type string|false $schedule How often the event should subsequently recur.
|
174 |
+
* @type mixed[] $args Array containing each separate argument to pass to the hook's callback function.
|
175 |
* @type int $interval The interval time in seconds for the schedule. Only present for recurring events.
|
176 |
* }
|
177 |
*/
|
180 |
return $event;
|
181 |
}, 99 );
|
182 |
|
183 |
+
$added = Event\add( $next_run_local, $cr->schedule, $cr->hookname, $args );
|
184 |
|
185 |
$redirect = array(
|
186 |
'page' => 'crontrol_admin_manage_page',
|
187 |
'crontrol_message' => '5',
|
188 |
+
'crontrol_name' => rawurlencode( $cr->hookname ),
|
189 |
);
|
190 |
|
191 |
if ( is_wp_error( $added ) ) {
|
196 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
197 |
exit;
|
198 |
|
199 |
+
} elseif ( isset( $_POST['action'] ) && ( 'crontrol_new_php_cron' === $_POST['action'] ) ) {
|
200 |
if ( ! current_user_can( 'edit_files' ) ) {
|
201 |
wp_die( esc_html__( 'You are not allowed to add new PHP cron events.', 'wp-crontrol' ), 401 );
|
202 |
}
|
203 |
+
check_admin_referer( 'crontrol-new-cron' );
|
204 |
+
|
205 |
+
$cr = $request->init( wp_unslash( $_POST ) );
|
206 |
+
|
207 |
+
$next_run_local = ( 'custom' === $cr->next_run_date_local ) ? $cr->next_run_date_local_custom_date . ' ' . $cr->next_run_date_local_custom_time : $cr->next_run_date_local;
|
208 |
$args = array(
|
209 |
+
'code' => $cr->hookcode,
|
210 |
+
'name' => $cr->eventname,
|
211 |
);
|
212 |
|
213 |
add_filter( 'schedule_event', function( $event ) {
|
218 |
/**
|
219 |
* Fires after a new PHP cron event is added.
|
220 |
*
|
221 |
+
* @param stdClass $event {
|
222 |
* An object containing the event's data.
|
223 |
*
|
224 |
* @type string $hook Action hook to execute when the event is run.
|
225 |
* @type int $timestamp Unix timestamp (UTC) for when to next run the event.
|
226 |
* @type string|false $schedule How often the event should subsequently recur.
|
227 |
+
* @type mixed[] $args Array containing each separate argument to pass to the hook's callback function.
|
228 |
* @type int $interval The interval time in seconds for the schedule. Only present for recurring events.
|
229 |
* }
|
230 |
*/
|
233 |
return $event;
|
234 |
}, 99 );
|
235 |
|
236 |
+
$added = Event\add( $next_run_local, $cr->schedule, 'crontrol_cron_job', $args );
|
237 |
|
238 |
+
$hookname = ( ! empty( $cr->eventname ) ) ? $cr->eventname : __( 'PHP Cron', 'wp-crontrol' );
|
239 |
$redirect = array(
|
240 |
'page' => 'crontrol_admin_manage_page',
|
241 |
'crontrol_message' => '5',
|
250 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
251 |
exit;
|
252 |
|
253 |
+
} elseif ( isset( $_POST['action'] ) && ( 'crontrol_edit_cron' === $_POST['action'] ) ) {
|
254 |
if ( ! current_user_can( 'manage_options' ) ) {
|
255 |
wp_die( esc_html__( 'You are not allowed to edit cron events.', 'wp-crontrol' ), 401 );
|
256 |
}
|
257 |
|
258 |
+
$cr = $request->init( wp_unslash( $_POST ) );
|
259 |
+
|
260 |
+
check_admin_referer( "crontrol-edit-cron_{$cr->original_hookname}_{$cr->original_sig}_{$cr->original_next_run_utc}" );
|
261 |
|
262 |
+
if ( 'crontrol_cron_job' === $cr->hookname && ! current_user_can( 'edit_files' ) ) {
|
263 |
wp_die( esc_html__( 'You are not allowed to edit PHP cron events.', 'wp-crontrol' ), 401 );
|
264 |
}
|
265 |
|
266 |
+
$args = json_decode( $cr->args, true );
|
267 |
|
268 |
+
if ( empty( $args ) ) {
|
269 |
+
$args = array();
|
270 |
}
|
271 |
|
272 |
$redirect = array(
|
273 |
'page' => 'crontrol_admin_manage_page',
|
274 |
'crontrol_message' => '4',
|
275 |
+
'crontrol_name' => rawurlencode( $cr->hookname ),
|
276 |
);
|
277 |
|
278 |
+
$original = Event\get_single( $cr->original_hookname, $cr->original_sig, $cr->original_next_run_utc );
|
279 |
|
280 |
if ( is_wp_error( $original ) ) {
|
281 |
set_message( $original->get_error_message() );
|
284 |
exit;
|
285 |
}
|
286 |
|
287 |
+
$deleted = Event\delete( $cr->original_hookname, $cr->original_sig, $cr->original_next_run_utc );
|
288 |
|
289 |
if ( is_wp_error( $deleted ) ) {
|
290 |
set_message( $deleted->get_error_message() );
|
293 |
exit;
|
294 |
}
|
295 |
|
296 |
+
$next_run_local = ( 'custom' === $cr->next_run_date_local ) ? $cr->next_run_date_local_custom_date . ' ' . $cr->next_run_date_local_custom_time : $cr->next_run_date_local;
|
297 |
|
298 |
+
/**
|
299 |
+
* Modifies an event before it is scheduled.
|
300 |
+
*
|
301 |
+
* @param stdClass|false $event An object containing the new event's data, or boolean false.
|
302 |
+
*/
|
303 |
add_filter( 'schedule_event', function( $event ) use ( $original ) {
|
304 |
+
if ( ! $event ) {
|
305 |
return $event;
|
306 |
}
|
307 |
|
308 |
/**
|
309 |
* Fires after a cron event is edited.
|
310 |
*
|
311 |
+
* @param stdClass $event {
|
312 |
* An object containing the new event's data.
|
313 |
*
|
314 |
* @type string $hook Action hook to execute when the event is run.
|
315 |
* @type int $timestamp Unix timestamp (UTC) for when to next run the event.
|
316 |
* @type string|false $schedule How often the event should subsequently recur.
|
317 |
+
* @type mixed[] $args Array containing each separate argument to pass to the hook's callback function.
|
318 |
* @type int $interval The interval time in seconds for the schedule. Only present for recurring events.
|
319 |
* }
|
320 |
+
* @param stdClass $original {
|
321 |
* An object containing the original event's data.
|
322 |
*
|
323 |
* @type string $hook Action hook to execute when the event is run.
|
324 |
* @type int $timestamp Unix timestamp (UTC) for when to next run the event.
|
325 |
* @type string|false $schedule How often the event should subsequently recur.
|
326 |
+
* @type mixed[] $args Array containing each separate argument to pass to the hook's callback function.
|
327 |
* @type int $interval The interval time in seconds for the schedule. Only present for recurring events.
|
328 |
* }
|
329 |
*/
|
332 |
return $event;
|
333 |
}, 99 );
|
334 |
|
335 |
+
$added = Event\add( $next_run_local, $cr->schedule, $cr->hookname, $args );
|
336 |
|
337 |
if ( is_wp_error( $added ) ) {
|
338 |
set_message( $added->get_error_message() );
|
342 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
343 |
exit;
|
344 |
|
345 |
+
} elseif ( isset( $_POST['action'] ) && ( 'crontrol_edit_php_cron' === $_POST['action'] ) ) {
|
346 |
if ( ! current_user_can( 'edit_files' ) ) {
|
347 |
wp_die( esc_html__( 'You are not allowed to edit PHP cron events.', 'wp-crontrol' ), 401 );
|
348 |
}
|
349 |
|
350 |
+
$cr = $request->init( wp_unslash( $_POST ) );
|
351 |
+
|
352 |
+
check_admin_referer( "crontrol-edit-cron_{$cr->original_hookname}_{$cr->original_sig}_{$cr->original_next_run_utc}" );
|
353 |
$args = array(
|
354 |
+
'code' => $cr->hookcode,
|
355 |
+
'name' => $cr->eventname,
|
356 |
);
|
357 |
+
$hookname = ( ! empty( $cr->eventname ) ) ? $cr->eventname : __( 'PHP Cron', 'wp-crontrol' );
|
358 |
$redirect = array(
|
359 |
'page' => 'crontrol_admin_manage_page',
|
360 |
'crontrol_message' => '4',
|
361 |
'crontrol_name' => rawurlencode( $hookname ),
|
362 |
);
|
363 |
|
364 |
+
$original = Event\get_single( $cr->original_hookname, $cr->original_sig, $cr->original_next_run_utc );
|
365 |
|
366 |
if ( is_wp_error( $original ) ) {
|
367 |
set_message( $original->get_error_message() );
|
370 |
exit;
|
371 |
}
|
372 |
|
373 |
+
$deleted = Event\delete( $cr->original_hookname, $cr->original_sig, $cr->original_next_run_utc );
|
374 |
|
375 |
if ( is_wp_error( $deleted ) ) {
|
376 |
set_message( $deleted->get_error_message() );
|
379 |
exit;
|
380 |
}
|
381 |
|
382 |
+
$next_run_local = ( 'custom' === $cr->next_run_date_local ) ? $cr->next_run_date_local_custom_date . ' ' . $cr->next_run_date_local_custom_time : $cr->next_run_date_local;
|
383 |
|
384 |
+
/**
|
385 |
+
* Modifies an event before it is scheduled.
|
386 |
+
*
|
387 |
+
* @param stdClass|false $event An object containing the new event's data, or boolean false.
|
388 |
+
*/
|
389 |
add_filter( 'schedule_event', function( $event ) use ( $original ) {
|
390 |
+
if ( ! $event ) {
|
391 |
return $event;
|
392 |
}
|
393 |
|
394 |
/**
|
395 |
* Fires after a PHP cron event is edited.
|
396 |
*
|
397 |
+
* @param stdClass $event {
|
398 |
* An object containing the new event's data.
|
399 |
*
|
400 |
* @type string $hook Action hook to execute when the event is run.
|
401 |
* @type int $timestamp Unix timestamp (UTC) for when to next run the event.
|
402 |
* @type string|false $schedule How often the event should subsequently recur.
|
403 |
+
* @type mixed[] $args Array containing each separate argument to pass to the hook's callback function.
|
404 |
* @type int $interval The interval time in seconds for the schedule. Only present for recurring events.
|
405 |
* }
|
406 |
+
* @param stdClass $original {
|
407 |
* An object containing the original event's data.
|
408 |
*
|
409 |
* @type string $hook Action hook to execute when the event is run.
|
410 |
* @type int $timestamp Unix timestamp (UTC) for when to next run the event.
|
411 |
* @type string|false $schedule How often the event should subsequently recur.
|
412 |
+
* @type mixed[] $args Array containing each separate argument to pass to the hook's callback function.
|
413 |
* @type int $interval The interval time in seconds for the schedule. Only present for recurring events.
|
414 |
* }
|
415 |
*/
|
418 |
return $event;
|
419 |
}, 99 );
|
420 |
|
421 |
+
$added = Event\add( $next_run_local, $cr->schedule, 'crontrol_cron_job', $args );
|
422 |
|
423 |
if ( is_wp_error( $added ) ) {
|
424 |
set_message( $added->get_error_message() );
|
428 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
429 |
exit;
|
430 |
|
431 |
+
} elseif ( isset( $_POST['crontrol_new_schedule'] ) ) {
|
432 |
if ( ! current_user_can( 'manage_options' ) ) {
|
433 |
wp_die( esc_html__( 'You are not allowed to add new cron schedules.', 'wp-crontrol' ), 401 );
|
434 |
}
|
435 |
+
check_admin_referer( 'crontrol-new-schedule' );
|
436 |
$name = wp_unslash( $_POST['internal_name'] );
|
437 |
$interval = absint( $_POST['interval'] );
|
438 |
$display = wp_unslash( $_POST['display_name'] );
|
446 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'options-general.php' ) ) );
|
447 |
exit;
|
448 |
|
449 |
+
} elseif ( isset( $_GET['action'] ) && 'crontrol-delete-schedule' === $_GET['action'] ) {
|
450 |
if ( ! current_user_can( 'manage_options' ) ) {
|
451 |
wp_die( esc_html__( 'You are not allowed to delete cron schedules.', 'wp-crontrol' ), 401 );
|
452 |
}
|
453 |
$schedule = wp_unslash( $_GET['id'] );
|
454 |
+
check_admin_referer( "crontrol-delete-schedule_{$schedule}" );
|
455 |
Schedule\delete( $schedule );
|
456 |
$redirect = array(
|
457 |
'page' => 'crontrol_admin_options_page',
|
461 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'options-general.php' ) ) );
|
462 |
exit;
|
463 |
|
464 |
+
} elseif ( ( isset( $_POST['action'] ) && 'crontrol_delete_crons' === $_POST['action'] ) || ( isset( $_POST['action2'] ) && 'crontrol_delete_crons' === $_POST['action2'] ) ) {
|
465 |
if ( ! current_user_can( 'manage_options' ) ) {
|
466 |
wp_die( esc_html__( 'You are not allowed to delete cron events.', 'wp-crontrol' ), 401 );
|
467 |
}
|
471 |
return;
|
472 |
}
|
473 |
|
474 |
+
/**
|
475 |
+
* @var array<string,array<string,string>>
|
476 |
+
*/
|
477 |
+
$delete = (array) wp_unslash( $_POST['delete'] );
|
478 |
$deleted = 0;
|
479 |
|
480 |
foreach ( $delete as $next_run_utc => $events ) {
|
481 |
+
foreach ( (array) $events as $hook => $sig ) {
|
482 |
if ( 'crontrol_cron_job' === $hook && ! current_user_can( 'edit_files' ) ) {
|
483 |
continue;
|
484 |
}
|
503 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
504 |
exit;
|
505 |
|
506 |
+
} elseif ( isset( $_GET['action'] ) && 'crontrol-delete-cron' === $_GET['action'] ) {
|
507 |
if ( ! current_user_can( 'manage_options' ) ) {
|
508 |
wp_die( esc_html__( 'You are not allowed to delete cron events.', 'wp-crontrol' ), 401 );
|
509 |
}
|
510 |
$hook = wp_unslash( $_GET['id'] );
|
511 |
$sig = wp_unslash( $_GET['sig'] );
|
512 |
+
$next_run_utc = wp_unslash( $_GET['next_run_utc'] );
|
513 |
+
check_admin_referer( "crontrol-delete-cron_{$hook}_{$sig}_{$next_run_utc}" );
|
514 |
|
515 |
if ( 'crontrol_cron_job' === $hook && ! current_user_can( 'edit_files' ) ) {
|
516 |
wp_die( esc_html__( 'You are not allowed to delete PHP cron events.', 'wp-crontrol' ), 401 );
|
540 |
/**
|
541 |
* Fires after a cron event is deleted.
|
542 |
*
|
543 |
+
* @param stdClass $event {
|
544 |
* An object containing the event's data.
|
545 |
*
|
546 |
* @type string $hook Action hook to execute when the event is run.
|
547 |
* @type int $timestamp Unix timestamp (UTC) for when to next run the event.
|
548 |
* @type string|false $schedule How often the event should subsequently recur.
|
549 |
+
* @type mixed[] $args Array containing each separate argument to pass to the hook's callback function.
|
550 |
* @type int $interval The interval time in seconds for the schedule. Only present for recurring events.
|
551 |
* }
|
552 |
*/
|
556 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
557 |
exit;
|
558 |
|
559 |
+
} elseif ( isset( $_GET['action'] ) && 'crontrol-delete-hook' === $_GET['action'] ) {
|
560 |
if ( ! current_user_can( 'manage_options' ) ) {
|
561 |
wp_die( esc_html__( 'You are not allowed to delete cron events.', 'wp-crontrol' ), 401 );
|
562 |
}
|
563 |
$hook = wp_unslash( $_GET['id'] );
|
564 |
$deleted = false;
|
565 |
+
check_admin_referer( "crontrol-delete-hook_{$hook}" );
|
566 |
|
567 |
if ( 'crontrol_cron_job' === $hook ) {
|
568 |
wp_die( esc_html__( 'You are not allowed to delete PHP cron events.', 'wp-crontrol' ), 401 );
|
605 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
606 |
exit;
|
607 |
}
|
608 |
+
} elseif ( isset( $_GET['action'] ) && 'crontrol-run-cron' === $_GET['action'] ) {
|
609 |
if ( ! current_user_can( 'manage_options' ) ) {
|
610 |
wp_die( esc_html__( 'You are not allowed to run cron events.', 'wp-crontrol' ), 401 );
|
611 |
}
|
612 |
$hook = wp_unslash( $_GET['id'] );
|
613 |
$sig = wp_unslash( $_GET['sig'] );
|
614 |
+
check_admin_referer( "crontrol-run-cron_{$hook}_{$sig}" );
|
615 |
|
616 |
$ran = Event\run( $hook, $sig );
|
617 |
|
622 |
);
|
623 |
|
624 |
if ( is_wp_error( $ran ) ) {
|
625 |
+
$set = set_message( $ran->get_error_message() );
|
626 |
+
|
627 |
+
// If we can't store the error message in a transient, just display it.
|
628 |
+
if ( ! $set ) {
|
629 |
+
wp_die(
|
630 |
+
esc_html( $ran->get_error_message() ),
|
631 |
+
'',
|
632 |
+
array(
|
633 |
+
'response' => 500,
|
634 |
+
'back_link' => true,
|
635 |
+
)
|
636 |
+
);
|
637 |
+
}
|
638 |
$redirect['crontrol_message'] = 'error';
|
639 |
}
|
640 |
|
641 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
642 |
+
exit;
|
643 |
+
} elseif ( isset( $_POST['action'] ) && 'crontrol-export-event-csv' === $_POST['action'] ) {
|
644 |
+
check_admin_referer( 'crontrol-export-event-csv', 'crontrol_nonce' );
|
645 |
+
|
646 |
+
require_once __DIR__ . '/src/event-list-table.php';
|
647 |
+
|
648 |
+
$type = isset( $_POST['hooks_type'] ) ? $_POST['hooks_type'] : 'all';
|
649 |
+
$headers = array(
|
650 |
+
'hook',
|
651 |
+
'arguments',
|
652 |
+
'next_run',
|
653 |
+
'next_run_gmt',
|
654 |
+
'action',
|
655 |
+
'recurrence',
|
656 |
+
'interval',
|
657 |
+
);
|
658 |
+
$filename = sprintf(
|
659 |
+
'cron-events-%s-%s.csv',
|
660 |
+
$type,
|
661 |
+
gmdate( 'Y-m-d-H.i.s' )
|
662 |
+
);
|
663 |
+
$csv = fopen( 'php://output', 'w' );
|
664 |
+
|
665 |
+
if ( false === $csv ) {
|
666 |
+
wp_die( esc_html__( 'Could not save CSV file.', 'wp-crontrol' ) );
|
667 |
+
}
|
668 |
+
|
669 |
+
$events = Table::get_filtered_events( Event\get() );
|
670 |
+
|
671 |
+
header( 'Content-Type: text/csv; charset=utf-8' );
|
672 |
+
header(
|
673 |
+
sprintf(
|
674 |
+
'Content-Disposition: attachment; filename="%s"',
|
675 |
+
esc_attr( $filename )
|
676 |
+
)
|
677 |
+
);
|
678 |
+
|
679 |
+
fputcsv( $csv, $headers );
|
680 |
+
|
681 |
+
if ( isset( $events[ $type ] ) ) {
|
682 |
+
foreach ( $events[ $type ] as $event ) {
|
683 |
+
$next_run_local = get_date_from_gmt( gmdate( 'Y-m-d H:i:s', $event->time ), 'c' );
|
684 |
+
$next_run_utc = gmdate( 'c', $event->time );
|
685 |
+
$hook_callbacks = \Crontrol\get_hook_callbacks( $event->hook );
|
686 |
+
|
687 |
+
if ( 'crontrol_cron_job' === $event->hook ) {
|
688 |
+
$args = __( 'PHP Code', 'wp-crontrol' );
|
689 |
+
} elseif ( empty( $event->args ) ) {
|
690 |
+
$args = '';
|
691 |
+
} else {
|
692 |
+
$args = \Crontrol\json_output( $event->args, false );
|
693 |
+
}
|
694 |
+
|
695 |
+
if ( 'crontrol_cron_job' === $event->hook ) {
|
696 |
+
$action = __( 'WP Crontrol', 'wp-crontrol' );
|
697 |
+
} else {
|
698 |
+
$callbacks = array();
|
699 |
+
|
700 |
+
foreach ( $hook_callbacks as $callback ) {
|
701 |
+
$callbacks[] = $callback['callback']['name'];
|
702 |
+
}
|
703 |
+
|
704 |
+
$action = implode( ',', $callbacks );
|
705 |
+
}
|
706 |
+
|
707 |
+
if ( $event->schedule ) {
|
708 |
+
$recurrence = Event\get_schedule_name( $event );
|
709 |
+
if ( is_wp_error( $recurrence ) ) {
|
710 |
+
$recurrence = $recurrence->get_error_message();
|
711 |
+
}
|
712 |
+
} else {
|
713 |
+
$recurrence = __( 'Non-repeating', 'wp-crontrol' );
|
714 |
+
}
|
715 |
+
|
716 |
+
$row = array(
|
717 |
+
$event->hook,
|
718 |
+
$args,
|
719 |
+
$next_run_local,
|
720 |
+
$next_run_utc,
|
721 |
+
$action,
|
722 |
+
$recurrence,
|
723 |
+
(int) $event->interval,
|
724 |
+
);
|
725 |
+
fputcsv( $csv, $row );
|
726 |
+
}
|
727 |
+
}
|
728 |
+
|
729 |
+
fclose( $csv );
|
730 |
+
|
731 |
exit;
|
732 |
}
|
733 |
}
|
736 |
* Adds options & management pages to the admin menu.
|
737 |
*
|
738 |
* Run using the 'admin_menu' action.
|
739 |
+
*
|
740 |
+
* @return void
|
741 |
*/
|
742 |
function action_admin_menu() {
|
743 |
+
$schedules = add_options_page(
|
744 |
+
esc_html__( 'Cron Schedules', 'wp-crontrol' ),
|
745 |
+
esc_html__( 'Cron Schedules', 'wp-crontrol' ),
|
746 |
+
'manage_options',
|
747 |
+
'crontrol_admin_options_page',
|
748 |
+
__NAMESPACE__ . '\admin_options_page'
|
749 |
+
);
|
750 |
+
$events = add_management_page(
|
751 |
+
esc_html__( 'Cron Events', 'wp-crontrol' ),
|
752 |
+
esc_html__( 'Cron Events', 'wp-crontrol' ),
|
753 |
+
'manage_options',
|
754 |
+
'crontrol_admin_manage_page',
|
755 |
+
__NAMESPACE__ . '\admin_manage_page'
|
756 |
+
);
|
757 |
|
758 |
add_action( "load-{$schedules}", __NAMESPACE__ . '\admin_help_tab' );
|
759 |
add_action( "load-{$events}", __NAMESPACE__ . '\admin_help_tab' );
|
760 |
}
|
761 |
|
762 |
/**
|
763 |
+
* Adds a Help tab with links to help resources.
|
764 |
+
*
|
765 |
+
* @return void
|
766 |
*/
|
767 |
function admin_help_tab() {
|
768 |
$screen = get_current_screen();
|
769 |
|
770 |
+
if ( ! $screen ) {
|
771 |
+
return;
|
772 |
+
}
|
773 |
+
|
774 |
$content = '<p>' . __( 'There are several places to get help with issues relating to WP-Cron:', 'wp-crontrol' ) . '</p>';
|
775 |
$content .= '<ul>';
|
776 |
$content .= '<li>';
|
807 |
/**
|
808 |
* Adds items to the plugin's action links on the Plugins listing screen.
|
809 |
*
|
810 |
+
* @param array<string,string> $actions Array of action links.
|
811 |
+
* @param string $plugin_file Path to the plugin file relative to the plugins directory.
|
812 |
+
* @param mixed[] $plugin_data An array of plugin data.
|
813 |
+
* @param string $context The plugin context.
|
814 |
+
* @return array<string,string> Array of action links.
|
815 |
*/
|
816 |
function plugin_action_links( $actions, $plugin_file, $plugin_data, $context ) {
|
817 |
$new = array(
|
840 |
*
|
841 |
* Called by the `cron_schedules` filter.
|
842 |
*
|
843 |
+
* @param array<string,array<string,(int|string)>> $scheds Array of cron schedule arrays. Usually empty.
|
844 |
+
* @return array<string,array<string,(int|string)>> Array of modified cron schedule arrays.
|
845 |
*/
|
846 |
function filter_cron_schedules( array $scheds ) {
|
847 |
$new_scheds = get_option( 'crontrol_schedules', array() );
|
855 |
|
856 |
/**
|
857 |
* Displays the options page for the plugin.
|
858 |
+
*
|
859 |
+
* @return void
|
860 |
*/
|
861 |
function admin_options_page() {
|
862 |
$messages = array(
|
926 |
<input type="text" value="" id="cron_display_name" name="display_name" required/>
|
927 |
</div>
|
928 |
<p class="submit">
|
929 |
+
<input id="schedadd-submit" type="submit" class="button button-primary" value="<?php esc_attr_e( 'Add Cron Schedule', 'wp-crontrol' ); ?>" name="crontrol_new_schedule"/>
|
930 |
</p>
|
931 |
+
<?php wp_nonce_field( 'crontrol-new-schedule' ); ?>
|
932 |
</form>
|
933 |
</div>
|
934 |
</div>
|
967 |
* - https://core.trac.wordpress.org/browser/trunk/src/wp-cron.php?rev=47198&marks=127,141#L122
|
968 |
*
|
969 |
* @param mixed $pre The pre-flight value of the event unschedule short-circuit. Not used.
|
970 |
+
* @return mixed The unaltered pre-flight value.
|
971 |
*/
|
972 |
function maybe_clear_doing_cron( $pre ) {
|
973 |
if ( defined( 'DOING_CRON' ) && DOING_CRON && isset( $_GET['crontrol-single-event'] ) ) {
|
979 |
|
980 |
/**
|
981 |
* Ajax handler which outputs a hash of the current list of scheduled events.
|
982 |
+
*
|
983 |
+
* @return void
|
984 |
*/
|
985 |
function ajax_check_events_hash() {
|
986 |
if ( ! current_user_can( 'manage_options' ) ) {
|
987 |
wp_send_json_error( null, 403 );
|
988 |
}
|
989 |
|
990 |
+
$data = json_encode( Event\get() );
|
991 |
+
|
992 |
+
if ( false === $data ) {
|
993 |
+
wp_send_json_error( null, 500 );
|
994 |
+
}
|
995 |
+
|
996 |
+
wp_send_json_success( md5( $data ) );
|
997 |
}
|
998 |
|
999 |
/**
|
1042 |
return true;
|
1043 |
}
|
1044 |
|
1045 |
+
$sslverify = version_compare( $wp_version, '4.0', '<' );
|
1046 |
$doing_wp_cron = sprintf( '%.22F', microtime( true ) );
|
1047 |
|
1048 |
$cron_request = apply_filters( 'cron_request', array(
|
1074 |
|
1075 |
}
|
1076 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1077 |
/**
|
1078 |
* Shows the status of WP-Cron functionality on the site. Only displays a message when there's a problem.
|
1079 |
*
|
1080 |
* @param string $tab The tab name.
|
1081 |
+
* @return void
|
1082 |
*/
|
1083 |
function show_cron_status( $tab ) {
|
|
|
|
|
|
|
|
|
1084 |
if ( 'UTC' !== date_default_timezone_get() ) {
|
1085 |
?>
|
1086 |
<div id="crontrol-timezone-warning" class="notice notice-warning">
|
1236 |
}
|
1237 |
|
1238 |
if ( is_array( $existing ) ) {
|
1239 |
+
$other_fields = wp_nonce_field( "crontrol-edit-cron_{$existing['hookname']}_{$existing['sig']}_{$existing['next_run']}", '_wpnonce', true, false );
|
1240 |
$other_fields .= sprintf( '<input name="original_hookname" type="hidden" value="%s" />',
|
1241 |
esc_attr( $existing['hookname'] )
|
1242 |
);
|
1244 |
esc_attr( $existing['sig'] )
|
1245 |
);
|
1246 |
$other_fields .= sprintf( '<input name="original_next_run_utc" type="hidden" value="%s" />',
|
1247 |
+
esc_attr( (string) $existing['next_run'] )
|
1248 |
);
|
1249 |
if ( ! empty( $existing['args'] ) ) {
|
1250 |
$display_args = wp_json_encode( $existing['args'] );
|
1251 |
+
|
1252 |
+
if ( false === $display_args ) {
|
1253 |
+
$display_args = '';
|
1254 |
+
}
|
1255 |
}
|
|
|
1256 |
$button = __( 'Update Event', 'wp-crontrol' );
|
1257 |
$next_run_gmt = gmdate( 'Y-m-d H:i:s', $existing['next_run'] );
|
1258 |
$next_run_date_local = get_date_from_gmt( $next_run_gmt, 'Y-m-d' );
|
1259 |
$next_run_time_local = get_date_from_gmt( $next_run_gmt, 'H:i:s' );
|
1260 |
} else {
|
1261 |
+
$other_fields = wp_nonce_field( 'crontrol-new-cron', '_wpnonce', true, false );
|
1262 |
$existing = array(
|
1263 |
'hookname' => '',
|
1264 |
'args' => array(),
|
1312 |
<table class="form-table"><tbody>
|
1313 |
<?php
|
1314 |
if ( $editing ) {
|
1315 |
+
$action = $is_editing_php ? 'crontrol_edit_php_cron' : 'crontrol_edit_cron';
|
1316 |
printf(
|
1317 |
'<input type="hidden" name="action" value="%s"/>',
|
1318 |
esc_attr( $action )
|
1324 |
<?php esc_html_e( 'Event Type', 'wp-crontrol' ); ?>
|
1325 |
</th>
|
1326 |
<td>
|
1327 |
+
<p><label><input type="radio" name="action" value="crontrol_new_cron" checked>Standard cron event</label></p>
|
1328 |
+
<p><label><input type="radio" name="action" value="crontrol_new_php_cron">PHP cron event</label></p>
|
1329 |
</td>
|
1330 |
</tr>
|
1331 |
<?php
|
1332 |
} else {
|
1333 |
?>
|
1334 |
+
<input type="hidden" name="action" value="crontrol_new_cron"/>
|
1335 |
<?php
|
1336 |
}
|
1337 |
|
1354 |
?>
|
1355 |
</p>
|
1356 |
<p><textarea class="large-text code" rows="10" cols="50" id="hookcode" name="hookcode"><?php echo esc_textarea( $editing ? $existing['args']['code'] : '' ); ?></textarea></p>
|
1357 |
+
<?php do_action( 'crontrol/manage/hookcode', $existing ); ?>
|
1358 |
</td>
|
1359 |
</tr>
|
1360 |
<tr class="crontrol-event-php">
|
1365 |
</th>
|
1366 |
<td>
|
1367 |
<input type="text" class="regular-text" id="eventname" name="eventname" value="<?php echo esc_attr( $editing ? $existing['args']['name'] : '' ); ?>"/>
|
1368 |
+
<?php do_action( 'crontrol/manage/eventname', $existing ); ?>
|
1369 |
</td>
|
1370 |
</tr>
|
1371 |
<?php
|
1381 |
</th>
|
1382 |
<td>
|
1383 |
<input type="text" autocorrect="off" autocapitalize="off" spellcheck="false" class="regular-text" id="hookname" name="hookname" value="<?php echo esc_attr( $existing['hookname'] ); ?>" required />
|
1384 |
+
<?php do_action( 'crontrol/manage/hookname', $existing ); ?>
|
1385 |
</td>
|
1386 |
</tr>
|
1387 |
<tr class="crontrol-event-standard">
|
1392 |
</th>
|
1393 |
<td>
|
1394 |
<input type="text" autocorrect="off" autocapitalize="off" spellcheck="false" class="regular-text code" id="args" name="args" value="<?php echo esc_attr( $display_args ); ?>"/>
|
1395 |
+
<?php do_action( 'crontrol/manage/args', $existing ); ?>
|
1396 |
<p class="description">
|
1397 |
<?php
|
1398 |
printf(
|
1449 |
</li>
|
1450 |
</ul>
|
1451 |
|
1452 |
+
<?php do_action( 'crontrol/manage/next_run', $existing ); ?>
|
1453 |
+
|
1454 |
<p class="description">
|
1455 |
<?php
|
1456 |
printf(
|
1470 |
</th>
|
1471 |
<td>
|
1472 |
<?php Schedule\dropdown( $existing['schedule'] ); ?>
|
1473 |
+
<?php do_action( 'crontrol/manage/schedule', $existing ); ?>
|
1474 |
</td>
|
1475 |
</tr>
|
1476 |
</tbody></table>
|
1489 |
|
1490 |
/**
|
1491 |
* Displays the manage page for the plugin.
|
1492 |
+
*
|
1493 |
+
* @return void
|
1494 |
*/
|
1495 |
function admin_manage_page() {
|
1496 |
$messages = array(
|
1543 |
__( 'Failed to save the cron event %s.', 'wp-crontrol' ),
|
1544 |
'error',
|
1545 |
),
|
1546 |
+
'error' => array(
|
1547 |
+
__( 'An unknown error occurred.', 'wp-crontrol' ),
|
1548 |
+
'error',
|
1549 |
+
),
|
1550 |
);
|
1551 |
|
1552 |
if ( isset( $_GET['crontrol_name'] ) && isset( $_GET['crontrol_message'] ) && isset( $messages[ $_GET['crontrol_message'] ] ) ) {
|
1555 |
$link = '';
|
1556 |
|
1557 |
if ( 'error' === $message ) {
|
1558 |
+
$error = get_message();
|
1559 |
+
|
1560 |
+
if ( $error ) {
|
1561 |
+
$messages['error'][0] = $error;
|
1562 |
+
}
|
1563 |
}
|
1564 |
|
1565 |
printf(
|
1585 |
|
1586 |
<h1 class="wp-heading-inline"><?php esc_html_e( 'Cron Events', 'wp-crontrol' ); ?></h1>
|
1587 |
|
1588 |
+
<?php echo '<a href="' . esc_url( admin_url( 'tools.php?page=crontrol_admin_manage_page&action=crontrol-new-cron' ) ) . '" class="page-title-action">' . esc_html__( 'Add New', 'wp-crontrol' ) . '</a>'; ?>
|
1589 |
|
1590 |
<hr class="wp-header-end">
|
1591 |
|
1632 |
/**
|
1633 |
* Get the states of the various cron-related tabs.
|
1634 |
*
|
1635 |
+
* @return array<string,bool> Array of states keyed by tab name.
|
1636 |
*/
|
1637 |
function get_tab_states() {
|
1638 |
+
$tabs = array(
|
1639 |
'events' => ( ! empty( $_GET['page'] ) && 'crontrol_admin_manage_page' === $_GET['page'] && empty( $_GET['action'] ) ),
|
1640 |
'schedules' => ( ! empty( $_GET['page'] ) && 'crontrol_admin_options_page' === $_GET['page'] ),
|
1641 |
+
'add-event' => ( ! empty( $_GET['action'] ) && 'crontrol-new-cron' === $_GET['action'] ),
|
1642 |
+
'edit-event' => ( ! empty( $_GET['action'] ) && 'crontrol-edit-cron' === $_GET['action'] ),
|
1643 |
);
|
1644 |
+
|
1645 |
+
$tabs = apply_filters( 'crontrol/tabs', $tabs );
|
1646 |
+
|
1647 |
+
return $tabs;
|
1648 |
}
|
1649 |
|
1650 |
/**
|
1651 |
* Output the cron-related tabs if we're on a cron-related admin screen.
|
1652 |
+
*
|
1653 |
+
* @return void
|
1654 |
*/
|
1655 |
function do_tabs() {
|
1656 |
$tabs = get_tab_states();
|
1678 |
<nav class="nav-tab-wrapper">
|
1679 |
<?php
|
1680 |
foreach ( $links as $id => $link ) {
|
1681 |
+
if ( ! empty( $tabs[ $id ] ) ) {
|
1682 |
printf(
|
1683 |
'<a href="%s" class="nav-tab nav-tab-active">%s</a>',
|
1684 |
esc_url( $link[0] ),
|
1717 |
* Returns an array of the callback functions that are attached to the given hook name.
|
1718 |
*
|
1719 |
* @param string $name The hook name.
|
1720 |
+
* @return array<int,array<string,mixed>> Array of callbacks attached to the hook.
|
1721 |
+
* @phpstan-return array<int,array{
|
1722 |
+
* priority: int,
|
1723 |
+
* callback: array<string,mixed>,
|
1724 |
+
* }>
|
1725 |
*/
|
1726 |
function get_hook_callbacks( $name ) {
|
1727 |
global $wp_filter;
|
1732 |
// See http://core.trac.wordpress.org/ticket/17817.
|
1733 |
$action = $wp_filter[ $name ];
|
1734 |
|
1735 |
+
/**
|
1736 |
+
* @var int $priority
|
1737 |
+
*/
|
1738 |
foreach ( $action as $priority => $callbacks ) {
|
1739 |
foreach ( $callbacks as $callback ) {
|
1740 |
$callback = populate_callback( $callback );
|
1753 |
/**
|
1754 |
* Populates the details of the given callback function.
|
1755 |
*
|
1756 |
+
* @param array<string,mixed> $callback A callback entry.
|
1757 |
+
* @phpstan-param array{
|
1758 |
+
* function: string|array<int,mixed>|object,
|
1759 |
+
* accepted_args: int,
|
1760 |
+
* } $callback
|
1761 |
+
* @return array<string,mixed> The updated callback entry.
|
1762 |
*/
|
1763 |
function populate_callback( array $callback ) {
|
1764 |
// If Query Monitor is installed, use its rich callback analysis.
|
1798 |
/**
|
1799 |
* Returns a user-friendly representation of the callback function.
|
1800 |
*
|
1801 |
+
* @param mixed[] $callback The callback entry.
|
1802 |
* @return string The displayable version of the callback name.
|
1803 |
*/
|
1804 |
function output_callback( array $callback ) {
|
1849 |
* echo \Crontrol\interval( 90 );
|
1850 |
* // 1 minute 30 seconds
|
1851 |
*
|
1852 |
+
* @param int|float $since A period of time in seconds.
|
1853 |
* @return string An interval represented as a string.
|
1854 |
*/
|
1855 |
function interval( $since ) {
|
1881 |
* x days, xx hours
|
1882 |
* so there's only two bits of calculation below:
|
1883 |
*/
|
|
|
1884 |
|
1885 |
// Step one: the first chunk.
|
1886 |
+
foreach ( array_keys( $chunks ) as $i ) {
|
1887 |
$seconds = $chunks[ $i ][0];
|
1888 |
$name = $chunks[ $i ][1];
|
1889 |
|
1890 |
// Finding the biggest chunk (if the chunk fits, break).
|
1891 |
+
$count = (int) floor( $since / $seconds );
|
1892 |
if ( $count ) {
|
1893 |
break;
|
1894 |
}
|
1898 |
$output = sprintf( translate_nooped_plural( $name, $count, 'wp-crontrol' ), $count );
|
1899 |
|
1900 |
// Step two: the second chunk.
|
1901 |
+
if ( $i + 1 < count( $chunks ) ) {
|
1902 |
$seconds2 = $chunks[ $i + 1 ][0];
|
1903 |
$name2 = $chunks[ $i + 1 ][1];
|
1904 |
+
$count2 = (int) floor( ( $since - ( $seconds * $count ) ) / $seconds2 );
|
1905 |
if ( $count2 ) {
|
1906 |
// Add to output var.
|
1907 |
$output .= ' ' . sprintf( translate_nooped_plural( $name2, $count2, 'wp-crontrol' ), $count2 );
|
1913 |
|
1914 |
/**
|
1915 |
* Sets up the Events listing screen.
|
1916 |
+
*
|
1917 |
+
* @return void
|
1918 |
*/
|
1919 |
function setup_manage_page() {
|
1920 |
// Initialise the list table
|
1933 |
* Registers the stylesheet and JavaScript for the admin areas.
|
1934 |
*
|
1935 |
* @param string $hook_suffix The admin screen ID.
|
1936 |
+
* @return void
|
1937 |
*/
|
1938 |
function enqueue_assets( $hook_suffix ) {
|
1939 |
$tab = get_tab_states();
|
1942 |
return;
|
1943 |
}
|
1944 |
|
1945 |
+
$ver = (string) filemtime( plugin_dir_path( __FILE__ ) . 'css/wp-crontrol.css' );
|
1946 |
wp_enqueue_style( 'wp-crontrol', plugin_dir_url( __FILE__ ) . 'css/wp-crontrol.css', array( 'dashicons' ), $ver );
|
1947 |
|
1948 |
+
$ver = (string) filemtime( plugin_dir_path( __FILE__ ) . 'js/wp-crontrol.js' );
|
1949 |
wp_enqueue_script( 'wp-crontrol', plugin_dir_url( __FILE__ ) . 'js/wp-crontrol.js', array( 'jquery', 'wp-a11y' ), $ver, true );
|
1950 |
|
1951 |
$vars = array();
|
1952 |
|
1953 |
if ( ! empty( $tab['events'] ) ) {
|
1954 |
+
$data = json_encode( Event\get() );
|
1955 |
+
|
1956 |
+
if ( false !== $data ) {
|
1957 |
+
$vars['eventsHash'] = md5( $data );
|
1958 |
+
$vars['eventsHashInterval'] = 20;
|
1959 |
+
}
|
1960 |
}
|
1961 |
|
1962 |
if ( ! empty( $tab['add-event'] ) || ! empty( $tab['edit-event'] ) ) {
|
1977 |
/**
|
1978 |
* Filters the list of query arguments which get removed from admin area URLs in WordPress.
|
1979 |
*
|
1980 |
+
* @param array<int,string> $args List of removable query arguments.
|
1981 |
+
* @return array<int,string> Updated list of removable query arguments.
|
1982 |
*/
|
1983 |
function filter_removable_query_args( array $args ) {
|
1984 |
return array_merge( $args, array(
|
1990 |
/**
|
1991 |
* Returns an array of cron event hooks that are persistently added by WordPress core.
|
1992 |
*
|
1993 |
+
* @return array<int,string> Array of hook names.
|
1994 |
*/
|
1995 |
function get_persistent_core_hooks() {
|
1996 |
return array(
|
1997 |
+
'wp_update_plugins', // 2.7.0
|
1998 |
+
'wp_update_themes', // 2.7.0
|
1999 |
+
'wp_version_check', // 2.7.0
|
2000 |
+
'wp_scheduled_delete', // 2.9.0
|
2001 |
+
'update_network_counts', // 3.1.0
|
2002 |
+
'wp_scheduled_auto_draft_delete', // 3.4.0
|
2003 |
+
'delete_expired_transients', // 4.9.0
|
2004 |
+
'wp_privacy_delete_old_export_files', // 4.9.6
|
2005 |
+
'recovery_mode_clean_expired_keys', // 5.2.0
|
2006 |
+
'wp_site_health_scheduled_check', // 5.4.0
|
2007 |
+
'wp_https_detection', // 5.7.0
|
2008 |
);
|
2009 |
}
|
2010 |
|
2011 |
/**
|
2012 |
* Returns an array of all cron event hooks that are added by WordPress core.
|
2013 |
*
|
2014 |
+
* @return array<int,string> Array of hook names.
|
2015 |
*/
|
2016 |
function get_all_core_hooks() {
|
2017 |
return array_merge(
|
2018 |
get_persistent_core_hooks(),
|
2019 |
array(
|
2020 |
+
'do_pings', // 2.1.0
|
2021 |
+
'publish_future_post', // 2.1.0
|
2022 |
+
'importer_scheduled_cleanup', // 2.5.0
|
2023 |
+
'upgrader_scheduled_cleanup', // 3.2.2
|
2024 |
+
'wp_maybe_auto_update', // 3.7.0
|
2025 |
+
'wp_split_shared_term_batch', // 4.3.0
|
2026 |
+
'wp_update_comment_type_batch', // 5.5.0
|
2027 |
+
'delete_temp_updater_backups', // 5.9.0
|
2028 |
+
'wp_delete_temp_updater_backups', // 5.9.0
|
2029 |
)
|
2030 |
);
|
2031 |
}
|
2033 |
/**
|
2034 |
* Returns an array of cron schedules that are added by WordPress core.
|
2035 |
*
|
2036 |
+
* @return array<int,string> Array of schedule names.
|
2037 |
*/
|
2038 |
function get_core_schedules() {
|
2039 |
return array(
|
2047 |
/**
|
2048 |
* Encodes some input as JSON for output.
|
2049 |
*
|
2050 |
+
* @param mixed $input The input.
|
2051 |
+
* @param bool $pretty Whether to pretty print the output. Default true.
|
2052 |
* @return string The JSON-encoded output.
|
2053 |
*/
|
2054 |
+
function json_output( $input, $pretty = true ) {
|
2055 |
$json_options = 0;
|
2056 |
|
2057 |
if ( defined( 'JSON_UNESCAPED_SLASHES' ) ) {
|
2058 |
// phpcs:ignore PHPCompatibility.Constants.NewConstants.json_unescaped_slashesFound
|
2059 |
$json_options |= JSON_UNESCAPED_SLASHES;
|
2060 |
}
|
2061 |
+
|
2062 |
+
if ( $pretty && defined( 'JSON_PRETTY_PRINT' ) ) {
|
2063 |
$json_options |= JSON_PRETTY_PRINT;
|
2064 |
}
|
2065 |
|
2066 |
+
$output = wp_json_encode( $input, $json_options );
|
2067 |
+
|
2068 |
+
if ( false === $output ) {
|
2069 |
+
$output = '';
|
2070 |
+
}
|
2071 |
+
|
2072 |
+
return $output;
|
2073 |
}
|
2074 |
|
2075 |
/**
|
2085 |
* Therefore, the user access level required to execute arbitrary PHP code does not change with WP Crontrol activated.
|
2086 |
*
|
2087 |
* @param string $code The PHP code to evaluate.
|
2088 |
+
* @return void
|
2089 |
*/
|
2090 |
function action_php_cron_event( $code ) {
|
2091 |
// phpcs:ignore Squiz.PHP.Eval.Discouraged
|