Version Description
Download this release
Release Info
Developer | johnbillion |
Plugin | WP Crontrol |
Version | 1.9.0 |
Comparing to | |
See all releases |
Code changes from version 1.8.5 to 1.9.0
- SECURITY.md +5 -0
- css/wp-crontrol.css +9 -1
- js/wp-crontrol.js +23 -0
- readme.md +93 -21
- src/event-list-table.php +114 -2
- src/event.php +100 -25
- src/schedule-list-table.php +2 -2
- src/schedule.php +17 -1
- wp-crontrol.php +428 -221
SECURITY.md
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Security Policy
|
2 |
+
|
3 |
+
## Reporting a Vulnerability
|
4 |
+
|
5 |
+
If you discover a security issue in WP Crontrol, please report it to [the security program on HackerOne](https://hackerone.com/johnblackbourn). Do not report security issues on GitHub or the WordPress.org support forums. Thank you.
|
css/wp-crontrol.css
CHANGED
@@ -1,4 +1,3 @@
|
|
1 |
-
|
2 |
@keyframes crontrol-rotating {
|
3 |
from {
|
4 |
transform: rotate(0deg);
|
@@ -91,3 +90,12 @@ table.wp-list-table {
|
|
91 |
.row-actions .in-use {
|
92 |
color: #666;
|
93 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
@keyframes crontrol-rotating {
|
2 |
from {
|
3 |
transform: rotate(0deg);
|
90 |
.row-actions .in-use {
|
91 |
color: #666;
|
92 |
}
|
93 |
+
|
94 |
+
.form-field input[type="number"] {
|
95 |
+
width: 100px;
|
96 |
+
}
|
97 |
+
|
98 |
+
.crontrol-edit-event-standard .crontrol-event-php,
|
99 |
+
.crontrol-edit-event-php .crontrol-event-standard {
|
100 |
+
display: none;
|
101 |
+
}
|
js/wp-crontrol.js
CHANGED
@@ -34,3 +34,26 @@ function crontrolCheckHash() {
|
|
34 |
}
|
35 |
} );
|
36 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
}
|
35 |
} );
|
36 |
}
|
37 |
+
|
38 |
+
jQuery(function($){
|
39 |
+
$('#next_run_date_local_custom_date,#next_run_date_local_custom_time').on('change', function() {
|
40 |
+
$('#next_run_date_local_custom').prop('checked',true);
|
41 |
+
});
|
42 |
+
|
43 |
+
if ( $('input[value="new_php_cron"]').length ) {
|
44 |
+
$('input[value="new_cron"]').on('click',function(){
|
45 |
+
$('.crontrol-edit-event').removeClass('crontrol-edit-event-php').addClass('crontrol-edit-event-standard');
|
46 |
+
$('#hookname').attr('required',true);
|
47 |
+
});
|
48 |
+
$('input[value="new_php_cron"]').on('click',function(){
|
49 |
+
$('.crontrol-edit-event').removeClass('crontrol-edit-event-standard').addClass('crontrol-edit-event-php');
|
50 |
+
$('#hookname').attr('required',false);
|
51 |
+
if ( ! $('#hookcode').hasClass('crontrol-editor-initialized') ) {
|
52 |
+
wp.codeEditor.initialize( 'hookcode', window.wpCrontrol.codeEditor );
|
53 |
+
}
|
54 |
+
$('#hookcode').addClass('crontrol-editor-initialized');
|
55 |
+
});
|
56 |
+
} else if ( $('#hookcode').length ) {
|
57 |
+
wp.codeEditor.initialize( 'hookcode', window.wpCrontrol.codeEditor );
|
58 |
+
}
|
59 |
+
});
|
readme.md
CHANGED
@@ -1,44 +1,104 @@
|
|
1 |
-
# WP Crontrol
|
2 |
|
3 |
Contributors: johnbillion, scompt
|
4 |
Tags: cron, wp-cron, crontrol, debug
|
5 |
Requires at least: 4.1
|
6 |
-
Tested up to: 5.
|
7 |
-
Stable tag: 1.
|
8 |
Requires PHP: 5.3
|
|
|
9 |
|
10 |
-
WP Crontrol
|
11 |
|
12 |
-
## Description
|
13 |
|
14 |
-
WP Crontrol
|
15 |
|
16 |
* View all cron events along with their arguments, recurrence, callback functions, and when they are next due.
|
17 |
* Edit, delete, and immediately run any cron events.
|
18 |
* Add new cron events.
|
19 |
* Bulk delete cron events.
|
20 |
-
* Add
|
21 |
|
22 |
-
|
23 |
|
24 |
-
### Usage
|
25 |
|
26 |
1. Go to the `Tools → Cron Events` menu to manage cron events.
|
27 |
2. Go to the `Settings → Cron Schedules` menu to manage cron schedules.
|
28 |
|
29 |
-
|
30 |
|
31 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
|
33 |
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.
|
34 |
|
35 |
-
### How do I create a new cron event?
|
36 |
|
37 |
There are two steps to getting a functioning cron event that executes regularly. The first step is telling WordPress about the hook. This is the part that WP Crontrol was created to provide. The second step is calling a function when your hook is executed.
|
38 |
|
39 |
*Step One: Adding the hook*
|
40 |
|
41 |
-
In the Tools → Cron Events admin panel, click on
|
42 |
|
43 |
*Step Two: Writing the function*
|
44 |
|
@@ -52,15 +112,15 @@ The next step is to write your function. Here's a simple example:
|
|
52 |
wp_mail( 'hello@example.com', 'WP Crontrol', 'WP Crontrol rocks!' );
|
53 |
}
|
54 |
|
55 |
-
### How do I create a new PHP cron event?
|
56 |
|
57 |
-
In the Tools → Cron Events admin panel, click on
|
58 |
|
59 |
-
### Which users can manage cron events and schedules?
|
60 |
|
61 |
Only users with the `manage_options` capability can manage cron events and schedules. By default, only Administrators have this capability.
|
62 |
|
63 |
-
### Which users can manage PHP cron events? Is this dangerous?
|
64 |
|
65 |
Only users with the `edit_files` capability can manage PHP cron events. This means if a user cannot edit files on the site (eg. through the Plugin Editor or Theme Editor) then they cannot edit or add a PHP cron event. By default, only Administrators have this capability, and with Multisite enabled only Super Admins have this capability.
|
66 |
|
@@ -68,18 +128,30 @@ If file editing has been disabled via the `DISALLOW_FILE_MODS` or `DISALLOW_FILE
|
|
68 |
|
69 |
Therefore, the user access level required to execute arbitrary PHP code does not change with WP Crontrol activated.
|
70 |
|
71 |
-
### Are any WP-CLI commands available?
|
72 |
|
73 |
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.
|
74 |
|
75 |
-
## Screenshots
|
76 |
|
77 |
-
1.
|
78 |
|
79 |
-
2. New cron
|
|
|
|
|
80 |
|
81 |
## Changelog ##
|
82 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
83 |
### 1.8.5 ###
|
84 |
|
85 |
* Fix an issue with the tabs in 1.8.4.
|
1 |
+
# WP Crontrol
|
2 |
|
3 |
Contributors: johnbillion, scompt
|
4 |
Tags: cron, wp-cron, crontrol, debug
|
5 |
Requires at least: 4.1
|
6 |
+
Tested up to: 5.6
|
7 |
+
Stable tag: 1.9.0
|
8 |
Requires PHP: 5.3
|
9 |
+
Donate link: https://github.com/sponsors/johnbillion
|
10 |
|
11 |
+
WP Crontrol enables you to view and control what's happening in the WP-Cron system.
|
12 |
|
13 |
+
## Description
|
14 |
|
15 |
+
WP Crontrol enables you to view and control what's happening in the WP-Cron system. From the admin screens you can:
|
16 |
|
17 |
* View all cron events along with their arguments, recurrence, callback functions, and when they are next due.
|
18 |
* Edit, delete, and immediately run any cron events.
|
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 |
|
25 |
+
### Usage
|
26 |
|
27 |
1. Go to the `Tools → Cron Events` menu to manage cron events.
|
28 |
2. Go to the `Settings → Cron Schedules` menu to manage cron schedules.
|
29 |
|
30 |
+
### Other Plugins
|
31 |
|
32 |
+
I maintain several other plugins for developers. Check them out:
|
33 |
+
|
34 |
+
* [Query Monitor](https://wordpress.org/plugins/query-monitor/) is the developer tools panel for WordPress.
|
35 |
+
* [User Switching](https://wordpress.org/plugins/user-switching/) provides instant switching between user accounts in WordPress.
|
36 |
+
|
37 |
+
## Frequently Asked Questions
|
38 |
+
|
39 |
+
### Does this plugin work with PHP 8?
|
40 |
+
|
41 |
+
Yes.
|
42 |
+
|
43 |
+
### I get the error "There was a problem spawning a call to the WP-Cron system on your site". How do I fix this?
|
44 |
+
|
45 |
+
If this error is persistent then you should contact your web host for support. It usually means the HTTP connection that runs cron events on your site is failing for some reason.
|
46 |
+
|
47 |
+
### Why do some cron events miss their schedule?
|
48 |
+
|
49 |
+
[You can read all about cron events that miss their schedule here](https://github.com/johnbillion/wp-crontrol/wiki/Cron-events-that-have-missed-their-schedule).
|
50 |
+
|
51 |
+
### Why do some cron events reappear shortly after I delete them?
|
52 |
+
|
53 |
+
If the event is added by a plugin then the plugin most likely rescheduled the event as soon as it saw that the event was missing. Unfortunately there's nothing that WP Crontrol can do about this - you should contact the author of the related plugin and ask for advice.
|
54 |
+
|
55 |
+
### Is it safe to delete cron events?
|
56 |
+
|
57 |
+
This depends entirely on the event. You can use your favourite search engine to search for the event name in order to find out which plugin it belongs to, and then decide whether or not to delete it.
|
58 |
+
|
59 |
+
If the event shows "None" as its action then it's usually safe to delete. Please see the other FAQs for more information about events with no action.
|
60 |
+
|
61 |
+
### Why can't I delete some cron events?
|
62 |
+
|
63 |
+
The WordPress core software uses cron events for some of its functionality and removing these events is not possible because WordPress would immediately reschedule them if you did delete them. For this reason, WP Crontrol doesn't let you delete these persistent events from WordPress core in the first place.
|
64 |
+
|
65 |
+
### What does it mean when "None" is shown for the Action of a cron event?
|
66 |
+
|
67 |
+
This means the cron event is scheduled to run at the specified time but there is no corresponding functionality that will be triggered when the event runs, therefore the event is useless.
|
68 |
+
|
69 |
+
This is often caused by plugins that don't clean up their cron events when you deactivate them. You can use your favourite search engine to search for the event name in order to find out which plugin it belongs to, and then decide whether or not to delete it.
|
70 |
+
|
71 |
+
### How do I change the next run time or the recurrence of a cron event?
|
72 |
+
|
73 |
+
You can change the time and recurrence of a cron event by clicking the "Edit" link next to the event.
|
74 |
+
|
75 |
+
### How can I create a cron event that requests a URL?
|
76 |
+
|
77 |
+
From the "Add PHP Cron Event" tab, create a cron event that includes PHP that fetches the URL using the WordPress HTTP API. For example:
|
78 |
+
|
79 |
+
wp_remote_get( 'http://example.com' );
|
80 |
+
|
81 |
+
### Why do changes that I make to some cron events not get saved?
|
82 |
+
|
83 |
+
Unfortunately WordPress core doesn't expose all the errors that can occur in its cron event system, so a plugin such as WP Crontrol can't always tell you if or what went wrong when saving cron events.
|
84 |
+
|
85 |
+
You should try deactivating your other plugins one by one to see if one is causing a problem. Otherwise, I'm afraid I don't have much useful information for you. Hopefully a future version of WordPress will provide better error handling for its cron event system.
|
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.
|
94 |
|
95 |
+
### How do I create a new cron event?
|
96 |
|
97 |
There are two steps to getting a functioning cron event that executes regularly. The first step is telling WordPress about the hook. This is the part that WP Crontrol was created to provide. The second step is calling a function when your hook is executed.
|
98 |
|
99 |
*Step One: Adding the hook*
|
100 |
|
101 |
+
In the Tools → Cron Events admin panel, click on "Add New" and enter the details of the hook. You're best off using a hook name that conforms to normal PHP variable naming conventions. The event schedule is how often your hook will be executed. If you don't see a good interval, then add one in the Settings → Cron Schedules admin panel.
|
102 |
|
103 |
*Step Two: Writing the function*
|
104 |
|
112 |
wp_mail( 'hello@example.com', 'WP Crontrol', 'WP Crontrol rocks!' );
|
113 |
}
|
114 |
|
115 |
+
### How do I create a new PHP cron event?
|
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.
|
122 |
|
123 |
+
### Which users can manage PHP cron events? Is this dangerous?
|
124 |
|
125 |
Only users with the `edit_files` capability can manage PHP cron events. This means if a user cannot edit files on the site (eg. through the Plugin Editor or Theme Editor) then they cannot edit or add a PHP cron event. By default, only Administrators have this capability, and with Multisite enabled only Super Admins have this capability.
|
126 |
|
128 |
|
129 |
Therefore, the user access level required to execute arbitrary PHP code does not change with WP Crontrol activated.
|
130 |
|
131 |
+
### Are any WP-CLI commands available?
|
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)
|
138 |
|
139 |
+
2. New cron events can be added<br>![](.wordpress-org/screenshot-2.png)
|
140 |
+
|
141 |
+
3. New cron schedules can be added, giving plugin developers more options when scheduling events<br>![](.wordpress-org/screenshot-2.png)
|
142 |
|
143 |
## Changelog ##
|
144 |
|
145 |
+
### 1.9.0 ###
|
146 |
+
|
147 |
+
* Add filters and sorting to the event listing screen. Props @yuriipavlov.
|
148 |
+
* Replace the "Add New" tabs with a more standard "Add New" button on the cron event listing page.
|
149 |
+
* Switch back to using browser-native controls for the date and time inputs.
|
150 |
+
* Add an error message when trying to edit a non-existent event.
|
151 |
+
* Introduce an informational message which appears when there are events that have missed their schedule.
|
152 |
+
* Fire actions when cron events and schedules are added, updated, and deleted.
|
153 |
+
|
154 |
+
|
155 |
### 1.8.5 ###
|
156 |
|
157 |
* Fix an issue with the tabs in 1.8.4.
|
src/event-list-table.php
CHANGED
@@ -37,6 +37,8 @@ class Table extends \WP_List_Table {
|
|
37 |
*/
|
38 |
protected static $count_by_hook;
|
39 |
|
|
|
|
|
40 |
/**
|
41 |
* Constructor.
|
42 |
*/
|
@@ -58,6 +60,7 @@ class Table extends \WP_List_Table {
|
|
58 |
self::$count_by_hook = count_by_hook();
|
59 |
|
60 |
$events = get();
|
|
|
61 |
|
62 |
if ( ! empty( $_GET['s'] ) ) {
|
63 |
$s = sanitize_text_field( wp_unslash( $_GET['s'] ) );
|
@@ -67,12 +70,35 @@ class Table extends \WP_List_Table {
|
|
67 |
} );
|
68 |
}
|
69 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
$count = count( $events );
|
71 |
$per_page = 50;
|
72 |
$offset = ( $this->get_pagenum() - 1 ) * $per_page;
|
73 |
|
74 |
$this->items = array_slice( $events, $offset, $per_page );
|
75 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
76 |
$this->set_pagination_args( array(
|
77 |
'total_items' => $count,
|
78 |
'per_page' => $per_page,
|
@@ -80,6 +106,34 @@ class Table extends \WP_List_Table {
|
|
80 |
) );
|
81 |
}
|
82 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
83 |
/**
|
84 |
* Returns an array of column names for the table.
|
85 |
*
|
@@ -100,6 +154,18 @@ class Table extends \WP_List_Table {
|
|
100 |
);
|
101 |
}
|
102 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
103 |
/**
|
104 |
* Returns an array of CSS class names for the table.
|
105 |
*
|
@@ -123,6 +189,39 @@ class Table extends \WP_List_Table {
|
|
123 |
);
|
124 |
}
|
125 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
126 |
/**
|
127 |
* Generates content for a single row of the table.
|
128 |
*
|
@@ -141,8 +240,17 @@ class Table extends \WP_List_Table {
|
|
141 |
$classes[] = 'crontrol-error';
|
142 |
}
|
143 |
|
144 |
-
|
|
|
|
|
145 |
$classes[] = 'crontrol-warning';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
146 |
}
|
147 |
|
148 |
if ( is_late( $event ) ) {
|
@@ -422,7 +530,11 @@ class Table extends \WP_List_Table {
|
|
422 |
* Outputs a message when there are no items to show in the table.
|
423 |
*/
|
424 |
public function no_items() {
|
425 |
-
|
|
|
|
|
|
|
|
|
426 |
}
|
427 |
|
428 |
}
|
37 |
*/
|
38 |
protected static $count_by_hook;
|
39 |
|
40 |
+
protected $all_events = array();
|
41 |
+
|
42 |
/**
|
43 |
* Constructor.
|
44 |
*/
|
60 |
self::$count_by_hook = count_by_hook();
|
61 |
|
62 |
$events = get();
|
63 |
+
$this->all_events = $events;
|
64 |
|
65 |
if ( ! empty( $_GET['s'] ) ) {
|
66 |
$s = sanitize_text_field( wp_unslash( $_GET['s'] ) );
|
70 |
} );
|
71 |
}
|
72 |
|
73 |
+
if ( ! empty( $_GET['hooks_type'] ) ) {
|
74 |
+
$hooks_type = sanitize_text_field( $_GET['hooks_type'] );
|
75 |
+
$filtered = $this->get_filtered_events( $events );
|
76 |
+
|
77 |
+
if ( isset( $filtered[ $hooks_type ] ) ) {
|
78 |
+
$events = $filtered[ $hooks_type ];
|
79 |
+
}
|
80 |
+
}
|
81 |
+
|
82 |
$count = count( $events );
|
83 |
$per_page = 50;
|
84 |
$offset = ( $this->get_pagenum() - 1 ) * $per_page;
|
85 |
|
86 |
$this->items = array_slice( $events, $offset, $per_page );
|
87 |
|
88 |
+
$has_late = (bool) array_filter( array_map( __NAMESPACE__ . '\\is_late', $this->items ) );
|
89 |
+
|
90 |
+
if ( $has_late ) {
|
91 |
+
add_action( 'admin_notices', function() {
|
92 |
+
printf(
|
93 |
+
'<div id="crontrol-late-message" class="notice notice-warning"><p>%1$s</p><p><a href="%2$s">%3$s</a></p></div>',
|
94 |
+
/* translators: %s: Help page URL. */
|
95 |
+
esc_html__( 'One or more cron events have missed their schedule.', 'wp-crontrol' ),
|
96 |
+
'https://github.com/johnbillion/wp-crontrol/wiki/Cron-events-that-have-missed-their-schedule',
|
97 |
+
esc_html__( 'More information', 'wp-crontrol' )
|
98 |
+
);
|
99 |
+
} );
|
100 |
+
}
|
101 |
+
|
102 |
$this->set_pagination_args( array(
|
103 |
'total_items' => $count,
|
104 |
'per_page' => $per_page,
|
106 |
) );
|
107 |
}
|
108 |
|
109 |
+
/**
|
110 |
+
* Returns events filtered by various parameters
|
111 |
+
*
|
112 |
+
* @param array $events The list of all events.
|
113 |
+
* @return array Array of filtered events keyed by parameter.
|
114 |
+
*/
|
115 |
+
protected function get_filtered_events( array $events ) {
|
116 |
+
$all_core_hooks = \Crontrol\get_all_core_hooks();
|
117 |
+
$filtered = array(
|
118 |
+
'all' => $events,
|
119 |
+
);
|
120 |
+
|
121 |
+
$filtered['noaction'] = array_filter( $events, function( $event ) {
|
122 |
+
$hook_callbacks = \Crontrol\get_hook_callbacks( $event->hook );
|
123 |
+
return empty( $hook_callbacks );
|
124 |
+
} );
|
125 |
+
|
126 |
+
$filtered['core'] = array_filter( $events, function( $event ) use ( $all_core_hooks ) {
|
127 |
+
return ( in_array( $event->hook, $all_core_hooks, true ) );
|
128 |
+
} );
|
129 |
+
|
130 |
+
$filtered['custom'] = array_filter( $events, function( $event ) use ( $all_core_hooks ) {
|
131 |
+
return ( ! in_array( $event->hook, $all_core_hooks, true ) );
|
132 |
+
} );
|
133 |
+
|
134 |
+
return $filtered;
|
135 |
+
}
|
136 |
+
|
137 |
/**
|
138 |
* Returns an array of column names for the table.
|
139 |
*
|
154 |
);
|
155 |
}
|
156 |
|
157 |
+
/**
|
158 |
+
* Columns to make sortable.
|
159 |
+
*
|
160 |
+
* @return array
|
161 |
+
*/
|
162 |
+
public function get_sortable_columns() {
|
163 |
+
return array(
|
164 |
+
'crontrol_hook' => array( 'crontrol_hook', true ),
|
165 |
+
'crontrol_next' => array( 'crontrol_next', false ),
|
166 |
+
);
|
167 |
+
}
|
168 |
+
|
169 |
/**
|
170 |
* Returns an array of CSS class names for the table.
|
171 |
*
|
189 |
);
|
190 |
}
|
191 |
|
192 |
+
/**
|
193 |
+
* Display the list of hook types.
|
194 |
+
*
|
195 |
+
* @return string[]
|
196 |
+
*/
|
197 |
+
public function get_views() {
|
198 |
+
$filtered = $this->get_filtered_events( $this->all_events );
|
199 |
+
|
200 |
+
$views = array();
|
201 |
+
$hooks_type = ( ! empty( $_GET['hooks_type'] ) ? $_GET['hooks_type'] : 'all' );
|
202 |
+
|
203 |
+
$types = array(
|
204 |
+
'all' => __( 'All hooks', 'wp-crontrol' ),
|
205 |
+
'noaction' => __( 'Hooks with no action', 'wp-crontrol' ),
|
206 |
+
'core' => __( 'WordPress core hooks', 'wp-crontrol' ),
|
207 |
+
'custom' => __( 'Custom hooks', 'wp-crontrol' ),
|
208 |
+
);
|
209 |
+
|
210 |
+
$url = admin_url( 'tools.php?page=crontrol_admin_manage_page' );
|
211 |
+
|
212 |
+
foreach ( $types as $key => $type ) {
|
213 |
+
$views[ $key ] = sprintf(
|
214 |
+
'<a href="%1$s"%2$s>%3$s <span class="count">(%4$s)</span></a>',
|
215 |
+
'all' === $key ? $url : add_query_arg( 'hooks_type', $key, $url ),
|
216 |
+
$hooks_type === $key ? ' class="current"' : '',
|
217 |
+
$type,
|
218 |
+
count( $filtered[ $key ] )
|
219 |
+
);
|
220 |
+
}
|
221 |
+
|
222 |
+
return $views;
|
223 |
+
}
|
224 |
+
|
225 |
/**
|
226 |
* Generates content for a single row of the table.
|
227 |
*
|
240 |
$classes[] = 'crontrol-error';
|
241 |
}
|
242 |
|
243 |
+
$callbacks = \Crontrol\get_hook_callbacks( $event->hook );
|
244 |
+
|
245 |
+
if ( ! $callbacks ) {
|
246 |
$classes[] = 'crontrol-warning';
|
247 |
+
} else {
|
248 |
+
foreach ( $callbacks as $callback ) {
|
249 |
+
if ( ! empty( $callback['callback']['error'] ) ) {
|
250 |
+
$classes[] = 'crontrol-error';
|
251 |
+
break;
|
252 |
+
}
|
253 |
+
}
|
254 |
}
|
255 |
|
256 |
if ( is_late( $event ) ) {
|
530 |
* Outputs a message when there are no items to show in the table.
|
531 |
*/
|
532 |
public function no_items() {
|
533 |
+
if ( empty( $_GET['s'] ) && empty( $_GET['hooks_type'] ) ) {
|
534 |
+
esc_html_e( 'There are currently no scheduled cron events.', 'wp-crontrol' );
|
535 |
+
} else {
|
536 |
+
esc_html_e( 'No matching cron events.', 'wp-crontrol' );
|
537 |
+
}
|
538 |
}
|
539 |
|
540 |
}
|
src/event.php
CHANGED
@@ -24,9 +24,15 @@ function run( $hookname, $sig ) {
|
|
24 |
$crons = _get_cron_array();
|
25 |
foreach ( $crons as $time => $cron ) {
|
26 |
if ( isset( $cron[ $hookname ][ $sig ] ) ) {
|
27 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
delete_transient( 'doing_cron' );
|
29 |
-
$scheduled = force_schedule_single_event( $hookname, $args ); // UTC
|
30 |
|
31 |
if ( false === $scheduled ) {
|
32 |
return $scheduled;
|
@@ -41,6 +47,21 @@ function run( $hookname, $sig ) {
|
|
41 |
|
42 |
sleep( 1 );
|
43 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
return true;
|
45 |
}
|
46 |
}
|
@@ -80,11 +101,11 @@ function force_schedule_single_event( $hook, $args = array() ) {
|
|
80 |
*
|
81 |
* @param string $next_run_local The time that the event should be run at, in the site's timezone.
|
82 |
* @param string $schedule The recurrence of the cron event.
|
83 |
-
* @param string $
|
84 |
* @param array $args Arguments to add to the cron event.
|
85 |
* @return bool Whether the addition was successful.
|
86 |
*/
|
87 |
-
function add( $next_run_local, $schedule, $
|
88 |
$next_run_local = strtotime( $next_run_local, current_time( 'timestamp' ) );
|
89 |
|
90 |
if ( false === $next_run_local ) {
|
@@ -97,7 +118,7 @@ function add( $next_run_local, $schedule, $hookname, array $args ) {
|
|
97 |
$args = array();
|
98 |
}
|
99 |
|
100 |
-
if ( 'crontrol_cron_job' === $
|
101 |
try {
|
102 |
// phpcs:ignore Squiz.PHP.Eval.Discouraged
|
103 |
eval( sprintf(
|
@@ -112,33 +133,34 @@ function add( $next_run_local, $schedule, $hookname, array $args ) {
|
|
112 |
}
|
113 |
|
114 |
if ( '_oneoff' === $schedule ) {
|
115 |
-
return ( false !== wp_schedule_single_event( $next_run_utc, $
|
116 |
} else {
|
117 |
-
return ( false !== wp_schedule_event( $next_run_utc, $schedule, $
|
118 |
}
|
119 |
}
|
120 |
|
121 |
/**
|
122 |
* Deletes a cron event.
|
123 |
*
|
124 |
-
* @param string $
|
125 |
* @param string $sig The cron event signature.
|
126 |
* @param string $next_run_utc The UTC time that the event would be run at.
|
127 |
* @return bool Whether the deletion was successful.
|
128 |
*/
|
129 |
-
function delete( $
|
130 |
-
$
|
131 |
-
if ( isset( $crons[ $next_run_utc ][ $to_delete ][ $sig ] ) ) {
|
132 |
-
$args = $crons[ $next_run_utc ][ $to_delete ][ $sig ]['args'];
|
133 |
-
$unscheduled = wp_unschedule_event( $next_run_utc, $to_delete, $args );
|
134 |
|
135 |
-
|
136 |
-
|
137 |
-
|
|
|
|
|
138 |
|
139 |
-
|
|
|
140 |
}
|
141 |
-
|
|
|
142 |
}
|
143 |
|
144 |
/**
|
@@ -174,17 +196,34 @@ function get() {
|
|
174 |
|
175 |
// Ensure events are always returned in date descending order.
|
176 |
// External cron runners such as Cavalcade don't guarantee events are returned in order of time.
|
177 |
-
uasort( $events,
|
178 |
-
if ( $a->time === $b->time ) {
|
179 |
-
return 0;
|
180 |
-
} else {
|
181 |
-
return ( $a->time > $b->time ) ? 1 : -1;
|
182 |
-
}
|
183 |
-
} );
|
184 |
|
185 |
return $events;
|
186 |
}
|
187 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
188 |
/**
|
189 |
* Returns an array of the number of events for each hook.
|
190 |
*
|
@@ -263,3 +302,39 @@ function get_list_table() {
|
|
263 |
|
264 |
return $table;
|
265 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
24 |
$crons = _get_cron_array();
|
25 |
foreach ( $crons as $time => $cron ) {
|
26 |
if ( isset( $cron[ $hookname ][ $sig ] ) ) {
|
27 |
+
$event = $cron[ $hookname ][ $sig ];
|
28 |
+
|
29 |
+
$event['hook'] = $hookname;
|
30 |
+
$event['timestamp'] = $time;
|
31 |
+
|
32 |
+
$event = (object) $event;
|
33 |
+
|
34 |
delete_transient( 'doing_cron' );
|
35 |
+
$scheduled = force_schedule_single_event( $hookname, $event->args ); // UTC
|
36 |
|
37 |
if ( false === $scheduled ) {
|
38 |
return $scheduled;
|
47 |
|
48 |
sleep( 1 );
|
49 |
|
50 |
+
/**
|
51 |
+
* Fires after a cron event is ran manually.
|
52 |
+
*
|
53 |
+
* @param object $event {
|
54 |
+
* An object containing the event's data.
|
55 |
+
*
|
56 |
+
* @type string $hook Action hook to execute when the event is run.
|
57 |
+
* @type int $timestamp Unix timestamp (UTC) for when to next run the event.
|
58 |
+
* @type string|false $schedule How often the event should subsequently recur.
|
59 |
+
* @type array $args Array containing each separate argument to pass to the hook's callback function.
|
60 |
+
* @type int $interval The interval time in seconds for the schedule. Only present for recurring events.
|
61 |
+
* }
|
62 |
+
*/
|
63 |
+
do_action( 'crontrol/ran_event', $event );
|
64 |
+
|
65 |
return true;
|
66 |
}
|
67 |
}
|
101 |
*
|
102 |
* @param string $next_run_local The time that the event should be run at, in the site's timezone.
|
103 |
* @param string $schedule The recurrence of the cron event.
|
104 |
+
* @param string $hook The name of the hook to execute.
|
105 |
* @param array $args Arguments to add to the cron event.
|
106 |
* @return bool Whether the addition was successful.
|
107 |
*/
|
108 |
+
function add( $next_run_local, $schedule, $hook, array $args ) {
|
109 |
$next_run_local = strtotime( $next_run_local, current_time( 'timestamp' ) );
|
110 |
|
111 |
if ( false === $next_run_local ) {
|
118 |
$args = array();
|
119 |
}
|
120 |
|
121 |
+
if ( 'crontrol_cron_job' === $hook && ! empty( $args['code'] ) && class_exists( '\ParseError' ) ) {
|
122 |
try {
|
123 |
// phpcs:ignore Squiz.PHP.Eval.Discouraged
|
124 |
eval( sprintf(
|
133 |
}
|
134 |
|
135 |
if ( '_oneoff' === $schedule ) {
|
136 |
+
return ( false !== wp_schedule_single_event( $next_run_utc, $hook, $args ) );
|
137 |
} else {
|
138 |
+
return ( false !== wp_schedule_event( $next_run_utc, $schedule, $hook, $args ) );
|
139 |
}
|
140 |
}
|
141 |
|
142 |
/**
|
143 |
* Deletes a cron event.
|
144 |
*
|
145 |
+
* @param string $hook The hook name of the event to delete.
|
146 |
* @param string $sig The cron event signature.
|
147 |
* @param string $next_run_utc The UTC time that the event would be run at.
|
148 |
* @return bool Whether the deletion was successful.
|
149 |
*/
|
150 |
+
function delete( $hook, $sig, $next_run_utc ) {
|
151 |
+
$event = get_single( $hook, $sig, $next_run_utc );
|
|
|
|
|
|
|
152 |
|
153 |
+
if ( ! $event ) {
|
154 |
+
return false;
|
155 |
+
}
|
156 |
+
|
157 |
+
$unscheduled = wp_unschedule_event( $event->timestamp, $event->hook, $event->args );
|
158 |
|
159 |
+
if ( false === $unscheduled ) {
|
160 |
+
return $unscheduled;
|
161 |
}
|
162 |
+
|
163 |
+
return true;
|
164 |
}
|
165 |
|
166 |
/**
|
196 |
|
197 |
// Ensure events are always returned in date descending order.
|
198 |
// External cron runners such as Cavalcade don't guarantee events are returned in order of time.
|
199 |
+
uasort( $events, 'Crontrol\Event\uasort_order_events' );
|
|
|
|
|
|
|
|
|
|
|
|
|
200 |
|
201 |
return $events;
|
202 |
}
|
203 |
|
204 |
+
/**
|
205 |
+
* Gets a single cron event.
|
206 |
+
*
|
207 |
+
* @param string $hook The hook name of the event.
|
208 |
+
* @param string $sig The event signature.
|
209 |
+
* @param string $next_run_utc The UTC time that the event would be run at.
|
210 |
+
*/
|
211 |
+
function get_single( $hook, $sig, $next_run_utc ) {
|
212 |
+
$crons = _get_cron_array();
|
213 |
+
if ( isset( $crons[ $next_run_utc ][ $hook ][ $sig ] ) ) {
|
214 |
+
$event = $crons[ $next_run_utc ][ $hook ][ $sig ];
|
215 |
+
|
216 |
+
$event['hook'] = $hook;
|
217 |
+
$event['timestamp'] = $next_run_utc;
|
218 |
+
|
219 |
+
$event = (object) $event;
|
220 |
+
|
221 |
+
return $event;
|
222 |
+
}
|
223 |
+
|
224 |
+
return null;
|
225 |
+
}
|
226 |
+
|
227 |
/**
|
228 |
* Returns an array of the number of events for each hook.
|
229 |
*
|
302 |
|
303 |
return $table;
|
304 |
}
|
305 |
+
|
306 |
+
/**
|
307 |
+
* Order events function.
|
308 |
+
*
|
309 |
+
* The comparison function returns an integer less than, equal to, or greater than zero if the first argument is
|
310 |
+
* considered to be respectively less than, equal to, or greater than the second.
|
311 |
+
*
|
312 |
+
* @param object $a The first event to compare.
|
313 |
+
* @param object $b The second event to compare.
|
314 |
+
* @return int
|
315 |
+
*/
|
316 |
+
function uasort_order_events( $a, $b ) {
|
317 |
+
$orderby = ( ! empty( $_GET['orderby'] ) ) ? sanitize_text_field( $_GET['orderby'] ) : 'crontrol_next';
|
318 |
+
$order = ( ! empty( $_GET['order'] ) ) ? sanitize_text_field( $_GET['order'] ) : 'desc';
|
319 |
+
|
320 |
+
switch ( $orderby ) {
|
321 |
+
case 'crontrol_hook':
|
322 |
+
if ( 'desc' === $order ) {
|
323 |
+
return strcmp( $a->hook, $b->hook );
|
324 |
+
} else {
|
325 |
+
return strcmp( $b->hook, $a->hook );
|
326 |
+
}
|
327 |
+
break;
|
328 |
+
default:
|
329 |
+
if ( $a->time === $b->time ) {
|
330 |
+
return 0;
|
331 |
+
} else {
|
332 |
+
if ( 'desc' === $order ) {
|
333 |
+
return ( $a->time > $b->time ) ? 1 : -1;
|
334 |
+
} else {
|
335 |
+
return ( $a->time < $b->time ) ? 1 : -1;
|
336 |
+
}
|
337 |
+
}
|
338 |
+
break;
|
339 |
+
}
|
340 |
+
}
|
src/schedule-list-table.php
CHANGED
@@ -66,7 +66,7 @@ class Schedule_List_Table extends \WP_List_Table {
|
|
66 |
*/
|
67 |
public function get_columns() {
|
68 |
return array(
|
69 |
-
'crontrol_name' => __( 'Name', 'wp-crontrol' ),
|
70 |
'crontrol_interval' => __( 'Interval', 'wp-crontrol' ),
|
71 |
'crontrol_display' => __( 'Display Name', 'wp-crontrol' ),
|
72 |
);
|
@@ -78,7 +78,7 @@ class Schedule_List_Table extends \WP_List_Table {
|
|
78 |
* @return string[] Array of class names.
|
79 |
*/
|
80 |
protected function get_table_classes() {
|
81 |
-
return array( 'widefat', 'striped', $this->_args['plural'] );
|
82 |
}
|
83 |
|
84 |
/**
|
66 |
*/
|
67 |
public function get_columns() {
|
68 |
return array(
|
69 |
+
'crontrol_name' => __( 'Internal Name', 'wp-crontrol' ),
|
70 |
'crontrol_interval' => __( 'Interval', 'wp-crontrol' ),
|
71 |
'crontrol_display' => __( 'Display Name', 'wp-crontrol' ),
|
72 |
);
|
78 |
* @return string[] Array of class names.
|
79 |
*/
|
80 |
protected function get_table_classes() {
|
81 |
+
return array( 'widefat', 'fixed', 'striped', 'table-view-list', $this->_args['plural'] );
|
82 |
}
|
83 |
|
84 |
/**
|
src/schedule.php
CHANGED
@@ -22,17 +22,33 @@ function add( $name, $interval, $display ) {
|
|
22 |
'display' => $display,
|
23 |
);
|
24 |
update_option( 'crontrol_schedules', $old_scheds );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
}
|
26 |
|
27 |
/**
|
28 |
* Deletes a custom cron schedule.
|
29 |
*
|
30 |
-
* @param string $name The
|
31 |
*/
|
32 |
function delete( $name ) {
|
33 |
$scheds = get_option( 'crontrol_schedules', array() );
|
34 |
unset( $scheds[ $name ] );
|
35 |
update_option( 'crontrol_schedules', $scheds );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
}
|
37 |
|
38 |
/**
|
22 |
'display' => $display,
|
23 |
);
|
24 |
update_option( 'crontrol_schedules', $old_scheds );
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Fires after a new cron schedule is added.
|
28 |
+
*
|
29 |
+
* @param string $name The internal name of the schedule.
|
30 |
+
* @param int $interval The interval between executions of the new schedule.
|
31 |
+
* @param string $display The display name of the schedule.
|
32 |
+
*/
|
33 |
+
do_action( 'crontrol/added_new_schedule', $name, $interval, $display );
|
34 |
}
|
35 |
|
36 |
/**
|
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() );
|
43 |
unset( $scheds[ $name ] );
|
44 |
update_option( 'crontrol_schedules', $scheds );
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Fires after a cron schedule is deleted.
|
48 |
+
*
|
49 |
+
* @param string $name The internal name of the schedule.
|
50 |
+
*/
|
51 |
+
do_action( 'crontrol/deleted_schedule', $name );
|
52 |
}
|
53 |
|
54 |
/**
|
wp-crontrol.php
CHANGED
@@ -2,10 +2,10 @@
|
|
2 |
/**
|
3 |
* Plugin Name: WP Crontrol
|
4 |
* Plugin URI: https://wordpress.org/plugins/wp-crontrol/
|
5 |
-
* Description: WP Crontrol
|
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
|
@@ -55,6 +55,7 @@ function init_hooks() {
|
|
55 |
add_filter( 'removable_query_args', __NAMESPACE__ . '\filter_removable_query_args' );
|
56 |
add_filter( 'in_admin_header', __NAMESPACE__ . '\do_tabs' );
|
57 |
add_filter( 'pre_unschedule_event', __NAMESPACE__ . '\maybe_clear_doing_cron' );
|
|
|
58 |
|
59 |
add_action( 'load-tools_page_crontrol_admin_manage_page', __NAMESPACE__ . '\setup_manage_page' );
|
60 |
|
@@ -64,6 +65,27 @@ function init_hooks() {
|
|
64 |
add_action( 'crontrol/tab-header', __NAMESPACE__ . '\show_cron_status', 20 );
|
65 |
}
|
66 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
/**
|
68 |
* Run using the 'init' action.
|
69 |
*/
|
@@ -75,7 +97,7 @@ function action_init() {
|
|
75 |
* Handles any POSTs made by the plugin. Run using the 'init' action.
|
76 |
*/
|
77 |
function action_handle_posts() {
|
78 |
-
if ( isset( $_POST['new_cron'] ) ) {
|
79 |
if ( ! current_user_can( 'manage_options' ) ) {
|
80 |
wp_die( esc_html__( 'You are not allowed to add new cron events.', 'wp-crontrol' ), 401 );
|
81 |
}
|
@@ -90,7 +112,30 @@ function action_handle_posts() {
|
|
90 |
$in_args = array();
|
91 |
}
|
92 |
|
93 |
-
$next_run_local = ( 'custom' === $in_next_run_date_local ) ? $
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
94 |
|
95 |
$added = Event\add( $next_run_local, $in_schedule, $in_hookname, $in_args );
|
96 |
|
@@ -107,18 +152,41 @@ function action_handle_posts() {
|
|
107 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
108 |
exit;
|
109 |
|
110 |
-
} elseif ( isset( $_POST['new_php_cron'] ) ) {
|
111 |
if ( ! current_user_can( 'edit_files' ) ) {
|
112 |
wp_die( esc_html__( 'You are not allowed to add new PHP cron events.', 'wp-crontrol' ), 401 );
|
113 |
}
|
114 |
check_admin_referer( 'new-cron' );
|
115 |
extract( wp_unslash( $_POST ), EXTR_PREFIX_ALL, 'in' );
|
116 |
-
$next_run_local = ( 'custom' === $in_next_run_date_local ) ? $
|
117 |
$args = array(
|
118 |
'code' => $in_hookcode,
|
119 |
'name' => $in_eventname,
|
120 |
);
|
121 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
122 |
$added = Event\add( $next_run_local, $in_schedule, 'crontrol_cron_job', $args );
|
123 |
|
124 |
$hookname = ( ! empty( $in_eventname ) ) ? $in_eventname : __( 'PHP Cron', 'wp-crontrol' );
|
@@ -135,7 +203,7 @@ function action_handle_posts() {
|
|
135 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
136 |
exit;
|
137 |
|
138 |
-
} elseif ( isset( $_POST['edit_cron'] ) ) {
|
139 |
if ( ! current_user_can( 'manage_options' ) ) {
|
140 |
wp_die( esc_html__( 'You are not allowed to edit cron events.', 'wp-crontrol' ), 401 );
|
141 |
}
|
@@ -153,9 +221,42 @@ function action_handle_posts() {
|
|
153 |
$in_args = array();
|
154 |
}
|
155 |
|
|
|
156 |
Event\delete( $in_original_hookname, $in_original_sig, $in_original_next_run_utc );
|
157 |
|
158 |
-
$next_run_local = ( 'custom' === $in_next_run_date_local ) ? $
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
159 |
|
160 |
$added = Event\add( $next_run_local, $in_schedule, $in_hookname, $in_args );
|
161 |
|
@@ -172,7 +273,7 @@ function action_handle_posts() {
|
|
172 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
173 |
exit;
|
174 |
|
175 |
-
} elseif ( isset( $_POST['edit_php_cron'] ) ) {
|
176 |
if ( ! current_user_can( 'edit_files' ) ) {
|
177 |
wp_die( esc_html__( 'You are not allowed to edit PHP cron events.', 'wp-crontrol' ), 401 );
|
178 |
}
|
@@ -184,9 +285,42 @@ function action_handle_posts() {
|
|
184 |
'name' => $in_eventname,
|
185 |
);
|
186 |
|
|
|
187 |
Event\delete( $in_original_hookname, $in_original_sig, $in_original_next_run_utc );
|
188 |
|
189 |
-
$next_run_local = ( 'custom' === $in_next_run_date_local ) ? $
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
190 |
|
191 |
$added = Event\add( $next_run_local, $in_schedule, 'crontrol_cron_job', $args );
|
192 |
|
@@ -251,13 +385,13 @@ function action_handle_posts() {
|
|
251 |
if ( ! current_user_can( 'manage_options' ) ) {
|
252 |
wp_die( esc_html__( 'You are not allowed to delete cron schedules.', 'wp-crontrol' ), 401 );
|
253 |
}
|
254 |
-
$
|
255 |
-
check_admin_referer( "delete-sched_{$
|
256 |
-
Schedule\delete( $
|
257 |
$redirect = array(
|
258 |
'page' => 'crontrol_admin_options_page',
|
259 |
'crontrol_message' => '2',
|
260 |
-
'crontrol_name' => rawurlencode( $
|
261 |
);
|
262 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'options-general.php' ) ) );
|
263 |
exit;
|
@@ -276,12 +410,18 @@ function action_handle_posts() {
|
|
276 |
$deleted = 0;
|
277 |
|
278 |
foreach ( $delete as $next_run_utc => $events ) {
|
279 |
-
foreach ( $events as $
|
280 |
-
if ( 'crontrol_cron_job' === $
|
281 |
continue;
|
282 |
}
|
283 |
-
|
|
|
|
|
|
|
284 |
$deleted++;
|
|
|
|
|
|
|
285 |
}
|
286 |
}
|
287 |
}
|
@@ -298,63 +438,82 @@ function action_handle_posts() {
|
|
298 |
if ( ! current_user_can( 'manage_options' ) ) {
|
299 |
wp_die( esc_html__( 'You are not allowed to delete cron events.', 'wp-crontrol' ), 401 );
|
300 |
}
|
301 |
-
$
|
302 |
$sig = wp_unslash( $_GET['sig'] );
|
303 |
$next_run_utc = intval( $_GET['next_run_utc'] );
|
304 |
-
check_admin_referer( "delete-cron_{$
|
305 |
|
306 |
-
if ( 'crontrol_cron_job' === $
|
307 |
wp_die( esc_html__( 'You are not allowed to delete PHP cron events.', 'wp-crontrol' ), 401 );
|
308 |
}
|
309 |
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
)
|
316 |
-
|
317 |
-
|
|
|
|
|
318 |
} else {
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
326 |
|
327 |
-
|
|
|
328 |
|
329 |
} elseif ( isset( $_GET['action'] ) && 'delete-hook' === $_GET['action'] ) {
|
330 |
if ( ! current_user_can( 'manage_options' ) ) {
|
331 |
wp_die( esc_html__( 'You are not allowed to delete cron events.', 'wp-crontrol' ), 401 );
|
332 |
}
|
333 |
-
$
|
334 |
$deleted = false;
|
335 |
-
check_admin_referer( "delete-hook_{$
|
336 |
|
337 |
-
if ( 'crontrol_cron_job' === $
|
338 |
wp_die( esc_html__( 'You are not allowed to delete PHP cron events.', 'wp-crontrol' ), 401 );
|
339 |
}
|
340 |
|
341 |
if ( function_exists( 'wp_unschedule_hook' ) ) {
|
342 |
-
$deleted = wp_unschedule_hook( $
|
343 |
}
|
344 |
|
345 |
if ( 0 === $deleted ) {
|
346 |
$redirect = array(
|
347 |
'page' => 'crontrol_admin_manage_page',
|
348 |
'crontrol_message' => '3',
|
349 |
-
'crontrol_name' => rawurlencode( $
|
350 |
);
|
351 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
352 |
exit;
|
353 |
} elseif ( $deleted ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
354 |
$redirect = array(
|
355 |
'page' => 'crontrol_admin_manage_page',
|
356 |
'crontrol_message' => '2',
|
357 |
-
'crontrol_name' => rawurlencode( $
|
358 |
);
|
359 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
360 |
exit;
|
@@ -362,7 +521,7 @@ function action_handle_posts() {
|
|
362 |
$redirect = array(
|
363 |
'page' => 'crontrol_admin_manage_page',
|
364 |
'crontrol_message' => '7',
|
365 |
-
'crontrol_name' => rawurlencode( $
|
366 |
);
|
367 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
368 |
exit;
|
@@ -371,26 +530,24 @@ function action_handle_posts() {
|
|
371 |
if ( ! current_user_can( 'manage_options' ) ) {
|
372 |
wp_die( esc_html__( 'You are not allowed to run cron events.', 'wp-crontrol' ), 401 );
|
373 |
}
|
374 |
-
$
|
375 |
$sig = wp_unslash( $_GET['sig'] );
|
376 |
-
check_admin_referer( "run-cron_{$
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
'crontrol_message' => '8',
|
389 |
-
'crontrol_name' => rawurlencode( $id ),
|
390 |
-
);
|
391 |
-
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
392 |
-
exit;
|
393 |
}
|
|
|
|
|
|
|
394 |
}
|
395 |
}
|
396 |
|
@@ -491,32 +648,44 @@ function admin_options_page() {
|
|
491 |
|
492 |
<?php $table->views(); ?>
|
493 |
|
494 |
-
<div class="
|
495 |
-
|
496 |
-
|
497 |
-
|
498 |
-
|
499 |
-
|
500 |
-
|
501 |
-
|
502 |
-
|
503 |
-
|
504 |
-
|
505 |
-
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
|
514 |
-
|
515 |
-
|
516 |
-
|
517 |
-
|
518 |
-
|
519 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
520 |
</div>
|
521 |
<?php
|
522 |
}
|
@@ -670,25 +839,17 @@ function show_cron_status( $tab ) {
|
|
670 |
}
|
671 |
|
672 |
if ( 'UTC' !== date_default_timezone_get() ) {
|
673 |
-
$string = sprintf(
|
674 |
-
/* translators: %s: Help page URL. */
|
675 |
-
__( 'PHP default timezone is not set to UTC. This may cause issues with cron event timings. <a href="%s">More information</a>.', 'wp-crontrol' ),
|
676 |
-
'https://github.com/johnbillion/wp-crontrol/wiki/PHP-default-timezone-is-not-set-to-UTC'
|
677 |
-
);
|
678 |
?>
|
679 |
<div id="crontrol-timezone-warning" class="notice notice-warning">
|
680 |
-
|
681 |
-
|
682 |
-
|
683 |
-
|
684 |
-
|
685 |
-
|
686 |
-
|
687 |
-
),
|
688 |
-
)
|
689 |
);
|
690 |
-
|
691 |
-
</p>
|
692 |
</div>
|
693 |
<?php
|
694 |
}
|
@@ -705,15 +866,18 @@ function show_cron_status( $tab ) {
|
|
705 |
} else {
|
706 |
?>
|
707 |
<div id="cron-status-error" class="error">
|
708 |
-
|
709 |
-
|
710 |
-
|
|
|
711 |
/* translators: 1: Error message text. */
|
712 |
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' ),
|
713 |
-
'
|
714 |
-
)
|
715 |
-
|
716 |
-
|
|
|
|
|
717 |
</div>
|
718 |
<?php
|
719 |
}
|
@@ -778,36 +942,47 @@ function get_utc_offset() {
|
|
778 |
* Shows the form used to add/edit cron events.
|
779 |
*
|
780 |
* @param bool $editing Whether the form is for the event editor.
|
781 |
-
* @param bool $is_php Whether the form is for a PHP event.
|
782 |
* @return void
|
783 |
*/
|
784 |
-
function show_cron_form( $editing
|
785 |
$display_args = '';
|
786 |
$edit_id = null;
|
787 |
$existing = false;
|
788 |
|
789 |
-
if ( ! empty( $_GET['id'] ) ) {
|
790 |
$edit_id = wp_unslash( $_GET['id'] );
|
791 |
-
}
|
792 |
|
793 |
-
|
794 |
-
|
795 |
-
|
796 |
-
|
797 |
-
|
798 |
-
|
799 |
-
|
800 |
-
|
801 |
-
|
802 |
-
|
|
|
803 |
}
|
804 |
-
}
|
805 |
|
806 |
-
|
807 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
808 |
}
|
809 |
|
810 |
-
|
|
|
|
|
811 |
$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' );
|
812 |
} else {
|
813 |
$helper_text = sprintf(
|
@@ -831,9 +1006,11 @@ function show_cron_form( $editing, $is_php = null ) {
|
|
831 |
if ( ! empty( $existing['args'] ) ) {
|
832 |
$display_args = wp_json_encode( $existing['args'] );
|
833 |
}
|
834 |
-
$action = $
|
835 |
$button = __( 'Update Event', 'wp-crontrol' );
|
836 |
-
$
|
|
|
|
|
837 |
} else {
|
838 |
$other_fields = wp_nonce_field( 'new-cron', '_wpnonce', true, false );
|
839 |
$existing = array(
|
@@ -843,12 +1020,12 @@ function show_cron_form( $editing, $is_php = null ) {
|
|
843 |
'schedule' => false,
|
844 |
);
|
845 |
|
846 |
-
$action = $is_php ? 'new_php_cron' : 'new_cron';
|
847 |
$button = __( 'Add Event', 'wp-crontrol' );
|
848 |
$next_run_date_local = '';
|
|
|
849 |
}
|
850 |
|
851 |
-
if ( $
|
852 |
if ( ! isset( $existing['args']['code'] ) ) {
|
853 |
$existing['args']['code'] = '';
|
854 |
}
|
@@ -857,23 +1034,16 @@ function show_cron_form( $editing, $is_php = null ) {
|
|
857 |
}
|
858 |
}
|
859 |
|
860 |
-
$
|
|
|
861 |
?>
|
862 |
<div id="crontrol_form" class="wrap narrow">
|
863 |
<?php
|
864 |
if ( $allowed ) {
|
865 |
if ( $editing ) {
|
866 |
-
|
867 |
-
$heading = __( 'Edit PHP Cron Event', 'wp-crontrol' );
|
868 |
-
} else {
|
869 |
-
$heading = __( 'Edit Cron Event', 'wp-crontrol' );
|
870 |
-
}
|
871 |
} else {
|
872 |
-
|
873 |
-
$heading = __( 'Add PHP Cron Event', 'wp-crontrol' );
|
874 |
-
} else {
|
875 |
-
$heading = __( 'Add Cron Event', 'wp-crontrol' );
|
876 |
-
}
|
877 |
}
|
878 |
|
879 |
printf(
|
@@ -886,15 +1056,40 @@ function show_cron_form( $editing, $is_php = null ) {
|
|
886 |
$helper_text
|
887 |
);
|
888 |
?>
|
889 |
-
<form method="post" action="<?php echo esc_url( admin_url( 'tools.php?page=crontrol_admin_manage_page' ) ); ?>">
|
890 |
<?php
|
891 |
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
892 |
echo $other_fields;
|
893 |
?>
|
894 |
<table class="form-table"><tbody>
|
895 |
-
<?php
|
896 |
-
|
897 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
898 |
<td>
|
899 |
<p class="description">
|
900 |
<?php
|
@@ -905,24 +1100,42 @@ function show_cron_form( $editing, $is_php = null ) {
|
|
905 |
);
|
906 |
?>
|
907 |
</p>
|
908 |
-
<p><textarea class="large-text code" rows="10" cols="50" id="hookcode" name="hookcode"><?php echo esc_textarea( $existing['args']['code'] ); ?></textarea></p>
|
909 |
</td>
|
910 |
</tr>
|
911 |
-
<tr>
|
912 |
-
<th valign="top" scope="row"
|
913 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
914 |
</tr>
|
915 |
-
|
916 |
-
|
917 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
918 |
<td>
|
919 |
<input type="text" autocorrect="off" autocapitalize="off" spellcheck="false" class="regular-text" id="hookname" name="hookname" value="<?php echo esc_attr( $existing['hookname'] ); ?>" required />
|
920 |
</td>
|
921 |
</tr>
|
922 |
-
<tr>
|
923 |
-
<th valign="top" scope="row"
|
|
|
|
|
|
|
|
|
924 |
<td>
|
925 |
-
<input type="text" autocorrect="off" autocapitalize="off" spellcheck="false" class="regular-text" id="args" name="args" value="<?php echo esc_attr( $display_args ); ?>"/>
|
926 |
<p class="description">
|
927 |
<?php
|
928 |
printf(
|
@@ -936,9 +1149,15 @@ function show_cron_form( $editing, $is_php = null ) {
|
|
936 |
</p>
|
937 |
</td>
|
938 |
</tr>
|
939 |
-
|
|
|
|
|
940 |
<tr>
|
941 |
-
<th valign="top" scope="row"
|
|
|
|
|
|
|
|
|
942 |
<td>
|
943 |
<ul>
|
944 |
<li>
|
@@ -961,8 +1180,11 @@ function show_cron_form( $editing, $is_php = null ) {
|
|
961 |
/* translators: %s: An input field for specifying a date and time */
|
962 |
esc_html__( 'At: %s', 'wp-crontrol' ),
|
963 |
sprintf(
|
964 |
-
'<br
|
965 |
-
|
|
|
|
|
|
|
966 |
)
|
967 |
);
|
968 |
?>
|
@@ -979,25 +1201,22 @@ function show_cron_form( $editing, $is_php = null ) {
|
|
979 |
);
|
980 |
?>
|
981 |
</p>
|
982 |
-
<p class="description">
|
983 |
-
<?php
|
984 |
-
printf(
|
985 |
-
/* translators: 1: Date/time format for an input field, 2: PHP function name. */
|
986 |
-
esc_html__( 'Format: %1$s or anything accepted by %2$s', 'wp-crontrol' ),
|
987 |
-
'<code>YYYY-MM-DD HH:MM:SS</code>',
|
988 |
-
'<a href="https://www.php.net/manual/function.strtotime.php"><code>strtotime()</code></a>'
|
989 |
-
);
|
990 |
-
?>
|
991 |
-
</p>
|
992 |
</td>
|
993 |
-
</tr
|
994 |
-
|
|
|
|
|
|
|
|
|
|
|
995 |
<td>
|
996 |
<?php Schedule\dropdown( $existing['schedule'] ); ?>
|
997 |
</td>
|
998 |
</tr>
|
999 |
</tbody></table>
|
1000 |
-
<p class="submit"
|
|
|
|
|
1001 |
</form>
|
1002 |
<?php } else { ?>
|
1003 |
<div class="error inline">
|
@@ -1098,7 +1317,11 @@ function admin_manage_page() {
|
|
1098 |
case $tabs['events']:
|
1099 |
?>
|
1100 |
<div class="wrap">
|
1101 |
-
<h1><?php esc_html_e( 'Cron Events', 'wp-crontrol' ); ?></h1>
|
|
|
|
|
|
|
|
|
1102 |
|
1103 |
<?php $table->views(); ?>
|
1104 |
|
@@ -1132,10 +1355,6 @@ function admin_manage_page() {
|
|
1132 |
show_cron_form( false );
|
1133 |
break;
|
1134 |
|
1135 |
-
case $tabs['add-php-event']:
|
1136 |
-
show_cron_form( false, true );
|
1137 |
-
break;
|
1138 |
-
|
1139 |
case $tabs['edit-event']:
|
1140 |
show_cron_form( true );
|
1141 |
break;
|
@@ -1154,7 +1373,6 @@ function get_tab_states() {
|
|
1154 |
'events' => ( ! empty( $_GET['page'] ) && 'crontrol_admin_manage_page' === $_GET['page'] && empty( $_GET['action'] ) ),
|
1155 |
'schedules' => ( ! empty( $_GET['page'] ) && 'crontrol_admin_options_page' === $_GET['page'] ),
|
1156 |
'add-event' => ( ! empty( $_GET['action'] ) && 'new-cron' === $_GET['action'] ),
|
1157 |
-
'add-php-event' => ( ! empty( $_GET['action'] ) && 'new-php-cron' === $_GET['action'] ),
|
1158 |
'edit-event' => ( ! empty( $_GET['action'] ) && 'edit-cron' === $_GET['action'] ),
|
1159 |
);
|
1160 |
}
|
@@ -1173,22 +1391,14 @@ function do_tabs() {
|
|
1173 |
$tab = array_keys( $tab );
|
1174 |
$tab = reset( $tab );
|
1175 |
$links = array(
|
1176 |
-
'events'
|
1177 |
'tools.php?page=crontrol_admin_manage_page',
|
1178 |
__( 'Cron Events', 'wp-crontrol' ),
|
1179 |
),
|
1180 |
-
'schedules'
|
1181 |
'options-general.php?page=crontrol_admin_options_page',
|
1182 |
__( 'Cron Schedules', 'wp-crontrol' ),
|
1183 |
),
|
1184 |
-
'add-event' => array(
|
1185 |
-
'tools.php?page=crontrol_admin_manage_page&action=new-cron',
|
1186 |
-
__( 'Add Cron Event', 'wp-crontrol' ),
|
1187 |
-
),
|
1188 |
-
'add-php-event' => array(
|
1189 |
-
'tools.php?page=crontrol_admin_manage_page&action=new-php-cron',
|
1190 |
-
__( 'Add PHP Cron Event', 'wp-crontrol' ),
|
1191 |
-
),
|
1192 |
);
|
1193 |
|
1194 |
?>
|
@@ -1211,7 +1421,12 @@ function do_tabs() {
|
|
1211 |
}
|
1212 |
}
|
1213 |
|
1214 |
-
if ( $tabs['
|
|
|
|
|
|
|
|
|
|
|
1215 |
printf(
|
1216 |
'<span class="nav-tab nav-tab-active">%s</span>',
|
1217 |
esc_html__( 'Edit Cron Event', 'wp-crontrol' )
|
@@ -1314,7 +1529,7 @@ function output_callback( array $callback ) {
|
|
1314 |
if ( class_exists( '\QM_Output_Html' ) ) {
|
1315 |
if ( ! empty( $callback['callback']['error'] ) ) {
|
1316 |
$return = '<code>' . $callback['callback']['name'] . '</code>';
|
1317 |
-
$return .= '<br><span
|
1318 |
$return .= esc_html( $callback['callback']['error']->get_error_message() );
|
1319 |
$return .= '</span>';
|
1320 |
return $return;
|
@@ -1428,30 +1643,6 @@ function setup_manage_page() {
|
|
1428 |
esc_html__( 'The scheduled cron events have changed since you first opened this page. Reload the page to see the up to date list.', 'wp-crontrol' )
|
1429 |
);
|
1430 |
} );
|
1431 |
-
|
1432 |
-
if ( ! function_exists( 'wp_enqueue_code_editor' ) ) {
|
1433 |
-
return;
|
1434 |
-
}
|
1435 |
-
if ( ! current_user_can( 'edit_files' ) ) {
|
1436 |
-
return;
|
1437 |
-
}
|
1438 |
-
|
1439 |
-
$settings = wp_enqueue_code_editor( array(
|
1440 |
-
'type' => 'text/x-php',
|
1441 |
-
) );
|
1442 |
-
|
1443 |
-
if ( false === $settings ) {
|
1444 |
-
return;
|
1445 |
-
}
|
1446 |
-
|
1447 |
-
wp_add_inline_script( 'code-editor', sprintf(
|
1448 |
-
'jQuery( function( $ ) {
|
1449 |
-
if ( $( "#hookcode" ).length ) {
|
1450 |
-
wp.codeEditor.initialize( "hookcode", %s );
|
1451 |
-
}
|
1452 |
-
} );',
|
1453 |
-
wp_json_encode( $settings )
|
1454 |
-
) );
|
1455 |
}
|
1456 |
|
1457 |
/**
|
@@ -1467,17 +1658,31 @@ function enqueue_assets( $hook_suffix ) {
|
|
1467 |
}
|
1468 |
|
1469 |
$ver = filemtime( plugin_dir_path( __FILE__ ) . 'css/wp-crontrol.css' );
|
1470 |
-
wp_enqueue_style( 'wp-crontrol', plugin_dir_url( __FILE__ ) . 'css/wp-crontrol.css', array(), $ver );
|
1471 |
|
1472 |
$ver = filemtime( plugin_dir_path( __FILE__ ) . 'js/wp-crontrol.js' );
|
1473 |
wp_enqueue_script( 'wp-crontrol', plugin_dir_url( __FILE__ ) . 'js/wp-crontrol.js', array( 'jquery' ), $ver, true );
|
1474 |
|
|
|
|
|
1475 |
if ( ! empty( $tab['events'] ) ) {
|
1476 |
-
|
1477 |
-
|
1478 |
-
'eventsHashInterval' => 20,
|
1479 |
-
) );
|
1480 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1481 |
}
|
1482 |
|
1483 |
/**
|
@@ -1528,6 +1733,7 @@ function get_all_core_hooks() {
|
|
1528 |
'upgrader_scheduled_cleanup',
|
1529 |
'wp_maybe_auto_update',
|
1530 |
'wp_split_shared_term_batch',
|
|
|
1531 |
)
|
1532 |
);
|
1533 |
}
|
@@ -1542,6 +1748,7 @@ function get_core_schedules() {
|
|
1542 |
'hourly',
|
1543 |
'twicedaily',
|
1544 |
'daily',
|
|
|
1545 |
);
|
1546 |
}
|
1547 |
|
2 |
/**
|
3 |
* Plugin Name: WP Crontrol
|
4 |
* Plugin URI: https://wordpress.org/plugins/wp-crontrol/
|
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.0
|
9 |
* Text Domain: wp-crontrol
|
10 |
* Domain Path: /languages/
|
11 |
* Requires PHP: 5.3.6
|
55 |
add_filter( 'removable_query_args', __NAMESPACE__ . '\filter_removable_query_args' );
|
56 |
add_filter( 'in_admin_header', __NAMESPACE__ . '\do_tabs' );
|
57 |
add_filter( 'pre_unschedule_event', __NAMESPACE__ . '\maybe_clear_doing_cron' );
|
58 |
+
add_filter( 'plugin_row_meta', __NAMESPACE__ . '\filter_plugin_row_meta', 10, 4 );
|
59 |
|
60 |
add_action( 'load-tools_page_crontrol_admin_manage_page', __NAMESPACE__ . '\setup_manage_page' );
|
61 |
|
65 |
add_action( 'crontrol/tab-header', __NAMESPACE__ . '\show_cron_status', 20 );
|
66 |
}
|
67 |
|
68 |
+
/**
|
69 |
+
* Filters the array of row meta for each plugin in the Plugins list table.
|
70 |
+
*
|
71 |
+
* @param string[] $plugin_meta An array of the plugin's metadata.
|
72 |
+
* @param string $plugin_file Path to the plugin file relative to the plugins directory.
|
73 |
+
* @return string[] An array of the plugin's metadata.
|
74 |
+
*/
|
75 |
+
function filter_plugin_row_meta( array $plugin_meta, $plugin_file ) {
|
76 |
+
if ( 'wp-crontrol/wp-crontrol.php' !== $plugin_file ) {
|
77 |
+
return $plugin_meta;
|
78 |
+
}
|
79 |
+
|
80 |
+
$plugin_meta[] = sprintf(
|
81 |
+
'<a href="%1$s"><span class="dashicons dashicons-star-filled" aria-hidden="true" style="font-size:14px;line-height:1.3"></span>%2$s</a>',
|
82 |
+
'https://github.com/sponsors/johnbillion',
|
83 |
+
esc_html_x( 'Sponsor', 'verb', 'wp-crontrol' )
|
84 |
+
);
|
85 |
+
|
86 |
+
return $plugin_meta;
|
87 |
+
}
|
88 |
+
|
89 |
/**
|
90 |
* Run using the 'init' action.
|
91 |
*/
|
97 |
* Handles any POSTs made by the plugin. Run using the 'init' action.
|
98 |
*/
|
99 |
function action_handle_posts() {
|
100 |
+
if ( isset( $_POST['action'] ) && ( 'new_cron' === $_POST['action'] ) ) {
|
101 |
if ( ! current_user_can( 'manage_options' ) ) {
|
102 |
wp_die( esc_html__( 'You are not allowed to add new cron events.', 'wp-crontrol' ), 401 );
|
103 |
}
|
112 |
$in_args = array();
|
113 |
}
|
114 |
|
115 |
+
$next_run_local = ( 'custom' === $in_next_run_date_local ) ? $in_next_run_date_local_custom_date . ' ' . $in_next_run_date_local_custom_time : $in_next_run_date_local;
|
116 |
+
|
117 |
+
add_filter( 'schedule_event', function( $event ) {
|
118 |
+
if ( ! $event ) {
|
119 |
+
return $event;
|
120 |
+
}
|
121 |
+
|
122 |
+
/**
|
123 |
+
* Fires after a new cron event is added.
|
124 |
+
*
|
125 |
+
* @param object $event {
|
126 |
+
* An object containing the event's data.
|
127 |
+
*
|
128 |
+
* @type string $hook Action hook to execute when the event is run.
|
129 |
+
* @type int $timestamp Unix timestamp (UTC) for when to next run the event.
|
130 |
+
* @type string|false $schedule How often the event should subsequently recur.
|
131 |
+
* @type array $args Array containing each separate argument to pass to the hook's callback function.
|
132 |
+
* @type int $interval The interval time in seconds for the schedule. Only present for recurring events.
|
133 |
+
* }
|
134 |
+
*/
|
135 |
+
do_action( 'crontrol/added_new_event', $event );
|
136 |
+
|
137 |
+
return $event;
|
138 |
+
}, 99 );
|
139 |
|
140 |
$added = Event\add( $next_run_local, $in_schedule, $in_hookname, $in_args );
|
141 |
|
152 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
153 |
exit;
|
154 |
|
155 |
+
} elseif ( isset( $_POST['action'] ) && ( 'new_php_cron' === $_POST['action'] ) ) {
|
156 |
if ( ! current_user_can( 'edit_files' ) ) {
|
157 |
wp_die( esc_html__( 'You are not allowed to add new PHP cron events.', 'wp-crontrol' ), 401 );
|
158 |
}
|
159 |
check_admin_referer( 'new-cron' );
|
160 |
extract( wp_unslash( $_POST ), EXTR_PREFIX_ALL, 'in' );
|
161 |
+
$next_run_local = ( 'custom' === $in_next_run_date_local ) ? $in_next_run_date_local_custom_date . ' ' . $in_next_run_date_local_custom_time : $in_next_run_date_local;
|
162 |
$args = array(
|
163 |
'code' => $in_hookcode,
|
164 |
'name' => $in_eventname,
|
165 |
);
|
166 |
|
167 |
+
add_filter( 'schedule_event', function( $event ) {
|
168 |
+
if ( ! $event ) {
|
169 |
+
return $event;
|
170 |
+
}
|
171 |
+
|
172 |
+
/**
|
173 |
+
* Fires after a new PHP cron event is added.
|
174 |
+
*
|
175 |
+
* @param object $event {
|
176 |
+
* An object containing the event's data.
|
177 |
+
*
|
178 |
+
* @type string $hook Action hook to execute when the event is run.
|
179 |
+
* @type int $timestamp Unix timestamp (UTC) for when to next run the event.
|
180 |
+
* @type string|false $schedule How often the event should subsequently recur.
|
181 |
+
* @type array $args Array containing each separate argument to pass to the hook's callback function.
|
182 |
+
* @type int $interval The interval time in seconds for the schedule. Only present for recurring events.
|
183 |
+
* }
|
184 |
+
*/
|
185 |
+
do_action( 'crontrol/added_new_php_event', $event );
|
186 |
+
|
187 |
+
return $event;
|
188 |
+
}, 99 );
|
189 |
+
|
190 |
$added = Event\add( $next_run_local, $in_schedule, 'crontrol_cron_job', $args );
|
191 |
|
192 |
$hookname = ( ! empty( $in_eventname ) ) ? $in_eventname : __( 'PHP Cron', 'wp-crontrol' );
|
203 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
204 |
exit;
|
205 |
|
206 |
+
} elseif ( isset( $_POST['action'] ) && ( 'edit_cron' === $_POST['action'] ) ) {
|
207 |
if ( ! current_user_can( 'manage_options' ) ) {
|
208 |
wp_die( esc_html__( 'You are not allowed to edit cron events.', 'wp-crontrol' ), 401 );
|
209 |
}
|
221 |
$in_args = array();
|
222 |
}
|
223 |
|
224 |
+
$original = Event\get_single( $in_original_hookname, $in_original_sig, $in_original_next_run_utc );
|
225 |
Event\delete( $in_original_hookname, $in_original_sig, $in_original_next_run_utc );
|
226 |
|
227 |
+
$next_run_local = ( 'custom' === $in_next_run_date_local ) ? $in_next_run_date_local_custom_date . ' ' . $in_next_run_date_local_custom_time : $in_next_run_date_local;
|
228 |
+
|
229 |
+
add_filter( 'schedule_event', function( $event ) use ( $original ) {
|
230 |
+
if ( ! $event || ! $original ) {
|
231 |
+
return $event;
|
232 |
+
}
|
233 |
+
|
234 |
+
/**
|
235 |
+
* Fires after a cron event is edited.
|
236 |
+
*
|
237 |
+
* @param object $event {
|
238 |
+
* An object containing the new event's data.
|
239 |
+
*
|
240 |
+
* @type string $hook Action hook to execute when the event is run.
|
241 |
+
* @type int $timestamp Unix timestamp (UTC) for when to next run the event.
|
242 |
+
* @type string|false $schedule How often the event should subsequently recur.
|
243 |
+
* @type array $args Array containing each separate argument to pass to the hook's callback function.
|
244 |
+
* @type int $interval The interval time in seconds for the schedule. Only present for recurring events.
|
245 |
+
* }
|
246 |
+
* @param object $original {
|
247 |
+
* An object containing the original event's data.
|
248 |
+
*
|
249 |
+
* @type string $hook Action hook to execute when the event is run.
|
250 |
+
* @type int $timestamp Unix timestamp (UTC) for when to next run the event.
|
251 |
+
* @type string|false $schedule How often the event should subsequently recur.
|
252 |
+
* @type array $args Array containing each separate argument to pass to the hook's callback function.
|
253 |
+
* @type int $interval The interval time in seconds for the schedule. Only present for recurring events.
|
254 |
+
* }
|
255 |
+
*/
|
256 |
+
do_action( 'crontrol/edited_event', $event, $original );
|
257 |
+
|
258 |
+
return $event;
|
259 |
+
}, 99 );
|
260 |
|
261 |
$added = Event\add( $next_run_local, $in_schedule, $in_hookname, $in_args );
|
262 |
|
273 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
274 |
exit;
|
275 |
|
276 |
+
} elseif ( isset( $_POST['action'] ) && ( 'edit_php_cron' === $_POST['action'] ) ) {
|
277 |
if ( ! current_user_can( 'edit_files' ) ) {
|
278 |
wp_die( esc_html__( 'You are not allowed to edit PHP cron events.', 'wp-crontrol' ), 401 );
|
279 |
}
|
285 |
'name' => $in_eventname,
|
286 |
);
|
287 |
|
288 |
+
$original = Event\get_single( $in_original_hookname, $in_original_sig, $in_original_next_run_utc );
|
289 |
Event\delete( $in_original_hookname, $in_original_sig, $in_original_next_run_utc );
|
290 |
|
291 |
+
$next_run_local = ( 'custom' === $in_next_run_date_local ) ? $in_next_run_date_local_custom_date . ' ' . $in_next_run_date_local_custom_time : $in_next_run_date_local;
|
292 |
+
|
293 |
+
add_filter( 'schedule_event', function( $event ) use ( $original ) {
|
294 |
+
if ( ! $event || ! $original ) {
|
295 |
+
return $event;
|
296 |
+
}
|
297 |
+
|
298 |
+
/**
|
299 |
+
* Fires after a PHP cron event is edited.
|
300 |
+
*
|
301 |
+
* @param object $event {
|
302 |
+
* An object containing the new event's data.
|
303 |
+
*
|
304 |
+
* @type string $hook Action hook to execute when the event is run.
|
305 |
+
* @type int $timestamp Unix timestamp (UTC) for when to next run the event.
|
306 |
+
* @type string|false $schedule How often the event should subsequently recur.
|
307 |
+
* @type array $args Array containing each separate argument to pass to the hook's callback function.
|
308 |
+
* @type int $interval The interval time in seconds for the schedule. Only present for recurring events.
|
309 |
+
* }
|
310 |
+
* @param object $original {
|
311 |
+
* An object containing the original event's data.
|
312 |
+
*
|
313 |
+
* @type string $hook Action hook to execute when the event is run.
|
314 |
+
* @type int $timestamp Unix timestamp (UTC) for when to next run the event.
|
315 |
+
* @type string|false $schedule How often the event should subsequently recur.
|
316 |
+
* @type array $args Array containing each separate argument to pass to the hook's callback function.
|
317 |
+
* @type int $interval The interval time in seconds for the schedule. Only present for recurring events.
|
318 |
+
* }
|
319 |
+
*/
|
320 |
+
do_action( 'crontrol/edited_php_event', $event, $original );
|
321 |
+
|
322 |
+
return $event;
|
323 |
+
}, 99 );
|
324 |
|
325 |
$added = Event\add( $next_run_local, $in_schedule, 'crontrol_cron_job', $args );
|
326 |
|
385 |
if ( ! current_user_can( 'manage_options' ) ) {
|
386 |
wp_die( esc_html__( 'You are not allowed to delete cron schedules.', 'wp-crontrol' ), 401 );
|
387 |
}
|
388 |
+
$schedule = wp_unslash( $_GET['id'] );
|
389 |
+
check_admin_referer( "delete-sched_{$schedule}" );
|
390 |
+
Schedule\delete( $schedule );
|
391 |
$redirect = array(
|
392 |
'page' => 'crontrol_admin_options_page',
|
393 |
'crontrol_message' => '2',
|
394 |
+
'crontrol_name' => rawurlencode( $schedule ),
|
395 |
);
|
396 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'options-general.php' ) ) );
|
397 |
exit;
|
410 |
$deleted = 0;
|
411 |
|
412 |
foreach ( $delete as $next_run_utc => $events ) {
|
413 |
+
foreach ( $events as $hook => $sig ) {
|
414 |
+
if ( 'crontrol_cron_job' === $hook && ! current_user_can( 'edit_files' ) ) {
|
415 |
continue;
|
416 |
}
|
417 |
+
|
418 |
+
$event = Event\get_single( urldecode( $hook ), $sig, $next_run_utc );
|
419 |
+
|
420 |
+
if ( Event\delete( urldecode( $hook ), $sig, $next_run_utc ) ) {
|
421 |
$deleted++;
|
422 |
+
|
423 |
+
/** This action is documented in wp-crontrol.php */
|
424 |
+
do_action( 'crontrol/deleted_event', $event );
|
425 |
}
|
426 |
}
|
427 |
}
|
438 |
if ( ! current_user_can( 'manage_options' ) ) {
|
439 |
wp_die( esc_html__( 'You are not allowed to delete cron events.', 'wp-crontrol' ), 401 );
|
440 |
}
|
441 |
+
$hook = wp_unslash( $_GET['id'] );
|
442 |
$sig = wp_unslash( $_GET['sig'] );
|
443 |
$next_run_utc = intval( $_GET['next_run_utc'] );
|
444 |
+
check_admin_referer( "delete-cron_{$hook}_{$sig}_{$next_run_utc}" );
|
445 |
|
446 |
+
if ( 'crontrol_cron_job' === $hook && ! current_user_can( 'edit_files' ) ) {
|
447 |
wp_die( esc_html__( 'You are not allowed to delete PHP cron events.', 'wp-crontrol' ), 401 );
|
448 |
}
|
449 |
|
450 |
+
$event = Event\get_single( $hook, $sig, $next_run_utc );
|
451 |
+
$deleted = Event\delete( $hook, $sig, $next_run_utc );
|
452 |
+
$redirect = array(
|
453 |
+
'page' => 'crontrol_admin_manage_page',
|
454 |
+
'crontrol_message' => '6',
|
455 |
+
'crontrol_name' => rawurlencode( $hook ),
|
456 |
+
);
|
457 |
+
|
458 |
+
if ( false === $deleted ) {
|
459 |
+
$redirect['crontrol_message'] = '7';
|
460 |
} else {
|
461 |
+
/**
|
462 |
+
* Fires after a cron event is deleted.
|
463 |
+
*
|
464 |
+
* @param object $event {
|
465 |
+
* An object containing the event's data.
|
466 |
+
*
|
467 |
+
* @type string $hook Action hook to execute when the event is run.
|
468 |
+
* @type int $timestamp Unix timestamp (UTC) for when to next run the event.
|
469 |
+
* @type string|false $schedule How often the event should subsequently recur.
|
470 |
+
* @type array $args Array containing each separate argument to pass to the hook's callback function.
|
471 |
+
* @type int $interval The interval time in seconds for the schedule. Only present for recurring events.
|
472 |
+
* }
|
473 |
+
*/
|
474 |
+
do_action( 'crontrol/deleted_event', $event );
|
475 |
+
}
|
476 |
|
477 |
+
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
478 |
+
exit;
|
479 |
|
480 |
} elseif ( isset( $_GET['action'] ) && 'delete-hook' === $_GET['action'] ) {
|
481 |
if ( ! current_user_can( 'manage_options' ) ) {
|
482 |
wp_die( esc_html__( 'You are not allowed to delete cron events.', 'wp-crontrol' ), 401 );
|
483 |
}
|
484 |
+
$hook = wp_unslash( $_GET['id'] );
|
485 |
$deleted = false;
|
486 |
+
check_admin_referer( "delete-hook_{$hook}" );
|
487 |
|
488 |
+
if ( 'crontrol_cron_job' === $hook ) {
|
489 |
wp_die( esc_html__( 'You are not allowed to delete PHP cron events.', 'wp-crontrol' ), 401 );
|
490 |
}
|
491 |
|
492 |
if ( function_exists( 'wp_unschedule_hook' ) ) {
|
493 |
+
$deleted = wp_unschedule_hook( $hook );
|
494 |
}
|
495 |
|
496 |
if ( 0 === $deleted ) {
|
497 |
$redirect = array(
|
498 |
'page' => 'crontrol_admin_manage_page',
|
499 |
'crontrol_message' => '3',
|
500 |
+
'crontrol_name' => rawurlencode( $hook ),
|
501 |
);
|
502 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
503 |
exit;
|
504 |
} elseif ( $deleted ) {
|
505 |
+
/**
|
506 |
+
* Fires after all cron events with the given hook are deleted.
|
507 |
+
*
|
508 |
+
* @param string $hook The hook name.
|
509 |
+
* @param int $deleted The number of events that were deleted.
|
510 |
+
*/
|
511 |
+
do_action( 'crontrol/deleted_all_with_hook', $hook, $deleted );
|
512 |
+
|
513 |
$redirect = array(
|
514 |
'page' => 'crontrol_admin_manage_page',
|
515 |
'crontrol_message' => '2',
|
516 |
+
'crontrol_name' => rawurlencode( $hook ),
|
517 |
);
|
518 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
519 |
exit;
|
521 |
$redirect = array(
|
522 |
'page' => 'crontrol_admin_manage_page',
|
523 |
'crontrol_message' => '7',
|
524 |
+
'crontrol_name' => rawurlencode( $hook ),
|
525 |
);
|
526 |
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
527 |
exit;
|
530 |
if ( ! current_user_can( 'manage_options' ) ) {
|
531 |
wp_die( esc_html__( 'You are not allowed to run cron events.', 'wp-crontrol' ), 401 );
|
532 |
}
|
533 |
+
$hook = wp_unslash( $_GET['id'] );
|
534 |
$sig = wp_unslash( $_GET['sig'] );
|
535 |
+
check_admin_referer( "run-cron_{$hook}_{$sig}" );
|
536 |
+
|
537 |
+
$ran = Event\run( $hook, $sig );
|
538 |
+
|
539 |
+
$redirect = array(
|
540 |
+
'page' => 'crontrol_admin_manage_page',
|
541 |
+
'crontrol_message' => '1',
|
542 |
+
'crontrol_name' => rawurlencode( $hook ),
|
543 |
+
);
|
544 |
+
|
545 |
+
if ( false === $ran ) {
|
546 |
+
$redirect['crontrol_message'] = '8';
|
|
|
|
|
|
|
|
|
|
|
547 |
}
|
548 |
+
|
549 |
+
wp_safe_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
|
550 |
+
exit;
|
551 |
}
|
552 |
}
|
553 |
|
648 |
|
649 |
<?php $table->views(); ?>
|
650 |
|
651 |
+
<div id="col-container" class="wp-clearfix">
|
652 |
+
<div id="col-left">
|
653 |
+
<div class="col-wrap">
|
654 |
+
<div class="form-wrap">
|
655 |
+
<h2><?php esc_html_e( 'Add Cron Schedule', 'wp-crontrol' ); ?></h2>
|
656 |
+
<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>
|
657 |
+
<form method="post" action="options-general.php?page=crontrol_admin_options_page">
|
658 |
+
<div class="form-field form-required">
|
659 |
+
<label for="cron_internal_name">
|
660 |
+
<?php esc_html_e( 'Internal Name', 'wp-crontrol' ); ?>
|
661 |
+
</label>
|
662 |
+
<input type="text" value="" id="cron_internal_name" name="internal_name" required/>
|
663 |
+
</div>
|
664 |
+
<div class="form-field form-required">
|
665 |
+
<label for="cron_interval">
|
666 |
+
<?php esc_html_e( 'Interval (seconds)', 'wp-crontrol' ); ?>
|
667 |
+
</label>
|
668 |
+
<input type="number" value="" id="cron_interval" name="interval" min="1" step="1" required/>
|
669 |
+
</div>
|
670 |
+
<div class="form-field form-required">
|
671 |
+
<label for="cron_display_name">
|
672 |
+
<?php esc_html_e( 'Display Name', 'wp-crontrol' ); ?>
|
673 |
+
</label>
|
674 |
+
<input type="text" value="" id="cron_display_name" name="display_name" required/>
|
675 |
+
</div>
|
676 |
+
<p class="submit">
|
677 |
+
<input id="schedadd-submit" type="submit" class="button button-primary" value="<?php esc_attr_e( 'Add Cron Schedule', 'wp-crontrol' ); ?>" name="new_schedule"/>
|
678 |
+
</p>
|
679 |
+
<?php wp_nonce_field( 'new-sched' ); ?>
|
680 |
+
</form>
|
681 |
+
</div>
|
682 |
+
</div>
|
683 |
+
</div>
|
684 |
+
<div id="col-right">
|
685 |
+
<div class="col-wrap">
|
686 |
+
<?php $table->display(); ?>
|
687 |
+
</div>
|
688 |
+
</div>
|
689 |
</div>
|
690 |
<?php
|
691 |
}
|
839 |
}
|
840 |
|
841 |
if ( 'UTC' !== date_default_timezone_get() ) {
|
|
|
|
|
|
|
|
|
|
|
842 |
?>
|
843 |
<div id="crontrol-timezone-warning" class="notice notice-warning">
|
844 |
+
<?php
|
845 |
+
printf(
|
846 |
+
'<p>%1$s</p><p><a href="%2$s">%3$s</a></p>',
|
847 |
+
/* translators: %s: Help page URL. */
|
848 |
+
esc_html__( 'PHP default timezone is not set to UTC. This may cause issues with cron event timings.', 'wp-crontrol' ),
|
849 |
+
'https://github.com/johnbillion/wp-crontrol/wiki/PHP-default-timezone-is-not-set-to-UTC',
|
850 |
+
esc_html__( 'More information', 'wp-crontrol' )
|
|
|
|
|
851 |
);
|
852 |
+
?>
|
|
|
853 |
</div>
|
854 |
<?php
|
855 |
}
|
866 |
} else {
|
867 |
?>
|
868 |
<div id="cron-status-error" class="error">
|
869 |
+
<?php
|
870 |
+
printf(
|
871 |
+
'<p>%1$s</p><p><a href="%2$s">%3$s</a></p>',
|
872 |
+
sprintf(
|
873 |
/* translators: 1: Error message text. */
|
874 |
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' ),
|
875 |
+
'</p><p><strong>' . esc_html( $status->get_error_message() ) . '</strong>'
|
876 |
+
),
|
877 |
+
'https://github.com/johnbillion/wp-crontrol/wiki/Problems-with-spawning-a-call-to-the-WP-Cron-system',
|
878 |
+
esc_html__( 'More information', 'wp-crontrol' )
|
879 |
+
);
|
880 |
+
?>
|
881 |
</div>
|
882 |
<?php
|
883 |
}
|
942 |
* Shows the form used to add/edit cron events.
|
943 |
*
|
944 |
* @param bool $editing Whether the form is for the event editor.
|
|
|
945 |
* @return void
|
946 |
*/
|
947 |
+
function show_cron_form( $editing ) {
|
948 |
$display_args = '';
|
949 |
$edit_id = null;
|
950 |
$existing = false;
|
951 |
|
952 |
+
if ( $editing && ! empty( $_GET['id'] ) ) {
|
953 |
$edit_id = wp_unslash( $_GET['id'] );
|
|
|
954 |
|
955 |
+
foreach ( Event\get() as $event ) {
|
956 |
+
if ( $edit_id === $event->hook && intval( $_GET['next_run_utc'] ) === $event->time && $event->sig === $_GET['sig'] ) {
|
957 |
+
$existing = array(
|
958 |
+
'hookname' => $event->hook,
|
959 |
+
'next_run' => $event->time, // UTC
|
960 |
+
'schedule' => ( $event->schedule ? $event->schedule : '_oneoff' ),
|
961 |
+
'sig' => $event->sig,
|
962 |
+
'args' => $event->args,
|
963 |
+
);
|
964 |
+
break;
|
965 |
+
}
|
966 |
}
|
|
|
967 |
|
968 |
+
if ( empty( $existing ) ) {
|
969 |
+
?>
|
970 |
+
<div id="crontrol-event-not-found" class="notice notice-error">
|
971 |
+
<?php
|
972 |
+
printf(
|
973 |
+
'<p>%1$s</p>',
|
974 |
+
esc_html__( 'The event you are trying to edit does not exist.', 'wp-crontrol' )
|
975 |
+
);
|
976 |
+
?>
|
977 |
+
</div>
|
978 |
+
<?php
|
979 |
+
return;
|
980 |
+
}
|
981 |
}
|
982 |
|
983 |
+
$is_editing_php = ( $existing && 'crontrol_cron_job' === $existing['hookname'] );
|
984 |
+
|
985 |
+
if ( $is_editing_php ) {
|
986 |
$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' );
|
987 |
} else {
|
988 |
$helper_text = sprintf(
|
1006 |
if ( ! empty( $existing['args'] ) ) {
|
1007 |
$display_args = wp_json_encode( $existing['args'] );
|
1008 |
}
|
1009 |
+
$action = $is_editing_php ? 'edit_php_cron' : 'edit_cron';
|
1010 |
$button = __( 'Update Event', 'wp-crontrol' );
|
1011 |
+
$next_run_gmt = gmdate( 'Y-m-d H:i:s', $existing['next_run'] );
|
1012 |
+
$next_run_date_local = get_date_from_gmt( $next_run_gmt, 'Y-m-d' );
|
1013 |
+
$next_run_time_local = get_date_from_gmt( $next_run_gmt, 'H:i:s' );
|
1014 |
} else {
|
1015 |
$other_fields = wp_nonce_field( 'new-cron', '_wpnonce', true, false );
|
1016 |
$existing = array(
|
1020 |
'schedule' => false,
|
1021 |
);
|
1022 |
|
|
|
1023 |
$button = __( 'Add Event', 'wp-crontrol' );
|
1024 |
$next_run_date_local = '';
|
1025 |
+
$next_run_time_local = '';
|
1026 |
}
|
1027 |
|
1028 |
+
if ( $is_editing_php ) {
|
1029 |
if ( ! isset( $existing['args']['code'] ) ) {
|
1030 |
$existing['args']['code'] = '';
|
1031 |
}
|
1034 |
}
|
1035 |
}
|
1036 |
|
1037 |
+
$can_add_php = current_user_can( 'edit_files' ) && ! $editing;
|
1038 |
+
$allowed = ( ! $is_editing_php || current_user_can( 'edit_files' ) );
|
1039 |
?>
|
1040 |
<div id="crontrol_form" class="wrap narrow">
|
1041 |
<?php
|
1042 |
if ( $allowed ) {
|
1043 |
if ( $editing ) {
|
1044 |
+
$heading = __( 'Edit Cron Event', 'wp-crontrol' );
|
|
|
|
|
|
|
|
|
1045 |
} else {
|
1046 |
+
$heading = __( 'Add Cron Event', 'wp-crontrol' );
|
|
|
|
|
|
|
|
|
1047 |
}
|
1048 |
|
1049 |
printf(
|
1056 |
$helper_text
|
1057 |
);
|
1058 |
?>
|
1059 |
+
<form method="post" action="<?php echo esc_url( admin_url( 'tools.php?page=crontrol_admin_manage_page' ) ); ?>" class="crontrol-edit-event crontrol-edit-event-<?php echo ( $is_editing_php ) ? 'php' : 'standard'; ?>">
|
1060 |
<?php
|
1061 |
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
1062 |
echo $other_fields;
|
1063 |
?>
|
1064 |
<table class="form-table"><tbody>
|
1065 |
+
<?php
|
1066 |
+
if ( $editing ) {
|
1067 |
+
printf(
|
1068 |
+
'<input type="hidden" name="action" value="%s"/>',
|
1069 |
+
esc_attr( $action )
|
1070 |
+
);
|
1071 |
+
} elseif ( $can_add_php ) {
|
1072 |
+
?>
|
1073 |
+
<tr class="hide-if-no-js">
|
1074 |
+
<th valign="top" scope="row">
|
1075 |
+
<?php esc_html_e( 'Event Type', 'wp-crontrol' ); ?>
|
1076 |
+
</th>
|
1077 |
+
<td>
|
1078 |
+
<p><label><input type="radio" name="action" value="new_cron" checked>Standard cron event</label></p>
|
1079 |
+
<p><label><input type="radio" name="action" value="new_php_cron">PHP cron event</label></p>
|
1080 |
+
</td>
|
1081 |
+
</tr>
|
1082 |
+
<?php
|
1083 |
+
}
|
1084 |
+
|
1085 |
+
if ( $is_editing_php || $can_add_php ) {
|
1086 |
+
?>
|
1087 |
+
<tr class="crontrol-event-php">
|
1088 |
+
<th valign="top" scope="row">
|
1089 |
+
<label for="hookcode">
|
1090 |
+
<?php esc_html_e( 'PHP Code', 'wp-crontrol' ); ?>
|
1091 |
+
</label>
|
1092 |
+
</th>
|
1093 |
<td>
|
1094 |
<p class="description">
|
1095 |
<?php
|
1100 |
);
|
1101 |
?>
|
1102 |
</p>
|
1103 |
+
<p><textarea class="large-text code" rows="10" cols="50" id="hookcode" name="hookcode"><?php echo esc_textarea( $editing ? $existing['args']['code'] : '' ); ?></textarea></p>
|
1104 |
</td>
|
1105 |
</tr>
|
1106 |
+
<tr class="crontrol-event-php">
|
1107 |
+
<th valign="top" scope="row">
|
1108 |
+
<label for="eventname">
|
1109 |
+
<?php esc_html_e( 'Event Name (optional)', 'wp-crontrol' ); ?>
|
1110 |
+
</label>
|
1111 |
+
</th>
|
1112 |
+
<td>
|
1113 |
+
<input type="text" class="regular-text" id="eventname" name="eventname" value="<?php echo esc_attr( $editing ? $existing['args']['name'] : '' ); ?>"/>
|
1114 |
+
</td>
|
1115 |
</tr>
|
1116 |
+
<?php
|
1117 |
+
}
|
1118 |
+
|
1119 |
+
if ( ! $is_editing_php ) {
|
1120 |
+
?>
|
1121 |
+
<tr class="crontrol-event-standard">
|
1122 |
+
<th valign="top" scope="row">
|
1123 |
+
<label for="hookname">
|
1124 |
+
<?php esc_html_e( 'Hook Name', 'wp-crontrol' ); ?>
|
1125 |
+
</label>
|
1126 |
+
</th>
|
1127 |
<td>
|
1128 |
<input type="text" autocorrect="off" autocapitalize="off" spellcheck="false" class="regular-text" id="hookname" name="hookname" value="<?php echo esc_attr( $existing['hookname'] ); ?>" required />
|
1129 |
</td>
|
1130 |
</tr>
|
1131 |
+
<tr class="crontrol-event-standard">
|
1132 |
+
<th valign="top" scope="row">
|
1133 |
+
<label for="args">
|
1134 |
+
<?php esc_html_e( 'Arguments (optional)', 'wp-crontrol' ); ?>
|
1135 |
+
</label>
|
1136 |
+
</th>
|
1137 |
<td>
|
1138 |
+
<input type="text" autocorrect="off" autocapitalize="off" spellcheck="false" class="regular-text code" id="args" name="args" value="<?php echo esc_attr( $display_args ); ?>"/>
|
1139 |
<p class="description">
|
1140 |
<?php
|
1141 |
printf(
|
1149 |
</p>
|
1150 |
</td>
|
1151 |
</tr>
|
1152 |
+
<?php
|
1153 |
+
}
|
1154 |
+
?>
|
1155 |
<tr>
|
1156 |
+
<th valign="top" scope="row">
|
1157 |
+
<label for="next_run_date_local">
|
1158 |
+
<?php esc_html_e( 'Next Run', 'wp-crontrol' ); ?>
|
1159 |
+
</label>
|
1160 |
+
</th>
|
1161 |
<td>
|
1162 |
<ul>
|
1163 |
<li>
|
1180 |
/* translators: %s: An input field for specifying a date and time */
|
1181 |
esc_html__( 'At: %s', 'wp-crontrol' ),
|
1182 |
sprintf(
|
1183 |
+
'<br>
|
1184 |
+
<input type="date" autocorrect="off" autocapitalize="off" spellcheck="false" name="next_run_date_local_custom_date" id="next_run_date_local_custom_date" value="%1$s" placeholder="yyyy-mm-dd" pattern="\d{4}-\d{2}-\d{2}" />
|
1185 |
+
<input type="time" autocorrect="off" autocapitalize="off" spellcheck="false" name="next_run_date_local_custom_time" id="next_run_date_local_custom_time" value="%2$s" step="1" placeholder="hh:mm:ss" pattern="\d{2}:\d{2}:\d{2}" />',
|
1186 |
+
esc_attr( $next_run_date_local ),
|
1187 |
+
esc_attr( $next_run_time_local )
|
1188 |
)
|
1189 |
);
|
1190 |
?>
|
1201 |
);
|
1202 |
?>
|
1203 |
</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1204 |
</td>
|
1205 |
+
</tr>
|
1206 |
+
<tr>
|
1207 |
+
<th valign="top" scope="row">
|
1208 |
+
<label for="schedule">
|
1209 |
+
<?php esc_html_e( 'Recurrence', 'wp-crontrol' ); ?>
|
1210 |
+
</label>
|
1211 |
+
</th>
|
1212 |
<td>
|
1213 |
<?php Schedule\dropdown( $existing['schedule'] ); ?>
|
1214 |
</td>
|
1215 |
</tr>
|
1216 |
</tbody></table>
|
1217 |
+
<p class="submit">
|
1218 |
+
<input type="submit" class="button button-primary" value="<?php echo esc_attr( $button ); ?>"/>
|
1219 |
+
</p>
|
1220 |
</form>
|
1221 |
<?php } else { ?>
|
1222 |
<div class="error inline">
|
1317 |
case $tabs['events']:
|
1318 |
?>
|
1319 |
<div class="wrap">
|
1320 |
+
<h1 class="wp-heading-inline"><?php esc_html_e( 'Cron Events', 'wp-crontrol' ); ?></h1>
|
1321 |
+
|
1322 |
+
<?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>'; ?>
|
1323 |
+
|
1324 |
+
<hr class="wp-header-end">
|
1325 |
|
1326 |
<?php $table->views(); ?>
|
1327 |
|
1355 |
show_cron_form( false );
|
1356 |
break;
|
1357 |
|
|
|
|
|
|
|
|
|
1358 |
case $tabs['edit-event']:
|
1359 |
show_cron_form( true );
|
1360 |
break;
|
1373 |
'events' => ( ! empty( $_GET['page'] ) && 'crontrol_admin_manage_page' === $_GET['page'] && empty( $_GET['action'] ) ),
|
1374 |
'schedules' => ( ! empty( $_GET['page'] ) && 'crontrol_admin_options_page' === $_GET['page'] ),
|
1375 |
'add-event' => ( ! empty( $_GET['action'] ) && 'new-cron' === $_GET['action'] ),
|
|
|
1376 |
'edit-event' => ( ! empty( $_GET['action'] ) && 'edit-cron' === $_GET['action'] ),
|
1377 |
);
|
1378 |
}
|
1391 |
$tab = array_keys( $tab );
|
1392 |
$tab = reset( $tab );
|
1393 |
$links = array(
|
1394 |
+
'events' => array(
|
1395 |
'tools.php?page=crontrol_admin_manage_page',
|
1396 |
__( 'Cron Events', 'wp-crontrol' ),
|
1397 |
),
|
1398 |
+
'schedules' => array(
|
1399 |
'options-general.php?page=crontrol_admin_options_page',
|
1400 |
__( 'Cron Schedules', 'wp-crontrol' ),
|
1401 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1402 |
);
|
1403 |
|
1404 |
?>
|
1421 |
}
|
1422 |
}
|
1423 |
|
1424 |
+
if ( $tabs['add-event'] ) {
|
1425 |
+
printf(
|
1426 |
+
'<span class="nav-tab nav-tab-active">%s</span>',
|
1427 |
+
esc_html__( 'Add Cron Event', 'wp-crontrol' )
|
1428 |
+
);
|
1429 |
+
} elseif ( $tabs['edit-event'] ) {
|
1430 |
printf(
|
1431 |
'<span class="nav-tab nav-tab-active">%s</span>',
|
1432 |
esc_html__( 'Edit Cron Event', 'wp-crontrol' )
|
1529 |
if ( class_exists( '\QM_Output_Html' ) ) {
|
1530 |
if ( ! empty( $callback['callback']['error'] ) ) {
|
1531 |
$return = '<code>' . $callback['callback']['name'] . '</code>';
|
1532 |
+
$return .= '<br><span class="status-crontrol-error"><span class="dashicons dashicons-warning" aria-hidden="true"></span> ';
|
1533 |
$return .= esc_html( $callback['callback']['error']->get_error_message() );
|
1534 |
$return .= '</span>';
|
1535 |
return $return;
|
1643 |
esc_html__( 'The scheduled cron events have changed since you first opened this page. Reload the page to see the up to date list.', 'wp-crontrol' )
|
1644 |
);
|
1645 |
} );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1646 |
}
|
1647 |
|
1648 |
/**
|
1658 |
}
|
1659 |
|
1660 |
$ver = filemtime( plugin_dir_path( __FILE__ ) . 'css/wp-crontrol.css' );
|
1661 |
+
wp_enqueue_style( 'wp-crontrol', plugin_dir_url( __FILE__ ) . 'css/wp-crontrol.css', array( 'dashicons' ), $ver );
|
1662 |
|
1663 |
$ver = filemtime( plugin_dir_path( __FILE__ ) . 'js/wp-crontrol.js' );
|
1664 |
wp_enqueue_script( 'wp-crontrol', plugin_dir_url( __FILE__ ) . 'js/wp-crontrol.js', array( 'jquery' ), $ver, true );
|
1665 |
|
1666 |
+
$vars = array();
|
1667 |
+
|
1668 |
if ( ! empty( $tab['events'] ) ) {
|
1669 |
+
$vars['eventsHash'] = md5( json_encode( Event\get_list_table()->items ) );
|
1670 |
+
$vars['eventsHashInterval'] = 20;
|
|
|
|
|
1671 |
}
|
1672 |
+
|
1673 |
+
if ( ! empty( $tab['add-event'] ) || ! empty( $tab['edit-event'] ) ) {
|
1674 |
+
if ( function_exists( 'wp_enqueue_code_editor' ) && current_user_can( 'edit_files' ) ) {
|
1675 |
+
$settings = wp_enqueue_code_editor( array(
|
1676 |
+
'type' => 'text/x-php',
|
1677 |
+
) );
|
1678 |
+
|
1679 |
+
if ( false !== $settings ) {
|
1680 |
+
$vars['codeEditor'] = $settings;
|
1681 |
+
}
|
1682 |
+
}
|
1683 |
+
}
|
1684 |
+
|
1685 |
+
wp_localize_script( 'wp-crontrol', 'wpCrontrol', $vars );
|
1686 |
}
|
1687 |
|
1688 |
/**
|
1733 |
'upgrader_scheduled_cleanup',
|
1734 |
'wp_maybe_auto_update',
|
1735 |
'wp_split_shared_term_batch',
|
1736 |
+
'wp_update_comment_type_batch',
|
1737 |
)
|
1738 |
);
|
1739 |
}
|
1748 |
'hourly',
|
1749 |
'twicedaily',
|
1750 |
'daily',
|
1751 |
+
'weekly',
|
1752 |
);
|
1753 |
}
|
1754 |
|