/** * Generates an excerpt from the given content string. * * Adapted from WordPress's `wp_trim_excerpt' function that is not useful * for applying to custom content. * * @param string $text The content to trim. * * @return string The excerpt. */ public function trim_excerpt(Ai1ec_Event $event, $length = 35, $more = '[...]') { global $post; $original_post = $post; $post = $event->get('post'); $raw_excerpt = $event->get('post')->post_content; if (!isset($raw_excerpt[0])) { $raw_excerpt = ' '; } $text = preg_replace('#<\\s*script[^>]*>.+<\\s*/\\s*script\\s*>#x', '', apply_filters('the_excerpt', $raw_excerpt)); $text = strip_shortcodes($text); $text = str_replace(']]>', ']]>', $text); $text = strip_tags($text); $excerpt_length = apply_filters('excerpt_length', $length); $excerpt_more = apply_filters('excerpt_more', $more); $words = preg_split('/\\s+/', $text, $excerpt_length + 1, PREG_SPLIT_NO_EMPTY); if (count($words) > $excerpt_length) { array_pop($words); $text = implode(' ', $words); $text = $text . $excerpt_more; } else { $text = implode(' ', $words); } $post = $original_post; return apply_filters('wp_trim_excerpt', $text, $raw_excerpt); }
/** * Render the full article for the event * * @param Ai1ec_Event $event */ public function get_full_article(Ai1ec_Event $event) { $title = apply_filters('the_title', $event->get('post')->post_title, $event->get('post_id')); $content = $this->get_content($event) . wpautop(apply_filters('ai1ec_the_content', apply_filters('the_content', $event->get('post')->post_content))); $args = compact('title', 'content'); $loader = $this->_registry->get('theme.loader'); return $loader->get_file('event-single-full.twig', $args, false)->get_content(); }
/** * Faded version of event category color */ protected function _get_color(Ai1ec_Event $event, $type) { static $categories_cache = array('rgba' => array(), 'faded' => array()); $methods = array('rgba' => 'get_event_category_rgba_color', 'faded' => 'get_event_category_faded_color'); $categories = $this->_registry->get('model.taxonomy')->get_post_categories($event->get('post_id')); if (!empty($categories)) { if (!isset($categories_cache[$type][$categories[0]->term_id])) { $method = $methods[$type]; $categories_cache[$type][$categories[0]->term_id] = $this->{$method}($categories[0]->term_id); } return $categories_cache[$type][$categories[0]->term_id]; } return ''; }
/** * Contact info as HTML */ public function get_contact_html(Ai1ec_Event $event) { $contact = ''; if ($event->get('contact_name')) { $contact .= '<div class="ai1ec-contact-name">' . '<i class="ai1ec-fa ai1ec-fa-fw ai1ec-fa-user"></i> ' . esc_html($event->get('contact_name')) . '</div> '; } if ($event->get('contact_phone')) { $contact .= '<div class="ai1ec-contact-phone">' . '<i class="ai1ec-fa ai1ec-fa-fw ai1ec-fa-phone"></i> ' . esc_html($event->get('contact_phone')) . '</div> '; } if ($event->get('contact_email')) { $contact .= '<div class="ai1ec-contact-email">' . '<a href="mailto:' . esc_attr($event->get('contact_email')) . '">' . '<i class="ai1ec-fa ai1ec-fa-fw ai1ec-fa-envelope-o"></i> ' . __('Email', AI1EC_PLUGIN_NAME) . '</a></div> '; } if ($event->get('contact_url')) { $contact .= '<div class="ai1ec-contact-url">' . '<a target="_blank" href="' . esc_attr($event->get('contact_url')) . '"><i class="ai1ec-fa ai1ec-fa-fw ai1ec-fa-link"></i> ' . apply_filters('ai1ec_contact_url', __('Event website', AI1EC_PLUGIN_NAME)) . ' <i class="ai1ec-fa ai1ec-fa-external-link"></i></a></div>'; } return $contact; }
/** * Renders the html of the page and returns it. * * @param Ai1ec_Event $event * * @return string the html of the page */ public function get_content(Ai1ec_Event $event) { $settings = $this->_registry->get('model.settings'); $rrule = $this->_registry->get('recurrence.rule'); $taxonomy = $this->_registry->get('view.event.taxonomy'); $location = $this->_registry->get('view.event.location'); $ticket = $this->_registry->get('view.event.ticket'); $content = $this->_registry->get('view.event.content'); $time = $this->_registry->get('view.event.time'); $subscribe_url = AI1EC_EXPORT_URL . '&ai1ec_post_ids=' . $event->get('post_id'); $event->set_runtime('tickets_url_label', $ticket->get_tickets_url_label($event, false)); $event->set_runtime('content_img_url', $content->get_content_img_url($event)); $extra_buttons = apply_filters('ai1ec_rendering_single_event_actions', '', $event); $venues_html = apply_filters('ai1ec_rendering_single_event_venues', nl2br($location->get_location($event)), $event); // objects are passed by reference so an action is ok do_action('ai1ec_single_event_page_before_render', $event); $args = array('event' => $event, 'recurrence' => $rrule->rrule_to_text($event->get('recurrence_rules')), 'exclude' => $time->get_exclude_html($event, $rrule), 'categories' => $taxonomy->get_categories_html($event), 'tags' => $taxonomy->get_tags_html($event), 'location' => $venues_html, 'map' => $location->get_map_view($event), 'contact' => $ticket->get_contact_html($event), 'back_to_calendar' => $content->get_back_to_calendar_button_html(), 'subscribe_url' => $subscribe_url, 'subscribe_url_no_html' => $subscribe_url . '&no_html=true', 'edit_instance_url' => null, 'edit_instance_text' => null, 'google_url' => 'http://www.google.com/calendar/render?cid=' . urlencode($subscribe_url), 'show_subscribe_buttons' => !$settings->get('turn_off_subscription_buttons'), 'hide_featured_image' => $settings->get('hide_featured_image'), 'extra_buttons' => $extra_buttons, 'text_add_calendar' => __('Add to Calendar', AI1EC_PLUGIN_NAME), 'subscribe_buttons_text' => $this->_registry->get('view.calendar.subscribe-button')->get_labels(), 'text_when' => __('When:', AI1EC_PLUGIN_NAME), 'text_where' => __('Where:', AI1EC_PLUGIN_NAME), 'text_cost' => __('Cost:', AI1EC_PLUGIN_NAME), 'text_contact' => __('Contact:', AI1EC_PLUGIN_NAME), 'text_free' => __('Free', AI1EC_PLUGIN_NAME), 'text_categories' => __('Categories', AI1EC_PLUGIN_NAME), 'text_tags' => __('Tags', AI1EC_PLUGIN_NAME)); if (!empty($args['recurrence']) && $event->get('instance_id') && current_user_can('edit_ai1ec_events')) { $args['edit_instance_url'] = admin_url('post.php?post=' . $event->get('post_id') . '&action=edit&instance=' . $event->get('instance_id')); $args['edit_instance_text'] = sprintf(Ai1ec_I18n::__('Edit this occurrence (%s)'), $event->get('start')->format_i18n('M j')); } $loader = $this->_registry->get('theme.loader'); return $loader->get_file('event-single.twig', $args, false)->get_content(); }
/** * Parse the fields of an Event to the structure used by API */ protected function _parse_event_fields_to_api_structure(Ai1ec_Event $event, WP_Post $post, $post_ticket_types, $api_fields_values) { $calendar_id = $this->_get_ticket_calendar(); if ($calendar_id <= 0) { return null; } //fields of ai1ec events table used by API $body['latitude'] = $event->get('latitude'); $body['longitude'] = $event->get('longitude'); $body['post_id'] = $event->get('post_id'); $body['calendar_id'] = $calendar_id; $body['dtstart'] = $event->get('start')->format_to_javascript(); $body['dtend'] = $event->get('end')->format_to_javascript(); $body['timezone'] = $event->get('timezone_name'); $body['venue_name'] = $event->get('venue'); $body['address'] = $event->get('address'); $body['city'] = $event->get('city'); $body['province'] = $event->get('province'); $body['postal_code'] = $event->get('postal_code'); $body['country'] = $event->get('country'); $body['contact_name'] = $event->get('contact_name'); $body['contact_phone'] = $event->get('contact_phone'); $body['contact_email'] = $event->get('contact_email'); $body['contact_website'] = $event->get('contact_url'); $body['uid'] = $event->get('ical_uid'); $body['title'] = $post->post_title; $body['description'] = $post->post_content; $body['url'] = get_permalink($post->ID); $body['status'] = $post->post_status; $body['tax_rate'] = 0; $utc_current_time = $this->_registry->get('date.time')->format_to_javascript(); $body['created_at'] = $utc_current_time; $body['updated_at'] = $utc_current_time; //removing blank values foreach ($body as $key => $value) { if (ai1ec_is_blank($value)) { unset($body[$key]); } } if (null !== $api_fields_values && is_array($api_fields_values)) { foreach ($api_fields_values as $key => $value) { $body[$key] = $api_fields_values[$key]; if ('visibility' === $key) { if (0 === strcasecmp('private', $value)) { $body['status'] = 'private'; } else { if (0 === strcasecmp('password', $value)) { $body['status'] = 'password'; } } } } } $tickets_types = array(); if (isset($post_ticket_types)) { $index = 0; foreach ($post_ticket_types as $ticket_type_ite) { if (false === isset($ticket_type_ite['id']) && isset($ticket_type_ite['remove'])) { //ignoring new tickets that didn't go to api yet continue; } $tickets_types[$index++] = $this->_parse_tickets_type_post_to_api_structure($ticket_type_ite, $event); } } $body['ticket_types'] = $tickets_types; return $body; }
/** * Returns the latitude/longitude coordinates as a textual string * parsable by the Geocoder API. * * @param Ai1ec_Event &$event The event to return data from * * @return string The latitude & longitude string, or null */ public function get_latlng(Ai1ec_Event $event) { // If the coordinates are set, use those, otherwise use the address. $location = NULL; // If the coordinates are set by hand use them. if ($event->get('show_coordinates')) { $longitude = floatval($event->get('longitude')); $latitude = floatval($event->get('latitude')); $location = $latitude . ',' . $longitude; } return $location; }
/** * Generate and store instance entries in database for given event. * * @param Ai1ec_Event $event Instance of event to create entries for. * * @return bool Success. */ protected function _create_instances_collection(Ai1ec_Event $event) { $events = array(); $event_item = array('post_id' => $event->get('post_id'), 'start' => $event->get('start')->format_to_gmt(), 'end' => $event->get('end')->format_to_gmt()); $duration = $event->get('end')->diff_sec($event->get('start')); $_start = $event->get('start')->format_to_gmt(); $_end = $event->get('end')->format_to_gmt(); // Always cache initial instance $events[$_start] = $event_item; if ($event->get('recurrence_rules') || $event->get('recurrence_dates')) { $start_timezone = $this->_registry->get('model.option')->get('timezone_string'); $events += $this->create_instances_by_recurrence($event, $event_item, $_start, $duration, $start_timezone); } $search_helper = $this->_registry->get('model.search'); foreach ($events as &$event_item) { // Find out if this event instance is already accounted for by an // overriding 'RECURRENCE-ID' of the same iCalendar feed (by comparing the // UID, start date, recurrence). If so, then do not create duplicate // instance of event. $start = $event_item['start']; $matching_event_id = null; if ($event->get('ical_uid')) { $matching_event_id = $search_helper->get_matching_event_id($event->get('ical_uid'), $event->get('ical_feed_url'), $event->get('start'), false, $event->get('post_id')); } // If no other instance was found if (null !== $matching_event_id) { $event_item = false; } } return array_filter($events); }
/** * Read post meta for post-attachment and return its URL as a string. * * @param Ai1ec_Event $event Event object. * @param array $ordered_img_sizes Image sizes order. * @param null $size (width, height) array of returned * image. * * @return string|null */ protected function _get_post_attachment_url(Ai1ec_Event $event, array $ordered_img_sizes, &$size = null) { // Since WP does will return null if the wrong size is targeted, // we iterate over an array of sizes, breaking if a URL is found. foreach ($ordered_img_sizes as $size) { $attributes = wp_get_attachment_image_src(get_post_thumbnail_id($event->get('post_id')), $size); if ($attributes) { $url = array_shift($attributes); $size = $attributes; break; } } return empty($url) ? null : $url; }
/** * Adds runtime properties to the event. * * @param Ai1ec_Event $event */ protected function _add_runtime_properties(Ai1ec_Event $event) { global $post; $original_post = $post; $post = $event->get('post'); $instance_permalink = get_permalink($event->get('post_id')); $instance_permalink = add_query_arg('instance_id', $event->get('instance_id'), $instance_permalink); $event->set_runtime('instance_permalink', $instance_permalink); $event->set_runtime('filtered_title', apply_filters('the_title', $event->get('post')->post_title, $event->get('post_id'), true)); $calendar_state = $this->_registry->get('calendar.state'); $calendar_state->set_append_content(false); $event->set_runtime('filtered_content', apply_filters('ai1ec_the_content', apply_filters('the_content', $event->get('post')->post_content))); $calendar_state->set_append_content(true); $taxonomy = $this->_registry->get('view.event.taxonomy'); $ticket = $this->_registry->get('view.event.ticket'); $event->set_runtime('color_style', $taxonomy->get_color_style($event)); $event->set_runtime('category_colors', $taxonomy->get_category_colors($event)); $event->set_runtime('ticket_url_label', $ticket->get_tickets_url_label($event, false)); $event->set_runtime('edit_post_link', get_edit_post_link($event->get('post_id'))); $event_post = $this->_registry->get('view.event.post'); $event->set_runtime('post_excerpt', $event_post->trim_excerpt($event)); $color = $this->_registry->get('view.event.color'); $event->set_runtime('faded_color', $color->get_faded_color($event)); $event->set_runtime('rgba_color', $color->get_rgba_color($event)); $event->set_runtime('short_start_time', $this->_registry->get('view.event.time')->get_short_time($event->get('start'))); $this->_add_view_specific_runtime_properties($event); $post = $original_post; }
/** * Convert an event from a feed into a new Ai1ec_Event object and add it to * the calendar. * * @param Ai1ec_Event $event Event object. * @param vcalendar $calendar Calendar object. * @param bool $export States whether events are created for export. * @param array $params Additional parameters for export. * * @return void */ protected function _insert_event_in_calendar(Ai1ec_Event $event, vcalendar $calendar, $export = false, array $params = array()) { $tz = $this->_registry->get('date.timezone')->get_default_timezone(); $e =& $calendar->newComponent('vevent'); $uid = ''; if ($event->get('ical_uid')) { $uid = addcslashes($event->get('ical_uid'), "\\;,\n"); } else { $uid = $event->get_uid(); $event->set('ical_uid', $uid); $event->save(true); } $e->setProperty('uid', $this->_sanitize_value($uid)); $e->setProperty('url', get_permalink($event->get('post_id'))); // ========================= // = Summary & description = // ========================= $e->setProperty('summary', $this->_sanitize_value(html_entity_decode(apply_filters('the_title', $event->get('post')->post_title), ENT_QUOTES, 'UTF-8'))); $content = apply_filters('ai1ec_the_content', apply_filters('the_content', $event->get('post')->post_content)); $post_meta_values = get_post_meta($event->get('post_id'), '', false); $cost_type = null; if ($post_meta_values) { foreach ($post_meta_values as $key => $value) { if ('_ai1ec_cost_type' === $key) { $cost_type = $value[0]; } if (isset($params['xml']) && $params['xml'] && false !== preg_match('/^x\\-meta\\-/i', $key)) { $e->setProperty($key, $this->_sanitize_value($value)); } } } if (false === ai1ec_is_blank($cost_type)) { $e->setProperty('X-COST-TYPE', $this->_sanitize_value($cost_type)); } $url = ''; $api = $this->_registry->get('model.api.api-ticketing'); $api_event_id = $api->get_api_event_id($event->get('post_id')); if ($api_event_id) { //getting all necessary informations that will be necessary on imported ticket events $e->setProperty('X-API-EVENT-ID', $api_event_id); $e->setProperty('X-API-URL', $api->get_api_event_url($event->get('post_id'))); $e->setProperty('X-CHECKOUT-URL', $api->get_api_event_checkout_url($event->get('post_id'))); $e->setProperty('X-API-EVENT-CURRENCY', $api->get_api_event_currency($event->get('post_id'))); } else { if ($event->get('ticket_url')) { $url = $event->get('ticket_url'); } } //Adding Ticket URL to the Description field if (false === ai1ec_is_blank($url)) { $content = $this->_remove_ticket_url($content); $content = $content . '<p>' . __('Tickets: ', AI1EC_PLUGIN_NAME) . '<a class="ai1ec-ticket-url-exported" href="' . $url . '">' . $url . '</a>.</p>'; } $content = str_replace(']]>', ']]>', $content); $content = html_entity_decode($content, ENT_QUOTES, 'UTF-8'); // Prepend featured image if available. $size = null; $avatar = $this->_registry->get('view.event.avatar'); $matches = $avatar->get_image_from_content($content); // if no img is already present - add thumbnail if (empty($matches)) { $post_id = get_post_thumbnail_id($event->get('post_id')); $images = null; $added = null; foreach (array('thumbnail', 'medium', 'large', 'full') as $_size) { $attributes = wp_get_attachment_image_src($post_id, $_size); if (false !== $attributes) { $key_str = sprintf('%d_%d', $attributes[1], $attributes[2]); if (null === $added || false === isset($added[$key_str])) { $added[$key_str] = true; array_unshift($attributes, $_size); $images[] = implode(';', $attributes); } } } if (null !== $images) { $e->setProperty('X-WP-IMAGES-URL', $this->_sanitize_value(implode(',', $images))); } if ($img_url = $avatar->get_post_thumbnail_url($event, $size)) { $content = '<div class="ai1ec-event-avatar alignleft timely"><img src="' . esc_attr($img_url) . '" width="' . $size[0] . '" height="' . $size[1] . '" /></div>' . $content; } } if (isset($params['no_html']) && $params['no_html']) { $e->setProperty('description', $this->_sanitize_value(strip_tags(strip_shortcodes($content)))); if (!empty($content)) { $html_content = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">\\n' . '<HTML>\\n<HEAD>\\n<TITLE></TITLE>\\n</HEAD>\\n<BODY>' . $content . '</BODY></HTML>'; $e->setProperty('X-ALT-DESC', $this->_sanitize_value($html_content), array('FMTTYPE' => 'text/html')); unset($html_content); } } else { $e->setProperty('description', $this->_sanitize_value($content)); } $revision = (int) current(array_keys(wp_get_post_revisions($event->get('post_id')))); $e->setProperty('sequence', $revision); // ===================== // = Start & end times = // ===================== $dtstartstring = ''; $dtstart = $dtend = array(); if ($event->is_allday()) { $dtstart['VALUE'] = $dtend['VALUE'] = 'DATE'; // For exporting all day events, don't set a timezone if ($tz && !$export) { $dtstart['TZID'] = $dtend['TZID'] = $tz; } // For exportin' all day events, only set the date not the time if ($export) { $e->setProperty('dtstart', $this->_sanitize_value($event->get('start')->format('Ymd')), $dtstart); $e->setProperty('dtend', $this->_sanitize_value($event->get('end')->format('Ymd')), $dtend); } else { $e->setProperty('dtstart', $this->_sanitize_value($event->get('start')->format("Ymd\\T")), $dtstart); $e->setProperty('dtend', $this->_sanitize_value($event->get('end')->format("Ymd\\T")), $dtend); } } else { if ($tz) { $dtstart['TZID'] = $dtend['TZID'] = $tz; } // This is used later. $dtstartstring = $event->get('start')->format("Ymd\\THis"); $e->setProperty('dtstart', $this->_sanitize_value($dtstartstring), $dtstart); if (false === (bool) $event->get('instant_event')) { $e->setProperty('dtend', $this->_sanitize_value($event->get('end')->format("Ymd\\THis")), $dtend); } } // ======================== // = Latitude & longitude = // ======================== if (floatval($event->get('latitude')) || floatval($event->get('longitude'))) { $e->setProperty('geo', $event->get('latitude'), $event->get('longitude')); } // =================== // = Venue & address = // =================== if ($event->get('venue') || $event->get('address')) { $location = array($event->get('venue'), $event->get('address')); $location = array_filter($location); $location = implode(' @ ', $location); $e->setProperty('location', $this->_sanitize_value($location)); } $categories = array(); $language = get_bloginfo('language'); foreach ($this->_taxonomy_model->get_post_categories($event->get('post_id')) as $cat) { if ('events_categories' === $cat->taxonomy) { $categories[] = $cat->name; } } $e->setProperty('categories', implode(',', $categories), array("LANGUAGE" => $language)); $tags = array(); foreach ($this->_taxonomy_model->get_post_tags($event->get('post_id')) as $tag) { $tags[] = $tag->name; } if (!empty($tags)) { $e->setProperty('X-TAGS', implode(',', $tags), array("LANGUAGE" => $language)); } // ================== // = Cost & tickets = // ================== if ($event->get('cost')) { $e->setProperty('X-COST', $this->_sanitize_value($event->get('cost'))); } if ($event->get('ticket_url')) { $e->setProperty('X-TICKETS-URL', $this->_sanitize_value($event->get('ticket_url'))); } // ================= // = Instant Event = // ================= if ($event->is_instant()) { $e->setProperty('X-INSTANT-EVENT', $this->_sanitize_value($event->is_instant())); } // ==================================== // = Contact name, phone, e-mail, URL = // ==================================== $contact = array($event->get('contact_name'), $event->get('contact_phone'), $event->get('contact_email'), $event->get('contact_url')); $contact = array_filter($contact); $contact = implode('; ', $contact); $e->setProperty('contact', $this->_sanitize_value($contact)); // ==================== // = Recurrence rules = // ==================== $rrule = array(); $recurrence = $event->get('recurrence_rules'); $recurrence = $this->_filter_rule($recurrence); if (!empty($recurrence)) { $rules = array(); foreach (explode(';', $recurrence) as $v) { if (strpos($v, '=') === false) { continue; } list($k, $v) = explode('=', $v); $k = strtoupper($k); // If $v is a comma-separated list, turn it into array for iCalcreator switch ($k) { case 'BYSECOND': case 'BYMINUTE': case 'BYHOUR': case 'BYDAY': case 'BYMONTHDAY': case 'BYYEARDAY': case 'BYWEEKNO': case 'BYMONTH': case 'BYSETPOS': $exploded = explode(',', $v); break; default: $exploded = $v; break; } // iCalcreator requires a more complex array structure for BYDAY... if ($k == 'BYDAY') { $v = array(); foreach ($exploded as $day) { $v[] = array('DAY' => $day); } } else { $v = $exploded; } $rrule[$k] = $v; } } // =================== // = Exception rules = // =================== $exceptions = $event->get('exception_rules'); $exceptions = $this->_filter_rule($exceptions); $exrule = array(); if (!empty($exceptions)) { $rules = array(); foreach (explode(';', $exceptions) as $v) { if (strpos($v, '=') === false) { continue; } list($k, $v) = explode('=', $v); $k = strtoupper($k); // If $v is a comma-separated list, turn it into array for iCalcreator switch ($k) { case 'BYSECOND': case 'BYMINUTE': case 'BYHOUR': case 'BYDAY': case 'BYMONTHDAY': case 'BYYEARDAY': case 'BYWEEKNO': case 'BYMONTH': case 'BYSETPOS': $exploded = explode(',', $v); break; default: $exploded = $v; break; } // iCalcreator requires a more complex array structure for BYDAY... if ($k == 'BYDAY') { $v = array(); foreach ($exploded as $day) { $v[] = array('DAY' => $day); } } else { $v = $exploded; } $exrule[$k] = $v; } } // add rrule to exported calendar if (!empty($rrule) && !isset($rrule['RDATE'])) { $e->setProperty('rrule', $this->_sanitize_value($rrule)); } // add exrule to exported calendar if (!empty($exrule) && !isset($exrule['EXDATE'])) { $e->setProperty('exrule', $this->_sanitize_value($exrule)); } // =================== // = Exception dates = // =================== // For all day events that use a date as DTSTART, date must be supplied // For other other events which use DATETIME, we must use that as well // We must also match the exact starting time $recurrence_dates = $event->get('recurrence_dates'); $recurrence_dates = $this->_filter_rule($recurrence_dates); if (!empty($recurrence_dates)) { $params = array('VALUE' => 'DATE-TIME', 'TZID' => $tz); $dt_suffix = $event->get('start')->format('\\THis'); foreach (explode(',', $recurrence_dates) as $exdate) { // date-time string in EXDATES is formatted as 'Ymd\THis\Z', that // means - in UTC timezone, thus we use `format_to_gmt` here. $exdate = $this->_registry->get('date.time', $exdate)->format_to_gmt('Ymd'); $e->setProperty('rdate', array($exdate . $dt_suffix), $params); } } $exception_dates = $event->get('exception_dates'); $exception_dates = $this->_filter_rule($exception_dates); if (!empty($exception_dates)) { $params = array('VALUE' => 'DATE-TIME', 'TZID' => $tz); $dt_suffix = $event->get('start')->format('\\THis'); foreach (explode(',', $exception_dates) as $exdate) { // date-time string in EXDATES is formatted as 'Ymd\THis\Z', that // means - in UTC timezone, thus we use `format_to_gmt` here. $exdate = $this->_registry->get('date.time', $exdate)->format_to_gmt('Ymd'); $e->setProperty('exdate', array($exdate . $dt_suffix), $params); } } return $calendar; }
/** * Filters past or out of range exception dates. * * @param Ai1ec_Event $event Event. * * @return array Filtered exception dates. */ protected function _filter_exception_dates(Ai1ec_Event $event) { $start = (int) $event->get('start')->format(); $exception_dates = explode(',', $event->get('exception_dates')); $dates = array(); foreach ($exception_dates as $date) { $ex_date = (int) $this->_registry->get('date.time', $date)->format(); if ($ex_date > $start) { $dates[] = $date; } } return $dates; }
/** * Filter Groups as HTML, either as blocks or inline. * * @param Ai1ec_Event $event Rendered Event. * @param array $filter_group Filter Group (Option Model) * @param string $format Return 'blocks' or 'inline' formatted result. * * @return string String of HTML for filter group blocks. */ public function get_filter_group_html(Ai1ec_Event $event, $filter_group, $format = 'blocks') { $filter_groups = $this->_taxonomy_model->get_post_taxonomy($event->get('post_id'), $filter_group['taxonomy_name']); $icon_name = ''; if ('ai1eccfgi-null' !== $filter_group['icon']) { $icon_name = $filter_group['icon']; } else { $icon_name = 'ai1ec-icon-timely'; } foreach ($filter_groups as &$group) { $href = $this->_registry->get('html.element.href', array($filter_group['taxonomy_name'] . '_ids' => $group->term_id)); $class = $data_type = $title = ''; if ($group->description) { $title = 'title="' . esc_attr($group->description) . '" '; } $html = ''; $class .= ' ai1ec-category'; $color_style = ''; if ('inline' === $format) { $taxonomy = $this->_registry->get('model.taxonomy'); $color_style = $taxonomy->get_category_color($group->term_id); if ($color_style !== '') { $color_style = 'style="color: ' . $color_style . ';" '; } $class .= '-inline'; } $html .= '<a ' . $data_type . ' class="' . $class . ' ai1ec-term-id-' . $group->term_id . ' p-category" ' . $title . $color_style . 'href="' . $href->generate_href() . '">'; if ('blocks' === $format) { $html .= $this->get_category_color_square($group->term_id) . ' '; } else { $html = $html . '<i ' . $color_style . ' class="ai1ec-fa ' . $icon_name . '"></i>'; } $html .= esc_html($group->name) . '</a>'; $group = $html; } return implode(' ', $filter_groups); }
/** * Convert an event from a feed into a new Ai1ec_Event object and add it to * the calendar. * * @param Ai1ec_Event $event Event object. * @param vcalendar $calendar Calendar object. * @param bool $export States whether events are created for export. * @param array $params Additional parameters for export. * * @return void */ protected function _insert_event_in_calendar(Ai1ec_Event $event, vcalendar $calendar, $export = false, array $params = array()) { $tz = $this->_registry->get('date.timezone')->get_default_timezone(); $e =& $calendar->newComponent('vevent'); $uid = ''; if ($event->get('ical_uid')) { $uid = addcslashes($event->get('ical_uid'), "\\;,\n"); } else { $uid = $event->get_uid(); $event->set('ical_uid', $uid); $event->save(true); } $e->setProperty('uid', $this->_sanitize_value($uid)); $e->setProperty('url', get_permalink($event->get('post_id'))); // ========================= // = Summary & description = // ========================= $e->setProperty('summary', $this->_sanitize_value(html_entity_decode(apply_filters('the_title', $event->get('post')->post_title), ENT_QUOTES, 'UTF-8'))); $content = apply_filters('the_content', $event->get('post')->post_content); $content = str_replace(']]>', ']]>', $content); $content = html_entity_decode($content, ENT_QUOTES, 'UTF-8'); // Prepend featured image if available. $size = null; $avatar = $this->_registry->get('view.event.avatar'); if ($img_url = $avatar->get_post_thumbnail_url($event, $size)) { $content = '<div class="ai1ec-event-avatar alignleft timely"><img src="' . esc_attr($img_url) . '" width="' . $size[0] . '" height="' . $size[1] . '" /></div>' . $content; } if (isset($params['no_html']) && $params['no_html']) { $e->setProperty('description', $this->_sanitize_value(strip_tags(strip_shortcodes($content)))); if (!empty($content)) { $html_content = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">\\n' . '<HTML>\\n<HEAD>\\n<TITLE></TITLE>\\n</HEAD>\\n<BODY>' . $content . '</BODY></HTML>'; $e->setProperty('X-ALT-DESC', $this->_sanitize_value($html_content), array('FMTTYPE' => 'text/html')); unset($html_content); } } else { $e->setProperty('description', $this->_sanitize_value($content)); } $revision = (int) current(array_keys(wp_get_post_revisions($event->get('post_id')))); $e->setProperty('sequence', $revision); // ===================== // = Start & end times = // ===================== $dtstartstring = ''; $dtstart = $dtend = array(); if ($event->is_allday()) { $dtstart['VALUE'] = $dtend['VALUE'] = 'DATE'; // For exporting all day events, don't set a timezone if ($tz && !$export) { $dtstart['TZID'] = $dtend['TZID'] = $tz; } // For exportin' all day events, only set the date not the time if ($export) { $e->setProperty('dtstart', $this->_sanitize_value($event->get('start')->format('Ymd')), $dtstart); $e->setProperty('dtend', $this->_sanitize_value($event->get('end')->format('Ymd')), $dtend); } else { $e->setProperty('dtstart', $this->_sanitize_value($event->get('start')->format("Ymd\\T")), $dtstart); $e->setProperty('dtend', $this->_sanitize_value($event->get('end')->format("Ymd\\T")), $dtend); } } else { if ($tz) { $dtstart['TZID'] = $dtend['TZID'] = $tz; } // This is used later. $dtstartstring = $event->get('start')->format("Ymd\\THis"); $e->setProperty('dtstart', $this->_sanitize_value($dtstartstring), $dtstart); $e->setProperty('dtend', $this->_sanitize_value($event->get('end')->format("Ymd\\THis")), $dtend); } // ======================== // = Latitude & longitude = // ======================== if (floatval($event->get('latitude')) || floatval($event->get('longitude'))) { $e->setProperty('geo', $event->get('latitude'), $event->get('longitude')); } // =================== // = Venue & address = // =================== if ($event->get('venue') || $event->get('address')) { $location = array($event->get('venue'), $event->get('address')); $location = array_filter($location); $location = implode(' @ ', $location); $e->setProperty('location', $this->_sanitize_value($location)); } $categories = array(); $language = get_bloginfo('language'); foreach ($this->_taxonomy_model->get_post_categories($event->get('post_id')) as $cat) { $categories[] = $cat->name; } $e->setProperty('categories', implode(',', $categories), array("LANGUAGE" => $language)); $tags = array(); foreach ($this->_taxonomy_model->get_post_tags($event->get('post_id')) as $tag) { $tags[] = $tag->name; } if (!empty($tags)) { $e->setProperty('X-TAGS', implode(',', $tags), array("LANGUAGE" => $language)); } // ================== // = Cost & tickets = // ================== if ($event->get('cost')) { $e->setProperty('X-COST', $this->_sanitize_value($event->get('cost'))); } if ($event->get('ticket_url')) { $e->setProperty('X-TICKETS-URL', $this->_sanitize_value($event->get_nonloggable_url($event->get('ticket_url')))); } // ==================================== // = Contact name, phone, e-mail, URL = // ==================================== $contact = array($event->get('contact_name'), $event->get('contact_phone'), $event->get('contact_email'), $event->get_nonloggable_url($event->get('contact_url'))); $contact = array_filter($contact); $contact = implode('; ', $contact); $e->setProperty('contact', $this->_sanitize_value($contact)); // ==================== // = Recurrence rules = // ==================== $rrule = array(); $recurrence = $event->get('recurrence_rules'); if (!empty($recurrence)) { $rules = array(); foreach (explode(';', $event->get('recurrence_rules')) as $v) { if (strpos($v, '=') === false) { continue; } list($k, $v) = explode('=', $v); $k = strtoupper($k); // If $v is a comma-separated list, turn it into array for iCalcreator switch ($k) { case 'BYSECOND': case 'BYMINUTE': case 'BYHOUR': case 'BYDAY': case 'BYMONTHDAY': case 'BYYEARDAY': case 'BYWEEKNO': case 'BYMONTH': case 'BYSETPOS': $exploded = explode(',', $v); break; default: $exploded = $v; break; } // iCalcreator requires a more complex array structure for BYDAY... if ($k == 'BYDAY') { $v = array(); foreach ($exploded as $day) { $v[] = array('DAY' => $day); } } else { $v = $exploded; } $rrule[$k] = $v; } } // =================== // = Exception rules = // =================== $exceptions = $event->get('exception_rules'); $exrule = array(); if (!empty($exceptions)) { $rules = array(); foreach (explode(';', $exceptions) as $v) { if (strpos($v, '=') === false) { continue; } list($k, $v) = explode('=', $v); $k = strtoupper($k); // If $v is a comma-separated list, turn it into array for iCalcreator switch ($k) { case 'BYSECOND': case 'BYMINUTE': case 'BYHOUR': case 'BYDAY': case 'BYMONTHDAY': case 'BYYEARDAY': case 'BYWEEKNO': case 'BYMONTH': case 'BYSETPOS': $exploded = explode(',', $v); break; default: $exploded = $v; break; } // iCalcreator requires a more complex array structure for BYDAY... if ($k == 'BYDAY') { $v = array(); foreach ($exploded as $day) { $v[] = array('DAY' => $day); } } else { $v = $exploded; } $exrule[$k] = $v; } } // add rrule to exported calendar if (!empty($rrule)) { $e->setProperty('rrule', $this->_sanitize_value($rrule)); } // add exrule to exported calendar if (!empty($exrule)) { $e->setProperty('exrule', $this->_sanitize_value($exrule)); } // =================== // = Exception dates = // =================== // For all day events that use a date as DTSTART, date must be supplied // For other other events which use DATETIME, we must use that as well // We must also match the exact starting time $exception_dates = $event->get('exception_dates'); if (!empty($exception_dates)) { $params = array('VALUE' => 'DATE-TIME', 'TZID' => $tz); $dt_suffix = $event->get('start')->format('\\THis'); foreach (explode(',', $exception_dates) as $exdate) { $exdate = $this->_registry->get('date.time', $exdate)->format('Ymd'); $e->setProperty('exdate', array($exdate . $dt_suffix), $params); } } return $calendar; }
protected function _add_view_specific_runtime_properties(Ai1ec_Event $event) { $end_day = $this->_registry->get('date.time', $event->get('end'))->adjust(-1, 'second')->format_i18n('d'); $event->set_runtime('multiday_end_day', $end_day); }
/** * Generate and store instance entries in database for given event. * * @param Ai1ec_Event $event Instance of event to create entries for. * * @return bool Success. */ protected function _create_instances_collection(Ai1ec_Event $event) { $events = array(); $event_item = array('post_id' => $event->get('post_id'), 'start' => $event->get('start')->format_to_gmt(), 'end' => $event->get('end')->format_to_gmt()); $duration = $event->get('end')->diff_sec($event->get('start')); $_start = $event->get('start')->format_to_gmt(); $_end = $event->get('end')->format_to_gmt(); // Always cache initial instance $events[$_start] = $event_item; if ($event->get('recurrence_rules') || $event->get('recurrence_dates')) { /** * NOTE: this timezone switch is intentional, because underlying * library doesn't allow us to pass it as an argument. Though no * lesser importance shall be given to the restore call bellow. */ $start_datetime = $event->get('start'); $start_datetime->assert_utc_timezone(); $start_timezone = $this->_registry->get('date.timezone')->get_name($start_datetime->get_timezone()); $events += $this->create_instances_by_recurrence($event, $event_item, $_start, $duration, $start_timezone); } $search_helper = $this->_registry->get('model.search'); foreach ($events as &$event_item) { // Find out if this event instance is already accounted for by an // overriding 'RECURRENCE-ID' of the same iCalendar feed (by comparing the // UID, start date, recurrence). If so, then do not create duplicate // instance of event. $start = $event_item['start']; $matching_event_id = null; if ($event->get('ical_uid')) { $matching_event_id = $search_helper->get_matching_event_id($event->get('ical_uid'), $event->get('ical_feed_url'), $event->get('start'), false, $event->get('post_id')); } // If no other instance was found if (null !== $matching_event_id) { $event_item = false; } } return array_filter($events); }
protected function _add_view_specific_runtime_properties(Ai1ec_Event $event) { $event->set_runtime('multiday', $event->get('_orig')->is_multiday()); }
/** * Simple regex-parse of post_content for matches of <img src="foo" />; if * one is found, return its URL. * * @param null $size (width, height) array of returned image * * @return string|null */ public function get_content_img_url(Ai1ec_Event $event, &$size = null) { preg_match('/<img([^>]+)src=["\']?([^"\'\\ >]+)([^>]*)>/i', $event->get('post')->post_content, $matches); // Check if we have a result, otherwise a notice is issued. if (empty($matches)) { return null; } $url = $matches[2]; $size = array(0, 0); // Try to detect width and height. $attrs = $matches[1] . $matches[3]; $matches = null; preg_match_all('/(width|height)=["\']?(\\d+)/i', $attrs, $matches, PREG_SET_ORDER); // Check if we have a result, otherwise a notice is issued. if (!empty($matches)) { foreach ($matches as $match) { $size[$match[1] === 'width' ? 0 : 1] = $match[2]; } } return $url; }
/** * Tags as HTML */ public function get_tags_html(Ai1ec_Event $event) { $tags = $this->_taxonomy_model->get_post_tags($event->get('post_id')); if (!$tags) { $tags = array(); } foreach ($tags as &$tag) { $href = $this->_registry->get('html.element.href', array('tag_ids' => $tag->term_id)); $class = ''; $data_type = ''; $title = ''; if ($tag->description) { $title = 'title="' . esc_attr($tag->description) . '" '; } $tag = '<a ' . $data_type . ' class="ai1ec-tag ' . $class . ' ai1ec-term-id-' . $tag->term_id . '" ' . $title . 'href="' . $href->generate_href() . '">' . '<i class="ai1ec-fa ai1ec-fa-tag"></i>' . esc_html($tag->name) . '</a>'; } return implode(' ', $tags); }
/** * Get the html for the exclude dates and exception rules. * * @param Ai1ec_Event $event * @param Ai1ec_Recurrence_Rule $rrule * @return string */ public function get_exclude_html(Ai1ec_Event $event, Ai1ec_Recurrence_Rule $rrule) { $excludes = array(); $exception_rules = $event->get('exception_rules'); $exception_dates = $event->get('exception_dates'); if ($exception_rules) { $excludes[] = $rrule->rrule_to_text($exception_rules); } if ($exception_dates && 0 !== strpos($exception_rules, 'EXDATE')) { $excludes[] = $rrule->exdate_to_text($exception_dates); } return implode(Ai1ec_I18n::__(', and '), $excludes); }
/** * Generate and store instance entries in database for given event. * * @param Ai1ec_Event $event Instance of event to create entries for. * * @return bool Success. */ public function create(Ai1ec_Event $event) { $evs = array(); $e = array('post_id' => $event->get('post_id'), 'start' => $event->get('start')->format_to_gmt(), 'end' => $event->get('end')->format_to_gmt()); $duration = $event->get('end')->diff_sec($event->get('start')); // Timestamp of today date + 3 years (94608000 seconds) $tif = $this->_registry->get('date.system')->current_time(true) + 94608000; // Always cache initial instance $evs[] = $e; $_start = $event->get('start')->format_to_gmt(); $_end = $event->get('end')->format_to_gmt(); if ($event->get('recurrence_rules')) { $_restore_default_tz = date_default_timezone_get(); $start_timezone = $event->get('start')->get_timezone(); date_default_timezone_set($start_timezone); $evs = array_merge($evs, $this->create_instances_by_recurrence($event, $e, $_start, $tif, $duration, $start_timezone)); date_default_timezone_set($_restore_default_tz); unset($_restore_default_tz); } // Make entries unique (sometimes recurrence generator creates duplicates?) $evs_unique = array(); foreach ($evs as $ev) { $evs_unique[md5(serialize($ev))] = $ev; } $search_helper = $this->_registry->get('model.search'); foreach ($evs_unique as $e) { // Find out if this event instance is already accounted for by an // overriding 'RECURRENCE-ID' of the same iCalendar feed (by comparing the // UID, start date, recurrence). If so, then do not create duplicate // instance of event. $start = $e['start']; $matching_event_id = null; if ($event->get('ical_uid')) { $matching_event_id = $search_helper->get_matching_event_id($event->get('ical_uid'), $event->get('ical_feed_url'), $event->get('start'), false, $event->get('post_id')); } // If no other instance was found if (null === $matching_event_id) { $this->_dbi->insert('ai1ec_event_instances', $e, array('%d', '%d', '%d')); } } return true; }