Example #1
0
/**
 * Update recurring event dates
 *
 * @since 0.9
 */
function ctc_update_recurring_event_dates()
{
    // Get all events with end date in past and have valid recurring value
    $events_query = new WP_Query(array('post_type' => 'ctc_event', 'nopaging' => true, 'meta_query' => array('relation' => 'AND', array('key' => '_ctc_event_end_date', 'value' => date_i18n('Y-m-d'), 'compare' => '<', 'type' => 'DATE'), array('key' => '_ctc_event_recurrence', 'value' => array('weekly', 'monthly', 'yearly'), 'compare' => 'IN'))));
    // Loop events
    if (!empty($events_query->posts)) {
        // Instantiate recurrence class
        $ctc_recurrence = new CT_Recurrence();
        // Loop events to modify dates
        foreach ($events_query->posts as $post) {
            // Get start and end date
            $start_date = get_post_meta($post->ID, '_ctc_event_start_date', true);
            $end_date = get_post_meta($post->ID, '_ctc_event_end_date', true);
            // Get recurrence
            $recurrence = get_post_meta($post->ID, '_ctc_event_recurrence', true);
            $recurrence_end_date = get_post_meta($post->ID, '_ctc_event_recurrence_end_date', true);
            // Difference between start and end date in seconds
            $time_difference = strtotime($end_date) - strtotime($start_date);
            // Get soonest occurence that is today or later
            $args = array('start_date' => $start_date, 'frequency' => $recurrence);
            $args = apply_filters('ctc_event_recurrence_args', $args, $post);
            // Custom Recurring Events add-on uses this
            $new_start_date = $ctc_recurrence->calc_next_future_date($args);
            // If no new start date gotten, set it to current start date
            // This could be because recurrence ended, arguments are invalid, etc.
            if (!$new_start_date) {
                $new_start_date = $start_date;
            }
            // Add difference between original start/end date to new start date to get new end date
            $new_end_date = date('Y-m-d', strtotime($new_start_date) + $time_difference);
            // Has recurrence ended?
            // Recurrence end date exists and is earlier than new start date
            if ($recurrence_end_date && strtotime($recurrence_end_date) < strtotime($new_start_date)) {
                // Unset recurrence option to keep dates from being moved forward
                update_post_meta($post->ID, '_ctc_event_recurrence', 'none');
            } else {
                // Update start and end dates
                update_post_meta($post->ID, '_ctc_event_start_date', $new_start_date);
                update_post_meta($post->ID, '_ctc_event_end_date', $new_end_date);
                // Update the hidden datetime fields for ordering
                ctc_update_event_date_time($post->ID);
            }
        }
    }
}
/**
 * Event calendar data
 *
 * Returns a month's headings, weeks, days and events for use in rendering an HTML calendar.
 * Considers start day of week in Settings > General and localization.
 *
 * @param array $args Arguments for year, month, etc.
 * @return array Array with days of weeks, weeks with days and days with events
 */
function ctfw_event_calendar_data($args)
{
    // Arguments
    $args = wp_parse_args($args, array('year_month' => '', 'get_events' => true, 'category' => '', 'recurrence_limit' => 160));
    // Extract arguments for easy use
    extract($args);
    // Date format
    $date_format = get_option('date_format');
    // Start calendar data array
    $calendar = array();
    // Get $year, $month and $month_ts, validated
    // If invalid date passed, current month/year used
    // This also removed preceding 0 from month
    $calendar['month_data'] = ctfw_event_calendar_month_data($year_month);
    extract($calendar['month_data']);
    // Get today
    $today = date_i18n('Y-m-d');
    $today_ts = strtotime($today);
    // Days in the month
    $days_in_month = date_i18n('t', $month_ts);
    // Get day of week for first day of month (0 - 6 representing Sunday - Saturday)
    // This is useful for determining where to start the calendar
    $first_day_in_month_ts = mktime(0, 0, 0, $month, 1, $year);
    $first_day_in_month_info = getdate($first_day_in_month_ts);
    $first_day_in_month_day_of_week = $first_day_in_month_info['wday'];
    // Previous month
    $previous_month_days = date_i18n('t', $first_day_in_month_ts - DAY_IN_SECONDS);
    // Build days of week array
    // Make start of week first in array
    $days_of_week = array();
    // Place days of week in array
    // Using first week of month specifically so can determine localized day of week names
    for ($day_in_month = 1; $day_in_month <= 7; $day_in_month++) {
        // This day's info
        $day_in_month_ts = mktime(0, 0, 0, $month, $day_in_month, $year);
        $day_in_month_info = getdate($day_in_month_ts);
        $day_in_month_day_of_week = $day_in_month_info['wday'];
        // Numeric day of week
        $days_of_week[$day_in_month_day_of_week]['numeric'] = $day_in_month_day_of_week;
        // on 0 - 6 scake
        $days_of_week[$day_in_month_day_of_week]['numeric_friendly'] = $day_in_month_day_of_week + 1;
        // on 1 - 7 scale
        // Localized names
        $days_of_week[$day_in_month_day_of_week]['name'] = date_i18n('l', $day_in_month_ts);
        $days_of_week[$day_in_month_day_of_week]['name_short'] = date_i18n('D', $day_in_month_ts);
    }
    // Sort by day of week 0 - 6
    ksort($days_of_week);
    // Change start of week (e.g. Monday instead of Sunday)
    // Settings > General controls this
    $start_of_week = get_option('start_of_week');
    // Day week starts on; numeric (0 - 6 representing Sunday - Saturday)
    $removed_days = array_splice($days_of_week, $start_of_week);
    // remove days before new first day from front
    $days_of_week = array_merge($removed_days, $days_of_week);
    // move them to end to effect new first day of week
    // Add to calendar array
    $calendar['days_of_week'] = $days_of_week;
    // Loop days of month to build rows
    $day = 1;
    $week = 0;
    $day_of_week = $first_day_in_month_day_of_week;
    $day_of_week = $day_of_week - $start_of_week;
    if ($day_of_week < 0) {
        $day_of_week = 7 + $day_of_week;
    }
    while ($day <= $days_in_month) {
        // Add day to array
        $calendar['weeks'][$week]['days'][$day_of_week] = array('day' => $day, 'month' => $month, 'year' => $year, 'other_month' => false);
        // Increment day, day of week and week
        $day++;
        if ($day_of_week == 6) {
            $week++;
            // next week/row
            $day_of_week = 0;
            // start week over on first day
        } else {
            $day_of_week++;
            // increment day
        }
    }
    // Fill in days from last month for first row
    $last_month_ts = $month_ts - DAY_IN_SECONDS;
    // timestamp is first of month so subtract one day
    $last_month_ts = strtotime(date_i18n('Y-m-d', $last_month_ts));
    // make it first second of first day of month for consistency
    $last_month = date_i18n('n', $last_month_ts);
    $last_month_year = date_i18n('Y', $last_month_ts);
    $first_row_missing_days = 7 - count($calendar['weeks'][0]['days']);
    $day_of_week = 0;
    if ($first_row_missing_days) {
        // Days in last month
        $days_in_last_month = date_i18n('t', $last_month_ts);
        // Add last days of last month to first row (week) in calendar
        $last_month_start_day = $days_in_last_month - $first_row_missing_days + 1;
        for ($day = $last_month_start_day; $day <= $days_in_last_month; $day++) {
            // Add day to array
            $calendar['weeks'][0]['days'][$day_of_week] = array('day' => $day, 'month' => $last_month, 'year' => $last_month_year, 'other_month' => true);
            $day_of_week++;
        }
        // Sort by day of week 0 - 6
        ksort($calendar['weeks'][0]['days']);
    }
    // Fill in days from next month for last row
    $next_month_ts = $month_ts + DAY_IN_SECONDS * 32;
    // this will always push into the next month
    $next_month_ts = strtotime(date_i18n('Y-m-d', $next_month_ts));
    // make it first second of first day of month for consistency
    $next_month = date_i18n('n', $next_month_ts);
    $next_month_year = date_i18n('Y', $next_month_ts);
    $last_row = count($calendar['weeks']) - 1;
    $next_month_last_day_of_week = count($calendar['weeks'][$last_row]['days']) - 1;
    $last_row_missing_days = 6 - $next_month_last_day_of_week;
    $day_of_week = $next_month_last_day_of_week;
    // start incrementing from last day's day of week
    if ($last_row_missing_days) {
        // Add first days of next month to last row (week) in calendar
        $next_month_stop_day = $last_row_missing_days;
        for ($day = 1; $day <= $next_month_stop_day; $day++) {
            // Increment day of week (picks up off of last day of week)
            $day_of_week++;
            // Add day to array
            $calendar['weeks'][$last_row]['days'][$day_of_week] = array('day' => $day, 'month' => $next_month, 'year' => $next_month_year, 'other_month' => true);
        }
    }
    // Add additional data to each day
    foreach ($calendar['weeks'] as $week_key => $week) {
        foreach ($week['days'] as $day_key => $day) {
            $date = date_i18n('Y-m-d', mktime(0, 0, 0, $day['month'], $day['day'], $day['year']));
            $date_ts = strtotime($date);
            $date_formatted = date_i18n($date_format, $date_ts);
            $calendar['weeks'][$week_key]['days'][$day_key]['date'] = $date;
            $calendar['weeks'][$week_key]['days'][$day_key]['date_ts'] = $date_ts;
            $calendar['weeks'][$week_key]['days'][$day_key]['date_formatted'] = $date_formatted;
            $last_of_previous_month = false;
            if ($day['other_month'] && $previous_month_days == $day['day']) {
                $last_of_previous_month = true;
            }
            $calendar['weeks'][$week_key]['days'][$day_key]['last_of_previous_month'] = $last_of_previous_month;
            $first_of_next_month = false;
            if ($day['other_month'] && 1 == $day['day']) {
                $first_of_next_month = true;
            }
            $calendar['weeks'][$week_key]['days'][$day_key]['first_of_next_month'] = $first_of_next_month;
            if ($args['get_events']) {
                $calendar['weeks'][$week_key]['days'][$day_key]['event_ids'] = array();
            }
        }
    }
    // Get events for days in calendar array
    if ($args['get_events']) {
        $calendar['events'] = array();
        // First date is today
        // Today is useful for months in future, because recurrence is caught up and can project into future
        // We also do not get events that are in past for current month
        $first_date_ts = $today_ts;
        $first_date = date_i18n('Y-m-d', $first_date_ts);
        // Last date is one week into next month
        // Some months will show the first days of the next month in calendar
        // We don't need events beyond that because nothing is calculated backwards
        // Backwards compatibility
        // Church Theme Content added rigid time fields in version 1.2
        // Continue ordering by old field for old versions of plugin
        $meta_type = 'DATETIME';
        // 0000-00-00 00:00:00
        $meta_key = '_ctc_event_start_date_start_time';
        // order by this
        if (defined('CTC_VERSION') && version_compare(CTC_VERSION, '1.2', '<')) {
            // CTC plugin is active and old
            $meta_type = 'DATE';
            // 0000-00-00
            $meta_key = '_ctc_event_start_date';
            // order by this; want earliest starting date/time first
        }
        // Arguments
        $query_args = array('post_type' => 'ctc_event', 'numberposts' => -1, 'meta_query' => array(array('key' => '_ctc_event_end_date', 'value' => $first_date, 'compare' => '>=', 'type' => 'DATE')), 'meta_key' => $meta_key, 'meta_type' => $meta_type, 'orderby' => 'meta_value', 'order' => 'ASC', 'suppress_filters' => false);
        // Filter by category if not all
        if (!empty($args['category'])) {
            $query_args['ctc_event_category'] = $args['category'];
        }
        // Get events
        $events = get_posts($query_args);
        // Prepare for recurrence calculations
        $ctfw_recurrence = new CT_Recurrence();
        // Loop events
        foreach ($events as $event) {
            // Get meta data
            $event_data = ctfw_event_data($event->ID);
            // friendly data
            // Prepare to capture every day event occurs on
            $event_dates = array();
            // Add Start Date to array
            $event_dates[] = $event_data['start_date'];
            // Recurring event?
            if ($event_data['recurrence'] && $event_data['recurrence'] != 'none') {
                // Recurrence interval
                $interval = 1;
                if ('weekly' == $event_data['recurrence']) {
                    $interval = $event_data['recurrence_weekly_interval'];
                } elseif ('monthly' == $event_data['recurrence']) {
                    $interval = $event_data['recurrence_monthly_interval'];
                }
                // Until date
                // This is either 38 days from first of month (+ 7 for first week of next, which may show)
                // Or, the recurrence end date if earlier
                $DateTime = new DateTime($first_of_month);
                $DateTime->modify('+38 days');
                $until_date = $DateTime->format('Y-m-d');
                // PHP 5.2 cannot chain methods
                if (!empty($event_data['recurrence_end_date']) && $event_data['recurrence_end_date'] < $until_date) {
                    $until_date = $event_data['recurrence_end_date'];
                }
                // Calculate future occurences of Start Date
                $recurrence_args = array('start_date' => $event_data['start_date'], 'until_date' => $until_date, 'frequency' => $event_data['recurrence'], 'interval' => $interval, 'monthly_type' => $event_data['recurrence_monthly_type'], 'monthly_week' => $event_data['recurrence_monthly_week'], 'limit' => $recurrence_limit);
                $calculated_dates = $ctfw_recurrence->get_dates($recurrence_args);
                // Add calculated dates to array
                $event_dates = array_merge($event_dates, $calculated_dates);
            }
            // Event is on multiple days
            if ($event_data['start_date'] != $event_data['end_date']) {
                // Loop all occurences of Start Date
                foreach ($event_dates as $date) {
                    // Add X days to Start Date to complete the range for all occurences
                    $while_date = $event_data['start_date'];
                    $WhileDateTime = new DateTime($while_date);
                    $DateTime = new DateTime($date);
                    while ($while_date <= $event_data['end_date']) {
                        // loop dates in original range
                        // Add date to array if today or future
                        // And is not beyond event's recur until date
                        if (strtotime($date) >= $today_ts && (!$event_data['recurrence_end_date'] || strtotime($date) <= strtotime($event_data['recurrence_end_date']))) {
                            $event_dates[] = $date;
                        }
                        // Move to next day
                        $WhileDateTime->modify('+1 day');
                        $while_date = $WhileDateTime->format('Y-m-d');
                        // PHP 5.2 cannot chain methods
                        $DateTime->modify('+1 day');
                        $date = $DateTime->format('Y-m-d');
                        // PHP 5.2 cannot chain methods
                    }
                }
            }
            // Remove duplicate dates
            $event_dates = array_unique($event_dates);
            // Store event ID in days for which it occurs
            // This is so can reference event from other array
            foreach ($calendar['weeks'] as $week_key => $week) {
                // Loop days in week
                foreach ($week['days'] as $day_key => $day) {
                    // Event occurs on this day
                    if (in_array($day['date'], $event_dates)) {
                        // Add event ID to day
                        $calendar['weeks'][$week_key]['days'][$day_key]['event_ids'][] = $event->ID;
                        // Add event to separate array, if doesn't already exist
                        // This array can be referenced so multiple events not added per month, just IDs
                        if (!isset($calendar['events'][$event->ID])) {
                            $calendar['events'][$event->ID]['post'] = $event;
                            $calendar['events'][$event->ID]['data'] = $event_data;
                        }
                    }
                }
            }
        }
        // Re-order events on each day earliest to latest and events with no time first (likely means all day / major event)
        // This considers that future occurences may have been injected so times are not in same order as original query
        foreach ($calendar['weeks'] as $week_key => $week) {
            // Loop days in week
            foreach ($week['days'] as $day_key => $day) {
                // Make new ID's array with keys to order by re-order events in
                $event_ids = array();
                foreach ($day['event_ids'] as $event_id) {
                    // Get event
                    $event = $calendar['events'][$event_id];
                    // Make key to order by
                    // In effect this sorts ascending primarily by start time then secondarily by ID (date of entry)
                    $order_key = $event['data']['start_time'];
                    if (empty($order_key)) {
                        $order_key = '00:00';
                        // if has no time value; backwards compatibility (CTC < 1.2)
                    }
                    $order_key .= ' ' . str_pad($event_id, 12, '0', STR_PAD_LEFT);
                    // for uniqueness and secondary ordering
                    // Add to array to be re-ordered
                    $event_ids[$order_key] = $event_id;
                }
                // Re-order events and remove ordering keys from array
                ksort($event_ids);
                $event_ids = array_values($event_ids);
                // Replace ID's array with array in new order
                $calendar['weeks'][$week_key]['days'][$day_key]['event_ids'] = $event_ids;
            }
        }
    }
    // DEBUG
    //ctfw_print_array( $calendar );
    // Filter
    $calendar = apply_filters('ctfw_event_calendar_data', $calendar, $args);
    return $calendar;
}