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

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