clanfront_labels( 'Game', 'Games', array( 'featured_image' => 'Cover image', 'set_featured_image' => 'Set cover image', 'remove_featured_image' => 'Remove cover image', 'use_featured_image' => 'Use as cover image', 'add_new' => 'Add game', ) ), 'public' => true, 'has_archive' => 'games', 'rewrite' => array( 'slug' => 'game', 'with_front' => false ), 'supports' => array( 'title', 'editor', 'thumbnail', 'page-attributes' ), 'show_in_menu' => CLANFRONT_MENU, 'show_in_rest' => false, ) ); register_post_type( 'clanfront_award', array( 'labels' => clanfront_labels( 'Medal', 'Medals', array( 'add_new' => 'Add medal', 'featured_image' => 'Medal picture (optional)', 'set_featured_image' => 'Set medal picture', 'remove_featured_image' => 'Remove medal picture', 'use_featured_image' => 'Use as medal picture', ) ), 'public' => false, 'show_ui' => true, 'exclude_from_search' => true, 'supports' => array( 'title', 'thumbnail', 'page-attributes' ), 'show_in_menu' => CLANFRONT_MENU, 'show_in_rest' => false, ) ); register_post_type( 'clanfront_shame', array( 'labels' => clanfront_labels( 'Hall of Shame entry', 'Hall of Shame', array( 'menu_name' => 'Hall of Shame', 'all_items' => 'Hall of Shame', 'add_new' => 'Add entry', 'not_found' => 'No shameful moments yet', 'featured_image' => 'Picture (optional)', 'set_featured_image' => 'Set picture', 'remove_featured_image' => 'Remove picture', 'use_featured_image' => 'Use as picture', ) ), 'public' => true, 'has_archive' => 'hall-of-shame', 'rewrite' => array( 'slug' => 'shame', 'with_front' => false ), 'supports' => array( 'title', 'editor', 'thumbnail' ), 'show_in_menu' => CLANFRONT_MENU, 'show_in_rest' => false, ) ); register_post_type( 'clanfront_milestone', array( 'labels' => clanfront_labels( 'Milestone', 'History', array( 'menu_name' => 'History', 'all_items' => 'History', 'add_new' => 'Add milestone', 'not_found' => 'No milestones yet', 'featured_image' => 'Picture (optional)', 'set_featured_image' => 'Set picture', 'remove_featured_image' => 'Remove picture', 'use_featured_image' => 'Use as picture', ) ), 'public' => true, 'has_archive' => 'history', 'rewrite' => array( 'slug' => 'milestone', 'with_front' => false ), 'supports' => array( 'title', 'editor', 'thumbnail' ), 'show_in_menu' => CLANFRONT_MENU, 'show_in_rest' => false, ) ); } add_action( 'init', 'clanfront_register_extra_types' ); // Hall of Shame entries and milestones have no page of their own: send visitors to the list, at that entry. add_action( 'template_redirect', function () { foreach ( array( 'clanfront_shame' => 'shame', 'clanfront_milestone' => 'milestone' ) as $type => $anchor ) { if ( is_singular( $type ) ) { wp_safe_redirect( get_post_type_archive_link( $type ) . '#' . $anchor . '-' . get_queried_object_id() ); exit; } } } ); /* ---------- Games ---------- */ function clanfront_game_statuses() { return array( 'active' => 'Playing now', 'retired' => 'Retired (the Game Graveyard)', ); } /** Game pages. $status: 'active', 'retired' or 'all'. In the order set in the admin. */ function clanfront_get_games( $status = 'active' ) { $all = get_posts( array( 'post_type' => 'clanfront_game', 'post_status' => 'publish', 'posts_per_page' => -1, 'orderby' => array( 'menu_order' => 'ASC', 'title' => 'ASC' ), 'no_found_rows' => true, ) ); if ( 'all' === $status ) { return $all; } $out = array(); foreach ( $all as $g ) { $s = 'retired' === (string) get_post_meta( $g->ID, 'clanfront_status', true ) ? 'retired' : 'active'; if ( $s === $status ) { $out[] = $g; } } return $out; } function clanfront_has_games() { return (bool) clanfront_get_games( 'all' ); } /** Lower-case game names written in a member's "Games" field. */ function clanfront_member_game_list( $member ) { $raw = (string) get_post_meta( $member->ID, 'clanfront_games', true ); $out = array(); foreach ( preg_split( '/[,\n;]+/', $raw ) as $g ) { $g = trim( $g ); if ( '' !== $g ) { $out[] = function_exists( 'mb_strtolower' ) ? mb_strtolower( $g ) : strtolower( $g ); } } return $out; } /** Active members who list this game in their "Games" field. */ function clanfront_game_players( $game ) { $name = trim( get_the_title( $game ) ); $name = function_exists( 'mb_strtolower' ) ? mb_strtolower( $name ) : strtolower( $name ); $out = array(); foreach ( clanfront_get_members() as $m ) { if ( in_array( $name, clanfront_member_game_list( $m ), true ) ) { $out[] = $m; } } return $out; } /** Cover picture of a game, or a tile with its first letters. */ function clanfront_game_cover( $game, $size = 'medium_large' ) { if ( has_post_thumbnail( $game ) ) { return '' . get_the_post_thumbnail( $game, $size, array( 'alt' => '', 'loading' => 'lazy' ) ) . ''; } $initials = function_exists( 'mb_substr' ) ? mb_strtoupper( mb_substr( get_the_title( $game ), 0, 2 ) ) : strtoupper( substr( get_the_title( $game ), 0, 2 ) ); return ''; } /** Cards that link to each game's page. */ function clanfront_game_cards( $games, $retired = false ) { if ( ! $games ) { return ''; } $html = '
'; foreach ( $games as $g ) { $note = (string) get_post_meta( $g->ID, 'clanfront_note', true ); $epitaph = (string) get_post_meta( $g->ID, 'clanfront_epitaph', true ); $sub = $retired ? $epitaph : $note; $html .= '' . clanfront_game_cover( $g ) . '' . ( $retired ? 'RIP' : '' ) . '' . esc_html( get_the_title( $g ) ) . '' . ( $sub ? '' . esc_html( $sub ) . '' : '' ) . ''; } return $html . '
'; } /** The "What we play" block for the homepage and About page: game pages when there are any, otherwise the Settings list. */ function clanfront_games_block() { $games = clanfront_get_games( 'active' ); if ( $games ) { return clanfront_game_cards( $games ); } $pairs = clanfront_pairs( 'games' ); if ( ! $pairs ) { return ''; } $html = '
'; foreach ( $pairs as $p ) { $html .= '
' . esc_html( $p[0] ) . '' . ( $p[1] ? '' . esc_html( $p[1] ) . '' : '' ) . '
'; } return $html . '
'; } /* ---------- Medals ---------- */ function clanfront_get_awards() { return get_posts( array( 'post_type' => 'clanfront_award', 'post_status' => 'publish', 'posts_per_page' => -1, 'orderby' => array( 'menu_order' => 'ASC', 'title' => 'ASC' ), 'no_found_rows' => true, ) ); } /** The medal's symbol: its picture when it has one, otherwise its emoji (πŸ… by default). */ function clanfront_award_icon( $award, $class = 'clanfront-medal-icon' ) { if ( has_post_thumbnail( $award ) ) { return '' . get_the_post_thumbnail( $award, 'thumbnail', array( 'alt' => '' ) ) . ''; } $icon = trim( (string) get_post_meta( $award->ID, 'clanfront_icon', true ) ); return ''; } /** Published medals a member has been given, in the medal order. */ function clanfront_member_awards( $member ) { $ids = get_post_meta( $member->ID, 'clanfront_awards', true ); $ids = is_array( $ids ) ? array_map( 'absint', $ids ) : array(); if ( ! $ids ) { return array(); } $out = array(); foreach ( clanfront_get_awards() as $a ) { if ( in_array( (int) $a->ID, $ids, true ) ) { $out[] = $a; } } return $out; } /** Small medal row on a roster card. */ function clanfront_member_medal_row( $member, $max = 5 ) { $awards = clanfront_member_awards( $member ); if ( ! $awards ) { return ''; } $html = ''; foreach ( array_slice( $awards, 0, $max ) as $a ) { $html .= '' . clanfront_award_icon( $a ) . '' . esc_html( get_the_title( $a ) ) . ''; } if ( count( $awards ) > $max ) { $html .= '+' . (int) ( count( $awards ) - $max ) . ''; } return $html . ''; } /** The full medal list on a member's page. */ function clanfront_member_medal_list( $member ) { $awards = clanfront_member_awards( $member ); if ( ! $awards ) { return ''; } $html = '

Medals

'; } /* ---------- Hall of Shame ---------- */ /** Published entries, newest first (by the date of the incident, then by when they were added). */ function clanfront_get_shame( $limit = -1 ) { $posts = get_posts( array( 'post_type' => 'clanfront_shame', 'post_status' => 'publish', 'posts_per_page' => -1, 'orderby' => 'date', 'order' => 'DESC', 'no_found_rows' => true, ) ); usort( $posts, function ( $a, $b ) { $da = (string) get_post_meta( $a->ID, 'clanfront_date', true ); $db = (string) get_post_meta( $b->ID, 'clanfront_date', true ); $ka = ( $da ? $da : get_the_date( 'Y-m-d', $a ) ) . ' ' . $a->post_date; $kb = ( $db ? $db : get_the_date( 'Y-m-d', $b ) ) . ' ' . $b->post_date; return strcmp( $kb, $ka ); } ); return ( (int) $limit > 0 ) ? array_slice( $posts, 0, (int) $limit ) : $posts; } function clanfront_has_shame() { return (bool) get_posts( array( 'post_type' => 'clanfront_shame', 'post_status' => 'publish', 'posts_per_page' => 1, 'fields' => 'ids', 'no_found_rows' => true, ) ); } /** Members named as responsible for an entry (published members only). */ function clanfront_shame_culprits( $entry ) { $ids = get_post_meta( $entry->ID, 'clanfront_culprits', true ); $ids = is_array( $ids ) ? array_map( 'absint', $ids ) : array(); $out = array(); foreach ( $ids as $id ) { $m = get_post( $id ); if ( $m && 'clanfront_member' === $m->post_type && 'publish' === $m->post_status ) { $out[] = $m; } } return $out; } /** How many Hall of Shame entries name this member. */ function clanfront_member_shame_count( $member ) { $n = 0; foreach ( clanfront_get_shame() as $e ) { foreach ( clanfront_shame_culprits( $e ) as $m ) { if ( (int) $m->ID === (int) $member->ID ) { ++$n; break; } } } return $n; } /** * The clip as an embedded player (YouTube, Vimeo, Streamable…), using WordPress's own embed support. * The answer is saved for a week so the provider is not asked on every visit. Returns '' when the * link can't be embedded, and the page then shows a "Watch the clip" button instead. */ function clanfront_clip_embed( $url ) { $url = clanfront_clean_url( $url ); if ( ! $url ) { return ''; } $key = 'clanfront_embed_' . md5( $url ); $cached = get_transient( $key ); if ( false !== $cached ) { return (string) $cached; } $html = wp_oembed_get( $url, array( 'width' => 960 ) ); $html = is_string( $html ) ? $html : ''; if ( $html ) { $html = str_replace( '