Version Description
Download this release
Release Info
Developer | johnbillion |
Plugin | WP Crontrol |
Version | 1.6 |
Comparing to | |
See all releases |
Code changes from version 1.5 to 1.6
- readme.txt +11 -2
- wp-crontrol.php +336 -127
readme.txt
CHANGED
@@ -2,8 +2,8 @@
|
|
2 |
Contributors: johnbillion, scompt
|
3 |
Tags: admin, cron, plugin, control, wp-cron, crontrol
|
4 |
Requires at least: 4.1
|
5 |
-
Tested up to: 4.
|
6 |
-
Stable tag: 1.
|
7 |
|
8 |
WP Crontrol lets you view and control what's happening in the WP-Cron system.
|
9 |
|
@@ -14,6 +14,7 @@ WP Crontrol lets you view and control what's happening in the WP-Cron system. Fr
|
|
14 |
* View all cron events along with their arguments, recurrence, callback functions, and when they are next due.
|
15 |
* Edit, delete, and immediately run any cron events.
|
16 |
* Add new cron events.
|
|
|
17 |
* Add, edit, and remove custom cron schedules.
|
18 |
|
19 |
The admin screen 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).
|
@@ -53,6 +54,14 @@ The next step is to write your function. Here's a simple example:
|
|
53 |
wp_mail( 'hello@example.com', 'WP Crontrol', 'WP Crontrol rocks!' );
|
54 |
}`
|
55 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
= Are any WP-CLI commands available? =
|
57 |
|
58 |
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.
|
2 |
Contributors: johnbillion, scompt
|
3 |
Tags: admin, cron, plugin, control, wp-cron, crontrol
|
4 |
Requires at least: 4.1
|
5 |
+
Tested up to: 4.9
|
6 |
+
Stable tag: 1.6
|
7 |
|
8 |
WP Crontrol lets you view and control what's happening in the WP-Cron system.
|
9 |
|
14 |
* View all cron events along with their arguments, recurrence, callback functions, and when they are next due.
|
15 |
* Edit, delete, and immediately run any cron events.
|
16 |
* Add new cron events.
|
17 |
+
* Bulk delete cron events.
|
18 |
* Add, edit, and remove custom cron schedules.
|
19 |
|
20 |
The admin screen 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).
|
54 |
wp_mail( 'hello@example.com', 'WP Crontrol', 'WP Crontrol rocks!' );
|
55 |
}`
|
56 |
|
57 |
+
= Which users can manage cron events and schedules? =
|
58 |
+
|
59 |
+
Only users with the `manage_options` capability can manage cron events and schedules. By default, only Administrators have this capability.
|
60 |
+
|
61 |
+
= Which users can manage PHP cron events? =
|
62 |
+
|
63 |
+
Only users with the `edit_files` capability can manage PHP cron events. By default, only Administrators have this capability, and with Multisite enabled only Super Admins have this capability.
|
64 |
+
|
65 |
= Are any WP-CLI commands available? =
|
66 |
|
67 |
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.
|
wp-crontrol.php
CHANGED
@@ -5,7 +5,7 @@
|
|
5 |
* Description: WP Crontrol lets you view and control what's happening in the WP-Cron system.
|
6 |
* Author: John Blackbourn & contributors
|
7 |
* Author URI: https://github.com/johnbillion/wp-crontrol/graphs/contributors
|
8 |
-
* Version: 1.
|
9 |
* Text Domain: wp-crontrol
|
10 |
* Domain Path: /languages/
|
11 |
* License: GPL v2 or later
|
@@ -54,6 +54,9 @@ class Crontrol {
|
|
54 |
add_action( 'init', array( $this, 'action_handle_posts' ) );
|
55 |
add_action( 'admin_menu', array( $this, 'action_admin_menu' ) );
|
56 |
add_filter( "plugin_action_links_{$plugin_file}", array( $this, 'plugin_action_links' ), 10, 4 );
|
|
|
|
|
|
|
57 |
|
58 |
register_activation_hook( __FILE__, array( $this, 'action_activate' ) );
|
59 |
|
@@ -65,7 +68,7 @@ class Crontrol {
|
|
65 |
* Evaluates the provided code using eval.
|
66 |
*/
|
67 |
public function action_php_cron_event( $code ) {
|
68 |
-
eval( $code );
|
69 |
}
|
70 |
|
71 |
/**
|
@@ -83,6 +86,9 @@ class Crontrol {
|
|
83 |
if ( ! current_user_can( 'manage_options' ) ) {
|
84 |
wp_die( esc_html__( 'You are not allowed to add new cron events.', 'wp-crontrol' ) );
|
85 |
}
|
|
|
|
|
|
|
86 |
check_admin_referer( 'new-cron' );
|
87 |
extract( wp_unslash( $_POST ), EXTR_PREFIX_ALL, 'in' );
|
88 |
$in_args = json_decode( $in_args, true );
|
@@ -91,12 +97,12 @@ class Crontrol {
|
|
91 |
$redirect = array(
|
92 |
'page' => 'crontrol_admin_manage_page',
|
93 |
'crontrol_message' => '5',
|
94 |
-
'crontrol_name' =>
|
95 |
);
|
96 |
-
|
97 |
exit;
|
98 |
|
99 |
-
}
|
100 |
if ( ! current_user_can( 'edit_files' ) ) {
|
101 |
wp_die( esc_html__( 'You are not allowed to add new PHP cron events.', 'wp-crontrol' ) );
|
102 |
}
|
@@ -112,12 +118,12 @@ class Crontrol {
|
|
112 |
$redirect = array(
|
113 |
'page' => 'crontrol_admin_manage_page',
|
114 |
'crontrol_message' => '5',
|
115 |
-
'crontrol_name' =>
|
116 |
);
|
117 |
-
|
118 |
exit;
|
119 |
|
120 |
-
}
|
121 |
if ( ! current_user_can( 'manage_options' ) ) {
|
122 |
wp_die( esc_html__( 'You are not allowed to edit cron events.', 'wp-crontrol' ) );
|
123 |
}
|
@@ -131,12 +137,12 @@ class Crontrol {
|
|
131 |
$redirect = array(
|
132 |
'page' => 'crontrol_admin_manage_page',
|
133 |
'crontrol_message' => '4',
|
134 |
-
'crontrol_name' =>
|
135 |
);
|
136 |
-
|
137 |
exit;
|
138 |
|
139 |
-
}
|
140 |
if ( ! current_user_can( 'edit_files' ) ) {
|
141 |
wp_die( esc_html__( 'You are not allowed to edit cron events.', 'wp-crontrol' ) );
|
142 |
}
|
@@ -156,12 +162,12 @@ class Crontrol {
|
|
156 |
$redirect = array(
|
157 |
'page' => 'crontrol_admin_manage_page',
|
158 |
'crontrol_message' => '4',
|
159 |
-
'crontrol_name' =>
|
160 |
);
|
161 |
-
|
162 |
exit;
|
163 |
|
164 |
-
}
|
165 |
if ( ! current_user_can( 'manage_options' ) ) {
|
166 |
wp_die( esc_html__( 'You are not allowed to add new cron schedules.', 'wp-crontrol' ) );
|
167 |
}
|
@@ -179,19 +185,19 @@ class Crontrol {
|
|
179 |
$redirect = array(
|
180 |
'page' => 'crontrol_admin_options_page',
|
181 |
'crontrol_message' => '7',
|
182 |
-
'crontrol_name' =>
|
183 |
);
|
184 |
-
|
185 |
exit;
|
186 |
}
|
187 |
$interval = $future - $now;
|
188 |
-
}
|
189 |
$redirect = array(
|
190 |
'page' => 'crontrol_admin_options_page',
|
191 |
'crontrol_message' => '7',
|
192 |
-
'crontrol_name' =>
|
193 |
);
|
194 |
-
|
195 |
exit;
|
196 |
}
|
197 |
|
@@ -199,12 +205,12 @@ class Crontrol {
|
|
199 |
$redirect = array(
|
200 |
'page' => 'crontrol_admin_options_page',
|
201 |
'crontrol_message' => '3',
|
202 |
-
'crontrol_name' =>
|
203 |
);
|
204 |
-
|
205 |
exit;
|
206 |
|
207 |
-
}
|
208 |
if ( ! current_user_can( 'manage_options' ) ) {
|
209 |
wp_die( esc_html__( 'You are not allowed to delete cron schedules.', 'wp-crontrol' ) );
|
210 |
}
|
@@ -214,39 +220,68 @@ class Crontrol {
|
|
214 |
$redirect = array(
|
215 |
'page' => 'crontrol_admin_options_page',
|
216 |
'crontrol_message' => '2',
|
217 |
-
'crontrol_name' =>
|
218 |
);
|
219 |
-
|
220 |
exit;
|
221 |
|
222 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
223 |
if ( ! current_user_can( 'manage_options' ) ) {
|
224 |
wp_die( esc_html__( 'You are not allowed to delete cron events.', 'wp-crontrol' ) );
|
225 |
}
|
226 |
$id = wp_unslash( $_GET['id'] );
|
227 |
$sig = wp_unslash( $_GET['sig'] );
|
228 |
-
$next_run = $_GET['next_run'];
|
229 |
check_admin_referer( "delete-cron_{$id}_{$sig}_{$next_run}" );
|
230 |
if ( $this->delete_cron( $id, $sig, $next_run ) ) {
|
231 |
$redirect = array(
|
232 |
'page' => 'crontrol_admin_manage_page',
|
233 |
'crontrol_message' => '6',
|
234 |
-
'crontrol_name' =>
|
235 |
);
|
236 |
-
|
237 |
exit;
|
238 |
} else {
|
239 |
$redirect = array(
|
240 |
'page' => 'crontrol_admin_manage_page',
|
241 |
'crontrol_message' => '7',
|
242 |
-
'crontrol_name' =>
|
243 |
);
|
244 |
-
|
245 |
exit;
|
246 |
|
247 |
};
|
248 |
|
249 |
-
}
|
250 |
if ( ! current_user_can( 'manage_options' ) ) {
|
251 |
wp_die( esc_html__( 'You are not allowed to run cron events.', 'wp-crontrol' ) );
|
252 |
}
|
@@ -257,17 +292,17 @@ class Crontrol {
|
|
257 |
$redirect = array(
|
258 |
'page' => 'crontrol_admin_manage_page',
|
259 |
'crontrol_message' => '1',
|
260 |
-
'crontrol_name' =>
|
261 |
);
|
262 |
-
|
263 |
exit;
|
264 |
} else {
|
265 |
$redirect = array(
|
266 |
'page' => 'crontrol_admin_manage_page',
|
267 |
'crontrol_message' => '8',
|
268 |
-
'crontrol_name' =>
|
269 |
);
|
270 |
-
|
271 |
exit;
|
272 |
}
|
273 |
}
|
@@ -312,7 +347,7 @@ class Crontrol {
|
|
312 |
if ( ! is_array( $args ) ) {
|
313 |
$args = array();
|
314 |
}
|
315 |
-
if ( '_oneoff'
|
316 |
return wp_schedule_single_event( $next_run, $hookname, $args ) === null;
|
317 |
} else {
|
318 |
return wp_schedule_event( $next_run, $schedule, $hookname, $args ) === null;
|
@@ -343,7 +378,10 @@ class Crontrol {
|
|
343 |
*/
|
344 |
public function add_schedule( $name, $interval, $display ) {
|
345 |
$old_scheds = get_option( 'crontrol_schedules', array() );
|
346 |
-
$old_scheds[ $name ] = array(
|
|
|
|
|
|
|
347 |
update_option( 'crontrol_schedules', $old_scheds );
|
348 |
}
|
349 |
|
@@ -385,12 +423,12 @@ class Crontrol {
|
|
385 |
public function plugin_action_links( $actions, $plugin_file, $plugin_data, $context ) {
|
386 |
$actions['crontrol-events'] = sprintf(
|
387 |
'<a href="%s">%s</a>',
|
388 |
-
admin_url( 'tools.php?page=crontrol_admin_manage_page' ),
|
389 |
esc_html__( 'Cron Events', 'wp-crontrol' )
|
390 |
);
|
391 |
$actions['crontrol-schedules'] = sprintf(
|
392 |
'<a href="%s">%s</a>',
|
393 |
-
admin_url( 'options-general.php?page=crontrol_admin_options_page' ),
|
394 |
esc_html__( 'Cron Schedules', 'wp-crontrol' )
|
395 |
);
|
396 |
return $actions;
|
@@ -414,9 +452,16 @@ class Crontrol {
|
|
414 |
*/
|
415 |
public function admin_options_page() {
|
416 |
$schedules = $this->get_schedules();
|
|
|
417 |
$custom_schedules = get_option( 'crontrol_schedules', array() );
|
418 |
$custom_keys = array_keys( $custom_schedules );
|
419 |
|
|
|
|
|
|
|
|
|
|
|
|
|
420 |
$messages = array(
|
421 |
/* translators: 1: The name of the cron schedule. */
|
422 |
'2' => __( 'Successfully deleted the cron schedule %s.', 'wp-crontrol' ),
|
@@ -427,7 +472,8 @@ class Crontrol {
|
|
427 |
);
|
428 |
if ( isset( $_GET['crontrol_message'] ) && isset( $_GET['crontrol_name'] ) && isset( $messages[ $_GET['crontrol_message'] ] ) ) {
|
429 |
$hook = wp_unslash( $_GET['crontrol_name'] );
|
430 |
-
$
|
|
|
431 |
|
432 |
printf( '<div id="message" class="updated notice is-dismissible"><p>%s</p></div>', $msg ); // WPCS:: XSS ok.
|
433 |
}
|
@@ -442,7 +488,7 @@ class Crontrol {
|
|
442 |
<th scope="col"><?php esc_html_e( 'Name', 'wp-crontrol' ); ?></th>
|
443 |
<th scope="col"><?php esc_html_e( 'Interval', 'wp-crontrol' ); ?></th>
|
444 |
<th scope="col"><?php esc_html_e( 'Display Name', 'wp-crontrol' ); ?></th>
|
445 |
-
<th
|
446 |
</tr>
|
447 |
</thead>
|
448 |
<tbody>
|
@@ -466,20 +512,27 @@ class Crontrol {
|
|
466 |
printf( '<td>%s</td>',
|
467 |
esc_html( $data['display'] )
|
468 |
);
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
-
|
473 |
-
'
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
480 |
} else {
|
481 |
-
echo '
|
482 |
}
|
|
|
483 |
echo '</tr>';
|
484 |
}
|
485 |
}
|
@@ -487,8 +540,18 @@ class Crontrol {
|
|
487 |
</tbody>
|
488 |
</table>
|
489 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
490 |
<div class="wrap narrow">
|
491 |
-
<h2 class="title"><?php esc_html_e( 'Add
|
492 |
<p><?php esc_html_e( 'Adding a new cron schedule will allow you to schedule events that re-occur at the given interval.', 'wp-crontrol' ); ?></p>
|
493 |
<form method="post" action="options-general.php?page=crontrol_admin_options_page">
|
494 |
<table class="form-table">
|
@@ -518,10 +581,14 @@ class Crontrol {
|
|
518 |
*/
|
519 |
public function get_schedules() {
|
520 |
$schedules = wp_get_schedules();
|
521 |
-
uasort( $schedules,
|
522 |
return $schedules;
|
523 |
}
|
524 |
|
|
|
|
|
|
|
|
|
525 |
/**
|
526 |
* Displays a dropdown filled with the possible schedules, including non-repeating.
|
527 |
*
|
@@ -589,7 +656,7 @@ class Crontrol {
|
|
589 |
|
590 |
if ( is_wp_error( $result ) ) {
|
591 |
return $result;
|
592 |
-
}
|
593 |
return new WP_Error( 'unexpected_http_response_code', sprintf(
|
594 |
/* translators: 1: The HTTP response code. */
|
595 |
__( 'Unexpected HTTP response code: %s', 'wp-crontrol' ),
|
@@ -611,7 +678,7 @@ class Crontrol {
|
|
611 |
$status = $this->test_cron_spawn();
|
612 |
|
613 |
if ( is_wp_error( $status ) ) {
|
614 |
-
if (
|
615 |
?>
|
616 |
<div id="cron-status-notice" class="notice notice-info">
|
617 |
<p><?php echo esc_html( $status->get_error_message() ); ?></p>
|
@@ -624,7 +691,8 @@ class Crontrol {
|
|
624 |
printf(
|
625 |
/* translators: 1: Error message text. */
|
626 |
esc_html__( 'There was a problem spawning a call to the WP-Cron system on your site. This means WP-Cron events on your site may not work. The problem was: %s', 'wp-crontrol' ),
|
627 |
-
'<br><strong>' . esc_html( $status->get_error_message() ) . '</strong>'
|
|
|
628 |
?></p>
|
629 |
</div>
|
630 |
<?php
|
@@ -679,6 +747,7 @@ class Crontrol {
|
|
679 |
$helper_text = esc_html__( 'Cron events trigger actions in your code. Enter the schedule of the event, as well as the PHP code to execute when the action is triggered.', 'wp-crontrol' );
|
680 |
} else {
|
681 |
$helper_text = sprintf(
|
|
|
682 |
esc_html__( 'Cron events trigger actions in your code. A cron event needs a corresponding action hook somewhere in code, e.g. the %1$s file in your theme.', 'wp-crontrol' ),
|
683 |
'<code>functions.php</code>'
|
684 |
);
|
@@ -703,11 +772,17 @@ class Crontrol {
|
|
703 |
list( $next_run_date, $next_run_time ) = explode( ' ', get_date_from_gmt( date( 'Y-m-d H:i:s', $existing['next_run'] ), 'Y-m-d H:i:s' ) );
|
704 |
} else {
|
705 |
$other_fields = wp_nonce_field( 'new-cron', '_wpnonce', true, false );
|
706 |
-
$existing = array(
|
|
|
|
|
|
|
|
|
|
|
707 |
$action = $is_php ? 'new_php_cron' : 'new_cron';
|
708 |
$button = $is_php ? $new_tabs['php-cron'] : $new_tabs['cron'];
|
709 |
$show_edit_tab = false;
|
710 |
-
$next_run_time =
|
|
|
711 |
}
|
712 |
if ( $is_php ) {
|
713 |
if ( ! isset( $existing['args']['code'] ) ) {
|
@@ -736,7 +811,18 @@ class Crontrol {
|
|
736 |
<?php if ( $is_php ) : ?>
|
737 |
<tr>
|
738 |
<th valign="top" scope="row"><label for="hookcode"><?php esc_html_e( 'PHP Code', 'wp-crontrol' ); ?></label></th>
|
739 |
-
<td
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
740 |
</tr>
|
741 |
<tr>
|
742 |
<th valign="top" scope="row"><label for="eventname"><?php esc_html_e( 'Event Name (optional)', 'wp-crontrol' ); ?></label></th>
|
@@ -751,15 +837,17 @@ class Crontrol {
|
|
751 |
<th valign="top" scope="row"><label for="args"><?php esc_html_e( 'Arguments (optional)', 'wp-crontrol' ); ?></label></th>
|
752 |
<td>
|
753 |
<input type="text" class="regular-text" id="args" name="args" value="<?php echo esc_attr( $display_args ); ?>"/>
|
754 |
-
<p class="description"
|
755 |
-
|
756 |
-
|
757 |
-
|
758 |
-
|
759 |
-
|
760 |
-
|
761 |
-
|
762 |
-
|
|
|
|
|
763 |
</td>
|
764 |
</tr>
|
765 |
<?php endif; ?>
|
@@ -782,23 +870,38 @@ class Crontrol {
|
|
782 |
</script>
|
783 |
<input type="date" placeholder="YYYY-MM-DD" id="next_run_date" name="next_run_date" value="<?php echo esc_attr( $next_run_date ); ?>" maxlength="10" pattern="\d{4}\-\d{2}\-\d{2}" required />
|
784 |
<input type="time" step="1" placeholder="HH:MM:SS" id="next_run_time" name="next_run_time" value="<?php echo esc_attr( $next_run_time ); ?>" maxlength="8" pattern="\d{2}:\d{2}:\d{2}" required />
|
785 |
-
|
786 |
-
|
787 |
-
|
788 |
-
|
789 |
-
|
790 |
-
|
791 |
-
|
792 |
-
|
793 |
-
|
794 |
-
|
795 |
-
|
796 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
797 |
</td>
|
798 |
</tr><tr>
|
799 |
<th valign="top" scope="row"><label for="schedule"><?php esc_html_e( 'Recurrence', 'wp-crontrol' ); ?></label></th>
|
800 |
<td>
|
801 |
<?php $this->schedules_dropdown( $existing['schedule'] ); ?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
802 |
</td>
|
803 |
</tr>
|
804 |
</tbody></table>
|
@@ -864,15 +967,17 @@ class Crontrol {
|
|
864 |
'7' => __( 'Failed to the delete the cron event %s.', 'wp-crontrol' ),
|
865 |
/* translators: 1: The name of the cron event. */
|
866 |
'8' => __( 'Failed to the execute the cron event %s.', 'wp-crontrol' ),
|
|
|
867 |
);
|
868 |
if ( isset( $_GET['crontrol_name'] ) && isset( $_GET['crontrol_message'] ) && isset( $messages[ $_GET['crontrol_message'] ] ) ) {
|
869 |
$hook = wp_unslash( $_GET['crontrol_name'] );
|
870 |
-
$
|
|
|
871 |
|
872 |
printf( '<div id="message" class="updated notice is-dismissible"><p>%s</p></div>', $msg ); // WPCS:: XSS ok.
|
873 |
}
|
874 |
$events = $this->get_cron_events();
|
875 |
-
$doing_edit = ( isset( $_GET['action'] ) && 'edit-cron'
|
876 |
$time_format = 'Y-m-d H:i:s';
|
877 |
|
878 |
$core_hooks = array(
|
@@ -882,6 +987,7 @@ class Crontrol {
|
|
882 |
'wp_scheduled_delete',
|
883 |
'wp_scheduled_auto_draft_delete',
|
884 |
'update_network_counts',
|
|
|
885 |
);
|
886 |
|
887 |
$this->show_cron_status();
|
@@ -889,9 +995,11 @@ class Crontrol {
|
|
889 |
?>
|
890 |
<div class="wrap">
|
891 |
<h1><?php esc_html_e( 'WP-Cron Events', 'wp-crontrol' ); ?></h1>
|
|
|
892 |
<table class="widefat striped">
|
893 |
<thead>
|
894 |
<tr>
|
|
|
895 |
<th scope="col"><?php esc_html_e( 'Hook Name', 'wp-crontrol' ); ?></th>
|
896 |
<th scope="col"><?php esc_html_e( 'Arguments', 'wp-crontrol' ); ?></th>
|
897 |
<th scope="col"><?php esc_html_e( 'Actions', 'wp-crontrol' ); ?></th>
|
@@ -904,7 +1012,7 @@ class Crontrol {
|
|
904 |
<?php
|
905 |
if ( is_wp_error( $events ) ) {
|
906 |
?>
|
907 |
-
<tr><td colspan="
|
908 |
<?php
|
909 |
} else {
|
910 |
foreach ( $events as $id => $event ) {
|
@@ -922,16 +1030,32 @@ class Crontrol {
|
|
922 |
if ( empty( $event->args ) ) {
|
923 |
$args = '<em>' . esc_html__( 'None', 'wp-crontrol' ) . '</em>';
|
924 |
} else {
|
|
|
|
|
925 |
if ( defined( 'JSON_UNESCAPED_SLASHES' ) ) {
|
926 |
-
$
|
927 |
-
} else {
|
928 |
-
$args = '<code>' . stripslashes( wp_json_encode( $event->args ) ) . '</code>';
|
929 |
}
|
|
|
|
|
|
|
|
|
|
|
930 |
}
|
931 |
|
932 |
-
echo '<tr
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
933 |
|
934 |
-
if ( 'crontrol_cron_job'
|
935 |
if ( ! empty( $event->args['name'] ) ) {
|
936 |
/* translators: 1: The name of the PHP cron event. */
|
937 |
echo '<td><em>' . esc_html( sprintf( __( 'PHP Cron (%s)', 'wp-crontrol' ), $event->args['name'] ) ) . '</em></td>';
|
@@ -946,39 +1070,37 @@ class Crontrol {
|
|
946 |
echo '<td>';
|
947 |
$callbacks = array();
|
948 |
foreach ( $this->get_action_callbacks( $event->hook ) as $callback ) {
|
949 |
-
$callbacks[] = '<
|
950 |
}
|
951 |
-
echo implode( '
|
952 |
echo '</td>';
|
953 |
}
|
954 |
|
955 |
-
echo '<td>';
|
956 |
printf( '%s (%s)',
|
957 |
esc_html( get_date_from_gmt( date( 'Y-m-d H:i:s', $event->time ), $time_format ) ),
|
958 |
esc_html( $this->time_since( time(), $event->time ) )
|
959 |
);
|
960 |
echo '</td>';
|
961 |
|
|
|
962 |
if ( $event->schedule ) {
|
963 |
-
echo
|
964 |
-
echo esc_html( $this->interval( $event->interval ) );
|
965 |
-
echo '</td>';
|
966 |
} else {
|
967 |
-
echo '<td>';
|
968 |
esc_html_e( 'Non-repeating', 'wp-crontrol' );
|
969 |
-
echo '</td>';
|
970 |
}
|
|
|
971 |
|
972 |
$links = array();
|
973 |
|
974 |
-
echo '<td><span class="row-actions visible">';
|
975 |
|
976 |
$link = array(
|
977 |
'page' => 'crontrol_admin_manage_page',
|
978 |
'action' => 'edit-cron',
|
979 |
-
'id' =>
|
980 |
-
'sig' =>
|
981 |
-
'next_run' =>
|
982 |
);
|
983 |
$link = add_query_arg( $link, admin_url( 'tools.php' ) ) . '#crontrol_form';
|
984 |
$links[] = "<a href='" . esc_url( $link ) . "'>" . esc_html__( 'Edit', 'wp-crontrol' ) . '</a>';
|
@@ -986,9 +1108,9 @@ class Crontrol {
|
|
986 |
$link = array(
|
987 |
'page' => 'crontrol_admin_manage_page',
|
988 |
'action' => 'run-cron',
|
989 |
-
'id' =>
|
990 |
-
'sig' =>
|
991 |
-
'next_run' =>
|
992 |
);
|
993 |
$link = add_query_arg( $link, admin_url( 'tools.php' ) );
|
994 |
$link = wp_nonce_url( $link, "run-cron_{$event->hook}_{$event->sig}" );
|
@@ -998,9 +1120,9 @@ class Crontrol {
|
|
998 |
$link = array(
|
999 |
'page' => 'crontrol_admin_manage_page',
|
1000 |
'action' => 'delete-cron',
|
1001 |
-
'id' =>
|
1002 |
-
'sig' =>
|
1003 |
-
'next_run' =>
|
1004 |
);
|
1005 |
$link = add_query_arg( $link, admin_url( 'tools.php' ) );
|
1006 |
$link = wp_nonce_url( $link, "delete-cron_{$event->hook}_{$event->sig}_{$event->time}" );
|
@@ -1016,13 +1138,22 @@ class Crontrol {
|
|
1016 |
?>
|
1017 |
</tbody>
|
1018 |
</table>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1019 |
|
1020 |
</div>
|
1021 |
<?php
|
1022 |
if ( is_array( $doing_edit ) ) {
|
1023 |
$this->show_cron_form( 'crontrol_cron_job' == $doing_edit['hookname'], $doing_edit );
|
1024 |
} else {
|
1025 |
-
$this->show_cron_form( ( isset( $_GET['action'] ) and 'new-php-cron'
|
1026 |
}
|
1027 |
}
|
1028 |
|
@@ -1031,30 +1162,24 @@ class Crontrol {
|
|
1031 |
|
1032 |
$actions = array();
|
1033 |
|
1034 |
-
if ( isset( $wp_filter[$name] ) ) {
|
1035 |
|
1036 |
# http://core.trac.wordpress.org/ticket/17817
|
1037 |
-
$action = $wp_filter[$name];
|
1038 |
|
1039 |
foreach ( $action as $priority => $callbacks ) {
|
1040 |
-
|
1041 |
foreach ( $callbacks as $callback ) {
|
1042 |
-
|
1043 |
$callback = self::populate_callback( $callback );
|
1044 |
|
1045 |
$actions[] = array(
|
1046 |
'priority' => $priority,
|
1047 |
'callback' => $callback,
|
1048 |
);
|
1049 |
-
|
1050 |
}
|
1051 |
-
|
1052 |
}
|
1053 |
-
|
1054 |
}
|
1055 |
|
1056 |
return $actions;
|
1057 |
-
|
1058 |
}
|
1059 |
|
1060 |
public static function populate_callback( array $callback ) {
|
@@ -1069,7 +1194,6 @@ class Crontrol {
|
|
1069 |
}
|
1070 |
|
1071 |
if ( is_array( $callback['function'] ) ) {
|
1072 |
-
|
1073 |
if ( is_object( $callback['function'][0] ) ) {
|
1074 |
$class = get_class( $callback['function'][0] );
|
1075 |
$access = '->';
|
@@ -1079,26 +1203,44 @@ class Crontrol {
|
|
1079 |
}
|
1080 |
|
1081 |
$callback['name'] = $class . $access . $callback['function'][1] . '()';
|
1082 |
-
|
1083 |
} elseif ( is_object( $callback['function'] ) ) {
|
1084 |
-
|
1085 |
if ( is_a( $callback['function'], 'Closure' ) ) {
|
1086 |
$callback['name'] = 'Closure';
|
1087 |
} else {
|
1088 |
$class = get_class( $callback['function'] );
|
1089 |
$callback['name'] = $class . '->__invoke()';
|
1090 |
}
|
1091 |
-
|
1092 |
} else {
|
1093 |
-
|
1094 |
$callback['name'] = $callback['function'] . '()';
|
1095 |
-
|
1096 |
}
|
1097 |
|
1098 |
return $callback;
|
1099 |
|
1100 |
}
|
1101 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1102 |
/**
|
1103 |
* Pretty-prints the difference in two times.
|
1104 |
*
|
@@ -1150,13 +1292,16 @@ class Crontrol {
|
|
1150 |
// x days, xx hours
|
1151 |
// so there's only two bits of calculation below:
|
1152 |
|
|
|
|
|
1153 |
// step one: the first chunk
|
1154 |
-
for ( $i = 0
|
1155 |
$seconds = $chunks[ $i ][0];
|
1156 |
$name = $chunks[ $i ][1];
|
1157 |
|
1158 |
// finding the biggest chunk (if the chunk fits, break)
|
1159 |
-
|
|
|
1160 |
break;
|
1161 |
}
|
1162 |
}
|
@@ -1168,8 +1313,8 @@ class Crontrol {
|
|
1168 |
if ( $i + 1 < $j ) {
|
1169 |
$seconds2 = $chunks[ $i + 1 ][0];
|
1170 |
$name2 = $chunks[ $i + 1 ][1];
|
1171 |
-
|
1172 |
-
if (
|
1173 |
// add to output var
|
1174 |
$output .= ' ' . sprintf( translate_nooped_plural( $name2, $count2, 'wp-crontrol' ), $count2 );
|
1175 |
}
|
@@ -1178,6 +1323,70 @@ class Crontrol {
|
|
1178 |
return $output;
|
1179 |
}
|
1180 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1181 |
public static function init() {
|
1182 |
|
1183 |
static $instance = null;
|
5 |
* Description: WP Crontrol lets you view and control what's happening in the WP-Cron system.
|
6 |
* Author: John Blackbourn & contributors
|
7 |
* Author URI: https://github.com/johnbillion/wp-crontrol/graphs/contributors
|
8 |
+
* Version: 1.6
|
9 |
* Text Domain: wp-crontrol
|
10 |
* Domain Path: /languages/
|
11 |
* License: GPL v2 or later
|
54 |
add_action( 'init', array( $this, 'action_handle_posts' ) );
|
55 |
add_action( 'admin_menu', array( $this, 'action_admin_menu' ) );
|
56 |
add_filter( "plugin_action_links_{$plugin_file}", array( $this, 'plugin_action_links' ), 10, 4 );
|
57 |
+
add_filter( 'removable_query_args', array( $this, 'filter_removable_query_args' ) );
|
58 |
+
|
59 |
+
add_action( 'load-tools_page_crontrol_admin_manage_page', array( $this, 'enqueue_code_editor' ) );
|
60 |
|
61 |
register_activation_hook( __FILE__, array( $this, 'action_activate' ) );
|
62 |
|
68 |
* Evaluates the provided code using eval.
|
69 |
*/
|
70 |
public function action_php_cron_event( $code ) {
|
71 |
+
eval( $code ); // @codingStandardsIgnoreLine
|
72 |
}
|
73 |
|
74 |
/**
|
86 |
if ( ! current_user_can( 'manage_options' ) ) {
|
87 |
wp_die( esc_html__( 'You are not allowed to add new cron events.', 'wp-crontrol' ) );
|
88 |
}
|
89 |
+
if ( 'crontrol_cron_job' === $in_hookname && ! current_user_can( 'edit_files' ) ) {
|
90 |
+
wp_die( esc_html__( 'You are not allowed to add new PHP cron events.', 'wp-crontrol' ) );
|
91 |
+
}
|
92 |
check_admin_referer( 'new-cron' );
|
93 |
extract( wp_unslash( $_POST ), EXTR_PREFIX_ALL, 'in' );
|
94 |
$in_args = json_decode( $in_args, true );
|
97 |
$redirect = array(
|
98 |
'page' => 'crontrol_admin_manage_page',
|
99 |
'crontrol_message' => '5',
|
100 |
+
'crontrol_name' => rawurlencode( $in_hookname ),
|
101 |
);
|
102 |
+
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
103 |
exit;
|
104 |
|
105 |
+
} elseif ( isset( $_POST['new_php_cron'] ) ) {
|
106 |
if ( ! current_user_can( 'edit_files' ) ) {
|
107 |
wp_die( esc_html__( 'You are not allowed to add new PHP cron events.', 'wp-crontrol' ) );
|
108 |
}
|
118 |
$redirect = array(
|
119 |
'page' => 'crontrol_admin_manage_page',
|
120 |
'crontrol_message' => '5',
|
121 |
+
'crontrol_name' => rawurlencode( $hookname ),
|
122 |
);
|
123 |
+
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
124 |
exit;
|
125 |
|
126 |
+
} elseif ( isset( $_POST['edit_cron'] ) ) {
|
127 |
if ( ! current_user_can( 'manage_options' ) ) {
|
128 |
wp_die( esc_html__( 'You are not allowed to edit cron events.', 'wp-crontrol' ) );
|
129 |
}
|
137 |
$redirect = array(
|
138 |
'page' => 'crontrol_admin_manage_page',
|
139 |
'crontrol_message' => '4',
|
140 |
+
'crontrol_name' => rawurlencode( $in_hookname ),
|
141 |
);
|
142 |
+
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
143 |
exit;
|
144 |
|
145 |
+
} elseif ( isset( $_POST['edit_php_cron'] ) ) {
|
146 |
if ( ! current_user_can( 'edit_files' ) ) {
|
147 |
wp_die( esc_html__( 'You are not allowed to edit cron events.', 'wp-crontrol' ) );
|
148 |
}
|
162 |
$redirect = array(
|
163 |
'page' => 'crontrol_admin_manage_page',
|
164 |
'crontrol_message' => '4',
|
165 |
+
'crontrol_name' => rawurlencode( $hookname ),
|
166 |
);
|
167 |
+
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
168 |
exit;
|
169 |
|
170 |
+
} elseif ( isset( $_POST['new_schedule'] ) ) {
|
171 |
if ( ! current_user_can( 'manage_options' ) ) {
|
172 |
wp_die( esc_html__( 'You are not allowed to add new cron schedules.', 'wp-crontrol' ) );
|
173 |
}
|
185 |
$redirect = array(
|
186 |
'page' => 'crontrol_admin_options_page',
|
187 |
'crontrol_message' => '7',
|
188 |
+
'crontrol_name' => rawurlencode( $interval ),
|
189 |
);
|
190 |
+
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'options-general.php' ) ) );
|
191 |
exit;
|
192 |
}
|
193 |
$interval = $future - $now;
|
194 |
+
} elseif ( $interval <= 0 ) {
|
195 |
$redirect = array(
|
196 |
'page' => 'crontrol_admin_options_page',
|
197 |
'crontrol_message' => '7',
|
198 |
+
'crontrol_name' => rawurlencode( $interval ),
|
199 |
);
|
200 |
+
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'options-general.php' ) ) );
|
201 |
exit;
|
202 |
}
|
203 |
|
205 |
$redirect = array(
|
206 |
'page' => 'crontrol_admin_options_page',
|
207 |
'crontrol_message' => '3',
|
208 |
+
'crontrol_name' => rawurlencode( $name ),
|
209 |
);
|
210 |
+
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'options-general.php' ) ) );
|
211 |
exit;
|
212 |
|
213 |
+
} elseif ( isset( $_GET['action'] ) && 'delete-sched' == $_GET['action'] ) {
|
214 |
if ( ! current_user_can( 'manage_options' ) ) {
|
215 |
wp_die( esc_html__( 'You are not allowed to delete cron schedules.', 'wp-crontrol' ) );
|
216 |
}
|
220 |
$redirect = array(
|
221 |
'page' => 'crontrol_admin_options_page',
|
222 |
'crontrol_message' => '2',
|
223 |
+
'crontrol_name' => rawurlencode( $id ),
|
224 |
);
|
225 |
+
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'options-general.php' ) ) );
|
226 |
exit;
|
227 |
|
228 |
+
} elseif ( isset( $_POST['delete_crons'] ) ) {
|
229 |
+
if ( ! current_user_can( 'manage_options' ) ) {
|
230 |
+
wp_die( esc_html__( 'You are not allowed to delete cron events.', 'wp-crontrol' ) );
|
231 |
+
}
|
232 |
+
check_admin_referer( 'bulk-delete-crons' );
|
233 |
+
|
234 |
+
if ( empty( $_POST['delete'] ) ) {
|
235 |
+
return;
|
236 |
+
}
|
237 |
+
|
238 |
+
$delete = wp_unslash( $_POST['delete'] );
|
239 |
+
$deleted = 0;
|
240 |
+
|
241 |
+
foreach ( $delete as $next_run => $events ) {
|
242 |
+
foreach ( $events as $id => $sig ) {
|
243 |
+
if ( $this->delete_cron( urldecode( $id ), $sig, $next_run ) ) {
|
244 |
+
$deleted++;
|
245 |
+
}
|
246 |
+
}
|
247 |
+
}
|
248 |
+
|
249 |
+
$redirect = array(
|
250 |
+
'page' => 'crontrol_admin_manage_page',
|
251 |
+
'crontrol_name' => $deleted,
|
252 |
+
'crontrol_message' => '9',
|
253 |
+
);
|
254 |
+
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
255 |
+
exit;
|
256 |
+
|
257 |
+
} elseif ( isset( $_GET['action'] ) && 'delete-cron' == $_GET['action'] ) {
|
258 |
if ( ! current_user_can( 'manage_options' ) ) {
|
259 |
wp_die( esc_html__( 'You are not allowed to delete cron events.', 'wp-crontrol' ) );
|
260 |
}
|
261 |
$id = wp_unslash( $_GET['id'] );
|
262 |
$sig = wp_unslash( $_GET['sig'] );
|
263 |
+
$next_run = intval( $_GET['next_run'] );
|
264 |
check_admin_referer( "delete-cron_{$id}_{$sig}_{$next_run}" );
|
265 |
if ( $this->delete_cron( $id, $sig, $next_run ) ) {
|
266 |
$redirect = array(
|
267 |
'page' => 'crontrol_admin_manage_page',
|
268 |
'crontrol_message' => '6',
|
269 |
+
'crontrol_name' => rawurlencode( $id ),
|
270 |
);
|
271 |
+
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
272 |
exit;
|
273 |
} else {
|
274 |
$redirect = array(
|
275 |
'page' => 'crontrol_admin_manage_page',
|
276 |
'crontrol_message' => '7',
|
277 |
+
'crontrol_name' => rawurlencode( $id ),
|
278 |
);
|
279 |
+
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
280 |
exit;
|
281 |
|
282 |
};
|
283 |
|
284 |
+
} elseif ( isset( $_GET['action'] ) && 'run-cron' == $_GET['action'] ) {
|
285 |
if ( ! current_user_can( 'manage_options' ) ) {
|
286 |
wp_die( esc_html__( 'You are not allowed to run cron events.', 'wp-crontrol' ) );
|
287 |
}
|
292 |
$redirect = array(
|
293 |
'page' => 'crontrol_admin_manage_page',
|
294 |
'crontrol_message' => '1',
|
295 |
+
'crontrol_name' => rawurlencode( $id ),
|
296 |
);
|
297 |
+
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
298 |
exit;
|
299 |
} else {
|
300 |
$redirect = array(
|
301 |
'page' => 'crontrol_admin_manage_page',
|
302 |
'crontrol_message' => '8',
|
303 |
+
'crontrol_name' => rawurlencode( $id ),
|
304 |
);
|
305 |
+
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
306 |
exit;
|
307 |
}
|
308 |
}
|
347 |
if ( ! is_array( $args ) ) {
|
348 |
$args = array();
|
349 |
}
|
350 |
+
if ( '_oneoff' === $schedule ) {
|
351 |
return wp_schedule_single_event( $next_run, $hookname, $args ) === null;
|
352 |
} else {
|
353 |
return wp_schedule_event( $next_run, $schedule, $hookname, $args ) === null;
|
378 |
*/
|
379 |
public function add_schedule( $name, $interval, $display ) {
|
380 |
$old_scheds = get_option( 'crontrol_schedules', array() );
|
381 |
+
$old_scheds[ $name ] = array(
|
382 |
+
'interval' => $interval,
|
383 |
+
'display' => $display,
|
384 |
+
);
|
385 |
update_option( 'crontrol_schedules', $old_scheds );
|
386 |
}
|
387 |
|
423 |
public function plugin_action_links( $actions, $plugin_file, $plugin_data, $context ) {
|
424 |
$actions['crontrol-events'] = sprintf(
|
425 |
'<a href="%s">%s</a>',
|
426 |
+
esc_url( admin_url( 'tools.php?page=crontrol_admin_manage_page' ) ),
|
427 |
esc_html__( 'Cron Events', 'wp-crontrol' )
|
428 |
);
|
429 |
$actions['crontrol-schedules'] = sprintf(
|
430 |
'<a href="%s">%s</a>',
|
431 |
+
esc_url( admin_url( 'options-general.php?page=crontrol_admin_options_page' ) ),
|
432 |
esc_html__( 'Cron Schedules', 'wp-crontrol' )
|
433 |
);
|
434 |
return $actions;
|
452 |
*/
|
453 |
public function admin_options_page() {
|
454 |
$schedules = $this->get_schedules();
|
455 |
+
$events = $this->get_cron_events();
|
456 |
$custom_schedules = get_option( 'crontrol_schedules', array() );
|
457 |
$custom_keys = array_keys( $custom_schedules );
|
458 |
|
459 |
+
if ( is_wp_error( $events ) ) {
|
460 |
+
$events = array();
|
461 |
+
}
|
462 |
+
|
463 |
+
$used_schedules = array_unique( wp_list_pluck( $events, 'schedule' ) );
|
464 |
+
|
465 |
$messages = array(
|
466 |
/* translators: 1: The name of the cron schedule. */
|
467 |
'2' => __( 'Successfully deleted the cron schedule %s.', 'wp-crontrol' ),
|
472 |
);
|
473 |
if ( isset( $_GET['crontrol_message'] ) && isset( $_GET['crontrol_name'] ) && isset( $messages[ $_GET['crontrol_message'] ] ) ) {
|
474 |
$hook = wp_unslash( $_GET['crontrol_name'] );
|
475 |
+
$message = wp_unslash( $_GET['crontrol_message'] );
|
476 |
+
$msg = sprintf( esc_html( $messages[ $message ] ), '<strong>' . esc_html( $hook ) . '</strong>' );
|
477 |
|
478 |
printf( '<div id="message" class="updated notice is-dismissible"><p>%s</p></div>', $msg ); // WPCS:: XSS ok.
|
479 |
}
|
488 |
<th scope="col"><?php esc_html_e( 'Name', 'wp-crontrol' ); ?></th>
|
489 |
<th scope="col"><?php esc_html_e( 'Interval', 'wp-crontrol' ); ?></th>
|
490 |
<th scope="col"><?php esc_html_e( 'Display Name', 'wp-crontrol' ); ?></th>
|
491 |
+
<th scope="col"><?php esc_html_e( 'Delete', 'wp-crontrol' ); ?></th>
|
492 |
</tr>
|
493 |
</thead>
|
494 |
<tbody>
|
512 |
printf( '<td>%s</td>',
|
513 |
esc_html( $data['display'] )
|
514 |
);
|
515 |
+
|
516 |
+
echo '<td>';
|
517 |
+
if ( in_array( $name, $custom_keys, true ) ) {
|
518 |
+
if ( in_array( $name, $used_schedules, true ) ) {
|
519 |
+
esc_html_e( 'This custom schedule is in use and cannot be deleted', 'wp-crontrol' );
|
520 |
+
} else {
|
521 |
+
$url = add_query_arg( array(
|
522 |
+
'page' => 'crontrol_admin_options_page',
|
523 |
+
'action' => 'delete-sched',
|
524 |
+
'id' => rawurlencode( $name ),
|
525 |
+
), admin_url( 'options-general.php' ) );
|
526 |
+
$url = wp_nonce_url( $url, 'delete-sched_' . $name );
|
527 |
+
printf( '<span class="row-actions visible"><span class="delete"><a href="%s">%s</a></span></span>',
|
528 |
+
esc_url( $url ),
|
529 |
+
esc_html__( 'Delete', 'wp-crontrol' )
|
530 |
+
);
|
531 |
+
}
|
532 |
} else {
|
533 |
+
echo ' ';
|
534 |
}
|
535 |
+
echo '</td>';
|
536 |
echo '</tr>';
|
537 |
}
|
538 |
}
|
540 |
</tbody>
|
541 |
</table>
|
542 |
</div>
|
543 |
+
<div class="wrap">
|
544 |
+
<p class="description">
|
545 |
+
<?php printf(
|
546 |
+
'<a href="%s">%s</a>',
|
547 |
+
esc_url( admin_url( 'tools.php?page=crontrol_admin_manage_page' ) ),
|
548 |
+
esc_html__( 'Manage Cron Events', 'wp-crontrol' )
|
549 |
+
);
|
550 |
+
?>
|
551 |
+
</p>
|
552 |
+
</div>
|
553 |
<div class="wrap narrow">
|
554 |
+
<h2 class="title"><?php esc_html_e( 'Add Cron Schedule', 'wp-crontrol' ); ?></h2>
|
555 |
<p><?php esc_html_e( 'Adding a new cron schedule will allow you to schedule events that re-occur at the given interval.', 'wp-crontrol' ); ?></p>
|
556 |
<form method="post" action="options-general.php?page=crontrol_admin_options_page">
|
557 |
<table class="form-table">
|
581 |
*/
|
582 |
public function get_schedules() {
|
583 |
$schedules = wp_get_schedules();
|
584 |
+
uasort( $schedules, array( $this, 'sort_schedules' ) );
|
585 |
return $schedules;
|
586 |
}
|
587 |
|
588 |
+
protected function sort_schedules( $a, $b ) {
|
589 |
+
return ( $a['interval'] - $b['interval'] );
|
590 |
+
}
|
591 |
+
|
592 |
/**
|
593 |
* Displays a dropdown filled with the possible schedules, including non-repeating.
|
594 |
*
|
656 |
|
657 |
if ( is_wp_error( $result ) ) {
|
658 |
return $result;
|
659 |
+
} elseif ( wp_remote_retrieve_response_code( $result ) >= 300 ) {
|
660 |
return new WP_Error( 'unexpected_http_response_code', sprintf(
|
661 |
/* translators: 1: The HTTP response code. */
|
662 |
__( 'Unexpected HTTP response code: %s', 'wp-crontrol' ),
|
678 |
$status = $this->test_cron_spawn();
|
679 |
|
680 |
if ( is_wp_error( $status ) ) {
|
681 |
+
if ( 'crontrol_info' === $status->get_error_code() ) {
|
682 |
?>
|
683 |
<div id="cron-status-notice" class="notice notice-info">
|
684 |
<p><?php echo esc_html( $status->get_error_message() ); ?></p>
|
691 |
printf(
|
692 |
/* translators: 1: Error message text. */
|
693 |
esc_html__( 'There was a problem spawning a call to the WP-Cron system on your site. This means WP-Cron events on your site may not work. The problem was: %s', 'wp-crontrol' ),
|
694 |
+
'<br><strong>' . esc_html( $status->get_error_message() ) . '</strong>'
|
695 |
+
);
|
696 |
?></p>
|
697 |
</div>
|
698 |
<?php
|
747 |
$helper_text = esc_html__( 'Cron events trigger actions in your code. Enter the schedule of the event, as well as the PHP code to execute when the action is triggered.', 'wp-crontrol' );
|
748 |
} else {
|
749 |
$helper_text = sprintf(
|
750 |
+
/* translators: %s: A file name */
|
751 |
esc_html__( 'Cron events trigger actions in your code. A cron event needs a corresponding action hook somewhere in code, e.g. the %1$s file in your theme.', 'wp-crontrol' ),
|
752 |
'<code>functions.php</code>'
|
753 |
);
|
772 |
list( $next_run_date, $next_run_time ) = explode( ' ', get_date_from_gmt( date( 'Y-m-d H:i:s', $existing['next_run'] ), 'Y-m-d H:i:s' ) );
|
773 |
} else {
|
774 |
$other_fields = wp_nonce_field( 'new-cron', '_wpnonce', true, false );
|
775 |
+
$existing = array(
|
776 |
+
'hookname' => '',
|
777 |
+
'args' => array(),
|
778 |
+
'next_run' => 'now',
|
779 |
+
'schedule' => false,
|
780 |
+
);
|
781 |
$action = $is_php ? 'new_php_cron' : 'new_cron';
|
782 |
$button = $is_php ? $new_tabs['php-cron'] : $new_tabs['cron'];
|
783 |
$show_edit_tab = false;
|
784 |
+
$next_run_time = '';
|
785 |
+
$next_run_date = '';
|
786 |
}
|
787 |
if ( $is_php ) {
|
788 |
if ( ! isset( $existing['args']['code'] ) ) {
|
811 |
<?php if ( $is_php ) : ?>
|
812 |
<tr>
|
813 |
<th valign="top" scope="row"><label for="hookcode"><?php esc_html_e( 'PHP Code', 'wp-crontrol' ); ?></label></th>
|
814 |
+
<td>
|
815 |
+
<p class="description">
|
816 |
+
<?php
|
817 |
+
printf(
|
818 |
+
/* translators: The PHP tag name */
|
819 |
+
esc_html__( 'The opening %s tag must not be included.', 'wp-crontrol' ),
|
820 |
+
'<code><?php</code>'
|
821 |
+
);
|
822 |
+
?>
|
823 |
+
</p>
|
824 |
+
<p><textarea class="large-text code" rows="10" cols="50" id="hookcode" name="hookcode"><?php echo esc_textarea( $existing['args']['code'] ); ?></textarea></p>
|
825 |
+
</td>
|
826 |
</tr>
|
827 |
<tr>
|
828 |
<th valign="top" scope="row"><label for="eventname"><?php esc_html_e( 'Event Name (optional)', 'wp-crontrol' ); ?></label></th>
|
837 |
<th valign="top" scope="row"><label for="args"><?php esc_html_e( 'Arguments (optional)', 'wp-crontrol' ); ?></label></th>
|
838 |
<td>
|
839 |
<input type="text" class="regular-text" id="args" name="args" value="<?php echo esc_attr( $display_args ); ?>"/>
|
840 |
+
<p class="description">
|
841 |
+
<?php
|
842 |
+
printf(
|
843 |
+
/* translators: 1, 2, and 3: Example values for an input field. */
|
844 |
+
esc_html__( 'Use a JSON encoded array, e.g. %1$s, %2$s, or %3$s', 'wp-crontrol' ),
|
845 |
+
'<code>[25]</code>',
|
846 |
+
'<code>["asdf"]</code>',
|
847 |
+
'<code>["i","want",25,"cakes"]</code>'
|
848 |
+
);
|
849 |
+
?>
|
850 |
+
</p>
|
851 |
</td>
|
852 |
</tr>
|
853 |
<?php endif; ?>
|
870 |
</script>
|
871 |
<input type="date" placeholder="YYYY-MM-DD" id="next_run_date" name="next_run_date" value="<?php echo esc_attr( $next_run_date ); ?>" maxlength="10" pattern="\d{4}\-\d{2}\-\d{2}" required />
|
872 |
<input type="time" step="1" placeholder="HH:MM:SS" id="next_run_time" name="next_run_time" value="<?php echo esc_attr( $next_run_time ); ?>" maxlength="8" pattern="\d{2}:\d{2}:\d{2}" required />
|
873 |
+
<p class="description">
|
874 |
+
<?php
|
875 |
+
printf(
|
876 |
+
/* translators: %s Timezone name. */
|
877 |
+
esc_html__( 'Timezone: %s', 'wp-crontrol' ),
|
878 |
+
'<code>' . esc_html( $this->get_timezone_name() ) . '</code>'
|
879 |
+
);
|
880 |
+
?>
|
881 |
+
</p>
|
882 |
+
<p class="description datetime-fallback hidden">
|
883 |
+
<?php
|
884 |
+
echo esc_html( sprintf(
|
885 |
+
/* translators: %s Date/time format for an input field. */
|
886 |
+
__( 'Format: %s', 'wp-crontrol' ),
|
887 |
+
date( 'Y' ) . '-02-25 12:34:00'
|
888 |
+
) );
|
889 |
+
?>
|
890 |
+
</p>
|
891 |
</td>
|
892 |
</tr><tr>
|
893 |
<th valign="top" scope="row"><label for="schedule"><?php esc_html_e( 'Recurrence', 'wp-crontrol' ); ?></label></th>
|
894 |
<td>
|
895 |
<?php $this->schedules_dropdown( $existing['schedule'] ); ?>
|
896 |
+
<p class="description">
|
897 |
+
<?php
|
898 |
+
printf(
|
899 |
+
'<a href="%s">%s</a>',
|
900 |
+
esc_url( admin_url( 'options-general.php?page=crontrol_admin_options_page' ) ),
|
901 |
+
esc_html__( 'Manage Cron Schedules', 'wp-crontrol' )
|
902 |
+
);
|
903 |
+
?>
|
904 |
+
</p>
|
905 |
</td>
|
906 |
</tr>
|
907 |
</tbody></table>
|
967 |
'7' => __( 'Failed to the delete the cron event %s.', 'wp-crontrol' ),
|
968 |
/* translators: 1: The name of the cron event. */
|
969 |
'8' => __( 'Failed to the execute the cron event %s.', 'wp-crontrol' ),
|
970 |
+
'9' => __( 'Successfully deleted the selected cron events.', 'wp-crontrol' ),
|
971 |
);
|
972 |
if ( isset( $_GET['crontrol_name'] ) && isset( $_GET['crontrol_message'] ) && isset( $messages[ $_GET['crontrol_message'] ] ) ) {
|
973 |
$hook = wp_unslash( $_GET['crontrol_name'] );
|
974 |
+
$message = wp_unslash( $_GET['crontrol_message'] );
|
975 |
+
$msg = sprintf( esc_html( $messages[ $message ] ), '<strong>' . esc_html( $hook ) . '</strong>' );
|
976 |
|
977 |
printf( '<div id="message" class="updated notice is-dismissible"><p>%s</p></div>', $msg ); // WPCS:: XSS ok.
|
978 |
}
|
979 |
$events = $this->get_cron_events();
|
980 |
+
$doing_edit = ( isset( $_GET['action'] ) && 'edit-cron' === $_GET['action'] ) ? wp_unslash( $_GET['id'] ) : false ;
|
981 |
$time_format = 'Y-m-d H:i:s';
|
982 |
|
983 |
$core_hooks = array(
|
987 |
'wp_scheduled_delete',
|
988 |
'wp_scheduled_auto_draft_delete',
|
989 |
'update_network_counts',
|
990 |
+
'delete_expired_transients',
|
991 |
);
|
992 |
|
993 |
$this->show_cron_status();
|
995 |
?>
|
996 |
<div class="wrap">
|
997 |
<h1><?php esc_html_e( 'WP-Cron Events', 'wp-crontrol' ); ?></h1>
|
998 |
+
<form method="post" action="tools.php?page=crontrol_admin_manage_page">
|
999 |
<table class="widefat striped">
|
1000 |
<thead>
|
1001 |
<tr>
|
1002 |
+
<td id="cb" class="manage-column column-cb check-column"><label class="screen-reader-text" for="cb-select-all-1"><?php esc_html_e( 'Select All', 'wp-crontrol' ); ?></label><input id="cb-select-all-1" type="checkbox"></td>
|
1003 |
<th scope="col"><?php esc_html_e( 'Hook Name', 'wp-crontrol' ); ?></th>
|
1004 |
<th scope="col"><?php esc_html_e( 'Arguments', 'wp-crontrol' ); ?></th>
|
1005 |
<th scope="col"><?php esc_html_e( 'Actions', 'wp-crontrol' ); ?></th>
|
1012 |
<?php
|
1013 |
if ( is_wp_error( $events ) ) {
|
1014 |
?>
|
1015 |
+
<tr><td colspan="7"><?php echo esc_html( $events->get_error_message() ); ?></td></tr>
|
1016 |
<?php
|
1017 |
} else {
|
1018 |
foreach ( $events as $id => $event ) {
|
1030 |
if ( empty( $event->args ) ) {
|
1031 |
$args = '<em>' . esc_html__( 'None', 'wp-crontrol' ) . '</em>';
|
1032 |
} else {
|
1033 |
+
$json_options = 0;
|
1034 |
+
|
1035 |
if ( defined( 'JSON_UNESCAPED_SLASHES' ) ) {
|
1036 |
+
$json_options |= JSON_UNESCAPED_SLASHES;
|
|
|
|
|
1037 |
}
|
1038 |
+
if ( defined( 'JSON_PRETTY_PRINT' ) ) {
|
1039 |
+
$json_options |= JSON_PRETTY_PRINT;
|
1040 |
+
}
|
1041 |
+
|
1042 |
+
$args = '<pre style="white-space:pre-wrap;margin-top:0">' . wp_json_encode( $event->args, $json_options ) . '</pre>';
|
1043 |
}
|
1044 |
|
1045 |
+
echo '<tr>';
|
1046 |
+
|
1047 |
+
echo '<th scope="row" class="check-column">';
|
1048 |
+
if ( ! in_array( $event->hook, $core_hooks, true ) ) {
|
1049 |
+
printf(
|
1050 |
+
'<input type="checkbox" name="delete[%1$s][%2$s]" value="%3$s">',
|
1051 |
+
esc_attr( $event->time ),
|
1052 |
+
esc_attr( rawurlencode( $event->hook ) ),
|
1053 |
+
esc_attr( $event->sig )
|
1054 |
+
);
|
1055 |
+
}
|
1056 |
+
echo '</th>';
|
1057 |
|
1058 |
+
if ( 'crontrol_cron_job' === $event->hook ) {
|
1059 |
if ( ! empty( $event->args['name'] ) ) {
|
1060 |
/* translators: 1: The name of the PHP cron event. */
|
1061 |
echo '<td><em>' . esc_html( sprintf( __( 'PHP Cron (%s)', 'wp-crontrol' ), $event->args['name'] ) ) . '</em></td>';
|
1070 |
echo '<td>';
|
1071 |
$callbacks = array();
|
1072 |
foreach ( $this->get_action_callbacks( $event->hook ) as $callback ) {
|
1073 |
+
$callbacks[] = '<pre style="margin-top:0">' . self::output_callback( $callback ) . '</pre>';
|
1074 |
}
|
1075 |
+
echo implode( '', $callbacks ); // WPCS:: XSS ok.
|
1076 |
echo '</td>';
|
1077 |
}
|
1078 |
|
1079 |
+
echo '<td style="white-space:nowrap">';
|
1080 |
printf( '%s (%s)',
|
1081 |
esc_html( get_date_from_gmt( date( 'Y-m-d H:i:s', $event->time ), $time_format ) ),
|
1082 |
esc_html( $this->time_since( time(), $event->time ) )
|
1083 |
);
|
1084 |
echo '</td>';
|
1085 |
|
1086 |
+
echo '<td style="white-space:nowrap">';
|
1087 |
if ( $event->schedule ) {
|
1088 |
+
echo esc_html( $this->get_schedule_name( $event->interval ) );
|
|
|
|
|
1089 |
} else {
|
|
|
1090 |
esc_html_e( 'Non-repeating', 'wp-crontrol' );
|
|
|
1091 |
}
|
1092 |
+
echo '</td>';
|
1093 |
|
1094 |
$links = array();
|
1095 |
|
1096 |
+
echo '<td style="white-space:nowrap"><span class="row-actions visible">';
|
1097 |
|
1098 |
$link = array(
|
1099 |
'page' => 'crontrol_admin_manage_page',
|
1100 |
'action' => 'edit-cron',
|
1101 |
+
'id' => rawurlencode( $event->hook ),
|
1102 |
+
'sig' => rawurlencode( $event->sig ),
|
1103 |
+
'next_run' => rawurlencode( $event->time ),
|
1104 |
);
|
1105 |
$link = add_query_arg( $link, admin_url( 'tools.php' ) ) . '#crontrol_form';
|
1106 |
$links[] = "<a href='" . esc_url( $link ) . "'>" . esc_html__( 'Edit', 'wp-crontrol' ) . '</a>';
|
1108 |
$link = array(
|
1109 |
'page' => 'crontrol_admin_manage_page',
|
1110 |
'action' => 'run-cron',
|
1111 |
+
'id' => rawurlencode( $event->hook ),
|
1112 |
+
'sig' => rawurlencode( $event->sig ),
|
1113 |
+
'next_run' => rawurlencode( $event->time ),
|
1114 |
);
|
1115 |
$link = add_query_arg( $link, admin_url( 'tools.php' ) );
|
1116 |
$link = wp_nonce_url( $link, "run-cron_{$event->hook}_{$event->sig}" );
|
1120 |
$link = array(
|
1121 |
'page' => 'crontrol_admin_manage_page',
|
1122 |
'action' => 'delete-cron',
|
1123 |
+
'id' => rawurlencode( $event->hook ),
|
1124 |
+
'sig' => rawurlencode( $event->sig ),
|
1125 |
+
'next_run' => rawurlencode( $event->time ),
|
1126 |
);
|
1127 |
$link = add_query_arg( $link, admin_url( 'tools.php' ) );
|
1128 |
$link = wp_nonce_url( $link, "delete-cron_{$event->hook}_{$event->sig}_{$event->time}" );
|
1138 |
?>
|
1139 |
</tbody>
|
1140 |
</table>
|
1141 |
+
<?php
|
1142 |
+
wp_nonce_field( 'bulk-delete-crons' );
|
1143 |
+
submit_button(
|
1144 |
+
__( 'Delete Selected Events', 'wp-crontrol' ),
|
1145 |
+
'primary large',
|
1146 |
+
'delete_crons'
|
1147 |
+
);
|
1148 |
+
?>
|
1149 |
+
</form>
|
1150 |
|
1151 |
</div>
|
1152 |
<?php
|
1153 |
if ( is_array( $doing_edit ) ) {
|
1154 |
$this->show_cron_form( 'crontrol_cron_job' == $doing_edit['hookname'], $doing_edit );
|
1155 |
} else {
|
1156 |
+
$this->show_cron_form( ( isset( $_GET['action'] ) and 'new-php-cron' === $_GET['action'] ), false );
|
1157 |
}
|
1158 |
}
|
1159 |
|
1162 |
|
1163 |
$actions = array();
|
1164 |
|
1165 |
+
if ( isset( $wp_filter[ $name ] ) ) {
|
1166 |
|
1167 |
# http://core.trac.wordpress.org/ticket/17817
|
1168 |
+
$action = $wp_filter[ $name ];
|
1169 |
|
1170 |
foreach ( $action as $priority => $callbacks ) {
|
|
|
1171 |
foreach ( $callbacks as $callback ) {
|
|
|
1172 |
$callback = self::populate_callback( $callback );
|
1173 |
|
1174 |
$actions[] = array(
|
1175 |
'priority' => $priority,
|
1176 |
'callback' => $callback,
|
1177 |
);
|
|
|
1178 |
}
|
|
|
1179 |
}
|
|
|
1180 |
}
|
1181 |
|
1182 |
return $actions;
|
|
|
1183 |
}
|
1184 |
|
1185 |
public static function populate_callback( array $callback ) {
|
1194 |
}
|
1195 |
|
1196 |
if ( is_array( $callback['function'] ) ) {
|
|
|
1197 |
if ( is_object( $callback['function'][0] ) ) {
|
1198 |
$class = get_class( $callback['function'][0] );
|
1199 |
$access = '->';
|
1203 |
}
|
1204 |
|
1205 |
$callback['name'] = $class . $access . $callback['function'][1] . '()';
|
|
|
1206 |
} elseif ( is_object( $callback['function'] ) ) {
|
|
|
1207 |
if ( is_a( $callback['function'], 'Closure' ) ) {
|
1208 |
$callback['name'] = 'Closure';
|
1209 |
} else {
|
1210 |
$class = get_class( $callback['function'] );
|
1211 |
$callback['name'] = $class . '->__invoke()';
|
1212 |
}
|
|
|
1213 |
} else {
|
|
|
1214 |
$callback['name'] = $callback['function'] . '()';
|
|
|
1215 |
}
|
1216 |
|
1217 |
return $callback;
|
1218 |
|
1219 |
}
|
1220 |
|
1221 |
+
public static function output_callback( array $callback ) {
|
1222 |
+
global $wp_filesystem;
|
1223 |
+
|
1224 |
+
$plugins = $wp_filesystem->wp_plugins_dir();
|
1225 |
+
$qm = $plugins . 'query-monitor/query-monitor.php';
|
1226 |
+
$html = plugin_dir_path( $qm ) . 'output/Html.php';
|
1227 |
+
|
1228 |
+
// If Query Monitor is installed, use its rich callback output:
|
1229 |
+
if ( class_exists( 'QueryMonitor' ) && file_exists( $html ) ) {
|
1230 |
+
require_once $html;
|
1231 |
+
|
1232 |
+
if ( class_exists( 'QM_Output_Html' ) ) {
|
1233 |
+
return QM_Output_Html::output_filename(
|
1234 |
+
$callback['callback']['name'],
|
1235 |
+
$callback['callback']['file'],
|
1236 |
+
$callback['callback']['line']
|
1237 |
+
);
|
1238 |
+
}
|
1239 |
+
}
|
1240 |
+
|
1241 |
+
return $callback['callback']['name'];
|
1242 |
+
}
|
1243 |
+
|
1244 |
/**
|
1245 |
* Pretty-prints the difference in two times.
|
1246 |
*
|
1292 |
// x days, xx hours
|
1293 |
// so there's only two bits of calculation below:
|
1294 |
|
1295 |
+
$j = count( $chunks );
|
1296 |
+
|
1297 |
// step one: the first chunk
|
1298 |
+
for ( $i = 0; $i < $j; $i++ ) {
|
1299 |
$seconds = $chunks[ $i ][0];
|
1300 |
$name = $chunks[ $i ][1];
|
1301 |
|
1302 |
// finding the biggest chunk (if the chunk fits, break)
|
1303 |
+
$count = floor( $since / $seconds );
|
1304 |
+
if ( $count ) {
|
1305 |
break;
|
1306 |
}
|
1307 |
}
|
1313 |
if ( $i + 1 < $j ) {
|
1314 |
$seconds2 = $chunks[ $i + 1 ][0];
|
1315 |
$name2 = $chunks[ $i + 1 ][1];
|
1316 |
+
$count2 = floor( ( $since - ( $seconds * $count ) ) / $seconds2 );
|
1317 |
+
if ( $count2 ) {
|
1318 |
// add to output var
|
1319 |
$output .= ' ' . sprintf( translate_nooped_plural( $name2, $count2, 'wp-crontrol' ), $count2 );
|
1320 |
}
|
1323 |
return $output;
|
1324 |
}
|
1325 |
|
1326 |
+
/**
|
1327 |
+
* Returns the schedule display name for a given interval.
|
1328 |
+
*
|
1329 |
+
* Falls back to the time interval if no corresponding schedule exists.
|
1330 |
+
*
|
1331 |
+
* @param int $interval An interval of time.
|
1332 |
+
* @return string The interval display name.
|
1333 |
+
*/
|
1334 |
+
protected function get_schedule_name( $interval ) {
|
1335 |
+
$schedules = $this->get_schedules();
|
1336 |
+
|
1337 |
+
foreach ( $schedules as $schedule ) {
|
1338 |
+
if ( $interval === $schedule['interval'] ) {
|
1339 |
+
return $schedule['display'];
|
1340 |
+
}
|
1341 |
+
}
|
1342 |
+
|
1343 |
+
return $this->interval( $interval );
|
1344 |
+
}
|
1345 |
+
|
1346 |
+
/**
|
1347 |
+
* Enqueues the editor UI that's used for the PHP cron event code editor.
|
1348 |
+
*/
|
1349 |
+
public function enqueue_code_editor() {
|
1350 |
+
if ( ! function_exists( 'wp_enqueue_code_editor' ) ) {
|
1351 |
+
return;
|
1352 |
+
}
|
1353 |
+
if ( ! current_user_can( 'edit_files' ) ) {
|
1354 |
+
return;
|
1355 |
+
}
|
1356 |
+
|
1357 |
+
$settings = wp_enqueue_code_editor( array(
|
1358 |
+
'type' => 'text/x-php',
|
1359 |
+
) );
|
1360 |
+
|
1361 |
+
if ( false === $settings ) {
|
1362 |
+
return;
|
1363 |
+
}
|
1364 |
+
|
1365 |
+
wp_add_inline_script( 'code-editor', sprintf(
|
1366 |
+
'jQuery( function( $ ) {
|
1367 |
+
if ( $( "#hookcode" ).length ) {
|
1368 |
+
wp.codeEditor.initialize( "hookcode", %s );
|
1369 |
+
}
|
1370 |
+
} );',
|
1371 |
+
wp_json_encode( $settings )
|
1372 |
+
) );
|
1373 |
+
}
|
1374 |
+
|
1375 |
+
/**
|
1376 |
+
* Filters the list of query arguments which get removed from admin area URLs in WordPress.
|
1377 |
+
*
|
1378 |
+
* @link https://core.trac.wordpress.org/ticket/23367
|
1379 |
+
*
|
1380 |
+
* @param string[] $args List of removable query arguments.
|
1381 |
+
* @return string[] Updated list of removable query arguments.
|
1382 |
+
*/
|
1383 |
+
public function filter_removable_query_args( array $args ) {
|
1384 |
+
return array_merge( $args, array(
|
1385 |
+
'crontrol_message',
|
1386 |
+
'crontrol_name',
|
1387 |
+
) );
|
1388 |
+
}
|
1389 |
+
|
1390 |
public static function init() {
|
1391 |
|
1392 |
static $instance = null;
|