PluginProbe
Timed Content / 2.68
Timed Content v2.68
2.99 trunk 1.0 1.1 1.2 2.0 2.1 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.10 2.11 2.12 2.15 2.2 2.3 2.3.1 2.4 2.5 2.5.1 2.50 2.51 2.52 All 67 releases
timed-content / timed-content.php

timed-content.php in Timed Content 2.68, at timed-content.php

2,339 lines 110.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: Timed Content
4 Text Domain: timed-content
5 Domain Path: /lang
6 Plugin URI: http://wordpress.org/plugins/timed-content/
7 Description: Plugin to show or hide portions of a Page or Post based on specific date/time characteristics. These actions can either be processed either server-side or client-side, depending on the desired effect.
8 Author: K. Tough, Arno Welzel, Enrico Bacis
9 Version: 2.68
10 Author URI: http://wordpress.org/plugins/timed-content/
11 */
12 defined('ABSPATH') or die();
13
14 include 'lib/customFieldsInterface.php';
15
16 define('TIMED_CONTENT_VERSION', '2.68');
17 define('TIMED_CONTENT_SLUG', 'timed-content');
18 define('TIMED_CONTENT_PLUGIN_URL', plugins_url() . '/' . TIMED_CONTENT_SLUG);
19 define('TIMED_CONTENT_SHORTCODE_CLIENT', 'timed-content-client');
20 define('TIMED_CONTENT_SHORTCODE_SERVER', 'timed-content-server');
21 define('TIMED_CONTENT_SHORTCODE_RULE', 'timed-content-rule');
22 define('TIMED_CONTENT_TIME_ZERO', '1970-01-01 00:00:00 +000'); // Start of Unix Epoch (32 bit)
23 define('TIMED_CONTENT_TIME_END', '2038-01-19 03:14:06 +000'); // End of Unix Epoch (32 bit)
24 define('TIMED_CONTENT_RULE_TYPE', 'timed_content_rule');
25 define('TIMED_CONTENT_RULE_POSTMETA_PREFIX', TIMED_CONTENT_RULE_TYPE . '_');
26 define('TIMED_CONTENT_CSS', TIMED_CONTENT_PLUGIN_URL . '/css/timed-content.css');
27 define('TIMED_CONTENT_CSS_DASHICONS', TIMED_CONTENT_PLUGIN_URL . '/css/dashicons/style.css');
28 define('TIMED_CONTENT_JQUERY_UI_CSS', TIMED_CONTENT_PLUGIN_URL . '/css/jqueryui/1.10.3/themes/smoothness/jquery-ui.css');
29 define('TIMED_CONTENT_JQUERY_UI_TIMEPICKER_JS', TIMED_CONTENT_PLUGIN_URL . '/js/jquery-ui-timepicker-0.3.3/jquery.ui.timepicker.js');
30 define('TIMED_CONTENT_JQUERY_UI_TIMEPICKER_CSS', TIMED_CONTENT_PLUGIN_URL . '/js/jquery-ui-timepicker-0.3.3/jquery.ui.timepicker.css');
31 define('TIMED_CONTENT_DATE_FORMAT_OUTPUT', 'Y-m-d H:i O');
32
33 /**
34 * Class timedContentPlugin
35 *
36 * @package TimedContent
37 */
38 class timedContentPlugin
39 {
40 var $rule_freq_array;
41 var $rule_days_array;
42 var $rule_ordinal_array;
43 var $rule_ordinal_days_array;
44 var $rule_occurrence_custom_fields;
45 var $rule_pattern_custom_fields;
46 var $rule_recurrence_custom_fields;
47 var $rule_exceptions_custom_fields;
48
49 var $meridiem;
50 var $show_period;
51 var $show_period_labels;
52 var $show_leading_zero;
53
54 var $jquery_ui_datetime_datepicker_i18n;
55 var $jquery_ui_datetime_timepicker_i18n;
56
57 /**
58 * Constructor
59 */
60 function __construct()
61 {
62 add_filter('timed_content_filter', 'convert_smilies');
63 add_filter('timed_content_filter', 'convert_chars');
64 add_filter('timed_content_filter', 'prepend_attachment');
65 add_filter('timed_content_filter', 'do_shortcode');
66 add_filter('manage_' . TIMED_CONTENT_RULE_TYPE . '_posts_columns', array($this, 'addDescColumnHead'));
67 add_filter('pre_get_posts', array($this, 'timedContentPreGetPosts'));
68 add_filter('post_updated_messages', array($this, 'timedContentRuleUpdatedMessages'), 1);
69
70 add_action('plugins_loaded', array($this, 'i18nInit'), 1);
71 add_action('init', array($this, 'init'), 2);
72 add_action('wp_head', array($this, 'addHeaderCode'), 1);
73 add_action('manage_' . TIMED_CONTENT_RULE_TYPE . '_posts_custom_column', array($this, 'addDescColumnContent'), 10, 2);
74 add_action('admin_enqueue_scripts', array($this, 'addAdminHeaderCode'), 1);
75 add_action('admin_init', array($this, 'setTinyMCEPluginVars'), 1);
76 add_action('admin_init', array($this, 'initTinyMCEPlugin'), 2);
77 add_action('wp_ajax_timedContentPluginGetTinyMCEDialog', array($this, 'timedContentPluginGetTinyMCEDialog'), 1);
78 add_action('wp_ajax_timedContentPluginGetRulePeriodsAjax', array($this, 'timedContentPluginGetRulePeriodsAjax'), 1);
79 add_action('wp_ajax_timedContentPluginGetScheduleDescriptionAjax', array($this, 'timedContentPluginGetScheduleDescriptionAjax'), 1);
80 add_action('dashboard_glance_items', array($this, 'addRulesCount'));
81 add_action('admin_head', array($this, 'addPostTypeIcons'), 1);
82
83 add_shortcode(TIMED_CONTENT_SHORTCODE_CLIENT, array($this, 'clientShowHTML'));
84 add_shortcode(TIMED_CONTENT_SHORTCODE_SERVER, array($this, 'serverShowHTML'));
85 add_shortcode(TIMED_CONTENT_SHORTCODE_RULE, array($this, 'rulesShowHTML'));
86 }
87
88 /**
89 * Initialise plugin
90 */
91 function init()
92 {
93 global $wp_locale;
94
95 $this->rule_freq_array = array(
96 0 => __('hourly', 'timed-content'),
97 1 => __('daily', 'timed-content'),
98 2 => __('weekly', 'timed-content'),
99 3 => __('monthly', 'timed-content'),
100 4 => __('yearly', 'timed-content')
101 );
102
103 $this->rule_days_array = array(
104 0 => __('Sunday', 'timed-content'),
105 1 => __('Monday', 'timed-content'),
106 2 => __('Tuesday', 'timed-content'),
107 3 => __('Wednesday', 'timed-content'),
108 4 => __('Thursday', 'timed-content'),
109 5 => __('Friday', 'timed-content'),
110 6 => __('Saturday', 'timed-content')
111 );
112
113 $this->rule_ordinal_array = array(
114 0 => __('first', 'timed-content'),
115 1 => __('second', 'timed-content'),
116 2 => __('third', 'timed-content'),
117 3 => __('fourth', 'timed-content'),
118 4 => __('last', 'timed-content')
119 );
120
121 $this->rule_ordinal_days_array = array(
122 0 => __('Sunday', 'timed-content'),
123 1 => __('Monday', 'timed-content'),
124 2 => __('Tuesday', 'timed-content'),
125 3 => __('Wednesday', 'timed-content'),
126 4 => __('Thursday', 'timed-content'),
127 5 => __('Friday', 'timed-content'),
128 6 => __('Saturday', 'timed-content'),
129 7 => __('day', 'timed-content')
130 );
131
132 $this->jquery_ui_datetime_datepicker_i18n = array(
133 "closeText" => _x("Done", "jQuery UI Datepicker Close label", "timed-content"), // Display text for close link
134 "prevText" => _x("Prev", "jQuery UI Datepicker Previous label", "timed-content"), // Display text for previous month link
135 "nextText" => _x("Next", "jQuery UI Datepicker Next label", "timed-content"), // Display text for next month link
136 "currentText" => _x("Today", "jQuery UI Datepicker Today label", "timed-content"), // Display text for current month link
137 "weekHeader" => _x("Wk", "jQuery UI Datepicker Week label", "timed-content"), // Column header for week of the year
138 // Replace the text indices for the following arrays with 0-based arrays
139 "monthNames" => $this->stripArrayIndices($wp_locale->month), // Names of months for drop-down and formatting
140 "monthNamesShort" => $this->stripArrayIndices($wp_locale->month_abbrev), // For formatting
141 "dayNames" => $this->stripArrayIndices($wp_locale->weekday), // For formatting
142 "dayNamesShort" => $this->stripArrayIndices($wp_locale->weekday_abbrev), // For formatting
143 "dayNamesMin" => $this->stripArrayIndices($wp_locale->weekday_initial), // Column headings for days starting at Sunday
144 "dateFormat" => 'yy-mm-dd',
145 "firstDay" => get_option('start_of_week'),
146 "isRTL" => $wp_locale->is_rtl(),
147 "showMonthAfterYear" => false, // True if the year select precedes month, false for month then year
148 "yearSuffix" => '' // Additional text to append to the year in the month headers
149 );
150
151 $tf = get_option('time_format');
152 if (false !== strpos($tf, "A")) {
153 $this->meridiem = array($wp_locale->meridiem['AM'], $wp_locale->meridiem['PM']);
154 $this->show_period = true;
155 $this->show_period_labels = true;
156 $this->show_leading_zero = false;
157 } elseif (false !== strpos($tf, "a")) {
158 $this->meridiem = array($wp_locale->meridiem['am'], $wp_locale->meridiem['pm']);
159 $this->show_period = true;
160 $this->show_period_labels = true;
161 $this->show_leading_zero = false;
162 } else {
163 $this->meridiem = array('', '');
164 $this->show_period = false;
165 $this->show_period_labels = false;
166 $this->show_leading_zero = true;
167 }
168
169 $this->jquery_ui_datetime_timepicker_i18n = array(
170 "hourText" => _x("Hour", "jQuery UI Timepicker 'Hour' label", "timed-content"),
171 "minuteText" => _x("Minute", "jQuery UI Timepicker 'Minute' label", "timed-content"),
172 "timeSeparator" => _x(":", "jQuery UI Datepicker: Character used to separate hours and minutes in translated language", 'timed-content'),
173 "closeButtonText" => _x("Done", "jQuery UI Timepicker 'Done' label", "timed-content"),
174 "nowButtonText" => _x("Now", "jQuery UI Timepicker 'Now' label", "timed-content"),
175 "deselectButtonText" => _x("Deselect", "jQuery UI Timepicker 'Deselect' label", "timed-content"),
176 "amPmText" => array('', ''),
177 "showPeriod" => false,
178 "showPeriodLabels" => false,
179 "showLeadingZero" => false,
180 "timeFormat" => 'G:i'
181 );
182
183 $this->timedContentRuleTypeInit();
184 $this->setupCustomFields();
185 }
186
187 /**
188 * Creates the Timed Content Rule post type and registers it with Wordpress
189 */
190 function timedContentRuleTypeInit()
191 {
192 $labels = array(
193 'name' => _x('Timed Content rules', 'post type general name', 'timed-content'),
194 'singular_name' => _x('Timed Content rule', 'post type singular name', 'timed-content'),
195 'add_new' => _x('Add new', 'Menu item/button label on Timed Content Rules admin page',
196 'timed-content'),
197 'add_new_item' => __('Add new Timed Content rule', 'timed-content'),
198 'edit_item' => __('Edit Timed Content rule', 'timed-content'),
199 'new_item' => __('New Timed Content rule', 'timed-content'),
200 'view_item' => __('View Timed Content rule', 'timed-content'),
201 'search_items' => __('Search Timed Content rules', 'timed-content'),
202 'not_found' => __('No Timed Content rules found', 'timed-content'),
203 'not_found_in_trash' => __('No Timed Content rules found in trash', 'timed-content'),
204 'parent_item_colon' => '',
205 'menu_name' => _x('Timed Content rules', 'post type general name', 'timed-content')
206 );
207 $args = array(
208 'labels' => $labels,
209 'description' => __('Create regular schedules to show or hide selected content in a page or post.',
210 'timed-content'),
211 'public' => false,
212 'publicly_queryable' => false,
213 'exclude_from_search' => false,
214 'show_ui' => true,
215 'show_in_menu' => true,
216 'show_in_nav_menus' => true,
217 'show_in_admin_bar' => true,
218 'query_var' => false,
219 'rewrite' => false,
220 'capability_type' => 'post',
221 'has_archive' => false,
222 'hierarchical' => false,
223 'menu_position' => 5,
224 'supports' => array('title')
225 );
226 register_post_type(TIMED_CONTENT_RULE_TYPE, $args);
227 }
228
229
230 /**
231 * Fix for date_i18n() as suggested in https://core.trac.wordpress.org/ticket/25768
232 *
233 * Modified from the original patch to use the currently set timezone from PHP,
234 * like PHP's date(), and to make the code more readable.
235 *
236 * @param $j
237 * @param $req_format
238 * @param bool $i
239 * @param bool $gmt
240 *
241 * @return bool|string
242 */
243 function fix_date_i18n($j, $req_format, $i = false, $gmt = false)
244 {
245 global $wp_locale;
246 global $post;
247
248 $timestamp = $i;
249
250 // get current timestamp if $i is false
251 if (false === $timestamp) {
252 if ($gmt) {
253 $timestamp = time();
254 } else {
255 $timestamp = current_time('timestamp');
256 }
257
258 // use debug parameter if current user is allowed to edit the post
259 if (isset($_GET['tctest']) && !empty($post) && current_user_can("edit_post", $post->post_id)) {
260 $dt = DateTime::createFromFormat('Y-m-d H:i:s', $_GET['tctest']);
261 if ($dt != false) {
262 $timestamp = $dt->getTimestamp();
263 }
264 }
265 }
266
267 // get components of the date (timestamp) as array
268 $date_components = getdate($timestamp);
269
270 // numeric representation of a month, with leading zeros
271 $date_month = $wp_locale->get_month($date_components['mon']);
272 $date_month_abbrev = $wp_locale->get_month_abbrev($date_month);
273 // numeric representation of the day of the week
274 $date_weekday = $wp_locale->get_weekday($date_components['wday']);
275 $date_weekday_abbrev = $wp_locale->get_weekday_abbrev($date_weekday);
276 // get if hour is Ante meridiem or Post meridiem
277 $meridiem = $date_components['hours'] >= 12 ? 'pm' : 'am';
278 // lowercase Ante meridiem and Post meridiem hours
279 $date_meridiem = $wp_locale->get_meridiem($meridiem);
280 // uppercase Ante meridiem and Post meridiem
281 $date_meridiem_capital = $wp_locale->get_meridiem(strtoupper($meridiem));
282
283 // escape literals
284 $date_weekday_abbrev = backslashit($date_weekday_abbrev);
285 $date_month = backslashit($date_month);
286 $date_weekday = backslashit($date_weekday);
287 $date_month_abbrev = backslashit($date_month_abbrev);
288 $date_meridiem = backslashit($date_meridiem);
289 $date_meridiem_capital = backslashit($date_meridiem_capital);
290
291 // the translated format string
292 $translated_date_format_string = '';
293 // the 2 arrays map a format literal to its translation (e. g. 'F' to the escaped month translation)
294 $translate_formats = array('D', 'F', 'l', 'M', 'a', 'A', 'c', 'r');
295 $translations = array(
296 $date_weekday_abbrev, // D
297 $date_month, // F
298 $date_weekday, // l
299 $date_month_abbrev, // M
300 $date_meridiem, // a
301 $date_meridiem_capital, // A
302 'Y-m-d\TH:i:sP', // c
303 sprintf('%s, d %s Y H:i:s O', $date_weekday_abbrev, $date_month_abbrev), // r
304 );
305
306 // find each format literal that needs translation and replace it by its translation
307 // respects the escaping
308 // iterate $req_format from ending to beginning
309 for ($i = strlen($req_format) - 1; $i > - 1; $i --) {
310 // test if current char is format literal that needs translation
311 $translate_formats_index = array_search($req_format[ $i ], $translate_formats);
312
313 if ($translate_formats_index !== false) {
314 // counts the slashes (the escape char) in front of the current char
315 $slashes_counter = 0;
316
317 // count all slashes left-hand side of the current char
318 for ($j = $i - 1; $j > - 1; $j --) {
319 if ($req_format[ $j ] == '\\') {
320 $slashes_counter ++;
321 } else {
322 break;
323 }
324 }
325
326 // number of slashes is even
327 if ($slashes_counter % 2 == 0) // current char is not escaped, therefore it is a format literal
328 {
329 $translated_date_format_string = $translations[ $translate_formats_index ] . $translated_date_format_string;
330 } else // current char is escaped, therefore it is not a format literal, just add it unchanged
331 {
332 $translated_date_format_string = $req_format[ $i ] . $translated_date_format_string;
333 }
334 } else // current char is no a format literal, just add it unchanged
335 {
336 $translated_date_format_string = $req_format[ $i ] . $translated_date_format_string;
337 }
338 }
339
340 $req_format = $translated_date_format_string;
341
342 if ($gmt) {
343 // get GMT date string
344 $date_formatted = gmdate($req_format, $timestamp);
345 } else {
346 // get Wordpress time zone
347 // $timezone_string = get_option('timezone_string');
348 // Haha, just kidding. Let's get the currently set timezone, as God and Rasmus intended
349 $timezone_string = date_default_timezone_get();
350
351 if ($timezone_string) {
352 // create time zone object
353 $timezone_object = timezone_open($timezone_string);
354 // create date object from time zone object
355 $local_date_object = date_create(null, $timezone_object);
356 // set time and date of $local_date_object to $timestamp
357 $date_components = isset($date_components) ? $date_components : getdate($timestamp);
358 date_date_set($local_date_object, $date_components['year'], $date_components['mon'],
359 $date_components['mday']);
360 date_time_set($local_date_object, $date_components['hours'], $date_components['minutes'],
361 $date_components['seconds']);
362 // format date according to the Wordpress time zone
363 $date_formatted = date_format($local_date_object, $req_format);
364 } else {
365 // fall back if no Wordpress time zone set
366 $date_formatted = date($req_format, $i);
367 }
368 }
369
370 return $date_formatted;
371 }
372
373 /**
374 * Filter to change sort order to title
375 *
376 * @param array $messages Array of currently defined messages for post types
377 *
378 * @return mixed Array of messages with appropriate messages for Timed Content Rules added in
379 */
380 function timedContentPreGetPosts($query)
381 {
382 if ($query->is_admin) {
383 if ($query->get('post_type') == TIMED_CONTENT_RULE_TYPE) {
384 $query->set('orderby', 'title');
385 $query->set('order', 'ASC');
386 }
387 }
388
389 return $query;
390 }
391
392 /**
393 * Filter to customize CRUD messages for Timed Content Rules
394 *
395 * @param array $messages Array of currently defined messages for post types
396 *
397 * @return mixed Array of messages with appropriate messages for Timed Content Rules added in
398 */
399 function timedContentRuleUpdatedMessages($messages)
400 {
401 global $post;
402
403 if (!empty($post)) {
404 /* translators: date and time format to activate rule. http://ca2.php.net/manual/en/function.date.php*/
405 $post_date = date_i18n(__('M j, Y @ G:i', 'timed-content'), strtotime($post->post_date));
406 } else {
407 $post_date = '';
408 }
409
410 $messages[ TIMED_CONTENT_RULE_TYPE ] = array(
411 0 => '', // Unused. Messages start at index 1.
412 1 => __('Timed Content Rule updated.', 'timed-content'),
413 2 => __('Custom field updated.', 'timed-content'),
414 3 => __('Custom field deleted.', 'timed-content'),
415 4 => __('Timed Content Rule updated.', 'timed-content'),
416 /* translators: %s: date and time of the revision */
417 5 => isset($_GET['revision']) ? sprintf(__('Timed Content Rule restored to revision from %s',
418 'timed-content'), wp_post_revision_title((int) $_GET['revision'], false)) : false,
419 6 => __('Timed Content Rule published.', 'timed-content'),
420 7 => __('Timed Content Rule saved.', 'timed-content'),
421 8 => __('Timed Content Rule submitted.', 'timed-content'),
422 /* translators: %s: date and time to activate rule. */
423 9 => sprintf(__('Timed Content Rule scheduled for: %s.', 'timed-content'),
424 "<strong>" . $post_date . "</strong>"),
425 10 => __('Timed Content Rule draft updated.', 'timed-content')
426 );
427
428 return $messages;
429 }
430
431 function datetimeToEnglish($date, $time = "")
432 {
433 $months = array(
434 "January",
435 "February",
436 "March",
437 "April",
438 "May",
439 "June",
440 "July",
441 "August",
442 "September",
443 "October",
444 "November",
445 "December"
446 );
447 $monthsI18N = array(
448 __("January", 'timed-content'),
449 __("February", 'timed-content'),
450 __("March", 'timed-content'),
451 __("April", 'timed-content'),
452 __("May", 'timed-content'),
453 __("June", 'timed-content'),
454 __("July", 'timed-content'),
455 __("August", 'timed-content'),
456 __("September", 'timed-content'),
457 __("October", 'timed-content'),
458 __("November", 'timed-content'),
459 __("December", 'timed-content')
460 );
461 $english_date = str_replace($monthsI18N, $months, $date);
462
463 return $english_date . " " . $time;
464 }
465
466 /**
467 * Advances a date by a set number of days
468 *
469 * @param int $current UNIX timestamp of the date before incrementing
470 * @param int $interval_multiplier Number of days to advance
471 *
472 * @return int Unix timestamp of the new date
473 */
474 function getNextDay($current, $interval_multiplier)
475 {
476 return strtotime($interval_multiplier . " day", $current);
477 }
478
479 /**
480 * Advances a date/time by a set number of hours
481 *
482 * @param int $current UNIX timestamp of the date/time before incrementing
483 * @param int $interval_multiplier Number of hours to advance
484 *
485 * @return int Unix timestamp of the new date/time
486 */
487 function getNextHour($current, $interval_multiplier)
488 {
489 return strtotime($interval_multiplier . " hour", $current);
490 }
491
492 /**
493 * Advances a date/time by a set number of weeks
494 *
495 * Advances a date/time by a set number of weeks. If given an array of days of the week, this function will
496 * advance the date/time to the next day in that array in the jumped-to week. Use this function if you're
497 * repeating an action on specific days of the week (i.e., on Weekdays, Tuesdays and Thursdays, etc.).
498 *
499 * @param int $current UNIX timestamp of the date before incrementing
500 * @param int $interval_multiplier Number of weeks to advance
501 * @param array $days Array of integers symbolizing the days of the week to
502 * repeat on (0 - Sunday, 1 - Monday, ..., 6 - Saturday).
503 *
504 * @return int Unix timestamp of the new date
505 */
506 function getNextWeek($current, $interval_multiplier, $days = array())
507 {
508 // If $days is empty, advance $interval_multiplier weeks from $current and return the timestamp
509 if (empty($days)) {
510 return strtotime($interval_multiplier . " week", $current);
511 }
512
513 // Otherwise, set up an array combining the days of the week to repeat on and the current day
514 // (keys and values of the array will be the same, and the array is sorted)
515 $currentDayOfWeekIndex = date("w", $current);
516 $days = array_merge(array($currentDayOfWeekIndex), $days);
517 $days = array_unique($days);
518 $days = array_values($days);
519 sort($days);
520 $daysOfWeek = array_combine($days, $days);
521
522 // If the current day is the last one of the days of the week to repeat on, jump ahead to
523 // the next week to be repeating on and get the earliest day in the array
524 if ($currentDayOfWeekIndex == max($daysOfWeek)) {
525 $pattern = ((7 - $currentDayOfWeekIndex) + (7 * ($interval_multiplier - 1)) + (min(array_keys($daysOfWeek)))) . " day";
526 } // Otherwise, cycle through the array until we find the next day to repeat on
527 else {
528 $nextDayOfWeekIndex = $currentDayOfWeekIndex;
529 do {
530 } while (!isset($daysOfWeek[ ++ $nextDayOfWeekIndex ]));
531 $pattern = ($nextDayOfWeekIndex - $currentDayOfWeekIndex) . " day";
532 }
533
534 return strtotime($pattern, $current);
535 }
536
537 /**
538 * Advances a date by a set number of months
539 *
540 * Advances a date by a set number of months. When the date of the first active period lies
541 * on the 29th, 30th, or 31st of the month, this function will return a date on the the last day
542 * of the month for those months not containing those days.
543 *
544 * @param int $current UNIX timestamp of the date before incrementing
545 * @param int $start UNIX timestamp of the first active period's date
546 * @param int $interval_multiplier Number of months to advance
547 *
548 * @return int Unix timestamp of the new date
549 */
550 function getNextMonth($current, $start, $interval_multiplier)
551 {
552 // For most days in the month, it's pretty easy. Get the day of month of the starting date.
553 $startDay = date("j", $start);
554
555 // If it's before or on the 28th, just jump the number of months and be done with it.
556 if ($startDay <= 28) {
557 return strtotime($interval_multiplier . " month", $current);
558 }
559
560 // If it's on the 29th, 30th, or 31st, it gets tricky. Some months don't have those days - so on those
561 // months we need to repeat on the last day of the month instead, but we also need to jump back to the
562 // correct day the following month. Let's say we want to repeat something on the 31st every month: this
563 // is what we expect to see for a pattern:
564 //
565 // .
566 // .
567 // .
568 // December 31st
569 // January 31st
570 // February 28th
571 // March 31st
572 // April 30th
573 // .
574 // .
575 // .
576 //
577 // Unfortunately, PHP relative date handling isn't that smart (add "+1 month" to January 31st, and you
578 // end up in March), so we'll have to figure it out ourselves by figuring out how many days to jump instead.
579
580 // We'll need to calculate this for each interval and return the timestamp after the last jump.
581 $temp_current = $current;
582 for ($i = 0; $i < $interval_multiplier; $i ++) {
583 // The pattern for jumping will be different in each interval.
584 /** @noinspection PhpUnusedLocalVariableInspection */
585 $temp_pattern = "";
586
587 // Get the month number of the current date.
588 //$currentMonth = date("n", $temp_current);
589
590 // Get the number of days in the month of the current date.
591 $lastDayThisMonth = date("t", strtotime("this month", $temp_current));
592
593 // Get the number of days for the next month relative to the current date .
594 // Subtract 3 days from the next month to counter known month skipping bugs in PHP's relative date
595 // handling, that being the difference between the shortest possible month (non-leap February - 28 days)
596 // and the longest (Jan., Mar., May, Jul., Aug., Oct., Dec. - 31 days). This may be fixed in PHP 5.3.x
597 // but this should be backwards-compatible anyway.
598 $lastDayNextMonth = date("t", strtotime("-3 day next month", $temp_current));
599
600 // If the current month is longer than next month, follow this block
601 if ($lastDayThisMonth > $lastDayNextMonth) {
602 // If we're repeating on the last day of this month, jump the number of days next month
603 if ($startDay == $lastDayThisMonth) {
604 $temp_pattern = $lastDayNextMonth . " days";
605 }
606 // If the start day doesn't exist in the next month (i.e., no "31st" in June), jump the
607 // number of days next month plus the difference between the start day and the number of days this month
608 elseif ($startDay > $lastDayNextMonth) {
609 $temp_pattern = ($lastDayThisMonth + $lastDayNextMonth - $startDay) . " days";
610 } // Otherwise, jump ahead the number of days in this month
611 else {
612 $temp_pattern = $lastDayThisMonth . " days";
613 }
614 } // Or, if the current month is shorter than next month
615 elseif ($lastDayThisMonth < $lastDayNextMonth) {
616 // If the start day doesn't exist in this month (i.e., no "31st" in June), jump the
617 // number of days next month plus the difference between the start day and the number of days this month
618 if ($startDay >= $lastDayThisMonth) {
619 $temp_pattern = $startDay . " days";
620 } // Otherwise, jump ahead the number of days in this month
621 else {
622 $temp_pattern = $lastDayThisMonth . " days";
623 }
624 } // If the current month and next month are equally long, jumping by "1 month" is fine
625 else {
626 $temp_pattern = "1 month";
627 }
628
629 $temp_current = strtotime($temp_pattern, $temp_current);
630 }
631
632 return $temp_current;
633
634 }
635
636 /**
637 * Advances a date to the 'n'th weekday of the next month (eg., first Wednesday, third Monday, last Friday, etc.).
638 *
639 * NB: if $ordinal is set to '4' and $day is set to '7', it wil return the last day of the month.
640 *
641 * @param int $current UNIX timestamp of the date before incrementing
642 * @param int $ordinal Integer symbolizing the ordinal (0 - first, 1 - second, 2 - third, 3 - fourth, 4 - last)
643 * @param int $day Integers symbolizing the days of the week to repeat on
644 * (0 - Sunday, 1 - Monday, ..., 6 - Saturday, 7 - day).
645 *
646 * @return int Unix timestamp of the new date
647 */
648 function getNthWeekdayOfMonth($current, $ordinal, $day)
649 {
650 // First, get the month/year we need to work with
651 $the_month = date("F", $current);
652 $the_year = date("Y", $current);
653 $lastDayThisMonth = date("t", $current);
654
655 // Get the time for the $current timestamp
656 $current_time = date("g:i A", $current);
657 $the_day = "";
658
659 if ($day == 7) { // If $day is "day of the month", get the day of month based on the ordinal
660 switch ($ordinal) {
661 case 0 :
662 $the_day = "1";
663 break; // First day of the month //
664 case 1 :
665 $the_day = "2";
666 break; // Second day of the month //
667 case 2 :
668 $the_day = "3";
669 break; // Third day of the month //
670 case 3 :
671 $the_day = "4";
672 break; // Fourth day of the month //
673 case 4 :
674 $the_day = $lastDayThisMonth;
675 break; // Last day of the month //
676 default :
677 $the_day = "1";
678 break;
679 }
680 } else { // If $day is one of the days of the week...
681 $day_range = array();
682 switch ($ordinal) { // ...get a 7-day range based on the ordinal...
683 case 0 :
684 $day_range = range(1, 7);
685 break; // First 7 days of the month //
686 case 1 :
687 $day_range = range(8, 14);
688 break; // Second 7 days of the month //
689 case 2 :
690 $day_range = range(15, 21);
691 break; // Third 7 days of the month //
692 case 3 :
693 $day_range = range(22, 28);
694 break; // Fourth 7 days of the month //
695 case 4 :
696 $day_range = range($lastDayThisMonth - 6, $lastDayThisMonth);
697 break; // Last 7 days of the month //
698 default :
699 $day_range = range(1, 7);
700 break;
701 }
702 foreach ($day_range as $a_day) { // ...and find the matching weekday in that range.
703 if ($day == date("w", strtotime($the_month . " " . $a_day . ", " . $the_year))) {
704 $the_day = $a_day;
705 break;
706 }
707 }
708 }
709
710 // Build the date string for the correct day and return its timestamp
711 $pattern = $the_month . " " . $the_day . ", " . $the_year . ", " . $current_time;
712
713 return strtotime($pattern);
714
715 }
716
717 /**
718 * Advances a date by a set number of years
719 *
720 * @param int $current UNIX timestamp of the date before incrementing
721 * @param int $interval_multiplier Number of years to advance
722 *
723 * @return int Unix timestamp of the new date
724 */
725 function getNextYear($current, $interval_multiplier)
726 {
727 return strtotime($interval_multiplier . " year", $current);
728 }
729
730 /**
731 * Validates the various Timed Content Rule parameters and returns a series of error messages.
732 *
733 * @param $args Array of Timed Content Rule parameters
734 *
735 * @return array Array of error messages
736 */
737 function validate($args)
738 {
739 $errors = array();
740
741 $instance_start = DateTime::createFromFormat('Y-m-d', $args['instance_start']['date']);
742 if($instance_start != false) {
743 $instance_start = $instance_start->getTimestamp();
744 }
745 $instance_end= DateTime::createFromFormat('Y-m-d', $args['instance_end']['date']);
746 if($instance_end != false) {
747 $instance_end = $instance_end->getTimestamp();
748 }
749 $end_date = DateTime::createFromFormat('Y-m-d', $args['end_date']);
750 if($end_date != false) {
751 $end_date = $end_date->getTimestamp();
752 }
753
754 if ($args['instance_start']['date'] == "") {
755 $errors[] = __("Starting date must not be empty.", 'timed-content');
756 }
757 if ($args['instance_start']['time'] == "") {
758 $errors[] = __("Starting time must not be empty.", 'timed-content');
759 }
760 if ($args['instance_end']['date'] == "") {
761 $errors[] = __("Ending date must not be empty.", 'timed-content');
762 }
763 if ($args['instance_end']['time'] == "") {
764 $errors[] = __("Ending time must not be empty.", 'timed-content');
765 }
766 if ($args['interval_multiplier'] == "") {
767 $errors[] = __("Interval must not be empty.", 'timed-content');
768 }
769 if (!is_numeric($args['interval_multiplier'])) {
770 $errors[] = __("Number of recurrences must be a number.", 'timed-content');
771 }
772 if (($args['num_repeat'] == "") && ($args['recurr_type'] == "recurrence_duration_num_repeat")) {
773 $errors[] = __("Number of repetitions must not be empty.", 'timed-content');
774 }
775 if ((!is_numeric($args['num_repeat'])) && ($args['recurr_type'] == "recurrence_duration_num_repeat")) {
776 $errors[] = __("Number of repetitions must be a number.", 'timed-content');
777 }
778 if (($args['end_date'] == "") && ($args['recurr_type'] == "recurrence_duration_end_date")) {
779 $errors[] = __("End date must not be empty.", 'timed-content');
780 }
781 if (false === $args['instance_start']) {
782 $errors[] = __("Starting date/time must be valid.", 'timed-content');
783 }
784 if (false === $args['instance_end']) {
785 $errors[] = __("Ending date/time must be valid.", 'timed-content');
786 }
787 if ($instance_start > $instance_end) {
788 $errors[] = __("Starting date/time must be before ending date/time.", 'timed-content');
789 }
790 if (($instance_end > $end_date) && ($args['recurr_type'] == "recurrence_duration_end_date")) {
791 $errors[] = __("Recurrence end date must be after ending date/time.", 'timed-content');
792 }
793
794 return $errors;
795 }
796
797 /**
798 * Calculates the active periods for a Timed Content Rule
799 *
800 * @param $args Array of Timed Content Rule parameters
801 *
802 * @return array Array of active periods. Each value in the array describes an active period as an array itself
803 * with "start" and "end" keys and values that are either UNIX timestamps or human-readable dates,
804 * based on whether $args['human_readable'] is set to true or false.
805 */
806 function getRulePeriods($args)
807 {
808 global $post;
809
810 $active_periods = array();
811 $period_count = 0;
812
813 $human_readable = $args['human_readable'];
814 $freq = $args['freq'];
815 $timezone = $args['timezone'];
816 $recurr_type = $args['recurr_type'];
817 $num_repeat = intval($args['num_repeat']);
818 $end_date = $args['end_date'];
819 $days_of_week = $args['days_of_week'];
820 $interval_multiplier = $args['interval_multiplier'];
821 $instance_start_date = $args['instance_start']['date'];
822 $instance_start_time = $args['instance_start']['time'];
823 $instance_end_date = $args['instance_end']['date'];
824 $instance_end_time = $args['instance_end']['time'];
825 $monthly_pattern = $args['monthly_pattern'];
826 $monthly_pattern_ord = $args['monthly_pattern_ord'];
827 $monthly_pattern_day = $args['monthly_pattern_day'];
828 $exceptions_dates = $args['exceptions_dates'];
829
830 add_filter('date_i18n', array(&$this, "fix_date_i18n"), 10, 4);
831 $temp_tz = date_default_timezone_get();
832 date_default_timezone_set($timezone);
833 $right_now_t = current_time('timestamp', 1);
834
835 // use debug parameter if current user is allowed to edit the post
836 if (isset($_GET['tctest']) && !empty($post) && current_user_can("edit_post", $post->post_id)) {
837 $dt = DateTime::createFromFormat('Y-m-d H:i:s', $_GET['tctest']);
838 if ($dt != false) {
839 $right_now_t = $dt->getTimestamp();
840 }
841 }
842
843 $instance_start = strtotime($this->datetimeToEnglish($instance_start_date,
844 $instance_start_time) . " " . $timezone); // Beginning of first occurrence
845 $instance_end = strtotime($this->datetimeToEnglish($instance_end_date,
846 $instance_end_time) . " " . $timezone); // End of first occurrence
847 $current = $instance_start;
848 $end_current = $instance_end;
849
850 if ($recurr_type == "recurrence_duration_num_repeat") {
851 $last_occurrence_start = strtotime(TIMED_CONTENT_TIME_END);
852 } else {
853 $last_occurrence_start = strtotime($this->datetimeToEnglish($end_date,
854 $instance_start_time) . " " . $timezone);
855 }
856
857 if ($recurr_type == "recurrence_duration_end_date") {
858 $loop_test = "return (\$current <= \$last_occurrence_start);";
859 } else {
860 $loop_test = "return (\$period_count < \$num_repeat);";
861 }
862
863 while (eval ($loop_test)) {
864 $exception_period = false;
865 $current_date = date('Y-m-d', $current);
866 if (is_array($exceptions_dates)) {
867 foreach ($exceptions_dates as $exceptions_date) {
868 if (is_numeric($exceptions_date)) {
869 $exceptions_date = date('Y-m-d', $exceptions_date);
870 }
871 if ($current_date === $exceptions_date) {
872 $exception_period = true;
873 break;
874 }
875 }
876 }
877
878 if ((eval ($loop_test)) && (!($exception_period))) {
879 $end_current = $current + ($instance_end - $instance_start);
880 if ($human_readable == true) {
881 $active_periods[ $period_count ]["start"] = date_i18n(TIMED_CONTENT_DATE_FORMAT_OUTPUT, $current);
882 $active_periods[ $period_count ]["end"] = date_i18n(TIMED_CONTENT_DATE_FORMAT_OUTPUT, $end_current);
883 if ($right_now_t < $current) {
884 $active_periods[ $period_count ]["status"] = "upcoming";
885 $active_periods[ $period_count ]["time"] = sprintf(_x('%s from now.',
886 'Human readable time difference', 'timed-content'),
887 human_time_diff($current, $right_now_t));
888 } elseif (($current <= $right_now_t) && ($right_now_t <= $end_current)) {
889 $active_periods[ $period_count ]["status"] = "active";
890 $active_periods[ $period_count ]["time"] = __("Right now!", 'timed-content');
891 } else {
892 $active_periods[ $period_count ]["status"] = "expired";
893 $active_periods[ $period_count ]["time"] = sprintf(_x('%s ago.',
894 'Human readable time difference', 'timed-content'),
895 human_time_diff($end_current, $right_now_t));
896 }
897 } else {
898 $active_periods[ $period_count ]["start"] = $current;
899 $active_periods[ $period_count ]["end"] = $end_current;
900 }
901 if (!($exception_period)) {
902 $period_count ++;
903 }
904 }
905
906 if ($freq == 0) {
907 $current = $this->getNextHour($current, $interval_multiplier);
908 } elseif ($freq == 1) {
909 $current = $this->getNextDay($current, $interval_multiplier);
910 } elseif ($freq == 2) {
911 $current = $this->getNextWeek($current, $interval_multiplier, $days_of_week);
912 } elseif ($freq == 3) {
913 $current = $this->getNextMonth($current, $instance_start, $interval_multiplier);
914 $temp_current = $current;
915 if ($monthly_pattern == "yes") {
916 $current = $this->getNthWeekdayOfMonth($current, $monthly_pattern_ord,
917 $monthly_pattern_day);
918 } else {
919 $current = $temp_current;
920 }
921 } elseif ($freq == 4) {
922 $current = $this->getNextYear($current, $interval_multiplier);
923 }
924 }
925 date_default_timezone_set($temp_tz);
926 remove_filter('date_i18n', array(&$this, "fix_date_i18n"), 10, 4);
927
928 return $active_periods;
929 }
930
931 /**
932 * Wrapper for calling timedContentPlugin::__getRulePeriods() by the ID of a Timed Content Rule
933 *
934 * @param int $ID ID of the Timed Content Rule
935 * @param bool $human_readable If true, the active periods are returned as a human-readable date
936 * as defined by the constant TIMED_CONTENT_DT_FORMAT_OUTPUT otherwise,
937 * they are returned as UNIX timestamps.
938 *
939 * @return array Array of active periods
940 */
941 function getRulePeriodsById($ID, $human_readable = false)
942 {
943 if (TIMED_CONTENT_RULE_TYPE != get_post_type($ID)) {
944 return array();
945 }
946
947 $prefix = TIMED_CONTENT_RULE_POSTMETA_PREFIX;
948 $args = array();
949
950 $args['human_readable'] = (bool) $human_readable;
951 $args['freq'] = get_post_meta($ID, $prefix . 'frequency', true);
952 $args['timezone'] = get_post_meta($ID, $prefix . 'timezone', true);
953 $args['recurr_type'] = get_post_meta($ID, $prefix . 'recurrence_duration', true);
954 $args['num_repeat'] = get_post_meta($ID, $prefix . 'recurrence_duration_num_repeat', true);
955 $args['end_date'] = get_post_meta($ID, $prefix . 'recurrence_duration_end_date', true);
956 $args['days_of_week'] = get_post_meta($ID, $prefix . 'weekly_days_of_week_to_repeat', true);
957 if ($args['freq'] == 0) {
958 $args['interval_multiplier'] = get_post_meta($ID, $prefix . 'hourly_num_of_hours', true);
959 }
960 if ($args['freq'] == 1) {
961 $args['interval_multiplier'] = get_post_meta($ID, $prefix . 'daily_num_of_days', true);
962 }
963 if ($args['freq'] == 2) {
964 $args['interval_multiplier'] = get_post_meta($ID, $prefix . 'weekly_num_of_weeks', true);
965 }
966 if ($args['freq'] == 3) {
967 $args['interval_multiplier'] = get_post_meta($ID, $prefix . 'monthly_num_of_months', true);
968 }
969 if ($args['freq'] == 4) {
970 $args['interval_multiplier'] = get_post_meta($ID, $prefix . 'yearly_num_of_years', true);
971 }
972 $args['instance_start'] = get_post_meta($ID, $prefix . 'instance_start', true);
973 $args['instance_end'] = get_post_meta($ID, $prefix . 'instance_end', true);
974 $args['monthly_pattern'] = get_post_meta($ID, $prefix . 'monthly_nth_weekday_of_month', true);
975 $args['monthly_pattern_ord'] = get_post_meta($ID, $prefix . 'monthly_nth_weekday_of_month_nth', true);
976 $args['monthly_pattern_day'] = get_post_meta($ID, $prefix . 'monthly_nth_weekday_of_month_weekday', true);
977
978 $exceptions_dates = get_post_meta($ID, $prefix . 'exceptions_dates');
979 if (false !== $exceptions_dates && isset($exceptions_dates[0]) && is_array($exceptions_dates[0])) {
980 $args['exceptions_dates'] = $exceptions_dates[0];
981 } else {
982 $args['exceptions_dates'] = false;
983 }
984
985 $args = $this->convertDateTimeParametersToISO($args);
986
987 return $this->getRulePeriods($args);
988 }
989
990 /**
991 * Wrapper for calling timedContentPlugin::__getRulePeriods() based on the contents of the form fields
992 * of the Add Timed Content Rule and Edit Timed Content Rule screens. Output is sent to output as JSON
993 */
994 function timedContentPluginGetRulePeriodsAjax()
995 {
996 if (current_user_can('edit_posts') || current_user_can('edit_pages')) {
997 $prefix = TIMED_CONTENT_RULE_POSTMETA_PREFIX;
998 $args = array();
999
1000 $args['human_readable'] = (((isset($_POST[ $prefix . 'human_readable' ])) && ($_POST[ $prefix . 'human_readable' ] == 'true')) ? (bool) $_POST[ $prefix . 'human_readable' ] : false);
1001 $args['freq'] = $_POST[ $prefix . 'frequency' ];
1002 $args['timezone'] = $_POST[ $prefix . 'timezone' ];
1003 $args['recurr_type'] = $_POST[ $prefix . 'recurrence_duration' ];
1004 $args['num_repeat'] = $_POST[ $prefix . 'recurrence_duration_num_repeat' ];
1005 $args['end_date'] = $_POST[ $prefix . 'recurrence_duration_end_date' ];
1006 $args['days_of_week'] = (isset($_POST[ $prefix . 'weekly_days_of_week_to_repeat' ]) ? $_POST[ $prefix . 'weekly_days_of_week_to_repeat' ] : array());
1007 $args['interval_multiplier'] = $_POST[ $prefix . 'interval_multiplier' ];
1008 $args['instance_start'] = $_POST[ $prefix . 'instance_start' ];
1009 $args['instance_end'] = $_POST[ $prefix . 'instance_end' ];
1010 $args['monthly_pattern'] = $_POST[ $prefix . 'monthly_nth_weekday_of_month' ];
1011 $args['monthly_pattern_ord'] = $_POST[ $prefix . 'monthly_nth_weekday_of_month_nth' ];
1012 $args['monthly_pattern_day'] = $_POST[ $prefix . 'monthly_nth_weekday_of_month_weekday' ];
1013 $args['exceptions_dates'] = (isset($_POST[ $prefix . 'exceptions_dates' ]) ? $_POST[ $prefix . 'exceptions_dates' ] : array());
1014
1015 $response = json_encode($this->getRulePeriods($args));
1016
1017 // response output
1018 header("Content-Type: application/json");
1019 echo $response;
1020 }
1021 die();
1022
1023 }
1024
1025 /**
1026 * Returns a human-readable description of a Timed Content Rule
1027 *
1028 * @param $args Array of Timed Content Rule parameters
1029 *
1030 * @return string Schedule description or warning, if the rule may not work properly
1031 */
1032 function getScheduleDescription($args)
1033 {
1034 $interval_multiplier = 1;
1035 $desc = "";
1036
1037 $errors = $this->validate($args);
1038 if ($errors) {
1039 $messages = "<div class=\"tcr-warning\">\n";
1040 $messages .= "<p class=\"heading\">" . __("Warning!", 'timed-content') . "</p>\n";
1041 $messages .= "<p>" . __("Some problems have been detected. Although you can still publish this rule, it may not work the way you expect.", 'timed-content') . "</p>\n";
1042 $messages .= "<ul>\n";
1043 foreach ($errors as $error) {
1044 $messages .= " <li>" . $error . "</li>\n";
1045 }
1046 $messages .= "</ul>\n";
1047 $messages .= "<p>" . __("Check that all of the conditions for this rule are correct, and use <b>Show projected dates/times</b> to ensure your rule is working properly.", 'timed-content') . "</p>\n";
1048 $messages .= "</div>\n";
1049
1050 return $messages;
1051 }
1052
1053 if ($args['action']) {
1054 $action = __("Show the content", 'timed-content');
1055 } else {
1056 $action = __("Hide the content", 'timed-content');
1057 }
1058 $freq = $args['freq'];
1059 $timezone = $args['timezone'];
1060 $recurr_type = $args['recurr_type'];
1061 $num_repeat = intval($args['num_repeat']);
1062 $end_date = $args['end_date'];
1063 $days_of_week = $args['days_of_week'];
1064 $interval_multiplier = $args['interval_multiplier'];
1065 $instance_start_date = $args['instance_start']['date'];
1066 $instance_start_time = $args['instance_start']['time'];
1067 $instance_end_date = $args['instance_end']['date'];
1068 $instance_end_time = $args['instance_end']['time'];
1069 $monthly_pattern = $args['monthly_pattern'];
1070 $monthly_pattern_ord = $args['monthly_pattern_ord'];
1071 $monthly_pattern_day = $args['monthly_pattern_day'];
1072 $exceptions_dates = $args['exceptions_dates'];
1073
1074 $desc = sprintf(_x('%1$s on %2$s @ %3$s until %4$s @ %5$s.',
1075 'Perform action (%1$s) from date/time of first active period (%2$s @ %3$s) until date/time of last active period (%4$s @ %5$s).',
1076 'timed-content'), $action, $instance_start_date, $instance_start_time, $instance_end_date,
1077 $instance_end_time);
1078
1079 if ($freq == 0) {
1080 $desc .= "<br />" . sprintf(_n('Repeat this action every hour.', 'Repeat this action every %d hours.',
1081 $interval_multiplier, 'timed-content'), $interval_multiplier);
1082 } elseif ($freq == 1) {
1083 $desc .= "<br />" . sprintf(_n('Repeat this action every day.', 'Repeat this action every %d days.',
1084 $interval_multiplier, 'timed-content'), $interval_multiplier);
1085 } elseif ($freq == 2) {
1086 if (($days_of_week) && (is_array($days_of_week))) {
1087 $days = array();
1088 $days_list = "";
1089 foreach ($days_of_week as $v) {
1090 $days[] = $this->rule_days_array[ $v ];
1091 }
1092 switch (count($days)) {
1093 case 1:
1094 $days_list = sprintf(_x('%1$s', 'List of one weekday', 'timed-content'), $days[0]);
1095 break;
1096 case 2:
1097 $days_list = sprintf(_x('%1$s and %2$s', 'List of two weekdays', 'timed-content'),
1098 $days[0], $days[1]);
1099 break;
1100 case 3:
1101 $days_list = sprintf(_x('%1$s, %2$s and %3$s', 'List of three weekdays',
1102 'timed-content'), $days[0], $days[1], $days[2]);
1103 break;
1104 case 4:
1105 $days_list = sprintf(_x('%1$s, %2$s, %3$s and %4$s', 'List of four weekdays',
1106 'timed-content'), $days[0], $days[1], $days[2], $days[3]);
1107 break;
1108 case 5:
1109 $days_list = sprintf(_x('%1$s, %2$s, %3$s, %4$s and %5$s', 'List of five weekdays',
1110 'timed-content'), $days[0], $days[1], $days[2], $days[3], $days[4]);
1111 break;
1112 case 6:
1113 $days_list = sprintf(_x('%1$s, %2$s, %3$s, %4$s, %5$s and %6$s', 'List of six weekdays',
1114 'timed-content'), $days[0], $days[1], $days[2], $days[3], $days[4], $days[5]);
1115 break;
1116 case 7:
1117 $days_list = sprintf(_x('%1$s, %2$s, %3$s, %4$s, %5$s, %6$s and %7$s',
1118 'List of all weekdays', 'timed-content'), $days[0], $days[1], $days[2], $days[3],
1119 $days[4], $days[5], $days[6]);
1120 break;
1121 }
1122 if ($interval_multiplier == 1) {
1123 $desc .= "<br />" . sprintf(_x('Repeat this action every week on %s.',
1124 'List the weekdays to repeat the rule when frequency is every week. %s is the list of weekdays.',
1125 'timed-content'), $days_list);
1126 } else {
1127 $desc .= "<br />" . sprintf(_x('Repeat this action every %1$d weeks on %2$s.',
1128 'List the weekdays to repeat the rule when frequency is every %1$d weeks. %2$s is the list of weekdays.',
1129 'timed-content'), $interval_multiplier, $days_list);
1130 }
1131 } else {
1132 $desc .= "<br />" . sprintf(_n('Repeat this action every week.',
1133 'Repeat this action every %d weeks.', $interval_multiplier, 'timed-content'),
1134 $interval_multiplier);
1135 }
1136
1137 } elseif ($freq == 3) {
1138 if ($monthly_pattern == "yes") {
1139 if ($interval_multiplier == 1) {
1140 $desc .= "<br />" . sprintf(_x('Repeat this action every month on the %1$s %2$s of the month.',
1141 "Example: 'Repeat this action every month on the second Friday of the month.'",
1142 'timed-content'), $this->rule_ordinal_array[ $monthly_pattern_ord ],
1143 $this->rule_ordinal_days_array[ $monthly_pattern_day ]);
1144 } else {
1145 $desc .= "<br />" . sprintf(_x('Repeat this action every %1$d months on the %2$s %3$s of the month.',
1146 "Example: 'Repeat this action every 2 months on the second Friday of the month.'",
1147 'timed-content'), $interval_multiplier,
1148 $this->rule_ordinal_array[ $monthly_pattern_ord ],
1149 $this->rule_ordinal_days_array[ $monthly_pattern_day ]);
1150 }
1151 } else {
1152 $desc .= "<br />" . sprintf(_n('Repeat this action every month.',
1153 'Repeat this action every %d months.', $interval_multiplier, 'timed-content'),
1154 $interval_multiplier);
1155 }
1156 } elseif ($freq == 4) {
1157 $desc .= "<br />" . sprintf(_n('Repeat this action every year.', 'Repeat this action every %d years.',
1158 $interval_multiplier, 'timed-content'), $interval_multiplier);
1159 }
1160
1161 if ($recurr_type == "recurrence_duration_num_repeat") {
1162 $desc .= "<br />" . sprintf(_n('This rule will be active for one recurrence.',
1163 'This rule will be active for %d recurrences.', $num_repeat, 'timed-content'), $num_repeat);
1164 } elseif ($recurr_type == "recurrence_duration_end_date") {
1165 $desc .= "<br />" . sprintf(__('This rule will be active until %s.', 'timed-content'), $end_date);
1166 }
1167
1168 if (($exceptions_dates) && (is_array($exceptions_dates))) {
1169 sort($exceptions_dates, SORT_NUMERIC);
1170 $exceptions_dates = array_unique($exceptions_dates);
1171 if ($exceptions_dates[0] == 0) {
1172 array_shift($exceptions_dates);
1173 }
1174 if (!empty($exceptions_dates)) {
1175 $desc .= "<br />" . sprintf(__('This rule will be inactive on the following dates: %s.',
1176 'timed-content'), join(", ", $exceptions_dates));
1177 }
1178 }
1179
1180 $desc .= "<br />" . sprintf(__('All times are in the %s timezone.', 'timed-content'), $timezone);
1181
1182 return $desc;
1183 }
1184
1185 /**
1186 * Wrapper for calling timedContentPlugin::__getScheduleDescription() by the ID of a Timed Content Rule
1187 *
1188 * @param int $ID ID of the Timed Content Rule
1189 *
1190 * @return string
1191 */
1192 function getScheduleDescriptionById($ID)
1193 {
1194 $defaults = array();
1195
1196 foreach ($this->rule_occurrence_custom_fields as $field) {
1197 $defaults[ $field['name'] ] = $field['default'];
1198 }
1199 foreach ($this->rule_pattern_custom_fields as $field) {
1200 $defaults[ $field['name'] ] = $field['default'];
1201 }
1202 foreach ($this->rule_recurrence_custom_fields as $field) {
1203 $defaults[ $field['name'] ] = $field['default'];
1204 }
1205 foreach ($this->rule_exceptions_custom_fields as $field) {
1206 $defaults[ $field['name'] ] = $field['default'];
1207 }
1208
1209 $prefix = TIMED_CONTENT_RULE_POSTMETA_PREFIX;
1210 $args = array();
1211
1212 $args['action'] = (false === get_post_meta($ID, $prefix . 'action',
1213 true) ? $defaults['action'] : get_post_meta($ID, $prefix . 'action', true));
1214 $args['freq'] = (false === get_post_meta($ID, $prefix . 'frequency',
1215 true) ? $defaults['frequency'] : get_post_meta($ID, $prefix . 'frequency', true));
1216 $args['timezone'] = (false === get_post_meta($ID, $prefix . 'timezone',
1217 true) ? $defaults['timezone'] : get_post_meta($ID, $prefix . 'timezone', true));
1218 $args['recurr_type'] = (false === get_post_meta($ID, $prefix . 'recurrence_duration',
1219 true) ? $defaults['recurrence_duration'] : get_post_meta($ID, $prefix . 'recurrence_duration',
1220 true));
1221 $args['num_repeat'] = (false === get_post_meta($ID, $prefix . 'recurrence_duration_num_repeat',
1222 true) ? $defaults['recurrence_duration_num_repeat'] : get_post_meta($ID,
1223 $prefix . 'recurrence_duration_num_repeat', true));
1224 $args['end_date'] = (false === get_post_meta($ID, $prefix . 'recurrence_duration_end_date',
1225 true) ? $defaults['recurrence_duration_end_date'] : get_post_meta($ID,
1226 $prefix . 'recurrence_duration_end_date', true));
1227 $args['days_of_week'] = (false === get_post_meta($ID, $prefix . 'weekly_days_of_week_to_repeat',
1228 true) ? $defaults['weekly_days_of_week_to_repeat'] : get_post_meta($ID,
1229 $prefix . 'weekly_days_of_week_to_repeat', true));
1230 if ($args['freq'] == 0) {
1231 $args['interval_multiplier'] = (false === get_post_meta($ID, $prefix . 'hourly_num_of_hours',
1232 true) ? $defaults['hourly_num_of_hours'] : get_post_meta($ID, $prefix . 'hourly_num_of_hours',
1233 true));
1234 }
1235 if ($args['freq'] == 1) {
1236 $args['interval_multiplier'] = (false === get_post_meta($ID, $prefix . 'daily_num_of_days',
1237 true) ? $defaults['daily_num_of_days'] : get_post_meta($ID, $prefix . 'daily_num_of_days',
1238 true));
1239 }
1240 if ($args['freq'] == 2) {
1241 $args['interval_multiplier'] = (false === get_post_meta($ID, $prefix . 'weekly_num_of_weeks',
1242 true) ? $defaults['weekly_num_of_weeks'] : get_post_meta($ID, $prefix . 'weekly_num_of_weeks',
1243 true));
1244 }
1245 if ($args['freq'] == 3) {
1246 $args['interval_multiplier'] = (false === get_post_meta($ID, $prefix . 'monthly_num_of_months',
1247 true) ? $defaults['monthly_num_of_months'] : get_post_meta($ID, $prefix . 'monthly_num_of_months',
1248 true));
1249 }
1250 if ($args['freq'] == 4) {
1251 $args['interval_multiplier'] = (false === get_post_meta($ID, $prefix . 'yearly_num_of_years',
1252 true) ? $defaults['yearly_num_of_years'] : get_post_meta($ID, $prefix . 'yearly_num_of_years',
1253 true));
1254 }
1255 $args['instance_start'] = (false === get_post_meta($ID, $prefix . 'instance_start',
1256 true) ? $defaults['instance_start'] : get_post_meta($ID, $prefix . 'instance_start', true));
1257 $args['instance_end'] = (false === get_post_meta($ID, $prefix . 'instance_end',
1258 true) ? $defaults['instance_end'] : get_post_meta($ID, $prefix . 'instance_end', true));
1259 $args['monthly_pattern'] = (false === get_post_meta($ID, $prefix . 'monthly_nth_weekday_of_month',
1260 true) ? $defaults['monthly_nth_weekday_of_month'] : get_post_meta($ID,
1261 $prefix . 'monthly_nth_weekday_of_month', true));
1262 $args['monthly_pattern_ord'] = (false === get_post_meta($ID, $prefix . 'monthly_nth_weekday_of_month_nth',
1263 true) ? $defaults['monthly_nth_weekday_of_month_nth'] : get_post_meta($ID,
1264 $prefix . 'monthly_nth_weekday_of_month_nth', true));
1265 $args['monthly_pattern_day'] = (false === get_post_meta($ID,
1266 $prefix . 'monthly_nth_weekday_of_month_weekday',
1267 true) ? $defaults['monthly_nth_weekday_of_month_weekday'] : get_post_meta($ID,
1268 $prefix . 'monthly_nth_weekday_of_month_weekday', true));
1269 $exceptions_dates = get_post_meta($ID, $prefix . 'exceptions_dates');
1270 if (false !== $exceptions_dates && isset($exceptions_dates[0]) && is_array($exceptions_dates[0])) {
1271 $args['exceptions_dates'] = $exceptions_dates[0];
1272 } else {
1273 $args['exceptions_dates'] = $defaults['exceptions_dates'];
1274 }
1275
1276 $args = $this->convertDateTimeParametersToISO($args);
1277
1278 return $this->getScheduleDescription($args);
1279 }
1280
1281 /**
1282 * Wrapper for calling timedContentPlugin::__getRulePeriods() based on the contents of the form fields
1283 * of the Add Timed Content Rule and Edit Timed Content Rule screens. Output is sent to output as plain text
1284 */
1285 function timedContentPluginGetScheduleDescriptionAjax()
1286 {
1287 if (current_user_can('edit_posts') || current_user_can('edit_pages')) {
1288 $prefix = TIMED_CONTENT_RULE_POSTMETA_PREFIX;
1289 $args = array();
1290
1291 $args['action'] = $_POST[ $prefix . 'action' ];
1292 $args['freq'] = $_POST[ $prefix . 'frequency' ];
1293 $args['timezone'] = $_POST[ $prefix . 'timezone' ];
1294 $args['recurr_type'] = $_POST[ $prefix . 'recurrence_duration' ];
1295 $args['num_repeat'] = $_POST[ $prefix . 'recurrence_duration_num_repeat' ];
1296 $args['end_date'] = $_POST[ $prefix . 'recurrence_duration_end_date' ];
1297 $args['days_of_week'] = (isset($_POST[ $prefix . 'weekly_days_of_week_to_repeat' ]) ? $_POST[ $prefix . 'weekly_days_of_week_to_repeat' ] : array());
1298 $args['interval_multiplier'] = $_POST[ $prefix . 'interval_multiplier' ];
1299 $args['instance_start'] = $_POST[ $prefix . 'instance_start' ];
1300 $args['instance_end'] = $_POST[ $prefix . 'instance_end' ];
1301 $args['monthly_pattern'] = $_POST[ $prefix . 'monthly_nth_weekday_of_month' ];
1302 $args['monthly_pattern_ord'] = $_POST[ $prefix . 'monthly_nth_weekday_of_month_nth' ];
1303 $args['monthly_pattern_day'] = $_POST[ $prefix . 'monthly_nth_weekday_of_month_weekday' ];
1304 $args['exceptions_dates'] = (isset($_POST[ $prefix . 'exceptions_dates' ]) ? $_POST[ $prefix . 'exceptions_dates' ] : array());
1305
1306 $response = $this->getScheduleDescription($args);
1307
1308 // response output
1309 header("Content-Type: text/plain");
1310 echo $response;
1311 }
1312 die();
1313 }
1314
1315 /**
1316 * Processes the [timed-content-client] shortcode.
1317 *
1318 * @param array $atts Shortcode attributes
1319 * @param null $content Content inside the shortcode
1320 *
1321 * @return string Processed output
1322 */
1323 function clientShowHTML($atts, $content = null)
1324 {
1325 $show_attr = "";
1326 $hide_attr = "";
1327 extract(shortcode_atts(array('show' => '0:00:000', 'hide' => '0:00:000', 'display' => 'div'), $atts));
1328
1329 // Initialize show/hide arguments
1330 $s_min = 0;
1331 $s_sec = 0;
1332 $s_fade = 0;
1333 $h_min = 0;
1334 $h_sec = 0;
1335 $h_fade = 0;
1336 @list($s_min, $s_sec, $s_fade) = explode(":", $show);
1337 @list($h_min, $h_sec, $h_fade) = explode(":", $hide);
1338
1339 if (((int) $s_min + (int) $s_sec) > 0) {
1340 $show_attr = "_show_" . $s_min . "_" . $s_sec . "_" . $s_fade;
1341 }
1342 if (((int) $h_min + (int) $h_sec) > 0) {
1343 $hide_attr = "_hide_" . $h_min . "_" . $h_sec . "_" . $h_fade;
1344 }
1345
1346 $the_class = TIMED_CONTENT_SHORTCODE_CLIENT . $show_attr . $hide_attr;
1347 $the_tag = ($display == "div" ? "div" : "span");
1348
1349 $the_filter = "timed_content_filter";
1350 $the_filter = apply_filters("timed_content_filter_override", $the_filter);
1351
1352 $the_HTML = "<"
1353 . $the_tag
1354 . " class='"
1355 . $the_class
1356 . "'"
1357 . (($show_attr != "") ? " style='display: none;'" : "") . ">"
1358 . str_replace(']]>', ']]&gt;', apply_filters($the_filter, $content))
1359 . "</" . $the_tag . ">";
1360
1361 return $the_HTML;
1362 }
1363
1364 /**
1365 * Processes the [timed-content-server] shortcode.
1366 *
1367 * @param array $atts Shortcode attributes
1368 * @param null $content Content inside the shortcode
1369 *
1370 * @return string Processed output
1371 */
1372 function serverShowHTML($atts, $content = null)
1373 {
1374 global $post;
1375
1376 extract(shortcode_atts(array(
1377 'show' => 0,
1378 'hide' => 0,
1379 'debug' => 'false'
1380 ), $atts));
1381
1382 // Get time and timezone object for "show" time
1383 $pos = strrpos($show, ' ');
1384 if ($pos !== false) {
1385 $show_time = substr($show, 0, $pos);
1386 $show_tzname = substr($show, $pos + 1);
1387 } else {
1388 $show_time = $show;
1389 $show_tzname = date_default_timezone_get();
1390 }
1391 try {
1392 $show_tz = new DateTimeZone($show_tzname);
1393 } catch(Exception $e) {
1394 $show_tz = new DateTimeZone('UTC');
1395 }
1396
1397 // Create time and timezone object for "hide" time
1398 $pos = strrpos($hide, ' ');
1399 if ($pos !== false) {
1400 $hide_time = substr($hide, 0, $pos);
1401 $hide_tzname = substr($hide, $pos + 1);
1402 } else {
1403 $hide_time = $hide;
1404 $hide_tzname = date_default_timezone_get();
1405 }
1406 try {
1407 $hide_tz = new DateTimeZone($hide_tzname);
1408 } catch(Exception $e) {
1409 $hide_tz = new DateTimeZone('UTC');
1410 }
1411
1412 // Try to parse date as ISO first
1413 $show_dt = DateTime::createFromFormat('Y-m-d G:i', $show_time, $show_tz);
1414 // Fallback to American format
1415 if ($show_dt === false) {
1416 $show_dt = DateTime::createFromFormat('m/d/Y G:i', $show_time, $show_tz);
1417 }
1418
1419 if ($show_dt !== false) {
1420 $show_t = $show_dt->getTimeStamp();
1421 } else {
1422 // If nothing else worked so far, try strtotime()
1423 // as it was before version 2.50
1424 $show_t = strtotime($show);
1425 if($show_t === false) $show_t = 0;
1426 $show_dt = new DateTime();
1427 $show_dt->setTimeStamp($show_t);
1428 $show_dt->setTimezone($show_tz);
1429 }
1430
1431 // Try to parse date as ISO first
1432 $hide_dt = DateTime::createFromFormat('Y-m-d G:i', $hide_time, $hide_tz);
1433 if ($hide_dt === false) {
1434 $hide_dt = DateTime::createFromFormat('m/d/Y G:i', $hide_time, $hide_tz);
1435 }
1436 if ($hide_dt !== false) {
1437 $hide_t = $hide_dt->getTimeStamp();
1438 } else {
1439 // If nothing else worked so far, try strtotime()
1440 // as it was before version 2.50
1441 $hide_t = strtotime($hide);
1442 if($hide_t === false) $hide_t = 0;
1443 $hide_dt = new DateTime();
1444 $hide_dt->setTimeStamp($hide_t);
1445 $hide_dt->setTimezone($hide_tz);
1446 }
1447
1448 $right_now_t = current_time('timestamp', 1);
1449 $debug_message = "";
1450
1451 // use debug parameter if current user is allowed to edit the post
1452 if (isset($_GET['tctest']) && !empty($post) && current_user_can("edit_post", $post->post_id)) {
1453 $dt = DateTime::createFromFormat('Y-m-d H:i:s', $_GET['tctest']);
1454 if ($dt != false) {
1455 $right_now_t = $dt->getTimestamp();
1456 }
1457 }
1458
1459 $the_filter = "timed_content_filter";
1460 $the_filter = apply_filters("timed_content_filter_override", $the_filter);
1461
1462 $show_content = false;
1463 if (($show_t <= $right_now_t) && ($right_now_t <= $hide_t || $hide_t == 0)) {
1464 $show_content = true;
1465 }
1466
1467 if ((($debug == "true") || ((!$show_content) && ($debug == "when_hidden"))) && (!empty($post) && current_user_can("edit_post", $post->post_id))) {
1468 add_filter('date_i18n', array(&$this, "fix_date_i18n"), 10, 4);
1469 $temp_tz = date_default_timezone_get();
1470 date_default_timezone_set(get_option('timezone_string'));
1471
1472 $right_now = date_i18n(TIMED_CONTENT_DATE_FORMAT_OUTPUT, $right_now_t);
1473
1474 if ($show_t > $right_now_t) {
1475 $show_diff_str = sprintf(_x('%s from now.', 'Human readable time difference', 'timed-content'),
1476 human_time_diff($show_t, $right_now_t));
1477 } else {
1478 $show_diff_str = sprintf(_x('%s ago.', 'Human readable time difference', 'timed-content'),
1479 human_time_diff($show_t, $right_now_t));
1480 }
1481 if ($hide_t > $right_now_t) {
1482 $hide_diff_str = sprintf(_x('%s from now.', 'Human readable time difference', 'timed-content'),
1483 human_time_diff($hide_t, $right_now_t));
1484 } else {
1485 $hide_diff_str = sprintf(_x('%s ago.', 'Human readable time difference', 'timed-content'),
1486 human_time_diff($hide_t, $right_now_t));
1487 }
1488
1489 $debug_message = "<div class=\"tcr-warning\">\n";
1490 $debug_message .= "<p class=\"heading\">" . _x("Notice", "Noun", 'timed-content') . "</p>\n";
1491 $debug_message .= "<p>" . sprintf(__('Debugging has been turned on for a %1$s shortcode on this post/page. Only website users who are currently logged in and can edit this post/page will see this. To turn off this message, remove the %2$s attribute from the shortcode.',
1492 'timed-content'), "<code>[timed-content-server]</code>", "<code>debug</code>") . "</p>\n";
1493
1494 if ($show_t === 0) {
1495 $debug_message .= "<p>" . sprintf(__('The %s attribute is not set or invalid.', 'timed-content'),
1496 "<code>show</code>") . "</p>\n";
1497 } else {
1498 $debug_message .= "<p>" . sprintf(__('The %s attribute is currently set to', 'timed-content'),
1499 "<code>show</code>") . ": " . $show . ",<br />\n "
1500 . __('The Timed Content plugin thinks the intended date/time is',
1501 'timed-content') . ": " . $show_dt->format(TIMED_CONTENT_DATE_FORMAT_OUTPUT)
1502 . " (" . $show_diff_str . ")</p>\n";
1503 }
1504
1505 if ($hide === 0) {
1506 $debug_message .= "<p>" . sprintf(__('The %s attribute is not set or invalid.', 'timed-content'),
1507 "<code>hide</code>") . "</p>\n";
1508 } else {
1509 $debug_message .= "<p>" . sprintf(__('The %s attribute is currently set to', 'timed-content'),
1510 "<code>hide</code>") . ": " . $hide . ",<br />\n"
1511 . __('The Timed Content plugin thinks the intended date/time is',
1512 'timed-content') . ": " . $hide_dt->format(TIMED_CONTENT_DATE_FORMAT_OUTPUT)
1513 . " (" . $hide_diff_str . ").</p>\n";
1514 }
1515
1516 $debug_message .= "<p>" . __('Current date:',
1517 'timed-content') . "&nbsp;" . $right_now . "</p>\n";
1518 $debug_message .= "<p>" . __('Content filter:', 'timed-content') . "&nbsp;" . $the_filter . "</p>\n";
1519 $debug_message .= "<p>" . _x('Content:', "Noun", 'timed-content') . "</p><p>" . $content . "</p>\n";
1520
1521 if ($show_content === true) {
1522 $debug_message .= "<p>" . __('The plugin will show the content.', 'timed-content') . "</p>";
1523 } else {
1524 $debug_message .= "<p>" . __('The plugin will hide the content.', 'timed-content'). "</p>";
1525 }
1526
1527 $debug_message .= "</div>\n";
1528
1529 date_default_timezone_set($temp_tz);
1530 remove_filter('date_i18n', array(&$this, "fix_date_i18n"), 10, 4);
1531 }
1532
1533 if ($show_content === true) {
1534 if (!empty($post)) {
1535 do_action("timed_content_server_show", $post->ID, $show, $hide, $content);
1536 } else {
1537 do_action("timed_content_server_show", null, $show, $hide, $content);
1538 }
1539
1540 return $debug_message . str_replace(']]>', ']]&gt;', apply_filters($the_filter, $content)) . "\n";
1541 } else {
1542 if (!empty($post)) {
1543 do_action("timed_content_server_hide", $post->ID, $show, $hide, $content);
1544 } else {
1545 do_action("timed_content_server_show", null, $show, $hide, $content);
1546 }
1547
1548 return $debug_message . "\n";
1549 }
1550
1551 }
1552
1553 /**
1554 * Processes the [timed-content-rule] shortcode.
1555 *
1556 * @param array $atts Shortcode attributes
1557 * @param null $content Content inside the shortcode
1558 *
1559 * @return string Processed output
1560 */
1561 function rulesShowHTML($atts, $content = null)
1562 {
1563 global $post;
1564
1565 extract(shortcode_atts(array('id' => 0), $atts));
1566 if (!is_numeric($id)) {
1567 $page = get_page_by_title($id, OBJECT, TIMED_CONTENT_RULE_TYPE);
1568 if ($page == null) {
1569 return;
1570 }
1571 $id = $page->ID;
1572 }
1573 if (TIMED_CONTENT_RULE_TYPE != get_post_type($id)) {
1574 return;
1575 }
1576
1577 $prefix = TIMED_CONTENT_RULE_POSTMETA_PREFIX;
1578 $right_now_t = current_time('timestamp', 1);
1579 $rule_is_active = false;
1580
1581 // use debug parameter if current user is allowed to edit the post
1582 if (isset($_GET['tctest']) && current_user_can("edit_post", $post->post_id)) {
1583 $dt = DateTime::createFromFormat('Y-m-d H:i:s', $_GET['tctest']);
1584 if ($dt != false) {
1585 $right_now_t = $dt->getTimestamp();
1586 }
1587 }
1588
1589 $active_periods = $this->getRulePeriodsById($id, false);
1590 $action_is_show = (bool) get_post_meta($id, $prefix . 'action', true);
1591
1592 foreach ($active_periods as $period) {
1593 if (($period['start'] <= $right_now_t) && ($right_now_t <= $period['end'])) {
1594 $rule_is_active = true;
1595 break;
1596 }
1597 }
1598
1599 $the_filter = "timed_content_filter";
1600 $the_filter = apply_filters("timed_content_filter_override", $the_filter);
1601
1602 if ((($rule_is_active == true) && ($action_is_show == true)) || (($rule_is_active == false) && ($action_is_show == false))) {
1603 if (!empty($post)) {
1604 do_action("timed_content_rule_show", $post->ID, $id, $content);
1605 } else {
1606 do_action("timed_content_rule_show", null, $id, $content);
1607 }
1608
1609 return str_replace(']]>', ']]&gt;', apply_filters($the_filter, $content));
1610 } else {
1611 if (!empty($post)) {
1612 do_action("timed_content_rule_hide", $post->ID, $id, $content);
1613 } else {
1614 do_action("timed_content_rule_hide", null, $id, $content);
1615 }
1616
1617 return "";
1618 }
1619 }
1620
1621 /**
1622 * Enqueues the JavaScript code necessary for the functionality of the [timed-content-client] shortcode.
1623 */
1624 function addHeaderCode()
1625 {
1626 if (!is_admin()) {
1627 wp_enqueue_style('timed-content-css', TIMED_CONTENT_CSS, false, TIMED_CONTENT_VERSION);
1628 wp_enqueue_script('timed-content_js', TIMED_CONTENT_PLUGIN_URL . '/js/timed-content.js',
1629 array('jquery'), TIMED_CONTENT_VERSION);
1630 }
1631 }
1632
1633 /**
1634 * Enqueues the CSS code necessary for custom icons for the Timed Content Rules management screens
1635 * and the TinyMCE editor. Echo'd to output.
1636 */
1637 function addPostTypeIcons()
1638 {
1639 wp_enqueue_style('timed-content-dashicons', TIMED_CONTENT_CSS_DASHICONS, false, TIMED_CONTENT_VERSION);
1640 ?>
1641 <style type="text/css" media="screen">
1642 #adminmenu #menu-posts-<?php echo TIMED_CONTENT_RULE_TYPE; ?>.menu-icon-post div.wp-menu-image:before {
1643 font-family: 'timed-content-dashicons' !important;
1644 content: '\e601';
1645 }
1646
1647 #dashboard_right_now li.<?php echo TIMED_CONTENT_RULE_TYPE; ?>-count a:before {
1648 font-family: 'timed-content-dashicons' !important;
1649 content: '\e601';
1650 }
1651
1652 .mce-i-timed_content:before {
1653 font: 400 24px/1 'timed-content-dashicons' !important;
1654 padding: 0;
1655 vertical-align: top;
1656 margin-left: -2px;
1657 padding-right: 2px;
1658 content: '\e601';
1659 }
1660 </style>
1661 <?php
1662 }
1663
1664 /**
1665 * Enqueues the JavaScript code necessary for the functionality of the Timed Content Rules management screens.
1666 */
1667 function addAdminHeaderCode()
1668 {
1669 if ((isset($_GET['post_type']) && $_GET['post_type'] == TIMED_CONTENT_RULE_TYPE)
1670 || (isset($post_type) && $post_type == TIMED_CONTENT_RULE_TYPE)
1671 || (isset($_GET['post']) && get_post_type($_GET['post']) == TIMED_CONTENT_RULE_TYPE)) {
1672 wp_enqueue_style('thickbox');
1673 wp_enqueue_style('timed-content-css', TIMED_CONTENT_CSS, false, TIMED_CONTENT_VERSION);
1674 // Enqueue the JavaScript file that manages the meta box UI
1675 wp_enqueue_script('timed-content-admin_js', TIMED_CONTENT_PLUGIN_URL . '/js/timed-content-admin.js',
1676 array('jquery'), TIMED_CONTENT_VERSION);
1677 // Enqueue the JavaScript file that makes AJAX requests
1678 wp_enqueue_script('timed-content-ajax_js', TIMED_CONTENT_PLUGIN_URL . '/js/timed-content-ajax.js',
1679 array('jquery', 'thickbox'), TIMED_CONTENT_VERSION);
1680
1681 // Set up local variables used in the Admin JavaScript file
1682 wp_localize_script('timed-content-admin_js', 'timedContentRuleAdmin', array(
1683 'no_exceptions_label' => __("- No exceptions set -", 'timed-content')
1684 ));
1685
1686 // Set up local variables used in the AJAX JavaScript file
1687 wp_localize_script('timed-content-ajax_js', 'timedContentRuleAjax', array(
1688 'ajaxurl' => admin_url('admin-ajax.php'),
1689 'start_label' => _x('Start',
1690 'Scheduled Dates/Times dialog - Beginning of active period table header', 'timed-content'),
1691 'end_label' => _x('End',
1692 'Scheduled Dates/Times dialog - End of active period table header', 'timed-content'),
1693 'dialog_label' => _x('Scheduled dates/times',
1694 'Scheduled Dates/Times dialog - dialog header', 'timed-content'),
1695 'button_loading_label' => __('Calculating dates/times', 'timed-content'),
1696 'button_finished_label' => __('Show projected dates/times', 'timed-content'),
1697 'dialog_width' => 800,
1698 'dialog_height' => 500,
1699 'error' => __("Error", 'timed-content'),
1700 'error_desc' => __("Something unexpected has happened along the way. The specific details are below:",
1701 'timed-content')
1702 ));
1703 }
1704 }
1705
1706 /**
1707 * Initializes the TinyMCE plugin bundled with this Wordpress plugin
1708 *
1709 * @return void
1710 */
1711 function initTinyMCEPlugin()
1712 {
1713 if ((!current_user_can('edit_posts')) && (!current_user_can('edit_pages'))) {
1714 return;
1715 }
1716
1717 // Add only in Rich Editor mode
1718 if (get_user_option('rich_editing') == 'true') {
1719 add_filter("mce_external_plugins", array(&$this, "addTimedContentTinyMCEPlugin"));
1720 add_filter("mce_buttons", array(&$this, "registerTinyMCEButton"));
1721 }
1722 }
1723
1724 /**
1725 * Sets up variables to use in the TinyMCE plugin's plugin.js.
1726 *
1727 * @return void
1728 */
1729 function setTinyMCEPluginVars()
1730 {
1731 global $wp_version;
1732 if ((!current_user_can('edit_posts')) && (!current_user_can('edit_pages'))) {
1733 return;
1734 }
1735
1736 // Add only in Rich Editor mode
1737 if (get_user_option('rich_editing') == 'true') {
1738 if (version_compare($wp_version, "3.8", "<")) {
1739 $image = "/clock.gif";
1740 } else {
1741 $image = "";
1742 }
1743 wp_localize_script('editor',
1744 'timedContentAdminTinyMCEOptions',
1745 array(
1746 'version' => TIMED_CONTENT_VERSION,
1747 'desc' => __("Add Timed Content shortcodes", 'timed-content'),
1748 'image' => $image
1749 ));
1750 }
1751 }
1752
1753 /**
1754 * Sets up the button for the associated TinyMCE plugin for use in the editor menubar.
1755 *
1756 * @param array $buttons Array of menu buttons already registered with TinyMCE
1757 *
1758 * @return array The array of TinyMCE menu buttons with ours now loaded in as well
1759 */
1760 function registerTinyMCEButton($buttons)
1761 {
1762 array_push($buttons, "|", "timed_content");
1763
1764 return $buttons;
1765 }
1766
1767 /**
1768 * Loads the associated TinyMCE plugin into TinyMCE's plugin array
1769 *
1770 * @param array $plugin_array Array of plugins already registered with TinyMCE
1771 *
1772 * @return array The array of TinyMCE plugins with ours now loaded in as well
1773 */
1774 function addTimedContentTinyMCEPlugin($plugin_array)
1775 {
1776 $plugin_array['timed_content'] = TIMED_CONTENT_PLUGIN_URL . "/tinymce_plugin/plugin.js";
1777
1778 return $plugin_array;
1779 }
1780
1781 /**
1782 * Generates JavaScript array of objects describing Timed Content rules. Used in the dialog box created by
1783 * timedContentPlugin::timedContentPluginGetTinyMCEDialog().
1784 *
1785 * @return string JavaScript array describing the Timed Content rules
1786 */
1787 function getRulesJS()
1788 {
1789 $the_js = "var rules = [\n";
1790 $args = array(
1791 'post_type' => TIMED_CONTENT_RULE_TYPE,
1792 'posts_per_page' => - 1,
1793 'post_status' => 'publish'
1794 );
1795 $the_rules = get_posts($args);
1796 foreach ($the_rules as $rule) {
1797 $desc = $this->getScheduleDescriptionById($rule->ID);
1798 $desc = str_replace('<br />', ' ', $desc);
1799 // Only add a rule if there's no errors or warnings
1800 if (false === strpos($desc, "tcr-warning")) {
1801 $the_js .= " { 'ID': " . $rule->ID . ", 'title': '" . esc_js(((strlen($rule->post_title) > 0) ? $rule->post_title : _x("(no title)",
1802 "No Timed Content Rule title",
1803 "timed-content"))) . "', 'desc': '" . esc_js($desc) . "' },\n";
1804 }
1805 }
1806 if (empty($the_rules)) {
1807 $the_js .= " { 'ID': -999, 'title': ' ---- ', 'desc': '" . __('No Timed Content Rules found',
1808 'timed-content') . "' }\n";
1809 }
1810
1811 $the_js .= "];\n";
1812
1813 return $the_js;
1814 }
1815
1816 /**
1817 * Display a dialog box for this plugin's associated TinyMCE plugin. Called from TinyMCE via AJAX.
1818 *
1819 * @return void
1820 */
1821 function timedContentPluginGetTinyMCEDialog()
1822 {
1823 wp_enqueue_style(TIMED_CONTENT_SLUG . '-jquery-ui-css', TIMED_CONTENT_JQUERY_UI_CSS);
1824 wp_enqueue_script('jquery-ui-datepicker');
1825 wp_register_style(TIMED_CONTENT_SLUG . '-jquery-ui-timepicker-css',
1826 TIMED_CONTENT_JQUERY_UI_TIMEPICKER_CSS);
1827 wp_enqueue_style(TIMED_CONTENT_SLUG . '-jquery-ui-timepicker-css');
1828 wp_register_script(TIMED_CONTENT_SLUG . '-jquery-ui-timepicker-js', TIMED_CONTENT_JQUERY_UI_TIMEPICKER_JS,
1829 array('jquery', 'jquery-ui-datepicker'), TIMED_CONTENT_VERSION);
1830 wp_enqueue_script(TIMED_CONTENT_SLUG . '-jquery-ui-timepicker-js');
1831 if (!(wp_script_is(TIMED_CONTENT_SLUG . '-jquery-ui-datetime-i18n-js', 'registered'))) {
1832 wp_register_script(TIMED_CONTENT_SLUG . '-jquery-ui-datetime-i18n-js',
1833 TIMED_CONTENT_PLUGIN_URL . "/js/timed-content-datetime-i18n.js",
1834 array('jquery', 'jquery-ui-datepicker', TIMED_CONTENT_SLUG . '-jquery-ui-timepicker-js'),
1835 TIMED_CONTENT_VERSION);
1836 wp_enqueue_script(TIMED_CONTENT_SLUG . '-jquery-ui-datetime-i18n-js');
1837 wp_localize_script(TIMED_CONTENT_SLUG . '-jquery-ui-datetime-i18n-js', 'TimedContentJQDatepickerI18n',
1838 $this->jquery_ui_datetime_datepicker_i18n);
1839 wp_localize_script(TIMED_CONTENT_SLUG . '-jquery-ui-datetime-i18n-js', 'TimedContentJQTimepickerI18n',
1840 $this->jquery_ui_datetime_timepicker_i18n);
1841 }
1842
1843 ob_start();
1844 include("tinymce_plugin/dialog.php");
1845 $content = ob_get_contents();
1846 ob_end_clean();
1847 echo $content;
1848 die();
1849 }
1850
1851 /**
1852 * Adds support for i18n (internationalization)
1853 *
1854 * @return void
1855 */
1856 function i18nInit()
1857 {
1858 $plugin_dir = basename(dirname(__FILE__)) . "/lang/";
1859 load_plugin_textdomain('timed-content', false, $plugin_dir);
1860 }
1861
1862 /**
1863 * Add custom columns to the Timed Content Rules overview page
1864 *
1865 * @return void
1866 */
1867 function addDescColumnHead($defaults)
1868 {
1869 unset($defaults['date']);
1870 $defaults['description'] = __('Description', 'timed-content');
1871 $defaults['shortcode'] = __('Shortcode', 'timed-content');
1872
1873 return $defaults;
1874 }
1875
1876 /**
1877 * Display content associated with custom columns on the Timed Content rules overview page
1878 *
1879 * @param $column_name Name of the column to be displayed
1880 * @param $post_ID ID of the Timed Content Rule being listed
1881 */
1882 function addDescColumnContent($column_name, $post_ID)
1883 {
1884 if ($column_name == 'shortcode') {
1885 echo '<code>[' . TIMED_CONTENT_SHORTCODE_RULE . ' id="' . $post_ID . '"]...[/' . TIMED_CONTENT_SHORTCODE_RULE . ']</code>';
1886 }
1887 if ($column_name == 'description') {
1888 $desc = $this->getScheduleDescriptionById($post_ID);
1889 if ($desc) {
1890 echo '<em>' . $desc . '</em>';
1891 }
1892 }
1893 }
1894
1895 /**
1896 * Display a count of Timed Content rules in the Dashboard's Right Now widget
1897 *
1898 * @return void
1899 */
1900 function addRulesCount() {
1901 if (!post_type_exists(TIMED_CONTENT_RULE_TYPE)) {
1902 return;
1903 }
1904
1905 $num_posts = wp_count_posts(TIMED_CONTENT_RULE_TYPE);
1906 $num = number_format_i18n($num_posts->publish);
1907 $text = _n('Timed Content rule', 'Timed Content rules', intval($num_posts->publish),
1908 'timed-content');
1909 if (current_user_can('edit_posts') || current_user_can('edit_pages')) {
1910 echo "<a href='edit.php?post_type=" . TIMED_CONTENT_RULE_TYPE . "'>"
1911 . '<li class="' . TIMED_CONTENT_RULE_TYPE . '-count">'
1912 . $num
1913 . ' '
1914 . $text
1915 . '</a></li>';
1916 }
1917
1918 if ($num_posts->pending > 0) {
1919 $num = number_format_i18n($num_posts->pending);
1920 $text = _n('Timed Content rule pending', 'Timed Content rules pending', intval($num_posts->pending),
1921 'timed-content');
1922 if (current_user_can('edit_posts') || current_user_can('edit_pages')) {
1923 echo "<a href='edit.php?post_status=pending&post_type=" . TIMED_CONTENT_RULE_TYPE . "'>"
1924 . '<li class="' . TIMED_CONTENT_RULE_TYPE . '-count">'
1925 . $num
1926 . ' '
1927 . $text
1928 . '</a></li>';
1929 }
1930 }
1931 }
1932
1933 /**
1934 * Setup custom fields for Timed Content rules
1935 *
1936 * @return void
1937 */
1938 function setupCustomFields()
1939 {
1940 global $post;
1941
1942 $now_ts = current_time('timestamp');
1943 $now_plus1h_dt = new DateTime();
1944 $now_plus2h_dt = new DateTime();
1945 $now_plus1y_dt = new DateTime();
1946 $now_plus1h_dt->setTimeStamp($now_ts);
1947 $now_plus2h_dt->setTimeStamp($now_ts);
1948 $now_plus1y_dt->setTimeStamp($now_ts);
1949 $now_plus1h_dt->add(new DateInterval('PT1H'));
1950 $now_plus2h_dt->add(new DateInterval('PT2H'));
1951 $now_plus1y_dt->add(new DateInterval('P1Y'));
1952
1953 $post_id = (isset($_GET['post']) && (TIMED_CONTENT_RULE_TYPE === get_post_type($_GET['post'])) ? intval($_GET['post']) : intval(0));
1954 $exceptions_dates = get_post_meta($post_id, TIMED_CONTENT_RULE_POSTMETA_PREFIX . "exceptions_dates");
1955 if (false !== $exceptions_dates && isset($exceptions_dates[0]) && is_array($exceptions_dates[0])) {
1956 $timed_content_rules_exceptions_dates = $exceptions_dates[0];
1957 sort($timed_content_rules_exceptions_dates, SORT_NUMERIC);
1958 $timed_content_rules_exceptions_dates = array_unique($timed_content_rules_exceptions_dates);
1959
1960 // If the exceptions are stored as timestamps, convert them to ISO first
1961 $num = 0;
1962 while ($num<count($timed_content_rules_exceptions_dates)) {
1963 if (is_numeric($timed_content_rules_exceptions_dates[$num])) {
1964 $timed_content_rules_exceptions_dates[$num] = date('Y-m-d', $timed_content_rules_exceptions_dates[$num]);
1965 }
1966 $num++;
1967 }
1968
1969 $timed_content_rules_exceptions_dates_array = array_combine($timed_content_rules_exceptions_dates, $timed_content_rules_exceptions_dates);
1970 } else {
1971 $timed_content_rules_exceptions_dates_array = array("0" => __("- No exceptions set -", 'timed-content'));
1972 }
1973
1974 $this->rule_occurrence_custom_fields = array(
1975 array(
1976 "name" => "action",
1977 "display" => "block",
1978 "title" => __("Action", 'timed-content'),
1979 "description" => __("Sets the action to be performed when the rule is active.", 'timed-content'),
1980 "type" => "radio",
1981 "values" => array(1 => __("Show the content", 'timed-content'),
1982 0 => __("Hide the content", 'timed-content')),
1983 "default" => 1,
1984 "scope" => array(TIMED_CONTENT_RULE_TYPE),
1985 "capability" => "edit_posts"
1986 ),
1987 array(
1988 "name" => "instance_start",
1989 "display" => "block",
1990 "title" => __("Starting date/time", 'timed-content'),
1991 "description" => __("Sets the date and time for the beginning of the first active period for this rule.", 'timed-content'),
1992 "type" => "datetime",
1993 "default" => array("date" => strftime('%Y-%m-%d', $now_plus1h_dt->getTimeStamp()),
1994 "time" => strftime('%H:%M', $now_plus1h_dt->getTimeStamp())),
1995 "scope" => array(TIMED_CONTENT_RULE_TYPE),
1996 "capability" => "edit_posts"
1997 ),
1998 array(
1999 "name" => "instance_end",
2000 "display" => "block",
2001 "title" => __("Ending date/time", 'timed-content'),
2002 "description" => __("Sets the date and time for the end of the first active period for this rule.", 'timed-content'),
2003 "type" => "datetime",
2004 "default" => array("date" => strftime('%Y-%m-%d', $now_plus2h_dt->getTimeStamp()),
2005 "time" => strftime('%H:%M', $now_plus2h_dt->getTimeStamp())),
2006 "scope" => array(TIMED_CONTENT_RULE_TYPE),
2007 "capability" => "edit_posts"
2008 ),
2009 array(
2010 "name" => "timezone",
2011 "display" => "block",
2012 "title" => __("Timezone", 'timed-content'),
2013 "description" => __("Select the timezone you wish to use for this rule.", 'timed-content'),
2014 "type" => "timezone-list",
2015 "default" => get_option('timezone_string'),
2016 "scope" => array(TIMED_CONTENT_RULE_TYPE),
2017 "capability" => "edit_posts"
2018 )
2019 );
2020
2021 $this->rule_pattern_custom_fields = array(
2022 array(
2023 "name" => "frequency",
2024 "display" => "block",
2025 "title" => __("Frequency", 'timed-content'),
2026 "description" => __("Sets the frequency at which the action should be repeated.", 'timed-content'),
2027 "type" => "list",
2028 "default" => "1",
2029 "values" => $this->rule_freq_array,
2030 "scope" => array(TIMED_CONTENT_RULE_TYPE),
2031 "capability" => "edit_posts"
2032 ),
2033 array(
2034 "name" => "hourly_num_of_hours",
2035 "display" => "none",
2036 "title" => __("Interval of recurrences", 'timed-content'),
2037 "description" => __("Repeat this action every X hours.", 'timed-content'),
2038 "type" => "number",
2039 "default" => "1",
2040 "min" => "1",
2041 "scope" => array(TIMED_CONTENT_RULE_TYPE),
2042 "capability" => "edit_posts"
2043 ),
2044 array(
2045 "name" => "daily_num_of_days",
2046 "display" => "none",
2047 "title" => __("Interval of recurrences", 'timed-content'),
2048 "description" => __("Repeat this action every X days.", 'timed-content'),
2049 "type" => "number",
2050 "default" => "1",
2051 "min" => "1",
2052 "scope" => array(TIMED_CONTENT_RULE_TYPE),
2053 "capability" => "edit_posts"
2054 ),
2055 array(
2056 "name" => "weekly_num_of_weeks",
2057 "display" => "none",
2058 "title" => __("Interval of recurrences", 'timed-content'),
2059 "description" => __("Repeat this action every X weeks.", 'timed-content'),
2060 "type" => "number",
2061 "default" => "1",
2062 "min" => "1",
2063 "scope" => array(TIMED_CONTENT_RULE_TYPE),
2064 "capability" => "edit_posts"
2065 ),
2066 array(
2067 "name" => "weekly_days_of_week_to_repeat",
2068 "display" => "none",
2069 "title" => __("Repeat on the following days", 'timed-content'),
2070 "description" => __("Repeat this action on these days of the week <strong>instead</strong> of the day of week the starting date/time falls on.", 'timed-content'),
2071 "type" => "checkbox-list",
2072 "default" => array(),
2073 "values" => $this->rule_days_array,
2074 "scope" => array(TIMED_CONTENT_RULE_TYPE),
2075 "capability" => "edit_posts"
2076 ),
2077 array(
2078 "name" => "monthly_num_of_months",
2079 "display" => "none",
2080 "title" => __("Interval of recurrences", 'timed-content'),
2081 "description" => __("Repeat this action every X months.", 'timed-content'),
2082 "type" => "number",
2083 "default" => "1",
2084 "min" => "1",
2085 "scope" => array(TIMED_CONTENT_RULE_TYPE),
2086 "capability" => "edit_posts"
2087 ),
2088 array(
2089 "name" => "monthly_nth_weekday_of_month",
2090 "display" => "none",
2091 "title" => __("Repeat on a specific weekday of the month", 'timed-content'),
2092 "description" => __("Repeat this action on a specific weekday of the month (for example, \"every third Tuesday\"). Check this box to select a pattern below.", 'timed-content'),
2093 "type" => "checkbox",
2094 "default" => "no",
2095 "scope" => array(TIMED_CONTENT_RULE_TYPE),
2096 "capability" => "edit_posts"
2097 ),
2098 array(
2099 "name" => "monthly_nth_weekday_of_month_nth",
2100 "display" => "none",
2101 "title" => __("Weekday ordinal", 'timed-content'),
2102 "description" => __("Select a value for week of the month (for example \"first\", \"second\", etc.).", 'timed-content'),
2103 "type" => "list",
2104 "default" => 0,
2105 "values" => $this->rule_ordinal_array,
2106 "scope" => array(TIMED_CONTENT_RULE_TYPE),
2107 "capability" => "edit_posts"
2108 ),
2109 array(
2110 "name" => "monthly_nth_weekday_of_month_weekday",
2111 "display" => "none",
2112 "title" => __("Day of the week", 'timed-content'),
2113 "description" => __("Select the day of week.", 'timed-content'),
2114 "type" => "list",
2115 "default" => 0,
2116 "values" => $this->rule_ordinal_days_array,
2117 "scope" => array(TIMED_CONTENT_RULE_TYPE),
2118 "capability" => "edit_posts"
2119 ),
2120 array(
2121 "name" => "yearly_num_of_years",
2122 "display" => "none",
2123 "title" => __("Interval of recurrences", 'timed-content'),
2124 "description" => __("Repeat this action every X years.", 'timed-content'),
2125 "type" => "number",
2126 "default" => "1",
2127 "min" => "1",
2128 "scope" => array(TIMED_CONTENT_RULE_TYPE),
2129 "capability" => "edit_posts"
2130 )
2131 );
2132
2133 $this->rule_recurrence_custom_fields = array(
2134 array(
2135 "name" => "recurrence_duration",
2136 "display" => "block",
2137 "title" => __("How often to repeat this action", 'timed-content'),
2138 "description" => "",
2139 "type" => "radio",
2140 "values" => array("recurrence_duration_end_date" => __("Keep repeating until a given date", 'timed-content'),
2141 "recurrence_duration_num_repeat" => __("Repeat a set number of times", 'timed-content')),
2142 "default" => "recurrence_duration_end_date",
2143 "scope" => array(TIMED_CONTENT_RULE_TYPE),
2144 "capability" => "edit_posts"
2145 ),
2146 array(
2147 "name" => "recurrence_duration_end_date",
2148 "display" => "none",
2149 "title" => __("End Date", 'timed-content'),
2150 "description" => __("Using the settings above, repeat this action until this date.", 'timed-content'),
2151 "type" => "date",
2152 "default" => strftime('%Y-%m-%d', $now_plus1y_dt->getTimeStamp()),
2153 "scope" => array(TIMED_CONTENT_RULE_TYPE),
2154 "capability" => "edit_posts"
2155 ),
2156 array(
2157 "name" => "recurrence_duration_num_repeat",
2158 "display" => "none",
2159 "title" => __("Number of repetitions", 'timed-content'),
2160 "description" => __("Using the settings above, repeat this action this many times.", 'timed-content'),
2161 "type" => "number",
2162 "default" => "1",
2163 "min" => "1",
2164 "scope" => array(TIMED_CONTENT_RULE_TYPE),
2165 "capability" => "edit_posts"
2166 )
2167 );
2168
2169 $exceptions_dates_picker_on_select = <<<FUNC
2170 onSelect: function (dateText, inst) {
2171 jQuery("#timed_content_rule_exceptions_dates option[value='0']").remove();
2172 jQuery("#timed_content_rule_exceptions_dates").append('<option value="' + dateText + '">' + dateText + '</option>');
2173 jQuery(this).val("");
2174 jQuery(this).trigger("change");
2175 },
2176 FUNC;
2177
2178 $this->rule_exceptions_custom_fields = array(
2179 array(
2180 "name" => "exceptions_dates_picker",
2181 "display" => "block",
2182 "title" => __("Add exception date:", 'timed-content'),
2183 "description" => __("Select a date to add to the exception dates list.", 'timed-content'),
2184 "type" => "date",
2185 "default" => "",
2186 "scope" => array(TIMED_CONTENT_RULE_TYPE),
2187 "capability" => "edit_posts",
2188 "custom_functions" => $exceptions_dates_picker_on_select
2189 ),
2190 array(
2191 "name" => "exceptions_dates",
2192 "display" => "block",
2193 "title" => __("Exception dates list", 'timed-content'),
2194 "description" => __("Dates that this Timed Content rule will not be active. Double-click on a date to remove it from the list.", 'timed-content'),
2195 "type" => "menu",
2196 "values" => $timed_content_rules_exceptions_dates_array,
2197 "size" => "10",
2198 "default" => array(),
2199 "scope" => array(TIMED_CONTENT_RULE_TYPE),
2200 "capability" => "edit_posts"
2201 )
2202 );
2203
2204 $scf = new customFieldsInterface("timed_content_rule_schedule",
2205 __('Rule description/schedule', 'timed-content'),
2206 "<div id=\"schedule_desc\" style=\"font-style: italic; overflow-y: auto;\">"
2207 . (isset($_GET['post']) && (TIMED_CONTENT_RULE_TYPE === get_post_type($_GET['post'])) ? $this->getScheduleDescriptionById(intval($_GET['post'])) : $this->getScheduleDescriptionById(intval(0)))
2208 . "</div>"
2209 . "<div id=\"tcr-dialogHolder\" style=\"display:none;\"></div>"
2210 . "<div style=\"padding-top: 10px;\"><input type=\"button\" class=\"button button-primary\" id=\"timed_content_rule_test\" value=\"" . __('Show projected dates/times',
2211 'timed-content') . "\" /></div>",
2212 TIMED_CONTENT_RULE_POSTMETA_PREFIX,
2213 array(TIMED_CONTENT_RULE_TYPE),
2214 array(),
2215 $this->jquery_ui_datetime_datepicker_i18n,
2216 $this->jquery_ui_datetime_timepicker_i18n);
2217 $ocf = new customFieldsInterface("timed_content_rule_initial_event",
2218 __('Action/Initial Event', 'timed-content'),
2219 __('Set the action to be taken and when it should first run.', 'timed-content'),
2220 TIMED_CONTENT_RULE_POSTMETA_PREFIX,
2221 array(TIMED_CONTENT_RULE_TYPE),
2222 $this->rule_occurrence_custom_fields,
2223 $this->jquery_ui_datetime_datepicker_i18n,
2224 $this->jquery_ui_datetime_timepicker_i18n);
2225 $pcf = new customFieldsInterface("timed_content_rule_recurrence",
2226 __('Repeating Pattern', 'timed-content'),
2227 __('Set how often the action should repeat.', 'timed-content'),
2228 TIMED_CONTENT_RULE_POSTMETA_PREFIX,
2229 array(TIMED_CONTENT_RULE_TYPE),
2230 $this->rule_pattern_custom_fields,
2231 $this->jquery_ui_datetime_datepicker_i18n,
2232 $this->jquery_ui_datetime_timepicker_i18n);
2233 $rcf = new customFieldsInterface("timed_content_rule_stop_condition",
2234 __('Stopping Condition', 'timed-content'),
2235 __('Set how long or how many times the action should occur.', 'timed-content'),
2236 TIMED_CONTENT_RULE_POSTMETA_PREFIX,
2237 array(TIMED_CONTENT_RULE_TYPE),
2238 $this->rule_recurrence_custom_fields,
2239 $this->jquery_ui_datetime_datepicker_i18n,
2240 $this->jquery_ui_datetime_timepicker_i18n);
2241 $ecf = new customFieldsInterface("timed_content_rule_exceptions",
2242 __('Exceptions', 'timed-content'),
2243 __('Set up any exceptions to this Timed Content Rule.', 'timed-content'),
2244 TIMED_CONTENT_RULE_POSTMETA_PREFIX,
2245 array(TIMED_CONTENT_RULE_TYPE),
2246 $this->rule_exceptions_custom_fields,
2247 $this->jquery_ui_datetime_datepicker_i18n,
2248 $this->jquery_ui_datetime_timepicker_i18n);
2249 }
2250
2251 /**
2252 * Strips indices from an array
2253 *
2254 * @param $ArrayToStrip
2255 *
2256 * @return array Processed array
2257 */
2258 function stripArrayIndices($ArrayToStrip)
2259 {
2260 foreach ($ArrayToStrip as $objArrayItem) {
2261 $NewArray[] = $objArrayItem;
2262 }
2263
2264 return $NewArray;
2265 }
2266
2267 /**
2268 * Convert dates and times to ISO format if needed
2269 *
2270 * @param array $args Existing date and time values
2271 *
2272 * @return array Converted date values in ISO format
2273 */
2274 function convertDateTimeParametersToISO($args)
2275 {
2276 $date_parsed = date_create_from_format('Y-m-d', $args['instance_start']['date']);
2277 if ($date_parsed === false) {
2278 $date_source = strtotime($this->datetimeToEnglish($args['instance_start']['date']));
2279 $args['instance_start']['date'] = strftime('%Y-%m-%d', $date_source);
2280 }
2281
2282 $date_parsed = date_create_from_format('Y-m-d', $args['instance_end']['date']);
2283 if ($date_parsed === false) {
2284 $date_source = strtotime($this->datetimeToEnglish($args['instance_end']['date']));
2285 $args['instance_end']['date'] = strftime('%Y-%m-%d', $date_source);
2286 }
2287
2288 $args['instance_start']['time'] = $this->convertTimeToISO($args['instance_start']['time']);
2289
2290 $args['instance_end']['time'] = $this->convertTimeToISO($args['instance_end']['time']);
2291
2292 $date_parsed = date_create_from_format('Y-m-d', $args['end_date']);
2293 if ($date_parsed === false) {
2294 $date_source = strtotime($this->datetimeToEnglish($args['end_date']));
2295 $args['end_date'] = strftime('%Y-%m-%d', $date_source);
2296 }
2297
2298 if(is_array($args['exceptions_dates'])) {
2299 foreach ($args['exceptions_dates'] as $key => $value) {
2300 $date_parsed = date_create_from_format('Y-m-d', $value);
2301 if ($date_parsed === false) {
2302 $date_source = strtotime($this->datetimeToEnglish($args['end_date']));
2303 $args['exceptions_dates'][$key] = strftime('%Y-%m-%d', $date_source);
2304 }
2305 }
2306 }
2307
2308 return $args;
2309 }
2310
2311 /**
2312 * Convert time to ISO format if needed
2313 *
2314 * @param string $time Existing time value
2315 *
2316 * @return string Converted time values in ISO format
2317 */
2318 function convertTimeToISO($time) {
2319 if (strpos($time, 'AM') !== false) {
2320 $time_base = trim(substr($time, 0, strlen($time)-2));
2321 $time_dt = date_create_from_format('G:i', $time_base);
2322 if($time_dt !== false) {
2323 $time = strftime('%H:%M', $time_dt->getTimestamp());
2324 }
2325 } else if (strpos($time, 'PM') !== false) {
2326 $time_base = trim(substr($time, 0, strlen($time)-2));
2327 $time_dt = date_create_from_format('G:i', $time_base);
2328 if($time_dt !== false) {
2329 $time = strftime('%H:%M', $time_dt->getTimestamp() + 43200);
2330 }
2331 }
2332
2333 return $time;
2334 }
2335 }
2336
2337 // Initialize plugin
2338 $timedContentPluginInstance = new timedContentPlugin();
2339 ?>