PluginProbe
Timed Content / 2.72
Timed Content v2.72
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.72, at timed-content.php

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