$pl ? 'wydarzenia' : 'events', 'slug_single' => '', 'slug_category' => $pl ? 'wydarzenia-kategoria' : 'event-category', 'slug_city' => $pl ? 'wydarzenia-miasto' : 'event-city', 'slug_venue' => $pl ? 'wydarzenia-miejsce' : 'venue', 'slug_organizer' => $pl ? 'organizator' : 'organizer', 'archive_title' => '', 'per_page' => 20, 'default_view' => 'list', 'default_view_tablet' => '', 'default_view_phone' => '', 'enabled_views' => array( 'list', 'month', 'tiles' ), 'show_switcher' => 1, 'show_filters' => 1, 'currency' => $pl ? 'PLN' : 'EUR', 'window_months' => 24, 'no_cache_lists' => 1, // Events. 'default_duration' => 0, // Appearance (light values below are the Cobalt preset). 'palette' => 'cobalt', 'accent_source' => 'custom', 'accent' => '#2A45C4', 'theme_color' => '', 'surface' => '#FFFFFF', 'text' => '#15202B', 'muted' => '#52606D', 'border' => '#D5DCE3', 'dark_accent' => '#7C93F5', 'dark_surface' => '#141B26', 'dark_text' => '#E8EDF3', 'dark_muted' => '#A3AFBD', 'dark_border' => '#2C3848', 'auto_contrast' => 1, 'radius' => 12, 'color_mode' => 'auto', 'show_images' => 1, 'fallback_tile' => 1, 'limit_image_sizes' => 0, 'fallback_image' => 0, // Single event. 'single_layout' => 'classic', 'show_map_link' => 1, 'map_provider' => 'google', 'show_related' => 1, 'show_ics' => 1, 'show_share' => 1, 'sticky_bar' => 1, // Affiliate notice. 'notice_default' => '', 'notice_langs' => array(), 'notice_position' => 'after_content', 'notice_only_ticket' => 1, // Advanced. 'schema' => 1, 'rss_fields' => 1, 'ics' => 1, 'delete_on_uninstall' => 0, 'credit_link' => 0, 'admin_language' => '', // Import. 'import_max_image_mb' => 8, 'import_images_day' => 300, 'import_media_hosts' => '', ); /** * Default settings. Add-ons add their own keys here so the settings * screen and the sanitizer know them. * * @param array $defaults Defaults. */ return (array) apply_filters( 'bcal_default_settings', $defaults ); } /** * Returns all settings merged with defaults. * * @param bool $reset Re-read the option. * @return array */ function bcal_settings( $reset = false ) { static $cache = null; if ( $reset || null === $cache ) { $saved = get_option( 'bcal_settings', array() ); $cache = wp_parse_args( is_array( $saved ) ? $saved : array(), bcal_default_settings() ); } return $cache; } /** * Returns a single setting. * * @param string $key Setting key. * @return mixed */ function bcal_opt( $key ) { $settings = bcal_settings(); return isset( $settings[ $key ] ) ? $settings[ $key ] : null; } add_action( 'update_option_bcal_settings', function () { bcal_settings( true ); } ); /** * Colour presets. Choosing one in the settings fills every colour field * (light and dark mode); the fields can then be adjusted freely. * * @return array */ function bcal_palettes() { $presets = array( 'cobalt' => array( 'label' => __( 'Cobalt', 'bearius-calendar' ), 'accent' => '#2A45C4', 'surface' => '#FFFFFF', 'text' => '#15202B', 'muted' => '#52606D', 'border' => '#D5DCE3', 'dark_accent' => '#7C93F5', 'dark_surface' => '#141B26', 'dark_text' => '#E8EDF3', 'dark_muted' => '#A3AFBD', 'dark_border' => '#2C3848', ), 'raspberry' => array( 'label' => __( 'Raspberry', 'bearius-calendar' ), 'accent' => '#B4235A', 'surface' => '#FFFFFF', 'text' => '#1F1418', 'muted' => '#6B5A60', 'border' => '#E6D8DD', 'dark_accent' => '#F07BA6', 'dark_surface' => '#1D1418', 'dark_text' => '#F4E9ED', 'dark_muted' => '#B9A5AD', 'dark_border' => '#3D2B32', ), 'teal' => array( 'label' => __( 'Teal', 'bearius-calendar' ), 'accent' => '#0F766E', 'surface' => '#FFFFFF', 'text' => '#102A28', 'muted' => '#4F6663', 'border' => '#D2E0DE', 'dark_accent' => '#4FD1C1', 'dark_surface' => '#0F1D1C', 'dark_text' => '#E3F1EF', 'dark_muted' => '#9DB7B3', 'dark_border' => '#24403D', ), 'amber' => array( 'label' => __( 'Amber', 'bearius-calendar' ), 'accent' => '#A15C07', 'surface' => '#FFFDF8', 'text' => '#241A0E', 'muted' => '#6E5E4A', 'border' => '#E8DFD0', 'dark_accent' => '#F2B45A', 'dark_surface' => '#1C1710', 'dark_text' => '#F5EEE3', 'dark_muted' => '#BBAE9A', 'dark_border' => '#3B3226', ), 'forest' => array( 'label' => __( 'Forest', 'bearius-calendar' ), 'accent' => '#2F6B3A', 'surface' => '#FBFCF8', 'text' => '#172117', 'muted' => '#56645A', 'border' => '#D7DFD3', 'dark_accent' => '#86C98F', 'dark_surface' => '#121A13', 'dark_text' => '#E6EFE6', 'dark_muted' => '#A2B3A4', 'dark_border' => '#2A382B', ), 'graphite' => array( 'label' => __( 'Graphite', 'bearius-calendar' ), 'accent' => '#1F2937', 'surface' => '#FFFFFF', 'text' => '#111827', 'muted' => '#5B6472', 'border' => '#DADDE2', 'dark_accent' => '#E5E7EB', 'dark_surface' => '#121417', 'dark_text' => '#ECEEF1', 'dark_muted' => '#A2A8B1', 'dark_border' => '#2B3036', ), ); return apply_filters( 'bcal_palettes', $presets ); } /** * Setting keys filled by a colour preset. * * @return array */ function bcal_palette_keys() { return array( 'accent', 'surface', 'text', 'muted', 'border', 'dark_accent', 'dark_surface', 'dark_text', 'dark_muted', 'dark_border' ); } /** * Casts shortcode-style booleans. * * @param mixed $value Value. * @return bool */ function bcal_bool( $value ) { if ( is_bool( $value ) ) { return $value; } return in_array( strtolower( (string) $value ), array( '1', 'true', 'yes', 'on' ), true ); } /* ========================================================================== Dates ========================================================================== */ /** * Current local time in MySQL format. * * @return string */ function bcal_now() { return current_time( 'mysql' ); } /** * Local "Y-m-d H:i:s" string to a Unix timestamp. * * @param string $datetime Local date and time. * @return int */ function bcal_ts( $datetime ) { if ( ! $datetime ) { return 0; } $date = date_create( $datetime, wp_timezone() ); return $date ? $date->getTimestamp() : 0; } /** * Parses loosely formatted input (import files, forms) into a local * "Y-m-d H:i:s" string. Returns an empty string when it cannot be parsed. * * @param mixed $value Raw value. * @return string */ function bcal_parse_datetime( $value ) { $value = trim( (string) $value ); if ( '' === $value ) { return ''; } $tz = wp_timezone(); if ( ctype_digit( $value ) && strlen( $value ) >= 9 ) { $date = new DateTimeImmutable( '@' . $value ); return $date->setTimezone( $tz )->format( 'Y-m-d H:i:s' ); } // "26.09.2026 19:00" and similar European formats. if ( preg_match( '/^(\d{1,2})\.(\d{1,2})\.(\d{4})(?:[ ,T]+(\d{1,2}):(\d{2})(?::(\d{2}))?)?$/', $value, $m ) ) { $value = sprintf( '%04d-%02d-%02d %02d:%02d:%02d', (int) $m[3], (int) $m[2], (int) $m[1], isset( $m[4] ) ? (int) $m[4] : 0, isset( $m[5] ) ? (int) $m[5] : 0, isset( $m[6] ) ? (int) $m[6] : 0 ); } try { $date = new DateTimeImmutable( $value, $tz ); } catch ( Exception $e ) { return ''; } return $date->setTimezone( $tz )->format( 'Y-m-d H:i:s' ); } /** * Formats a local date and time. * * @param string $format PHP date format. * @param string $datetime Local date and time. * @return string */ function bcal_date( $format, $datetime ) { $ts = bcal_ts( $datetime ); return $ts ? wp_date( $format, $ts ) : ''; } /** * Multibyte-safe ucfirst. * * @param string $text Text. * @return string */ function bcal_ucfirst( $text ) { if ( '' === $text ) { return $text; } if ( function_exists( 'mb_substr' ) ) { return mb_strtoupper( mb_substr( $text, 0, 1 ) ) . mb_substr( $text, 1 ); } return ucfirst( $text ); } /** * Month name in the form used after a day number ("26 września" in Polish). * * @param int $ts Timestamp. * @return string */ function bcal_month_after_day( $ts ) { return trim( preg_replace( '/^\d+\.?\s*/u', '', wp_date( 'j F', $ts ) ) ); } /* ========================================================================== Event data ========================================================================== */ /** * Meta keys stored for every event (without the "_bcal_" prefix). * * @return array */ function bcal_meta_keys() { return array( 'start' => 'string', 'end' => 'string', 'all_day' => 'boolean', 'rrule' => 'string', 'exdates' => 'string', 'rdates' => 'string', 'exrule' => 'string', 'ticket_url' => 'string', 'ticket_url_2' => 'string', 'ticket_label_2' => 'string', 'price' => 'string', 'currency' => 'string', 'status' => 'string', 'online' => 'boolean', 'online_url' => 'string', 'featured' => 'boolean', 'source_id' => 'string', 'source_url' => 'string', ); } /** * Normalized event data. * * @param int $post_id Event ID. * @param bool $fresh Skip the request cache. * @return array */ function bcal_get_event( $post_id, $fresh = false ) { static $cache = array(); $post_id = (int) $post_id; if ( ! $fresh && isset( $cache[ $post_id ] ) ) { return $cache[ $post_id ]; } $meta = array(); foreach ( array_keys( bcal_meta_keys() ) as $key ) { $meta[ $key ] = get_post_meta( $post_id, '_bcal_' . $key, true ); } $currency = (string) $meta['currency']; $status = (string) $meta['status']; $event = array( 'id' => $post_id, 'start' => (string) $meta['start'], 'end' => (string) $meta['end'], 'end_effective' => '', 'end_auto' => false, 'all_day' => (bool) $meta['all_day'], 'rrule' => (string) $meta['rrule'], 'exdates' => array_values( array_filter( array_map( 'trim', explode( ',', (string) $meta['exdates'] ) ) ) ), 'rdates' => bcal_normalize_rdates( (string) $meta['rdates'], $meta['start'] ? substr( (string) $meta['start'], 11 ) : '00:00:00' ), 'exrule' => (string) $meta['exrule'], 'ticket_url' => (string) $meta['ticket_url'], 'ticket_url_2' => (string) $meta['ticket_url_2'], 'ticket_label_2' => (string) $meta['ticket_label_2'], 'price' => (string) $meta['price'], 'currency' => '' !== $currency ? $currency : (string) bcal_opt( 'currency' ), 'status' => '' !== $status ? $status : 'scheduled', 'online' => (bool) $meta['online'], 'online_url' => (string) $meta['online_url'], 'featured' => (bool) $meta['featured'], 'source_id' => (string) $meta['source_id'], 'source_url' => (string) $meta['source_url'], ); $event['end_effective'] = bcal_effective_end( $event ); $event['end_auto'] = '' === $event['end'] && '' !== $event['end_effective']; $cache[ $post_id ] = $event; return $event; } /** * Whether an event has more than one date (a rule or extra dates). * * @param array $event Event data. * @return bool */ function bcal_is_recurring( $event ) { return '' !== (string) $event['rrule'] || ! empty( $event['rdates'] ); } /** * Default event duration in minutes (0 = off). * * @return int */ function bcal_default_duration() { return max( 0, min( 1440, (int) bcal_opt( 'default_duration' ) ) ); } /** * End of an event: the end saved on the event, or start plus the default * duration from the settings. A saved end always wins and is never changed. * * @param array $event Event data with start, end and all_day. * @return string Local "Y-m-d H:i:s" or empty string. */ function bcal_effective_end( $event ) { if ( '' !== (string) $event['end'] ) { return (string) $event['end']; } if ( ! empty( $event['all_day'] ) || '' === (string) $event['start'] ) { return ''; } $minutes = bcal_default_duration(); if ( ! $minutes ) { return ''; } $start = date_create_immutable( (string) $event['start'], wp_timezone() ); return $start ? $start->modify( '+' . $minutes . ' minutes' )->format( 'Y-m-d H:i:s' ) : ''; } /** * Link to one date of an event. Recurring events get a ?bcal_date= parameter * so the event page shows that date; the canonical URL stays the event URL. * * @param int $post_id Event ID. * @param string $start_dt Local start of the occurrence. * @return string */ function bcal_occurrence_url( $post_id, $start_dt ) { $url = (string) get_permalink( $post_id ); $event = bcal_get_event( $post_id ); if ( ! bcal_is_recurring( $event ) || ! $start_dt ) { return $url; } return add_query_arg( 'bcal_date', substr( (string) $start_dt, 0, 10 ), $url ); } /** * Date requested with ?bcal_date= for the event shown on the current page. * * @param int $post_id Event ID. * @return string "Y-m-d" or empty string. */ function bcal_requested_date( $post_id ) { if ( ! isset( $_GET['bcal_date'] ) || (int) get_queried_object_id() !== (int) $post_id ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended return ''; } $date = sanitize_text_field( wp_unslash( $_GET['bcal_date'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended if ( ! preg_match( '/^\d{4}-\d{2}-\d{2}$/', $date ) ) { return ''; } $event = bcal_get_event( $post_id ); return bcal_is_recurring( $event ) ? $date : ''; } /** * City of a venue saved on the venue itself. * * @param WP_Term|null $venue Venue term. * @return WP_Term|null */ function bcal_venue_city( $venue ) { if ( ! $venue ) { return null; } $city_id = (int) get_term_meta( $venue->term_id, 'bcal_city_id', true ); if ( ! $city_id ) { return null; } $city = get_term( $city_id, 'bcal_city' ); return ( $city && ! is_wp_error( $city ) ) ? $city : null; } /** * First term of a taxonomy assigned to a post. * * @param int $post_id Post ID. * @param string $taxonomy Taxonomy. * @return WP_Term|null */ function bcal_first_term( $post_id, $taxonomy ) { $terms = get_the_terms( $post_id, $taxonomy ); return ( $terms && ! is_wp_error( $terms ) ) ? $terms[0] : null; } /** * Event status labels. * * @return array */ function bcal_status_labels() { return array( 'scheduled' => __( 'Scheduled', 'bearius-calendar' ), 'cancelled' => __( 'Cancelled', 'bearius-calendar' ), 'postponed' => __( 'Postponed', 'bearius-calendar' ), 'soldout' => __( 'Sold out', 'bearius-calendar' ), 'moved_online' => __( 'Moved online', 'bearius-calendar' ), ); } /** * Label of a single status. * * @param string $status Status key. * @return string */ function bcal_status_label( $status ) { $labels = bcal_status_labels(); return isset( $labels[ $status ] ) ? $labels[ $status ] : ''; } /** * Human currency symbol. * * @param string $code ISO code. * @return string */ function bcal_currency_symbol( $code ) { $map = array( 'PLN' => 'zł', 'EUR' => '€', 'USD' => '$', 'GBP' => '£', 'CZK' => 'Kč', ); $code = strtoupper( trim( (string) $code ) ); return isset( $map[ $code ] ) ? $map[ $code ] : $code; } /** * "from 60 zł", "Free entry" or the raw text when the price is not numeric. * * @param string $price Price. * @param string $currency Currency code. * @return string */ function bcal_price_label( $price, $currency ) { $price = trim( (string) $price ); if ( '' === $price ) { return ''; } $normalized = str_replace( array( ' ', ',' ), array( '', '.' ), $price ); if ( ! is_numeric( $normalized ) ) { return $price; } $number = (float) $normalized; if ( $number <= 0 ) { return __( 'Free entry', 'bearius-calendar' ); } $decimals = ( floor( $number ) === $number ) ? 0 : 2; /* translators: 1: price, 2: currency symbol */ return sprintf( __( 'from %1$s %2$s', 'bearius-calendar' ), number_format_i18n( $number, $decimals ), bcal_currency_symbol( $currency ) ); } /** * Plain excerpt. * * @param int $post_id Post ID. * @param int $words Word limit. * @return string */ function bcal_excerpt( $post_id, $words = 22 ) { $post = get_post( $post_id ); if ( ! $post ) { return ''; } $text = '' !== $post->post_excerpt ? $post->post_excerpt : $post->post_content; $text = wp_strip_all_tags( strip_shortcodes( $text ) ); return wp_trim_words( $text, $words, '…' ); } /** * Presentation data for one occurrence row. * * @param object $row Index row (event_id, start_dt, end_dt, all_day, featured). * @return array */ function bcal_card( $row ) { $id = (int) $row->event_id; $event = bcal_get_event( $id ); $ts = bcal_ts( $row->start_dt ); $venue = bcal_first_term( $id, 'bcal_venue' ); $city = bcal_first_term( $id, 'bcal_city' ); $cat = bcal_first_term( $id, 'bcal_category' ); if ( ! $city ) { $city = bcal_venue_city( $venue ); } $place = implode( ', ', array_filter( array( $venue ? $venue->name : '', $city ? $city->name : '' ) ) ); if ( '' === $place && $event['online'] ) { $place = __( 'Online', 'bearius-calendar' ); } $all_day = ! empty( $row->all_day ); return array( 'id' => $id, 'url' => bcal_occurrence_url( $id, $row->start_dt ), 'title' => get_the_title( $id ), 'start' => $row->start_dt, 'end' => $row->end_dt, 'ts' => $ts, 'all_day' => $all_day, 'day' => $ts ? wp_date( 'j', $ts ) : '', 'month_short' => $ts ? wp_date( 'M', $ts ) : '', 'month' => $ts ? bcal_month_after_day( $ts ) : '', 'weekday' => $ts ? wp_date( 'l', $ts ) : '', 'time' => ( $ts && ! $all_day ) ? wp_date( (string) get_option( 'time_format' ), $ts ) : '', 'date_label' => $ts ? bcal_ucfirst( wp_date( 'l, j F', $ts ) ) : '', 'place' => $place, 'venue' => $venue, 'city' => $city, 'category' => $cat ? $cat->name : '', 'cat_color' => bcal_category_color( $cat ), 'price' => bcal_price_label( $event['price'], $event['currency'] ), 'ticket_url' => $event['ticket_url'], 'cta' => $event['ticket_url'] ? __( 'Buy tickets', 'bearius-calendar' ) : __( 'Details', 'bearius-calendar' ), 'status' => $event['status'], 'status_label' => 'scheduled' !== $event['status'] ? bcal_status_label( $event['status'] ) : '', 'has_image' => has_post_thumbnail( $id ), 'excerpt' => bcal_excerpt( $id ), 'featured' => ! empty( $row->featured ) || ! empty( $row->pick ), ); } /* ========================================================================== Images ========================================================================== */ /** * Event image using the closest size that already exists for the file. * WordPress picks the smallest generated size covering the requested box * and adds srcset from the remaining ones, so nothing new is generated. * * @param int $post_id Event ID. * @param int $width Target width in CSS px. * @param int $height Target height in CSS px. * @param string $sizes Sizes attribute. * @param bool $eager Load immediately (above the fold). * @param string $class Extra class. * @return string */ function bcal_image( $post_id, $width, $height, $sizes, $eager = false, $class = '' ) { $thumb = get_post_thumbnail_id( $post_id ); if ( ! $thumb ) { return ''; } $attr = array( 'class' => trim( 'bcal-img ' . $class ), 'sizes' => $sizes, 'decoding' => 'async', 'loading' => $eager ? 'eager' : 'lazy', ); if ( $eager ) { $attr['fetchpriority'] = 'high'; } return wp_get_attachment_image( $thumb, array( (int) $width, (int) $height ), false, $attr ); } /* ========================================================================== Venue, maps ========================================================================== */ /** * Venue address line. * * @param WP_Term|null $venue Venue term. * @param WP_Term|null $city City term. * @return string */ function bcal_venue_address( $venue, $city ) { $parts = array(); if ( $venue ) { $parts[] = (string) get_term_meta( $venue->term_id, 'bcal_address', true ); $postal = (string) get_term_meta( $venue->term_id, 'bcal_postal', true ); $city_n = $city ? $city->name : ''; $parts[] = trim( $postal . ' ' . $city_n ); } elseif ( $city ) { $parts[] = $city->name; } return implode( ', ', array_filter( array_map( 'trim', $parts ) ) ); } /** * Links to external map apps. Plain links only: nothing is loaded from a * map provider until the visitor clicks. * * @param WP_Term|null $venue Venue term. * @param WP_Term|null $city City term. * @return array|null { href, apple } */ function bcal_map_links( $venue, $city ) { $name = $venue ? $venue->name : ''; $address = bcal_venue_address( $venue, $city ); $lat = $venue ? trim( (string) get_term_meta( $venue->term_id, 'bcal_lat', true ) ) : ''; $lng = $venue ? trim( (string) get_term_meta( $venue->term_id, 'bcal_lng', true ) ) : ''; $coords = ( '' !== $lat && '' !== $lng ) ? $lat . ',' . $lng : ''; $query = '' !== $coords ? $coords : implode( ', ', array_filter( array( $name, $address ) ) ); if ( '' === trim( $query ) ) { return null; } $google = 'https://www.google.com/maps/search/?api=1&query=' . rawurlencode( $query ); $apple = 'https://maps.apple.com/?q=' . rawurlencode( '' !== $name ? $name : $query ); $apple .= '' !== $coords ? '&ll=' . rawurlencode( $coords ) : '&address=' . rawurlencode( $address ); $osm = '' !== $coords ? sprintf( 'https://www.openstreetmap.org/?mlat=%1$s&mlon=%2$s#map=17/%1$s/%2$s', rawurlencode( $lat ), rawurlencode( $lng ) ) : 'https://www.openstreetmap.org/search?query=' . rawurlencode( $query ); switch ( bcal_opt( 'map_provider' ) ) { case 'osm': return array( 'href' => $osm, 'apple' => '', ); case 'apple_ios': return array( 'href' => $google, 'apple' => $apple, ); default: return array( 'href' => $google, 'apple' => '', ); } } /* ========================================================================== Languages, affiliate notice ========================================================================== */ /** * Current content language code. * * @return string */ function bcal_current_lang() { if ( function_exists( 'pll_current_language' ) ) { $lang = pll_current_language( 'slug' ); if ( $lang ) { return (string) $lang; } } $wpml = apply_filters( 'wpml_current_language', null ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WPML API. if ( $wpml ) { return (string) $wpml; } return substr( (string) determine_locale(), 0, 2 ); } /** * Languages used on the site (Polylang, WPML or the site locale). * * @return array */ function bcal_site_languages() { $langs = array(); if ( function_exists( 'pll_languages_list' ) ) { $langs = (array) pll_languages_list( array( 'fields' => 'slug' ) ); } else { $wpml = apply_filters( 'wpml_active_languages', null ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WPML API. if ( is_array( $wpml ) ) { $langs = array_keys( $wpml ); } } if ( ! $langs ) { $langs = array( substr( (string) get_locale(), 0, 2 ) ); } $saved = (array) bcal_opt( 'notice_langs' ); $langs = array_merge( $langs, array_keys( $saved ) ); return array_values( array_unique( array_filter( array_map( 'sanitize_key', $langs ) ) ) ); } /** * Affiliate notice text for the current language. * * @return string */ function bcal_notice_text() { $langs = (array) bcal_opt( 'notice_langs' ); $lang = bcal_current_lang(); if ( ! empty( $langs[ $lang ] ) ) { return (string) $langs[ $lang ]; } return (string) bcal_opt( 'notice_default' ); } /** * Notice markup for a given place in the layout. * * @param array $event Event data. * @param string $place "content" or "ticket". * @return string */ function bcal_notice_html( $event, $place ) { $position = (string) bcal_opt( 'notice_position' ); $wanted = ( 'both' === $position ) || ( 'content' === $place && 'after_content' === $position ) || ( 'ticket' === $place && 'near_ticket' === $position ); if ( ! $wanted ) { return ''; } if ( bcal_opt( 'notice_only_ticket' ) && empty( $event['ticket_url'] ) && empty( $event['ticket_url_2'] ) ) { return ''; } $text = trim( bcal_notice_text() ); if ( '' === $text ) { return ''; } return '
' . bcal_icon( 'info' ) . '

' . nl2br( esc_html( $text ) ) . '

'; } /* ========================================================================== Templates, views, icons ========================================================================== */ /** * Available list views. * * @return array */ function bcal_views() { return apply_filters( 'bcal_views', array( 'list' => array( 'label' => __( 'List', 'bearius-calendar' ), 'template' => 'views/list', ), 'month' => array( 'label' => __( 'Month', 'bearius-calendar' ), 'template' => 'views/month', ), 'tiles' => array( 'label' => __( 'Tiles', 'bearius-calendar' ), 'template' => 'views/tiles', ), ) ); } /** * Available single event layouts. * * @return array */ function bcal_single_layouts() { return apply_filters( 'bcal_single_layouts', array( 'classic' => array( 'label' => __( 'Classic', 'bearius-calendar' ), 'template' => 'single/classic', ), ) ); } /** * Finds a template. Themes may override any file by copying it to * "your-theme/bearius-calendar/.php". * * @param string $name Template name without extension. * @return string */ function bcal_locate_template( $name ) { $name = ltrim( (string) $name, '/' ); $theme = locate_template( array( 'bearius-calendar/' . $name . '.php' ) ); if ( $theme ) { return $theme; } $paths = (array) apply_filters( 'bcal_template_paths', array( BCAL_DIR . 'templates/' ) ); foreach ( $paths as $path ) { $file = trailingslashit( $path ) . $name . '.php'; if ( file_exists( $file ) ) { return $file; } } return ''; } /** * Renders a template to a string. Templates receive data in $args. * * @param string $name Template name. * @param array $args Data. * @return string */ function bcal_get_template_html( $name, $args = array() ) { $file = bcal_locate_template( $name ); if ( ! $file ) { return ''; } ob_start(); load_template( $file, false, $args ); return (string) ob_get_clean(); } /** * Inline stroke icons, no icon font. * * @param string $name Icon name. * @return string */ function bcal_icon( $name ) { $paths = array( 'pin' => '', 'clock' => '', 'calendar' => '', 'plus-cal' => '', 'share' => '', 'info' => '', 'left' => '', 'right' => '', 'nav' => '', 'copy' => '', 'ticket' => '', 'repeat' => '', 'down' => '', ); if ( ! isset( $paths[ $name ] ) ) { return ''; } return ''; } /** * ICS download URL for an event, or for one date of a recurring event. * * @param int $post_id Event ID. * @param string $date Optional "Y-m-d" of one occurrence. * @return string */ function bcal_ics_url( $post_id, $date = '' ) { $args = array( 'bcal_ics' => (int) $post_id ); if ( $date ) { $args['bcal_date'] = $date; } return add_query_arg( $args, home_url( '/' ) ); } /** * Colour of a category (term field), inherited from the parent when empty. * * @param WP_Term|null $term Category. * @return string Hex or empty. */ function bcal_category_color( $term ) { $depth = 0; while ( $term instanceof WP_Term && $depth < 5 ) { $color = bcal_normalize_hex( (string) get_term_meta( $term->term_id, 'bcal_color', true ) ); if ( $color ) { return $color; } $term = $term->parent ? get_term( $term->parent, $term->taxonomy ) : null; ++$depth; } return ''; } /** * Inline style that hands a category colour to CSS. * * @param string $color Hex. * @return string */ function bcal_cat_style( $color ) { return $color ? '--bcal-cat:' . $color . ';' : ''; } /** * Fallback image (settings). Used only where an image is technically * required: Event structured data and social previews. Never shown on * the calendar pages themselves. * * @return int Attachment ID or 0. */ function bcal_fallback_image_id() { $id = absint( bcal_opt( 'fallback_image' ) ); return ( $id && wp_attachment_is_image( $id ) ) ? $id : 0; } /** * Image URL for machines: the event image, else the fallback image. * * @param int $post_id Event ID. * @param string $size Image size. * @return string */ function bcal_machine_image_url( $post_id, $size = 'large' ) { $url = get_the_post_thumbnail_url( $post_id, $size ); if ( ! $url ) { $fallback = bcal_fallback_image_id(); $url = $fallback ? (string) wp_get_attachment_image_url( $fallback, $size ) : ''; } return (string) $url; }