WP Crontrol - Version 1.1

Version Description

  • Bug fixes for running cron jobs and adding cron schedules

=

Download this release

Release Info

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

Code changes from version 1.0 to 1.1

Files changed (4) hide show
  1. readme.txt +97 -90
  2. screenshot-1.png +0 -0
  3. screenshot-2.png +0 -0
  4. wp-crontrol.php +124 -75
readme.txt CHANGED
@@ -1,90 +1,97 @@
1
- === WP-Crontrol ===
2
- Contributors: scompt
3
- Donate link: http://scompt.com/projects/wp-crontrol
4
- Tags: admin, cron, plugin, control
5
- Requires at least: 2.2
6
- Tested up to: 2.5.1
7
- Stable tag: 1.0
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. Goto the Options->Crontrol panel to add some new cron schedules.
20
- 1. Goto the Manage->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
-
30
- In the Manage->Crontrol admin panel, click on the "add new PHP entry" link underneath the cron entry 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 entry schedule is how often your hook will be executed. If you don't see a good interval, then add one in the Options->Crontrol admin panel. In the "Hook code" area, enter the PHP code that should be run when your cron entry is executed. You don't need to provide the PHP opening tag (`<?php`).
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
-
38
- In the Manage->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 entry schedule is how often your hook will be executed. If you don't see a good interval, then add one in the Options->Crontrol admin panel.
39
-
40
- *Step Two: Writing the function*
41
-
42
- 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:
43
-
44
- `add_action('my_hookname', 'my_function');`
45
-
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
-
62
- 1. New cron entries can be added, modified, and deleted. In addition, they can be executed on-demand.
63
- 1. New cron schedules can be added to WordPress, giving plugin developers more options when scheduling commands.
64
-
65
- == Version History ==
66
-
67
- = Version 0.1 =
68
-
69
- * Super basic, look at what's in WP-Cron functionality.
70
-
71
- = Version 0.2 =
72
-
73
- * Fully documented the code.
74
- * Fixed the bug that the activate action wouldn't be run if the plugin wasn't in a subdirectory.
75
- * Now will play nicely in case any other plugins specify additional cron schedules.
76
- * Minor cosmetic fixes.
77
-
78
- = Version 0.3 =
79
-
80
- * Internationalization
81
- * Editing/deleting/execution of cron entries
82
- * More text, status messages, etc.
83
- * Allow a user to enter a schedule entry in a human manner
84
- * Looks better on WordPress 2.5
85
-
86
- = Version 1.0 =
87
-
88
- * Input of PHP code for cron entries
89
- * Non-repeating cron entries
90
- * Handles cron entries with arguments
 
 
 
 
 
 
 
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
+
30
+ In the Tools -> Crontrol admin panel, click on the "add new PHP entry" link underneath the cron entry 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 entry schedule is how often your hook will be executed. If you don't see a good interval, then add one in the Settings -> Crontrol admin panel. In the "Hook code" area, enter the PHP code that should be run when your cron entry is executed. You don't need to provide the PHP opening tag (`<?php`).
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
+
38
+ 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 entry schedule is how often your hook will be executed. If you don't see a good interval, then add one in the Settings -> Crontrol admin panel.
39
+
40
+ *Step Two: Writing the function*
41
+
42
+ 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:
43
+
44
+ `add_action('my_hookname', 'my_function');`
45
+
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
+
62
+ 1. New cron entries can be added, modified, and deleted. In addition, they can be executed on-demand.
63
+ 1. New cron schedules can be added to WordPress, giving plugin developers more options when scheduling commands.
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
75
+ * Various small tweaks
76
+ * WordPress 3.4 compatibility
77
+
78
+ = 1.0 =
79
+ * Input of PHP code for cron entries
80
+ * Non-repeating cron entries
81
+ * Handles cron entries with arguments
82
+
83
+ = 0.3 =
84
+ * Internationalization
85
+ * Editing/deleting/execution of cron entries
86
+ * More text, status messages, etc.
87
+ * Allow a user to enter a schedule entry in a human manner
88
+ * Looks better on WordPress 2.5
89
+
90
+ = 0.2 =
91
+ * Fully documented the code.
92
+ * Fixed the bug that the activate action wouldn't be run if the plugin wasn't in a subdirectory.
93
+ * Now will play nicely in case any other plugins specify additional cron schedules.
94
+ * Minor cosmetic fixes.
95
+
96
+ = 0.1 =
97
+ * Super basic, look at what's in WP-Cron functionality.
screenshot-1.png CHANGED
Binary file
screenshot-2.png CHANGED
Binary file
wp-crontrol.php CHANGED
@@ -3,9 +3,10 @@
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: Edward Dale
7
- * Version: 1.0
8
- * Author URI: http://www.scompt.com
 
9
  */
10
 
11
  /**
@@ -29,16 +30,15 @@
29
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
30
  *
31
  * @package WP-Crontrol
32
- * @author Edward Dale <scompt@scompt.com>
33
- * @copyright Copyright 2007 Edward Dale
34
  * @license http://www.gnu.org/licenses/gpl.txt GPL 2.0
35
- * @version $Id: wp-crontrol.php 49327 2008-06-06 09:08:48Z scompt $
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
  */
@@ -54,10 +54,10 @@ class Crontrol {
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
  /**
@@ -66,14 +66,14 @@ class Crontrol {
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', str_replace(ABSPATH, '', dirname(__FILE__).'/gettext'));
75
  }
76
-
77
  /**
78
  * Handles any POSTs made by the plugin. Run using the 'init' action.
79
  */
@@ -84,7 +84,7 @@ class Crontrol {
84
  extract($_POST, EXTR_PREFIX_ALL, 'in');
85
  $in_args = $this->json->decode(stripslashes($in_args));
86
  $this->add_cron($in_next_run, $in_schedule, $in_hookname, $in_args);
87
- wp_redirect("edit.php?page=crontrol_admin_manage_page&crontrol_message=5&crontrol_name={$in_hookname}");
88
 
89
  } else if( isset($_POST['new_php_cron']) ) {
90
  if( !current_user_can('manage_options') ) die(__('You are not allowed to add new cron events.', 'crontrol'));
@@ -93,8 +93,8 @@ class Crontrol {
93
  $args = array('code'=>stripslashes($in_hookcode));
94
  $hookname = CRONTROL_CRON_JOB;
95
  $this->add_cron($in_next_run, $in_schedule, $hookname, $args);
96
- wp_redirect("edit.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
 
@@ -103,7 +103,7 @@ class Crontrol {
103
  $in_args = $this->json->decode(stripslashes($in_args));
104
  $i=$this->delete_cron($in_original_hookname, $in_original_sig, $in_original_next_run);
105
  $i=$this->add_cron($in_next_run, $in_schedule, $in_hookname, $in_args);
106
- wp_redirect("edit.php?page=crontrol_admin_manage_page&crontrol_message=4&crontrol_name={$in_hookname}");
107
 
108
  } else if( isset($_POST['edit_php_cron']) ) {
109
  if( !current_user_can('manage_options') ) die(__('You are not allowed to edit cron events.', 'crontrol'));
@@ -115,7 +115,7 @@ class Crontrol {
115
  $args = array('code'=>stripslashes($in_hookcode));
116
  $i=$this->delete_cron($in_original_hookname, $in_original_sig, $in_original_next_run);
117
  $i=$this->add_cron($in_next_run, $in_schedule, $hookname, $args);
118
- wp_redirect("edit.php?page=crontrol_admin_manage_page&crontrol_message=4&crontrol_name={$in_hookname}");
119
 
120
  } else if( isset($_POST['new_schedule']) ) {
121
  if( !current_user_can('manage_options') ) die(__('You are not allowed to add new cron schedules.', 'crontrol'));
@@ -145,7 +145,7 @@ class Crontrol {
145
  } else if( isset($_GET['action']) && $_GET['action']=='delete-sched') {
146
  if( !current_user_can('manage_options') ) die(__('You are not allowed to delete cron schedules.', 'crontrol'));
147
  $id = $_GET['id'];
148
- check_admin_referer("delete-sched_$id");
149
  $this->delete_schedule($id);
150
  wp_redirect("options-general.php?page=crontrol_admin_options_page&crontrol_message=2&crontrol_name=$id");
151
 
@@ -154,26 +154,26 @@ class Crontrol {
154
  $id = $_GET['id'];
155
  $sig = $_GET['sig'];
156
  $next_run = $_GET['next_run'];
157
- check_admin_referer("delete-cron_$id_$sig_{$next_run}");
158
  if( $this->delete_cron($id, $sig, $next_run) ) {
159
- wp_redirect("edit.php?page=crontrol_admin_manage_page&crontrol_message=6&crontrol_name=$id");
160
  } else {
161
- wp_redirect("edit.php?page=crontrol_admin_manage_page&crontrol_message=7&crontrol_name=$id");
162
  };
163
 
164
  } else if( isset($_GET['action']) && $_GET['action']=='run-cron') {
165
  if( !current_user_can('manage_options') ) die(__('You are not allowed to run cron events.', 'crontrol'));
166
  $id = $_GET['id'];
167
  $sig = $_GET['sig'];
168
- check_admin_referer("run-cron_$id_$sig");
169
  if( $this->run_cron($id, $sig) ) {
170
- wp_redirect("edit.php?page=crontrol_admin_manage_page&crontrol_message=1&crontrol_name=$id");
171
  } else {
172
- wp_redirect("edit.php?page=crontrol_admin_manage_page&crontrol_message=8&crontrol_name=$id");
173
  }
174
  }
175
  }
176
-
177
  /**
178
  * Executes a cron entry immediately.
179
  *
@@ -186,6 +186,7 @@ class Crontrol {
186
  foreach( $crons as $time=>$cron ) {
187
  if( isset( $cron[$hookname][$sig] ) ) {
188
  $args = $cron[$hookname][$sig]['args'];
 
189
  wp_schedule_single_event(time()-1, $hookname, $args);
190
  spawn_cron();
191
  return true;
@@ -193,7 +194,7 @@ class Crontrol {
193
  }
194
  return false;
195
  }
196
-
197
  /**
198
  * Adds a new cron entry.
199
  *
@@ -212,7 +213,7 @@ class Crontrol {
212
  return wp_schedule_event( $next_run, $schedule, $hookname, $args ) === NULL;
213
  }
214
  }
215
-
216
  /**
217
  * Deletes a cron entry.
218
  *
@@ -227,7 +228,7 @@ class Crontrol {
227
  }
228
  return false;
229
  }
230
-
231
  /**
232
  * Adds a new custom cron schedule.
233
  *
@@ -236,25 +237,25 @@ class Crontrol {
236
  * @param string $display The display name of the schedule
237
  */
238
  function add_schedule($name, $interval, $display) {
239
- $old_scheds = get_option('crontrol_schedules');
240
  $old_scheds[$name] = array('interval'=>$interval, 'display'=>$display);
241
  update_option('crontrol_schedules', $old_scheds);
242
  }
243
-
244
  /**
245
  * Deletes a custom cron schedule.
246
  *
247
  * @param string $name The internal_name of the schedule to delete.
248
  */
249
  function delete_schedule($name) {
250
- $scheds = get_option('crontrol_schedules');
251
  unset($scheds[$name]);
252
  update_option('crontrol_schedules', $scheds);
253
  }
254
-
255
  /**
256
  * Sets up the plugin environment upon first activation.
257
- *
258
  * Run using the 'activate_' action.
259
  */
260
  function activate() {
@@ -266,7 +267,7 @@ class Crontrol {
266
  _set_cron_array(array());
267
  }
268
  }
269
-
270
  /**
271
  * Adds options & management pages to the admin menu.
272
  *
@@ -276,7 +277,7 @@ class Crontrol {
276
  $page = add_options_page('Crontrol', 'Crontrol', 'manage_options', 'crontrol_admin_options_page', array(&$this, 'admin_options_page') );
277
  $page = add_management_page('Crontrol', "Crontrol", 'manage_options', 'crontrol_admin_manage_page', array(&$this, 'admin_manage_page') );
278
  }
279
-
280
  /**
281
  * Gives WordPress the plugin's set of cron schedules.
282
  *
@@ -286,18 +287,18 @@ class Crontrol {
286
  * @return array The existing cron schedules along with the plugin's schedules.
287
  */
288
  function cron_schedules($scheds) {
289
- $new_scheds = get_option('crontrol_schedules');
290
  return array_merge($new_scheds, $scheds);
291
  }
292
-
293
  /**
294
  * Displays the options page for the plugin.
295
  */
296
  function admin_options_page() {
297
  $schedules = $this->get_schedules();
298
- $custom_schedules = get_option('crontrol_schedules');
299
  $custom_keys = array_keys($custom_schedules);
300
-
301
  if( isset($_GET['crontrol_message']) ) {
302
  $messages = array( '2' => __("Successfully deleted the cron schedule <b>%s</b>", 'crontrol'),
303
  '3' => __("Successfully added the cron schedule <b>%s</b>", 'crontrol'),
@@ -307,9 +308,10 @@ class Crontrol {
307
 
308
  echo "<div id=\"message\" class=\"updated fade\"><p>$msg</p></div>";
309
  }
310
-
311
  ?>
312
  <div class="wrap">
 
313
  <h2><?php _e("Cron Schedules", "crontrol"); ?></h2>
314
  <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>
315
  <div id="ajax-response"></div>
@@ -343,12 +345,13 @@ class Crontrol {
343
  echo "</tr>";
344
  $class = empty($class)?"alternate":"";
345
  }
346
- }
347
  ?>
348
  </tbody>
349
  </table>
350
  </div>
351
  <div class="wrap narrow">
 
352
  <h2><?php _e('Add new cron schedule', 'crontrol'); ?></h2>
353
  <p><?php _e('Adding a new cron schedule will allow you to schedule events that re-occur at the given interval.', 'crontrol'); ?></p>
354
  <form method="post" action="options-general.php?page=crontrol_admin_options_page">
@@ -367,7 +370,7 @@ class Crontrol {
367
  <td width="67%"><input type="text" size="40" value="" id="display_name" name="display_name"/></td>
368
  </tr>
369
  </tbody></table>
370
- <p class="submit"><input id="schedadd-submit" type="submit" value="<?php _e('Add Cron Schedule &raquo;', 'crontrol'); ?>" name="new_schedule"/></p>
371
  <?php wp_nonce_field('new-sched') ?>
372
  </form>
373
  </div>
@@ -400,6 +403,56 @@ class Crontrol {
400
  </select><?php
401
  }
402
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
403
  /**
404
  * Shows the form used to add/edit cron entries.
405
  *
@@ -408,11 +461,11 @@ class Crontrol {
408
  */
409
  function show_cron_form($is_php, $existing) {
410
  if( $is_php ) {
411
- $helper_text = __('Cron entries 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="edit.php?page=crontrol_admin_manage_page&action=new-cron#crontrol_form">this form</a>.', 'crontrol');
412
- $link = ' (<a href="edit.php?page=crontrol_admin_manage_page#crontrol_form">'. __('Add new entry', 'crontrol') .'</a>)';
413
  } else {
414
- $helper_text = __('Cron entries trigger actions in your code. A cron entry added using the form below needs a corresponding action hook somewhere in code, perhaps the <code>functions.php</code> file in your theme. It is also possible to create your action hook from within WordPress using <a href="edit.php?page=crontrol_admin_manage_page&action=new-php-cron#crontrol_form">this form</a>.', 'crontrol');
415
- $link = ' (<a href="edit.php?page=crontrol_admin_manage_page&amp;action=new-php-cron#crontrol_form">'. __('Add new PHP entry', 'crontrol') .'</a>)';
416
  }
417
  if( is_array($existing) ) {
418
  $other_fields = wp_nonce_field( "edit-cron_{$existing['hookname']}_{$existing['sig']}_{$existing['next_run']}", "_wpnonce", true, false );
@@ -432,6 +485,7 @@ class Crontrol {
432
  }
433
  ?>
434
  <div id="crontrol_form" class="wrap narrow">
 
435
  <h2><?php echo $button; if($link) echo '<span style="font-size:xx-small">'.$link.'</span>'; ?></h2>
436
  <p><?php echo $helper_text ?></p>
437
  <form method="post">
@@ -462,7 +516,7 @@ class Crontrol {
462
  </td>
463
  </tr>
464
  </tbody></table>
465
- <p class="submit"><input type="submit" value="<?php echo $button ?> &raquo;" name="<?php echo $action ?>"/></p>
466
  </form>
467
  </div>
468
  <?php
@@ -487,8 +541,10 @@ class Crontrol {
487
  $crons = _get_cron_array();
488
  $schedules = $this->get_schedules();
489
  $doing_edit = (isset( $_GET['action']) && $_GET['action']=='edit-cron') ? $_GET['id'] : false ;
 
490
  ?>
491
  <div class="wrap">
 
492
  <h2><?php _e('WP-Cron Entries', 'crontrol'); ?></h2>
493
  <p></p>
494
  <table class="widefat">
@@ -505,7 +561,7 @@ class Crontrol {
505
  <?php
506
  if( empty($crons) ) {
507
  ?>
508
- <tr colspan="6"><td><?php _e('You currently have no cron entries. Add one below!', 'crontrol') ?></td></tr>
509
  <?php
510
  } else {
511
  $class = "";
@@ -523,11 +579,11 @@ class Crontrol {
523
  echo "<tr id=\"cron-$hook-$sig\" class=\"$class\">";
524
  echo "<td>".($hook==CRONTROL_CRON_JOB ? __('<i>PHP Cron</i>', 'crontrol') : $hook)."</td>";
525
  echo "<td>".($hook==CRONTROL_CRON_JOB ? __('<i>PHP Code</i>', 'crontrol') : $this->json->encode($data['args']))."</td>";
526
- echo "<td>".strftime("%D %T", $time)." (".$this->time_since(time(), $time).")</td>";
527
  echo "<td>".($data['schedule'] ? $data['interval'].' ('.$this->interval($data['interval']).')' : __('Non-repeating', 'crontrol'))."</td>";
528
- echo "<td><a class='view' href='edit.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>";
529
- echo "<td><a class='view' href='".wp_nonce_url("edit.php?page=crontrol_admin_manage_page&amp;action=run-cron&amp;id=$hook&amp;sig=$sig", "run-cron_$hook_$sig")."'>Do Now</a></td>";
530
- echo "<td><a class='delete' href='".wp_nonce_url("edit.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>";
531
  echo "</tr>";
532
  $class = empty($class)?"alternate":"";
533
  }
@@ -542,10 +598,10 @@ class Crontrol {
542
  if( is_array( $doing_edit ) ) {
543
  $this->show_cron_form($doing_edit['hookname']==CRONTROL_CRON_JOB, $doing_edit);
544
  } else {
545
- $this->show_cron_form($_GET['action']=='new-php-cron', false);
546
  }
547
  }
548
-
549
  /**
550
  * Pretty-prints the difference in two times.
551
  *
@@ -554,23 +610,23 @@ class Crontrol {
554
  * @return string The pretty time_since value
555
  * @link http://binarybonsai.com/code/timesince.txt
556
  */
557
- function time_since($older_date, $newer_date) {
558
  return $this->interval( $newer_date - $older_date );
559
  }
560
-
561
  function interval( $since ) {
562
  // array of time period chunks
563
  $chunks = array(
564
- array(60 * 60 * 24 * 365 , __ngettext_noop('%s year', '%s years', 'crontrol')),
565
- array(60 * 60 * 24 * 30 , __ngettext_noop('%s month', '%s months', 'crontrol')),
566
- array(60 * 60 * 24 * 7, __ngettext_noop('%s week', '%s weeks', 'crontrol')),
567
- array(60 * 60 * 24 , __ngettext_noop('%s day', '%s days', 'crontrol')),
568
- array(60 * 60 , __ngettext_noop('%s hour', '%s hours', 'crontrol')),
569
- array(60 , __ngettext_noop('%s minute', '%s minutes', 'crontrol')),
570
- array( 1 , __ngettext_noop('%s second', '%s seconds', 'crontrol')),
571
  );
572
-
573
 
 
574
  if( $since <= 0 ) {
575
  return __('now', 'crontrol');
576
  }
@@ -594,7 +650,7 @@ class Crontrol {
594
  }
595
 
596
  // set output var
597
- $output = sprintf(__ngettext($name[0], $name[1], $count, 'crontrol'), $count);
598
 
599
  // step two: the second chunk
600
  if ($i + 1 < $j)
@@ -605,7 +661,7 @@ class Crontrol {
605
  if (($count2 = floor(($since - ($seconds * $count)) / $seconds2)) != 0)
606
  {
607
  // add to output var
608
- $output .= ' '.sprintf(__ngettext($name2[0], $name2[1], $count2, 'crontrol'), $count2);
609
  }
610
  }
611
 
@@ -615,9 +671,9 @@ class Crontrol {
615
 
616
  // PHP4 doesn't have json_encode built-in.
617
  if( !function_exists('json_encode' ) ) {
618
- if( !class_exists('Services_JSON') )
619
  require_once('JSON.php');
620
-
621
  class Crontrol_JSON {
622
  var $json;
623
  function Crontrol_JSON() {
@@ -641,13 +697,6 @@ if( !function_exists('json_encode' ) ) {
641
  }
642
  }
643
 
644
- // WordPress <2.5 doesn't have this function, so we provide it if needed
645
- if( !function_exists(__ngettext_noop) ) {
646
- function __ngettext_noop($single, $plural, $number=1, $domain = 'default') {
647
- return array($single, $plural);
648
- }
649
- }
650
-
651
  // Get this show on the road
652
  new Crontrol();
653
  ?>
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
  /**
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
  */
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
  /**
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
  */
84
  extract($_POST, EXTR_PREFIX_ALL, 'in');
85
  $in_args = $this->json->decode(stripslashes($in_args));
86
  $this->add_cron($in_next_run, $in_schedule, $in_hookname, $in_args);
87
+ wp_redirect("tools.php?page=crontrol_admin_manage_page&crontrol_message=5&crontrol_name={$in_hookname}");
88
 
89
  } else if( isset($_POST['new_php_cron']) ) {
90
  if( !current_user_can('manage_options') ) die(__('You are not allowed to add new cron events.', 'crontrol'));
93
  $args = array('code'=>stripslashes($in_hookcode));
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
 
103
  $in_args = $this->json->decode(stripslashes($in_args));
104
  $i=$this->delete_cron($in_original_hookname, $in_original_sig, $in_original_next_run);
105
  $i=$this->add_cron($in_next_run, $in_schedule, $in_hookname, $in_args);
106
+ wp_redirect("tools.php?page=crontrol_admin_manage_page&crontrol_message=4&crontrol_name={$in_hookname}");
107
 
108
  } else if( isset($_POST['edit_php_cron']) ) {
109
  if( !current_user_can('manage_options') ) die(__('You are not allowed to edit cron events.', 'crontrol'));
115
  $args = array('code'=>stripslashes($in_hookcode));
116
  $i=$this->delete_cron($in_original_hookname, $in_original_sig, $in_original_next_run);
117
  $i=$this->add_cron($in_next_run, $in_schedule, $hookname, $args);
118
+ wp_redirect("tools.php?page=crontrol_admin_manage_page&crontrol_message=4&crontrol_name={$in_hookname}");
119
 
120
  } else if( isset($_POST['new_schedule']) ) {
121
  if( !current_user_can('manage_options') ) die(__('You are not allowed to add new cron schedules.', 'crontrol'));
145
  } else if( isset($_GET['action']) && $_GET['action']=='delete-sched') {
146
  if( !current_user_can('manage_options') ) die(__('You are not allowed to delete cron schedules.', 'crontrol'));
147
  $id = $_GET['id'];
148
+ check_admin_referer("delete-sched_{$id}");
149
  $this->delete_schedule($id);
150
  wp_redirect("options-general.php?page=crontrol_admin_options_page&crontrol_message=2&crontrol_name=$id");
151
 
154
  $id = $_GET['id'];
155
  $sig = $_GET['sig'];
156
  $next_run = $_GET['next_run'];
157
+ check_admin_referer("delete-cron_{$id}_{$sig}_{$next_run}");
158
  if( $this->delete_cron($id, $sig, $next_run) ) {
159
+ wp_redirect("tools.php?page=crontrol_admin_manage_page&crontrol_message=6&crontrol_name=$id");
160
  } else {
161
+ wp_redirect("tools.php?page=crontrol_admin_manage_page&crontrol_message=7&crontrol_name=$id");
162
  };
163
 
164
  } else if( isset($_GET['action']) && $_GET['action']=='run-cron') {
165
  if( !current_user_can('manage_options') ) die(__('You are not allowed to run cron events.', 'crontrol'));
166
  $id = $_GET['id'];
167
  $sig = $_GET['sig'];
168
+ check_admin_referer("run-cron_{$id}_{$sig}");
169
  if( $this->run_cron($id, $sig) ) {
170
+ wp_redirect("tools.php?page=crontrol_admin_manage_page&crontrol_message=1&crontrol_name=$id");
171
  } else {
172
+ wp_redirect("tools.php?page=crontrol_admin_manage_page&crontrol_message=8&crontrol_name=$id");
173
  }
174
  }
175
  }
176
+
177
  /**
178
  * Executes a cron entry immediately.
179
  *
186
  foreach( $crons as $time=>$cron ) {
187
  if( isset( $cron[$hookname][$sig] ) ) {
188
  $args = $cron[$hookname][$sig]['args'];
189
+ delete_transient( 'doing_cron' );
190
  wp_schedule_single_event(time()-1, $hookname, $args);
191
  spawn_cron();
192
  return true;
194
  }
195
  return false;
196
  }
197
+
198
  /**
199
  * Adds a new cron entry.
200
  *
213
  return wp_schedule_event( $next_run, $schedule, $hookname, $args ) === NULL;
214
  }
215
  }
216
+
217
  /**
218
  * Deletes a cron entry.
219
  *
228
  }
229
  return false;
230
  }
231
+
232
  /**
233
  * Adds a new custom cron schedule.
234
  *
237
  * @param string $display The display name of the schedule
238
  */
239
  function add_schedule($name, $interval, $display) {
240
+ $old_scheds = get_option('crontrol_schedules',array());
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
  *
248
  * @param string $name The internal_name of the schedule to delete.
249
  */
250
  function delete_schedule($name) {
251
+ $scheds = get_option('crontrol_schedules',array());
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() {
267
  _set_cron_array(array());
268
  }
269
  }
270
+
271
  /**
272
  * Adds options & management pages to the admin menu.
273
  *
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
  *
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
  */
297
  function admin_options_page() {
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
 
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>
345
  echo "</tr>";
346
  $class = empty($class)?"alternate":"";
347
  }
348
+ }
349
  ?>
350
  </tbody>
351
  </table>
352
  </div>
353
  <div class="wrap narrow">
354
+ <?php screen_icon(); ?>
355
  <h2><?php _e('Add new cron schedule', 'crontrol'); ?></h2>
356
  <p><?php _e('Adding a new cron schedule will allow you to schedule events that re-occur at the given interval.', 'crontrol'); ?></p>
357
  <form method="post" action="options-general.php?page=crontrol_admin_options_page">
370
  <td width="67%"><input type="text" size="40" value="" id="display_name" name="display_name"/></td>
371
  </tr>
372
  </tbody></table>
373
+ <p class="submit"><input id="schedadd-submit" type="submit" class="button-primary" value="<?php _e('Add Cron Schedule &raquo;', 'crontrol'); ?>" name="new_schedule"/></p>
374
  <?php wp_nonce_field('new-sched') ?>
375
  </form>
376
  </div>
403
  </select><?php
404
  }
405
 
406
+ /**
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 ) );
421
+ $cron_url = site_url( 'wp-cron.php?doing_wp_cron=' . $doing_wp_cron );
422
+
423
+ $result = wp_remote_post( $cron_url, array(
424
+ 'timeout' => 3,
425
+ 'blocking' => true,
426
+ 'sslverify' => apply_filters( 'https_local_ssl_verify', true )
427
+ ) );
428
+
429
+ if ( is_wp_error( $result ) ) {
430
+ return $result;
431
+ } else {
432
+ set_transient( 'wp-cron-test-ok', 1, 3600 );
433
+ return true;
434
+ }
435
+
436
+ }
437
+
438
+ /**
439
+ * Shows the status of WP-Cron functionality on the site. Only displays a message when there's a problem.
440
+ *
441
+ */
442
+ function show_cron_status() {
443
+
444
+ $status = $this->test_cron_spawn();
445
+
446
+ if ( is_wp_error( $status ) ) {
447
+ ?>
448
+ <div id="cron-status-error" class="error">
449
+ <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:<br /><strong>%s</strong>', 'crontrol' ), esc_html( $status->get_error_message() ) ); ?></p>
450
+ </div>
451
+ <?php
452
+ }
453
+
454
+ }
455
+
456
  /**
457
  * Shows the form used to add/edit cron entries.
458
  *
461
  */
462
  function show_cron_form($is_php, $existing) {
463
  if( $is_php ) {
464
+ $helper_text = __('Cron entries 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="tools.php?page=crontrol_admin_manage_page&action=new-cron#crontrol_form">this form</a>.', 'crontrol');
465
+ $link = ' (<a href="tools.php?page=crontrol_admin_manage_page#crontrol_form">'. __('Add new entry', 'crontrol') .'</a>)';
466
  } else {
467
+ $helper_text = __('Cron entries trigger actions in your code. A cron entry added using the form below needs a corresponding action hook somewhere in code, perhaps the <code>functions.php</code> file in your theme. It is also possible to create your action hook from within WordPress using <a href="tools.php?page=crontrol_admin_manage_page&action=new-php-cron#crontrol_form">this form</a>.', 'crontrol');
468
+ $link = ' (<a href="tools.php?page=crontrol_admin_manage_page&amp;action=new-php-cron#crontrol_form">'. __('Add new PHP entry', 'crontrol') .'</a>)';
469
  }
470
  if( is_array($existing) ) {
471
  $other_fields = wp_nonce_field( "edit-cron_{$existing['hookname']}_{$existing['sig']}_{$existing['next_run']}", "_wpnonce", true, false );
485
  }
486
  ?>
487
  <div id="crontrol_form" class="wrap narrow">
488
+ <?php screen_icon(); ?>
489
  <h2><?php echo $button; if($link) echo '<span style="font-size:xx-small">'.$link.'</span>'; ?></h2>
490
  <p><?php echo $helper_text ?></p>
491
  <form method="post">
516
  </td>
517
  </tr>
518
  </tbody></table>
519
+ <p class="submit"><input type="submit" class="button-primary" value="<?php echo $button ?> &raquo;" name="<?php echo $action ?>"/></p>
520
  </form>
521
  </div>
522
  <?php
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
  ?>
546
  <div class="wrap">
547
+ <?php screen_icon(); ?>
548
  <h2><?php _e('WP-Cron Entries', 'crontrol'); ?></h2>
549
  <p></p>
550
  <table class="widefat">
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 = "";
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
  }
598
  if( is_array( $doing_edit ) ) {
599
  $this->show_cron_form($doing_edit['hookname']==CRONTROL_CRON_JOB, $doing_edit);
600
  } else {
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
  * @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(
620
+ array(60 * 60 * 24 * 365 , _n_noop('%s year', '%s years', 'crontrol')),
621
+ array(60 * 60 * 24 * 30 , _n_noop('%s month', '%s months', 'crontrol')),
622
+ array(60 * 60 * 24 * 7, _n_noop('%s week', '%s weeks', 'crontrol')),
623
+ array(60 * 60 * 24 , _n_noop('%s day', '%s days', 'crontrol')),
624
+ array(60 * 60 , _n_noop('%s hour', '%s hours', 'crontrol')),
625
+ array(60 , _n_noop('%s minute', '%s minutes', 'crontrol')),
626
+ array( 1 , _n_noop('%s second', '%s seconds', 'crontrol')),
627
  );
 
628
 
629
+
630
  if( $since <= 0 ) {
631
  return __('now', 'crontrol');
632
  }
650
  }
651
 
652
  // set output var
653
+ $output = sprintf(_n($name[0], $name[1], $count, 'crontrol'), $count);
654
 
655
  // step two: the second chunk
656
  if ($i + 1 < $j)
661
  if (($count2 = floor(($since - ($seconds * $count)) / $seconds2)) != 0)
662
  {
663
  // add to output var
664
+ $output .= ' '.sprintf(_n($name2[0], $name2[1], $count2, 'crontrol'), $count2);
665
  }
666
  }
667
 
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() {
697
  }
698
  }
699
 
 
 
 
 
 
 
 
700
  // Get this show on the road
701
  new Crontrol();
702
  ?>