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