WP Crontrol - Version 1.3

Version Description

  • Improvements to the UI.
  • More error detection when testing WP-Cron functionality.
  • Improve the capability checks for single site and multisite.
  • Lots of escaping and sanitising.
  • Fix various issues with multiple events with the same hook name.
  • Removed the WP-CLI commands, as these have now been added to WP-CLI core (see wp help cron for more info)
Download this release

Release Info

Developer johnbillion
Plugin Icon 128x128 WP Crontrol
Version 1.3
Comparing to
See all releases

Code changes from version 1.2.3 to 1.3

class-wp-cli.php DELETED
@@ -1,173 +0,0 @@
1
- <?php
2
-
3
- /*
4
- @todo add-event
5
- */
6
-
7
- class Crontrol_Command extends WP_CLI_Command {
8
-
9
- protected $crontrol = null;
10
-
11
- public function __construct() {
12
-
13
- $this->crontrol = Crontrol::init();
14
-
15
- }
16
-
17
- /**
18
- * List scheduled cron events.
19
- *
20
- * @since 1.2
21
- *
22
- * @alias list
23
- * @subcommand list-events
24
- * @synopsis [--format=<format>]
25
- */
26
- public function list_events( $args, $assoc_args ) {
27
-
28
- $defaults = array(
29
- 'format' => 'table',
30
- );
31
- $values = wp_parse_args( $assoc_args, $defaults );
32
-
33
- $events = $this->crontrol->get_cron_events();
34
-
35
- if ( is_wp_error( $events ) ) {
36
- WP_CLI::line( WP_CLI::error_to_string( $events ) );
37
- die();
38
- }
39
-
40
- $events = array_map( array( $this, '_map_event' ), $events );
41
-
42
- $fields = array(
43
- 'hook',
44
- 'next_run',
45
- 'recurrence'
46
- );
47
-
48
- \WP_CLI\Utils\format_items( $values['format'], $events, $fields );
49
-
50
- }
51
-
52
- /**
53
- * Run the next scheduled cron event for the given hook.
54
- *
55
- * @since 1.2.2
56
- *
57
- * @synopsis <hook>
58
- * @subcommand run-event
59
- */
60
- public function run_event( $args, $assoc_args ) {
61
-
62
- $hook = $args[0];
63
- $result = false;
64
- $events = $this->crontrol->get_cron_events();
65
-
66
- if ( is_wp_error( $events ) )
67
- WP_CLI::error( $events );
68
-
69
- foreach ( $events as $id => $event ) {
70
- if ( $event->hook == $hook ) {
71
- $result = $this->crontrol->run_cron( $event->hook, $event->sig );
72
- break;
73
- }
74
- }
75
-
76
- if ( $result )
77
- WP_CLI::success( sprintf( __( 'Successfully executed the cron event %s', 'crontrol' ), "'" . $hook . "'" ) );
78
- else
79
- WP_CLI::error( sprintf( __( 'Failed to the execute the cron event %s', 'crontrol' ), "'" . $hook . "'" ) );
80
-
81
- }
82
-
83
- /**
84
- * Delete the next scheduled cron event for the given hook.
85
- *
86
- * @since 1.2.2
87
- *
88
- * @synopsis <hook>
89
- * @subcommand delete-event
90
- */
91
- public function delete_event( $args, $assoc_args ) {
92
-
93
- $hook = $args[0];
94
- $result = false;
95
- $events = $this->crontrol->get_cron_events();
96
-
97
- if ( is_wp_error( $events ) )
98
- WP_CLI::error( $events );
99
-
100
- foreach ( $events as $id => $event ) {
101
- if ( $event->hook == $hook ) {
102
- $result = $this->crontrol->delete_cron( $event->hook, $event->sig, $event->time );
103
- break;
104
- }
105
- }
106
-
107
- if ( $result )
108
- WP_CLI::success( sprintf( __( 'Successfully deleted the cron event %s', 'crontrol' ), "'" . $hook . "'" ) );
109
- else
110
- WP_CLI::error( sprintf( __( 'Failed to the delete the cron event %s', 'crontrol' ), "'" . $hook . "'" ) );
111
-
112
- }
113
-
114
- /**
115
- * List available cron schedules.
116
- *
117
- * @since 1.2
118
- *
119
- * @subcommand list-schedules
120
- * @synopsis [--format=<format>]
121
- */
122
- public function list_schedules( $args, $assoc_args ) {
123
-
124
- $defaults = array(
125
- 'format' => 'table',
126
- );
127
- $values = wp_parse_args( $assoc_args, $defaults );
128
-
129
- $schedules = $this->crontrol->get_schedules();
130
- $schedules = array_map( array( $this, '_map_schedule' ), $schedules, array_keys( $schedules ) );
131
-
132
- $fields = array(
133
- 'name',
134
- 'display',
135
- 'interval'
136
- );
137
-
138
- \WP_CLI\Utils\format_items( $values['format'], $schedules, $fields );
139
-
140
- }
141
-
142
- /**
143
- * Test the WP Cron spawning system and report back any errors.
144
- *
145
- * @since 1.2
146
- */
147
- public function test() {
148
-
149
- $status = $this->crontrol->test_cron_spawn( false );
150
-
151
- if ( is_wp_error( $status ) )
152
- WP_CLI::error( $status );
153
- else
154
- WP_CLI::success( __( 'WP-Cron is working as expected.', 'crontrol' ) );
155
-
156
- }
157
-
158
- protected function _map_event( $event ) {
159
- $time_format = 'Y/m/d H:i:s';
160
- $event->next_run = get_date_from_gmt(date('Y-m-d H:i:s',$event->time),$time_format) . " (".$this->crontrol->time_since(time(), $event->time).")";
161
- $event->recurrence = ($event->schedule ? $this->crontrol->interval($event->interval) : __('Non-repeating', 'crontrol'));
162
- return $event;
163
- }
164
-
165
- protected function _map_schedule( $schedule, $name ) {
166
- $schedule = (object) $schedule;
167
- $schedule->name = $name;
168
- return $schedule;
169
- }
170
-
171
- }
172
-
173
- WP_CLI::add_command( 'crontrol', 'Crontrol_Command' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
gettext/crontrol-de_DE.mo DELETED
Binary file
gettext/crontrol-de_DE.po DELETED
@@ -1,170 +0,0 @@
1
- # German translations for PACKAGE package
2
- # German messages for PACKAGE.
3
- # Copyright (C) 2008 THE PACKAGE'S COPYRIGHT HOLDER
4
- # This file is distributed under the same license as the PACKAGE package.
5
- # Edward Dale <>, 2008.
6
- #
7
- msgid ""
8
- msgstr ""
9
- "Project-Id-Version: PACKAGE VERSION\n"
10
- "Report-Msgid-Bugs-To: \n"
11
- "POT-Creation-Date: 2008-04-25 17:22+0200\n"
12
- "PO-Revision-Date: 2008-04-25 17:27+0200\n"
13
- "Last-Translator: Edward Dale <>\n"
14
- "Language-Team: German\n"
15
- "MIME-Version: 1.0\n"
16
- "Content-Type: text/plain; charset=UTF-8\n"
17
- "Content-Transfer-Encoding: 8bit\n"
18
- "Plural-Forms: nplurals=2; plural=(n != 1);\n"
19
-
20
- #: wp-crontrol.php:102 wp-crontrol.php:111
21
- msgid "You are not allowed to add new cron events."
22
- msgstr ""
23
-
24
- #: wp-crontrol.php:122
25
- msgid "You are not allowed to add new cron schedules."
26
- msgstr ""
27
-
28
- #: wp-crontrol.php:147
29
- msgid "You are not allowed to delete cron schedules."
30
- msgstr ""
31
-
32
- #: wp-crontrol.php:154
33
- msgid "You are not allowed to delete cron events."
34
- msgstr ""
35
-
36
- #: wp-crontrol.php:161
37
- msgid "You are not allowed to run cron events."
38
- msgstr ""
39
-
40
- #: wp-crontrol.php:218
41
- msgid "Twice Daily"
42
- msgstr ""
43
-
44
- #: wp-crontrol.php:258
45
- msgid "Successfully deleted the cron schedule <b>%s</b>"
46
- msgstr "Cron Zeitplan <b>%s</b> erfolgreich gel&ouml;scht"
47
-
48
- #: wp-crontrol.php:269
49
- msgid "Cron Schedules"
50
- msgstr "Cron Zeitpl&auml;ne"
51
-
52
- #: wp-crontrol.php:270
53
- msgid ""
54
- "Cron schedules are the time intervals that are available to WordPress and "
55
- "plugin developers to schedule events. You can only delete cron schedules "
56
- "that you have created with WP-Crontrol."
57
- msgstr ""
58
-
59
- #: wp-crontrol.php:275
60
- msgid "Name"
61
- msgstr "Name"
62
-
63
- #: wp-crontrol.php:276 wp-crontrol.php:311
64
- msgid "Interval"
65
- msgstr "Intervall"
66
-
67
- #: wp-crontrol.php:277
68
- msgid "Display Name"
69
- msgstr ""
70
-
71
- #: wp-crontrol.php:278 wp-crontrol.php:354
72
- msgid "Actions"
73
- msgstr ""
74
-
75
- #: wp-crontrol.php:301
76
- msgid "Add new cron schedule"
77
- msgstr ""
78
-
79
- #: wp-crontrol.php:302
80
- msgid ""
81
- "Adding a new cron schedule will allow you to schedule events that re-occur "
82
- "at the given interval."
83
- msgstr ""
84
-
85
- #: wp-crontrol.php:307
86
- msgid "Internal name"
87
- msgstr ""
88
-
89
- #: wp-crontrol.php:315
90
- msgid "Display name"
91
- msgstr ""
92
-
93
- #: wp-crontrol.php:319
94
- msgid "Add Cron Schedule &raquo;"
95
- msgstr ""
96
-
97
- #: wp-crontrol.php:331
98
- msgid "Successfully executed the cron entry <b>%s</b>"
99
- msgstr "Cron Eintrag <b>%s</b> erfolgreich ausgef&uuml;hrt"
100
-
101
- #: wp-crontrol.php:332
102
- msgid "Successfully edited the cron entry <b>%s</b>"
103
- msgstr "Cron Eintrag <b>%s</b> erfolgreich bearbeitet"
104
-
105
- #: wp-crontrol.php:333
106
- msgid "Successfully created the cron entry <b>%s</b>"
107
- msgstr "Cron Eintrag <b>%s</b> erfolgreich geschaffen"
108
-
109
- #: wp-crontrol.php:334
110
- msgid "Successfully deleted the cron entry <b>%s</b>"
111
- msgstr "Cron Eintrag <b>%s</b> erfolgreich gel&ouml;scht"
112
-
113
- #: wp-crontrol.php:345
114
- msgid "WP-Cron Entries"
115
- msgstr "WP-Cron Eintr&auml;ge"
116
-
117
- #: wp-crontrol.php:351
118
- msgid "Hook Name"
119
- msgstr ""
120
-
121
- #: wp-crontrol.php:352
122
- msgid "Next Run"
123
- msgstr ""
124
-
125
- #: wp-crontrol.php:353
126
- msgid "Recurrence"
127
- msgstr ""
128
-
129
- #: wp-crontrol.php:386
130
- msgid "Edit cron entry"
131
- msgstr ""
132
-
133
- #: wp-crontrol.php:386
134
- msgid "Add new"
135
- msgstr ""
136
-
137
- #: wp-crontrol.php:392 wp-crontrol.php:422
138
- msgid "Hook name"
139
- msgstr ""
140
-
141
- #: wp-crontrol.php:395 wp-crontrol.php:425
142
- msgid "Next run"
143
- msgstr ""
144
-
145
- #: wp-crontrol.php:398 wp-crontrol.php:428
146
- msgid "Entry schedule"
147
- msgstr ""
148
-
149
- #: wp-crontrol.php:411
150
- msgid "Modify Cron Entry &raquo;"
151
- msgstr ""
152
-
153
- #: wp-crontrol.php:416
154
- msgid "Add new cron entry"
155
- msgstr ""
156
-
157
- #: wp-crontrol.php:417
158
- msgid ""
159
- "Cron entries trigger actions in your code. After adding a new cron entry "
160
- "here, you will need to add a corresponding action hook somewhere in code, "
161
- "perhaps the <code>functions.php</code> file in your theme."
162
- msgstr ""
163
-
164
- #: wp-crontrol.php:440
165
- msgid "Add Cron Entry &raquo;"
166
- msgstr ""
167
-
168
- #: wp-crontrol.php:471
169
- msgid "now"
170
- msgstr "jetzt"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
gettext/crontrol.pot DELETED
@@ -1,298 +0,0 @@
1
- # SOME DESCRIPTIVE TITLE.
2
- # Copyright (C) YEAR Edward Dale
3
- # This file is distributed under the same license as the PACKAGE package.
4
- # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5
- #
6
- #, fuzzy
7
- msgid ""
8
- msgstr ""
9
- "Project-Id-Version: PACKAGE VERSION\n"
10
- "Report-Msgid-Bugs-To: http://wordpress.org/tag/wp-crontrol\n"
11
- "POT-Creation-Date: 2008-06-02 07:15+0000\n"
12
- "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13
- "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
- "Language-Team: LANGUAGE <LL@li.org>\n"
15
- "MIME-Version: 1.0\n"
16
- "Content-Type: text/plain; charset=CHARSET\n"
17
- "Content-Transfer-Encoding: 8bit\n"
18
- "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
19
-
20
- #: wp-crontrol.php:88 wp-crontrol.php:96
21
- msgid "You are not allowed to add new cron events."
22
- msgstr ""
23
-
24
- #: wp-crontrol.php:106
25
- msgid "You are not allowed to add new cron schedules."
26
- msgstr ""
27
-
28
- #: wp-crontrol.php:131
29
- msgid "You are not allowed to delete cron schedules."
30
- msgstr ""
31
-
32
- #: wp-crontrol.php:138
33
- msgid "You are not allowed to delete cron events."
34
- msgstr ""
35
-
36
- #: wp-crontrol.php:150
37
- msgid "You are not allowed to run cron events."
38
- msgstr ""
39
-
40
- #: wp-crontrol.php:256
41
- msgid "Twice Daily"
42
- msgstr ""
43
-
44
- #: wp-crontrol.php:301
45
- #, php-format
46
- msgid "Successfully deleted the cron schedule <b>%s</b>"
47
- msgstr ""
48
-
49
- #: wp-crontrol.php:302
50
- #, php-format
51
- msgid "Successfully added the cron schedule <b>%s</b>"
52
- msgstr ""
53
-
54
- #: wp-crontrol.php:303
55
- #, php-format
56
- msgid "Cron schedule not added because there was a problem parsing <b>%s</b>"
57
- msgstr ""
58
-
59
- #: wp-crontrol.php:312
60
- msgid "Cron Schedules"
61
- msgstr ""
62
-
63
- #: wp-crontrol.php:313
64
- msgid ""
65
- "Cron schedules are the time intervals that are available to WordPress and "
66
- "plugin developers to schedule events. You can only delete cron schedules "
67
- "that you have created with WP-Crontrol."
68
- msgstr ""
69
-
70
- #: wp-crontrol.php:318
71
- msgid "Name"
72
- msgstr ""
73
-
74
- #: wp-crontrol.php:319 wp-crontrol.php:361
75
- msgid "Interval"
76
- msgstr ""
77
-
78
- #: wp-crontrol.php:320
79
- msgid "Display Name"
80
- msgstr ""
81
-
82
- #: wp-crontrol.php:321 wp-crontrol.php:419
83
- msgid "Actions"
84
- msgstr ""
85
-
86
- #: wp-crontrol.php:328
87
- msgid "You currently have no cron schedules. Add one below!"
88
- msgstr ""
89
-
90
- #: wp-crontrol.php:338
91
- #, php-format
92
- msgid ""
93
- "You are about to delete the schedule '%s'.\n"
94
- "'OK' to delete, 'Cancel' to stop."
95
- msgstr ""
96
-
97
- #: wp-crontrol.php:338
98
- msgid "Delete"
99
- msgstr ""
100
-
101
- #: wp-crontrol.php:351
102
- msgid "Add new cron schedule"
103
- msgstr ""
104
-
105
- #: wp-crontrol.php:352
106
- msgid ""
107
- "Adding a new cron schedule will allow you to schedule events that re-occur "
108
- "at the given interval."
109
- msgstr ""
110
-
111
- #: wp-crontrol.php:357
112
- msgid "Internal name"
113
- msgstr ""
114
-
115
- #: wp-crontrol.php:365
116
- msgid "Display name"
117
- msgstr ""
118
-
119
- #: wp-crontrol.php:369
120
- msgid "Add Cron Schedule &raquo;"
121
- msgstr ""
122
-
123
- #: wp-crontrol.php:393
124
- #, php-format
125
- msgid "Successfully executed the cron entry <b>%s</b>"
126
- msgstr ""
127
-
128
- #: wp-crontrol.php:394
129
- #, php-format
130
- msgid "Successfully edited the cron entry <b>%s</b>"
131
- msgstr ""
132
-
133
- #: wp-crontrol.php:395
134
- #, php-format
135
- msgid "Successfully created the cron entry <b>%s</b>"
136
- msgstr ""
137
-
138
- #: wp-crontrol.php:396
139
- #, php-format
140
- msgid "Successfully deleted the cron entry <b>%s</b>"
141
- msgstr ""
142
-
143
- #: wp-crontrol.php:397
144
- #, php-format
145
- msgid "Failed to the delete the cron entry <b>%s</b>"
146
- msgstr ""
147
-
148
- #: wp-crontrol.php:398
149
- #, php-format
150
- msgid "Failed to the execute the cron entry <b>%s</b>"
151
- msgstr ""
152
-
153
- #: wp-crontrol.php:410
154
- msgid "WP-Cron Entries"
155
- msgstr ""
156
-
157
- #: wp-crontrol.php:415
158
- msgid "Hook Name"
159
- msgstr ""
160
-
161
- #: wp-crontrol.php:416 wp-crontrol.php:472 wp-crontrol.php:502
162
- msgid "Arguments"
163
- msgstr ""
164
-
165
- #: wp-crontrol.php:417
166
- msgid "Next Run"
167
- msgstr ""
168
-
169
- #: wp-crontrol.php:418
170
- msgid "Recurrence"
171
- msgstr ""
172
-
173
- #: wp-crontrol.php:426
174
- msgid "You currently have no cron entries. Add one below!"
175
- msgstr ""
176
-
177
- #: wp-crontrol.php:461
178
- msgid "Edit cron entry"
179
- msgstr ""
180
-
181
- #: wp-crontrol.php:461
182
- msgid "Add new"
183
- msgstr ""
184
-
185
- #: wp-crontrol.php:469 wp-crontrol.php:499
186
- msgid "Hook name"
187
- msgstr ""
188
-
189
- #: wp-crontrol.php:472 wp-crontrol.php:502
190
- msgid "e.g., [], [25], [\"asdf\"], or [\"i\",\"want\",25,\"cakes\"]"
191
- msgstr ""
192
-
193
- #: wp-crontrol.php:475 wp-crontrol.php:505
194
- msgid "Next run"
195
- msgstr ""
196
-
197
- #: wp-crontrol.php:478 wp-crontrol.php:508
198
- msgid "Entry schedule"
199
- msgstr ""
200
-
201
- #: wp-crontrol.php:484
202
- msgid "Modify Cron Entry &raquo;"
203
- msgstr ""
204
-
205
- #: wp-crontrol.php:490
206
- #, php-format
207
- msgid "Could not load cron entry <b>%s</b>"
208
- msgstr ""
209
-
210
- #: wp-crontrol.php:493
211
- msgid "Add new cron entry"
212
- msgstr ""
213
-
214
- #: wp-crontrol.php:494
215
- msgid ""
216
- "Cron entries trigger actions in your code. After adding a new cron entry "
217
- "here, you will need to add a corresponding action hook somewhere in code, "
218
- "perhaps the <code>functions.php</code> file in your theme."
219
- msgstr ""
220
-
221
- #: wp-crontrol.php:514
222
- msgid "Add Cron Entry &raquo;"
223
- msgstr ""
224
-
225
- #: wp-crontrol.php:535
226
- #, php-format
227
- msgid "%s year"
228
- msgid_plural "%s years"
229
- msgstr[0] ""
230
- msgstr[1] ""
231
-
232
- #: wp-crontrol.php:536
233
- #, php-format
234
- msgid "%s month"
235
- msgid_plural "%s months"
236
- msgstr[0] ""
237
- msgstr[1] ""
238
-
239
- #: wp-crontrol.php:537
240
- #, php-format
241
- msgid "%s week"
242
- msgid_plural "%s weeks"
243
- msgstr[0] ""
244
- msgstr[1] ""
245
-
246
- #: wp-crontrol.php:538
247
- #, php-format
248
- msgid "%s day"
249
- msgid_plural "%s days"
250
- msgstr[0] ""
251
- msgstr[1] ""
252
-
253
- #: wp-crontrol.php:539
254
- #, php-format
255
- msgid "%s hour"
256
- msgid_plural "%s hours"
257
- msgstr[0] ""
258
- msgstr[1] ""
259
-
260
- #: wp-crontrol.php:540
261
- #, php-format
262
- msgid "%s minute"
263
- msgid_plural "%s minutes"
264
- msgstr[0] ""
265
- msgstr[1] ""
266
-
267
- #: wp-crontrol.php:541
268
- #, php-format
269
- msgid "%s second"
270
- msgid_plural "%s seconds"
271
- msgstr[0] ""
272
- msgstr[1] ""
273
-
274
- #: wp-crontrol.php:546
275
- msgid "now"
276
- msgstr ""
277
-
278
- #. Plugin Name of an extension
279
- msgid "WP-Crontrol"
280
- msgstr ""
281
-
282
- #. Plugin URI of an extension
283
- msgid "http://www.scompt.com/projects/wp-crontrol"
284
- msgstr ""
285
-
286
- #. Description of an extension
287
- msgid ""
288
- "WP-Crontrol lets you take control over what's happening in the WP-Cron "
289
- "system."
290
- msgstr ""
291
-
292
- #. Author of an extension
293
- msgid "Edward Dale"
294
- msgstr ""
295
-
296
- #. Author URI of an extension
297
- msgid "http://www.scompt.com"
298
- msgstr ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
languages/wp-crontrol.pot ADDED
@@ -0,0 +1,351 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (C) 2015 John Blackbourn & Edward Dale
2
+ # This file is distributed under the GPL v2 or later.
3
+ msgid ""
4
+ msgstr ""
5
+ "Project-Id-Version: WP Crontrol 1.3\n"
6
+ "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/wp-crontrol\n"
7
+ "POT-Creation-Date: 2015-10-02 12:38:03+00:00\n"
8
+ "MIME-Version: 1.0\n"
9
+ "Content-Type: text/plain; charset=utf-8\n"
10
+ "Content-Transfer-Encoding: 8bit\n"
11
+ "PO-Revision-Date: 2015-MO-DA HO:MI+ZONE\n"
12
+ "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13
+ "Language-Team: LANGUAGE <LL@li.org>\n"
14
+ "X-Generator: grunt-wp-i18n 0.5.3\n"
15
+ "X-Poedit-KeywordsList: "
16
+ "__;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;_n_noop:1,2;_nx_noop:1,2,3c;esc_"
17
+ "attr__;esc_html__;esc_attr_e;esc_html_e;esc_attr_x:1,2c;esc_html_x:1,2c;\n"
18
+ "Language: en\n"
19
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
20
+ "X-Poedit-Country: United States\n"
21
+ "X-Poedit-SourceCharset: UTF-8\n"
22
+ "X-Poedit-Basepath: ../\n"
23
+ "X-Poedit-SearchPath-0: .\n"
24
+ "X-Poedit-Bookmarks: \n"
25
+ "X-Textdomain-Support: yes\n"
26
+
27
+ #: wp-crontrol.php:84
28
+ msgid "You are not allowed to add new cron events."
29
+ msgstr ""
30
+
31
+ #: wp-crontrol.php:98
32
+ msgid "You are not allowed to add new PHP cron events."
33
+ msgstr ""
34
+
35
+ #: wp-crontrol.php:112 wp-crontrol.php:128
36
+ msgid "You are not allowed to edit cron events."
37
+ msgstr ""
38
+
39
+ #: wp-crontrol.php:145
40
+ msgid "You are not allowed to add new cron schedules."
41
+ msgstr ""
42
+
43
+ #: wp-crontrol.php:186
44
+ msgid "You are not allowed to delete cron schedules."
45
+ msgstr ""
46
+
47
+ #: wp-crontrol.php:199
48
+ msgid "You are not allowed to delete cron events."
49
+ msgstr ""
50
+
51
+ #: wp-crontrol.php:224
52
+ msgid "You are not allowed to run cron events."
53
+ msgstr ""
54
+
55
+ #: wp-crontrol.php:347 wp-crontrol.php:360
56
+ msgid "Cron Schedules"
57
+ msgstr ""
58
+
59
+ #: wp-crontrol.php:348 wp-crontrol.php:355
60
+ msgid "Cron Events"
61
+ msgstr ""
62
+
63
+ #: wp-crontrol.php:387
64
+ msgid "Successfully deleted the cron schedule %s."
65
+ msgstr ""
66
+
67
+ #: wp-crontrol.php:388
68
+ msgid "Successfully added the cron schedule %s."
69
+ msgstr ""
70
+
71
+ #: wp-crontrol.php:389
72
+ msgid "Cron schedule not added because there was a problem parsing %s."
73
+ msgstr ""
74
+
75
+ #: wp-crontrol.php:400
76
+ msgid "WP-Cron Schedules"
77
+ msgstr ""
78
+
79
+ #: wp-crontrol.php:401
80
+ msgid ""
81
+ "WP-Cron schedules are the time intervals that are available for scheduling "
82
+ "events. You can only delete custom schedules."
83
+ msgstr ""
84
+
85
+ #: wp-crontrol.php:406
86
+ msgid "Name"
87
+ msgstr ""
88
+
89
+ #: wp-crontrol.php:407
90
+ msgid "Interval"
91
+ msgstr ""
92
+
93
+ #: wp-crontrol.php:408
94
+ msgid "Display Name"
95
+ msgstr ""
96
+
97
+ #: wp-crontrol.php:416
98
+ msgid "You currently have no schedules. Add one below."
99
+ msgstr ""
100
+
101
+ #: wp-crontrol.php:442 wp-crontrol.php:829
102
+ msgid "Delete"
103
+ msgstr ""
104
+
105
+ #: wp-crontrol.php:455
106
+ msgid "Add new cron schedule"
107
+ msgstr ""
108
+
109
+ #: wp-crontrol.php:456
110
+ msgid ""
111
+ "Adding a new cron schedule will allow you to schedule events that re-occur "
112
+ "at the given interval."
113
+ msgstr ""
114
+
115
+ #: wp-crontrol.php:461
116
+ msgid "Internal name"
117
+ msgstr ""
118
+
119
+ #: wp-crontrol.php:465
120
+ msgid "Interval (seconds)"
121
+ msgstr ""
122
+
123
+ #: wp-crontrol.php:469
124
+ msgid "Display name"
125
+ msgstr ""
126
+
127
+ #: wp-crontrol.php:473
128
+ msgid "Add Cron Schedule"
129
+ msgstr ""
130
+
131
+ #: wp-crontrol.php:498 wp-crontrol.php:797
132
+ msgid "Non-repeating"
133
+ msgstr ""
134
+
135
+ #: wp-crontrol.php:519
136
+ msgid "The DISABLE_WP_CRON constant is set to true. WP-Cron spawning is disabled."
137
+ msgstr ""
138
+
139
+ #: wp-crontrol.php:551
140
+ msgid "Unexpected HTTP response code: %s"
141
+ msgstr ""
142
+
143
+ #: wp-crontrol.php:572
144
+ msgid ""
145
+ "There was a problem spawning a call to the WP-Cron system on your site. "
146
+ "This means WP-Cron events on your site may not work. The problem was: %s"
147
+ msgstr ""
148
+
149
+ #: wp-crontrol.php:587
150
+ msgid "Add Cron Event"
151
+ msgstr ""
152
+
153
+ #: wp-crontrol.php:588
154
+ msgid "Add PHP Cron Event"
155
+ msgstr ""
156
+
157
+ #: wp-crontrol.php:591
158
+ msgid "Modify Cron Event"
159
+ msgstr ""
160
+
161
+ #: wp-crontrol.php:592
162
+ msgid "Modify PHP Cron Event"
163
+ msgstr ""
164
+
165
+ #: wp-crontrol.php:599
166
+ msgid ""
167
+ "Cron events trigger actions in your code. Using the form below, you can "
168
+ "enter the schedule of the action, as well as the PHP code for the action "
169
+ "itself."
170
+ msgstr ""
171
+
172
+ #: wp-crontrol.php:602
173
+ msgid ""
174
+ "Cron events trigger actions in your code. A cron event added using the form "
175
+ "below needs a corresponding action hook somewhere in code, perhaps the %1$s "
176
+ "file in your theme."
177
+ msgstr ""
178
+
179
+ #: wp-crontrol.php:646
180
+ msgid "Hook code:"
181
+ msgstr ""
182
+
183
+ #: wp-crontrol.php:651
184
+ msgid "Hook name:"
185
+ msgstr ""
186
+
187
+ #: wp-crontrol.php:655
188
+ msgid "Arguments:"
189
+ msgstr ""
190
+
191
+ #: wp-crontrol.php:658
192
+ msgid "e.g. [25], ['asdf'], or ['i','want',25,'cakes']"
193
+ msgstr ""
194
+
195
+ #: wp-crontrol.php:663
196
+ msgid "Next run (UTC):"
197
+ msgstr ""
198
+
199
+ #: wp-crontrol.php:666
200
+ msgid "e.g. 'now', 'tomorrow', '+2 days', or '25-02-2020 12:34:00'"
201
+ msgstr ""
202
+
203
+ #: wp-crontrol.php:669
204
+ msgid "Event schedule:"
205
+ msgstr ""
206
+
207
+ #: wp-crontrol.php:689
208
+ msgid "You currently have no scheduled cron events."
209
+ msgstr ""
210
+
211
+ #: wp-crontrol.php:720
212
+ msgid "Successfully executed the cron event %s"
213
+ msgstr ""
214
+
215
+ #: wp-crontrol.php:721
216
+ msgid "Successfully edited the cron event %s"
217
+ msgstr ""
218
+
219
+ #: wp-crontrol.php:722
220
+ msgid "Successfully created the cron event %s"
221
+ msgstr ""
222
+
223
+ #: wp-crontrol.php:723
224
+ msgid "Successfully deleted the cron event %s"
225
+ msgstr ""
226
+
227
+ #: wp-crontrol.php:724
228
+ msgid "Failed to the delete the cron event %s"
229
+ msgstr ""
230
+
231
+ #: wp-crontrol.php:725
232
+ msgid "Failed to the execute the cron event %s"
233
+ msgstr ""
234
+
235
+ #: wp-crontrol.php:752
236
+ msgid "WP-Cron Events"
237
+ msgstr ""
238
+
239
+ #: wp-crontrol.php:757
240
+ msgid "Hook Name"
241
+ msgstr ""
242
+
243
+ #: wp-crontrol.php:758
244
+ msgid "Arguments"
245
+ msgstr ""
246
+
247
+ #: wp-crontrol.php:759
248
+ msgid "Next Run"
249
+ msgstr ""
250
+
251
+ #: wp-crontrol.php:760
252
+ msgid "Recurrence"
253
+ msgstr ""
254
+
255
+ #: wp-crontrol.php:784
256
+ msgid "None"
257
+ msgstr ""
258
+
259
+ #: wp-crontrol.php:794
260
+ msgid "PHP Cron"
261
+ msgstr ""
262
+
263
+ #: wp-crontrol.php:795
264
+ msgid "PHP Code"
265
+ msgstr ""
266
+
267
+ #: wp-crontrol.php:807
268
+ msgid "Edit"
269
+ msgstr ""
270
+
271
+ #: wp-crontrol.php:818
272
+ msgid "Run Now"
273
+ msgstr ""
274
+
275
+ #: wp-crontrol.php:841
276
+ msgid "Local timezone is %s"
277
+ msgstr ""
278
+
279
+ #: wp-crontrol.php:842
280
+ msgid "UTC time is %s"
281
+ msgstr ""
282
+
283
+ #: wp-crontrol.php:843
284
+ msgid "Local time is %s"
285
+ msgstr ""
286
+
287
+ #: wp-crontrol.php:871
288
+ msgid "%s year"
289
+ msgid_plural "%s years"
290
+ msgstr[0] ""
291
+ msgstr[1] ""
292
+
293
+ #: wp-crontrol.php:872
294
+ msgid "%s month"
295
+ msgid_plural "%s months"
296
+ msgstr[0] ""
297
+ msgstr[1] ""
298
+
299
+ #: wp-crontrol.php:873
300
+ msgid "%s week"
301
+ msgid_plural "%s weeks"
302
+ msgstr[0] ""
303
+ msgstr[1] ""
304
+
305
+ #: wp-crontrol.php:874
306
+ msgid "%s day"
307
+ msgid_plural "%s days"
308
+ msgstr[0] ""
309
+ msgstr[1] ""
310
+
311
+ #: wp-crontrol.php:875
312
+ msgid "%s hour"
313
+ msgid_plural "%s hours"
314
+ msgstr[0] ""
315
+ msgstr[1] ""
316
+
317
+ #: wp-crontrol.php:876
318
+ msgid "%s minute"
319
+ msgid_plural "%s minutes"
320
+ msgstr[0] ""
321
+ msgstr[1] ""
322
+
323
+ #: wp-crontrol.php:877
324
+ msgid "%s second"
325
+ msgid_plural "%s seconds"
326
+ msgstr[0] ""
327
+ msgstr[1] ""
328
+
329
+ #: wp-crontrol.php:882
330
+ msgid "now"
331
+ msgstr ""
332
+
333
+ #. Plugin Name of the plugin/theme
334
+ msgid "WP Crontrol"
335
+ msgstr ""
336
+
337
+ #. Plugin URI of the plugin/theme
338
+ msgid "https://wordpress.org/plugins/wp-crontrol/"
339
+ msgstr ""
340
+
341
+ #. Description of the plugin/theme
342
+ msgid ""
343
+ "WP Crontrol lets you view and control what's happening in the WP-Cron "
344
+ "system."
345
+ msgstr ""
346
+
347
+ #. Author of the plugin/theme
348
+ msgid ""
349
+ "<a href=\"https://johnblackbourn.com/\">John Blackbourn</a> & <a "
350
+ "href=\"http://www.scompt.com/\">Edward Dale</a>"
351
+ msgstr ""
readme.txt CHANGED
@@ -1,25 +1,27 @@
1
  === WP Crontrol ===
2
- Contributors: scompt, johnbillion
3
- Tags: admin, cron, plugin, control, wp-cron, crontrol, wp-cli
4
- Requires at least: 3.0
5
- Tested up to: 4.0
6
- Stable tag: 1.2.3
7
 
8
  WP Crontrol lets you view and control what's happening in the WP-Cron system.
9
 
10
  == Description ==
11
 
12
- WP Crontrol lets you view and control what's happening in the WP-Cron system. From the admin screen you can:
13
 
14
- * View all cron events along with their arguments, recurrence and when they are next due.
15
  * Edit, delete, and immediately run any cron events.
16
  * Add new cron events.
 
17
 
18
  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).
19
 
20
- From the settings screen you can also add, edit and remove cron schedules.
21
 
22
- WP Crontrol includes commands for [WP-CLI](http://wp-cli.org/). See the FAQ or type `wp help crontrol` for more details.
 
23
 
24
  == Installation ==
25
 
@@ -34,65 +36,58 @@ Alternatively, see the guide to [Manually Installing Plugins](http://codex.wordp
34
 
35
  = Usage =
36
 
37
- 1. Go to the Tools -> Crontrol menu to see what cron events are scheduled and to add some new ones.
38
- 2. Go to the Settings -> Cron Schedules menu to add new cron schedules.
39
 
40
  == Frequently Asked Questions ==
41
 
42
  = What's the use of adding new cron schedules? =
43
 
44
- Cron schedules are used by WordPress and WordPress plugins to allow you to schedule events to be executed at regular intervals. Intervals must be provided by the WordPress core or a plugin in order to be used. An example of a plugin that uses these schedules is [WordPress Database Backup](http://www.ilfilosofo.com/blog/wp-db-backup/). Out of the box, only daily and hourly backups are supported. In order to do a weekly backup, a weekly cron schedule must be entered into WP Crontrol first and then the backup plugin can take advantage of it as an interval.
45
 
46
  = How do I create a new PHP cron event? =
47
 
48
- In the Tools -> Crontrol admin panel, click on the "Add new PHP event" link underneath the cron event table. In the form that appears, enter the schedule and next run time in the boxes. Next run is the next time that the hook will execute. This can be entered in using [GNU Date Input Formats](http://www.gnu.org/software/tar/manual/html_node/tar_113.html), but often *now* is good enough. 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. 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`).
49
 
50
  = How do I create a new regular cron event? =
51
 
52
- 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 your function when your hook is executed. You've got to do that on your own, but I'll explain how below.
53
 
54
  *Step One: Adding the hook*
55
 
56
- In the Tools -> Crontrol admin panel, enter the details of the hook. You're best off having a hookname that conforms to normal PHP variable naming conventions. This could save you trouble later. Other than that, the hookname can be whatever you want it to be. Next run is the next time that the hook will execute. This can be entered in using [GNU Date Input Formats](http://www.gnu.org/software/tar/manual/html_node/tar_113.html), but often *now* is good enough. 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.
57
 
58
  *Step Two: Writing the function*
59
 
60
- This part takes place in PHP code (for example, in the `functions.php` file from your theme). To execute your hook, WordPress runs an [action](http://codex.wordpress.org/Plugin_API#Actions). For this reason, we need to now tell WordPress which function to execute when this action is run. The following line accomplishes that:
61
 
62
- `add_action('my_hookname', 'my_function');`
63
 
64
- The next step is to write your function. Here's a simple example:
65
 
66
  `function my_function() {
67
- wp_mail('hello@example.com', 'WP Crontrol', 'WP Crontrol rocks!');
68
  }`
69
 
70
- = Do I really need the entire `wp-crontrol` directory? =
71
-
72
- No, you can get rid of the whole directory and just use `wp-crontrol.php` if you wish. If you want to use WP-CLI then you'll need to include `class-wp-cli.php` too.
73
-
74
- = Which WP-CLI commands are available? =
75
 
76
- * `wp crontrol list-events` Lists the scheduled events on your site.
77
- * `wp crontrol run-event <hook>` Runs the next scheduled WP-Cron event for the given hook
78
- * `wp crontrol delete-event <hook>` Deletes the next scheduled WP-Cron event for the given hook
79
- * `wp crontrol list-schedules` Lists the available WP-Cron schedules on your site.
80
- * `wp crontrol test` Performs a WP-Cron spawning test to make sure WP-Cron can function as expected.
81
-
82
- Note that WP-CLI support is a work in progress and will be improved over time. Feedback welcome!
83
 
84
  == Screenshots ==
85
 
86
- 1. New cron events can be added, modified, and deleted. In addition, they can be executed on-demand.
87
- 1. New cron schedules can be added to WordPress, giving plugin developers more options when scheduling events.
88
-
89
- == Upgrade Notice ==
90
-
91
- = 1.2.2 =
92
- * Added `wp crontrol run-event` and `wp crontrol delete-event` WP-CLI commands
93
 
94
  == Changelog ==
95
 
 
 
 
 
 
 
 
 
96
  = 1.2.3 =
97
  * Tweaks to i18n and date and args formatting
98
  * Properly escape the `crontrol_message` query var (props Julio Potier)
1
  === WP Crontrol ===
2
+ Contributors: johnbillion, scompt
3
+ Tags: admin, cron, plugin, control, wp-cron, crontrol
4
+ Requires at least: 4.0
5
+ Tested up to: 4.5
6
+ Stable tag: 1.3
7
 
8
  WP Crontrol lets you view and control what's happening in the WP-Cron system.
9
 
10
  == Description ==
11
 
12
+ WP Crontrol lets you view and control what's happening in the WP-Cron system. From the admin screens you can:
13
 
14
+ * View all cron events along with their arguments, recurrence, 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).
20
 
21
+ = Usage =
22
 
23
+ 1. Go to the Tools -> Cron Events menu to manage cron events.
24
+ 2. Go to the Settings -> Cron Schedules menu to manage cron schedules.
25
 
26
  == Installation ==
27
 
36
 
37
  = Usage =
38
 
39
+ 1. Go to the Tools -> Cron Events menu to manage cron events.
40
+ 2. Go to the Settings -> Cron Schedules menu to manage cron schedules.
41
 
42
  == Frequently Asked Questions ==
43
 
44
  = What's the use of adding new cron schedules? =
45
 
46
+ 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.
47
 
48
  = How do I create a new PHP cron event? =
49
 
50
+ In the Tools -> Cron Events admin panel, click on the "Add PHP Cron Event" tab underneath the cron event table. In the form that appears, enter the schedule and next run time in the boxes. 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`).
51
 
52
  = How do I create a new regular cron event? =
53
 
54
+ 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.
55
 
56
  *Step One: Adding the hook*
57
 
58
+ In the Tools -> Cron Events admin panel, enter the details of the hook. You're best off having a hookname 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.
59
 
60
  *Step Two: Writing the function*
61
 
62
+ This part takes place in PHP code (for example, in the `functions.php` file from your theme). To execute your hook, WordPress runs an [action](https://codex.wordpress.org/Plugin_API#Actions). For this reason, we need to tell WordPress which function to execute when this action is run. The following line accomplishes that:
63
 
64
+ `add_action( 'my_hookname', 'my_function' );`
65
 
66
+ The next step is to write your function. Here's a simple example:
67
 
68
  `function my_function() {
69
+ wp_mail( 'hello@example.com', 'WP Crontrol', 'WP Crontrol rocks!' );
70
  }`
71
 
72
+ = Are any WP-CLI commands available? =
 
 
 
 
73
 
74
+ 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.
 
 
 
 
 
 
75
 
76
  == Screenshots ==
77
 
78
+ 1. New cron events can be added, modified, deleted, and executed.
79
+ 2. New cron schedules can be added, giving plugin developers more options when scheduling events.
 
 
 
 
 
80
 
81
  == Changelog ==
82
 
83
+ = 1.3 =
84
+ * Improvements to the UI.
85
+ * More error detection when testing WP-Cron functionality.
86
+ * Improve the capability checks for single site and multisite.
87
+ * Lots of escaping and sanitising.
88
+ * Fix various issues with multiple events with the same hook name.
89
+ * Removed the WP-CLI commands, as these have now been added to WP-CLI core (see `wp help cron` for more info)
90
+
91
  = 1.2.3 =
92
  * Tweaks to i18n and date and args formatting
93
  * Properly escape the `crontrol_message` query var (props Julio Potier)
wp-crontrol.php CHANGED
@@ -3,417 +3,554 @@
3
  * Plugin Name: WP Crontrol
4
  * Plugin URI: https://wordpress.org/plugins/wp-crontrol/
5
  * Description: WP Crontrol lets you view and control what's happening in the WP-Cron system.
6
- * Author: <a href="http://www.scompt.com/">Edward Dale</a> & <a href="https://johnblackbourn.com/">John Blackbourn</a>
7
- * Version: 1.2.3
8
  * Text Domain: wp-crontrol
9
- * Domain Path: /gettext/
 
10
  */
11
 
12
- /**
13
- * WP Crontrol lets you take control over what's happening in the WP-Cron system.
14
- *
15
- * LICENSE
16
- * This file is part of WP Crontrol.
17
- *
18
- * WP Crontrol is free software; you can redistribute it and/or
19
- * modify it under the terms of the GNU General Public License
20
- * as published by the Free Software Foundation; either version 2
21
- * of the License, or (at your option) any later version.
22
- *
23
- * This program is distributed in the hope that it will be useful,
24
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
25
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26
- * GNU General Public License for more details.
27
- *
28
- * You should have received a copy of the GNU General Public License
29
- * along with this program; if not, write to the Free Software
30
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
31
- *
32
- * @package WP Crontrol
33
- * @author Edward Dale <scompt@scompt.com> & John Blackbourn <john@johnblackbourn.com>
34
- * @copyright Copyright 2013 Edward Dale & John Blackbourn
35
- * @license http://www.gnu.org/licenses/gpl.txt GPL 2.0
36
- * @link https://wordpress.org/plugins/wp-crontrol/
37
- * @since 0.2
38
- */
39
 
40
  defined( 'ABSPATH' ) or die();
41
 
42
  class Crontrol {
43
 
44
- /**
45
- * Hook onto all of the actions and filters needed by the plugin.
46
- */
47
- protected function __construct() {
48
- add_action('init', array($this, 'action_init'));
49
- add_action('init', array($this, 'action_handle_posts'));
50
- add_action('admin_menu', array($this, 'action_admin_menu'));
51
-
52
- register_activation_hook( __FILE__, array($this, 'action_activate') );
53
-
54
- add_filter('cron_schedules', array($this, 'filter_cron_schedules'));
55
- add_action('crontrol_cron_job', array($this, 'action_php_cron_event'));
56
- }
57
-
58
- /**
59
- * Evaluates the provided code using eval.
60
- */
61
- function action_php_cron_event($code) {
62
- eval($code);
63
- }
64
-
65
- /**
66
- * Run using the 'init' action.
67
- */
68
- function action_init() {
69
- load_plugin_textdomain( 'wp-crontrol', false, dirname( plugin_basename( __FILE__ ) ) . '/gettext' );
70
- }
71
-
72
- /**
73
- * Handles any POSTs made by the plugin. Run using the 'init' action.
74
- */
75
- function action_handle_posts() {
76
- if( isset($_POST['new_cron']) ) {
77
- if( !current_user_can('manage_options') ) die(__('You are not allowed to add new cron events.', 'wp-crontrol'));
78
- check_admin_referer("new-cron");
79
- extract($_POST, EXTR_PREFIX_ALL, 'in');
80
- $in_args = json_decode(stripslashes($in_args),true);
81
- $this->add_cron($in_next_run, $in_schedule, $in_hookname, $in_args);
82
- wp_redirect("tools.php?page=crontrol_admin_manage_page&crontrol_message=5&crontrol_name={$in_hookname}");
83
-
84
- } else if( isset($_POST['new_php_cron']) ) {
85
- if( !current_user_can('manage_options') ) die(__('You are not allowed to add new cron events.', 'wp-crontrol'));
86
- check_admin_referer("new-cron");
87
- extract($_POST, EXTR_PREFIX_ALL, 'in');
88
- $args = array('code'=>stripslashes($in_hookcode));
89
- $this->add_cron($in_next_run, $in_schedule, 'crontrol_cron_job', $args);
90
- wp_redirect("tools.php?page=crontrol_admin_manage_page&crontrol_message=5&crontrol_name={$in_hookname}");
91
-
92
- } else if( isset($_POST['edit_cron']) ) {
93
- if( !current_user_can('manage_options') ) die(__('You are not allowed to edit cron events.', 'wp-crontrol'));
94
-
95
- extract($_POST, EXTR_PREFIX_ALL, 'in');
96
- check_admin_referer("edit-cron_{$in_original_hookname}_{$in_original_sig}_{$in_original_next_run}");
97
- $in_args = json_decode(stripslashes($in_args),true);
98
- $i=$this->delete_cron($in_original_hookname, $in_original_sig, $in_original_next_run);
99
- $i=$this->add_cron($in_next_run, $in_schedule, $in_hookname, $in_args);
100
- wp_redirect("tools.php?page=crontrol_admin_manage_page&crontrol_message=4&crontrol_name={$in_hookname}");
101
-
102
- } else if( isset($_POST['edit_php_cron']) ) {
103
- if( !current_user_can('manage_options') ) die(__('You are not allowed to edit cron events.', 'wp-crontrol'));
104
-
105
- extract($_POST, EXTR_PREFIX_ALL, 'in');
106
- check_admin_referer("edit-cron_{$in_original_hookname}_{$in_original_sig}_{$in_original_next_run}");
107
- $args['code'] = stripslashes($in_hookcode);
108
- $args = array('code'=>stripslashes($in_hookcode));
109
- $i=$this->delete_cron($in_original_hookname, $in_original_sig, $in_original_next_run);
110
- $i=$this->add_cron($in_next_run, $in_schedule, 'crontrol_cron_job', $args);
111
- wp_redirect("tools.php?page=crontrol_admin_manage_page&crontrol_message=4&crontrol_name={$in_hookname}");
112
-
113
- } else if( isset($_POST['new_schedule']) ) {
114
- if( !current_user_can('manage_options') ) die(__('You are not allowed to add new cron schedules.', 'wp-crontrol'));
115
- check_admin_referer("new-sched");
116
- $name = $_POST['internal_name'];
117
- $interval = $_POST['interval'];
118
- $display = $_POST['display_name'];
119
-
120
- // The user entered something that wasn't a number.
121
- // Try to convert it with strtotime
122
- if( !is_numeric($interval) ) {
123
- $now = time();
124
- $future = strtotime($interval, $now);
125
- if( $future===FALSE || $future == -1 || $now>$future) {
126
- wp_redirect("options-general.php?page=crontrol_admin_options_page&crontrol_message=7&crontrol_name=".urlencode($interval));
127
- return;
128
- }
129
- $interval = $future-$now;
130
- } else if( $interval<=0 ) {
131
- wp_redirect("options-general.php?page=crontrol_admin_options_page&crontrol_message=7&crontrol_name=".urlencode($interval));
132
- return;
133
- }
134
-
135
- $this->add_schedule($name, $interval, $display);
136
- wp_redirect("options-general.php?page=crontrol_admin_options_page&crontrol_message=3&crontrol_name=$name");
137
-
138
- } else if( isset($_GET['action']) && $_GET['action']=='delete-sched') {
139
- if( !current_user_can('manage_options') ) die(__('You are not allowed to delete cron schedules.', 'wp-crontrol'));
140
- $id = $_GET['id'];
141
- check_admin_referer("delete-sched_{$id}");
142
- $this->delete_schedule($id);
143
- wp_redirect("options-general.php?page=crontrol_admin_options_page&crontrol_message=2&crontrol_name=$id");
144
-
145
- } else if( isset($_GET['action']) && $_GET['action']=='delete-cron') {
146
- if( !current_user_can('manage_options') ) die(__('You are not allowed to delete cron events.', 'wp-crontrol'));
147
- $id = $_GET['id'];
148
- $sig = $_GET['sig'];
149
- $next_run = $_GET['next_run'];
150
- check_admin_referer("delete-cron_{$id}_{$sig}_{$next_run}");
151
- if( $this->delete_cron($id, $sig, $next_run) ) {
152
- wp_redirect("tools.php?page=crontrol_admin_manage_page&crontrol_message=6&crontrol_name=$id");
153
- } else {
154
- wp_redirect("tools.php?page=crontrol_admin_manage_page&crontrol_message=7&crontrol_name=$id");
155
- };
156
-
157
- } else if( isset($_GET['action']) && $_GET['action']=='run-cron') {
158
- if( !current_user_can('manage_options') ) die(__('You are not allowed to run cron events.', 'wp-crontrol'));
159
- $id = $_GET['id'];
160
- $sig = $_GET['sig'];
161
- check_admin_referer("run-cron_{$id}_{$sig}");
162
- if( $this->run_cron($id, $sig) ) {
163
- wp_redirect("tools.php?page=crontrol_admin_manage_page&crontrol_message=1&crontrol_name=$id");
164
- } else {
165
- wp_redirect("tools.php?page=crontrol_admin_manage_page&crontrol_message=8&crontrol_name=$id");
166
- }
167
- }
168
- }
169
-
170
- /**
171
- * Executes a cron event immediately.
172
- *
173
- * Executes an event by scheduling a new single event with the same arguments.
174
- *
175
- * @param string $hookname The hookname of the cron event to run
176
- */
177
- function run_cron($hookname, $sig) {
178
- $crons = _get_cron_array();
179
- foreach( $crons as $time=>$cron ) {
180
- if( isset( $cron[$hookname][$sig] ) ) {
181
- $args = $cron[$hookname][$sig]['args'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
  delete_transient( 'doing_cron' );
183
- wp_schedule_single_event(time()-1, $hookname, $args);
184
- spawn_cron();
185
- return true;
186
- }
187
- }
188
- return false;
189
- }
190
-
191
- /**
192
- * Adds a new cron event.
193
- *
194
- * @param string $next_run A human-readable (strtotime) time that the event should be run at
195
- * @param string $schedule The recurrence of the cron event
196
- * @param string $hookname The name of the hook to execute
197
- * @param array $args Arguments to add to the cron event
198
- */
199
- function add_cron($next_run, $schedule, $hookname, $args) {
200
- $next_run = strtotime($next_run);
201
- if( $next_run===FALSE || $next_run==-1 ) $next_run=time();
202
- if( !is_array($args) ) $args=array();
203
- if( $schedule == '_oneoff' ) {
204
- return wp_schedule_single_event($next_run, $hookname, $args) === NULL;
205
- } else {
206
- return wp_schedule_event( $next_run, $schedule, $hookname, $args ) === NULL;
207
- }
208
- }
209
-
210
- /**
211
- * Deletes a cron event.
212
- *
213
- * @param string $name The hookname of the event to delete.
214
- */
215
- function delete_cron($to_delete, $sig, $next_run) {
216
- $crons = _get_cron_array();
217
- if( isset( $crons[$next_run][$to_delete][$sig] ) ) {
218
- $args = $crons[$next_run][$to_delete][$sig]['args'];
219
- wp_unschedule_event($next_run, $to_delete, $args);
220
- return true;
221
- }
222
- return false;
223
- }
224
-
225
- /**
226
- * Adds a new custom cron schedule.
227
- *
228
- * @param string $name The internal name of the schedule
229
- * @param int $interval The interval between executions of the new schedule
230
- * @param string $display The display name of the schedule
231
- */
232
- function add_schedule($name, $interval, $display) {
233
- $old_scheds = get_option('crontrol_schedules',array());
234
- $old_scheds[$name] = array('interval'=>$interval, 'display'=>$display);
235
- update_option('crontrol_schedules', $old_scheds);
236
- }
237
-
238
- /**
239
- * Deletes a custom cron schedule.
240
- *
241
- * @param string $name The internal_name of the schedule to delete.
242
- */
243
- function delete_schedule($name) {
244
- $scheds = get_option('crontrol_schedules',array());
245
- unset($scheds[$name]);
246
- update_option('crontrol_schedules', $scheds);
247
- }
248
-
249
- /**
250
- * Sets up the plugin environment upon first activation.
251
- *
252
- * Run using the 'activate_' action.
253
- */
254
- function action_activate() {
255
- $extra_scheds = array('twicedaily'=>array('interval'=>43200, 'display'=>__('Twice Daily', 'wp-crontrol')));
256
- add_option('crontrol_schedules', $extra_scheds);
257
-
258
- // if there's never been a cron event, _get_cron_array will return FALSE
259
- if( _get_cron_array() === FALSE ) {
260
- _set_cron_array(array());
261
- }
262
- }
263
-
264
- /**
265
- * Adds options & management pages to the admin menu.
266
- *
267
- * Run using the 'admin_menu' action.
268
- */
269
- function action_admin_menu() {
270
- $page = add_options_page('Cron Schedules', 'Cron Schedules', 'manage_options', 'crontrol_admin_options_page', array($this, 'admin_options_page') );
271
- $page = add_management_page('Crontrol', "Crontrol", 'manage_options', 'crontrol_admin_manage_page', array($this, 'admin_manage_page') );
272
- }
273
-
274
- /**
275
- * Gives WordPress the plugin's set of cron schedules.
276
- *
277
- * Called by the 'cron_schedules' filter.
278
- *
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
279
  * @param array $scheds The current cron schedules. Usually an empty array.
280
  * @return array The existing cron schedules along with the plugin's schedules.
281
- */
282
- function filter_cron_schedules($scheds) {
283
- $new_scheds = get_option('crontrol_schedules',array());
284
- return array_merge($new_scheds, $scheds);
285
- }
286
-
287
- /**
288
- * Displays the options page for the plugin.
289
- */
290
- function admin_options_page() {
291
- $schedules = $this->get_schedules();
292
- $custom_schedules = get_option('crontrol_schedules',array());
293
- $custom_keys = array_keys($custom_schedules);
294
-
295
- if( isset($_GET['crontrol_message']) ) {
296
- $messages = array(
297
- '2' => __( 'Successfully deleted the cron schedule %s', 'wp-crontrol' ),
298
- '3' => __( 'Successfully added the cron schedule %s', 'wp-crontrol' ),
299
- '7' => __( 'Cron schedule not added because there was a problem parsing %s', 'wp-crontrol' )
300
- );
301
- $hook = stripslashes( $_GET['crontrol_name'] );
302
- $msg = sprintf($messages[$_GET['crontrol_message']], '<strong>' . esc_html( $hook ) . '</strong>' );
303
-
304
- echo "<div id=\"message\" class=\"updated fade\"><p>$msg</p></div>";
305
- }
306
-
307
- ?>
308
- <div class="wrap">
309
- <?php screen_icon(); ?>
310
- <h2><?php _e("Cron Schedules", "crontrol"); ?></h2>
311
- <p><?php _e('Cron schedules are the time intervals that are available to WordPress and plugin developers to schedule events. You can only delete cron schedules that you have created with WP Crontrol.', 'wp-crontrol'); ?></p>
312
- <div id="ajax-response"></div>
313
- <table class="widefat">
314
- <thead>
315
- <tr>
316
- <th><?php _e('Name', 'wp-crontrol'); ?></th>
317
- <th><?php _e('Interval', 'wp-crontrol'); ?></th>
318
- <th><?php _e('Display Name', 'wp-crontrol'); ?></th>
319
- <th>&nbsp;</th>
320
- </tr>
321
- </thead>
322
- <tbody>
323
- <?php
324
- if( empty($schedules) ) {
325
- ?>
326
- <tr colspan="4"><td><?php _e('You currently have no cron schedules. Add one below!', 'wp-crontrol') ?></td></tr>
327
- <?php
328
- } else {
329
- $class = "";
330
- foreach( $schedules as $name=>$data ) {
331
- echo "<tr id=\"sched-$name\" class=\"$class\">";
332
- echo "<td>$name</td>";
333
- echo "<td>{$data['interval']} (".$this->interval($data['interval']).")</td>";
334
- echo "<td>{$data['display']}</td>";
335
- if( in_array($name, $custom_keys) ) {
336
- echo "<td><a href='" . wp_nonce_url( "options-general.php?page=crontrol_admin_options_page&amp;action=delete-sched&amp;id=$name", 'delete-sched_' . $name ) . "' class='delete'>".__( 'Delete' )."</a></td>";
337
- } else {
338
- echo "<td>&nbsp;</td>\n";
339
- }
340
- echo "</tr>";
341
- $class = empty($class)?"alternate":"";
342
- }
343
- }
344
- ?>
345
- </tbody>
346
- </table>
347
- </div>
348
- <div class="wrap narrow">
349
- <?php screen_icon(); ?>
350
- <h2><?php _e('Add new cron schedule', 'wp-crontrol'); ?></h2>
351
- <p><?php _e('Adding a new cron schedule will allow you to schedule events that re-occur at the given interval.', 'wp-crontrol'); ?></p>
352
- <form method="post" action="options-general.php?page=crontrol_admin_options_page">
353
- <table width="100%" cellspacing="2" cellpadding="5" class="editform form-table">
354
- <tbody>
355
- <tr>
356
- <th width="33%" valign="top" scope="row"><label for="cron_internal_name"><?php _e('Internal name', 'wp-crontrol'); ?>:</label></th>
357
- <td width="67%"><input type="text" size="40" value="" id="cron_internal_name" name="internal_name"/></td>
358
- </tr>
359
- <tr>
360
- <th width="33%" valign="top" scope="row"><label for="cron_interval"><?php _e('Interval (seconds)', 'wp-crontrol'); ?>:</label></th>
361
- <td width="67%"><input type="text" size="40" value="" id="cron_interval" name="interval"/></td>
362
- </tr>
363
- <tr>
364
- <th width="33%" valign="top" scope="row"><label for="cron_display_name"><?php _e('Display name', 'wp-crontrol'); ?>:</label></th>
365
- <td width="67%"><input type="text" size="40" value="" id="cron_display_name" name="display_name"/></td>
366
- </tr>
367
- </tbody></table>
368
- <p class="submit"><input id="schedadd-submit" type="submit" class="button-primary" value="<?php _e('Add Cron Schedule &raquo;', 'wp-crontrol'); ?>" name="new_schedule"/></p>
369
- <?php wp_nonce_field('new-sched') ?>
370
- </form>
371
- </div>
372
- <?php
373
- }
374
-
375
- /**
376
- * Gets a sorted (according to interval) list of the cron schedules
377
- */
378
- function get_schedules() {
379
- $schedules = wp_get_schedules();
380
- uasort($schedules, create_function('$a,$b', 'return $a["interval"]-$b["interval"];'));
381
- return $schedules;
382
- }
383
-
384
- /**
385
- * Displays a dropdown filled with the possible schedules, including non-repeating.
386
- *
387
- * @param boolean $current The currently selected schedule
388
- */
389
- function schedules_dropdown($current=false) {
390
- $schedules = $this->get_schedules();
391
- ?>
392
- <select class="postform" name="schedule">
393
- <option <?php selected($current, '_oneoff') ?> value="_oneoff"><?php _e('Non-repeating', 'wp-crontrol') ?></option>
394
- <?php foreach( $schedules as $sched_name=>$sched_data ) { ?>
395
- <option <?php selected($current, $sched_name) ?> value="<?php echo $sched_name ?>">
396
- <?php echo $sched_data['display'] ?> (<?php echo $this->interval($sched_data['interval']) ?>)
397
- </option>
398
- <?php } ?>
399
- </select>
400
- <?php
401
- }
402
-
403
- /**
404
- * Gets the status of WP-Cron functionality on the site by performing a test spawn. Cached for one hour when all is well.
405
- *
406
- */
407
- function test_cron_spawn( $cache = true ) {
408
-
409
- if ( defined('ALTERNATE_WP_CRON') && ALTERNATE_WP_CRON )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
410
  return true;
 
411
 
412
  $cached_status = get_transient( 'wp-cron-test-ok' );
413
 
414
- if ( $cache and $cached_status )
415
  return true;
 
416
 
 
417
  $doing_wp_cron = sprintf( '%.22F', microtime( true ) );
418
 
419
  $cron_request = apply_filters( 'cron_request', array(
@@ -422,8 +559,8 @@ class Crontrol {
422
  'args' => array(
423
  'timeout' => 3,
424
  'blocking' => true,
425
- 'sslverify' => apply_filters( 'https_local_ssl_verify', true )
426
- )
427
  ) );
428
 
429
  $cron_request['args']['blocking'] = true;
@@ -432,6 +569,11 @@ class Crontrol {
432
 
433
  if ( is_wp_error( $result ) ) {
434
  return $result;
 
 
 
 
 
435
  } else {
436
  set_transient( 'wp-cron-test-ok', 1, 3600 );
437
  return true;
@@ -439,102 +581,130 @@ class Crontrol {
439
 
440
  }
441
 
442
- /**
443
- * Shows the status of WP-Cron functionality on the site. Only displays a message when there's a problem.
444
- *
445
- */
446
- function show_cron_status() {
447
 
448
  $status = $this->test_cron_spawn();
449
 
450
  if ( is_wp_error( $status ) ) {
451
  ?>
452
  <div id="cron-status-error" class="error">
453
- <p><?php printf( __( 'There was a problem spawning a call to the WP-Cron system on your site. This means WP-Cron jobs on your site may not work. The problem was: %s', 'wp-crontrol' ), '<br><strong>' . esc_html( $status->get_error_message() ) . '</strong>' ); ?></p>
454
  </div>
455
  <?php
456
  }
457
 
458
  }
459
 
460
- /**
461
- * Shows the form used to add/edit cron events.
462
- *
463
- * @param boolean $is_php Whether this is a PHP cron event
464
- * @param mixed $existing An array of existing values for the cron event, or NULL
465
- */
466
- function show_cron_form($is_php, $existing) {
467
- if( $is_php ) {
468
- $helper_text = sprintf( __( 'Cron events trigger actions in your code. Using the form below, you can enter the schedule of the action, as well as the PHP code for the action itself. Alternatively, the schedule can be specified from within WordPress and the code for the action in a file on on your server using <a href="%1$s">this form</a>.', 'wp-crontrol' ),
469
- admin_url( 'tools.php?page=crontrol_admin_manage_page&action=new-cron#crontrol_form' )
470
- );
471
- $link = ' (<a href="tools.php?page=crontrol_admin_manage_page#crontrol_form">'. __('Add new event', 'wp-crontrol') .'</a>)';
472
- } else {
473
- $helper_text = sprintf( __( 'Cron events trigger actions in your code. A cron event added using the form below needs a corresponding action hook somewhere in code, perhaps the %1$s file in your theme. It is also possible to create your action hook from within WordPress using <a href="%2$s">this form</a>.', 'wp-crontrol' ),
474
- '<code>functions.php</code>',
475
- admin_url( 'tools.php?page=crontrol_admin_manage_page&action=new-php-cron#crontrol_form' )
476
- );
477
- $link = ' (<a href="tools.php?page=crontrol_admin_manage_page&amp;action=new-php-cron#crontrol_form">'. __('Add new PHP event', 'wp-crontrol') .'</a>)';
478
- }
479
- if( is_array($existing) ) {
480
- $other_fields = wp_nonce_field( "edit-cron_{$existing['hookname']}_{$existing['sig']}_{$existing['next_run']}", "_wpnonce", true, false );
481
- $other_fields .= '<input name="original_hookname" type="hidden" value="'. $existing['hookname'] .'" />';
482
- $other_fields .= '<input name="original_sig" type="hidden" value="'. $existing['sig'] .'" />';
483
- $other_fields .= '<input name="original_next_run" type="hidden" value="'. $existing['next_run'] .'" />';
484
- $existing['args'] = $is_php ? $existing['args']['code'] : json_encode($existing['args']);
485
- $existing['next_run'] = date('Y-m-d H:i:s', $existing['next_run']);
486
- $action = $is_php ? 'edit_php_cron' : 'edit_cron';
487
- $button = $is_php ? __('Modify PHP Cron Event', 'wp-crontrol') : __('Modify Cron Event', 'wp-crontrol');
488
- $link = false;
489
- } else {
490
- $other_fields = wp_nonce_field( "new-cron", "_wpnonce", true, false );
491
- $existing = array('hookname'=>'','hookcode'=>'','args'=>'','next_run'=>'now','schedule'=>false);
492
- $action = $is_php ? 'new_php_cron' : 'new_cron';
493
- $button = $is_php ? __('Add PHP Cron Event', 'wp-crontrol') : __('Add Cron Event', 'wp-crontrol');
494
- }
495
- ?>
496
- <div id="crontrol_form" class="wrap narrow">
497
- <?php screen_icon(); ?>
498
- <h2><?php echo $button; if($link) echo '<span style="font-size:xx-small">'.$link.'</span>'; ?></h2>
499
- <p><?php echo $helper_text ?></p>
500
- <form method="post">
501
- <?php echo $other_fields ?>
502
- <table width="100%" cellspacing="2" cellpadding="5" class="editform form-table"><tbody>
503
- <?php if( $is_php ): ?>
504
- <tr>
505
- <th width="33%" valign="top" scope="row"><label for="hookcode"><?php _e('Hook code', 'wp-crontrol'); ?>:</label></th>
506
- <td width="67%"><textarea style="width:95%" class="code" rows="5" name="hookcode"><?php echo esc_textarea( $existing['args'] ); ?></textarea></td>
507
- </tr>
508
- <?php else: ?>
509
- <tr>
510
- <th width="33%" valign="top" scope="row"><label for="hookname"><?php _e('Hook name', 'wp-crontrol'); ?>:</label></th>
511
- <td width="67%"><input type="text" size="40" id="hookname" name="hookname" value="<?php echo esc_attr( $existing['hookname'] ); ?>"/></td>
512
- </tr>
513
- <tr>
514
- <th width="33%" valign="top" scope="row"><label for="args"><?php _e('Arguments', 'wp-crontrol'); ?>:</label><br /><span style="font-size:xx-small"><?php _e('e.g., [], [25], ["asdf"], or ["i","want",25,"cakes"]', 'wp-crontrol') ?></span></th>
515
- <td width="67%"><input type="text" size="40" id="args" name="args" value="<?php echo esc_textarea( $existing['args'] ); ?>"/></td>
516
- </tr>
517
- <?php endif; ?>
518
- <tr>
519
- <th width="33%" valign="top" scope="row"><label for="next_run"><?php _e('Next run (UTC)', 'wp-crontrol'); ?>:</label><br /><span style="font-size:xx-small"><?php _e( 'e.g., "now", "tomorrow", "+2 days", or "25-02-2014 15:27:09"', 'wp-crontrol' ) ?></th>
520
- <td width="67%"><input type="text" size="40" id="next_run" name="next_run" value="<?php echo esc_attr( $existing['next_run'] ); ?>"/></td>
521
- </tr><tr>
522
- <th valign="top" scope="row"><label for="schedule"><?php _e('Event schedule', 'wp-crontrol'); ?>:</label></th>
523
- <td>
524
- <?php $this->schedules_dropdown($existing['schedule']) ?>
525
- </td>
526
- </tr>
527
- </tbody></table>
528
- <p class="submit"><input type="submit" class="button-primary" value="<?php echo $button ?> &raquo;" name="<?php echo $action ?>"/></p>
529
- </form>
530
- </div>
531
- <?php
532
- }
533
-
534
- function get_cron_events() {
535
-
536
- $crons = _get_cron_array();
537
- $events = array();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
538
 
539
  if ( empty( $crons ) ) {
540
  return new WP_Error(
@@ -543,12 +713,12 @@ class Crontrol {
543
  );
544
  }
545
 
546
- foreach( $crons as $time=>$cron ) {
547
- foreach( $cron as $hook=>$dings) {
548
- foreach( $dings as $sig=>$data ) {
549
 
550
  # This is a prime candidate for a Crontrol_Event class but I'm not bothering currently.
551
- $events["$hook-$sig"] = (object) array(
552
  'hook' => $hook,
553
  'time' => $time,
554
  'sig' => $sig,
@@ -563,67 +733,67 @@ class Crontrol {
563
 
564
  return $events;
565
 
566
- }
567
-
568
- /**
569
- * Displays the manage page for the plugin.
570
- */
571
- function admin_manage_page() {
572
- if( isset($_GET['crontrol_message']) ) {
573
- $messages = array(
574
- '1' => __( 'Successfully executed the cron event %s', 'wp-crontrol' ),
575
- '4' => __( 'Successfully edited the cron event %s', 'wp-crontrol' ),
576
- '5' => __( 'Successfully created the cron event %s', 'wp-crontrol' ),
577
- '6' => __( 'Successfully deleted the cron event %s', 'wp-crontrol' ),
578
- '7' => __( 'Failed to the delete the cron event %s', 'wp-crontrol' ),
579
- '8' => __( 'Failed to the execute the cron event %s', 'wp-crontrol ')
580
- );
581
- $hook = stripslashes( $_GET['crontrol_name'] );
582
- $msg = sprintf($messages[$_GET['crontrol_message']], '<strong>' . esc_html( $hook ) . '</strong>' );
583
 
584
- echo "<div id=\"message\" class=\"updated fade\"><p>$msg</p></div>";
585
- }
586
- $events = $this->get_cron_events();
587
- $doing_edit = (isset( $_GET['action']) && $_GET['action']=='edit-cron') ? $_GET['id'] : false ;
588
- $time_format = 'Y-m-d H:i:s';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
589
 
590
- $tzstring = get_option( 'timezone_string' );
591
- $current_offset = get_option( 'gmt_offset' );
592
 
593
- if ( $current_offset >= 0 )
594
  $current_offset = '+' . $current_offset;
 
595
 
596
- if ( '' === $tzstring )
597
  $tz = sprintf( 'UTC%s', $current_offset );
598
- else
599
  $tz = sprintf( '%s (UTC%s)', str_replace( '_', ' ', $tzstring ), $current_offset );
 
600
 
601
- $this->show_cron_status();
602
-
603
- ?>
604
- <div class="wrap">
605
- <?php screen_icon(); ?>
606
- <h2><?php _e('WP-Cron Events', 'wp-crontrol'); ?></h2>
607
- <p></p>
608
- <table class="widefat">
609
- <thead>
610
- <tr>
611
- <th><?php _e('Hook Name', 'wp-crontrol'); ?></th>
612
- <th><?php _e('Arguments', 'wp-crontrol'); ?></th>
613
- <th><?php _e('Next Run', 'wp-crontrol'); ?></th>
614
- <th><?php _e('Recurrence', 'wp-crontrol'); ?></th>
615
- <th colspan="3">&nbsp;</th>
616
- </tr>
617
- </thead>
618
- <tbody>
619
- <?php
620
- if( is_wp_error($events) ) {
621
- ?>
622
- <tr><td colspan="7"><?php echo $events->get_error_message(); ?></td></tr>
623
- <?php
624
- } else {
625
- $class = "";
626
- foreach( $events as $id=>$event ) {
627
 
628
  if ( $doing_edit && $doing_edit == $event->hook && $event->time == $_GET['next_run'] && $event->sig == $_GET['sig'] ) {
629
  $doing_edit = array(
@@ -631,127 +801,177 @@ class Crontrol {
631
  'next_run' => $event->time,
632
  'schedule' => ( $event->schedule ? $event->schedule : '_oneoff' ),
633
  'sig' => $event->sig,
634
- 'args' => $event->args
635
  );
636
  }
637
 
638
- $args = empty( $event->args ) ? '<em>' . __( 'None', 'wp-crontrol' ) . '</em>' : json_encode( $event->args );
639
-
640
- echo "<tr id=\"cron-{$id}\" class=\"{$class}\">";
641
- echo "<td>".($event->hook=='crontrol_cron_job' ? '<em>' . __( 'PHP Cron', 'wp-crontrol' ) . '</em>' : $event->hook)."</td>";
642
- echo "<td>".($event->hook=='crontrol_cron_job' ? '<em>' . __( 'PHP Code', 'wp-crontrol' ) . '</em>' : $args )."</td>";
643
- echo "<td>".get_date_from_gmt(date('Y-m-d H:i:s',$event->time),$time_format)." (".$this->time_since(time(), $event->time).")</td>";
644
- echo "<td>".($event->schedule ? $this->interval($event->interval) : __('Non-repeating', 'wp-crontrol'))."</td>";
645
- echo "<td><a class='view' href='tools.php?page=crontrol_admin_manage_page&amp;action=edit-cron&amp;id={$event->hook}&amp;sig={$event->sig}&amp;next_run={$event->time}#crontrol_form'>" . __( 'Edit', 'wp-crontrol' ) . "</a></td>";
646
- echo "<td><a class='view' href='".wp_nonce_url("tools.php?page=crontrol_admin_manage_page&amp;action=run-cron&amp;id={$event->hook}&amp;sig={$event->sig}", "run-cron_{$event->hook}_{$event->sig}")."'>" . __( 'Run Now', 'wp-crontrol' ) . "</a></td>";
647
- echo "<td><a class='delete' href='".wp_nonce_url("tools.php?page=crontrol_admin_manage_page&amp;action=delete-cron&amp;id={$event->hook}&amp;sig={$event->sig}&amp;next_run={$event->time}", "delete-cron_{$event->hook}_{$event->sig}_{$event->time}")."'>" . __( 'Delete', 'wp-crontrol' ) . "</a></td>";
648
- echo "</tr>";
649
- $class = empty($class)?"alternate":"";
650
-
651
- }
652
- }
653
- ?>
654
- </tbody>
655
- </table>
656
-
657
- <div class="tablenav">
658
- <p class="description">
659
- <?php printf( __( 'Local timezone is %s', 'wp-crontrol' ), '<code>' . $tz . '</code>' ); ?>
660
- <span id="utc-time"><?php printf( __( 'UTC time is %s', 'wp-crontrol' ), '<code>' . date_i18n( $time_format, false, true ) . '</code>' ); ?></span>
661
- <span id="local-time"><?php printf( __( 'Local time is %s', 'wp-crontrol' ), '<code>' . date_i18n( $time_format ) . '</code>' ); ?></span>
662
- </p>
663
- </div>
664
-
665
- </div>
666
- <?php
667
- if( is_array( $doing_edit ) ) {
668
- $this->show_cron_form($doing_edit['hookname']=='crontrol_cron_job', $doing_edit);
669
- } else {
670
- $this->show_cron_form((isset($_GET['action']) and $_GET['action']=='new-php-cron'), false);
671
- }
672
- }
673
-
674
- /**
675
- * Pretty-prints the difference in two times.
676
- *
677
- * @param time $older_date
678
- * @param time $newer_date
679
- * @return string The pretty time_since value
680
- * @link http://binarybonsai.com/code/timesince.txt
681
- */
682
- function time_since($older_date, $newer_date) {
683
- return $this->interval( $newer_date - $older_date );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
684
  }
685
 
686
- function interval( $since ) {
687
- // array of time period chunks
688
- $chunks = array(
689
- array(60 * 60 * 24 * 365 , _n_noop('%s year', '%s years', 'wp-crontrol')),
690
- array(60 * 60 * 24 * 30 , _n_noop('%s month', '%s months', 'wp-crontrol')),
691
- array(60 * 60 * 24 * 7, _n_noop('%s week', '%s weeks', 'wp-crontrol')),
692
- array(60 * 60 * 24 , _n_noop('%s day', '%s days', 'wp-crontrol')),
693
- array(60 * 60 , _n_noop('%s hour', '%s hours', 'wp-crontrol')),
694
- array(60 , _n_noop('%s minute', '%s minutes', 'wp-crontrol')),
695
- array( 1 , _n_noop('%s second', '%s seconds', 'wp-crontrol')),
696
- );
697
-
698
-
699
- if( $since <= 0 ) {
700
- return __('now', 'wp-crontrol');
701
- }
702
-
703
- // we only want to output two chunks of time here, eg:
704
- // x years, xx months
705
- // x days, xx hours
706
- // so there's only two bits of calculation below:
707
-
708
- // step one: the first chunk
709
- for ($i = 0, $j = count($chunks); $i < $j; $i++)
710
- {
711
- $seconds = $chunks[$i][0];
712
- $name = $chunks[$i][1];
713
-
714
- // finding the biggest chunk (if the chunk fits, break)
715
- if (($count = floor($since / $seconds)) != 0)
716
- {
717
- break;
718
- }
719
- }
720
-
721
- // set output var
722
- $output = sprintf(_n($name[0], $name[1], $count, 'wp-crontrol'), $count);
723
-
724
- // step two: the second chunk
725
- if ($i + 1 < $j)
726
- {
727
- $seconds2 = $chunks[$i + 1][0];
728
- $name2 = $chunks[$i + 1][1];
729
-
730
- if (($count2 = floor(($since - ($seconds * $count)) / $seconds2)) != 0)
731
- {
732
- // add to output var
733
- $output .= ' '.sprintf(_n($name2[0], $name2[1], $count2, 'wp-crontrol'), $count2);
734
- }
735
- }
736
-
737
- return $output;
738
  }
739
 
740
  public static function init() {
741
 
742
  static $instance = null;
743
 
744
- if ( !$instance )
745
  $instance = new Crontrol;
 
746
 
747
  return $instance;
748
 
749
  }
750
-
751
  }
752
 
753
- if ( defined( 'WP_CLI' ) and WP_CLI and is_readable( $wp_cli = dirname( __FILE__ ) . '/class-wp-cli.php' ) )
754
- include_once $wp_cli;
755
-
756
  // Get this show on the road
757
  Crontrol::init();
3
  * Plugin Name: WP Crontrol
4
  * Plugin URI: https://wordpress.org/plugins/wp-crontrol/
5
  * Description: WP Crontrol lets you view and control what's happening in the WP-Cron system.
6
+ * Author: <a href="https://johnblackbourn.com/">John Blackbourn</a> & <a href="http://www.scompt.com/">Edward Dale</a>
7
+ * Version: 1.3
8
  * Text Domain: wp-crontrol
9
+ * Domain Path: /languages/
10
+ * License: GPL v2 or later
11
  */
12
 
13
+ /**
14
+ * WP Crontrol lets you view and control what's happening in the WP-Cron system.
15
+ *
16
+ * LICENSE
17
+ * This file is part of WP Crontrol.
18
+ *
19
+ * WP Crontrol is free software; you can redistribute it and/or
20
+ * modify it under the terms of the GNU General Public License
21
+ * as published by the Free Software Foundation; either version 2
22
+ * of the License, or (at your option) any later version.
23
+ *
24
+ * This program is distributed in the hope that it will be useful,
25
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
26
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27
+ * GNU General Public License for more details.
28
+ *
29
+ * You should have received a copy of the GNU General Public License
30
+ * along with this program; if not, write to the Free Software
31
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
32
+ *
33
+ * @package WP Crontrol
34
+ * @author Edward Dale <scompt@scompt.com> & John Blackbourn <john@johnblackbourn.com>
35
+ * @copyright Copyright 2013 Edward Dale & John Blackbourn
36
+ * @license http://www.gnu.org/licenses/gpl.txt GPL 2.0
37
+ * @link https://wordpress.org/plugins/wp-crontrol/
38
+ * @since 0.2
39
+ */
40
 
41
  defined( 'ABSPATH' ) or die();
42
 
43
  class Crontrol {
44
 
45
+ /**
46
+ * Hook onto all of the actions and filters needed by the plugin.
47
+ */
48
+ protected function __construct() {
49
+
50
+ $plugin_file = plugin_basename( __FILE__ );
51
+
52
+ add_action( 'init', array( $this, 'action_init' ) );
53
+ add_action( 'init', array( $this, 'action_handle_posts' ) );
54
+ add_action( 'admin_menu', array( $this, 'action_admin_menu' ) );
55
+ add_filter( "plugin_action_links_{$plugin_file}", array( $this, 'plugin_action_links' ), 10, 4 );
56
+
57
+ register_activation_hook( __FILE__, array( $this, 'action_activate' ) );
58
+
59
+ add_filter( 'cron_schedules', array( $this, 'filter_cron_schedules' ) );
60
+ add_action( 'crontrol_cron_job', array( $this, 'action_php_cron_event' ) );
61
+ }
62
+
63
+ /**
64
+ * Evaluates the provided code using eval.
65
+ */
66
+ public function action_php_cron_event( $code ) {
67
+ eval( $code );
68
+ }
69
+
70
+ /**
71
+ * Run using the 'init' action.
72
+ */
73
+ public function action_init() {
74
+ load_plugin_textdomain( 'wp-crontrol', false, dirname( plugin_basename( __FILE__ ) ) . '/gettext' );
75
+ }
76
+
77
+ /**
78
+ * Handles any POSTs made by the plugin. Run using the 'init' action.
79
+ */
80
+ public function action_handle_posts() {
81
+ if ( isset( $_POST['new_cron'] ) ) {
82
+ if ( ! current_user_can( 'manage_options' ) ) {
83
+ wp_die( esc_html__( 'You are not allowed to add new cron events.', 'wp-crontrol' ) );
84
+ }
85
+ check_admin_referer( 'new-cron' );
86
+ extract( wp_unslash( $_POST ), EXTR_PREFIX_ALL, 'in' );
87
+ $in_args = json_decode( $in_args, true );
88
+ $this->add_cron( $in_next_run, $in_schedule, $in_hookname, $in_args );
89
+ $redirect = array(
90
+ 'page' => 'crontrol_admin_manage_page',
91
+ 'crontrol_message' => '5',
92
+ 'crontrol_name' => urlencode( $in_hookname ),
93
+ );
94
+ wp_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
95
+ exit;
96
+
97
+ } else if ( isset( $_POST['new_php_cron'] ) ) {
98
+ if ( ! current_user_can( 'edit_files' ) ) {
99
+ wp_die( esc_html__( 'You are not allowed to add new PHP cron events.', 'wp-crontrol' ) );
100
+ }
101
+ check_admin_referer( 'new-cron' );
102
+ extract( wp_unslash( $_POST ), EXTR_PREFIX_ALL, 'in' );
103
+ $args = array( 'code' => $in_hookcode );
104
+ $this->add_cron( $in_next_run, $in_schedule, 'crontrol_cron_job', $args );
105
+ $redirect = array(
106
+ 'page' => 'crontrol_admin_manage_page',
107
+ 'crontrol_message' => '5',
108
+ 'crontrol_name' => urlencode( $in_hookname ),
109
+ );
110
+ wp_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
111
+ exit;
112
+
113
+ } else if ( isset( $_POST['edit_cron'] ) ) {
114
+ if ( ! current_user_can( 'manage_options' ) ) {
115
+ wp_die( esc_html__( 'You are not allowed to edit cron events.', 'wp-crontrol' ) );
116
+ }
117
+
118
+ extract( wp_unslash( $_POST ), EXTR_PREFIX_ALL, 'in' );
119
+ check_admin_referer( "edit-cron_{$in_original_hookname}_{$in_original_sig}_{$in_original_next_run}" );
120
+ $in_args = json_decode( $in_args, true );
121
+ $i = $this->delete_cron( $in_original_hookname, $in_original_sig, $in_original_next_run );
122
+ $i = $this->add_cron( $in_next_run, $in_schedule, $in_hookname, $in_args );
123
+ $redirect = array(
124
+ 'page' => 'crontrol_admin_manage_page',
125
+ 'crontrol_message' => '4',
126
+ 'crontrol_name' => urlencode( $in_hookname ),
127
+ );
128
+ wp_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
129
+ exit;
130
+
131
+ } else if ( isset( $_POST['edit_php_cron'] ) ) {
132
+ if ( ! current_user_can( 'manage_options' ) ) {
133
+ wp_die( esc_html__( 'You are not allowed to edit cron events.', 'wp-crontrol' ) );
134
+ }
135
+
136
+ extract( wp_unslash( $_POST ), EXTR_PREFIX_ALL, 'in' );
137
+ check_admin_referer( "edit-cron_{$in_original_hookname}_{$in_original_sig}_{$in_original_next_run}" );
138
+ $args['code'] = $in_hookcode;
139
+ $args = array( 'code' => $in_hookcode );
140
+ $i = $this->delete_cron( $in_original_hookname, $in_original_sig, $in_original_next_run );
141
+ $i = $this->add_cron( $in_next_run, $in_schedule, 'crontrol_cron_job', $args );
142
+ $redirect = array(
143
+ 'page' => 'crontrol_admin_manage_page',
144
+ 'crontrol_message' => '4',
145
+ 'crontrol_name' => urlencode( $in_hookname ),
146
+ );
147
+ wp_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
148
+ exit;
149
+
150
+ } else if ( isset( $_POST['new_schedule'] ) ) {
151
+ if ( ! current_user_can( 'manage_options' ) ) {
152
+ wp_die( esc_html__( 'You are not allowed to add new cron schedules.', 'wp-crontrol' ) );
153
+ }
154
+ check_admin_referer( 'new-sched' );
155
+ $name = wp_unslash( $_POST['internal_name'] );
156
+ $interval = wp_unslash( $_POST['interval'] );
157
+ $display = wp_unslash( $_POST['display_name'] );
158
+
159
+ // The user entered something that wasn't a number.
160
+ // Try to convert it with strtotime
161
+ if ( ! is_numeric( $interval ) ) {
162
+ $now = time();
163
+ $future = strtotime( $interval, $now );
164
+ if ( false === $future || -1 == $future || $now > $future ) {
165
+ $redirect = array(
166
+ 'page' => 'crontrol_admin_options_page',
167
+ 'crontrol_message' => '7',
168
+ 'crontrol_name' => urlencode( $interval ),
169
+ );
170
+ wp_redirect( add_query_arg( $redirect, admin_url( 'options-general.php' ) ) );
171
+ exit;
172
+ }
173
+ $interval = $future - $now;
174
+ } else if ( $interval <= 0 ) {
175
+ $redirect = array(
176
+ 'page' => 'crontrol_admin_options_page',
177
+ 'crontrol_message' => '7',
178
+ 'crontrol_name' => urlencode( $interval ),
179
+ );
180
+ wp_redirect( add_query_arg( $redirect, admin_url( 'options-general.php' ) ) );
181
+ exit;
182
+ }
183
+
184
+ $this->add_schedule( $name, $interval, $display );
185
+ $redirect = array(
186
+ 'page' => 'crontrol_admin_options_page',
187
+ 'crontrol_message' => '3',
188
+ 'crontrol_name' => urlencode( $name ),
189
+ );
190
+ wp_redirect( add_query_arg( $redirect, admin_url( 'options-general.php' ) ) );
191
+ exit;
192
+
193
+ } else if ( isset( $_GET['action'] ) && 'delete-sched' == $_GET['action'] ) {
194
+ if ( ! current_user_can( 'manage_options' ) ) {
195
+ wp_die( esc_html__( 'You are not allowed to delete cron schedules.', 'wp-crontrol' ) );
196
+ }
197
+ $id = wp_unslash( $_GET['id'] );
198
+ check_admin_referer( "delete-sched_{$id}" );
199
+ $this->delete_schedule( $id );
200
+ $redirect = array(
201
+ 'page' => 'crontrol_admin_options_page',
202
+ 'crontrol_message' => '2',
203
+ 'crontrol_name' => urlencode( $id ),
204
+ );
205
+ wp_redirect( add_query_arg( $redirect, admin_url( 'options-general.php' ) ) );
206
+ exit;
207
+
208
+ } else if ( isset( $_GET['action'] ) && 'delete-cron' == $_GET['action'] ) {
209
+ if ( ! current_user_can( 'manage_options' ) ) {
210
+ wp_die( esc_html__( 'You are not allowed to delete cron events.', 'wp-crontrol' ) );
211
+ }
212
+ $id = wp_unslash( $_GET['id'] );
213
+ $sig = wp_unslash( $_GET['sig'] );
214
+ $next_run = $_GET['next_run'];
215
+ check_admin_referer( "delete-cron_{$id}_{$sig}_{$next_run}" );
216
+ if ( $this->delete_cron( $id, $sig, $next_run ) ) {
217
+ $redirect = array(
218
+ 'page' => 'crontrol_admin_manage_page',
219
+ 'crontrol_message' => '6',
220
+ 'crontrol_name' => urlencode( $id ),
221
+ );
222
+ wp_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
223
+ exit;
224
+ } else {
225
+ $redirect = array(
226
+ 'page' => 'crontrol_admin_manage_page',
227
+ 'crontrol_message' => '7',
228
+ 'crontrol_name' => urlencode( $id ),
229
+ );
230
+ wp_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
231
+ exit;
232
+
233
+ };
234
+
235
+ } else if ( isset( $_GET['action'] ) && 'run-cron' == $_GET['action'] ) {
236
+ if ( ! current_user_can( 'manage_options' ) ) {
237
+ wp_die( esc_html__( 'You are not allowed to run cron events.', 'wp-crontrol' ) );
238
+ }
239
+ $id = wp_unslash( $_GET['id'] );
240
+ $sig = wp_unslash( $_GET['sig'] );
241
+ check_admin_referer( "run-cron_{$id}_{$sig}" );
242
+ if ( $this->run_cron( $id, $sig ) ) {
243
+ $redirect = array(
244
+ 'page' => 'crontrol_admin_manage_page',
245
+ 'crontrol_message' => '1',
246
+ 'crontrol_name' => urlencode( $id ),
247
+ );
248
+ wp_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
249
+ exit;
250
+ } else {
251
+ $redirect = array(
252
+ 'page' => 'crontrol_admin_manage_page',
253
+ 'crontrol_message' => '8',
254
+ 'crontrol_name' => urlencode( $id ),
255
+ );
256
+ wp_redirect( add_query_arg( $redirect, admin_url( 'tools.php' ) ) );
257
+ exit;
258
+ }
259
+ }
260
+ }
261
+
262
+ /**
263
+ * Executes a cron event immediately.
264
+ *
265
+ * Executes an event by scheduling a new single event with the same arguments.
266
+ *
267
+ * @param string $hookname The hookname of the cron event to run
268
+ */
269
+ public function run_cron( $hookname, $sig ) {
270
+ $crons = _get_cron_array();
271
+ foreach ( $crons as $time => $cron ) {
272
+ if ( isset( $cron[ $hookname ][ $sig ] ) ) {
273
+ $args = $cron[ $hookname ][ $sig ]['args'];
274
  delete_transient( 'doing_cron' );
275
+ wp_schedule_single_event( time() - 1, $hookname, $args );
276
+ spawn_cron();
277
+ return true;
278
+ }
279
+ }
280
+ return false;
281
+ }
282
+
283
+ /**
284
+ * Adds a new cron event.
285
+ *
286
+ * @param string $next_run A human-readable (strtotime) time that the event should be run at
287
+ * @param string $schedule The recurrence of the cron event
288
+ * @param string $hookname The name of the hook to execute
289
+ * @param array $args Arguments to add to the cron event
290
+ */
291
+ public function add_cron( $next_run, $schedule, $hookname, $args ) {
292
+ $next_run = strtotime( $next_run );
293
+ if ( false === $next_run || -1 == $next_run ) {
294
+ $next_run = time();
295
+ }
296
+ if ( ! is_array( $args ) ) {
297
+ $args = array();
298
+ }
299
+ if ( '_oneoff' == $schedule ) {
300
+ return wp_schedule_single_event( $next_run, $hookname, $args ) === null;
301
+ } else {
302
+ return wp_schedule_event( $next_run, $schedule, $hookname, $args ) === null;
303
+ }
304
+ }
305
+
306
+ /**
307
+ * Deletes a cron event.
308
+ *
309
+ * @param string $name The hookname of the event to delete.
310
+ */
311
+ public function delete_cron( $to_delete, $sig, $next_run ) {
312
+ $crons = _get_cron_array();
313
+ if ( isset( $crons[ $next_run ][ $to_delete ][ $sig ] ) ) {
314
+ $args = $crons[ $next_run ][ $to_delete ][ $sig ]['args'];
315
+ wp_unschedule_event( $next_run, $to_delete, $args );
316
+ return true;
317
+ }
318
+ return false;
319
+ }
320
+
321
+ /**
322
+ * Adds a new custom cron schedule.
323
+ *
324
+ * @param string $name The internal name of the schedule
325
+ * @param int $interval The interval between executions of the new schedule
326
+ * @param string $display The display name of the schedule
327
+ */
328
+ public function add_schedule( $name, $interval, $display ) {
329
+ $old_scheds = get_option( 'crontrol_schedules', array() );
330
+ $old_scheds[ $name ] = array( 'interval' => $interval, 'display' => $display );
331
+ update_option( 'crontrol_schedules', $old_scheds );
332
+ }
333
+
334
+ /**
335
+ * Deletes a custom cron schedule.
336
+ *
337
+ * @param string $name The internal_name of the schedule to delete.
338
+ */
339
+ public function delete_schedule( $name ) {
340
+ $scheds = get_option( 'crontrol_schedules', array() );
341
+ unset( $scheds[ $name ] );
342
+ update_option( 'crontrol_schedules', $scheds );
343
+ }
344
+
345
+ /**
346
+ * Sets up the plugin environment upon first activation.
347
+ *
348
+ * Run using the 'activate_' action.
349
+ */
350
+ public function action_activate() {
351
+ add_option( 'crontrol_schedules', array() );
352
+
353
+ // if there's never been a cron event, _get_cron_array will return false
354
+ if ( _get_cron_array() === false ) {
355
+ _set_cron_array( array() );
356
+ }
357
+ }
358
+
359
+ /**
360
+ * Adds options & management pages to the admin menu.
361
+ *
362
+ * Run using the 'admin_menu' action.
363
+ */
364
+ public function action_admin_menu() {
365
+ add_options_page( esc_html__( 'Cron Schedules', 'wp-crontrol' ), esc_html__( 'Cron Schedules', 'wp-crontrol' ), 'manage_options', 'crontrol_admin_options_page', array( $this, 'admin_options_page' ) );
366
+ add_management_page( esc_html__( 'Cron Events', 'wp-crontrol' ), esc_html__( 'Cron Events', 'wp-crontrol' ), 'manage_options', 'crontrol_admin_manage_page', array( $this, 'admin_manage_page' ) );
367
+ }
368
+
369
+ public function plugin_action_links( $actions, $plugin_file, $plugin_data, $context ) {
370
+ $actions['crontrol-events'] = sprintf(
371
+ '<a href="%s">%s</a>',
372
+ admin_url( 'tools.php?page=crontrol_admin_manage_page' ),
373
+ esc_html__( 'Cron Events', 'wp-crontrol' )
374
+ );
375
+ $actions['crontrol-schedules'] = sprintf(
376
+ '<a href="%s">%s</a>',
377
+ admin_url( 'options-general.php?page=crontrol_admin_options_page' ),
378
+ esc_html__( 'Cron Schedules', 'wp-crontrol' )
379
+ );
380
+ return $actions;
381
+ }
382
+
383
+ /**
384
+ * Gives WordPress the plugin's set of cron schedules.
385
+ *
386
+ * Called by the 'cron_schedules' filter.
387
+ *
388
  * @param array $scheds The current cron schedules. Usually an empty array.
389
  * @return array The existing cron schedules along with the plugin's schedules.
390
+ */
391
+ public function filter_cron_schedules( $scheds ) {
392
+ $new_scheds = get_option( 'crontrol_schedules', array() );
393
+ return array_merge( $new_scheds, $scheds );
394
+ }
395
+
396
+ /**
397
+ * Displays the options page for the plugin.
398
+ */
399
+ public function admin_options_page() {
400
+ $schedules = $this->get_schedules();
401
+ $custom_schedules = get_option( 'crontrol_schedules', array() );
402
+ $custom_keys = array_keys( $custom_schedules );
403
+
404
+ $messages = array(
405
+ '2' => __( 'Successfully deleted the cron schedule %s.', 'wp-crontrol' ),
406
+ '3' => __( 'Successfully added the cron schedule %s.', 'wp-crontrol' ),
407
+ '7' => __( 'Cron schedule not added because there was a problem parsing %s.', 'wp-crontrol' ),
408
+ );
409
+ if ( isset( $_GET['crontrol_message'] ) && isset( $_GET['crontrol_name'] ) && isset( $messages[ $_GET['crontrol_message'] ] ) ) {
410
+ $hook = wp_unslash( $_GET['crontrol_name'] );
411
+ $msg = sprintf( esc_html( $messages[ $_GET['crontrol_message'] ] ), '<strong>' . esc_html( $hook ) . '</strong>' );
412
+
413
+ printf( '<div id="message" class="updated notice is-dismissible"><p>%s</p></div>', $msg ); // WPCS:: XSS ok.
414
+ }
415
+
416
+ ?>
417
+ <div class="wrap">
418
+ <h1><?php esc_html_e( 'WP-Cron Schedules', 'wp-crontrol' ); ?></h1>
419
+ <p><?php esc_html_e( 'WP-Cron schedules are the time intervals that are available for scheduling events. You can only delete custom schedules.', 'wp-crontrol' ); ?></p>
420
+ <div id="ajax-response"></div>
421
+ <table class="widefat striped">
422
+ <thead>
423
+ <tr>
424
+ <th scope="col"><?php esc_html_e( 'Name', 'wp-crontrol' ); ?></th>
425
+ <th scope="col"><?php esc_html_e( 'Interval', 'wp-crontrol' ); ?></th>
426
+ <th scope="col"><?php esc_html_e( 'Display Name', 'wp-crontrol' ); ?></th>
427
+ <th>&nbsp;</th>
428
+ </tr>
429
+ </thead>
430
+ <tbody>
431
+ <?php
432
+ if ( empty( $schedules ) ) {
433
+ ?>
434
+ <tr colspan="4"><td><?php esc_html_e( 'You currently have no schedules. Add one below.', 'wp-crontrol' ); ?></td></tr>
435
+ <?php
436
+ } else {
437
+ foreach ( $schedules as $name => $data ) {
438
+ printf( '<tr id="sched-%s">',
439
+ esc_attr( $name )
440
+ );
441
+ printf( '<td>%s</td>',
442
+ esc_html( $name )
443
+ );
444
+ printf( '<td>%s (%s)</td>',
445
+ esc_html( $data['interval'] ),
446
+ esc_html( $this->interval( $data['interval'] ) )
447
+ );
448
+ printf( '<td>%s</td>',
449
+ esc_html( $data['display'] )
450
+ );
451
+ if ( in_array( $name, $custom_keys ) ) {
452
+ $url = add_query_arg( array(
453
+ 'page' => 'crontrol_admin_options_page',
454
+ 'action' => 'delete-sched',
455
+ 'id' => urlencode( $name ),
456
+ ), admin_url( 'options-general.php' ) );
457
+ $url = wp_nonce_url( $url, 'delete-sched_' . $name );
458
+ printf( '<td><a href="%s" class="delete">%s</a></td>',
459
+ esc_url( $url ),
460
+ esc_html__( 'Delete', 'wp-crontrol' )
461
+ );
462
+ } else {
463
+ echo '<td>&nbsp;</td>';
464
+ }
465
+ echo '</tr>';
466
+ }
467
+ }
468
+ ?>
469
+ </tbody>
470
+ </table>
471
+ </div>
472
+ <div class="wrap narrow">
473
+ <h2 class="title"><?php esc_html_e( 'Add new cron schedule', 'wp-crontrol' ); ?></h2>
474
+ <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>
475
+ <form method="post" action="options-general.php?page=crontrol_admin_options_page">
476
+ <table class="form-table">
477
+ <tbody>
478
+ <tr>
479
+ <th valign="top" scope="row"><label for="cron_internal_name"><?php esc_html_e( 'Internal name', 'wp-crontrol' ); ?>:</label></th>
480
+ <td><input type="text" class="regular-text" value="" id="cron_internal_name" name="internal_name"/></td>
481
+ </tr>
482
+ <tr>
483
+ <th valign="top" scope="row"><label for="cron_interval"><?php esc_html_e( 'Interval (seconds)', 'wp-crontrol' ); ?>:</label></th>
484
+ <td><input type="text" class="regular-text" value="" id="cron_interval" name="interval"/></td>
485
+ </tr>
486
+ <tr>
487
+ <th valign="top" scope="row"><label for="cron_display_name"><?php esc_html_e( 'Display name', 'wp-crontrol' ); ?>:</label></th>
488
+ <td><input type="text" class="regular-text" value="" id="cron_display_name" name="display_name"/></td>
489
+ </tr>
490
+ </tbody></table>
491
+ <p class="submit"><input id="schedadd-submit" type="submit" class="button-primary" value="<?php esc_attr_e( 'Add Cron Schedule', 'wp-crontrol' ); ?>" name="new_schedule"/></p>
492
+ <?php wp_nonce_field( 'new-sched' ); ?>
493
+ </form>
494
+ </div>
495
+ <?php
496
+ }
497
+
498
+ /**
499
+ * Gets a sorted (according to interval) list of the cron schedules
500
+ */
501
+ public function get_schedules() {
502
+ $schedules = wp_get_schedules();
503
+ uasort( $schedules, create_function( '$a, $b', 'return $a["interval"] - $b["interval"];' ) );
504
+ return $schedules;
505
+ }
506
+
507
+ /**
508
+ * Displays a dropdown filled with the possible schedules, including non-repeating.
509
+ *
510
+ * @param boolean $current The currently selected schedule
511
+ */
512
+ public function schedules_dropdown( $current = false ) {
513
+ $schedules = $this->get_schedules();
514
+ ?>
515
+ <select class="postform" name="schedule" id="schedule">
516
+ <option <?php selected( $current, '_oneoff' ); ?> value="_oneoff"><?php esc_html_e( 'Non-repeating', 'wp-crontrol' ); ?></option>
517
+ <?php foreach ( $schedules as $sched_name => $sched_data ) { ?>
518
+ <option <?php selected( $current, $sched_name ); ?> value="<?php echo esc_attr( $sched_name ); ?>">
519
+ <?php
520
+ printf(
521
+ '%s (%s)',
522
+ esc_html( $sched_data['display'] ),
523
+ esc_html( $this->interval( $sched_data['interval'] ) )
524
+ );
525
+ ?>
526
+ </option>
527
+ <?php } ?>
528
+ </select>
529
+ <?php
530
+ }
531
+
532
+ /**
533
+ * Gets the status of WP-Cron functionality on the site by performing a test spawn. Cached for one hour when all is well.
534
+ *
535
+ */
536
+ public function test_cron_spawn( $cache = true ) {
537
+ global $wp_version;
538
+
539
+ if ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ) {
540
+ return new WP_Error( 'disable_wp_cron', __( 'The DISABLE_WP_CRON constant is set to true. WP-Cron spawning is disabled.', 'wp-crontrol' ) );
541
+ }
542
+
543
+ if ( defined( 'ALTERNATE_WP_CRON' ) && ALTERNATE_WP_CRON ) {
544
  return true;
545
+ }
546
 
547
  $cached_status = get_transient( 'wp-cron-test-ok' );
548
 
549
+ if ( $cache && $cached_status ) {
550
  return true;
551
+ }
552
 
553
+ $sslverify = version_compare( $wp_version, 4.0, '<' );
554
  $doing_wp_cron = sprintf( '%.22F', microtime( true ) );
555
 
556
  $cron_request = apply_filters( 'cron_request', array(
559
  'args' => array(
560
  'timeout' => 3,
561
  'blocking' => true,
562
+ 'sslverify' => apply_filters( 'https_local_ssl_verify', $sslverify ),
563
+ ),
564
  ) );
565
 
566
  $cron_request['args']['blocking'] = true;
569
 
570
  if ( is_wp_error( $result ) ) {
571
  return $result;
572
+ } else if ( wp_remote_retrieve_response_code( $result ) >= 300 ) {
573
+ return new WP_Error( 'unexpected_http_response_code', sprintf(
574
+ __( 'Unexpected HTTP response code: %s', 'wp-crontrol' ),
575
+ intval( wp_remote_retrieve_response_code( $result ) )
576
+ ) );
577
  } else {
578
  set_transient( 'wp-cron-test-ok', 1, 3600 );
579
  return true;
581
 
582
  }
583
 
584
+ /**
585
+ * Shows the status of WP-Cron functionality on the site. Only displays a message when there's a problem.
586
+ *
587
+ */
588
+ public function show_cron_status() {
589
 
590
  $status = $this->test_cron_spawn();
591
 
592
  if ( is_wp_error( $status ) ) {
593
  ?>
594
  <div id="cron-status-error" class="error">
595
+ <p><?php printf( 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' ), '<br><strong>' . esc_html( $status->get_error_message() ) . '</strong>' ); ?></p>
596
  </div>
597
  <?php
598
  }
599
 
600
  }
601
 
602
+ /**
603
+ * Shows the form used to add/edit cron events.
604
+ *
605
+ * @param boolean $is_php Whether this is a PHP cron event
606
+ * @param mixed $existing An array of existing values for the cron event, or null
607
+ */
608
+ public function show_cron_form( $is_php, $existing ) {
609
+ $new_tabs = array(
610
+ 'cron' => __( 'Add Cron Event', 'wp-crontrol' ),
611
+ 'php-cron' => __( 'Add PHP Cron Event', 'wp-crontrol' ),
612
+ );
613
+ $modify_tabs = array(
614
+ 'cron' => __( 'Modify Cron Event', 'wp-crontrol' ),
615
+ 'php-cron' => __( 'Modify PHP Cron Event', 'wp-crontrol' ),
616
+ );
617
+ $new_links = array(
618
+ 'cron' => admin_url( 'tools.php?page=crontrol_admin_manage_page&action=new-cron' ) . '#crontrol_form',
619
+ 'php-cron' => admin_url( 'tools.php?page=crontrol_admin_manage_page&action=new-php-cron' ) . '#crontrol_form',
620
+ );
621
+ if ( $is_php ) {
622
+ $helper_text = esc_html__( 'Cron events trigger actions in your code. Using the form below, you can enter the schedule of the action, as well as the PHP code for the action itself.', 'wp-crontrol' );
623
+ } else {
624
+ $helper_text = sprintf(
625
+ esc_html__( 'Cron events trigger actions in your code. A cron event added using the form below needs a corresponding action hook somewhere in code, perhaps the %1$s file in your theme.', 'wp-crontrol' ),
626
+ '<code>functions.php</code>'
627
+ );
628
+ }
629
+ if ( is_array( $existing ) ) {
630
+ $other_fields = wp_nonce_field( "edit-cron_{$existing['hookname']}_{$existing['sig']}_{$existing['next_run']}", '_wpnonce', true, false );
631
+ $other_fields .= sprintf( '<input name="original_hookname" type="hidden" value="%s" />',
632
+ esc_attr( $existing['hookname'] )
633
+ );
634
+ $other_fields .= sprintf( '<input name="original_sig" type="hidden" value="%s" />',
635
+ esc_attr( $existing['sig'] )
636
+ );
637
+ $other_fields .= sprintf( '<input name="original_next_run" type="hidden" value="%s" />',
638
+ esc_attr( $existing['next_run'] )
639
+ );
640
+ $existing['args'] = $is_php ? $existing['args']['code'] : wp_json_encode( $existing['args'] );
641
+ $existing['next_run'] = date( 'Y-m-d H:i:s', $existing['next_run'] );
642
+ $action = $is_php ? 'edit_php_cron' : 'edit_cron';
643
+ $button = $is_php ? $modify_tabs['php-cron'] : $modify_tabs['cron'];
644
+ $show_edit_tab = true;
645
+ } else {
646
+ $other_fields = wp_nonce_field( 'new-cron', '_wpnonce', true, false );
647
+ $existing = array( 'hookname' => '', 'hookcode' => '', 'args' => '', 'next_run' => 'now', 'schedule' => false );
648
+ $action = $is_php ? 'new_php_cron' : 'new_cron';
649
+ $button = $is_php ? $new_tabs['php-cron'] : $new_tabs['cron'];
650
+ $show_edit_tab = false;
651
+ }
652
+ ?>
653
+ <div id="crontrol_form" class="wrap narrow">
654
+ <h2 class="nav-tab-wrapper">
655
+ <a href="<?php echo esc_url( $new_links['cron'] ); ?>" class="nav-tab<?php if ( ! $show_edit_tab && ! $is_php ) { echo ' nav-tab-active'; } ?>"><?php echo esc_html( $new_tabs['cron'] ); ?></a>
656
+ <?php if ( current_user_can( 'edit_files' ) ) { ?>
657
+ <a href="<?php echo esc_url( $new_links['php-cron'] ); ?>" class="nav-tab<?php if ( ! $show_edit_tab && $is_php ) { echo ' nav-tab-active'; } ?>"><?php echo esc_html( $new_tabs['php-cron'] ); ?></a>
658
+ <?php } ?>
659
+ <?php if ( $show_edit_tab ) { ?>
660
+ <span class="nav-tab nav-tab-active"><?php echo esc_html( $button ); ?></span>
661
+ <?php } ?>
662
+ </h2>
663
+ <p><?php echo $helper_text; // WPCS:: XSS ok. ?></p>
664
+ <form method="post" action="<?php echo esc_url( admin_url( 'tools.php?page=crontrol_admin_manage_page' ) ); ?>">
665
+ <?php echo $other_fields; // WPCS:: XSS ok. ?>
666
+ <table class="form-table"><tbody>
667
+ <?php if ( $is_php ) : ?>
668
+ <tr>
669
+ <th valign="top" scope="row"><label for="hookcode"><?php esc_html_e( 'Hook code:', 'wp-crontrol' ); ?></label></th>
670
+ <td><textarea class="large-text code" rows="10" cols="50" id="hookcode" name="hookcode"><?php echo esc_textarea( $existing['args'] ); ?></textarea></td>
671
+ </tr>
672
+ <?php else : ?>
673
+ <tr>
674
+ <th valign="top" scope="row"><label for="hookname"><?php esc_html_e( 'Hook name:', 'wp-crontrol' ); ?></label></th>
675
+ <td><input type="text" class="regular-text" id="hookname" name="hookname" value="<?php echo esc_attr( $existing['hookname'] ); ?>"/></td>
676
+ </tr>
677
+ <tr>
678
+ <th valign="top" scope="row"><label for="args"><?php esc_html_e( 'Arguments:', 'wp-crontrol' ); ?></label></th>
679
+ <td>
680
+ <input type="text" class="regular-text" id="args" name="args" value="<?php echo esc_attr( $existing['args'] ); ?>"/>
681
+ <p class="description"><?php esc_html_e( "e.g. [25], ['asdf'], or ['i','want',25,'cakes']", 'wp-crontrol' ); ?></p>
682
+ </td>
683
+ </tr>
684
+ <?php endif; ?>
685
+ <tr>
686
+ <th valign="top" scope="row"><label for="next_run"><?php esc_html_e( 'Next run (UTC):', 'wp-crontrol' ); ?></label></th>
687
+ <td>
688
+ <input type="text" class="regular-text" id="next_run" name="next_run" value="<?php echo esc_attr( $existing['next_run'] ); ?>"/>
689
+ <p class="description"><?php esc_html_e( "e.g. 'now', 'tomorrow', '+2 days', or '25-02-2020 12:34:00'", 'wp-crontrol' ); ?></p>
690
+ </td>
691
+ </tr><tr>
692
+ <th valign="top" scope="row"><label for="schedule"><?php esc_html_e( 'Event schedule:', 'wp-crontrol' ); ?></label></th>
693
+ <td>
694
+ <?php $this->schedules_dropdown( $existing['schedule'] ); ?>
695
+ </td>
696
+ </tr>
697
+ </tbody></table>
698
+ <p class="submit"><input type="submit" class="button-primary" value="<?php echo esc_attr( $button ); ?>" name="<?php echo esc_attr( $action ); ?>"/></p>
699
+ </form>
700
+ </div>
701
+ <?php
702
+ }
703
+
704
+ public function get_cron_events() {
705
+
706
+ $crons = _get_cron_array();
707
+ $events = array();
708
 
709
  if ( empty( $crons ) ) {
710
  return new WP_Error(
713
  );
714
  }
715
 
716
+ foreach ( $crons as $time => $cron ) {
717
+ foreach ( $cron as $hook => $dings ) {
718
+ foreach ( $dings as $sig => $data ) {
719
 
720
  # This is a prime candidate for a Crontrol_Event class but I'm not bothering currently.
721
+ $events[ "$hook-$sig-$time" ] = (object) array(
722
  'hook' => $hook,
723
  'time' => $time,
724
  'sig' => $sig,
733
 
734
  return $events;
735
 
736
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
737
 
738
+ /**
739
+ * Displays the manage page for the plugin.
740
+ */
741
+ public function admin_manage_page() {
742
+ $messages = array(
743
+ '1' => __( 'Successfully executed the cron event %s', 'wp-crontrol' ),
744
+ '4' => __( 'Successfully edited the cron event %s', 'wp-crontrol' ),
745
+ '5' => __( 'Successfully created the cron event %s', 'wp-crontrol' ),
746
+ '6' => __( 'Successfully deleted the cron event %s', 'wp-crontrol' ),
747
+ '7' => __( 'Failed to the delete the cron event %s', 'wp-crontrol' ),
748
+ '8' => __( 'Failed to the execute the cron event %s', 'wp-crontrol' ),
749
+ );
750
+ if ( isset( $_GET['crontrol_name'] ) && isset( $_GET['crontrol_message'] ) && isset( $messages[ $_GET['crontrol_message'] ] ) ) {
751
+ $hook = wp_unslash( $_GET['crontrol_name'] );
752
+ $msg = sprintf( esc_html( $messages[ $_GET['crontrol_message'] ] ), '<strong>' . esc_html( $hook ) . '</strong>' );
753
+
754
+ printf( '<div id="message" class="updated notice is-dismissible"><p>%s</p></div>', $msg ); // WPCS:: XSS ok.
755
+ }
756
+ $events = $this->get_cron_events();
757
+ $doing_edit = ( isset( $_GET['action'] ) && 'edit-cron' == $_GET['action'] ) ? wp_unslash( $_GET['id'] ) : false ;
758
+ $time_format = 'Y-m-d H:i:s';
759
 
760
+ $tzstring = get_option( 'timezone_string' );
761
+ $current_offset = get_option( 'gmt_offset' );
762
 
763
+ if ( $current_offset >= 0 ) {
764
  $current_offset = '+' . $current_offset;
765
+ }
766
 
767
+ if ( '' === $tzstring ) {
768
  $tz = sprintf( 'UTC%s', $current_offset );
769
+ } else {
770
  $tz = sprintf( '%s (UTC%s)', str_replace( '_', ' ', $tzstring ), $current_offset );
771
+ }
772
 
773
+ $this->show_cron_status();
774
+
775
+ ?>
776
+ <div class="wrap">
777
+ <h1><?php esc_html_e( 'WP-Cron Events', 'wp-crontrol' ); ?></h1>
778
+ <p></p>
779
+ <table class="widefat striped">
780
+ <thead>
781
+ <tr>
782
+ <th><?php esc_html_e( 'Hook Name', 'wp-crontrol' ); ?></th>
783
+ <th><?php esc_html_e( 'Arguments', 'wp-crontrol' ); ?></th>
784
+ <th><?php esc_html_e( 'Next Run', 'wp-crontrol' ); ?></th>
785
+ <th><?php esc_html_e( 'Recurrence', 'wp-crontrol' ); ?></th>
786
+ <th colspan="3">&nbsp;</th>
787
+ </tr>
788
+ </thead>
789
+ <tbody>
790
+ <?php
791
+ if ( is_wp_error( $events ) ) {
792
+ ?>
793
+ <tr><td colspan="7"><?php echo esc_html( $events->get_error_message() ); ?></td></tr>
794
+ <?php
795
+ } else {
796
+ foreach ( $events as $id => $event ) {
 
 
797
 
798
  if ( $doing_edit && $doing_edit == $event->hook && $event->time == $_GET['next_run'] && $event->sig == $_GET['sig'] ) {
799
  $doing_edit = array(
801
  'next_run' => $event->time,
802
  'schedule' => ( $event->schedule ? $event->schedule : '_oneoff' ),
803
  'sig' => $event->sig,
804
+ 'args' => $event->args,
805
  );
806
  }
807
 
808
+ if ( empty( $event->args ) ) {
809
+ $args = __( 'None', 'wp-crontrol' );
810
+ } else {
811
+ if ( defined( 'JSON_UNESCAPED_SLASHES' ) ) {
812
+ $args = wp_json_encode( $event->args, JSON_UNESCAPED_SLASHES );
813
+ } else {
814
+ $args = stripslashes( wp_json_encode( $event->args ) );
815
+ }
816
+ }
817
+
818
+ echo '<tr id="cron-' . esc_attr( $id ) . '" class="">';
819
+
820
+ if ( 'crontrol_cron_job' == $event->hook ) {
821
+ echo '<td><em>' . esc_html__( 'PHP Cron', 'wp-crontrol' ) . '</em></td>';
822
+ echo '<td><em>' . esc_html__( 'PHP Code', 'wp-crontrol' ) . '</em></td>';
823
+ } else {
824
+ echo '<td>' . esc_html( $event->hook ) . '</td>';
825
+ echo '<td>' . esc_html( $args ) . '</td>';
826
+ }
827
+
828
+ echo '<td>';
829
+ printf( '%s (%s)',
830
+ esc_html( get_date_from_gmt( date( 'Y-m-d H:i:s', $event->time ), $time_format ) ),
831
+ esc_html( $this->time_since( time(), $event->time ) )
832
+ );
833
+ echo '</td>';
834
+
835
+ if ( $event->schedule ) {
836
+ echo '<td>';
837
+ echo esc_html( $this->interval( $event->interval ) );
838
+ echo '</td>';
839
+ } else {
840
+ echo '<td>';
841
+ esc_html_e( 'Non-repeating', 'wp-crontrol' );
842
+ echo '</td>';
843
+ }
844
+
845
+ $link = array(
846
+ 'page' => 'crontrol_admin_manage_page',
847
+ 'action' => 'edit-cron',
848
+ 'id' => urlencode( $event->hook ),
849
+ 'sig' => urlencode( $event->sig ),
850
+ 'next_run' => urlencode( $event->time ),
851
+ );
852
+ $link = add_query_arg( $link, admin_url( 'tools.php' ) ) . '#crontrol_form';
853
+ echo "<td><a class='view' href='" . esc_url( $link ) . "'>" . esc_html__( 'Edit', 'wp-crontrol' ) . '</a></td>';
854
+
855
+ $link = array(
856
+ 'page' => 'crontrol_admin_manage_page',
857
+ 'action' => 'run-cron',
858
+ 'id' => urlencode( $event->hook ),
859
+ 'sig' => urlencode( $event->sig ),
860
+ 'next_run' => urlencode( $event->time ),
861
+ );
862
+ $link = add_query_arg( $link, admin_url( 'tools.php' ) );
863
+ $link = wp_nonce_url( $link, "run-cron_{$event->hook}_{$event->sig}" );
864
+ echo "<td><a class='view' href='". esc_url( $link ) ."'>" . esc_html__( 'Run Now', 'wp-crontrol' ) . '</a></td>';
865
+
866
+ $link = array(
867
+ 'page' => 'crontrol_admin_manage_page',
868
+ 'action' => 'delete-cron',
869
+ 'id' => urlencode( $event->hook ),
870
+ 'sig' => urlencode( $event->sig ),
871
+ 'next_run' => urlencode( $event->time ),
872
+ );
873
+ $link = add_query_arg( $link, admin_url( 'tools.php' ) );
874
+ $link = wp_nonce_url( $link, "delete-cron_{$event->hook}_{$event->sig}_{$event->time}" );
875
+ echo "<td><a class='delete' href='".esc_url( $link )."'>" . esc_html__( 'Delete', 'wp-crontrol' ) . '</a></td>';
876
+
877
+ echo '</tr>';
878
+
879
+ }
880
+ }
881
+ ?>
882
+ </tbody>
883
+ </table>
884
+
885
+ <div class="tablenav">
886
+ <p class="description">
887
+ <?php printf( esc_html__( 'Local timezone is %s', 'wp-crontrol' ), '<code>' . esc_html( $tz ) . '</code>' ); ?>
888
+ <span id="utc-time"><?php printf( esc_html__( 'UTC time is %s', 'wp-crontrol' ), '<code>' . esc_html( date_i18n( $time_format, false, true ) ) . '</code>' ); ?></span>
889
+ <span id="local-time"><?php printf( esc_html__( 'Local time is %s', 'wp-crontrol' ), '<code>' . esc_html( date_i18n( $time_format ) ) . '</code>' ); ?></span>
890
+ </p>
891
+ </div>
892
+
893
+ </div>
894
+ <?php
895
+ if ( is_array( $doing_edit ) ) {
896
+ $this->show_cron_form( 'crontrol_cron_job' == $doing_edit['hookname'], $doing_edit );
897
+ } else {
898
+ $this->show_cron_form( ( isset( $_GET['action'] ) and 'new-php-cron' == $_GET['action'] ), false );
899
+ }
900
+ }
901
+
902
+ /**
903
+ * Pretty-prints the difference in two times.
904
+ *
905
+ * @param time $older_date
906
+ * @param time $newer_date
907
+ * @return string The pretty time_since value
908
+ * @link http://binarybonsai.com/code/timesince.txt
909
+ */
910
+ public function time_since( $older_date, $newer_date ) {
911
+ return $this->interval( $newer_date - $older_date );
912
  }
913
 
914
+ public function interval( $since ) {
915
+ // array of time period chunks
916
+ $chunks = array(
917
+ array( 60 * 60 * 24 * 365, _n_noop( '%s year', '%s years', 'wp-crontrol' ) ),
918
+ array( 60 * 60 * 24 * 30, _n_noop( '%s month', '%s months', 'wp-crontrol' ) ),
919
+ array( 60 * 60 * 24 * 7, _n_noop( '%s week', '%s weeks', 'wp-crontrol' ) ),
920
+ array( 60 * 60 * 24, _n_noop( '%s day', '%s days', 'wp-crontrol' ) ),
921
+ array( 60 * 60, _n_noop( '%s hour', '%s hours', 'wp-crontrol' ) ),
922
+ array( 60, _n_noop( '%s minute', '%s minutes', 'wp-crontrol' ) ),
923
+ array( 1, _n_noop( '%s second', '%s seconds', 'wp-crontrol' ) ),
924
+ );
925
+
926
+ if ( $since <= 0 ) {
927
+ return __( 'now', 'wp-crontrol' );
928
+ }
929
+
930
+ // we only want to output two chunks of time here, eg:
931
+ // x years, xx months
932
+ // x days, xx hours
933
+ // so there's only two bits of calculation below:
934
+
935
+ // step one: the first chunk
936
+ for ( $i = 0, $j = count( $chunks ); $i < $j; $i++ ) {
937
+ $seconds = $chunks[ $i ][0];
938
+ $name = $chunks[ $i ][1];
939
+
940
+ // finding the biggest chunk (if the chunk fits, break)
941
+ if ( ( $count = floor( $since / $seconds ) ) != 0 ) {
942
+ break;
943
+ }
944
+ }
945
+
946
+ // set output var
947
+ $output = sprintf( translate_nooped_plural( $name, $count, 'wp-crontrol' ), $count );
948
+
949
+ // step two: the second chunk
950
+ if ( $i + 1 < $j ) {
951
+ $seconds2 = $chunks[ $i + 1 ][0];
952
+ $name2 = $chunks[ $i + 1 ][1];
953
+
954
+ if ( ( $count2 = floor( ( $since - ( $seconds * $count ) ) / $seconds2 ) ) != 0 ) {
955
+ // add to output var
956
+ $output .= ' ' . sprintf( translate_nooped_plural( $name2, $count2, 'wp-crontrol' ), $count2 );
957
+ }
958
+ }
959
+
960
+ return $output;
 
 
 
 
 
961
  }
962
 
963
  public static function init() {
964
 
965
  static $instance = null;
966
 
967
+ if ( ! $instance ) {
968
  $instance = new Crontrol;
969
+ }
970
 
971
  return $instance;
972
 
973
  }
 
974
  }
975
 
 
 
 
976
  // Get this show on the road
977
  Crontrol::init();