set_format_timezone( wp_timezone_string() ); } /** * Initialise plugin */ function init() { global $wp_locale; load_plugin_textdomain( 'timed-content', false, '/timed-content/lang/' ); $this->rule_freq_array = array( 0 => __( 'hourly', 'timed-content' ), 1 => __( 'daily', 'timed-content' ), 2 => __( 'weekly', 'timed-content' ), 3 => __( 'monthly', 'timed-content' ), 4 => __( 'yearly', 'timed-content' ), ); $this->rule_days_array = array( 0 => __( 'Sunday', 'timed-content' ), 1 => __( 'Monday', 'timed-content' ), 2 => __( 'Tuesday', 'timed-content' ), 3 => __( 'Wednesday', 'timed-content' ), 4 => __( 'Thursday', 'timed-content' ), 5 => __( 'Friday', 'timed-content' ), 6 => __( 'Saturday', 'timed-content' ), ); $this->rule_ordinal_array = array( 0 => __( 'first', 'timed-content' ), 1 => __( 'second', 'timed-content' ), 2 => __( 'third', 'timed-content' ), 3 => __( 'fourth', 'timed-content' ), 4 => __( 'last', 'timed-content' ), 5 => __( 'fifth', 'timed-content' ), ); $this->rule_ordinal_days_array = array( 0 => __( 'Sunday', 'timed-content' ), 1 => __( 'Monday', 'timed-content' ), 2 => __( 'Tuesday', 'timed-content' ), 3 => __( 'Wednesday', 'timed-content' ), 4 => __( 'Thursday', 'timed-content' ), 5 => __( 'Friday', 'timed-content' ), 6 => __( 'Saturday', 'timed-content' ), 7 => __( 'day', 'timed-content' ), ); $this->jquery_ui_datetime_datepicker_i18n = array( 'closeText' => _x( 'Done', 'jQuery UI Datepicker Close label', 'timed-content' ), // Display text for close link 'prevText' => _x( 'Prev', 'jQuery UI Datepicker Previous label', 'timed-content' ), // Display text for previous month link 'nextText' => _x( 'Next', 'jQuery UI Datepicker Next label', 'timed-content' ), // Display text for next month link 'currentText' => _x( 'Today', 'jQuery UI Datepicker Today label', 'timed-content' ), // Display text for current month link 'weekHeader' => _x( 'Wk', 'jQuery UI Datepicker Week label', 'timed-content' ), // Column header for week of the year // Replace the text indices for the following arrays with 0-based arrays 'monthNames' => $this->strip_array_indices( $wp_locale->month ), // Names of months for drop-down and formatting 'monthNamesShort' => $this->strip_array_indices( $wp_locale->month_abbrev ), // For formatting 'dayNames' => $this->strip_array_indices( $wp_locale->weekday ), // For formatting 'dayNamesShort' => $this->strip_array_indices( $wp_locale->weekday_abbrev ), // For formatting 'dayNamesMin' => $this->strip_array_indices( $wp_locale->weekday_initial ), // Column headings for days starting at Sunday 'dateFormat' => 'yy-mm-dd', 'firstDay' => get_option( 'start_of_week' ), 'isRTL' => $wp_locale->is_rtl(), 'showMonthAfterYear' => false, // True if the year select precedes month, false for month then year 'yearSuffix' => '', // Additional text to append to the year in the month headers ); $tf = get_option( 'time_format' ); if ( false !== strpos( $tf, 'A' ) ) { $this->meridiem = array( $wp_locale->meridiem['AM'], $wp_locale->meridiem['PM'] ); $this->show_period = true; $this->show_period_labels = true; $this->show_leading_zero = false; } elseif ( false !== strpos( $tf, 'a' ) ) { $this->meridiem = array( $wp_locale->meridiem['am'], $wp_locale->meridiem['pm'] ); $this->show_period = true; $this->show_period_labels = true; $this->show_leading_zero = false; } else { $this->meridiem = array( '', '' ); $this->show_period = false; $this->show_period_labels = false; $this->show_leading_zero = true; } $this->jquery_ui_datetime_timepicker_i18n = array( 'hourText' => _x( 'Hour', "jQuery UI Timepicker 'Hour' label", 'timed-content' ), 'minuteText' => _x( 'Minute', "jQuery UI Timepicker 'Minute' label", 'timed-content' ), 'timeSeparator' => _x( ':', 'jQuery UI Datepicker: Character used to separate hours and minutes in translated language', 'timed-content' ), 'closeButtonText' => _x( 'Done', "jQuery UI Timepicker 'Done' label", 'timed-content' ), 'nowButtonText' => _x( 'Now', "jQuery UI Timepicker 'Now' label", 'timed-content' ), 'deselectButtonText' => _x( 'Deselect', "jQuery UI Timepicker 'Deselect' label", 'timed-content' ), 'amPmText' => array( '', '' ), 'showPeriod' => false, 'showPeriodLabels' => false, 'showLeadingZero' => false, 'timeFormat' => 'G:i', ); $this->timed_content_rule_type_init(); $this->setup_custom_fields(); } /** * Creates the Timed Content Rule post type and registers it with WordPress */ function timed_content_rule_type_init() { $labels = array( 'name' => _x( 'Timed Content rules', 'post type general name', 'timed-content' ), 'singular_name' => _x( 'Timed Content rule', 'post type singular name', 'timed-content' ), 'add_new' => _x( 'Add new', 'Menu item/button label on Timed Content Rules admin page', 'timed-content' ), 'add_new_item' => __( 'Add new Timed Content rule', 'timed-content' ), 'edit_item' => __( 'Edit Timed Content rule', 'timed-content' ), 'new_item' => __( 'New Timed Content rule', 'timed-content' ), 'view_item' => __( 'View Timed Content rule', 'timed-content' ), 'search_items' => __( 'Search Timed Content rules', 'timed-content' ), 'not_found' => __( 'No Timed Content rules found', 'timed-content' ), 'not_found_in_trash' => __( 'No Timed Content rules found in trash', 'timed-content' ), 'parent_item_colon' => '', 'menu_name' => _x( 'Timed Content rules', 'post type general name', 'timed-content' ), ); $args = array( 'labels' => $labels, 'description' => __( 'Create regular schedules to show or hide selected content in a page or post.', 'timed-content' ), 'public' => false, 'publicly_queryable' => false, 'exclude_from_search' => false, 'show_ui' => true, 'show_in_menu' => true, 'show_in_nav_menus' => true, 'show_in_admin_bar' => true, 'query_var' => false, 'rewrite' => false, 'capability_type' => 'post', 'has_archive' => false, 'hierarchical' => false, 'menu_position' => 5, 'supports' => array( 'title' ), ); register_post_type( TIMED_CONTENT_RULE_TYPE, $args ); } /** * Filter to change sort order to title */ function timed_content_pre_get_posts( $query ) { if ( $query->is_admin ) { if ( $query->get( 'post_type' ) === TIMED_CONTENT_RULE_TYPE ) { $query->set( 'orderby', 'title' ); $query->set( 'order', 'ASC' ); } } return $query; } /** * Filter to customize CRUD messages for Timed Content Rules */ function timed_content_rule_updated_messages( $messages ) { global $post; if ( ! empty( $post ) ) { /* translators: date and time format to activate rule. http://ca2.php.net/manual/en/function.date.php*/ $post_date = date_i18n( __( 'M j, Y @ G:i', 'timed-content' ), strtotime( $post->post_date ) ); } else { $post_date = ''; } $messages[ TIMED_CONTENT_RULE_TYPE ] = array( 0 => '', // Unused. Messages start at index 1. 1 => __( 'Timed Content Rule updated.', 'timed-content' ), 2 => __( 'Custom field updated.', 'timed-content' ), 3 => __( 'Custom field deleted.', 'timed-content' ), 4 => __( 'Timed Content Rule updated.', 'timed-content' ), 5 => isset( $_GET['revision'] ) ? sprintf( /* translators: %s: date and time of the revision */ __( 'Timed Content Rule restored to revision from %s', 'timed-content' ), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false, 6 => __( 'Timed Content Rule published.', 'timed-content' ), 7 => __( 'Timed Content Rule saved.', 'timed-content' ), 8 => __( 'Timed Content Rule submitted.', 'timed-content' ), 9 => sprintf( /* translators: %s: date and time to activate rule. */ __( 'Timed Content Rule scheduled for: %s.', 'timed-content' ), '' . $post_date . '' ), 10 => __( 'Timed Content Rule draft updated.', 'timed-content' ), ); return $messages; } /** * Convert localized date/time string to English */ function date_time_to_english( $date, $time = '' ) { $months = array( 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December', ); $months_i18n = array( __( 'January', 'timed-content' ), __( 'February', 'timed-content' ), __( 'March', 'timed-content' ), __( 'April', 'timed-content' ), __( 'May', 'timed-content' ), __( 'June', 'timed-content' ), __( 'July', 'timed-content' ), __( 'August', 'timed-content' ), __( 'September', 'timed-content' ), __( 'October', 'timed-content' ), __( 'November', 'timed-content' ), __( 'December', 'timed-content' ), ); $english_date = str_replace( $months_i18n, $months, $date ); return $english_date . ' ' . $time; } /** * Advances a date by a set number of days */ function get_next_day( $current, $interval_multiplier ) { return strtotime( $interval_multiplier . ' day', $current ); } /** * Advances a date/time by a set number of hours */ function get_next_hour( $current, $interval_multiplier ) { return strtotime( $interval_multiplier . ' hour', $current ); } /** * Advances a date/time by a set number of weeks. If given an array of days of the week, this function will * advance the date/time to the next day in that array in the jumped-to week. Use this function if you're * repeating an action on specific days of the week (i.e., on Weekdays, Tuesdays and Thursdays, etc.). */ function get_next_week( $current, $interval_multiplier, $days = array() ) { // If $days is empty, advance $interval_multiplier weeks from $current and return the timestamp if ( empty( $days ) ) { return strtotime( $interval_multiplier . ' week', $current ); } // Otherwise, set up an array combining the days of the week to repeat on and the current day // (keys and values of the array will be the same, and the array is sorted) $current_day_of_week_index = $this->format_timestamp( 'w', $current ); $days = array_merge( array( $current_day_of_week_index ), $days ); $days = array_unique( $days ); $days = array_values( $days ); sort( $days ); $days_of_week = array_combine( $days, $days ); // If the current day is the last one of the days of the week to repeat on, jump ahead to // the next week to be repeating on and get the earliest day in the array if ( max( $days_of_week ) === $current_day_of_week_index ) { $pattern = ( ( 7 - $current_day_of_week_index ) + ( 7 * ( $interval_multiplier - 1 ) ) + ( min( array_keys( $days_of_week ) ) ) ) . ' day'; } else { // Otherwise, cycle through the array until we find the next day to repeat on $next_day_of_week_index = $current_day_of_week_index; do { } while ( ! isset( $days_of_week[ ++$next_day_of_week_index ] ) ); $pattern = ( $next_day_of_week_index - $current_day_of_week_index ) . ' day'; } return strtotime( $pattern, $current ); } /** * Advances a date by a set number of months. When the date of the first active period lies * on the 29th, 30th, or 31st of the month, this function will return a date on the last day * of the month for those months not containing those days. */ function get_next_month( $current, $start, $interval_multiplier ) { $dateCurrent = new DateTime(); $dateCurrent->setTimestamp( $current ); $dateCurrent->setTimezone($this->get_format_timezone()); $dateStart = new DateTime(); $dateStart->setTimestamp( $start ); $dateStart->setTimezone($this->get_format_timezone()); $day = $dateCurrent->format( 'j' ); $month = $dateCurrent->format( 'n' ); $year = $dateCurrent->format( 'Y' ); // It can happen, that previous months limited the day of the month to a lower value (28, 29, 30) // so we make sure, that we use the original day if possible $dayStart = $dateStart->format( 'j' ); if ($dayStart > $day) { $day = $dayStart; } $month++; if ( $month > 12 ) { $month = 1; $year++; } if ( $day > 28 ) { $dateCurrent->setDate($year, $month, 1); $day = $dateCurrent->format('t'); if ($day > $dayStart) { $day = $dayStart; } } $dateCurrent->setDate($year, $month, $day); return $dateCurrent->getTimestamp(); } /** * Advances a date to the 'n'th weekday of the next month (eg., first Wednesday, third Monday, last Friday, etc.). * * Note: If $ordinal is set to '4' and $day is set to '7', it will return the last day of the month. */ function get_nth_weekday_of_month( $current, $ordinal, $day ) { // First, get the month/year we need to work with $the_month = $this->format_timestamp( 'm', $current ); $the_year = $this->format_timestamp( 'Y', $current ); $last_day_this_month = $this->format_timestamp( 't', $current ); // Get the time for the $current timestamp $the_hour = $this->format_timestamp( 'H', $current ); $the_minute = $this->format_timestamp( 'i', $current ); // The target day $the_day = ''; if ( 7 === $day ) { // If $day is "day of the month", get the day of month based on the ordinal switch ( $ordinal ) { case 0: $the_day = '1'; break; // First day of the month // case 1: $the_day = '2'; break; // Second day of the month // case 2: $the_day = '3'; break; // Third day of the month // case 3: $the_day = '4'; break; // Fourth day of the month // case 4: case 5: $the_day = $last_day_this_month; break; // Last day of the month // default: $the_day = '1'; break; } } else { // If $day is one of the days of the week... $day_range = array(); switch ( $ordinal ) { // ...get a 7-day range based on the ordinal... case 0: $day_range = range( 1, 7 ); break; // First 7 days of the month // case 1: $day_range = range( 8, 14 ); break; // Second 7 days of the month // case 2: $day_range = range( 15, 21 ); break; // Third 7 days of the month // case 3: $day_range = range( 22, 28 ); break; // Fourth 7 days of the month // case 4: case 5: $day_range = range( $last_day_this_month - 6, $last_day_this_month ); break; // Last 7 days of the month // default: $day_range = range( 1, 7 ); break; } foreach ( $day_range as $a_day ) { // ...and find the matching weekday in that range. $date_test = date_create_from_format('Y-m-d H:i', sprintf( '%04d-%02d-%02d 00:00', $the_year, $the_month, $a_day ), $this->get_format_timezone() ); if ( $date_test->format( 'w') === $day ) { $the_day = $a_day; break; } } // If this should be the fifth day of the month, it may happen // that the fourth and last day are identical - then you gave // go on to the next month if ('5' === $ordinal) { $day_range = range( 22, 28 ); foreach ( $day_range as $a_day ) { // ...and find the matching weekday in that range. $date_test = date_create_from_format('Y-m-d H:i', sprintf( '%04d-%02d-%02d 00:00', $the_year, $the_month, $a_day ), $this->get_format_timezone() ); if ( $date_test->format( 'w') === $day ) { $the_day_previous = $a_day; break; } } if ($the_day_previous === $the_day) { $the_day = 1; $the_month++; if ($the_month > 12) { $the_month = 1; $the_year++; } $date = date_create_from_format( 'Y-m-d H:i', sprintf( '%04d-%02d-%02d %02d:%02d', $the_year, $the_month, $the_day, $the_hour, $the_minute ), $this->get_format_timezone() ); $current_next_month = $date->getTimestamp(); return $this->get_nth_weekday_of_month( $current_next_month, $ordinal, $day ); } } } $date = date_create_from_format( 'Y-m-d H:i', sprintf( '%04d-%02d-%02d %02d:%02d', $the_year, $the_month, $the_day, $the_hour, $the_minute ), $this->get_format_timezone() ); return $date->getTimestamp(); } /** * Advances a date by a set number of years */ function get_next_year( $current, $interval_multiplier ) { return strtotime( $interval_multiplier . ' year', $current ); } /** * Validates the various Timed Content Rule parameters and returns a series of error messages. */ function validate( $args ) { $errors = array(); $instance_start = DateTime::createFromFormat( 'Y-m-d H:i', $args['instance_start']['date'] . ' ' . $args['instance_start']['time'] ); if ( false !== $instance_start ) { $instance_start = $instance_start->getTimestamp(); } $instance_end = DateTime::createFromFormat( 'Y-m-d H:i', $args['instance_end']['date'] . ' ' . $args['instance_end']['time'] ); if ( false !== $instance_end ) { $instance_end = $instance_end->getTimestamp(); } $end_date = DateTime::createFromFormat( 'Y-m-d', $args['end_date'] ); if ( false !== $end_date ) { $end_date = $end_date->getTimestamp(); } if ( empty( $args['instance_start']['date'] ) ) { $errors[] = __( 'Starting date must not be empty.', 'timed-content' ); } if ( empty( $args['instance_start']['time'] ) ) { $errors[] = __( 'Starting time must not be empty.', 'timed-content' ); } if ( empty( $args['instance_end']['date'] ) ) { $errors[] = __( 'Ending date must not be empty.', 'timed-content' ); } if ( empty( $args['instance_end']['time'] ) ) { $errors[] = __( 'Ending time must not be empty.', 'timed-content' ); } if ( empty( $args['interval_multiplier'] ) ) { $errors[] = __( 'Interval must not be empty.', 'timed-content' ); } elseif ( ! is_numeric( $args['interval_multiplier'] ) ) { $errors[] = __( 'Number of recurrences must be a number.', 'timed-content' ); } if ( 'recurrence_duration_num_repeat' === $args['recurr_type'] ) { if ( empty( $args['num_repeat'] ) ) { $errors[] = __( 'Number of repetitions must not be empty.', 'timed-content' ); } elseif ( ! is_numeric( $args['num_repeat'] ) ) { $errors[] = __( 'Number of repetitions must be a number.', 'timed-content' ); } } elseif ( 'recurrence_duration_end_date' === $args['recurr_type'] ) { if ( empty( $args['end_date'] ) ) { $errors[] = __( 'End date must not be empty.', 'timed-content' ); } if ( $instance_end > $end_date ) { $errors[] = __( 'Recurrence end date must be after ending date/time.', 'timed-content' ); } } if ( empty( $args['instance_start'] ) ) { $errors[] = __( 'Starting date/time must be valid.', 'timed-content' ); } if ( empty( $args['instance_end'] ) ) { $errors[] = __( 'Ending date/time must be valid.', 'timed-content' ); } if ( $instance_start > $instance_end ) { $errors[] = __( 'Starting date/time must be before ending date/time.', 'timed-content' ); } return $errors; } /** * Helper to determine if the current rule loop is already finished */ function loop_test( $recurr_type, $current, $last_occurrence_start, $period_count, $num_repeat ) { if ( 'recurrence_duration_end_date' === $recurr_type ) { return $current <= $last_occurrence_start; } return $period_count < $num_repeat; } /** * Calculates the active periods for a Timed Content Rule * * Note: if $args['human_readable'] is set to true, then the result will be in human readable form */ function get_rule_periods( $args ) { global $post; $active_periods = array(); $period_count = 0; $human_readable = (bool) $args['human_readable']; $freq = (int) $args['freq']; $timezone = $args['timezone']; $recurr_type = $args['recurr_type']; $num_repeat = intval( $args['num_repeat'] ); $end_date = $args['end_date']; $days_of_week = $args['days_of_week']; $interval_multiplier = $args['interval_multiplier']; $instance_start_date = $args['instance_start']['date']; $instance_start_time = $args['instance_start']['time']; $instance_end_date = $args['instance_end']['date']; $instance_end_time = $args['instance_end']['time']; $monthly_pattern = $args['monthly_pattern']; $monthly_pattern_ord = $args['monthly_pattern_ord']; $monthly_pattern_day = $args['monthly_pattern_day']; $exceptions_dates = $args['exceptions_dates']; $this->set_format_timezone( $timezone ); $right_now_t = time(); // use debug parameter if current user is allowed to edit the post if ( isset( $_GET['tctest'] ) && ! empty( $post ) && current_user_can( 'edit_post', $post->post_id ) ) { $dt = DateTime::createFromFormat( 'Y-m-d H:i:s', sanitize_text_field( $_GET['tctest'] ), $this->current_timezone ); if ( false !== $dt ) { $right_now_t = $dt->getTimestamp(); } } // Beginning of first occurrence $instance_start = strtotime( $this->date_time_to_english( $instance_start_date, $instance_start_time ) . ' ' . $timezone ); $start_has_dst = $this->format_timestamp( 'I', $instance_start ); // End of first occurrence $instance_end = strtotime( $this->date_time_to_english( $instance_end_date, $instance_end_time ) . ' ' . $timezone ); $current = $instance_start; $end_current = $instance_end; if ( 'recurrence_duration_num_repeat' === $recurr_type ) { $last_occurrence_start = strtotime( TIMED_CONTENT_TIME_END ); } else { $last_occurrence_start = strtotime( $this->date_time_to_english( $end_date, $instance_start_time ) . ' ' . $timezone ); } switch ( $freq ) { case TIMED_CONTENT_FREQ_HOURLY: $day_limit = 1; break; case TIMED_CONTENT_FREQ_DAILY: $day_limit = 7; break; case TIMED_CONTENT_FREQ_WEEKLY: $day_limit = 21; break; case TIMED_CONTENT_FREQ_MONTHLY: $day_limit = 80; break; default: // TIMED_CONTENT_FREQ_YEARLY: $day_limit = 380; break; } $future_repeats = 0; while ( $this->loop_test( $recurr_type, $current, $last_occurrence_start, $period_count, $num_repeat ) && ( $current < $right_now_t || $future_repeats < 20 ) ) { $exception_period = false; $current_date = $this->format_timestamp( 'Y-m-d', $current ); if ( is_array( $exceptions_dates ) ) { foreach ( $exceptions_dates as $exceptions_date ) { if ( is_numeric( $exceptions_date ) ) { $exceptions_date = $this->format_timestamp( 'Y-m-d', $exceptions_date ); } if ( $current_date === $exceptions_date ) { $exception_period = true; break; } } } if ( ! $exception_period && $current > $right_now_t - $day_limit * 86400 ) { // Adjust current date offset if start DST differs from current DST and we don't have a monthly pattern $current_adjusted = $current; if (TIMED_CONTENT_FREQ_MONTHLY !== $freq) { $current_has_dst = $this->format_timestamp('I', $current); if ('1' === $start_has_dst && '0' === $current_has_dst) { $current_adjusted += 3600; } if ('0' === $start_has_dst && '1' === $current_has_dst) { $current_adjusted -= 3600; } } if ( $current > $right_now_t ) { $future_repeats++; } $end_current = $current_adjusted + ( $instance_end - $instance_start ); if ( true === $human_readable ) { $active_periods[ $period_count ]['start'] = $this->format_timestamp( TIMED_CONTENT_DATE_FORMAT_OUTPUT, $current_adjusted ); $active_periods[ $period_count ]['end'] = $this->format_timestamp( TIMED_CONTENT_DATE_FORMAT_OUTPUT, $end_current ); $active_periods[ $period_count ]['timezone'] = $timezone; if ( $right_now_t < $current ) { $active_periods[ $period_count ]['status'] = 'upcoming'; $active_periods[ $period_count ]['time'] = sprintf( /* translators: %s: time difference */ _x( '%s from now.', 'Human readable time difference', 'timed-content' ), human_time_diff( $current, $right_now_t ) ); } elseif ( ( $current <= $right_now_t ) && ( $right_now_t <= $end_current ) ) { $active_periods[ $period_count ]['status'] = 'active'; $active_periods[ $period_count ]['time'] = __( 'Right now!', 'timed-content' ); } else { $active_periods[ $period_count ]['status'] = 'expired'; $active_periods[ $period_count ]['time'] = sprintf( /* translators: %s: time difference */ _x( '%s ago.', 'Human readable time difference', 'timed-content' ), human_time_diff( $end_current, $right_now_t ) ); } } else { $active_periods[ $period_count ]['start'] = $current_adjusted; $active_periods[ $period_count ]['end'] = $end_current; $active_periods[ $period_count ]['timezone'] = $timezone; } $period_count++; } switch ( $freq ) { case TIMED_CONTENT_FREQ_HOURLY: $current = $this->get_next_hour( $current, $interval_multiplier ); break; case TIMED_CONTENT_FREQ_DAILY: $current = $this->get_next_day( $current, $interval_multiplier ); break; case TIMED_CONTENT_FREQ_WEEKLY: $current = $this->get_next_week( $current, $interval_multiplier, $days_of_week ); break; case TIMED_CONTENT_FREQ_MONTHLY: $current = $this->get_next_month( $current, $instance_start, $interval_multiplier ); $temp_current = $current; if ( 'yes' === $monthly_pattern ) { $current = $this->get_nth_weekday_of_month( $current, $monthly_pattern_ord, $monthly_pattern_day ); } else { $current = $temp_current; } break; default: // TIMED_CONTENT_FREQ_YEARLY: $current = $this->get_next_year( $current, $interval_multiplier ); break; } } return $active_periods; } /** * Get stored rule periods by ID */ function get_rule_periods_by_id( $id, $human_readable = false ) { if ( TIMED_CONTENT_RULE_TYPE !== get_post_type( $id ) ) { return array(); } $prefix = TIMED_CONTENT_RULE_POSTMETA_PREFIX; $args = array(); $args['human_readable'] = (bool) $human_readable; $args['freq'] = get_post_meta( $id, $prefix . 'frequency', true ); $args['timezone'] = get_post_meta( $id, $prefix . 'timezone', true ); $args['recurr_type'] = get_post_meta( $id, $prefix . 'recurrence_duration', true ); $args['num_repeat'] = get_post_meta( $id, $prefix . 'recurrence_duration_num_repeat', true ); $args['end_date'] = get_post_meta( $id, $prefix . 'recurrence_duration_end_date', true ); $args['days_of_week'] = get_post_meta( $id, $prefix . 'weekly_days_of_week_to_repeat', true ); switch ( intval( $args['freq'] ) ) { case 0: $args['interval_multiplier'] = get_post_meta( $id, $prefix . 'hourly_num_of_hours', true ); break; case 1: $args['interval_multiplier'] = get_post_meta( $id, $prefix . 'daily_num_of_days', true ); break; case 2: $args['interval_multiplier'] = get_post_meta( $id, $prefix . 'weekly_num_of_weeks', true ); break; case 3: $args['interval_multiplier'] = get_post_meta( $id, $prefix . 'monthly_num_of_months', true ); break; case 4: $args['interval_multiplier'] = get_post_meta( $id, $prefix . 'yearly_num_of_years', true ); break; default: $args['interval_multiplier'] = 1; } $args['instance_start'] = get_post_meta( $id, $prefix . 'instance_start', true ); $args['instance_end'] = get_post_meta( $id, $prefix . 'instance_end', true ); $args['monthly_pattern'] = get_post_meta( $id, $prefix . 'monthly_nth_weekday_of_month', true ); $args['monthly_pattern_ord'] = get_post_meta( $id, $prefix . 'monthly_nth_weekday_of_month_nth', true ); $args['monthly_pattern_day'] = get_post_meta( $id, $prefix . 'monthly_nth_weekday_of_month_weekday', true ); $exceptions_dates = get_post_meta( $id, $prefix . 'exceptions_dates' ); if ( false !== $exceptions_dates && isset( $exceptions_dates[0] ) && is_array( $exceptions_dates[0] ) ) { $args['exceptions_dates'] = $exceptions_dates[0]; } else { $args['exceptions_dates'] = false; } $args = $this->convert_date_time_parameters_to_iso( $args ); return $this->get_rule_periods( $args ); } /** * Helper to get a sanitized post parameter */ function get_post_param( $name ) { $full_name = TIMED_CONTENT_RULE_POSTMETA_PREFIX . $name; if ( ! isset( $_POST[ $full_name ] ) ) { return ''; } return sanitize_text_field( $_POST[ $full_name ] ); } /** * Helper to get a sanitized post array parameter */ function get_post_array_param( $name ) { $full_name = TIMED_CONTENT_RULE_POSTMETA_PREFIX . $name; if ( ! isset( $_POST[ $full_name ] ) || ! is_array( $_POST[ $full_name ] ) ) { return array(); } $array = array(); foreach ( $_POST[ $full_name ] as $key => $value ) { $array[ sanitize_text_field( $key ) ] = sanitize_text_field( $value ); } return $array; } /** * Get rule periods based on the contents of the form fields of the Add Timed Content Rule and * Edit Timed Content Rule screens. Output is sent as JSON. */ function timed_content_plugin_get_rule_periods_ajax() { if ( current_user_can( 'edit_posts' ) || current_user_can( 'edit_pages' ) ) { $prefix = TIMED_CONTENT_RULE_POSTMETA_PREFIX; $args = array(); $args['human_readable'] = $this->get_post_param( 'human_readable' ); $args['freq'] = $this->get_post_param( 'frequency' ); $args['timezone'] = $this->get_post_param( 'timezone' ); $args['recurr_type'] = $this->get_post_param( 'recurrence_duration' ); $args['num_repeat'] = $this->get_post_param( 'recurrence_duration_num_repeat' ); $args['end_date'] = $this->get_post_param( 'recurrence_duration_end_date' ); $args['days_of_week'] = $this->get_post_array_param( 'weekly_days_of_week_to_repeat' ); $args['interval_multiplier'] = $this->get_post_param( 'interval_multiplier' ); $args['instance_start'] = $this->get_post_array_param( 'instance_start' ); $args['instance_end'] = $this->get_post_array_param( 'instance_end' ); $args['monthly_pattern'] = $this->get_post_param( 'monthly_nth_weekday_of_month' ); $args['monthly_pattern_ord'] = $this->get_post_param( 'monthly_nth_weekday_of_month_nth' ); $args['monthly_pattern_day'] = $this->get_post_param( 'monthly_nth_weekday_of_month_weekday' ); $args['exceptions_dates'] = $this->get_post_array_param( 'exceptions_dates' ); $errors = $this->validate( $args ); if ( count( $errors ) === 0 ) { header( 'Content-Type: application/json' ); echo json_encode( $this->get_rule_periods( $args ) ); } } die(); } /** * Returns a human-readable description of a Timed Content Rule */ function get_schedule_description( $args ) { $interval_multiplier = 1; $desc = ''; $errors = $this->validate( $args ); if ( $errors ) { $message = sprintf( '
%s
' . '%s
' . '%s
', __( 'Warning!', 'timed-content' ), __( 'Some problems have been detected. Although you can still publish this rule, it may not work the way you expect.', 'timed-content' ), implode( '' . _x( 'Notice', 'Noun', 'timed-content' ) . "
\n"; $debug_message .= '' . sprintf(
/* translators: %1$s: shortcode, %2$s attribute in shortcode */
__(
'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'
),
'[timed-content-server]',
'debug'
) . "
' . sprintf(
/* translators: %s: attribute name */
__( 'The %s attribute is not set or invalid.', 'timed-content' ),
'show'
) . "
' . sprintf(
/* translators: %s: attribute name */
__( 'The %s attribute is currently set to', 'timed-content' ),
'show'
) . ': ' . $show . ",
\n "
. __(
'The Timed Content plugin thinks the intended date/time is',
'timed-content'
) . ': ' . $show_dt->format( TIMED_CONTENT_DATE_FORMAT_OUTPUT )
. ' (' . $show_diff_str . ")
' . sprintf(
/* translators: %s: attribute name */
__( 'The %s attribute is not set or invalid.', 'timed-content' ),
'hide'
) . "
' . sprintf(
/* translators: %s: attribute name */
__( 'The %s attribute is currently set to', 'timed-content' ),
'hide'
) . ': ' . $hide . ",
\n"
. __(
'The Timed Content plugin thinks the intended date/time is',
'timed-content'
) . ': ' . $hide_dt->format( TIMED_CONTENT_DATE_FORMAT_OUTPUT )
. ' (' . $hide_diff_str . ").
' . __( 'Current date:', 'timed-content' ) . ' ' . $right_now . "
\n"; $debug_message .= '' . __( 'Content filter:', 'timed-content' ) . ' ' . $the_filter . "
\n"; $debug_message .= '' . _x( 'Content:', 'Noun', 'timed-content' ) . '
' . $content . "
\n"; if ( true === $show_content ) { $debug_message .= '' . __( 'The plugin will show the content.', 'timed-content' ) . '
'; } else { $debug_message .= '' . __( 'The plugin will hide the content.', 'timed-content' ) . '
'; } $debug_message .= "[%s id="%s"]...[/%s]',
TIMED_CONTENT_SHORTCODE_RULE,
$post_id,
TIMED_CONTENT_SHORTCODE_RULE
);
}
if ( 'description' === $column_name ) {
$desc = $this->get_schedule_description_by_id( $post_id );
if ( $desc ) {
echo sprintf( '%s', $desc );
}
}
}
/**
* Display a count of Timed Content rules in the Dashboard's Right Now widget
*/
function add_rules_count() {
$items = [];
if ( ! post_type_exists( TIMED_CONTENT_RULE_TYPE ) ) {
return;
}
$num_posts = wp_count_posts( TIMED_CONTENT_RULE_TYPE );
$num = number_format_i18n( $num_posts->publish );
$text = _n(
'Timed Content rule',
'Timed Content rules',
intval( $num_posts->publish ),
'timed-content'
);
if ( current_user_can( 'edit_posts' ) || current_user_can( 'edit_pages' ) ) {
$items[] = ''
. $num
. ' '
. $text
. '';
}
if ( $num_posts->pending > 0 ) {
$num = number_format_i18n( $num_posts->pending );
$text = _n(
'Timed Content rule pending',
'Timed Content rules pending',
intval( $num_posts->pending ),
'timed-content'
);
if ( current_user_can( 'edit_posts' ) || current_user_can( 'edit_pages' ) ) {
$items[] = ''
. $num
. ' '
. $text
. '';
}
}
return $items;
}
/**
* Setup custom fields for Timed Content rules
*/
function setup_custom_fields() {
global $post;
$now_ts = time();
$now_plus1h_dt = new DateTime();
$now_plus2h_dt = new DateTime();
$now_plus1y_dt = new DateTime();
$now_plus1h_dt->setTimeStamp( $now_ts );
$now_plus2h_dt->setTimeStamp( $now_ts );
$now_plus1y_dt->setTimeStamp( $now_ts );
$now_plus1h_dt->add( new DateInterval( 'PT1H' ) );
$now_plus2h_dt->add( new DateInterval( 'PT2H' ) );
$now_plus1y_dt->add( new DateInterval( 'P1Y' ) );
$post_id = ( isset( $_GET['post'] ) && ( TIMED_CONTENT_RULE_TYPE === get_post_type( $_GET['post'] ) ) ? intval( $_GET['post'] ) : intval( 0 ) );
$exceptions_dates = get_post_meta( $post_id, TIMED_CONTENT_RULE_POSTMETA_PREFIX . 'exceptions_dates' );
if ( false !== $exceptions_dates && isset( $exceptions_dates[0] ) && is_array( $exceptions_dates[0] ) ) {
$timed_content_rules_exceptions_dates = $exceptions_dates[0];
sort( $timed_content_rules_exceptions_dates, SORT_NUMERIC );
$timed_content_rules_exceptions_dates = array_unique( $timed_content_rules_exceptions_dates );
// If the exceptions are stored as timestamps, convert them to ISO first
$num = 0;
while ( $num < count( $timed_content_rules_exceptions_dates ) ) {
if ( is_numeric( $timed_content_rules_exceptions_dates[ $num ] ) ) {
$timed_content_rules_exceptions_dates[ $num ] = $this->format_timestamp( 'Y-m-d', $timed_content_rules_exceptions_dates[ $num ] );
}
$num++;
}
$timed_content_rules_exceptions_dates_array = array_combine( $timed_content_rules_exceptions_dates, $timed_content_rules_exceptions_dates );
} else {
$timed_content_rules_exceptions_dates_array = array( '0' => __( '- No exceptions set -', 'timed-content' ) );
}
$this->rule_occurrence_custom_fields = array(
array(
'name' => 'action',
'display' => 'block',
'title' => __( 'Action', 'timed-content' ),
'description' => __( 'Sets the action to be performed when the rule is active.', 'timed-content' ),
'type' => 'radio',
'values' => array(
'1' => __( 'Show the content', 'timed-content' ),
'0' => __( 'Hide the content', 'timed-content' ),
),
'default' => '1',
'scope' => array( TIMED_CONTENT_RULE_TYPE ),
'capability' => 'edit_posts',
),
array(
'name' => 'instance_start',
'display' => 'block',
'title' => __( 'Starting date/time', 'timed-content' ),
'description' => __( 'Sets the date and time for the beginning of the first active period for this rule.', 'timed-content' ),
'type' => 'datetime',
'default' => array(
'date' => $this->format_timestamp( 'Y-m-d', $now_plus1h_dt->getTimeStamp() ),
'time' => $this->format_timestamp( 'H:i', $now_plus1h_dt->getTimeStamp() ),
),
'scope' => array( TIMED_CONTENT_RULE_TYPE ),
'capability' => 'edit_posts',
),
array(
'name' => 'instance_end',
'display' => 'block',
'title' => __( 'Ending date/time', 'timed-content' ),
'description' => __( 'Sets the date and time for the end of the first active period for this rule.', 'timed-content' ),
'type' => 'datetime',
'default' => array(
'date' => $this->format_timestamp( 'Y-m-d', $now_plus2h_dt->getTimeStamp() ),
'time' => $this->format_timestamp( 'H:i', $now_plus2h_dt->getTimeStamp() ),
),
'scope' => array( TIMED_CONTENT_RULE_TYPE ),
'capability' => 'edit_posts',
),
array(
'name' => 'timezone',
'display' => 'block',
'title' => __( 'Timezone', 'timed-content' ),
'description' => __( 'Select the timezone you wish to use for this rule.', 'timed-content' ),
'type' => 'timezone-list',
'default' => get_option( 'timezone_string' ),
'scope' => array( TIMED_CONTENT_RULE_TYPE ),
'capability' => 'edit_posts',
),
);
$this->rule_pattern_custom_fields = array(
array(
'name' => 'frequency',
'display' => 'block',
'title' => __( 'Frequency', 'timed-content' ),
'description' => __( 'Sets the frequency at which the action should be repeated.', 'timed-content' ),
'type' => 'list',
'default' => '1',
'values' => $this->rule_freq_array,
'scope' => array( TIMED_CONTENT_RULE_TYPE ),
'capability' => 'edit_posts',
),
array(
'name' => 'hourly_num_of_hours',
'display' => 'none',
'title' => __( 'Interval of recurrences', 'timed-content' ),
'description' => __( 'Repeat this action every X hours.', 'timed-content' ),
'type' => 'number',
'default' => '1',
'min' => '1',
'scope' => array( TIMED_CONTENT_RULE_TYPE ),
'capability' => 'edit_posts',
),
array(
'name' => 'daily_num_of_days',
'display' => 'none',
'title' => __( 'Interval of recurrences', 'timed-content' ),
'description' => __( 'Repeat this action every X days.', 'timed-content' ),
'type' => 'number',
'default' => '1',
'min' => '1',
'scope' => array( TIMED_CONTENT_RULE_TYPE ),
'capability' => 'edit_posts',
),
array(
'name' => 'weekly_num_of_weeks',
'display' => 'none',
'title' => __( 'Interval of recurrences', 'timed-content' ),
'description' => __( 'Repeat this action every X weeks.', 'timed-content' ),
'type' => 'number',
'default' => '1',
'min' => '1',
'scope' => array( TIMED_CONTENT_RULE_TYPE ),
'capability' => 'edit_posts',
),
array(
'name' => 'weekly_days_of_week_to_repeat',
'display' => 'none',
'title' => __( 'Repeat on the following days', 'timed-content' ),
'description' => __( 'Repeat this action on these days of the week instead of the day of week the starting date/time falls on.', 'timed-content' ),
'type' => 'checkbox-list',
'default' => array(),
'values' => $this->rule_days_array,
'scope' => array( TIMED_CONTENT_RULE_TYPE ),
'capability' => 'edit_posts',
),
array(
'name' => 'monthly_num_of_months',
'display' => 'none',
'title' => __( 'Interval of recurrences', 'timed-content' ),
'description' => __( 'Repeat this action every X months.', 'timed-content' ),
'type' => 'number',
'default' => '1',
'min' => '1',
'scope' => array( TIMED_CONTENT_RULE_TYPE ),
'capability' => 'edit_posts',
),
array(
'name' => 'monthly_nth_weekday_of_month',
'display' => 'none',
'title' => __( 'Repeat on a specific weekday of the month', 'timed-content' ),
'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' ),
'type' => 'checkbox',
'default' => 'no',
'scope' => array( TIMED_CONTENT_RULE_TYPE ),
'capability' => 'edit_posts',
),
array(
'name' => 'monthly_nth_weekday_of_month_nth',
'display' => 'none',
'title' => __( 'Weekday ordinal', 'timed-content' ),
'description' => __( 'Select a value for week of the month (for example "first", "second", etc.). Please note, that "fifth" will skip months, where the day is not repeated five times!', 'timed-content' ),
'type' => 'list',
'default' => 0,
'values' => $this->rule_ordinal_array,
'scope' => array( TIMED_CONTENT_RULE_TYPE ),
'capability' => 'edit_posts',
),
array(
'name' => 'monthly_nth_weekday_of_month_weekday',
'display' => 'none',
'title' => __( 'Day of the week', 'timed-content' ),
'description' => __( 'Select the day of week.', 'timed-content' ),
'type' => 'list',
'default' => 0,
'values' => $this->rule_ordinal_days_array,
'scope' => array( TIMED_CONTENT_RULE_TYPE ),
'capability' => 'edit_posts',
),
array(
'name' => 'yearly_num_of_years',
'display' => 'none',
'title' => __( 'Interval of recurrences', 'timed-content' ),
'description' => __( 'Repeat this action every X years.', 'timed-content' ),
'type' => 'number',
'default' => '1',
'min' => '1',
'scope' => array( TIMED_CONTENT_RULE_TYPE ),
'capability' => 'edit_posts',
),
);
$this->rule_recurrence_custom_fields = array(
array(
'name' => 'recurrence_duration',
'display' => 'block',
'title' => __( 'How often to repeat this action', 'timed-content' ),
'description' => '',
'type' => 'radio',
'values' => array(
'recurrence_duration_end_date' => __( 'Keep repeating until a given date', 'timed-content' ),
'recurrence_duration_num_repeat' => __( 'Repeat a set number of times', 'timed-content' ),
),
'default' => 'recurrence_duration_end_date',
'scope' => array( TIMED_CONTENT_RULE_TYPE ),
'capability' => 'edit_posts',
),
array(
'name' => 'recurrence_duration_end_date',
'display' => 'none',
'title' => __( 'End Date', 'timed-content' ),
'description' => __( 'Using the settings above, repeat this action until this date.', 'timed-content' ),
'type' => 'date',
'default' => $this->format_timestamp( 'Y-m-d', $now_plus1y_dt->getTimeStamp() ),
'scope' => array( TIMED_CONTENT_RULE_TYPE ),
'capability' => 'edit_posts',
),
array(
'name' => 'recurrence_duration_num_repeat',
'display' => 'none',
'title' => __( 'Number of repetitions', 'timed-content' ),
'description' => __( 'Using the settings above, repeat this action this many times.', 'timed-content' ),
'type' => 'number',
'default' => '1',
'min' => '1',
'scope' => array( TIMED_CONTENT_RULE_TYPE ),
'capability' => 'edit_posts',
),
);
$this->rule_exceptions_custom_fields = array(
array(
'name' => 'exceptions_dates_picker',
'display' => 'block',
'title' => __( 'Add exception date:', 'timed-content' ),
'description' => __( 'Select a date to add to the exception dates list.', 'timed-content' ),
'type' => 'date',
'default' => '',
'scope' => array( TIMED_CONTENT_RULE_TYPE ),
'capability' => 'edit_posts',
),
array(
'name' => 'exceptions_dates',
'display' => 'block',
'title' => __( 'Exception dates list', 'timed-content' ),
'description' => __( 'Dates that this Timed Content rule will not be active. Double-click on a date to remove it from the list.', 'timed-content' ),
'type' => 'menu',
'values' => $timed_content_rules_exceptions_dates_array,
'size' => '10',
'default' => array(),
'scope' => array( TIMED_CONTENT_RULE_TYPE ),
'capability' => 'edit_posts',
),
);
$rule_description = '';
if ( isset( $_GET['post'] ) ) {
$post_id = intval( $_GET['post'] );
if ( get_post_type( $post_id ) === TIMED_CONTENT_RULE_TYPE ) {
$rule_description = $this->get_schedule_description_by_id( $post_id );
}
}
$scf = new CustomFieldsInterface(
'timed_content_rule_schedule',
__( 'Rule description/schedule', 'timed-content' ),
'',
TIMED_CONTENT_RULE_POSTMETA_PREFIX,
array( TIMED_CONTENT_RULE_TYPE ),
array(),
$this->jquery_ui_datetime_datepicker_i18n,
$this->jquery_ui_datetime_timepicker_i18n,
$rule_description
);
$ocf = new CustomFieldsInterface(
'timed_content_rule_initial_event',
__( 'Action/Initial Event', 'timed-content' ),
__( 'Set the action to be taken and when it should first run.', 'timed-content' ),
TIMED_CONTENT_RULE_POSTMETA_PREFIX,
array( TIMED_CONTENT_RULE_TYPE ),
$this->rule_occurrence_custom_fields,
$this->jquery_ui_datetime_datepicker_i18n,
$this->jquery_ui_datetime_timepicker_i18n
);
$pcf = new CustomFieldsInterface(
'timed_content_rule_recurrence',
__( 'Repeating Pattern', 'timed-content' ),
__( 'Set how often the action should repeat.', 'timed-content' ),
TIMED_CONTENT_RULE_POSTMETA_PREFIX,
array( TIMED_CONTENT_RULE_TYPE ),
$this->rule_pattern_custom_fields,
$this->jquery_ui_datetime_datepicker_i18n,
$this->jquery_ui_datetime_timepicker_i18n
);
$rcf = new CustomFieldsInterface(
'timed_content_rule_stop_condition',
__( 'Stopping Condition', 'timed-content' ),
__( 'Set how long or how many times the action should occur.', 'timed-content' ),
TIMED_CONTENT_RULE_POSTMETA_PREFIX,
array( TIMED_CONTENT_RULE_TYPE ),
$this->rule_recurrence_custom_fields,
$this->jquery_ui_datetime_datepicker_i18n,
$this->jquery_ui_datetime_timepicker_i18n
);
$ecf = new CustomFieldsInterface(
'timed_content_rule_exceptions',
__( 'Exceptions', 'timed-content' ),
__( 'Set up any exceptions to this Timed Content Rule.', 'timed-content' ),
TIMED_CONTENT_RULE_POSTMETA_PREFIX,
array( TIMED_CONTENT_RULE_TYPE ),
$this->rule_exceptions_custom_fields,
$this->jquery_ui_datetime_datepicker_i18n,
$this->jquery_ui_datetime_timepicker_i18n
);
}
/**
* Strips indices from an array
*/
function strip_array_indices( $array_to_strip ) {
foreach ( $array_to_strip as $array_item ) {
$new_array[] = $array_item;
}
return $new_array;
}
/**
* Convert dates and times to ISO format if needed
*/
function convert_date_time_parameters_to_iso( $args ) {
$date_parsed = date_create_from_format( 'Y-m-d', $args['instance_start']['date'] );
if ( false === $date_parsed ) {
$date_source = strtotime( $this->date_time_to_english( $args['instance_start']['date'] ) );
$args['instance_start']['date'] = $this->format_timestamp( 'Y-m-d', $date_source );
}
$date_parsed = date_create_from_format( 'Y-m-d', $args['instance_end']['date'] );
if ( false === $date_parsed ) {
$date_source = strtotime( $this->date_time_to_english( $args['instance_end']['date'] ) );
$args['instance_end']['date'] = $this->format_timestamp( 'Y-m-d', $date_source );
}
$args['instance_start']['time'] = $this->convert_time_to_iso( $args['instance_start']['time'] );
$args['instance_end']['time'] = $this->convert_time_to_iso( $args['instance_end']['time'] );
$date_parsed = date_create_from_format( 'Y-m-d', $args['end_date'] );
if ( false === $date_parsed ) {
$date_source = strtotime( $this->date_time_to_english( $args['end_date'] ) );
$args['end_date'] = $this->format_timestamp( 'Y-m-d', $date_source );
}
if ( is_array( $args['exceptions_dates'] ) ) {
foreach ( $args['exceptions_dates'] as $key => $value ) {
$date_parsed = date_create_from_format( 'Y-m-d', $value );
if ( false === $date_parsed ) {
$date_source = strtotime( $this->date_time_to_english( $args['end_date'] ) );
$args['exceptions_dates'][ $key ] = $this->format_timestamp( 'Y-m-d', $date_source );
}
}
}
return $args;
}
/**
* Convert time to ISO format if needed
*/
function convert_time_to_iso( $time ) {
if ( strpos( $time, 'AM' ) !== false ) {
$time_base = trim( substr( $time, 0, strlen( $time ) - 2 ) );
$time_dt = date_create_from_format( 'G:i', $time_base );
if ( false !== $time_dt ) {
$time = $this->format_timestamp( 'H:i', $time_dt->getTimestamp() );
}
} elseif ( strpos( $time, 'PM' ) !== false ) {
$time_base = trim( substr( $time, 0, strlen( $time ) - 2 ) );
$time_dt = date_create_from_format( 'G:i', $time_base );
if ( false !== $time_dt ) {
$time = $this->format_timestamp( 'H:i', $time_dt->getTimestamp() + 43200 );
}
}
return $time;
}
/**
* Set the timezone to be used for format_date()
*/
function set_format_timezone( $timezone ) {
$this->current_timezone = new DateTimeZone( $timezone );
if ( false === $this->current_timezone ) {
$this->current_timezone = new DateTimeZone( 'UTC' );
}
}
/**
* Get the timezone to be used for format_date()
*/
function get_format_timezone() {
return $this->current_timezone;
}
/**
* Format a given timestamp with the specified timezone
*/
function format_timestamp( $format, $timestamp ) {
try {
$dt = new DateTime();
$dt->setTimestamp( $timestamp );
$dt->setTimezone( $this->current_timezone );
} catch ( Exception $e ) {
return '';
}
return $dt->format( $format );
}
}