/** * 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; }