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

2,316 lines 108.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: Timed Content
4 Text Domain: timed-content
5 Domain Path: /lang
6 Plugin URI: http://wordpress.org/plugins/timed-content/
7 Description: Plugin to show or hide portions of a Page or Post based on specific date/time characteristics. These actions can either be processed either server-side or client-side, depending on the desired effect.
8 Author: K. Tough, Arno Welzel, Enrico Bacis
9 Version: 2.65
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.65');
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[] = __("Interval 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
824 add_filter( 'date_i18n', array( &$this, "fix_date_i18n" ), 10, 4 );
825 $temp_tz = date_default_timezone_get();
826 date_default_timezone_set( $timezone );
827 $right_now_t = current_time( 'timestamp', 1 );
828
829 // use debug parameter if current user is allowed to edit the post
830 if ( isset( $_GET['tctest'] ) && current_user_can( "edit_post", $post->post_id ) ) {
831 $dt = DateTime::createFromFormat( 'Y-m-d H:i:s', $_GET['tctest'] );
832 if ( $dt != false ) {
833 $right_now_t = $dt->getTimestamp();
834 }
835 }
836
837 $instance_start = strtotime( $this->datetimeToEnglish( $instance_start_date,
838 $instance_start_time ) . " " . $timezone ); // Beginning of first occurrence
839 $instance_end = strtotime( $this->datetimeToEnglish( $instance_end_date,
840 $instance_end_time ) . " " . $timezone ); // End of first occurrence
841 $current = $instance_start;
842 $end_current = $instance_end;
843
844 if ( $recurr_type == "recurrence_duration_num_repeat" ) {
845 $last_occurrence_start = strtotime( TIMED_CONTENT_TIME_END );
846 } else {
847 $last_occurrence_start = strtotime( $this->datetimeToEnglish( $end_date,
848 $instance_start_time ) . " " . $timezone );
849 }
850
851 if ( $recurr_type == "recurrence_duration_end_date" ) {
852 $loop_test = "return ( \$current <= \$last_occurrence_start );";
853 } else {
854 $loop_test = "return ( \$period_count < \$num_repeat );";
855 }
856
857 while ( eval ( $loop_test ) ) {
858 $exception_period = false;
859 $current_date = date('Y-m-d', $current);
860 if ( is_array( $exceptions_dates ) ) {
861 foreach ( $exceptions_dates as $exceptions_date ) {
862 if (is_numeric($exceptions_date)) {
863 $exceptions_date = date('Y-m-d', $exceptions_date);
864 }
865 if ( $current_date === $exceptions_date ) {
866 $exception_period = true;
867 break;
868 }
869 }
870 }
871
872 if ( ( eval ( $loop_test ) ) && ( ! ( $exception_period ) ) ) {
873 $end_current = $current + ( $instance_end - $instance_start );
874 if ( $human_readable == true ) {
875 $active_periods[ $period_count ]["start"] = date_i18n( TIMED_CONTENT_DATE_FORMAT_OUTPUT, $current );
876 $active_periods[ $period_count ]["end"] = date_i18n( TIMED_CONTENT_DATE_FORMAT_OUTPUT, $end_current );
877 if ( $right_now_t < $current ) {
878 $active_periods[ $period_count ]["status"] = "upcoming";
879 $active_periods[ $period_count ]["time"] = sprintf( _x( '%s from now.',
880 'Human readable time difference', 'timed-content' ),
881 human_time_diff( $current, $right_now_t ) );
882 } elseif ( ( $current <= $right_now_t ) && ( $right_now_t <= $end_current ) ) {
883 $active_periods[ $period_count ]["status"] = "active";
884 $active_periods[ $period_count ]["time"] = __( "Right now!", 'timed-content' );
885 } else {
886 $active_periods[ $period_count ]["status"] = "expired";
887 $active_periods[ $period_count ]["time"] = sprintf( _x( '%s ago.',
888 'Human readable time difference', 'timed-content' ),
889 human_time_diff( $end_current, $right_now_t ) );
890 }
891 } else {
892 $active_periods[ $period_count ]["start"] = $current;
893 $active_periods[ $period_count ]["end"] = $end_current;
894 }
895 if ( ! ( $exception_period ) ) {
896 $period_count ++;
897 }
898 }
899
900 if ( $freq == 0 ) {
901 $current = $this->getNextHour( $current, $interval_multiplier );
902 } elseif ( $freq == 1 ) {
903 $current = $this->getNextDay( $current, $interval_multiplier );
904 } elseif ( $freq == 2 ) {
905 $current = $this->getNextWeek( $current, $interval_multiplier, $days_of_week );
906 } elseif ( $freq == 3 ) {
907 $current = $this->getNextMonth( $current, $instance_start, $interval_multiplier );
908 $temp_current = $current;
909 if ( $monthly_pattern == "yes" ) {
910 $current = $this->getNthWeekdayOfMonth( $current, $monthly_pattern_ord,
911 $monthly_pattern_day );
912 } else {
913 $current = $temp_current;
914 }
915 } elseif ( $freq == 4 ) {
916 $current = $this->getNextYear( $current, $interval_multiplier );
917 }
918 }
919 date_default_timezone_set( $temp_tz );
920 remove_filter( 'date_i18n', array( &$this, "fix_date_i18n" ), 10, 4 );
921
922 return $active_periods;
923 }
924
925 /**
926 * Wrapper for calling timedContentPlugin::__getRulePeriods() by the ID of a Timed Content Rule
927 *
928 * @param int $ID ID of the Timed Content Rule
929 * @param bool $human_readable If true, the active periods are returned as a human-readable date
930 * as defined by the constant TIMED_CONTENT_DT_FORMAT_OUTPUT otherwise,
931 * they are returned as UNIX timestamps.
932 *
933 * @return array Array of active periods
934 */
935 function getRulePeriodsById( $ID, $human_readable = false )
936 {
937 if ( TIMED_CONTENT_RULE_TYPE != get_post_type( $ID ) ) {
938 return array();
939 }
940
941 $prefix = TIMED_CONTENT_RULE_POSTMETA_PREFIX;
942 $args = array();
943
944 $args['human_readable'] = (bool) $human_readable;
945 $args['freq'] = get_post_meta( $ID, $prefix . 'frequency', true );
946 $args['timezone'] = get_post_meta( $ID, $prefix . 'timezone', true );
947 $args['recurr_type'] = get_post_meta( $ID, $prefix . 'recurrence_duration', true );
948 $args['num_repeat'] = get_post_meta( $ID, $prefix . 'recurrence_duration_num_repeat', true );
949 $args['end_date'] = get_post_meta( $ID, $prefix . 'recurrence_duration_end_date', true );
950 $args['days_of_week'] = get_post_meta( $ID, $prefix . 'weekly_days_of_week_to_repeat', true );
951 if ( $args['freq'] == 0 ) {
952 $args['interval_multiplier'] = get_post_meta( $ID, $prefix . 'hourly_num_of_hours', true );
953 }
954 if ( $args['freq'] == 1 ) {
955 $args['interval_multiplier'] = get_post_meta( $ID, $prefix . 'daily_num_of_days', true );
956 }
957 if ( $args['freq'] == 2 ) {
958 $args['interval_multiplier'] = get_post_meta( $ID, $prefix . 'weekly_num_of_weeks', true );
959 }
960 if ( $args['freq'] == 3 ) {
961 $args['interval_multiplier'] = get_post_meta( $ID, $prefix . 'monthly_num_of_months', true );
962 }
963 if ( $args['freq'] == 4 ) {
964 $args['interval_multiplier'] = get_post_meta( $ID, $prefix . 'yearly_num_of_years', true );
965 }
966 $args['instance_start'] = get_post_meta( $ID, $prefix . 'instance_start', true );
967 $args['instance_end'] = get_post_meta( $ID, $prefix . 'instance_end', true );
968 $args['monthly_pattern'] = get_post_meta( $ID, $prefix . 'monthly_nth_weekday_of_month', true );
969 $args['monthly_pattern_ord'] = get_post_meta( $ID, $prefix . 'monthly_nth_weekday_of_month_nth', true );
970 $args['monthly_pattern_day'] = get_post_meta( $ID, $prefix . 'monthly_nth_weekday_of_month_weekday', true );
971
972 $exceptions_dates = get_post_meta( $ID, $prefix . 'exceptions_dates' );
973 if (false !== $exceptions_dates && isset($exceptions_dates[0]) && is_array($exceptions_dates[0])) {
974 $args['exceptions_dates'] = $exceptions_dates[0];
975 } else {
976 $args['exceptions_dates'] = false;
977 }
978
979 $args = $this->convertDateTimeParametersToISO($args);
980
981 return $this->getRulePeriods( $args );
982 }
983
984 /**
985 * Wrapper for calling timedContentPlugin::__getRulePeriods() based on the contents of the form fields
986 * of the Add Timed Content Rule and Edit Timed Content Rule screens. Output is sent to output as JSON
987 */
988 function timedContentPluginGetRulePeriodsAjax()
989 {
990 if ( current_user_can( 'edit_posts' ) || current_user_can( 'edit_pages' ) ) {
991 $prefix = TIMED_CONTENT_RULE_POSTMETA_PREFIX;
992 $args = array();
993
994 $args['human_readable'] = ( ( ( isset( $_POST[ $prefix . 'human_readable' ] ) ) && ( $_POST[ $prefix . 'human_readable' ] == 'true' ) ) ? (bool) $_POST[ $prefix . 'human_readable' ] : false );
995 $args['freq'] = $_POST[ $prefix . 'frequency' ];
996 $args['timezone'] = $_POST[ $prefix . 'timezone' ];
997 $args['recurr_type'] = $_POST[ $prefix . 'recurrence_duration' ];
998 $args['num_repeat'] = $_POST[ $prefix . 'recurrence_duration_num_repeat' ];
999 $args['end_date'] = $_POST[ $prefix . 'recurrence_duration_end_date' ];
1000 $args['days_of_week'] = ( isset( $_POST[ $prefix . 'weekly_days_of_week_to_repeat' ] ) ? $_POST[ $prefix . 'weekly_days_of_week_to_repeat' ] : array() );
1001 $args['interval_multiplier'] = $_POST[ $prefix . 'interval_multiplier' ];
1002 $args['instance_start'] = $_POST[ $prefix . 'instance_start' ];
1003 $args['instance_end'] = $_POST[ $prefix . 'instance_end' ];
1004 $args['monthly_pattern'] = $_POST[ $prefix . 'monthly_nth_weekday_of_month' ];
1005 $args['monthly_pattern_ord'] = $_POST[ $prefix . 'monthly_nth_weekday_of_month_nth' ];
1006 $args['monthly_pattern_day'] = $_POST[ $prefix . 'monthly_nth_weekday_of_month_weekday' ];
1007 $args['exceptions_dates'] = ( isset( $_POST[ $prefix . 'exceptions_dates' ] ) ? $_POST[ $prefix . 'exceptions_dates' ] : array() );
1008
1009 $response = json_encode( $this->getRulePeriods( $args ) );
1010
1011 // response output
1012 header( "Content-Type: application/json" );
1013 echo $response;
1014 }
1015 die();
1016
1017 }
1018
1019 /**
1020 * Returns a human-readable description of a Timed Content Rule
1021 *
1022 * @param $args Array of Timed Content Rule parameters
1023 *
1024 * @return string Schedule description or warning, if the rule may not work properly
1025 */
1026 function getScheduleDescription( $args )
1027 {
1028 $interval_multiplier = 1;
1029 $desc = "";
1030
1031 $errors = $this->validate( $args );
1032 if ( $errors ) {
1033 $messages = "<div class=\"tcr-warning\">\n";
1034 $messages .= "<p class=\"heading\">" . __( "Warning!", 'timed-content' ) . "</p>\n";
1035 $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";
1036 $messages .= "<ul>\n";
1037 foreach ( $errors as $error ) {
1038 $messages .= " <li>" . $error . "</li>\n";
1039 }
1040 $messages .= "</ul>\n";
1041 $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";
1042 $messages .= "</div>\n";
1043
1044 return $messages;
1045 }
1046
1047 if ( $args['action'] ) {
1048 $action = __( "Show the content", 'timed-content' );
1049 } else {
1050 $action = __( "Hide the content", 'timed-content' );
1051 }
1052 $freq = $args['freq'];
1053 $timezone = $args['timezone'];
1054 $recurr_type = $args['recurr_type'];
1055 $num_repeat = intval( $args['num_repeat'] );
1056 $end_date = $args['end_date'];
1057 $days_of_week = $args['days_of_week'];
1058 $interval_multiplier = $args['interval_multiplier'];
1059 $instance_start_date = $args['instance_start']['date'];
1060 $instance_start_time = $args['instance_start']['time'];
1061 $instance_end_date = $args['instance_end']['date'];
1062 $instance_end_time = $args['instance_end']['time'];
1063 $monthly_pattern = $args['monthly_pattern'];
1064 $monthly_pattern_ord = $args['monthly_pattern_ord'];
1065 $monthly_pattern_day = $args['monthly_pattern_day'];
1066 $exceptions_dates = $args['exceptions_dates'];
1067
1068 $desc = sprintf( _x( '%1$s on %2$s @ %3$s until %4$s @ %5$s.',
1069 '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).',
1070 'timed-content' ), $action, $instance_start_date, $instance_start_time, $instance_end_date,
1071 $instance_end_time );
1072
1073 if ( $freq == 0 ) {
1074 $desc .= "<br />" . sprintf( _n( 'Repeat this action every hour.', 'Repeat this action every %d hours.',
1075 $interval_multiplier, 'timed-content' ), $interval_multiplier );
1076 } elseif ( $freq == 1 ) {
1077 $desc .= "<br />" . sprintf( _n( 'Repeat this action every day.', 'Repeat this action every %d days.',
1078 $interval_multiplier, 'timed-content' ), $interval_multiplier );
1079 } elseif ( $freq == 2 ) {
1080 if ( ( $days_of_week ) && ( is_array( $days_of_week ) ) ) {
1081 $days = array();
1082 $days_list = "";
1083 foreach ( $days_of_week as $v ) {
1084 $days[] = $this->rule_days_array[ $v ];
1085 }
1086 switch ( count( $days ) ) {
1087 case 1:
1088 $days_list = sprintf( _x( '%1$s', 'List of one weekday', 'timed-content' ), $days[0] );
1089 break;
1090 case 2:
1091 $days_list = sprintf( _x( '%1$s and %2$s', 'List of two weekdays', 'timed-content' ),
1092 $days[0], $days[1] );
1093 break;
1094 case 3:
1095 $days_list = sprintf( _x( '%1$s, %2$s and %3$s', 'List of three weekdays',
1096 'timed-content' ), $days[0], $days[1], $days[2] );
1097 break;
1098 case 4:
1099 $days_list = sprintf( _x( '%1$s, %2$s, %3$s and %4$s', 'List of four weekdays',
1100 'timed-content' ), $days[0], $days[1], $days[2], $days[3] );
1101 break;
1102 case 5:
1103 $days_list = sprintf( _x( '%1$s, %2$s, %3$s, %4$s and %5$s', 'List of five weekdays',
1104 'timed-content' ), $days[0], $days[1], $days[2], $days[3], $days[4] );
1105 break;
1106 case 6:
1107 $days_list = sprintf( _x( '%1$s, %2$s, %3$s, %4$s, %5$s and %6$s', 'List of six weekdays',
1108 'timed-content' ), $days[0], $days[1], $days[2], $days[3], $days[4], $days[5] );
1109 break;
1110 case 7:
1111 $days_list = sprintf( _x( '%1$s, %2$s, %3$s, %4$s, %5$s, %6$s and %7$s',
1112 'List of all weekdays', 'timed-content' ), $days[0], $days[1], $days[2], $days[3],
1113 $days[4], $days[5], $days[6] );
1114 break;
1115 }
1116 if ( $interval_multiplier == 1 ) {
1117 $desc .= "<br />" . sprintf( _x( 'Repeat this action every week on %s.',
1118 'List the weekdays to repeat the rule when frequency is every week. %s is the list of weekdays.',
1119 'timed-content' ), $days_list );
1120 } else {
1121 $desc .= "<br />" . sprintf( _x( 'Repeat this action every %1$d weeks on %2$s.',
1122 'List the weekdays to repeat the rule when frequency is every %1$d weeks. %2$s is the list of weekdays.',
1123 'timed-content' ), $interval_multiplier, $days_list );
1124 }
1125 } else {
1126 $desc .= "<br />" . sprintf( _n( 'Repeat this action every week.',
1127 'Repeat this action every %d weeks.', $interval_multiplier, 'timed-content' ),
1128 $interval_multiplier );
1129 }
1130
1131 } elseif ( $freq == 3 ) {
1132 if ( $monthly_pattern == "yes" ) {
1133 if ( $interval_multiplier == 1 ) {
1134 $desc .= "<br />" . sprintf( _x( 'Repeat this action every month on the %1$s %2$s of the month.',
1135 "Example: 'Repeat this action every month on the second Friday of the month.'",
1136 'timed-content' ), $this->rule_ordinal_array[ $monthly_pattern_ord ],
1137 $this->rule_ordinal_days_array[ $monthly_pattern_day ] );
1138 } else {
1139 $desc .= "<br />" . sprintf( _x( 'Repeat this action every %1$d months on the %2$s %3$s of the month.',
1140 "Example: 'Repeat this action every 2 months on the second Friday of the month.'",
1141 'timed-content' ), $interval_multiplier,
1142 $this->rule_ordinal_array[ $monthly_pattern_ord ],
1143 $this->rule_ordinal_days_array[ $monthly_pattern_day ] );
1144 }
1145 } else {
1146 $desc .= "<br />" . sprintf( _n( 'Repeat this action every month.',
1147 'Repeat this action every %d months.', $interval_multiplier, 'timed-content' ),
1148 $interval_multiplier );
1149 }
1150 } elseif ( $freq == 4 ) {
1151 $desc .= "<br />" . sprintf( _n( 'Repeat this action every year.', 'Repeat this action every %d years.',
1152 $interval_multiplier, 'timed-content' ), $interval_multiplier );
1153 }
1154
1155 if ( $recurr_type == "recurrence_duration_num_repeat" ) {
1156 $desc .= "<br />" . sprintf( _n( 'This rule will be active for one recurrence.',
1157 'This rule will be active for %d recurrences.', $num_repeat, 'timed-content' ), $num_repeat );
1158 } elseif ( $recurr_type == "recurrence_duration_end_date" ) {
1159 $desc .= "<br />" . sprintf( __( 'This rule will be active until %s.', 'timed-content' ), $end_date );
1160 }
1161
1162 if ( ( $exceptions_dates ) && ( is_array( $exceptions_dates ) ) ) {
1163 sort( $exceptions_dates, SORT_NUMERIC );
1164 $exceptions_dates = array_unique( $exceptions_dates );
1165 if ( $exceptions_dates[0] == 0 ) {
1166 array_shift( $exceptions_dates );
1167 }
1168 if ( ! empty( $exceptions_dates ) ) {
1169 $desc .= "<br />" . sprintf( __( 'This rule will be inactive on the following dates: %s.',
1170 'timed-content' ), join( ", ", $exceptions_dates ) );
1171 }
1172 }
1173
1174 $desc .= "<br />" . sprintf( __( 'All times are in the %s timezone.', 'timed-content' ), $timezone );
1175
1176 return $desc;
1177 }
1178
1179 /**
1180 * Wrapper for calling timedContentPlugin::__getScheduleDescription() by the ID of a Timed Content Rule
1181 *
1182 * @param int $ID ID of the Timed Content Rule
1183 *
1184 * @return string
1185 */
1186 function getScheduleDescriptionById( $ID )
1187 {
1188 $defaults = array();
1189
1190 foreach ( $this->rule_occurrence_custom_fields as $field ) {
1191 $defaults[ $field['name'] ] = $field['default'];
1192 }
1193 foreach ( $this->rule_pattern_custom_fields as $field ) {
1194 $defaults[ $field['name'] ] = $field['default'];
1195 }
1196 foreach ( $this->rule_recurrence_custom_fields as $field ) {
1197 $defaults[ $field['name'] ] = $field['default'];
1198 }
1199 foreach ( $this->rule_exceptions_custom_fields as $field ) {
1200 $defaults[ $field['name'] ] = $field['default'];
1201 }
1202
1203 $prefix = TIMED_CONTENT_RULE_POSTMETA_PREFIX;
1204 $args = array();
1205
1206 $args['action'] = ( false === get_post_meta( $ID, $prefix . 'action',
1207 true ) ? $defaults['action'] : get_post_meta( $ID, $prefix . 'action', true ) );
1208 $args['freq'] = ( false === get_post_meta( $ID, $prefix . 'frequency',
1209 true ) ? $defaults['frequency'] : get_post_meta( $ID, $prefix . 'frequency', true ) );
1210 $args['timezone'] = ( false === get_post_meta( $ID, $prefix . 'timezone',
1211 true ) ? $defaults['timezone'] : get_post_meta( $ID, $prefix . 'timezone', true ) );
1212 $args['recurr_type'] = ( false === get_post_meta( $ID, $prefix . 'recurrence_duration',
1213 true ) ? $defaults['recurrence_duration'] : get_post_meta( $ID, $prefix . 'recurrence_duration',
1214 true ) );
1215 $args['num_repeat'] = ( false === get_post_meta( $ID, $prefix . 'recurrence_duration_num_repeat',
1216 true ) ? $defaults['recurrence_duration_num_repeat'] : get_post_meta( $ID,
1217 $prefix . 'recurrence_duration_num_repeat', true ) );
1218 $args['end_date'] = ( false === get_post_meta( $ID, $prefix . 'recurrence_duration_end_date',
1219 true ) ? $defaults['recurrence_duration_end_date'] : get_post_meta( $ID,
1220 $prefix . 'recurrence_duration_end_date', true ) );
1221 $args['days_of_week'] = ( false === get_post_meta( $ID, $prefix . 'weekly_days_of_week_to_repeat',
1222 true ) ? $defaults['weekly_days_of_week_to_repeat'] : get_post_meta( $ID,
1223 $prefix . 'weekly_days_of_week_to_repeat', true ) );
1224 if ( $args['freq'] == 0 ) {
1225 $args['interval_multiplier'] = ( false === get_post_meta( $ID, $prefix . 'hourly_num_of_hours',
1226 true ) ? $defaults['hourly_num_of_hours'] : get_post_meta( $ID, $prefix . 'hourly_num_of_hours',
1227 true ) );
1228 }
1229 if ( $args['freq'] == 1 ) {
1230 $args['interval_multiplier'] = ( false === get_post_meta( $ID, $prefix . 'daily_num_of_days',
1231 true ) ? $defaults['daily_num_of_days'] : get_post_meta( $ID, $prefix . 'daily_num_of_days',
1232 true ) );
1233 }
1234 if ( $args['freq'] == 2 ) {
1235 $args['interval_multiplier'] = ( false === get_post_meta( $ID, $prefix . 'weekly_num_of_weeks',
1236 true ) ? $defaults['weekly_num_of_weeks'] : get_post_meta( $ID, $prefix . 'weekly_num_of_weeks',
1237 true ) );
1238 }
1239 if ( $args['freq'] == 3 ) {
1240 $args['interval_multiplier'] = ( false === get_post_meta( $ID, $prefix . 'monthly_num_of_months',
1241 true ) ? $defaults['monthly_num_of_months'] : get_post_meta( $ID, $prefix . 'monthly_num_of_months',
1242 true ) );
1243 }
1244 if ( $args['freq'] == 4 ) {
1245 $args['interval_multiplier'] = ( false === get_post_meta( $ID, $prefix . 'yearly_num_of_years',
1246 true ) ? $defaults['yearly_num_of_years'] : get_post_meta( $ID, $prefix . 'yearly_num_of_years',
1247 true ) );
1248 }
1249 $args['instance_start'] = ( false === get_post_meta( $ID, $prefix . 'instance_start',
1250 true ) ? $defaults['instance_start'] : get_post_meta( $ID, $prefix . 'instance_start', true ) );
1251 $args['instance_end'] = ( false === get_post_meta( $ID, $prefix . 'instance_end',
1252 true ) ? $defaults['instance_end'] : get_post_meta( $ID, $prefix . 'instance_end', true ) );
1253 $args['monthly_pattern'] = ( false === get_post_meta( $ID, $prefix . 'monthly_nth_weekday_of_month',
1254 true ) ? $defaults['monthly_nth_weekday_of_month'] : get_post_meta( $ID,
1255 $prefix . 'monthly_nth_weekday_of_month', true ) );
1256 $args['monthly_pattern_ord'] = ( false === get_post_meta( $ID, $prefix . 'monthly_nth_weekday_of_month_nth',
1257 true ) ? $defaults['monthly_nth_weekday_of_month_nth'] : get_post_meta( $ID,
1258 $prefix . 'monthly_nth_weekday_of_month_nth', true ) );
1259 $args['monthly_pattern_day'] = ( false === get_post_meta( $ID,
1260 $prefix . 'monthly_nth_weekday_of_month_weekday',
1261 true ) ? $defaults['monthly_nth_weekday_of_month_weekday'] : get_post_meta( $ID,
1262 $prefix . 'monthly_nth_weekday_of_month_weekday', true ) );
1263 $exceptions_dates = get_post_meta( $ID, $prefix . 'exceptions_dates' );
1264 if (false !== $exceptions_dates && isset($exceptions_dates[0]) && is_array($exceptions_dates[0])) {
1265 $args['exceptions_dates'] = $exceptions_dates[0];
1266 } else {
1267 $args['exceptions_dates'] = $defaults['exceptions_dates'];
1268 }
1269
1270 $args = $this->convertDateTimeParametersToISO( $args );
1271
1272 return $this->getScheduleDescription( $args );
1273 }
1274
1275 /**
1276 * Wrapper for calling timedContentPlugin::__getRulePeriods() based on the contents of the form fields
1277 * of the Add Timed Content Rule and Edit Timed Content Rule screens. Output is sent to output as plain text
1278 */
1279 function timedContentPluginGetScheduleDescriptionAjax()
1280 {
1281 if ( current_user_can( 'edit_posts' ) || current_user_can( 'edit_pages' ) ) {
1282 $prefix = TIMED_CONTENT_RULE_POSTMETA_PREFIX;
1283 $args = array();
1284
1285 $args['action'] = $_POST[ $prefix . 'action' ];
1286 $args['freq'] = $_POST[ $prefix . 'frequency' ];
1287 $args['timezone'] = $_POST[ $prefix . 'timezone' ];
1288 $args['recurr_type'] = $_POST[ $prefix . 'recurrence_duration' ];
1289 $args['num_repeat'] = $_POST[ $prefix . 'recurrence_duration_num_repeat' ];
1290 $args['end_date'] = $_POST[ $prefix . 'recurrence_duration_end_date' ];
1291 $args['days_of_week'] = ( isset( $_POST[ $prefix . 'weekly_days_of_week_to_repeat' ] ) ? $_POST[ $prefix . 'weekly_days_of_week_to_repeat' ] : array() );
1292 $args['interval_multiplier'] = $_POST[ $prefix . 'interval_multiplier' ];
1293 $args['instance_start'] = $_POST[ $prefix . 'instance_start' ];
1294 $args['instance_end'] = $_POST[ $prefix . 'instance_end' ];
1295 $args['monthly_pattern'] = $_POST[ $prefix . 'monthly_nth_weekday_of_month' ];
1296 $args['monthly_pattern_ord'] = $_POST[ $prefix . 'monthly_nth_weekday_of_month_nth' ];
1297 $args['monthly_pattern_day'] = $_POST[ $prefix . 'monthly_nth_weekday_of_month_weekday' ];
1298 $args['exceptions_dates'] = ( isset( $_POST[ $prefix . 'exceptions_dates' ] ) ? $_POST[ $prefix . 'exceptions_dates' ] : array() );
1299
1300 $response = $this->getScheduleDescription( $args );
1301
1302 // response output
1303 header( "Content-Type: text/plain" );
1304 echo $response;
1305 }
1306 die();
1307 }
1308
1309 /**
1310 * Processes the [timed-content-client] shortcode.
1311 *
1312 * @param array $atts Shortcode attributes
1313 * @param null $content Content inside the shortcode
1314 *
1315 * @return string Processed output
1316 */
1317 function clientShowHTML( $atts, $content = null )
1318 {
1319 $show_attr = "";
1320 $hide_attr = "";
1321 extract( shortcode_atts( array( 'show' => '0:00:000', 'hide' => '0:00:000', 'display' => 'div' ), $atts ) );
1322
1323 // Initialize show/hide arguments
1324 $s_min = 0;
1325 $s_sec = 0;
1326 $s_fade = 0;
1327 $h_min = 0;
1328 $h_sec = 0;
1329 $h_fade = 0;
1330 @list( $s_min, $s_sec, $s_fade ) = explode( ":", $show );
1331 @list( $h_min, $h_sec, $h_fade ) = explode( ":", $hide );
1332
1333 if ( ( (int) $s_min + (int) $s_sec ) > 0 ) {
1334 $show_attr = "_show_" . $s_min . "_" . $s_sec . "_" . $s_fade;
1335 }
1336 if ( ( (int) $h_min + (int) $h_sec ) > 0 ) {
1337 $hide_attr = "_hide_" . $h_min . "_" . $h_sec . "_" . $h_fade;
1338 }
1339
1340 $the_class = TIMED_CONTENT_SHORTCODE_CLIENT . $show_attr . $hide_attr;
1341 $the_tag = ( $display == "div" ? "div" : "span" );
1342
1343 $the_filter = "timed_content_filter";
1344 $the_filter = apply_filters( "timed_content_filter_override", $the_filter );
1345
1346 $the_HTML = "<"
1347 . $the_tag
1348 . " class='"
1349 . $the_class
1350 . "'"
1351 . ( ( $show_attr != "" ) ? " style='display: none;'" : "" ) . ">"
1352 . str_replace( ']]>', ']]&gt;', apply_filters( $the_filter, $content ) )
1353 . "</" . $the_tag . ">";
1354
1355 return $the_HTML;
1356 }
1357
1358 /**
1359 * Processes the [timed-content-server] shortcode.
1360 *
1361 * @param array $atts Shortcode attributes
1362 * @param null $content Content inside the shortcode
1363 *
1364 * @return string Processed output
1365 */
1366 function serverShowHTML( $atts, $content = null )
1367 {
1368 global $post;
1369 extract( shortcode_atts( array(
1370 'show' => 0,
1371 'hide' => 0,
1372 'debug' => 'false'
1373 ), $atts ) );
1374
1375 // Get time and timezone object for "show" time
1376 $pos = strrpos( $show, ' ' );
1377 if ( $pos !== false ) {
1378 $show_time = substr( $show, 0, $pos );
1379 $show_tzname = substr( $show, $pos + 1 );
1380 } else {
1381 $show_time = $show;
1382 $show_tzname = date_default_timezone_get();
1383 }
1384 try {
1385 $show_tz = new DateTimeZone($show_tzname);
1386 } catch(Exception $e) {
1387 $show_tz = new DateTimeZone('UTC');
1388 }
1389
1390 // Create time and timezone object for "hide" time
1391 $pos = strrpos( $hide, ' ' );
1392 if ( $pos !== false ) {
1393 $hide_time = substr( $hide, 0, $pos );
1394 $hide_tzname = substr( $hide, $pos + 1 );
1395 } else {
1396 $hide_time = $hide;
1397 $hide_tzname = date_default_timezone_get();
1398 }
1399 try {
1400 $hide_tz = new DateTimeZone($hide_tzname);
1401 } catch(Exception $e) {
1402 $hide_tz = new DateTimeZone('UTC');
1403 }
1404
1405 // Try to parse date as ISO first
1406 $show_dt = DateTime::createFromFormat( 'Y-m-d G:i', $show_time, $show_tz);
1407 // Fallback to American format
1408 if ($show_dt === false) {
1409 $show_dt = DateTime::createFromFormat('m/d/Y G:i', $show_time, $show_tz);
1410 }
1411
1412 if ( $show_dt !== false ) {
1413 $show_t = $show_dt->getTimeStamp();
1414 } else {
1415 // If nothing else worked so far, try strtotime()
1416 // as it was before version 2.50
1417 $show_t = strtotime($show);
1418 if($show_t === false) $show_t = 0;
1419 $show_dt = new DateTime();
1420 $show_dt->setTimeStamp($show_t);
1421 $show_dt->setTimezone($show_tz);
1422 }
1423
1424 // Try to parse date as ISO first
1425 $hide_dt = DateTime::createFromFormat( 'Y-m-d G:i', $hide_time, $hide_tz);
1426 if ($hide_dt === false) {
1427 $hide_dt = DateTime::createFromFormat( 'm/d/Y G:i', $hide_time, $hide_tz);
1428 }
1429 if ( $hide_dt !== false ) {
1430 $hide_t = $hide_dt->getTimeStamp();
1431 } else {
1432 // If nothing else worked so far, try strtotime()
1433 // as it was before version 2.50
1434 $hide_t = strtotime($hide);
1435 if($hide_t === false) $hide_t = 0;
1436 $hide_dt = new DateTime();
1437 $hide_dt->setTimeStamp($hide_t);
1438 $hide_dt->setTimezone($hide_tz);
1439 }
1440
1441 $right_now_t = current_time( 'timestamp', 1 );
1442 $debug_message = "";
1443
1444 // use debug parameter if current user is allowed to edit the post
1445 if ( isset( $_GET['tctest'] ) && current_user_can( "edit_post", $post->post_id ) ) {
1446 $dt = DateTime::createFromFormat( 'Y-m-d H:i:s', $_GET['tctest'] );
1447 if ( $dt != false ) {
1448 $right_now_t = $dt->getTimestamp();
1449 }
1450 }
1451
1452 $the_filter = "timed_content_filter";
1453 $the_filter = apply_filters( "timed_content_filter_override", $the_filter );
1454
1455 $show_content = false;
1456 if ( ( $show_t <= $right_now_t ) && ( $right_now_t <= $hide_t || $hide_t == 0 ) ) {
1457 $show_content = true;
1458 }
1459
1460 if ( ( ( $debug == "true" ) || ( ( ! $show_content ) && ( $debug == "when_hidden" ) ) )
1461 && ( current_user_can( "edit_post", $post->post_id ) ) ) {
1462 add_filter( 'date_i18n', array( &$this, "fix_date_i18n" ), 10, 4 );
1463 $temp_tz = date_default_timezone_get();
1464 date_default_timezone_set( get_option( 'timezone_string' ) );
1465
1466 $right_now = date_i18n( TIMED_CONTENT_DATE_FORMAT_OUTPUT, $right_now_t );
1467
1468 if ( $show_t > $right_now_t ) {
1469 $show_diff_str = sprintf( _x( '%s from now.', 'Human readable time difference', 'timed-content' ),
1470 human_time_diff( $show_t, $right_now_t ) );
1471 } else {
1472 $show_diff_str = sprintf( _x( '%s ago.', 'Human readable time difference', 'timed-content' ),
1473 human_time_diff( $show_t, $right_now_t ) );
1474 }
1475 if ( $hide_t > $right_now_t ) {
1476 $hide_diff_str = sprintf( _x( '%s from now.', 'Human readable time difference', 'timed-content' ),
1477 human_time_diff( $hide_t, $right_now_t ) );
1478 } else {
1479 $hide_diff_str = sprintf( _x( '%s ago.', 'Human readable time difference', 'timed-content' ),
1480 human_time_diff( $hide_t, $right_now_t ) );
1481 }
1482
1483 $debug_message = "<div class=\"tcr-warning\">\n";
1484 $debug_message .= "<p class=\"heading\">" . _x( "Notice", "Noun", 'timed-content' ) . "</p>\n";
1485 $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.',
1486 'timed-content' ), "<code>[timed-content-server]</code>", "<code>debug</code>" ) . "</p>\n";
1487
1488 if ( $show_t === 0 ) {
1489 $debug_message .= "<p>" . sprintf( __( 'The %s attribute is not set or invalid.', 'timed-content' ),
1490 "<code>show</code>" ) . "</p>\n";
1491 } else {
1492 $debug_message .= "<p>" . sprintf( __( 'The %s attribute is currently set to', 'timed-content' ),
1493 "<code>show</code>" ) . ": " . $show . ",<br />\n "
1494 . __( 'The Timed Content plugin thinks the intended date/time is',
1495 'timed-content' ) . ": " . $show_dt->format( TIMED_CONTENT_DATE_FORMAT_OUTPUT)
1496 . " (" . $show_diff_str . ")</p>\n";
1497 }
1498
1499 if ( $hide === 0 ) {
1500 $debug_message .= "<p>" . sprintf( __( 'The %s attribute is not set or invalid.', 'timed-content' ),
1501 "<code>hide</code>" ) . "</p>\n";
1502 } else {
1503 $debug_message .= "<p>" . sprintf( __( 'The %s attribute is currently set to', 'timed-content' ),
1504 "<code>hide</code>" ) . ": " . $hide . ",<br />\n"
1505 . __( 'The Timed Content plugin thinks the intended date/time is',
1506 'timed-content' ) . ": " . $hide_dt->format(TIMED_CONTENT_DATE_FORMAT_OUTPUT)
1507 . " (" . $hide_diff_str . ").</p>\n";
1508 }
1509
1510 $debug_message .= "<p>" . __( 'Current date:',
1511 'timed-content' ) . "&nbsp;" . $right_now . "</p>\n";
1512 $debug_message .= "<p>" . __( 'Content filter:', 'timed-content' ) . "&nbsp;" . $the_filter . "</p>\n";
1513 $debug_message .= "<p>" . _x( 'Content:', "Noun", 'timed-content' ) . "</p><p>" . $content . "</p>\n";
1514
1515 if ( $show_content === true ) {
1516 $debug_message .= "<p>" . __( 'The plugin will show the content.', 'timed-content' ) . "</p>";
1517 } else {
1518 $debug_message .= "<p>" . __( 'The plugin will hide the content.', 'timed-content' ). "</p>";
1519 }
1520
1521 $debug_message .= "</div>\n";
1522
1523 date_default_timezone_set( $temp_tz );
1524 remove_filter( 'date_i18n', array( &$this, "fix_date_i18n" ), 10, 4 );
1525 }
1526
1527 if ( $show_content === true ) {
1528 do_action( "timed_content_server_show", $post->ID, $show, $hide, $content );
1529
1530 return $debug_message . str_replace( ']]>', ']]&gt;', apply_filters( $the_filter, $content ) ) . "\n";
1531 } else {
1532 do_action( "timed_content_server_hide", $post->ID, $show, $hide, $content );
1533
1534 return $debug_message . "\n";
1535 }
1536
1537 }
1538
1539 /**
1540 * Processes the [timed-content-rule] shortcode.
1541 *
1542 * @param array $atts Shortcode attributes
1543 * @param null $content Content inside the shortcode
1544 *
1545 * @return string Processed output
1546 */
1547 function rulesShowHTML( $atts, $content = null )
1548 {
1549 global $post;
1550 extract( shortcode_atts( array( 'id' => 0 ), $atts ) );
1551 if ( ! is_numeric( $id ) ) {
1552 $page = get_page_by_title( $id, OBJECT, TIMED_CONTENT_RULE_TYPE );
1553 if ( $page == null ) {
1554 return;
1555 }
1556 $id = $page->ID;
1557 }
1558 if ( TIMED_CONTENT_RULE_TYPE != get_post_type( $id ) ) {
1559 return;
1560 }
1561
1562 $prefix = TIMED_CONTENT_RULE_POSTMETA_PREFIX;
1563 $right_now_t = current_time( 'timestamp', 1 );
1564 $rule_is_active = false;
1565
1566 // use debug parameter if current user is allowed to edit the post
1567 if ( isset( $_GET['tctest'] ) && current_user_can( "edit_post", $post->post_id ) ) {
1568 $dt = DateTime::createFromFormat( 'Y-m-d H:i:s', $_GET['tctest'] );
1569 if ( $dt != false ) {
1570 $right_now_t = $dt->getTimestamp();
1571 }
1572 }
1573
1574 $active_periods = $this->getRulePeriodsById( $id, false );
1575 $action_is_show = (bool) get_post_meta( $id, $prefix . 'action', true );
1576
1577 foreach ( $active_periods as $period ) {
1578 if ( ( $period['start'] <= $right_now_t ) && ( $right_now_t <= $period['end'] ) ) {
1579 $rule_is_active = true;
1580 break;
1581 }
1582 }
1583
1584 $the_filter = "timed_content_filter";
1585 $the_filter = apply_filters( "timed_content_filter_override", $the_filter );
1586
1587 if ( ( ( $rule_is_active == true ) && ( $action_is_show == true ) ) || ( ( $rule_is_active == false ) && ( $action_is_show == false ) ) ) {
1588 do_action( "timed_content_rule_show", $post->ID, $id, $content );
1589
1590 return str_replace( ']]>', ']]&gt;', apply_filters( $the_filter, $content ) );
1591 } else {
1592 do_action( "timed_content_rule_hide", $post->ID, $id, $content );
1593
1594 return "";
1595 }
1596 }
1597
1598 /**
1599 * Enqueues the JavaScript code necessary for the functionality of the [timed-content-client] shortcode.
1600 */
1601 function addHeaderCode()
1602 {
1603 if ( ! is_admin() ) {
1604 wp_enqueue_style( 'timed-content-css', TIMED_CONTENT_CSS, false, TIMED_CONTENT_VERSION );
1605 wp_enqueue_script( 'timed-content_js', TIMED_CONTENT_PLUGIN_URL . '/js/timed-content.js',
1606 array( 'jquery' ), TIMED_CONTENT_VERSION );
1607 }
1608 }
1609
1610 /**
1611 * Enqueues the CSS code necessary for custom icons for the Timed Content Rules management screens
1612 * and the TinyMCE editor. Echo'd to output.
1613 */
1614 function addPostTypeIcons()
1615 {
1616 wp_enqueue_style( 'timed-content-dashicons', TIMED_CONTENT_CSS_DASHICONS, false, TIMED_CONTENT_VERSION );
1617 ?>
1618 <style type="text/css" media="screen">
1619 #adminmenu #menu-posts-<?php echo TIMED_CONTENT_RULE_TYPE; ?>.menu-icon-post div.wp-menu-image:before {
1620 font-family: 'timed-content-dashicons' !important;
1621 content: '\e601';
1622 }
1623
1624 #dashboard_right_now li.<?php echo TIMED_CONTENT_RULE_TYPE; ?>-count a:before {
1625 font-family: 'timed-content-dashicons' !important;
1626 content: '\e601';
1627 }
1628
1629 .mce-i-timed_content:before {
1630 font: 400 24px/1 'timed-content-dashicons' !important;
1631 padding: 0;
1632 vertical-align: top;
1633 margin-left: -2px;
1634 padding-right: 2px;
1635 content: '\e601';
1636 }
1637 </style>
1638 <?php
1639 }
1640
1641 /**
1642 * Enqueues the JavaScript code necessary for the functionality of the Timed Content Rules management screens.
1643 */
1644 function addAdminHeaderCode()
1645 {
1646 if ( ( isset( $_GET['post_type'] ) && $_GET['post_type'] == TIMED_CONTENT_RULE_TYPE )
1647 || ( isset( $post_type ) && $post_type == TIMED_CONTENT_RULE_TYPE )
1648 || ( isset( $_GET['post'] ) && get_post_type( $_GET['post'] ) == TIMED_CONTENT_RULE_TYPE ) ) {
1649 wp_enqueue_style( 'thickbox' );
1650 wp_enqueue_style( 'timed-content-css', TIMED_CONTENT_CSS, false, TIMED_CONTENT_VERSION );
1651 // Enqueue the JavaScript file that manages the meta box UI
1652 wp_enqueue_script( 'timed-content-admin_js', TIMED_CONTENT_PLUGIN_URL . '/js/timed-content-admin.js',
1653 array( 'jquery' ), TIMED_CONTENT_VERSION );
1654 // Enqueue the JavaScript file that makes AJAX requests
1655 wp_enqueue_script( 'timed-content-ajax_js', TIMED_CONTENT_PLUGIN_URL . '/js/timed-content-ajax.js',
1656 array( 'jquery', 'thickbox' ), TIMED_CONTENT_VERSION );
1657
1658 // Set up local variables used in the Admin JavaScript file
1659 wp_localize_script( 'timed-content-admin_js', 'timedContentRuleAdmin', array(
1660 'no_exceptions_label' => __( "- No exceptions set -", 'timed-content' )
1661 ) );
1662
1663 // Set up local variables used in the AJAX JavaScript file
1664 wp_localize_script( 'timed-content-ajax_js', 'timedContentRuleAjax', array(
1665 'ajaxurl' => admin_url( 'admin-ajax.php' ),
1666 'start_label' => _x( 'Start',
1667 'Scheduled Dates/Times dialog - Beginning of active period table header', 'timed-content' ),
1668 'end_label' => _x( 'End',
1669 'Scheduled Dates/Times dialog - End of active period table header', 'timed-content' ),
1670 'dialog_label' => _x( 'Scheduled dates/times',
1671 'Scheduled Dates/Times dialog - dialog header', 'timed-content' ),
1672 'button_loading_label' => __( 'Calculating dates/times', 'timed-content' ),
1673 'button_finished_label' => __( 'Show projected dates/times', 'timed-content' ),
1674 'dialog_width' => 800,
1675 'dialog_height' => 500,
1676 'error' => __( "Error", 'timed-content' ),
1677 'error_desc' => __( "Something unexpected has happened along the way. The specific details are below:",
1678 'timed-content' )
1679 ) );
1680 }
1681 }
1682
1683 /**
1684 * Initializes the TinyMCE plugin bundled with this Wordpress plugin
1685 *
1686 * @return void
1687 */
1688 function initTinyMCEPlugin()
1689 {
1690 if ( ( ! current_user_can( 'edit_posts' ) ) && ( ! current_user_can( 'edit_pages' ) ) ) {
1691 return;
1692 }
1693
1694 // Add only in Rich Editor mode
1695 if ( get_user_option( 'rich_editing' ) == 'true' ) {
1696 add_filter( "mce_external_plugins", array( &$this, "addTimedContentTinyMCEPlugin" ) );
1697 add_filter( "mce_buttons", array( &$this, "registerTinyMCEButton" ) );
1698 }
1699 }
1700
1701 /**
1702 * Sets up variables to use in the TinyMCE plugin's plugin.js.
1703 *
1704 * @return void
1705 */
1706 function setTinyMCEPluginVars()
1707 {
1708 global $wp_version;
1709 if ( ( ! current_user_can( 'edit_posts' ) ) && ( ! current_user_can( 'edit_pages' ) ) ) {
1710 return;
1711 }
1712
1713 // Add only in Rich Editor mode
1714 if ( get_user_option( 'rich_editing' ) == 'true' ) {
1715 if ( version_compare( $wp_version, "3.8", "<" ) ) {
1716 $image = "/clock.gif";
1717 } else {
1718 $image = "";
1719 }
1720 wp_localize_script( 'editor',
1721 'timedContentAdminTinyMCEOptions',
1722 array(
1723 'version' => TIMED_CONTENT_VERSION,
1724 'desc' => __( "Add Timed Content shortcodes", 'timed-content' ),
1725 'image' => $image
1726 ) );
1727 }
1728 }
1729
1730 /**
1731 * Sets up the button for the associated TinyMCE plugin for use in the editor menubar.
1732 *
1733 * @param array $buttons Array of menu buttons already registered with TinyMCE
1734 *
1735 * @return array The array of TinyMCE menu buttons with ours now loaded in as well
1736 */
1737 function registerTinyMCEButton( $buttons )
1738 {
1739 array_push( $buttons, "|", "timed_content" );
1740
1741 return $buttons;
1742 }
1743
1744 /**
1745 * Loads the associated TinyMCE plugin into TinyMCE's plugin array
1746 *
1747 * @param array $plugin_array Array of plugins already registered with TinyMCE
1748 *
1749 * @return array The array of TinyMCE plugins with ours now loaded in as well
1750 */
1751 function addTimedContentTinyMCEPlugin( $plugin_array )
1752 {
1753 $plugin_array['timed_content'] = TIMED_CONTENT_PLUGIN_URL . "/tinymce_plugin/plugin.js";
1754
1755 return $plugin_array;
1756 }
1757
1758 /**
1759 * Generates JavaScript array of objects describing Timed Content rules. Used in the dialog box created by
1760 * timedContentPlugin::timedContentPluginGetTinyMCEDialog().
1761 *
1762 * @return string JavaScript array describing the Timed Content rules
1763 */
1764 function getRulesJS()
1765 {
1766 $the_js = "var rules = [\n";
1767 $args = array(
1768 'post_type' => TIMED_CONTENT_RULE_TYPE,
1769 'posts_per_page' => - 1,
1770 'post_status' => 'publish'
1771 );
1772 $the_rules = get_posts( $args );
1773 foreach ( $the_rules as $rule ) {
1774 $desc = $this->getScheduleDescriptionById( $rule->ID );
1775 $desc = str_replace('<br />', ' ', $desc);
1776 // Only add a rule if there's no errors or warnings
1777 if ( false === strpos( $desc, "tcr-warning" ) ) {
1778 $the_js .= " { 'ID': " . $rule->ID . ", 'title': '" . esc_js( ( ( strlen( $rule->post_title ) > 0 ) ? $rule->post_title : _x( "(no title)",
1779 "No Timed Content Rule title",
1780 "timed-content" ) ) ) . "', 'desc': '" . esc_js( $desc ) . "' },\n";
1781 }
1782 }
1783 if ( empty( $the_rules ) ) {
1784 $the_js .= " { 'ID': -999, 'title': ' ---- ', 'desc': '" . __( 'No Timed Content Rules found',
1785 'timed-content' ) . "' }\n";
1786 }
1787
1788 $the_js .= "];\n";
1789
1790 return $the_js;
1791 }
1792
1793 /**
1794 * Display a dialog box for this plugin's associated TinyMCE plugin. Called from TinyMCE via AJAX.
1795 *
1796 * @return void
1797 */
1798 function timedContentPluginGetTinyMCEDialog()
1799 {
1800 wp_enqueue_style( TIMED_CONTENT_SLUG . '-jquery-ui-css', TIMED_CONTENT_JQUERY_UI_CSS );
1801 wp_enqueue_script( 'jquery-ui-datepicker' );
1802 wp_register_style( TIMED_CONTENT_SLUG . '-jquery-ui-timepicker-css',
1803 TIMED_CONTENT_JQUERY_UI_TIMEPICKER_CSS );
1804 wp_enqueue_style( TIMED_CONTENT_SLUG . '-jquery-ui-timepicker-css' );
1805 wp_register_script( TIMED_CONTENT_SLUG . '-jquery-ui-timepicker-js', TIMED_CONTENT_JQUERY_UI_TIMEPICKER_JS,
1806 array( 'jquery', 'jquery-ui-datepicker' ), TIMED_CONTENT_VERSION );
1807 wp_enqueue_script( TIMED_CONTENT_SLUG . '-jquery-ui-timepicker-js' );
1808 if ( ! ( wp_script_is( TIMED_CONTENT_SLUG . '-jquery-ui-datetime-i18n-js', 'registered' ) ) ) {
1809 wp_register_script( TIMED_CONTENT_SLUG . '-jquery-ui-datetime-i18n-js',
1810 TIMED_CONTENT_PLUGIN_URL . "/js/timed-content-datetime-i18n.js",
1811 array( 'jquery', 'jquery-ui-datepicker', TIMED_CONTENT_SLUG . '-jquery-ui-timepicker-js' ),
1812 TIMED_CONTENT_VERSION );
1813 wp_enqueue_script( TIMED_CONTENT_SLUG . '-jquery-ui-datetime-i18n-js' );
1814 wp_localize_script( TIMED_CONTENT_SLUG . '-jquery-ui-datetime-i18n-js', 'TimedContentJQDatepickerI18n',
1815 $this->jquery_ui_datetime_datepicker_i18n );
1816 wp_localize_script( TIMED_CONTENT_SLUG . '-jquery-ui-datetime-i18n-js', 'TimedContentJQTimepickerI18n',
1817 $this->jquery_ui_datetime_timepicker_i18n );
1818 }
1819
1820 ob_start();
1821 include( "tinymce_plugin/dialog.php" );
1822 $content = ob_get_contents();
1823 ob_end_clean();
1824 echo $content;
1825 die();
1826 }
1827
1828 /**
1829 * Adds support for i18n (internationalization)
1830 *
1831 * @return void
1832 */
1833 function i18nInit()
1834 {
1835 $plugin_dir = basename( dirname( __FILE__ ) ) . "/lang/";
1836 load_plugin_textdomain( 'timed-content', false, $plugin_dir );
1837 }
1838
1839 /**
1840 * Add custom columns to the Timed Content Rules overview page
1841 *
1842 * @return void
1843 */
1844 function addDescColumnHead( $defaults )
1845 {
1846 unset( $defaults['date'] );
1847 $defaults['description'] = __( 'Description', 'timed-content' );
1848 $defaults['shortcode'] = __( 'Shortcode', 'timed-content' );
1849
1850 return $defaults;
1851 }
1852
1853 /**
1854 * Display content associated with custom columns on the Timed Content rules overview page
1855 *
1856 * @param $column_name Name of the column to be displayed
1857 * @param $post_ID ID of the Timed Content Rule being listed
1858 */
1859 function addDescColumnContent( $column_name, $post_ID )
1860 {
1861 if ( $column_name == 'shortcode' ) {
1862 echo '<code>[' . TIMED_CONTENT_SHORTCODE_RULE . ' id="' . $post_ID . '"]...[/' . TIMED_CONTENT_SHORTCODE_RULE . ']</code>';
1863 }
1864 if ( $column_name == 'description' ) {
1865 $desc = $this->getScheduleDescriptionById( $post_ID );
1866 if ( $desc ) {
1867 echo '<em>' . $desc . '</em>';
1868 }
1869 }
1870 }
1871
1872 /**
1873 * Display a count of Timed Content rules in the Dashboard's Right Now widget
1874 *
1875 * @return void
1876 */
1877 function addRulesCount() {
1878 if ( ! post_type_exists( TIMED_CONTENT_RULE_TYPE ) ) {
1879 return;
1880 }
1881
1882 $num_posts = wp_count_posts( TIMED_CONTENT_RULE_TYPE );
1883 $num = number_format_i18n( $num_posts->publish );
1884 $text = _n( 'Timed Content rule', 'Timed Content rules', intval( $num_posts->publish ),
1885 'timed-content' );
1886 if ( current_user_can( 'edit_posts' ) || current_user_can( 'edit_pages' ) ) {
1887 echo "<a href='edit.php?post_type=" . TIMED_CONTENT_RULE_TYPE . "'>"
1888 . '<li class="' . TIMED_CONTENT_RULE_TYPE . '-count">'
1889 . $num
1890 . ' '
1891 . $text
1892 . '</a></li>';
1893 }
1894
1895 if ( $num_posts->pending > 0 ) {
1896 $num = number_format_i18n( $num_posts->pending );
1897 $text = _n( 'Timed Content rule pending', 'Timed Content rules pending', intval( $num_posts->pending ),
1898 'timed-content' );
1899 if ( current_user_can( 'edit_posts' ) || current_user_can( 'edit_pages' ) ) {
1900 echo "<a href='edit.php?post_status=pending&post_type=" . TIMED_CONTENT_RULE_TYPE . "'>"
1901 . '<li class="' . TIMED_CONTENT_RULE_TYPE . '-count">'
1902 . $num
1903 . ' '
1904 . $text
1905 . '</a></li>';
1906 }
1907 }
1908 }
1909
1910 /**
1911 * Setup custom fields for Timed Content rules
1912 *
1913 * @return void
1914 */
1915 function setupCustomFields()
1916 {
1917 global $post;
1918
1919 $now_ts = current_time( 'timestamp' );
1920 $now_plus1h_dt = new DateTime();
1921 $now_plus2h_dt = new DateTime();
1922 $now_plus1y_dt = new DateTime();
1923 $now_plus1h_dt->setTimeStamp($now_ts);
1924 $now_plus2h_dt->setTimeStamp($now_ts);
1925 $now_plus1y_dt->setTimeStamp($now_ts);
1926 $now_plus1h_dt->add(new DateInterval('PT1H'));
1927 $now_plus2h_dt->add(new DateInterval('PT2H'));
1928 $now_plus1y_dt->add(new DateInterval('P1Y'));
1929
1930 $post_id = ( isset( $_GET['post'] ) && ( TIMED_CONTENT_RULE_TYPE === get_post_type( $_GET['post'] ) ) ? intval( $_GET['post'] ) : intval( 0 ) );
1931 $exceptions_dates = get_post_meta( $post_id, TIMED_CONTENT_RULE_POSTMETA_PREFIX . "exceptions_dates" );
1932 if (false !== $exceptions_dates && isset($exceptions_dates[0]) && is_array($exceptions_dates[0])) {
1933 $timed_content_rules_exceptions_dates = $exceptions_dates[0];
1934 sort( $timed_content_rules_exceptions_dates, SORT_NUMERIC );
1935 $timed_content_rules_exceptions_dates = array_unique( $timed_content_rules_exceptions_dates );
1936
1937 // If the exceptions are stored as timestamps, convert them to ISO first
1938 $num = 0;
1939 while ($num<count($timed_content_rules_exceptions_dates)) {
1940 if (is_numeric($timed_content_rules_exceptions_dates[$num])) {
1941 $timed_content_rules_exceptions_dates[$num] = date('Y-m-d', $timed_content_rules_exceptions_dates[$num]);
1942 }
1943 $num++;
1944 }
1945
1946 $timed_content_rules_exceptions_dates_array = array_combine($timed_content_rules_exceptions_dates, $timed_content_rules_exceptions_dates);
1947 } else {
1948 $timed_content_rules_exceptions_dates_array = array( "0" => __( "- No exceptions set -", 'timed-content' ) );
1949 }
1950
1951 $this->rule_occurrence_custom_fields = array(
1952 array(
1953 "name" => "action",
1954 "display" => "block",
1955 "title" => __( "Action", 'timed-content' ),
1956 "description" => __( "Sets the action to be performed when the rule is active.", 'timed-content' ),
1957 "type" => "radio",
1958 "values" => array(1 => __( "Show the content", 'timed-content' ),
1959 0 => __( "Hide the content", 'timed-content' ) ),
1960 "default" => 1,
1961 "scope" => array(TIMED_CONTENT_RULE_TYPE ),
1962 "capability" => "edit_posts"
1963 ),
1964 array(
1965 "name" => "instance_start",
1966 "display" => "block",
1967 "title" => __( "Starting date/time", 'timed-content' ),
1968 "description" => __( "Sets the date and time for the beginning of the first active period for this rule.", 'timed-content' ),
1969 "type" => "datetime",
1970 "default" => array("date" => strftime('%Y-%m-%d', $now_plus1h_dt->getTimeStamp()),
1971 "time" => strftime('%H:%M', $now_plus1h_dt->getTimeStamp())),
1972 "scope" => array(TIMED_CONTENT_RULE_TYPE ),
1973 "capability" => "edit_posts"
1974 ),
1975 array(
1976 "name" => "instance_end",
1977 "display" => "block",
1978 "title" => __( "Ending date/time", 'timed-content' ),
1979 "description" => __( "Sets the date and time for the end of the first active period for this rule.", 'timed-content' ),
1980 "type" => "datetime",
1981 "default" => array("date" => strftime('%Y-%m-%d', $now_plus2h_dt->getTimeStamp()),
1982 "time" => strftime('%H:%M', $now_plus2h_dt->getTimeStamp())),
1983 "scope" => array( TIMED_CONTENT_RULE_TYPE ),
1984 "capability" => "edit_posts"
1985 ),
1986 array(
1987 "name" => "timezone",
1988 "display" => "block",
1989 "title" => __( "Timezone", 'timed-content' ),
1990 "description" => __( "Select the timezone you wish to use for this rule.", 'timed-content' ),
1991 "type" => "timezone-list",
1992 "default" => get_option( 'timezone_string' ),
1993 "scope" => array( TIMED_CONTENT_RULE_TYPE ),
1994 "capability" => "edit_posts"
1995 )
1996 );
1997
1998 $this->rule_pattern_custom_fields = array(
1999 array(
2000 "name" => "frequency",
2001 "display" => "block",
2002 "title" => __( "Frequency", 'timed-content' ),
2003 "description" => __( "Sets the frequency at which the action should be repeated.", 'timed-content' ),
2004 "type" => "list",
2005 "default" => "1",
2006 "values" => $this->rule_freq_array,
2007 "scope" => array( TIMED_CONTENT_RULE_TYPE ),
2008 "capability" => "edit_posts"
2009 ),
2010 array(
2011 "name" => "hourly_num_of_hours",
2012 "display" => "none",
2013 "title" => __( "Interval of recurrences", 'timed-content' ),
2014 "description" => __( "Repeat this action every X hours.", 'timed-content' ),
2015 "type" => "number",
2016 "default" => "1",
2017 "min" => "1",
2018 "scope" => array( TIMED_CONTENT_RULE_TYPE ),
2019 "capability" => "edit_posts"
2020 ),
2021 array(
2022 "name" => "daily_num_of_days",
2023 "display" => "none",
2024 "title" => __( "Interval of recurrences", 'timed-content' ),
2025 "description" => __( "Repeat this action every X days.", 'timed-content' ),
2026 "type" => "number",
2027 "default" => "1",
2028 "min" => "1",
2029 "scope" => array( TIMED_CONTENT_RULE_TYPE ),
2030 "capability" => "edit_posts"
2031 ),
2032 array(
2033 "name" => "weekly_num_of_weeks",
2034 "display" => "none",
2035 "title" => __( "Interval of recurrences", 'timed-content' ),
2036 "description" => __( "Repeat this action every X weeks.", 'timed-content' ),
2037 "type" => "number",
2038 "default" => "1",
2039 "min" => "1",
2040 "scope" => array( TIMED_CONTENT_RULE_TYPE ),
2041 "capability" => "edit_posts"
2042 ),
2043 array(
2044 "name" => "weekly_days_of_week_to_repeat",
2045 "display" => "none",
2046 "title" => __( "Repeat on the following days", 'timed-content' ),
2047 "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' ),
2048 "type" => "checkbox-list",
2049 "default" => array(),
2050 "values" => $this->rule_days_array,
2051 "scope" => array( TIMED_CONTENT_RULE_TYPE ),
2052 "capability" => "edit_posts"
2053 ),
2054 array(
2055 "name" => "monthly_num_of_months",
2056 "display" => "none",
2057 "title" => __( "Interval of recurrences", 'timed-content' ),
2058 "description" => __( "Repeat this action every X months.", 'timed-content' ),
2059 "type" => "number",
2060 "default" => "1",
2061 "min" => "1",
2062 "scope" => array( TIMED_CONTENT_RULE_TYPE ),
2063 "capability" => "edit_posts"
2064 ),
2065 array(
2066 "name" => "monthly_nth_weekday_of_month",
2067 "display" => "none",
2068 "title" => __( "Repeat on a specific weekday of the month", 'timed-content' ),
2069 "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' ),
2070 "type" => "checkbox",
2071 "default" => "no",
2072 "scope" => array( TIMED_CONTENT_RULE_TYPE ),
2073 "capability" => "edit_posts"
2074 ),
2075 array(
2076 "name" => "monthly_nth_weekday_of_month_nth",
2077 "display" => "none",
2078 "title" => __( "Weekday ordinal", 'timed-content' ),
2079 "description" => __( "Select a value for week of the month (for example \"first\", \"second\", etc.).", 'timed-content' ),
2080 "type" => "list",
2081 "default" => 0,
2082 "values" => $this->rule_ordinal_array,
2083 "scope" => array( TIMED_CONTENT_RULE_TYPE ),
2084 "capability" => "edit_posts"
2085 ),
2086 array(
2087 "name" => "monthly_nth_weekday_of_month_weekday",
2088 "display" => "none",
2089 "title" => __( "Day of the week", 'timed-content' ),
2090 "description" => __( "Select the day of week.", 'timed-content' ),
2091 "type" => "list",
2092 "default" => 0,
2093 "values" => $this->rule_ordinal_days_array,
2094 "scope" => array( TIMED_CONTENT_RULE_TYPE ),
2095 "capability" => "edit_posts"
2096 ),
2097 array(
2098 "name" => "yearly_num_of_years",
2099 "display" => "none",
2100 "title" => __( "Interval of recurrences", 'timed-content' ),
2101 "description" => __( "Repeat this action every X years.", 'timed-content' ),
2102 "type" => "number",
2103 "default" => "1",
2104 "min" => "1",
2105 "scope" => array( TIMED_CONTENT_RULE_TYPE ),
2106 "capability" => "edit_posts"
2107 )
2108 );
2109
2110 $this->rule_recurrence_custom_fields = array(
2111 array(
2112 "name" => "recurrence_duration",
2113 "display" => "block",
2114 "title" => __( "How often to repeat this action", 'timed-content' ),
2115 "description" => "",
2116 "type" => "radio",
2117 "values" => array("recurrence_duration_end_date" => __( "Keep repeating until a given date", 'timed-content' ),
2118 "recurrence_duration_num_repeat" => __( "Repeat a set number of times", 'timed-content' ) ),
2119 "default" => "recurrence_duration_end_date",
2120 "scope" => array( TIMED_CONTENT_RULE_TYPE ),
2121 "capability" => "edit_posts"
2122 ),
2123 array(
2124 "name" => "recurrence_duration_end_date",
2125 "display" => "none",
2126 "title" => __( "End Date", 'timed-content' ),
2127 "description" => __( "Using the settings above, repeat this action until this date.", 'timed-content' ),
2128 "type" => "date",
2129 "default" => strftime('%Y-%m-%d', $now_plus1y_dt->getTimeStamp()),
2130 "scope" => array( TIMED_CONTENT_RULE_TYPE ),
2131 "capability" => "edit_posts"
2132 ),
2133 array(
2134 "name" => "recurrence_duration_num_repeat",
2135 "display" => "none",
2136 "title" => __( "Number of repetitions", 'timed-content' ),
2137 "description" => __( "Using the settings above, repeat this action this many times.", 'timed-content' ),
2138 "type" => "number",
2139 "default" => "1",
2140 "min" => "1",
2141 "scope" => array( TIMED_CONTENT_RULE_TYPE ),
2142 "capability" => "edit_posts"
2143 )
2144 );
2145
2146 $exceptions_dates_picker_on_select = <<<FUNC
2147 onSelect: function (dateText, inst) {
2148 jQuery("#timed_content_rule_exceptions_dates option[value='0']" ).remove();
2149 jQuery("#timed_content_rule_exceptions_dates").append( '<option value="' + dateText + '">' + dateText + '</option>' );
2150 jQuery(this).val("");
2151 jQuery(this).trigger("change");
2152 },
2153 FUNC;
2154
2155 $this->rule_exceptions_custom_fields = array(
2156 array(
2157 "name" => "exceptions_dates_picker",
2158 "display" => "block",
2159 "title" => __( "Add exception date:", 'timed-content' ),
2160 "description" => __( "Select a date to add to the exception dates list.", 'timed-content' ),
2161 "type" => "date",
2162 "default" => "",
2163 "scope" => array( TIMED_CONTENT_RULE_TYPE ),
2164 "capability" => "edit_posts",
2165 "custom_functions" => $exceptions_dates_picker_on_select
2166 ),
2167 array(
2168 "name" => "exceptions_dates",
2169 "display" => "block",
2170 "title" => __( "Exception dates list", 'timed-content' ),
2171 "description" => __( "Dates that this Timed Content rule will not be active. Double-click on a date to remove it from the list.", 'timed-content' ),
2172 "type" => "menu",
2173 "values" => $timed_content_rules_exceptions_dates_array,
2174 "size" => "10",
2175 "default" => array(),
2176 "scope" => array( TIMED_CONTENT_RULE_TYPE ),
2177 "capability" => "edit_posts"
2178 )
2179 );
2180
2181 $scf = new customFieldsInterface( "timed_content_rule_schedule",
2182 __( 'Rule description/schedule', 'timed-content' ),
2183 "<div id=\"schedule_desc\" style=\"font-style: italic; overflow-y: auto;\">"
2184 . ( isset( $_GET['post'] ) && ( TIMED_CONTENT_RULE_TYPE === get_post_type( $_GET['post'] ) ) ? $this->getScheduleDescriptionById( intval( $_GET['post'] ) ) : $this->getScheduleDescriptionById( intval( 0 ) ) )
2185 . "</div>"
2186 . "<div id=\"tcr-dialogHolder\" style=\"display:none;\"></div>"
2187 . "<div style=\"padding-top: 10px;\"><input type=\"button\" class=\"button button-primary\" id=\"timed_content_rule_test\" value=\"" . __( 'Show projected dates/times',
2188 'timed-content' ) . "\" /></div>",
2189 TIMED_CONTENT_RULE_POSTMETA_PREFIX,
2190 array( TIMED_CONTENT_RULE_TYPE ),
2191 array(),
2192 $this->jquery_ui_datetime_datepicker_i18n,
2193 $this->jquery_ui_datetime_timepicker_i18n);
2194 $ocf = new customFieldsInterface( "timed_content_rule_initial_event",
2195 __( 'Action/Initial Event', 'timed-content' ),
2196 __( 'Set the action to be taken and when it should first run.', 'timed-content' ),
2197 TIMED_CONTENT_RULE_POSTMETA_PREFIX,
2198 array( TIMED_CONTENT_RULE_TYPE ),
2199 $this->rule_occurrence_custom_fields,
2200 $this->jquery_ui_datetime_datepicker_i18n,
2201 $this->jquery_ui_datetime_timepicker_i18n);
2202 $pcf = new customFieldsInterface( "timed_content_rule_recurrence",
2203 __( 'Repeating Pattern', 'timed-content' ),
2204 __( 'Set how often the action should repeat.', 'timed-content' ),
2205 TIMED_CONTENT_RULE_POSTMETA_PREFIX,
2206 array( TIMED_CONTENT_RULE_TYPE ),
2207 $this->rule_pattern_custom_fields,
2208 $this->jquery_ui_datetime_datepicker_i18n,
2209 $this->jquery_ui_datetime_timepicker_i18n );
2210 $rcf = new customFieldsInterface( "timed_content_rule_stop_condition",
2211 __( 'Stopping Condition', 'timed-content' ),
2212 __( 'Set how long or how many times the action should occur.', 'timed-content' ),
2213 TIMED_CONTENT_RULE_POSTMETA_PREFIX,
2214 array( TIMED_CONTENT_RULE_TYPE ),
2215 $this->rule_recurrence_custom_fields,
2216 $this->jquery_ui_datetime_datepicker_i18n,
2217 $this->jquery_ui_datetime_timepicker_i18n );
2218 $ecf = new customFieldsInterface( "timed_content_rule_exceptions",
2219 __( 'Exceptions', 'timed-content' ),
2220 __( 'Set up any exceptions to this Timed Content Rule.', 'timed-content' ),
2221 TIMED_CONTENT_RULE_POSTMETA_PREFIX,
2222 array( TIMED_CONTENT_RULE_TYPE ),
2223 $this->rule_exceptions_custom_fields,
2224 $this->jquery_ui_datetime_datepicker_i18n,
2225 $this->jquery_ui_datetime_timepicker_i18n );
2226 }
2227
2228 /**
2229 * Strips indices from an array
2230 *
2231 * @param $ArrayToStrip
2232 *
2233 * @return array Processed array
2234 */
2235 function stripArrayIndices($ArrayToStrip)
2236 {
2237 foreach ($ArrayToStrip as $objArrayItem) {
2238 $NewArray[] = $objArrayItem;
2239 }
2240
2241 return $NewArray;
2242 }
2243
2244 /**
2245 * Convert dates and times to ISO format if needed
2246 *
2247 * @param array $args Existing date and time values
2248 *
2249 * @return array Converted date values in ISO format
2250 */
2251 function convertDateTimeParametersToISO($args)
2252 {
2253 $date_parsed = date_create_from_format('Y-m-d', $args['instance_start']['date']);
2254 if ($date_parsed === false) {
2255 $date_source = strtotime($this->datetimeToEnglish($args['instance_start']['date']));
2256 $args['instance_start']['date'] = strftime('%Y-%m-%d', $date_source);
2257 }
2258
2259 $date_parsed = date_create_from_format('Y-m-d', $args['instance_end']['date']);
2260 if ($date_parsed === false) {
2261 $date_source = strtotime($this->datetimeToEnglish($args['instance_end']['date']));
2262 $args['instance_end']['date'] = strftime('%Y-%m-%d', $date_source);
2263 }
2264
2265 $args['instance_start']['time'] = $this->convertTimeToISO($args['instance_start']['time']);
2266
2267 $args['instance_end']['time'] = $this->convertTimeToISO($args['instance_end']['time']);
2268
2269 $date_parsed = date_create_from_format('Y-m-d', $args['end_date']);
2270 if ($date_parsed === false) {
2271 $date_source = strtotime($this->datetimeToEnglish($args['end_date']));
2272 $args['end_date'] = strftime('%Y-%m-%d', $date_source);
2273 }
2274
2275 if( is_array($args['exceptions_dates'])) {
2276 foreach ($args['exceptions_dates'] as $key => $value) {
2277 $date_parsed = date_create_from_format('Y-m-d', $value);
2278 if ($date_parsed === false) {
2279 $date_source = strtotime($this->datetimeToEnglish($args['end_date']));
2280 $args['exceptions_dates'][$key] = strftime('%Y-%m-%d', $date_source);
2281 }
2282 }
2283 }
2284
2285 return $args;
2286 }
2287
2288 /**
2289 * Convert time to ISO format if needed
2290 *
2291 * @param string $time Existing time value
2292 *
2293 * @return string Converted time values in ISO format
2294 */
2295 function convertTimeToISO($time) {
2296 if (strpos($time, 'AM') !== false) {
2297 $time_base = trim(substr($time, 0, strlen($time)-2));
2298 $time_dt = date_create_from_format('G:i', $time_base);
2299 if($time_dt !== false) {
2300 $time = strftime('%H:%M', $time_dt->getTimestamp());
2301 }
2302 } else if (strpos($time, 'PM') !== 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() + 43200);
2307 }
2308 }
2309
2310 return $time;
2311 }
2312 }
2313
2314 // Initialize plugin
2315 $timedContentPluginInstance = new timedContentPlugin();
2316 ?>