status) {
return '';
}
return '' . esc_html__('Cancelled', '3task-calendar') . ' ';
}
/**
* "Date to be announced" note for an event of which only the month is known.
*
* @since 1.6.0
* @param ThreeCal_Event $event Event.
* @return string Escaped HTML, empty for events with a known day.
*/
public static function tba_note($event) {
if (!$event || !$event->is_month_only()) {
return '';
}
return '' . esc_html(ThreeCal_Event::tba_text()) . '';
}
/**
* Settings
*/
private $settings;
/**
* Constructor
*/
public function __construct() {
$this->settings = get_option('threecal_settings', array());
}
/**
* Date format from the plugin settings or WordPress.
*/
private function date_format() {
return threecal_date_format();
}
/**
* Time format from the plugin settings or WordPress.
*/
private function time_format() {
return threecal_time_format();
}
/**
* Attributes of the link to an event's URL, filterable per event.
*
* @since 1.6.3
*
* @param ThreeCal_Event $event The event.
* @param string $context Where the link is printed: card, poster, single, upcoming.
* @param array $attrs Attributes the template already sets (class, target, rel ...).
* @return string Escaped HTML attributes, href included.
*/
public static function link_attributes($event, $context, $attrs = array()) {
$attrs = array_merge($attrs, array('href' => $event->url));
$attrs = self::apply_link_rule($attrs, $event);
/**
* Filters the attributes of the link to an event's URL.
*
* Return for example rel => 'nofollow noopener' and target => '_blank' for
* events of other organisers. Since 1.6.3
*
* @param array $attrs Attributes (href, class, target, rel ...).
* @param ThreeCal_Event $event The event.
* @param string $context card, poster, single, upcoming or details.
*/
$attrs = apply_filters('threecal_event_link_attributes', $attrs, $event, $context);
$out = array();
foreach ((array) $attrs as $name => $value) {
if (!preg_match('/^[a-z][a-z0-9-]*$/', (string) $name) || null === $value || false === $value) {
continue;
}
$out[] = esc_attr($name) . '="' . ('href' === $name ? esc_url($value) : esc_attr($value)) . '"';
}
return implode(' ', $out);
}
/**
* Link rule for links to other websites (since 1.7.0).
*
* Links to the own site stay as they are. Other links open in a new window and are
* nofollow, unless the setting "Links to other websites" says follow or one of the
* event's categories is marked as follow.
*
* @param array $attrs Attributes with href.
* @param ThreeCal_Event $event The event.
* @return array
*/
public static function apply_link_rule($attrs, $event) {
$href = isset($attrs['href']) ? (string) $attrs['href'] : '';
$host = wp_parse_url($href, PHP_URL_HOST);
if (!$host) {
return $attrs;
}
$own = (string) wp_parse_url(home_url('/'), PHP_URL_HOST);
if (0 === strcasecmp(preg_replace('/^www\./i', '', $host), preg_replace('/^www\./i', '', $own))) {
return $attrs;
}
$settings = get_option('threecal_settings', array());
$follow = isset($settings['external_links']) && 'follow' === $settings['external_links'];
if (!$follow && !empty($event->id)) {
$follow_ids = ThreeCal_Category::follow_ids();
if ($follow_ids) {
foreach ((array) ThreeCal_Event::get_categories($event->id) as $cat) {
if (in_array((int) $cat->id, $follow_ids, true)) {
$follow = true;
break;
}
}
}
}
$rel = isset($attrs['rel']) ? preg_split('/\s+/', trim((string) $attrs['rel'])) : array();
$rel = array_values(array_diff($rel, array('nofollow', 'noopener')));
if (!$follow) {
$rel[] = 'nofollow';
}
$rel[] = 'noopener';
$attrs['rel'] = implode(' ', $rel);
$attrs['target'] = '_blank';
return $attrs;
}
/**
* Highlighted category of an event (first match), null if none. Since 1.7.0
*
* @param array $categories Category rows of the event.
* @return object|null
*/
public static function highlight_category($categories) {
$ids = ThreeCal_Category::highlighted_ids();
if (!$ids) {
return null;
}
foreach ((array) $categories as $cat) {
if (in_array((int) $cat->id, $ids, true)) {
return $cat;
}
}
return null;
}
/**
* Badge of a highlighted event: star and name of the category. Since 1.7.0
*
* @param array $categories Category rows of the event.
* @return string Escaped HTML or empty string.
*/
public static function highlight_badge($categories) {
$cat = self::highlight_category($categories);
if (!$cat) {
return '';
}
ob_start();
ThreeCal_Icons::render('star', 12);
$icon = ob_get_clean();
return '' . $icon . esc_html($cat->name) . '';
}
/**
* Classes of an event card, filterable per event.
*
* @since 1.6.3
*
* @param array $classes Classes the template sets.
* @param ThreeCal_Event $event The event.
* @param string $view list, compact, poster.
* @param array $categories Category rows of the event (since 1.7.0, for the highlight class).
* @return string Escaped class attribute value.
*/
public static function card_classes($classes, $event, $view, $categories = array()) {
if (self::highlight_category($categories)) {
$classes[] = 'threecal-is-highlight';
}
/**
* Filters the CSS classes of an event card. Since 1.6.3
*
* @param array $classes Classes.
* @param ThreeCal_Event $event The event.
* @param string $view list, compact, poster.
*/
$classes = apply_filters('threecal_event_card_classes', array_values(array_filter((array) $classes)), $event, $view);
return esc_attr(implode(' ', array_unique(array_map('sanitize_html_class', (array) $classes))));
}
/**
* Search field (since 1.8.0).
*
* In the calendar the field is handled by JavaScript (same public request as the month
* navigation). In the event list it is a plain GET form, so it works without JavaScript
* and page caches keep working: every search term is its own address.
*
* @param array $args id (prefix for the field id), value (current term), param (query
* parameter), method ('get' for a real form, '' for the calendar),
* action (URL of the form), keep (query parameters to carry along).
* @return string
*/
public static function render_search_form($args = array()) {
$args = wp_parse_args($args, array(
'id' => 'threecal-' . wp_rand(1000, 9999),
'value' => '',
'param' => 'tc_q',
'method' => '',
'action' => '',
'keep' => array(),
));
$field_id = $args['id'] . '-search';
$out = '
$calendar_id)); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Escaped in render_search_form(). Since 1.8.0, next to the category filter. ?>
render_month_view( $month, $year, $args );
?>
ThreeCal_Event::visible_statuses(),
'range_start' => gmdate('Y-m-d 00:00:00', $first_day),
'range_end' => gmdate('Y-m-t 23:59:59', $first_day)
);
if (!empty($args['category_id'])) {
$event_args['category_id'] = $args['category_id'];
}
if (!empty($args['location_id'])) {
$event_args['location_id'] = $args['location_id'];
}
$events = ThreeCal_Event::get_all($event_args);
$categories = ThreeCal_Event::get_categories_for_events(wp_list_pluck($events, 'id'));
$time_format = $this->time_format();
// Group events by every day they cover (multi-day events appear on each day)
$events_by_day = array();
$month_only = array();
foreach ($events as $event) {
// Only the month is known: shown in a bar above the grid, not on the 1st.
if ($event->is_month_only()) {
$month_only[] = array(
'event' => $event,
'color' => ThreeCal_Themes::event_color($event, isset($categories[$event->id]) ? $categories[$event->id] : array()),
);
continue;
}
foreach ($event->get_days_in_month($month, $year) as $day) {
$events_by_day[$day][] = array(
'event' => $event,
'color' => ThreeCal_Themes::event_color($event, isset($categories[$event->id]) ? $categories[$event->id] : array()),
'starts_here' => substr($event->start_date, 0, 10) === sprintf('%04d-%02d-%02d', $year, $month, $day),
);
}
}
$today = current_time('Y-m-d');
$total_cells = $first_weekday + $days_in_month;
$weeks = (int) ceil($total_cells / 7);
$day = 1;
ob_start();
?>