label. */ function clanfront_page_templates() { return array( 'clanfront-home' => 'Clanfront: Homepage', 'clanfront-about' => 'Clanfront: About', 'clanfront-join' => 'Clanfront: Join us', 'clanfront-rules' => 'Clanfront: Rules', 'clanfront-servers' => 'Clanfront: Game servers', 'clanfront-page' => 'Clanfront: Page', ); } add_filter( 'theme_page_templates', function ( $templates ) { return array_merge( $templates, clanfront_page_templates() ); } ); /** Which Clanfront view is showing, or '' for normal theme pages. */ function clanfront_view() { if ( is_singular( 'clanfront_member' ) ) { return 'single-member'; } if ( is_singular( 'clanfront_match' ) ) { return 'single-match'; } if ( is_post_type_archive( 'clanfront_member' ) ) { return 'archive-member'; } if ( is_post_type_archive( 'clanfront_match' ) ) { return 'archive-match'; } if ( is_post_type_archive( 'clanfront_media' ) ) { return 'archive-media'; } if ( is_singular( 'clanfront_news' ) ) { return 'single-news'; } if ( is_post_type_archive( 'clanfront_news' ) ) { return 'archive-news'; } if ( is_singular( 'clanfront_game' ) ) { return 'single-game'; } if ( is_post_type_archive( 'clanfront_game' ) ) { return 'archive-game'; } if ( is_post_type_archive( 'clanfront_shame' ) ) { return 'archive-shame'; } if ( is_post_type_archive( 'clanfront_milestone' ) ) { return 'archive-history'; } $section = function_exists( 'clanfront_competition_request' ) ? clanfront_competition_request() : ''; if ( $section && ( clanfront_feature_on( $section ) || current_user_can( 'edit_posts' ) ) ) { if ( is_singular( 'clanfront_tourney' ) ) { return 'single-tournament'; } return is_post_type_archive( 'clanfront_tourney' ) ? 'archive-tournament' : ''; } if ( is_page() ) { $slug = (string) get_page_template_slug( get_queried_object_id() ); if ( 0 === strpos( $slug, 'clanfront-' ) && array_key_exists( $slug, clanfront_page_templates() ) ) { return substr( $slug, strlen( 'clanfront-' ) ); } } return ''; } // A gallery item has no page of its own: send visitors to the gallery. add_action( 'template_redirect', function () { if ( is_singular( 'clanfront_media' ) ) { wp_safe_redirect( get_post_type_archive_link( 'clanfront_media' ) ); exit; } } ); add_filter( 'template_include', function ( $template ) { $view = clanfront_view(); if ( $view ) { $file = CLANFRONT_DIR . 'templates/' . $view . '.php'; if ( file_exists( $file ) ) { return $file; } } return $template; }, 99 ); add_action( 'wp_enqueue_scripts', function () { if ( ! clanfront_view() ) { return; } wp_enqueue_style( 'clanfront-site', CLANFRONT_URL . 'assets/style.css', array(), CLANFRONT_VERSION ); wp_enqueue_script( 'clanfront-site', CLANFRONT_URL . 'assets/site.js', array(), CLANFRONT_VERSION, true ); } ); // On Clanfront views, unload the theme's own styles so they can't fight the design. add_action( 'wp_print_styles', function () { if ( ! clanfront_view() ) { return; } $wp_styles = wp_styles(); $theme_dirs = array_unique( array( get_template_directory_uri(), get_stylesheet_directory_uri() ) ); foreach ( (array) $wp_styles->queue as $handle ) { $src = isset( $wp_styles->registered[ $handle ] ) ? (string) $wp_styles->registered[ $handle ]->src : ''; foreach ( $theme_dirs as $dir ) { if ( $src && 0 === strpos( $src, $dir ) ) { wp_dequeue_style( $handle ); } } } // GeneratePress prints its customiser colours inline under these handles (harmless with other themes). wp_dequeue_style( 'generate-style' ); wp_dequeue_style( 'generate-main' ); }, 100 ); add_filter( 'body_class', function ( $classes ) { if ( clanfront_view() ) { $classes[] = 'clanfront-site'; } return $classes; } ); /** Default when the active theme does not manage it. */ function clanfront_document_title() { if ( current_theme_supports( 'title-tag' ) ) { return; } echo '<title>' . esc_html( wp_get_document_title() ) . '' . "\n"; } /* ---------- Calendar feed (.ics) ---------- */ function clanfront_ics_escape( $text ) { $text = str_replace( array( '\\', ';', ',' ), array( '\\\\', '\;', '\\,' ), (string) $text ); return str_replace( array( "\r\n", "\r", "\n" ), '\\n', $text ); } /** Fold a line to 75 bytes as the calendar format asks. */ function clanfront_ics_fold( $line ) { $out = ''; while ( strlen( $line ) > 75 ) { $cut = 75; while ( $cut > 0 && ( ord( $line[ $cut ] ) & 0xC0 ) === 0x80 ) { --$cut; // Do not split inside a multi-byte character. } $out .= substr( $line, 0, $cut ) . "\r\n "; $line = substr( $line, $cut ); } return $out . $line; } /** Calendar text for upcoming events, or for one event when $only is given. */ function clanfront_ics( $events ) { $lines = array( 'BEGIN:VCALENDAR', 'VERSION:2.0', 'PRODID:-//Clanfront//EN', 'CALSCALE:GREGORIAN', 'METHOD:PUBLISH', 'X-WR-CALNAME:' . clanfront_ics_escape( clanfront_name() ) ); $host = (string) wp_parse_url( home_url(), PHP_URL_HOST ); $utc = new DateTimeZone( 'UTC' ); $stamp = gmdate( 'Ymd\THis\Z' ); foreach ( $events as $e ) { $start = clanfront_event_start( $e ); if ( ! $start ) { continue; } $game = (string) get_post_meta( $e->ID, 'clanfront_game', true ); $opp = (string) get_post_meta( $e->ID, 'clanfront_opponent', true ); $notes = (string) get_post_meta( $e->ID, 'clanfront_notes', true ); $summary = get_the_title( $e ) . ( $game ? ' (' . $game . ')' : '' ); $desc = trim( clanfront_event_kind_label( $e ) . ( $opp ? ' vs ' . $opp : '' ) . ( $notes ? "\n" . $notes : '' ) ); $lines[] = 'BEGIN:VEVENT'; $lines[] = 'UID:clanfront-' . (int) $e->ID . '@' . $host; $lines[] = 'DTSTAMP:' . $stamp; if ( clanfront_event_time( $e ) ) { $s = clone $start; $s->setTimezone( $utc ); $end = clone $s; $end->modify( '+2 hours' ); $lines[] = 'DTSTART:' . $s->format( 'Ymd\THis\Z' ); $lines[] = 'DTEND:' . $end->format( 'Ymd\THis\Z' ); } else { $next = clone $start; $next->modify( '+1 day' ); $lines[] = 'DTSTART;VALUE=DATE:' . $start->format( 'Ymd' ); $lines[] = 'DTEND;VALUE=DATE:' . $next->format( 'Ymd' ); } $lines[] = 'SUMMARY:' . clanfront_ics_escape( $summary ); $lines[] = 'DESCRIPTION:' . clanfront_ics_escape( $desc ); $lines[] = 'URL:' . esc_url_raw( get_permalink( $e ) ); $lines[] = 'END:VEVENT'; } $lines[] = 'END:VCALENDAR'; return implode( "\r\n", array_map( 'clanfront_ics_fold', $lines ) ) . "\r\n"; } /** The feed address people add to Google Calendar, Apple Calendar or Outlook. */ function clanfront_ics_url() { return add_query_arg( 'clanfront_ics', '1', home_url( '/' ) ); } add_action( 'template_redirect', function () { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- a public, read-only feed. if ( ! isset( $_GET['clanfront_ics'] ) ) { return; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended $one = isset( $_GET['event'] ) ? absint( $_GET['event'] ) : 0; $events = array(); if ( $one ) { $p = get_post( $one ); if ( $p && 'clanfront_match' === $p->post_type && 'publish' === $p->post_status ) { $events = array( $p ); } } else { $events = clanfront_get_events( array( 'when' => 'upcoming' ) ); } nocache_headers(); header( 'Content-Type: text/calendar; charset=utf-8' ); header( 'Content-Disposition: inline; filename="' . ( $one ? 'event' : 'schedule' ) . '.ics"' ); echo clanfront_ics( $events ); // phpcs:ignore WordPress.Security.EscapeOutput -- calendar text, escaped by clanfront_ics_escape(). exit; }, 1 ); // Layout choice as a body class (centered column or full width). add_filter( 'body_class', function ( $classes ) { if ( function_exists( 'clanfront_view' ) && clanfront_view() ) { $classes[] = 'full' === clanfront_setting( 'layout' ) ? 'clanfront-layout-full' : 'clanfront-layout-centered'; } return $classes; } );