diff --git a/includes/sp-venue-meta.php b/includes/sp-venue-meta.php index 95ae76c..9595e78 100644 --- a/includes/sp-venue-meta.php +++ b/includes/sp-venue-meta.php @@ -2,7 +2,7 @@ /** * Venue term metadata support. * - * Adds short name and abbreviation fields to SportsPress venues. + * Adds short name, abbreviation, and ground rules fields to SportsPress venues. */ if ( ! defined( 'ABSPATH' ) ) { @@ -40,9 +40,319 @@ function tony_sportspress_register_venue_term_meta() { }, ) ); + + register_term_meta( + 'sp_venue', + 'tse_ground_rules', + array( + 'type' => 'string', + 'single' => true, + 'sanitize_callback' => 'wp_kses_post', + 'show_in_rest' => true, + 'auth_callback' => static function() { + return current_user_can( 'manage_categories' ); + }, + ) + ); } add_action( 'init', 'tony_sportspress_register_venue_term_meta' ); +/** + * Determine whether the field page should show its event list. + * + * The setting is stored in the core SportsPress Events settings page under + * the venue/field section. + * + * @return bool + */ +function tony_sportspress_field_event_list_enabled() { + $enabled = get_option( 'sportspress_event_show_venue_list', 'yes' ) === 'yes'; + + return (bool) apply_filters( 'tony_sportspress_field_event_list_enabled', $enabled ); +} + +/** + * Get the venue map caption text. + * + * @return string + */ +function tony_sportspress_get_venue_map_caption() { + return (string) apply_filters( 'tony_sportspress_venue_map_caption', __( 'Field Map', 'tonys-sportspress-enhancements' ) ); +} + +/** + * Add the field page event list setting to SportsPress > Settings > Games > Fields. + * + * @param array $options Existing venue settings. + * @return array + */ +function tony_sportspress_add_venue_settings( $options ) { + $options[] = array( + 'title' => esc_attr__( 'Event List', 'tonys-sportspress-enhancements' ), + 'desc' => esc_attr__( 'Display event list on field pages', 'tonys-sportspress-enhancements' ), + 'id' => 'sportspress_event_show_venue_list', + 'default' => 'yes', + 'type' => 'checkbox', + ); + + return $options; +} +add_filter( 'sportspress_venue_options', 'tony_sportspress_add_venue_settings' ); + +/** + * Enqueue the visual editor on the venue taxonomy screen. + * + * This turns the built-in description textarea into the standard WordPress + * TinyMCE editor so venue descriptions can use markup and links. + * + * @param string $hook_suffix Current admin page hook. + */ +function tony_sportspress_enqueue_venue_description_editor( $hook_suffix ) { + if ( ! in_array( $hook_suffix, array( 'edit-tags.php', 'term.php' ), true ) ) { + return; + } + + $taxonomy = isset( $_GET['taxonomy'] ) ? sanitize_key( wp_unslash( $_GET['taxonomy'] ) ) : ''; + if ( 'sp_venue' !== $taxonomy ) { + return; + } + + if ( ! function_exists( 'wp_enqueue_editor' ) ) { + return; + } + + wp_enqueue_editor(); + + $script = <<<'JS' +(function() { + function initEditor(id) { + var textarea = document.getElementById(id); + if (!textarea || textarea.dataset.tseEditorInitialized) { + return; + } + + textarea.dataset.tseEditorInitialized = '1'; + window.wp.editor.initialize(id, { + tinymce: { + wpautop: true, + menubar: false, + statusbar: true, + toolbar1: 'formatselect,bold,italic,bullist,numlist,blockquote,alignleft,aligncenter,alignright,link,unlink,wp_more,spellchecker,fullscreen', + toolbar2: 'strikethrough,hr,forecolor,pastetext,removeformat,charmap,outdent,indent,undo,redo,wp_help', + block_formats: 'Paragraph=p; Heading 2=h2; Heading 3=h3; Heading 4=h4; Preformatted=pre', + }, + quicktags: true, + mediaButtons: true + }); + } + + document.addEventListener('DOMContentLoaded', function() { + if (!window.wp || !wp.editor) { + return; + } + + // Different taxonomy screens use different IDs for the same description field. + initEditor('description'); + initEditor('tag-description'); + }); +})(); +JS; + + wp_add_inline_script( 'editor', $script ); +} +add_action( 'admin_enqueue_scripts', 'tony_sportspress_enqueue_venue_description_editor' ); + +/** + * Hide the built-in venue archive description output. + * + * Venue content is rendered as SportsPress-style sections instead of inside + * the archive header. + * + * @param string $description Archive description HTML. + * @return string + */ +function tony_sportspress_hide_venue_archive_description( $description ) { + if ( is_tax( 'sp_venue' ) ) { + return ''; + } + + return $description; +} +add_filter( 'get_the_archive_description', 'tony_sportspress_hide_venue_archive_description', 99 ); + +/** + * Determine whether the current venue has map coordinates. + * + * @return bool + */ +function tony_sportspress_current_venue_has_map() { + $term = get_queried_object(); + if ( ! $term instanceof WP_Term ) { + return false; + } + + $latitude = trim( (string) get_term_meta( $term->term_id, 'sp_latitude', true ) ); + $longitude = trim( (string) get_term_meta( $term->term_id, 'sp_longitude', true ) ); + + return '' !== $latitude && '' !== $longitude; +} + +/** + * Render the venue ground rules section. + * + * @return void + */ +function tony_sportspress_render_venue_ground_rules_section() { + if ( ! is_tax( 'sp_venue' ) ) { + return; + } + + $term = get_queried_object(); + if ( ! $term instanceof WP_Term ) { + return; + } + + $ground_rules = get_term_meta( $term->term_id, 'tse_ground_rules', true ); + if ( ! is_string( $ground_rules ) || '' === trim( $ground_rules ) ) { + return; + } + + $ground_rules = apply_filters( 'the_content', $ground_rules ); + + echo '

' . esc_html__( 'Ground Rules', 'tonys-sportspress-enhancements' ) . '

' . $ground_rules . '
'; +} +add_action( 'sportspress_before_venue_map', 'tony_sportspress_render_venue_ground_rules_section', 5 ); + +/** + * Open the venue map section wrapper. + * + * @return void + */ +function tony_sportspress_open_venue_map_section() { + if ( ! is_tax( 'sp_venue' ) || ! tony_sportspress_current_venue_has_map() ) { + return; + } + + $GLOBALS['tse_venue_map_section_open'] = true; + echo '

' . esc_html( tony_sportspress_get_venue_map_caption() ) . '

'; +} +add_action( 'sportspress_before_venue_map', 'tony_sportspress_open_venue_map_section', 15 ); + +/** + * Close the venue map section wrapper. + * + * @return void + */ +function tony_sportspress_close_venue_map_section() { + if ( empty( $GLOBALS['tse_venue_map_section_open'] ) ) { + return; + } + + $GLOBALS['tse_venue_map_section_open'] = false; + echo '
'; +} +add_action( 'sportspress_after_venue_map', 'tony_sportspress_close_venue_map_section', 5 ); + +/** + * Enqueue venue section styles. + * + * The venue map and ground rules are rendered as SportsPress-style sections + * rather than archive header content, so they need section-scoped typography + * and list styling. + * + * @return void + */ +function tony_sportspress_enqueue_venue_section_styles() { + if ( ! is_tax( 'sp_venue' ) ) { + return; + } + + wp_register_style( 'tony-sportspress-venue-sections', false, array(), TONY_SPORTSPRESS_ENHANCEMENTS_VERSION ); + wp_enqueue_style( 'tony-sportspress-venue-sections' ); + + $event_list_display = tony_sportspress_field_event_list_enabled() ? 'block' : 'none'; + + $css = <<

+
+ + 'tse_ground_rules', + 'textarea_rows' => 10, + 'media_buttons' => true, + 'teeny' => false, + 'quicktags' => true, + 'drag_drop_upload' => true, + ) + ); + ?> +

+
term_id, 'tse_short_name', true ); $abbreviation = get_term_meta( $term->term_id, 'tse_abbreviation', true ); + $ground_rules = get_term_meta( $term->term_id, 'tse_ground_rules', true ); ?> @@ -89,6 +418,28 @@ function tony_sportspress_edit_venue_meta_fields( $term ) {

+ + + + + + 'tse_ground_rules', + 'textarea_rows' => 10, + 'media_buttons' => true, + 'teeny' => false, + 'quicktags' => true, + 'drag_drop_upload' => true, + ) + ); + ?> +

+ +