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

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