true, 'id' => true, 'style' => true, 'title' => true, 'role' => true, 'aria-label' => true, 'aria-hidden' => true, 'tabindex' => true, 'data-*' => true, ); $extra = array( 'iframe' => array( 'src' => true, 'width' => true, 'height' => true, 'frameborder' => true, 'allow' => true, 'allowfullscreen' => true, 'allowtransparency' => true, 'loading' => true, 'referrerpolicy' => true, 'sandbox' => true, 'name' => true, ), 'img' => array( 'srcset' => true, 'sizes' => true, 'decoding' => true, 'loading' => true, 'fetchpriority' => true, ), 'svg' => array( 'viewbox' => true, 'xmlns' => true, 'width' => true, 'height' => true, 'fill' => true, 'stroke' => true, 'focusable' => true, ), 'path' => array( 'd' => true, 'fill' => true, 'stroke' => true, 'stroke-width' => true, 'stroke-linecap' => true, 'stroke-linejoin' => true, ), 'rect' => array( 'x' => true, 'y' => true, 'width' => true, 'height' => true, 'rx' => true, 'fill' => true, 'stroke' => true, ), 'circle' => array( 'cx' => true, 'cy' => true, 'r' => true, 'fill' => true, 'stroke' => true, ), 'form' => array( 'action' => true, 'method' => true, ), 'input' => array( 'type' => true, 'name' => true, 'value' => true, 'checked' => true, 'required' => true, 'min' => true, 'max' => true, 'maxlength' => true, 'autocomplete' => true, 'placeholder' => true, 'list' => true, ), 'select' => array( 'name' => true, 'required' => true, ), 'option' => array( 'value' => true, 'selected' => true, ), 'textarea' => array( 'name' => true, 'rows' => true, 'maxlength' => true, 'required' => true, ), 'button' => array( 'type' => true, 'name' => true, ), 'label' => array( 'for' => true, ), 'datalist' => array(), 'time' => array( 'datetime' => true, ), ); foreach ( $extra as $tag => $attrs ) { $allowed[ $tag ] = array_merge( isset( $allowed[ $tag ] ) ? $allowed[ $tag ] : array(), $attrs ); } foreach ( $allowed as $tag => $attrs ) { $allowed[ $tag ] = array_merge( is_array( $attrs ) ? $attrs : array(), $global ); } return $allowed; } /* ---------- Settings ---------- */ function clanfront_default_settings() { return array( 'clan_name' => 'Your Clan', 'tagline' => 'Play together. Win together.', 'mission' => 'We are a community of players who love competing and having fun together. Write your mission statement here: who you are, what you stand for, and who you are looking for.', 'logo' => '', 'hero_image' => '', // Empty = the banner that ships with the plugin. 'hero_video' => '', // Optional .mp4 address. Plays silently behind the headline. 'color' => '#7c5cff', 'layout' => 'centered', // centered or full (edge to edge). 'join_label' => 'Join us', 'values' => '', 'games' => '', 'achievements' => '', 'recruiting' => '1', 'requirements' => '', 'min_age' => 0, 'application_url' => '', 'application_email' => '', 'rules' => '', 'discord_invite' => '', 'discord_server_id' => '', 'twitch_client_id' => '', 'twitch_client_secret' => '', 'twitch_videos' => '1', // Latest Twitch videos on the homepage and member pages (needs the Twitch keys). 'show_tournaments' => '0', // Tournaments stay hidden from visitors until switched on. 'email' => '', 'instagram' => '', 'x' => '', 'youtube_channel' => '', 'tiktok' => '', 'twitch_channel' => '', 'support_url' => '', // Optional "Support us" link, for example a Buy Me a Coffee page. 'support_label' => 'Support us', ); } /** Settings that are long text and keep their line breaks. */ function clanfront_textarea_keys() { return array( 'mission', 'values', 'games', 'achievements', 'requirements', 'rules' ); } function clanfront_settings() { $saved = get_option( 'clanfront_settings', array() ); return wp_parse_args( is_array( $saved ) ? $saved : array(), clanfront_default_settings() ); } function clanfront_setting( $key ) { $s = clanfront_settings(); $v = isset( $s[ $key ] ) ? $s[ $key ] : ''; if ( 'hero_image' === $key ) { return '' === $v ? CLANFRONT_URL . 'assets/img/hero.jpg' : $v; } if ( 'clan_name' === $key && '' === $v ) { $d = clanfront_default_settings(); return $d['clan_name']; } if ( 'color' === $key ) { return preg_match( '/^#[0-9a-fA-F]{6}$/', (string) $v ) ? $v : '#7c5cff'; } if ( 'application_email' === $key && '' === $v ) { return (string) get_option( 'admin_email' ); } return $v; } function clanfront_name() { return clanfront_setting( 'clan_name' ); } /** * Make an image address from this site work from anywhere. * An address saved as http://192.168.x.x/wp-content/... (or any other host) * becomes /wp-content/..., so the browser loads it from whatever address the * visitor used: local IP, domain, http or https. Links to other sites are left alone. */ function clanfront_local_url( $url ) { $url = (string) $url; $path = (string) wp_parse_url( $url, PHP_URL_PATH ); $base = (string) wp_parse_url( content_url(), PHP_URL_PATH ); // Usually "/wp-content". if ( $path && $base && 0 === strpos( $path, rtrim( $base, '/' ) . '/' ) ) { $query = (string) wp_parse_url( $url, PHP_URL_QUERY ); return $path . ( $query ? '?' . $query : '' ); } return $url; } /** A setting with one item per line, as a list of non-empty trimmed lines. */ function clanfront_lines( $key ) { return array_values( array_filter( array_map( 'trim', preg_split( '/\r\n|\r|\n/', (string) clanfront_setting( $key ) ) ), 'strlen' ) ); } /** "Title | text" lines as a list of array( title, text ). */ function clanfront_pairs( $key ) { $out = array(); foreach ( clanfront_lines( $key ) as $line ) { $parts = array_map( 'trim', explode( '|', $line, 2 ) ); $out[] = array( $parts[0], isset( $parts[1] ) ? $parts[1] : '' ); } return $out; } /** The games the clan plays: the game pages (Clanfront → Games) and the "Games" setting (the name is the part before a |). */ function clanfront_game_names() { $names = array(); if ( function_exists( 'clanfront_get_games' ) ) { foreach ( clanfront_get_games( 'active' ) as $g ) { $names[] = get_the_title( $g ); } } foreach ( clanfront_pairs( 'games' ) as $p ) { $names[] = $p[0]; } return array_values( array_unique( $names ) ); } /** The game page with this name, or null. */ function clanfront_game_by_name( $name ) { $name = trim( (string) $name ); if ( '' === $name || ! function_exists( 'clanfront_get_games' ) ) { return null; } foreach ( clanfront_get_games( 'all' ) as $g ) { if ( 0 === strcasecmp( trim( get_the_title( $g ) ), $name ) ) { return $g; } } return null; } /** The optional "Support us" button (a Buy Me a Coffee page or similar), or ''. */ function clanfront_support_link( $class = 'clanfront-btn' ) { $url = clanfront_clean_url( clanfront_setting( 'support_url' ) ); if ( ! $url ) { return ''; } $label = trim( (string) clanfront_setting( 'support_label' ) ); return '' . esc_html( '' !== $label ? $label : 'Support us' ) . ''; } /* ---------- Social and link helpers ---------- */ /** The footer social icons: setting key => label. */ function clanfront_social_fields() { return array( 'twitch_channel' => 'Twitch', 'youtube_channel' => 'YouTube', 'x' => 'X', 'instagram' => 'Instagram', 'tiktok' => 'TikTok', ); } /** A Twitch channel name from a name or a link such as https://twitch.tv/name. */ function clanfront_twitch_login( $value ) { $value = trim( (string) $value ); if ( '' === $value ) { return ''; } if ( preg_match( '#twitch\.tv/([A-Za-z0-9_]{2,25})#i', $value, $m ) ) { return strtolower( $m[1] ); } return preg_match( '/^[A-Za-z0-9_]{2,25}$/', $value ) ? strtolower( $value ) : ''; } /** Only web links. Anything else becomes an empty string. */ function clanfront_clean_url( $url ) { $url = trim( (string) $url ); if ( '' === $url ) { return ''; } return esc_url_raw( $url, array( 'http', 'https' ) ); } /* ---------- Dates ---------- */ function clanfront_today() { return current_time( 'Y-m-d' ); } function clanfront_format_date( $ymd ) { if ( ! $ymd ) { return ''; } $ts = strtotime( $ymd . ' 12:00:00' ); return $ts ? date_i18n( 'M j, Y', $ts ) : ''; } function clanfront_format_time( $hm ) { if ( ! $hm || ! preg_match( '/^\d{2}:\d{2}$/', $hm ) ) { return ''; } $ts = strtotime( '2000-01-01 ' . $hm . ':00' ); return $ts ? date_i18n( get_option( 'time_format', 'H:i' ), $ts ) : ''; } /* ---------- Members ---------- */ /** Roles offered in the member form. Any other text also works. */ function clanfront_roles() { return array( 'Leader', 'Co-Leader', 'Captain', 'Coach', 'Recruiter', 'Officer', 'Player', 'Member' ); } /** Active members, in the order set in the admin (lowest "Order" first). */ function clanfront_get_members( $opts = array() ) { $o = wp_parse_args( $opts, array( 'limit' => -1 ) ); $all = get_posts( array( 'post_type' => 'clanfront_member', 'post_status' => 'publish', 'posts_per_page' => -1, 'orderby' => array( 'menu_order' => 'ASC', 'title' => 'ASC' ), 'no_found_rows' => true, ) ); $members = array(); foreach ( $all as $m ) { if ( '0' !== (string) get_post_meta( $m->ID, 'clanfront_active', true ) ) { $members[] = $m; } } return ( (int) $o['limit'] > 0 ) ? array_slice( $members, 0, (int) $o['limit'] ) : $members; } /** A member's own accent colour (#rrggbb), or '' to use the clan's colour. */ function clanfront_member_color( $member ) { $c = (string) get_post_meta( $member->ID, 'clanfront_color', true ); return preg_match( '/^#[0-9a-fA-F]{6}$/', $c ) ? $c : ''; } function clanfront_member_role( $member ) { return (string) get_post_meta( $member->ID, 'clanfront_role', true ); } /** The member's links as a list of array( label, url ). */ function clanfront_member_links( $member ) { $links = array(); $login = clanfront_twitch_login( get_post_meta( $member->ID, 'clanfront_twitch', true ) ); if ( $login ) { $links[] = array( 'Twitch', 'https://www.twitch.tv/' . $login, clanfront_status_tag( $login, clanfront_live_streams() ) ); } $map = array( 'clanfront_youtube' => 'YouTube', 'clanfront_x' => 'X', 'clanfront_instagram' => 'Instagram', 'clanfront_stats_url' => 'Stats', ); foreach ( $map as $key => $label ) { $url = clanfront_clean_url( get_post_meta( $member->ID, $key, true ) ); if ( $url ) { $links[] = array( $label, $url ); } } return $links; } function clanfront_buttons( $links, $class = 'clanfront-btn clanfront-btn--small' ) { $html = ''; foreach ( $links as $l ) { $tag = isset( $l[2] ) ? (string) $l[2] : ''; // Already escaped by clanfront_status_tag(). $html .= sprintf( '%s%s', esc_attr( $class ), esc_url( $l[1] ), esc_html( $l[0] ), $tag ? ' ' . $tag : '' ); } return $html; } /** Picture for a member: the uploaded image, or a tile with their initials. */ function clanfront_avatar( $member, $size = 'medium_large' ) { if ( has_post_thumbnail( $member ) ) { return '
' . esc_html( $empty ) . '
'; } $html = 'No game servers listed yet.
'; } $html = '
Community
See who is online, find a team and join the conversation.
' . esc_html( $empty ) . '
' : ''; } ob_start(); echo '