WP Crontrol - Version 1.2

Version Description

  • Added support for wp-cli

=

Download this release

Release Info

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

Code changes from version 1.1 to 1.2

Files changed (6) hide show
  1. JSON.php +0 -806
  2. class-wp-cli.php +98 -0
  3. readme.txt +46 -19
  4. screenshot-1.png +0 -0
  5. screenshot-2.png +0 -0
  6. wp-crontrol.php +132 -101
JSON.php DELETED
@@ -1,806 +0,0 @@
1
- <?php
2
- /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
-
4
- /**
5
- * Converts to and from JSON format.
6
- *
7
- * JSON (JavaScript Object Notation) is a lightweight data-interchange
8
- * format. It is easy for humans to read and write. It is easy for machines
9
- * to parse and generate. It is based on a subset of the JavaScript
10
- * Programming Language, Standard ECMA-262 3rd Edition - December 1999.
11
- * This feature can also be found in Python. JSON is a text format that is
12
- * completely language independent but uses conventions that are familiar
13
- * to programmers of the C-family of languages, including C, C++, C#, Java,
14
- * JavaScript, Perl, TCL, and many others. These properties make JSON an
15
- * ideal data-interchange language.
16
- *
17
- * This package provides a simple encoder and decoder for JSON notation. It
18
- * is intended for use with client-side Javascript applications that make
19
- * use of HTTPRequest to perform server communication functions - data can
20
- * be encoded into JSON notation for use in a client-side javascript, or
21
- * decoded from incoming Javascript requests. JSON format is native to
22
- * Javascript, and can be directly eval()'ed with no further parsing
23
- * overhead
24
- *
25
- * All strings should be in ASCII or UTF-8 format!
26
- *
27
- * LICENSE: Redistribution and use in source and binary forms, with or
28
- * without modification, are permitted provided that the following
29
- * conditions are met: Redistributions of source code must retain the
30
- * above copyright notice, this list of conditions and the following
31
- * disclaimer. Redistributions in binary form must reproduce the above
32
- * copyright notice, this list of conditions and the following disclaimer
33
- * in the documentation and/or other materials provided with the
34
- * distribution.
35
- *
36
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
37
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
38
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
39
- * NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
40
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
41
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
42
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
44
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
45
- * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
46
- * DAMAGE.
47
- *
48
- * @category
49
- * @package Services_JSON
50
- * @author Michal Migurski <mike-json@teczno.com>
51
- * @author Matt Knapp <mdknapp[at]gmail[dot]com>
52
- * @author Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
53
- * @copyright 2005 Michal Migurski
54
- * @version CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $
55
- * @license http://www.opensource.org/licenses/bsd-license.php
56
- * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198
57
- */
58
-
59
- /**
60
- * Marker constant for Services_JSON::decode(), used to flag stack state
61
- */
62
- define('SERVICES_JSON_SLICE', 1);
63
-
64
- /**
65
- * Marker constant for Services_JSON::decode(), used to flag stack state
66
- */
67
- define('SERVICES_JSON_IN_STR', 2);
68
-
69
- /**
70
- * Marker constant for Services_JSON::decode(), used to flag stack state
71
- */
72
- define('SERVICES_JSON_IN_ARR', 3);
73
-
74
- /**
75
- * Marker constant for Services_JSON::decode(), used to flag stack state
76
- */
77
- define('SERVICES_JSON_IN_OBJ', 4);
78
-
79
- /**
80
- * Marker constant for Services_JSON::decode(), used to flag stack state
81
- */
82
- define('SERVICES_JSON_IN_CMT', 5);
83
-
84
- /**
85
- * Behavior switch for Services_JSON::decode()
86
- */
87
- define('SERVICES_JSON_LOOSE_TYPE', 16);
88
-
89
- /**
90
- * Behavior switch for Services_JSON::decode()
91
- */
92
- define('SERVICES_JSON_SUPPRESS_ERRORS', 32);
93
-
94
- /**
95
- * Converts to and from JSON format.
96
- *
97
- * Brief example of use:
98
- *
99
- * <code>
100
- * // create a new instance of Services_JSON
101
- * $json = new Services_JSON();
102
- *
103
- * // convert a complexe value to JSON notation, and send it to the browser
104
- * $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4)));
105
- * $output = $json->encode($value);
106
- *
107
- * print($output);
108
- * // prints: ["foo","bar",[1,2,"baz"],[3,[4]]]
109
- *
110
- * // accept incoming POST data, assumed to be in JSON notation
111
- * $input = file_get_contents('php://input', 1000000);
112
- * $value = $json->decode($input);
113
- * </code>
114
- */
115
- class Services_JSON
116
- {
117
- /**
118
- * constructs a new JSON instance
119
- *
120
- * @param int $use object behavior flags; combine with boolean-OR
121
- *
122
- * possible values:
123
- * - SERVICES_JSON_LOOSE_TYPE: loose typing.
124
- * "{...}" syntax creates associative arrays
125
- * instead of objects in decode().
126
- * - SERVICES_JSON_SUPPRESS_ERRORS: error suppression.
127
- * Values which can't be encoded (e.g. resources)
128
- * appear as NULL instead of throwing errors.
129
- * By default, a deeply-nested resource will
130
- * bubble up with an error, so all return values
131
- * from encode() should be checked with isError()
132
- */
133
- function Services_JSON($use = 0)
134
- {
135
- $this->use = $use;
136
- }
137
-
138
- /**
139
- * convert a string from one UTF-16 char to one UTF-8 char
140
- *
141
- * Normally should be handled by mb_convert_encoding, but
142
- * provides a slower PHP-only method for installations
143
- * that lack the multibye string extension.
144
- *
145
- * @param string $utf16 UTF-16 character
146
- * @return string UTF-8 character
147
- * @access private
148
- */
149
- function utf162utf8($utf16)
150
- {
151
- // oh please oh please oh please oh please oh please
152
- if(function_exists('mb_convert_encoding')) {
153
- return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
154
- }
155
-
156
- $bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
157
-
158
- switch(true) {
159
- case ((0x7F & $bytes) == $bytes):
160
- // this case should never be reached, because we are in ASCII range
161
- // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
162
- return chr(0x7F & $bytes);
163
-
164
- case (0x07FF & $bytes) == $bytes:
165
- // return a 2-byte UTF-8 character
166
- // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
167
- return chr(0xC0 | (($bytes >> 6) & 0x1F))
168
- . chr(0x80 | ($bytes & 0x3F));
169
-
170
- case (0xFFFF & $bytes) == $bytes:
171
- // return a 3-byte UTF-8 character
172
- // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
173
- return chr(0xE0 | (($bytes >> 12) & 0x0F))
174
- . chr(0x80 | (($bytes >> 6) & 0x3F))
175
- . chr(0x80 | ($bytes & 0x3F));
176
- }
177
-
178
- // ignoring UTF-32 for now, sorry
179
- return '';
180
- }
181
-
182
- /**
183
- * convert a string from one UTF-8 char to one UTF-16 char
184
- *
185
- * Normally should be handled by mb_convert_encoding, but
186
- * provides a slower PHP-only method for installations
187
- * that lack the multibye string extension.
188
- *
189
- * @param string $utf8 UTF-8 character
190
- * @return string UTF-16 character
191
- * @access private
192
- */
193
- function utf82utf16($utf8)
194
- {
195
- // oh please oh please oh please oh please oh please
196
- if(function_exists('mb_convert_encoding')) {
197
- return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
198
- }
199
-
200
- switch(strlen($utf8)) {
201
- case 1:
202
- // this case should never be reached, because we are in ASCII range
203
- // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
204
- return $utf8;
205
-
206
- case 2:
207
- // return a UTF-16 character from a 2-byte UTF-8 char
208
- // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
209
- return chr(0x07 & (ord($utf8{0}) >> 2))
210
- . chr((0xC0 & (ord($utf8{0}) << 6))
211
- | (0x3F & ord($utf8{1})));
212
-
213
- case 3:
214
- // return a UTF-16 character from a 3-byte UTF-8 char
215
- // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
216
- return chr((0xF0 & (ord($utf8{0}) << 4))
217
- | (0x0F & (ord($utf8{1}) >> 2)))
218
- . chr((0xC0 & (ord($utf8{1}) << 6))
219
- | (0x7F & ord($utf8{2})));
220
- }
221
-
222
- // ignoring UTF-32 for now, sorry
223
- return '';
224
- }
225
-
226
- /**
227
- * encodes an arbitrary variable into JSON format
228
- *
229
- * @param mixed $var any number, boolean, string, array, or object to be encoded.
230
- * see argument 1 to Services_JSON() above for array-parsing behavior.
231
- * if var is a strng, note that encode() always expects it
232
- * to be in ASCII or UTF-8 format!
233
- *
234
- * @return mixed JSON string representation of input var or an error if a problem occurs
235
- * @access public
236
- */
237
- function encode($var)
238
- {
239
- switch (gettype($var)) {
240
- case 'boolean':
241
- return $var ? 'true' : 'false';
242
-
243
- case 'NULL':
244
- return 'null';
245
-
246
- case 'integer':
247
- return (int) $var;
248
-
249
- case 'double':
250
- case 'float':
251
- return (float) $var;
252
-
253
- case 'string':
254
- // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
255
- $ascii = '';
256
- $strlen_var = strlen($var);
257
-
258
- /*
259
- * Iterate over every character in the string,
260
- * escaping with a slash or encoding to UTF-8 where necessary
261
- */
262
- for ($c = 0; $c < $strlen_var; ++$c) {
263
-
264
- $ord_var_c = ord($var{$c});
265
-
266
- switch (true) {
267
- case $ord_var_c == 0x08:
268
- $ascii .= '\b';
269
- break;
270
- case $ord_var_c == 0x09:
271
- $ascii .= '\t';
272
- break;
273
- case $ord_var_c == 0x0A:
274
- $ascii .= '\n';
275
- break;
276
- case $ord_var_c == 0x0C:
277
- $ascii .= '\f';
278
- break;
279
- case $ord_var_c == 0x0D:
280
- $ascii .= '\r';
281
- break;
282
-
283
- case $ord_var_c == 0x22:
284
- case $ord_var_c == 0x2F:
285
- case $ord_var_c == 0x5C:
286
- // double quote, slash, slosh
287
- $ascii .= '\\'.$var{$c};
288
- break;
289
-
290
- case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
291
- // characters U-00000000 - U-0000007F (same as ASCII)
292
- $ascii .= $var{$c};
293
- break;
294
-
295
- case (($ord_var_c & 0xE0) == 0xC0):
296
- // characters U-00000080 - U-000007FF, mask 110XXXXX
297
- // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
298
- $char = pack('C*', $ord_var_c, ord($var{$c + 1}));
299
- $c += 1;
300
- $utf16 = $this->utf82utf16($char);
301
- $ascii .= sprintf('\u%04s', bin2hex($utf16));
302
- break;
303
-
304
- case (($ord_var_c & 0xF0) == 0xE0):
305
- // characters U-00000800 - U-0000FFFF, mask 1110XXXX
306
- // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
307
- $char = pack('C*', $ord_var_c,
308
- ord($var{$c + 1}),
309
- ord($var{$c + 2}));
310
- $c += 2;
311
- $utf16 = $this->utf82utf16($char);
312
- $ascii .= sprintf('\u%04s', bin2hex($utf16));
313
- break;
314
-
315
- case (($ord_var_c & 0xF8) == 0xF0):
316
- // characters U-00010000 - U-001FFFFF, mask 11110XXX
317
- // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
318
- $char = pack('C*', $ord_var_c,
319
- ord($var{$c + 1}),
320
- ord($var{$c + 2}),
321
- ord($var{$c + 3}));
322
- $c += 3;
323
- $utf16 = $this->utf82utf16($char);
324
- $ascii .= sprintf('\u%04s', bin2hex($utf16));
325
- break;
326
-
327
- case (($ord_var_c & 0xFC) == 0xF8):
328
- // characters U-00200000 - U-03FFFFFF, mask 111110XX
329
- // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
330
- $char = pack('C*', $ord_var_c,
331
- ord($var{$c + 1}),
332
- ord($var{$c + 2}),
333
- ord($var{$c + 3}),
334
- ord($var{$c + 4}));
335
- $c += 4;
336
- $utf16 = $this->utf82utf16($char);
337
- $ascii .= sprintf('\u%04s', bin2hex($utf16));
338
- break;
339
-
340
- case (($ord_var_c & 0xFE) == 0xFC):
341
- // characters U-04000000 - U-7FFFFFFF, mask 1111110X
342
- // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
343
- $char = pack('C*', $ord_var_c,
344
- ord($var{$c + 1}),
345
- ord($var{$c + 2}),
346
- ord($var{$c + 3}),
347
- ord($var{$c + 4}),
348
- ord($var{$c + 5}));
349
- $c += 5;
350
- $utf16 = $this->utf82utf16($char);
351
- $ascii .= sprintf('\u%04s', bin2hex($utf16));
352
- break;
353
- }
354
- }
355
-
356
- return '"'.$ascii.'"';
357
-
358
- case 'array':
359
- /*
360
- * As per JSON spec if any array key is not an integer
361
- * we must treat the the whole array as an object. We
362
- * also try to catch a sparsely populated associative
363
- * array with numeric keys here because some JS engines
364
- * will create an array with empty indexes up to
365
- * max_index which can cause memory issues and because
366
- * the keys, which may be relevant, will be remapped
367
- * otherwise.
368
- *
369
- * As per the ECMA and JSON specification an object may
370
- * have any string as a property. Unfortunately due to
371
- * a hole in the ECMA specification if the key is a
372
- * ECMA reserved word or starts with a digit the
373
- * parameter is only accessible using ECMAScript's
374
- * bracket notation.
375
- */
376
-
377
- // treat as a JSON object
378
- if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
379
- $properties = array_map(array($this, 'name_value'),
380
- array_keys($var),
381
- array_values($var));
382
-
383
- foreach($properties as $property) {
384
- if(Services_JSON::isError($property)) {
385
- return $property;
386
- }
387
- }
388
-
389
- return '{' . join(',', $properties) . '}';
390
- }
391
-
392
- // treat it like a regular array
393
- $elements = array_map(array($this, 'encode'), $var);
394
-
395
- foreach($elements as $element) {
396
- if(Services_JSON::isError($element)) {
397
- return $element;
398
- }
399
- }
400
-
401
- return '[' . join(',', $elements) . ']';
402
-
403
- case 'object':
404
- $vars = get_object_vars($var);
405
-
406
- $properties = array_map(array($this, 'name_value'),
407
- array_keys($vars),
408
- array_values($vars));
409
-
410
- foreach($properties as $property) {
411
- if(Services_JSON::isError($property)) {
412
- return $property;
413
- }
414
- }
415
-
416
- return '{' . join(',', $properties) . '}';
417
-
418
- default:
419
- return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
420
- ? 'null'
421
- : new Services_JSON_Error(gettype($var)." can not be encoded as JSON string");
422
- }
423
- }
424
-
425
- /**
426
- * array-walking function for use in generating JSON-formatted name-value pairs
427
- *
428
- * @param string $name name of key to use
429
- * @param mixed $value reference to an array element to be encoded
430
- *
431
- * @return string JSON-formatted name-value pair, like '"name":value'
432
- * @access private
433
- */
434
- function name_value($name, $value)
435
- {
436
- $encoded_value = $this->encode($value);
437
-
438
- if(Services_JSON::isError($encoded_value)) {
439
- return $encoded_value;
440
- }
441
-
442
- return $this->encode(strval($name)) . ':' . $encoded_value;
443
- }
444
-
445
- /**
446
- * reduce a string by removing leading and trailing comments and whitespace
447
- *
448
- * @param $str string string value to strip of comments and whitespace
449
- *
450
- * @return string string value stripped of comments and whitespace
451
- * @access private
452
- */
453
- function reduce_string($str)
454
- {
455
- $str = preg_replace(array(
456
-
457
- // eliminate single line comments in '// ...' form
458
- '#^\s*//(.+)$#m',
459
-
460
- // eliminate multi-line comments in '/* ... */' form, at start of string
461
- '#^\s*/\*(.+)\*/#Us',
462
-
463
- // eliminate multi-line comments in '/* ... */' form, at end of string
464
- '#/\*(.+)\*/\s*$#Us'
465
-
466
- ), '', $str);
467
-
468
- // eliminate extraneous space
469
- return trim($str);
470
- }
471
-
472
- /**
473
- * decodes a JSON string into appropriate variable
474
- *
475
- * @param string $str JSON-formatted string
476
- *
477
- * @return mixed number, boolean, string, array, or object
478
- * corresponding to given JSON input string.
479
- * See argument 1 to Services_JSON() above for object-output behavior.
480
- * Note that decode() always returns strings
481
- * in ASCII or UTF-8 format!
482
- * @access public
483
- */
484
- function decode($str)
485
- {
486
- $str = $this->reduce_string($str);
487
-
488
- switch (strtolower($str)) {
489
- case 'true':
490
- return true;
491
-
492
- case 'false':
493
- return false;
494
-
495
- case 'null':
496
- return null;
497
-
498
- default:
499
- $m = array();
500
-
501
- if (is_numeric($str)) {
502
- // Lookie-loo, it's a number
503
-
504
- // This would work on its own, but I'm trying to be
505
- // good about returning integers where appropriate:
506
- // return (float)$str;
507
-
508
- // Return float or int, as appropriate
509
- return ((float)$str == (integer)$str)
510
- ? (integer)$str
511
- : (float)$str;
512
-
513
- } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
514
- // STRINGS RETURNED IN UTF-8 FORMAT
515
- $delim = substr($str, 0, 1);
516
- $chrs = substr($str, 1, -1);
517
- $utf8 = '';
518
- $strlen_chrs = strlen($chrs);
519
-
520
- for ($c = 0; $c < $strlen_chrs; ++$c) {
521
-
522
- $substr_chrs_c_2 = substr($chrs, $c, 2);
523
- $ord_chrs_c = ord($chrs{$c});
524
-
525
- switch (true) {
526
- case $substr_chrs_c_2 == '\b':
527
- $utf8 .= chr(0x08);
528
- ++$c;
529
- break;
530
- case $substr_chrs_c_2 == '\t':
531
- $utf8 .= chr(0x09);
532
- ++$c;
533
- break;
534
- case $substr_chrs_c_2 == '\n':
535
- $utf8 .= chr(0x0A);
536
- ++$c;
537
- break;
538
- case $substr_chrs_c_2 == '\f':
539
- $utf8 .= chr(0x0C);
540
- ++$c;
541
- break;
542
- case $substr_chrs_c_2 == '\r':
543
- $utf8 .= chr(0x0D);
544
- ++$c;
545
- break;
546
-
547
- case $substr_chrs_c_2 == '\\"':
548
- case $substr_chrs_c_2 == '\\\'':
549
- case $substr_chrs_c_2 == '\\\\':
550
- case $substr_chrs_c_2 == '\\/':
551
- if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
552
- ($delim == "'" && $substr_chrs_c_2 != '\\"')) {
553
- $utf8 .= $chrs{++$c};
554
- }
555
- break;
556
-
557
- case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
558
- // single, escaped unicode character
559
- $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
560
- . chr(hexdec(substr($chrs, ($c + 4), 2)));
561
- $utf8 .= $this->utf162utf8($utf16);
562
- $c += 5;
563
- break;
564
-
565
- case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
566
- $utf8 .= $chrs{$c};
567
- break;
568
-
569
- case ($ord_chrs_c & 0xE0) == 0xC0:
570
- // characters U-00000080 - U-000007FF, mask 110XXXXX
571
- //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
572
- $utf8 .= substr($chrs, $c, 2);
573
- ++$c;
574
- break;
575
-
576
- case ($ord_chrs_c & 0xF0) == 0xE0:
577
- // characters U-00000800 - U-0000FFFF, mask 1110XXXX
578
- // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
579
- $utf8 .= substr($chrs, $c, 3);
580
- $c += 2;
581
- break;
582
-
583
- case ($ord_chrs_c & 0xF8) == 0xF0:
584
- // characters U-00010000 - U-001FFFFF, mask 11110XXX
585
- // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
586
- $utf8 .= substr($chrs, $c, 4);
587
- $c += 3;
588
- break;
589
-
590
- case ($ord_chrs_c & 0xFC) == 0xF8:
591
- // characters U-00200000 - U-03FFFFFF, mask 111110XX
592
- // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
593
- $utf8 .= substr($chrs, $c, 5);
594
- $c += 4;
595
- break;
596
-
597
- case ($ord_chrs_c & 0xFE) == 0xFC:
598
- // characters U-04000000 - U-7FFFFFFF, mask 1111110X
599
- // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
600
- $utf8 .= substr($chrs, $c, 6);
601
- $c += 5;
602
- break;
603
-
604
- }
605
-
606
- }
607
-
608
- return $utf8;
609
-
610
- } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
611
- // array, or object notation
612
-
613
- if ($str{0} == '[') {
614
- $stk = array(SERVICES_JSON_IN_ARR);
615
- $arr = array();
616
- } else {
617
- if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
618
- $stk = array(SERVICES_JSON_IN_OBJ);
619
- $obj = array();
620
- } else {
621
- $stk = array(SERVICES_JSON_IN_OBJ);
622
- $obj = new stdClass();
623
- }
624
- }
625
-
626
- array_push($stk, array('what' => SERVICES_JSON_SLICE,
627
- 'where' => 0,
628
- 'delim' => false));
629
-
630
- $chrs = substr($str, 1, -1);
631
- $chrs = $this->reduce_string($chrs);
632
-
633
- if ($chrs == '') {
634
- if (reset($stk) == SERVICES_JSON_IN_ARR) {
635
- return $arr;
636
-
637
- } else {
638
- return $obj;
639
-
640
- }
641
- }
642
-
643
- //print("\nparsing {$chrs}\n");
644
-
645
- $strlen_chrs = strlen($chrs);
646
-
647
- for ($c = 0; $c <= $strlen_chrs; ++$c) {
648
-
649
- $top = end($stk);
650
- $substr_chrs_c_2 = substr($chrs, $c, 2);
651
-
652
- if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) {
653
- // found a comma that is not inside a string, array, etc.,
654
- // OR we've reached the end of the character list
655
- $slice = substr($chrs, $top['where'], ($c - $top['where']));
656
- array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
657
- //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
658
-
659
- if (reset($stk) == SERVICES_JSON_IN_ARR) {
660
- // we are in an array, so just push an element onto the stack
661
- array_push($arr, $this->decode($slice));
662
-
663
- } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
664
- // we are in an object, so figure
665
- // out the property name and set an
666
- // element in an associative array,
667
- // for now
668
- $parts = array();
669
-
670
- if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
671
- // "name":value pair
672
- $key = $this->decode($parts[1]);
673
- $val = $this->decode($parts[2]);
674
-
675
- if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
676
- $obj[$key] = $val;
677
- } else {
678
- $obj->$key = $val;
679
- }
680
- } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
681
- // name:value pair, where name is unquoted
682
- $key = $parts[1];
683
- $val = $this->decode($parts[2]);
684
-
685
- if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
686
- $obj[$key] = $val;
687
- } else {
688
- $obj->$key = $val;
689
- }
690
- }
691
-
692
- }
693
-
694
- } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) {
695
- // found a quote, and we are not inside a string
696
- array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
697
- //print("Found start of string at {$c}\n");
698
-
699
- } elseif (($chrs{$c} == $top['delim']) &&
700
- ($top['what'] == SERVICES_JSON_IN_STR) &&
701
- ((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) {
702
- // found a quote, we're in a string, and it's not escaped
703
- // we know that it's not escaped becase there is _not_ an
704
- // odd number of backslashes at the end of the string so far
705
- array_pop($stk);
706
- //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
707
-
708
- } elseif (($chrs{$c} == '[') &&
709
- in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
710
- // found a left-bracket, and we are in an array, object, or slice
711
- array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
712
- //print("Found start of array at {$c}\n");
713
-
714
- } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) {
715
- // found a right-bracket, and we're in an array
716
- array_pop($stk);
717
- //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
718
-
719
- } elseif (($chrs{$c} == '{') &&
720
- in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
721
- // found a left-brace, and we are in an array, object, or slice
722
- array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
723
- //print("Found start of object at {$c}\n");
724
-
725
- } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) {
726
- // found a right-brace, and we're in an object
727
- array_pop($stk);
728
- //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
729
-
730
- } elseif (($substr_chrs_c_2 == '/*') &&
731
- in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
732
- // found a comment start, and we are in an array, object, or slice
733
- array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
734
- $c++;
735
- //print("Found start of comment at {$c}\n");
736
-
737
- } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) {
738
- // found a comment end, and we're in one now
739
- array_pop($stk);
740
- $c++;
741
-
742
- for ($i = $top['where']; $i <= $c; ++$i)
743
- $chrs = substr_replace($chrs, ' ', $i, 1);
744
-
745
- //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
746
-
747
- }
748
-
749
- }
750
-
751
- if (reset($stk) == SERVICES_JSON_IN_ARR) {
752
- return $arr;
753
-
754
- } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
755
- return $obj;
756
-
757
- }
758
-
759
- }
760
- }
761
- }
762
-
763
- /**
764
- * @todo Ultimately, this should just call PEAR::isError()
765
- */
766
- function isError($data, $code = null)
767
- {
768
- if (class_exists('pear')) {
769
- return PEAR::isError($data, $code);
770
- } elseif (is_object($data) && (get_class($data) == 'services_json_error' ||
771
- is_subclass_of($data, 'services_json_error'))) {
772
- return true;
773
- }
774
-
775
- return false;
776
- }
777
- }
778
-
779
- if (class_exists('PEAR_Error')) {
780
-
781
- class Services_JSON_Error extends PEAR_Error
782
- {
783
- function Services_JSON_Error($message = 'unknown error', $code = null,
784
- $mode = null, $options = null, $userinfo = null)
785
- {
786
- parent::PEAR_Error($message, $code, $mode, $options, $userinfo);
787
- }
788
- }
789
-
790
- } else {
791
-
792
- /**
793
- * @todo Ultimately, this class shall be descended from PEAR_Error
794
- */
795
- class Services_JSON_Error
796
- {
797
- function Services_JSON_Error($message = 'unknown error', $code = null,
798
- $mode = null, $options = null, $userinfo = null)
799
- {
800
-
801
- }
802
- }
803
-
804
- }
805
-
806
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
class-wp-cli.php ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+
5
+ @todo add, delete, run, etc
6
+
7
+ */
8
+
9
+ class Crontrol_Command extends WP_CLI_Command {
10
+
11
+ public $crontrol = null;
12
+
13
+ public function __construct() {
14
+
15
+ $this->crontrol = Crontrol::init();
16
+
17
+ }
18
+
19
+ /**
20
+ * List scheduled cron events.
21
+ *
22
+ * @since 1.2
23
+ *
24
+ * @alias list
25
+ * @subcommand list-events
26
+ */
27
+ public function list_events() {
28
+
29
+ $events = $this->crontrol->get_cron_events();
30
+
31
+ if ( is_wp_error( $events ) ) {
32
+ WP_CLI::line( WP_CLI::error_to_string( $events ) );
33
+ die();
34
+ }
35
+
36
+ $events = array_map( array( $this, '_map_event' ), $events );
37
+
38
+ $fields = array(
39
+ 'hook',
40
+ 'next_run',
41
+ 'recurrence'
42
+ );
43
+
44
+ \WP_CLI\Utils\format_items( 'table', $events, $fields );
45
+
46
+ }
47
+
48
+ /**
49
+ * List available cron schedules.
50
+ *
51
+ * @since 1.2
52
+ *
53
+ * @subcommand list-schedules
54
+ */
55
+ public function list_schedules() {
56
+
57
+ $schedules = $this->crontrol->get_schedules();
58
+
59
+ $schedules = array_map( array( $this, '_map_schedule' ), $schedules );
60
+
61
+ $fields = array(
62
+ 'display',
63
+ 'interval'
64
+ );
65
+
66
+ \WP_CLI\Utils\format_items( 'table', $schedules, $fields );
67
+
68
+ }
69
+
70
+ /**
71
+ * Test the WP Cron spawning system and report back any errors.
72
+ *
73
+ * @since 1.2
74
+ */
75
+ public function test() {
76
+
77
+ $status = $this->crontrol->test_cron_spawn( false );
78
+
79
+ if ( is_wp_error( $status ) )
80
+ WP_CLI::error( $status );
81
+ else
82
+ WP_CLI::success( __( 'WP-Cron working as expected.', 'control' ) );
83
+
84
+ }
85
+
86
+ protected function _map_event( $event ) {
87
+ $event->next_run = strftime("%Y/%m/%d %H:%M:%S", $event->time) . " (".$this->crontrol->time_since(time(), $event->time).")";
88
+ $event->recurrence = ($event->schedule ? $event->interval.' ('.$this->crontrol->interval($event->interval).')' : __('Non-repeating', 'crontrol'));
89
+ return $event;
90
+ }
91
+
92
+ protected function _map_schedule( $schedule ) {
93
+ return (object) $schedule;
94
+ }
95
+
96
+ }
97
+
98
+ WP_CLI::add_command( 'crontrol', 'Crontrol_Command' );
readme.txt CHANGED
@@ -1,29 +1,47 @@
1
- === WP-Crontrol ===
2
  Contributors: scompt, johnbillion
3
- Donate link: http://scompt.com/projects/wp-crontrol
4
- Tags: admin, cron, plugin, control
5
  Requires at least: 3.0
6
- Tested up to: 3.4
7
- Stable tag: 1.1
8
 
9
- WP-Crontrol lets you take control over what's happening in the WP-Cron system.
10
 
11
  == Description ==
12
 
13
- WP-Crontrol lets you take control over what's happening in the WP-Cron system. See my series on [Taking control of WP-Cron using WP-Crontrol](http://scompt.com/archives/series/taking-control-of-wp-cron-using-wp-crontrol) for usage ideas.
 
 
 
 
 
 
 
 
 
 
14
 
15
  == Installation ==
16
 
17
- 1. Upload the `wp-crontrol` directory to the `/wp-content/plugins/` directory
18
- 1. Activate the plugin through the 'Plugins' menu in WordPress
19
- 1. Go to the Settings -> Crontrol panel to add some new cron schedules.
20
- 1. Go to the Tools -> Crontrol panel to see what cron entries are scheduled and to add some new ones.
 
 
 
 
 
 
 
 
 
21
 
22
  == Frequently Asked Questions ==
23
 
24
  = What's the use of adding new cron schedules? =
25
 
26
- Cron schedules are used by WordPress and WordPress plugins to allow you to schedule commands 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.
27
 
28
  = How do I create a new PHP cron entry? =
29
 
@@ -31,7 +49,7 @@ In the Tools -> Crontrol admin panel, click on the "add new PHP entry" link unde
31
 
32
  = How do I create a new regular cron entry? =
33
 
34
- There are two steps to getting a functioning cron entry 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.
35
 
36
  *Step One: Adding the hook*
37
 
@@ -46,16 +64,20 @@ This part takes place in PHP code (for example, in the `functions.php` file from
46
  The next step is to write your function. Here's a simple example:
47
 
48
  `function my_function() {
49
- wp_mail('scompt@scompt.com', 'WP-Crontrol', 'WP-Crontrol rocks!');
50
  }`
51
 
52
  = Do I really need the entire `wp-crontrol` directory? =
53
 
54
- Maybe... The most important file is `wp-crontrol.php`. If your server is running PHP4, you'll need `JSON.php` also. If you're on PHP5, then you can get rid of the whole directory and just use `wp-crontrol.php`.
 
 
55
 
56
- = How do I ask a frequently asked question? =
 
 
57
 
58
- Email [me](mailto:scompt@scompt.com).
59
 
60
  == Screenshots ==
61
 
@@ -64,11 +86,15 @@ Email [me](mailto:scompt@scompt.com).
64
 
65
  == Upgrade Notice ==
66
 
67
- = 1.1 =
68
- * Bug fixes for running cron jobs and adding cron schedules
69
 
70
  == Changelog ==
71
 
 
 
 
 
72
  = 1.1 =
73
  * Bug fixes for running cron jobs and adding cron schedules
74
  * Added a cron spawn test to check for errors when spawning cron
@@ -95,3 +121,4 @@ Email [me](mailto:scompt@scompt.com).
95
 
96
  = 0.1 =
97
  * Super basic, look at what's in WP-Cron functionality.
 
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: 3.6
6
+ Stable tag: 1.2
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 entries along with their arguments, recurrence and when they are next due.
15
+ * Edit, delete, and immediately run any cron entries.
16
+ * Add new cron entries.
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 entries).
19
+
20
+ From the settings screen you can also add, edit and remove cron schedues.
21
+
22
+ Now supports [wp-cli](http://wp-cli.org/)!
23
 
24
  == Installation ==
25
 
26
+ You can install this plugin directly from your WordPress dashboard:
27
+
28
+ 1. Go to the *Plugins* menu and click *Add New*.
29
+ 2. Search for *WP Crontrol*.
30
+ 3. Click *Install Now* next to the *WP Crontrol* plugin.
31
+ 4. Activate the plugin.
32
+
33
+ Alternatively, see the guide to [Manually Installing Plugins](http://codex.wordpress.org/Managing_Plugins#Manual_Plugin_Installation).
34
+
35
+ = Usage =
36
+
37
+ 1. Go to the Settings -> Crontrol menu to add some new cron schedules.
38
+ 2. Go to the Tools -> Crontrol menu to see what cron entries are scheduled and to add some new ones.
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 commands 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 entry? =
47
 
49
 
50
  = How do I create a new regular cron entry? =
51
 
52
+ There are two steps to getting a functioning cron entry 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
 
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` Lists the scheduled events on your site.
77
+ * `wp crontrol test` Performs a WP-Cron spawning test to make sure WP-Cron can function as expected.
78
+ * `wp crontrol list-schedules` Lists the available WP-Cron schedules on your site.
79
 
80
+ Note that wp-cli support was only recently added. This will be improved over time. Feedback welcome!
81
 
82
  == Screenshots ==
83
 
86
 
87
  == Upgrade Notice ==
88
 
89
+ = 1.2 =
90
+ * Added support for [wp-cli](http://wp-cli.org/)
91
 
92
  == Changelog ==
93
 
94
+ = 1.2 =
95
+ * Added support for [wp-cli](http://wp-cli.org/)
96
+ * Removed some PHP4 code that's no longer relevant
97
+
98
  = 1.1 =
99
  * Bug fixes for running cron jobs and adding cron schedules
100
  * Added a cron spawn test to check for errors when spawning cron
121
 
122
  = 0.1 =
123
  * Super basic, look at what's in WP-Cron functionality.
124
+
screenshot-1.png DELETED
Binary file
screenshot-2.png DELETED
Binary file
wp-crontrol.php CHANGED
@@ -1,21 +1,21 @@
1
  <?php
2
  /*
3
- * Plugin Name: WP-Crontrol
4
- * Plugin URI: http://www.scompt.com/projects/wp-crontrol
5
- * Description: WP-Crontrol lets you take control over what's happening in the WP-Cron system. See my series on <a target="_blank" href="http://scompt.com/archives/series/taking-control-of-wp-cron-using-wp-crontrol">Taking control of WP-Cron using WP-Crontrol</a> for usage ideas.
6
- * Author: <a href="http://www.scompt.com/">Edward Dale</a> & <a href="http://lud.icro.us/">John Blackbourn</a>
7
- * Version: 1.1
8
  * Text Domain: 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.
@@ -29,55 +29,58 @@
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 2012 Edward Dale & John Blackbourn
35
  * @license http://www.gnu.org/licenses/gpl.txt GPL 2.0
36
- * @link http://www.scompt.com/projects/wp-crontrol
37
  * @since 0.2
38
  */
 
 
 
39
  class Crontrol {
40
  var $json;
41
 
42
  /**
43
  * Hook onto all of the actions and filters needed by the plugin.
44
  */
45
- function Crontrol() {
46
  define( 'CRONTROL_CRON_JOB', 'crontrol_cron_job');
47
  $this->json = new Crontrol_JSON();
48
  if( function_exists('add_action') ) {
49
- add_action('init', array(&$this, 'init'));
50
- add_action('init', array(&$this, 'handle_posts'));
51
- add_action('admin_menu', array(&$this, 'admin_menu'));
52
 
53
  // Make sure the activation works from subdirectories as well as
54
  // directly in the plugin directory.
55
  $activate_action = str_replace(ABSPATH.PLUGINDIR.'/', 'activate_', __FILE__);
56
- add_action($activate_action, array(&$this, 'activate'));
57
 
58
- add_filter('cron_schedules', array(&$this, 'cron_schedules'));
59
- add_action(CRONTROL_CRON_JOB, array(&$this, 'php_cron_entry'));
60
  }
61
  }
62
 
63
  /**
64
  * Evaluates the provided code using eval.
65
  */
66
- function php_cron_entry($code) {
67
  eval($code);
68
  }
69
-
70
  /**
71
  * Run using the 'init' action.
72
  */
73
- function init() {
74
  load_plugin_textdomain( '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
- function handle_posts() {
81
  if( isset($_POST['new_cron']) ) {
82
  if( !current_user_can('manage_options') ) die(__('You are not allowed to add new cron events.', 'crontrol'));
83
  check_admin_referer("new-cron");
@@ -94,7 +97,7 @@ class Crontrol {
94
  $hookname = CRONTROL_CRON_JOB;
95
  $this->add_cron($in_next_run, $in_schedule, $hookname, $args);
96
  wp_redirect("tools.php?page=crontrol_admin_manage_page&crontrol_message=5&crontrol_name={$in_hookname}");
97
-
98
  } else if( isset($_POST['edit_cron']) ) {
99
  if( !current_user_can('manage_options') ) die(__('You are not allowed to edit cron events.', 'crontrol'));
100
 
@@ -173,7 +176,7 @@ class Crontrol {
173
  }
174
  }
175
  }
176
-
177
  /**
178
  * Executes a cron entry immediately.
179
  *
@@ -194,7 +197,7 @@ class Crontrol {
194
  }
195
  return false;
196
  }
197
-
198
  /**
199
  * Adds a new cron entry.
200
  *
@@ -213,7 +216,7 @@ class Crontrol {
213
  return wp_schedule_event( $next_run, $schedule, $hookname, $args ) === NULL;
214
  }
215
  }
216
-
217
  /**
218
  * Deletes a cron entry.
219
  *
@@ -228,7 +231,7 @@ class Crontrol {
228
  }
229
  return false;
230
  }
231
-
232
  /**
233
  * Adds a new custom cron schedule.
234
  *
@@ -241,7 +244,7 @@ class Crontrol {
241
  $old_scheds[$name] = array('interval'=>$interval, 'display'=>$display);
242
  update_option('crontrol_schedules', $old_scheds);
243
  }
244
-
245
  /**
246
  * Deletes a custom cron schedule.
247
  *
@@ -252,13 +255,13 @@ class Crontrol {
252
  unset($scheds[$name]);
253
  update_option('crontrol_schedules', $scheds);
254
  }
255
-
256
  /**
257
  * Sets up the plugin environment upon first activation.
258
- *
259
  * Run using the 'activate_' action.
260
  */
261
- function activate() {
262
  $extra_scheds = array('twicedaily'=>array('interval'=>43200, 'display'=>__('Twice Daily', 'crontrol')));
263
  add_option('crontrol_schedules', $extra_scheds);
264
 
@@ -267,17 +270,17 @@ class Crontrol {
267
  _set_cron_array(array());
268
  }
269
  }
270
-
271
  /**
272
  * Adds options & management pages to the admin menu.
273
  *
274
  * Run using the 'admin_menu' action.
275
  */
276
- function admin_menu() {
277
  $page = add_options_page('Crontrol', 'Crontrol', 'manage_options', 'crontrol_admin_options_page', array(&$this, 'admin_options_page') );
278
  $page = add_management_page('Crontrol', "Crontrol", 'manage_options', 'crontrol_admin_manage_page', array(&$this, 'admin_manage_page') );
279
  }
280
-
281
  /**
282
  * Gives WordPress the plugin's set of cron schedules.
283
  *
@@ -286,11 +289,11 @@ class Crontrol {
286
  * @param array $scheds The current cron schedules. Usually an empty array.
287
  * @return array The existing cron schedules along with the plugin's schedules.
288
  */
289
- function cron_schedules($scheds) {
290
  $new_scheds = get_option('crontrol_schedules',array());
291
  return array_merge($new_scheds, $scheds);
292
  }
293
-
294
  /**
295
  * Displays the options page for the plugin.
296
  */
@@ -298,7 +301,7 @@ class Crontrol {
298
  $schedules = $this->get_schedules();
299
  $custom_schedules = get_option('crontrol_schedules',array());
300
  $custom_keys = array_keys($custom_schedules);
301
-
302
  if( isset($_GET['crontrol_message']) ) {
303
  $messages = array( '2' => __("Successfully deleted the cron schedule <b>%s</b>", 'crontrol'),
304
  '3' => __("Successfully added the cron schedule <b>%s</b>", 'crontrol'),
@@ -308,12 +311,12 @@ class Crontrol {
308
 
309
  echo "<div id=\"message\" class=\"updated fade\"><p>$msg</p></div>";
310
  }
311
-
312
  ?>
313
  <div class="wrap">
314
  <?php screen_icon(); ?>
315
  <h2><?php _e("Cron Schedules", "crontrol"); ?></h2>
316
- <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.', 'crontrol'); ?></p>
317
  <div id="ajax-response"></div>
318
  <table class="widefat">
319
  <thead>
@@ -321,7 +324,7 @@ class Crontrol {
321
  <th><?php _e('Name', 'crontrol'); ?></th>
322
  <th><?php _e('Interval', 'crontrol'); ?></th>
323
  <th><?php _e('Display Name', 'crontrol'); ?></th>
324
- <th><?php _e('Actions', 'crontrol'); ?></th>
325
  </tr>
326
  </thead>
327
  <tbody>
@@ -345,7 +348,7 @@ class Crontrol {
345
  echo "</tr>";
346
  $class = empty($class)?"alternate":"";
347
  }
348
- }
349
  ?>
350
  </tbody>
351
  </table>
@@ -407,14 +410,14 @@ class Crontrol {
407
  * Gets the status of WP-Cron functionality on the site by performing a test spawn. Cached for one hour when all is well.
408
  *
409
  */
410
- function test_cron_spawn() {
411
 
412
  if ( defined('ALTERNATE_WP_CRON') && ALTERNATE_WP_CRON )
413
  return true;
414
 
415
  $cached_status = get_transient( 'wp-cron-test-ok' );
416
 
417
- if ( $cached_status )
418
  return true;
419
 
420
  $doing_wp_cron = sprintf( '%.22F', microtime( true ) );
@@ -522,6 +525,40 @@ class Crontrol {
522
  <?php
523
  }
524
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
525
  /**
526
  * Displays the manage page for the plugin.
527
  */
@@ -538,8 +575,7 @@ class Crontrol {
538
 
539
  echo "<div id=\"message\" class=\"updated fade\"><p>$msg</p></div>";
540
  }
541
- $crons = _get_cron_array();
542
- $schedules = $this->get_schedules();
543
  $doing_edit = (isset( $_GET['action']) && $_GET['action']=='edit-cron') ? $_GET['id'] : false ;
544
  $this->show_cron_status();
545
  ?>
@@ -554,40 +590,40 @@ class Crontrol {
554
  <th><?php _e('Arguments', 'crontrol'); ?></th>
555
  <th><?php _e('Next Run', 'crontrol'); ?></th>
556
  <th><?php _e('Recurrence', 'crontrol'); ?></th>
557
- <th colspan="3"><?php _e('Actions', 'crontrol'); ?></th>
558
  </tr>
559
  </thead>
560
  <tbody>
561
  <?php
562
- if( empty($crons) ) {
563
  ?>
564
- <tr><td colspan="7"><?php _e('You currently have no cron entries. Add one below!', 'crontrol') ?></td></tr>
565
  <?php
566
  } else {
567
  $class = "";
568
- foreach( $crons as $time=>$cron ) {
569
- foreach( $cron as $hook=>$dings) {
570
- foreach( $dings as $sig=>$data ) {
571
- if( $doing_edit && $doing_edit==$hook && $time == $_GET['next_run'] && $sig==$_GET['sig'] ) {
572
- $doing_edit = array('hookname'=>$hook,
573
- 'next_run'=>$time,
574
- 'schedule'=>($data['schedule'] ? $data['schedule'] : '_oneoff'),
575
- 'sig'=>$sig,
576
- 'args'=>$data['args']);
577
- }
578
-
579
- echo "<tr id=\"cron-$hook-$sig\" class=\"$class\">";
580
- echo "<td>".($hook==CRONTROL_CRON_JOB ? __('<i>PHP Cron</i>', 'crontrol') : $hook)."</td>";
581
- echo "<td>".($hook==CRONTROL_CRON_JOB ? __('<i>PHP Code</i>', 'crontrol') : $this->json->encode($data['args']))."</td>";
582
- echo "<td>".strftime("%Y/%m/%d %H:%M:%S", $time)." (".$this->time_since(time(), $time).")</td>";
583
- echo "<td>".($data['schedule'] ? $data['interval'].' ('.$this->interval($data['interval']).')' : __('Non-repeating', 'crontrol'))."</td>";
584
- echo "<td><a class='view' href='tools.php?page=crontrol_admin_manage_page&amp;action=edit-cron&amp;id=$hook&amp;sig=$sig&amp;next_run=$time#crontrol_form'>Edit</a></td>";
585
- echo "<td><a class='view' href='".wp_nonce_url("tools.php?page=crontrol_admin_manage_page&amp;action=run-cron&amp;id=$hook&amp;sig=$sig", "run-cron_{$hook}_{$sig}")."'>Run Now</a></td>";
586
- echo "<td><a class='delete' href='".wp_nonce_url("tools.php?page=crontrol_admin_manage_page&amp;action=delete-cron&amp;id=$hook&amp;sig=$sig&amp;next_run=$time", "delete-cron_{$hook}_{$sig}_{$time}")."'>Delete</a></td>";
587
- echo "</tr>";
588
- $class = empty($class)?"alternate":"";
589
- }
590
- }
591
  }
592
  }
593
  ?>
@@ -601,7 +637,7 @@ class Crontrol {
601
  $this->show_cron_form((isset($_GET['action']) and $_GET['action']=='new-php-cron'), false);
602
  }
603
  }
604
-
605
  /**
606
  * Pretty-prints the difference in two times.
607
  *
@@ -610,10 +646,10 @@ class Crontrol {
610
  * @return string The pretty time_since value
611
  * @link http://binarybonsai.com/code/timesince.txt
612
  */
613
- function time_since($older_date, $newer_date) {
614
  return $this->interval( $newer_date - $older_date );
615
  }
616
-
617
  function interval( $since ) {
618
  // array of time period chunks
619
  $chunks = array(
@@ -626,7 +662,7 @@ class Crontrol {
626
  array( 1 , _n_noop('%s second', '%s seconds', 'crontrol')),
627
  );
628
 
629
-
630
  if( $since <= 0 ) {
631
  return __('now', 'crontrol');
632
  }
@@ -667,36 +703,31 @@ class Crontrol {
667
 
668
  return $output;
669
  }
 
 
 
 
 
 
 
 
 
 
 
 
670
  }
671
 
672
- // PHP4 doesn't have json_encode built-in.
673
- if( !function_exists('json_encode' ) ) {
674
- if( !class_exists('Services_JSON') )
675
- require_once('JSON.php');
676
-
677
- class Crontrol_JSON {
678
- var $json;
679
- function Crontrol_JSON() {
680
- $this->json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE);
681
- }
682
- function encode($in) {
683
- return $this->json->encode($in);
684
- }
685
- function decode($in) {
686
- return $this->json->decode($in);
687
- }
688
  }
689
- } else {
690
- class Crontrol_JSON {
691
- function encode($in) {
692
- return json_encode($in);
693
- }
694
- function decode($in) {
695
- return json_decode($in, true);
696
- }
697
  }
698
  }
699
 
 
 
 
700
  // Get this show on the road
701
- new Crontrol();
702
- ?>
1
  <?php
2
  /*
3
+ * Plugin Name: WP Crontrol
4
+ * Plugin URI: http://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="http://lud.icro.us/">John Blackbourn</a>
7
+ * Version: 1.2
8
  * Text Domain: 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.
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 2012 Edward Dale & John Blackbourn
35
  * @license http://www.gnu.org/licenses/gpl.txt GPL 2.0
36
+ * @link http://wordpress.org/plugins/wp-crontrol/
37
  * @since 0.2
38
  */
39
+
40
+ defined( 'ABSPATH' ) or die();
41
+
42
  class Crontrol {
43
  var $json;
44
 
45
  /**
46
  * Hook onto all of the actions and filters needed by the plugin.
47
  */
48
+ protected function __construct() {
49
  define( 'CRONTROL_CRON_JOB', 'crontrol_cron_job');
50
  $this->json = new Crontrol_JSON();
51
  if( function_exists('add_action') ) {
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
 
56
  // Make sure the activation works from subdirectories as well as
57
  // directly in the plugin directory.
58
  $activate_action = str_replace(ABSPATH.PLUGINDIR.'/', 'activate_', __FILE__);
59
+ add_action($activate_action, array(&$this, 'action_activate'));
60
 
61
+ add_filter('cron_schedules', array(&$this, 'filter_cron_schedules'));
62
+ add_action(CRONTROL_CRON_JOB, array(&$this, 'action_php_cron_entry'));
63
  }
64
  }
65
 
66
  /**
67
  * Evaluates the provided code using eval.
68
  */
69
+ function action_php_cron_entry($code) {
70
  eval($code);
71
  }
72
+
73
  /**
74
  * Run using the 'init' action.
75
  */
76
+ function action_init() {
77
  load_plugin_textdomain( 'crontrol', false, dirname( plugin_basename( __FILE__ ) ) . '/gettext' );
78
  }
79
+
80
  /**
81
  * Handles any POSTs made by the plugin. Run using the 'init' action.
82
  */
83
+ function action_handle_posts() {
84
  if( isset($_POST['new_cron']) ) {
85
  if( !current_user_can('manage_options') ) die(__('You are not allowed to add new cron events.', 'crontrol'));
86
  check_admin_referer("new-cron");
97
  $hookname = CRONTROL_CRON_JOB;
98
  $this->add_cron($in_next_run, $in_schedule, $hookname, $args);
99
  wp_redirect("tools.php?page=crontrol_admin_manage_page&crontrol_message=5&crontrol_name={$in_hookname}");
100
+
101
  } else if( isset($_POST['edit_cron']) ) {
102
  if( !current_user_can('manage_options') ) die(__('You are not allowed to edit cron events.', 'crontrol'));
103
 
176
  }
177
  }
178
  }
179
+
180
  /**
181
  * Executes a cron entry immediately.
182
  *
197
  }
198
  return false;
199
  }
200
+
201
  /**
202
  * Adds a new cron entry.
203
  *
216
  return wp_schedule_event( $next_run, $schedule, $hookname, $args ) === NULL;
217
  }
218
  }
219
+
220
  /**
221
  * Deletes a cron entry.
222
  *
231
  }
232
  return false;
233
  }
234
+
235
  /**
236
  * Adds a new custom cron schedule.
237
  *
244
  $old_scheds[$name] = array('interval'=>$interval, 'display'=>$display);
245
  update_option('crontrol_schedules', $old_scheds);
246
  }
247
+
248
  /**
249
  * Deletes a custom cron schedule.
250
  *
255
  unset($scheds[$name]);
256
  update_option('crontrol_schedules', $scheds);
257
  }
258
+
259
  /**
260
  * Sets up the plugin environment upon first activation.
261
+ *
262
  * Run using the 'activate_' action.
263
  */
264
+ function action_activate() {
265
  $extra_scheds = array('twicedaily'=>array('interval'=>43200, 'display'=>__('Twice Daily', 'crontrol')));
266
  add_option('crontrol_schedules', $extra_scheds);
267
 
270
  _set_cron_array(array());
271
  }
272
  }
273
+
274
  /**
275
  * Adds options & management pages to the admin menu.
276
  *
277
  * Run using the 'admin_menu' action.
278
  */
279
+ function action_admin_menu() {
280
  $page = add_options_page('Crontrol', 'Crontrol', 'manage_options', 'crontrol_admin_options_page', array(&$this, 'admin_options_page') );
281
  $page = add_management_page('Crontrol', "Crontrol", 'manage_options', 'crontrol_admin_manage_page', array(&$this, 'admin_manage_page') );
282
  }
283
+
284
  /**
285
  * Gives WordPress the plugin's set of cron schedules.
286
  *
289
  * @param array $scheds The current cron schedules. Usually an empty array.
290
  * @return array The existing cron schedules along with the plugin's schedules.
291
  */
292
+ function filter_cron_schedules($scheds) {
293
  $new_scheds = get_option('crontrol_schedules',array());
294
  return array_merge($new_scheds, $scheds);
295
  }
296
+
297
  /**
298
  * Displays the options page for the plugin.
299
  */
301
  $schedules = $this->get_schedules();
302
  $custom_schedules = get_option('crontrol_schedules',array());
303
  $custom_keys = array_keys($custom_schedules);
304
+
305
  if( isset($_GET['crontrol_message']) ) {
306
  $messages = array( '2' => __("Successfully deleted the cron schedule <b>%s</b>", 'crontrol'),
307
  '3' => __("Successfully added the cron schedule <b>%s</b>", 'crontrol'),
311
 
312
  echo "<div id=\"message\" class=\"updated fade\"><p>$msg</p></div>";
313
  }
314
+
315
  ?>
316
  <div class="wrap">
317
  <?php screen_icon(); ?>
318
  <h2><?php _e("Cron Schedules", "crontrol"); ?></h2>
319
+ <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.', 'crontrol'); ?></p>
320
  <div id="ajax-response"></div>
321
  <table class="widefat">
322
  <thead>
324
  <th><?php _e('Name', 'crontrol'); ?></th>
325
  <th><?php _e('Interval', 'crontrol'); ?></th>
326
  <th><?php _e('Display Name', 'crontrol'); ?></th>
327
+ <th>&nbsp;</th>
328
  </tr>
329
  </thead>
330
  <tbody>
348
  echo "</tr>";
349
  $class = empty($class)?"alternate":"";
350
  }
351
+ }
352
  ?>
353
  </tbody>
354
  </table>
410
  * Gets the status of WP-Cron functionality on the site by performing a test spawn. Cached for one hour when all is well.
411
  *
412
  */
413
+ function test_cron_spawn( $cache = true ) {
414
 
415
  if ( defined('ALTERNATE_WP_CRON') && ALTERNATE_WP_CRON )
416
  return true;
417
 
418
  $cached_status = get_transient( 'wp-cron-test-ok' );
419
 
420
+ if ( $cache and $cached_status )
421
  return true;
422
 
423
  $doing_wp_cron = sprintf( '%.22F', microtime( true ) );
525
  <?php
526
  }
527
 
528
+ function get_cron_events() {
529
+
530
+ $crons = _get_cron_array();
531
+ $events = array();
532
+
533
+ if ( empty( $crons ) ) {
534
+ return new WP_Error(
535
+ 'no_events',
536
+ __( 'You currently have no cron entries.', 'crontrol' )
537
+ );
538
+ }
539
+
540
+ foreach( $crons as $time=>$cron ) {
541
+ foreach( $cron as $hook=>$dings) {
542
+ foreach( $dings as $sig=>$data ) {
543
+
544
+ # This is a prime candidate for a Crontrol_Event class but I'm not bothering currently.
545
+ $events["$hook-$sig"] = (object) array(
546
+ 'hook' => $hook,
547
+ 'time' => $time,
548
+ 'sig' => $sig,
549
+ 'args' => $data['args'],
550
+ 'schedule' => $data['schedule'],
551
+ 'interval' => $data['interval'],
552
+ );
553
+
554
+ }
555
+ }
556
+ }
557
+
558
+ return $events;
559
+
560
+ }
561
+
562
  /**
563
  * Displays the manage page for the plugin.
564
  */
575
 
576
  echo "<div id=\"message\" class=\"updated fade\"><p>$msg</p></div>";
577
  }
578
+ $events = $this->get_cron_events();
 
579
  $doing_edit = (isset( $_GET['action']) && $_GET['action']=='edit-cron') ? $_GET['id'] : false ;
580
  $this->show_cron_status();
581
  ?>
590
  <th><?php _e('Arguments', 'crontrol'); ?></th>
591
  <th><?php _e('Next Run', 'crontrol'); ?></th>
592
  <th><?php _e('Recurrence', 'crontrol'); ?></th>
593
+ <th colspan="3">&nbsp;</th>
594
  </tr>
595
  </thead>
596
  <tbody>
597
  <?php
598
+ if( is_wp_error($events) ) {
599
  ?>
600
+ <tr><td colspan="7"><?php echo $events->get_error_message(); ?></td></tr>
601
  <?php
602
  } else {
603
  $class = "";
604
+ foreach( $events as $id=>$event ) {
605
+
606
+ if ( $doing_edit && $doing_edit == $event->hook && $event->time == $_GET['next_run'] && $event->sig == $_GET['sig'] ) {
607
+ $doing_edit = array(
608
+ 'hookname' => $event->hook,
609
+ 'next_run' => $event->time,
610
+ 'schedule' => ( $event->schedule ? $event->schedule : '_oneoff' ),
611
+ 'sig' => $event->sig,
612
+ 'args' => $event->args
613
+ );
614
+ }
615
+
616
+ echo "<tr id=\"cron-{$id}\" class=\"{$class}\">";
617
+ echo "<td>".($event->hook==CRONTROL_CRON_JOB ? __('<i>PHP Cron</i>', 'crontrol') : $event->hook)."</td>";
618
+ echo "<td>".($event->hook==CRONTROL_CRON_JOB ? __('<i>PHP Code</i>', 'crontrol') : $this->json->encode($event->args))."</td>";
619
+ echo "<td>".strftime("%Y/%m/%d %H:%M:%S", $event->time)." (".$this->time_since(time(), $event->time).")</td>";
620
+ echo "<td>".($event->schedule ? $event->interval.' ('.$this->interval($event->interval).')' : __('Non-repeating', 'crontrol'))."</td>";
621
+ 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</a></td>";
622
+ 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</a></td>";
623
+ 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</a></td>";
624
+ echo "</tr>";
625
+ $class = empty($class)?"alternate":"";
626
+
627
  }
628
  }
629
  ?>
637
  $this->show_cron_form((isset($_GET['action']) and $_GET['action']=='new-php-cron'), false);
638
  }
639
  }
640
+
641
  /**
642
  * Pretty-prints the difference in two times.
643
  *
646
  * @return string The pretty time_since value
647
  * @link http://binarybonsai.com/code/timesince.txt
648
  */
649
+ function time_since($older_date, $newer_date) {
650
  return $this->interval( $newer_date - $older_date );
651
  }
652
+
653
  function interval( $since ) {
654
  // array of time period chunks
655
  $chunks = array(
662
  array( 1 , _n_noop('%s second', '%s seconds', 'crontrol')),
663
  );
664
 
665
+
666
  if( $since <= 0 ) {
667
  return __('now', 'crontrol');
668
  }
703
 
704
  return $output;
705
  }
706
+
707
+ public function init() {
708
+
709
+ static $instance = null;
710
+
711
+ if ( !$instance )
712
+ $instance = new Crontrol;
713
+
714
+ return $instance;
715
+
716
+ }
717
+
718
  }
719
 
720
+ class Crontrol_JSON {
721
+ function encode($in) {
722
+ return json_encode($in);
 
 
 
 
 
 
 
 
 
 
 
 
 
723
  }
724
+ function decode($in) {
725
+ return json_decode($in, true);
 
 
 
 
 
 
726
  }
727
  }
728
 
729
+ if ( defined( 'WP_CLI' ) and WP_CLI and is_readable( $wp_cli = dirname( __FILE__ ) . '/class-wp-cli.php' ) )
730
+ include_once $wp_cli;
731
+
732
  // Get this show on the road
733
+ Crontrol::init();