'date', 'Time' => 'time', 'Venue' => 'venue', 'Home' => 'home', 'Away' => 'away', 'Week / Round' => 'week_round', 'Division' => '', 'Label' => '', 'League' => 'league', 'Season' => 'season', 'Home Score' => 'home_score', 'Away Score' => 'away_score', 'Referee' => '', 'Assistant Referees' => '', 'Notes' => 'notes', ); } /** * Capability used for importer access. * * @return string */ function tse_sp_event_csv_importer_capability() { return current_user_can( 'manage_sportspress' ) ? 'manage_sportspress' : 'manage_options'; } /** * Get available SportsPress event formats. * * @return array */ function tse_sp_event_csv_event_formats() { $formats = array(); if ( function_exists( 'SP' ) && is_object( SP() ) && isset( SP()->formats->event ) && is_array( SP()->formats->event ) ) { $formats = SP()->formats->event; } if ( empty( $formats ) ) { $formats = array( 'league' => __( 'Competitive', 'sportspress' ), 'friendly' => __( 'Friendly', 'sportspress' ), ); } return $formats; } /** * Validate incoming event format against available SportsPress formats. * * @param string $event_format Proposed format key. * @return string */ function tse_sp_event_csv_validate_event_format( $event_format ) { $event_format = sanitize_key( (string) $event_format ); $formats = tse_sp_event_csv_event_formats(); if ( isset( $formats[ $event_format ] ) ) { return $event_format; } return 'league'; } /** * Normalize an outcome token for case-insensitive matching. * * @param string $value Outcome value. * @return string */ function tse_sp_event_csv_normalize_outcome_token( $value ) { $value = wp_strip_all_tags( (string) $value ); $value = html_entity_decode( $value, ENT_QUOTES, get_bloginfo( 'charset' ) ); $value = strtolower( trim( preg_replace( '/\s+/', ' ', $value ) ) ); return $value; } /** * Build and cache SportsPress outcome maps. * * @param bool $refresh Force cache rebuild. * @return array */ function tse_sp_event_csv_outcome_catalog( $refresh = false ) { static $catalog = null; if ( ! $refresh && null !== $catalog ) { return $catalog; } $catalog = array( 'slugs' => array(), 'titles' => array(), 'compact_slugs' => array(), ); $outcome_posts = get_posts( array( 'post_type' => 'sp_outcome', 'post_status' => array( 'publish', 'draft', 'pending', 'future', 'private' ), 'posts_per_page' => -1, 'no_found_rows' => true, ) ); foreach ( $outcome_posts as $outcome_post ) { if ( empty( $outcome_post->post_name ) ) { continue; } $slug = (string) $outcome_post->post_name; $title = (string) $outcome_post->post_title; $catalog['slugs'][ $slug ] = $slug; $catalog['titles'][ tse_sp_event_csv_normalize_outcome_token( $title ) ] = $slug; $catalog['compact_slugs'][ preg_replace( '/[^a-z0-9]/', '', strtolower( $slug ) ) ] = $slug; } return $catalog; } /** * Resolve a user-entered outcome token to an outcome slug. * * Creates outcome posts when a custom value is supplied and no match exists. * * @param string $value Outcome input value. * @return string */ function tse_sp_event_csv_resolve_outcome_slug( $value ) { $value = sanitize_text_field( wp_strip_all_tags( (string) $value ) ); $value = trim( $value ); if ( '' === $value ) { return ''; } $catalog = tse_sp_event_csv_outcome_catalog(); $raw_slug = sanitize_key( $value ); $slug_guess = sanitize_title( $value ); $title_key = tse_sp_event_csv_normalize_outcome_token( $value ); $compact_key = preg_replace( '/[^a-z0-9]/', '', strtolower( $value ) ); if ( '' !== $raw_slug && isset( $catalog['slugs'][ $raw_slug ] ) ) { return $catalog['slugs'][ $raw_slug ]; } if ( '' !== $slug_guess && isset( $catalog['slugs'][ $slug_guess ] ) ) { return $catalog['slugs'][ $slug_guess ]; } if ( '' !== $title_key && isset( $catalog['titles'][ $title_key ] ) ) { return $catalog['titles'][ $title_key ]; } if ( '' !== $compact_key && isset( $catalog['compact_slugs'][ $compact_key ] ) ) { return $catalog['compact_slugs'][ $compact_key ]; } $title = preg_match( '/\s/', $value ) ? $value : ucwords( str_replace( array( '-', '_' ), ' ', $value ) ); $post_id = wp_insert_post( array( 'post_type' => 'sp_outcome', 'post_status' => 'publish', 'post_title' => wp_strip_all_tags( $title ), ), true ); if ( is_wp_error( $post_id ) || ! $post_id ) { return ''; } update_post_meta( $post_id, '_sp_import', 1 ); $outcome = get_post( $post_id ); if ( ! $outcome || empty( $outcome->post_name ) ) { return ''; } tse_sp_event_csv_outcome_catalog( true ); return (string) $outcome->post_name; } /** * Parse an outcome input value into an array of outcome slugs. * * @param string $value Outcome input value. * @return array */ function tse_sp_event_csv_parse_outcome_value( $value ) { $value = trim( (string) $value ); if ( '' === $value ) { return array(); } $tokens = preg_split( '/[\|,]/', $value ); $outcomes = array(); foreach ( $tokens as $token ) { $slug = tse_sp_event_csv_resolve_outcome_slug( $token ); if ( '' !== $slug ) { $outcomes[ $slug ] = $slug; } } return array_values( $outcomes ); } /** * Build default home/away outcomes based on score. * * @param string $home_score Home score. * @param string $away_score Away score. * @return array */ function tse_sp_event_csv_default_outcomes( $home_score, $away_score ) { if ( ! is_numeric( $home_score ) || ! is_numeric( $away_score ) ) { return array( 'home' => '', 'away' => '', ); } $home_score = (float) $home_score; $away_score = (float) $away_score; if ( $home_score > $away_score ) { return array( 'home' => 'win', 'away' => 'loss', ); } if ( $away_score > $home_score ) { return array( 'home' => 'loss', 'away' => 'win', ); } return array( 'home' => 'tie', 'away' => 'tie', ); } /** * Get suggested outcome slugs for preview inputs. * * @return array */ function tse_sp_event_csv_outcome_suggestions() { $suggestions = array( 'technicalforfeitwin', 'technicalforfeitloss', 'win', 'loss', 'tie', 'forfeitwin', 'forfeitloss', ); $catalog = tse_sp_event_csv_outcome_catalog(); foreach ( array_keys( $catalog['slugs'] ) as $slug ) { $suggestions[] = $slug; } $suggestions = array_values( array_unique( array_filter( $suggestions ) ) ); sort( $suggestions ); return $suggestions; } /** * Register importer in WordPress Tools > Import screen. */ function tse_sp_event_csv_register_importer() { if ( ! is_admin() ) { return; } if ( ! function_exists( 'register_importer' ) ) { require_once ABSPATH . 'wp-admin/includes/import.php'; } if ( ! function_exists( 'register_importer' ) ) { return; } register_importer( 'tse_sp_event_csv', __( 'SportsPress Events CSV', 'tonys-sportspress-enhancements' ), __( 'Import SportsPress events directly from CSV with preview and duplicate detection. Provided by Tony\'s SportsPress Enhancements.', 'tonys-sportspress-enhancements' ), 'tse_sp_event_csv_importer_bootstrap' ); } add_action( 'admin_init', 'tse_sp_event_csv_register_importer' ); /** * Importer callback wrapper for WordPress importer screen. */ function tse_sp_event_csv_importer_bootstrap() { if ( ! current_user_can( 'import' ) ) { wp_die( esc_html__( 'You do not have permission to import.', 'tonys-sportspress-enhancements' ) ); } tse_sp_event_csv_importer_page(); } /** * Get transient key for current user's preview payload. * * @return string */ function tse_sp_event_csv_preview_key() { return 'tse_sp_event_csv_preview_' . get_current_user_id(); } /** * Normalize header labels (trim/BOM cleanup). * * @param string $header Header label. * @return string */ function tse_sp_event_csv_normalize_header( $header ) { $header = trim( (string) $header ); return (string) preg_replace( '/^\xEF\xBB\xBF/', '', $header ); } /** * Build CSV column index map from incoming header. * * @param array $header Normalized CSV header row. * @return array|WP_Error */ function tse_sp_event_csv_build_header_map( $header ) { $recognized = tse_sp_event_csv_recognized_headers(); $map = array(); foreach ( $header as $index => $column ) { $field = isset( $recognized[ $column ] ) ? $recognized[ $column ] : null; if ( null === $field || '' === $field ) { continue; } if ( ! isset( $map[ $field ] ) ) { $map[ $field ] = (int) $index; } } $required = array( 'date' => 'Date', 'home' => 'Home', 'away' => 'Away', 'home_score' => 'Home Score', 'away_score' => 'Away Score', ); $missing = array(); foreach ( $required as $required_field => $required_label ) { if ( ! isset( $map[ $required_field ] ) ) { $missing[] = $required_label; } } if ( ! empty( $missing ) ) { return new WP_Error( 'invalid_header', sprintf( /* translators: %s: missing required CSV columns. */ __( 'CSV header is missing required columns: %s', 'tonys-sportspress-enhancements' ), implode( ', ', $missing ) ) ); } return $map; } /** * Get a normalized CSV cell by logical field. * * @param array $values CSV row values. * @param array $header_map Field->index map. * @param string $field Logical field key. * @return string */ function tse_sp_event_csv_row_value( $values, $header_map, $field ) { if ( ! isset( $header_map[ $field ] ) ) { return ''; } $index = (int) $header_map[ $field ]; if ( ! isset( $values[ $index ] ) ) { return ''; } return trim( (string) $values[ $index ] ); } /** * Normalize team lookup tokens. * * @param string $value Raw team text. * @return string */ function tse_sp_event_csv_normalize_team_token( $value ) { $value = wp_strip_all_tags( (string) $value ); $value = trim( $value ); if ( '' === $value ) { return ''; } $value = html_entity_decode( $value, ENT_QUOTES, get_bloginfo( 'charset' ) ); $value = preg_replace( '/\s+/', ' ', $value ); $value = strtolower( $value ); return trim( (string) $value ); } /** * Build a normalized lookup map for existing SportsPress teams. * * @param bool $refresh Force cache rebuild. * @return array */ function tse_sp_event_csv_team_lookup_map( $refresh = false ) { static $map = null; if ( ! $refresh && null !== $map ) { return $map; } $map = array(); $team_ids = get_posts( array( 'post_type' => 'sp_team', 'post_status' => array( 'publish', 'draft', 'pending', 'future', 'private' ), 'posts_per_page' => -1, 'fields' => 'ids', 'no_found_rows' => true, ) ); foreach ( $team_ids as $team_id ) { $tokens = array( get_the_title( $team_id ), get_post_meta( $team_id, 'sp_short_name', true ), get_post_meta( $team_id, 'sp_abbreviation', true ), ); foreach ( $tokens as $token ) { $key = tse_sp_event_csv_normalize_team_token( $token ); if ( '' === $key ) { continue; } if ( ! isset( $map[ $key ] ) ) { $map[ $key ] = (int) $team_id; } } } return $map; } /** * Find team post ID by exact title. * * @param string $team_name Team name. * @return int */ function tse_sp_event_csv_find_team_id( $team_name ) { $key = tse_sp_event_csv_normalize_team_token( $team_name ); if ( '' === $key ) { return 0; } $map = tse_sp_event_csv_team_lookup_map(); if ( isset( $map[ $key ] ) ) { return (int) $map[ $key ]; } return 0; } /** * Find existing team or create a new one. * * @param string $team_name Team name. * @return int|WP_Error */ function tse_sp_event_csv_find_or_create_team( $team_name ) { $team_name = trim( (string) $team_name ); if ( '' === $team_name ) { return new WP_Error( 'team_name_missing', __( 'Team name is required.', 'tonys-sportspress-enhancements' ) ); } $team_id = tse_sp_event_csv_find_team_id( $team_name ); if ( $team_id > 0 ) { return $team_id; } $team_id = wp_insert_post( array( 'post_type' => 'sp_team', 'post_status' => 'publish', 'post_title' => wp_strip_all_tags( $team_name ), ), true ); if ( is_wp_error( $team_id ) ) { return $team_id; } update_post_meta( $team_id, '_sp_import', 1 ); // Refresh static lookup cache for subsequent rows in the same request. tse_sp_event_csv_team_lookup_map( true ); return (int) $team_id; } /** * Parse date/time into local site datetime string. * * @param string $date_raw Date text. * @param string $time_raw Time text. * @return string|WP_Error */ function tse_sp_event_csv_parse_datetime( $date_raw, $time_raw ) { $date_raw = trim( (string) $date_raw ); $time_raw = trim( (string) $time_raw ); if ( '' === $date_raw ) { return new WP_Error( 'missing_date', __( 'Date is required.', 'tonys-sportspress-enhancements' ) ); } $input = $date_raw . ' ' . ( '' !== $time_raw ? $time_raw : '00:00' ); $dt = date_create_immutable( $input, wp_timezone() ); if ( false === $dt ) { return new WP_Error( 'invalid_datetime', __( 'Date/Time could not be parsed.', 'tonys-sportspress-enhancements' ) ); } return $dt->format( 'Y-m-d H:i:s' ); } /** * Build a deterministic event key from post_date and two team IDs. * * @param string $post_date Event post_date. * @param int $team_a Team ID A. * @param int $team_b Team ID B. * @return string */ function tse_sp_event_csv_build_event_key( $post_date, $team_a, $team_b ) { $post_date = trim( (string) $post_date ); $teams = array_values( array_filter( array_map( 'intval', array( $team_a, $team_b ) ) ) ); if ( '' === $post_date || count( $teams ) < 2 ) { return ''; } sort( $teams ); return $post_date . '|' . $teams[0] . '|' . $teams[1]; } /** * Build a row signature for in-file duplicate checks. * * @param string $post_date Event post_date. * @param string $home Home team text. * @param string $away Away team text. * @return string */ function tse_sp_event_csv_build_row_signature( $post_date, $home, $away ) { $post_date = trim( (string) $post_date ); if ( '' === $post_date ) { return ''; } $teams = array( tse_sp_event_csv_normalize_team_token( $home ), tse_sp_event_csv_normalize_team_token( $away ), ); $teams = array_values( array_filter( $teams ) ); if ( count( $teams ) < 2 ) { return ''; } sort( $teams ); return $post_date . '|name:' . $teams[0] . '|name:' . $teams[1]; } /** * Build existing SportsPress event key map for duplicate detection. * * @return array */ function tse_sp_event_csv_existing_event_keys() { static $keys = null; if ( null !== $keys ) { return $keys; } $keys = array(); $event_ids = get_posts( array( 'post_type' => 'sp_event', 'post_status' => array( 'publish', 'future', 'draft', 'pending', 'private' ), 'posts_per_page' => -1, 'fields' => 'ids', 'no_found_rows' => true, ) ); foreach ( $event_ids as $event_id ) { $post_date = (string) get_post_field( 'post_date', $event_id ); $teams = array_values( array_filter( array_map( 'intval', (array) get_post_meta( $event_id, 'sp_team', false ) ) ) ); if ( count( $teams ) < 2 ) { continue; } $key = tse_sp_event_csv_build_event_key( $post_date, $teams[0], $teams[1] ); if ( '' !== $key ) { $keys[ $key ] = (int) $event_id; } } return $keys; } /** * Get the primary result key from SportsPress result variables. * * @return string */ function tse_sp_event_csv_primary_result_key() { if ( function_exists( 'sp_get_var_labels' ) ) { $labels = sp_get_var_labels( 'sp_result' ); if ( is_array( $labels ) && ! empty( $labels ) ) { return (string) array_key_first( $labels ); } } return 'result'; } /** * Parse uploaded CSV into normalized preview payload. * * @param string $file_path Temp uploaded file path. * @return array|WP_Error */ function tse_sp_event_csv_parse_file( $file_path ) { $handle = fopen( $file_path, 'r' ); if ( false === $handle ) { return new WP_Error( 'file_open_failed', __( 'Unable to read uploaded CSV file.', 'tonys-sportspress-enhancements' ) ); } $header = fgetcsv( $handle, 0, ',', '"', '\\' ); if ( false === $header ) { fclose( $handle ); return new WP_Error( 'missing_header', __( 'CSV appears empty.', 'tonys-sportspress-enhancements' ) ); } $header = array_map( 'tse_sp_event_csv_normalize_header', $header ); $header_map = tse_sp_event_csv_build_header_map( $header ); if ( is_wp_error( $header_map ) ) { fclose( $handle ); return $header_map; } $rows = array(); $total_rows = 0; $rows_with_errors = 0; $rows_with_new_teams = 0; $rows_with_duplicates = 0; $new_teams = array(); $line_number = 1; $seen_row_signatures = array(); $existing_event_keys = tse_sp_event_csv_existing_event_keys(); while ( ( $values = fgetcsv( $handle, 0, ',', '"', '\\' ) ) !== false ) { ++$line_number; if ( ! is_array( $values ) ) { continue; } if ( 1 === count( $values ) && '' === trim( (string) $values[0] ) ) { continue; } $normalized = array( 'line' => $line_number, 'date' => tse_sp_event_csv_row_value( $values, $header_map, 'date' ), 'time' => tse_sp_event_csv_row_value( $values, $header_map, 'time' ), 'venue' => tse_sp_event_csv_row_value( $values, $header_map, 'venue' ), 'home' => tse_sp_event_csv_row_value( $values, $header_map, 'home' ), 'away' => tse_sp_event_csv_row_value( $values, $header_map, 'away' ), 'week_round' => tse_sp_event_csv_row_value( $values, $header_map, 'week_round' ), 'league' => tse_sp_event_csv_row_value( $values, $header_map, 'league' ), 'season' => tse_sp_event_csv_row_value( $values, $header_map, 'season' ), 'home_score' => tse_sp_event_csv_row_value( $values, $header_map, 'home_score' ), 'away_score' => tse_sp_event_csv_row_value( $values, $header_map, 'away_score' ), 'notes' => tse_sp_event_csv_row_value( $values, $header_map, 'notes' ), 'errors' => array(), 'duplicate_existing' => false, 'duplicate_file' => false, 'home_team_id'=> 0, 'away_team_id'=> 0, ); if ( '' === $normalized['home'] ) { $normalized['errors'][] = __( 'Home team is required.', 'tonys-sportspress-enhancements' ); } if ( '' === $normalized['away'] ) { $normalized['errors'][] = __( 'Away team is required.', 'tonys-sportspress-enhancements' ); } $parsed_datetime = tse_sp_event_csv_parse_datetime( $normalized['date'], $normalized['time'] ); if ( is_wp_error( $parsed_datetime ) ) { $normalized['errors'][] = $parsed_datetime->get_error_message(); } else { $normalized['post_date'] = $parsed_datetime; } if ( '' !== $normalized['home'] ) { $normalized['home_team_id'] = tse_sp_event_csv_find_team_id( $normalized['home'] ); } if ( '' !== $normalized['away'] ) { $normalized['away_team_id'] = tse_sp_event_csv_find_team_id( $normalized['away'] ); } $row_signature = tse_sp_event_csv_build_row_signature( isset( $normalized['post_date'] ) ? $normalized['post_date'] : '', $normalized['home'], $normalized['away'] ); if ( '' !== $row_signature ) { if ( isset( $seen_row_signatures[ $row_signature ] ) ) { $normalized['duplicate_file'] = true; } else { $seen_row_signatures[ $row_signature ] = $line_number; } } $event_key = tse_sp_event_csv_build_event_key( isset( $normalized['post_date'] ) ? $normalized['post_date'] : '', $normalized['home_team_id'], $normalized['away_team_id'] ); if ( '' !== $event_key && isset( $existing_event_keys[ $event_key ] ) ) { $normalized['duplicate_existing'] = true; } if ( $normalized['home_team_id'] <= 0 || $normalized['away_team_id'] <= 0 ) { ++$rows_with_new_teams; } if ( $normalized['home_team_id'] <= 0 && '' !== $normalized['home'] ) { $new_teams[ tse_sp_event_csv_normalize_team_token( $normalized['home'] ) ] = $normalized['home']; } if ( $normalized['away_team_id'] <= 0 && '' !== $normalized['away'] ) { $new_teams[ tse_sp_event_csv_normalize_team_token( $normalized['away'] ) ] = $normalized['away']; } if ( ! empty( $normalized['errors'] ) ) { ++$rows_with_errors; } if ( $normalized['duplicate_existing'] || $normalized['duplicate_file'] ) { ++$rows_with_duplicates; } $rows[] = $normalized; ++$total_rows; } fclose( $handle ); return array( 'created_at' => time(), 'rows' => $rows, 'total_rows' => $total_rows, 'rows_with_errors' => $rows_with_errors, 'rows_with_new_teams' => $rows_with_new_teams, 'rows_with_duplicates' => $rows_with_duplicates, 'unique_new_teams' => array_values( array_filter( $new_teams ) ), 'result_key' => tse_sp_event_csv_primary_result_key(), ); } /** * Import parsed preview payload into SportsPress events. * * @param array $preview Preview payload. * @param array $options Import options. * @return array */ function tse_sp_event_csv_run_import( $preview, $options = array() ) { $results = array( 'imported' => 0, 'updated' => 0, 'skipped' => 0, 'excluded' => 0, 'errors' => array(), ); $result_key = isset( $preview['result_key'] ) ? (string) $preview['result_key'] : tse_sp_event_csv_primary_result_key(); $delimiter = get_option( 'sportspress_event_teams_delimiter', 'vs' ); $rows = ( isset( $preview['rows'] ) && is_array( $preview['rows'] ) ) ? $preview['rows'] : array(); $selection_mode = ! empty( $options['selection_mode'] ); $include_lookup = ( isset( $options['include_lookup'] ) && is_array( $options['include_lookup'] ) ) ? $options['include_lookup'] : array(); $duplicate_actions = ( isset( $options['duplicate_actions'] ) && is_array( $options['duplicate_actions'] ) ) ? $options['duplicate_actions'] : array(); $home_outcome_inputs = ( isset( $options['home_outcomes'] ) && is_array( $options['home_outcomes'] ) ) ? $options['home_outcomes'] : array(); $away_outcome_inputs = ( isset( $options['away_outcomes'] ) && is_array( $options['away_outcomes'] ) ) ? $options['away_outcomes'] : array(); $event_format = isset( $options['event_format'] ) ? tse_sp_event_csv_validate_event_format( $options['event_format'] ) : 'league'; $existing_event_keys = tse_sp_event_csv_existing_event_keys(); foreach ( $rows as $row ) { $line = isset( $row['line'] ) ? (int) $row['line'] : 0; if ( $selection_mode && ! isset( $include_lookup[ $line ] ) ) { ++$results['excluded']; continue; } if ( ! empty( $row['errors'] ) ) { ++$results['skipped']; $results['errors'][] = sprintf( /* translators: %d: line number. */ __( 'Line %d skipped (invalid preview row).', 'tonys-sportspress-enhancements' ), $line ); continue; } $post_date = isset( $row['post_date'] ) ? $row['post_date'] : ''; $home_id = tse_sp_event_csv_find_or_create_team( isset( $row['home'] ) ? $row['home'] : '' ); $away_id = tse_sp_event_csv_find_or_create_team( isset( $row['away'] ) ? $row['away'] : '' ); if ( is_wp_error( $home_id ) || is_wp_error( $away_id ) ) { ++$results['skipped']; $results['errors'][] = sprintf( /* translators: 1: line number, 2: error details. */ __( 'Line %1$d skipped: %2$s', 'tonys-sportspress-enhancements' ), $line, is_wp_error( $home_id ) ? $home_id->get_error_message() : $away_id->get_error_message() ); continue; } if ( '' === $post_date ) { ++$results['skipped']; $results['errors'][] = sprintf( /* translators: %d: line number. */ __( 'Line %d skipped: missing parsed date.', 'tonys-sportspress-enhancements' ), $line ); continue; } $event_key = tse_sp_event_csv_build_event_key( $post_date, (int) $home_id, (int) $away_id ); $duplicate_action = isset( $duplicate_actions[ $line ] ) ? $duplicate_actions[ $line ] : 'ignore'; if ( 'update' !== $duplicate_action ) { $duplicate_action = 'ignore'; } $is_update = false; if ( '' !== $event_key && isset( $existing_event_keys[ $event_key ] ) ) { if ( 'update' !== $duplicate_action ) { ++$results['skipped']; $results['errors'][] = sprintf( /* translators: %d: line number. */ __( 'Line %d skipped: duplicate event already exists for same date/time and teams.', 'tonys-sportspress-enhancements' ), $line ); continue; } $event_id = wp_update_post( array( 'ID' => (int) $existing_event_keys[ $event_key ], 'post_date' => $post_date, 'post_title' => trim( $row['home'] . ' ' . $delimiter . ' ' . $row['away'] ), 'post_content' => isset( $row['notes'] ) ? wp_kses_post( $row['notes'] ) : '', ), true ); $is_update = true; } else { $event_id = wp_insert_post( array( 'post_type' => 'sp_event', 'post_status' => 'publish', 'post_date' => $post_date, 'post_title' => trim( $row['home'] . ' ' . $delimiter . ' ' . $row['away'] ), 'post_content' => isset( $row['notes'] ) ? wp_kses_post( $row['notes'] ) : '', ), true ); } if ( is_wp_error( $event_id ) || ! $event_id ) { ++$results['skipped']; $results['errors'][] = sprintf( /* translators: 1: line number, 2: error details. */ __( 'Line %1$d failed: %2$s', 'tonys-sportspress-enhancements' ), $line, is_wp_error( $event_id ) ? $event_id->get_error_message() : __( 'Unknown save error', 'tonys-sportspress-enhancements' ) ); continue; } update_post_meta( $event_id, '_sp_import', 1 ); update_post_meta( $event_id, 'sp_format', $event_format ); delete_post_meta( $event_id, 'sp_team' ); add_post_meta( $event_id, 'sp_team', (int) $home_id ); add_post_meta( $event_id, 'sp_team', (int) $away_id ); if ( ! $is_update ) { add_post_meta( $event_id, 'sp_player', 0 ); add_post_meta( $event_id, 'sp_player', 0 ); } if ( ! empty( $row['venue'] ) ) { wp_set_object_terms( $event_id, sanitize_text_field( $row['venue'] ), 'sp_venue', false ); } if ( ! empty( $row['league'] ) ) { $league_term = sanitize_text_field( $row['league'] ); wp_set_object_terms( $event_id, $league_term, 'sp_league', false ); // Ensure teams are linked to every league they appear in. wp_set_object_terms( (int) $home_id, $league_term, 'sp_league', true ); wp_set_object_terms( (int) $away_id, $league_term, 'sp_league', true ); } if ( ! empty( $row['season'] ) ) { $season_term = sanitize_text_field( $row['season'] ); wp_set_object_terms( $event_id, $season_term, 'sp_season', false ); // Ensure teams are linked to every season they appear in. wp_set_object_terms( (int) $home_id, $season_term, 'sp_season', true ); wp_set_object_terms( (int) $away_id, $season_term, 'sp_season', true ); } $home_score = isset( $row['home_score'] ) ? trim( (string) $row['home_score'] ) : ''; $away_score = isset( $row['away_score'] ) ? trim( (string) $row['away_score'] ) : ''; $default_outcomes = tse_sp_event_csv_default_outcomes( $home_score, $away_score ); $home_outcome_input = isset( $home_outcome_inputs[ $line ] ) ? (string) $home_outcome_inputs[ $line ] : ''; $away_outcome_input = isset( $away_outcome_inputs[ $line ] ) ? (string) $away_outcome_inputs[ $line ] : ''; if ( '' === trim( $home_outcome_input ) ) { $home_outcome_input = $default_outcomes['home']; } if ( '' === trim( $away_outcome_input ) ) { $away_outcome_input = $default_outcomes['away']; } $home_outcomes = tse_sp_event_csv_parse_outcome_value( $home_outcome_input ); $away_outcomes = tse_sp_event_csv_parse_outcome_value( $away_outcome_input ); if ( '' !== $home_score || '' !== $away_score || ! empty( $home_outcomes ) || ! empty( $away_outcomes ) ) { update_post_meta( $event_id, 'sp_results', array( (int) $home_id => array( $result_key => $home_score, 'outcome' => $home_outcomes, ), (int) $away_id => array( $result_key => $away_score, 'outcome' => $away_outcomes, ), ) ); } if ( $is_update ) { ++$results['updated']; } else { ++$results['imported']; } if ( '' !== $event_key ) { $existing_event_keys[ $event_key ] = (int) $event_id; } } return $results; } /** * Render importer admin page and process actions. */ function tse_sp_event_csv_importer_page() { if ( ! current_user_can( tse_sp_event_csv_importer_capability() ) ) { wp_die( esc_html__( 'You do not have permission to access this importer.', 'tonys-sportspress-enhancements' ) ); } $messages = array(); $error_lines = array(); $key = tse_sp_event_csv_preview_key(); $request_method = isset( $_SERVER['REQUEST_METHOD'] ) ? strtoupper( sanitize_text_field( wp_unslash( $_SERVER['REQUEST_METHOD'] ) ) ) : ''; if ( 'POST' === $request_method ) { $action = isset( $_POST['tse_action'] ) ? sanitize_key( wp_unslash( $_POST['tse_action'] ) ) : ''; if ( 'preview' === $action ) { check_admin_referer( 'tse_sp_event_csv_preview' ); if ( empty( $_FILES['tse_csv_file']['tmp_name'] ) || ! is_uploaded_file( $_FILES['tse_csv_file']['tmp_name'] ) ) { $messages[] = array( 'type' => 'error', 'text' => __( 'Please choose a CSV file to preview.', 'tonys-sportspress-enhancements' ), ); } else { $preview = tse_sp_event_csv_parse_file( $_FILES['tse_csv_file']['tmp_name'] ); if ( is_wp_error( $preview ) ) { $messages[] = array( 'type' => 'error', 'text' => $preview->get_error_message(), ); } else { set_transient( $key, $preview, 6 * HOUR_IN_SECONDS ); $messages[] = array( 'type' => 'success', 'text' => __( 'Preview ready. Review rows below, then import or abort.', 'tonys-sportspress-enhancements' ), ); } } } elseif ( 'abort' === $action ) { check_admin_referer( 'tse_sp_event_csv_abort' ); delete_transient( $key ); $messages[] = array( 'type' => 'success', 'text' => __( 'Preview aborted. Nothing was imported.', 'tonys-sportspress-enhancements' ), ); } elseif ( 'import' === $action ) { check_admin_referer( 'tse_sp_event_csv_import' ); $preview = get_transient( $key ); if ( ! is_array( $preview ) || empty( $preview['rows'] ) ) { $messages[] = array( 'type' => 'error', 'text' => __( 'No preview data found. Upload the CSV again.', 'tonys-sportspress-enhancements' ), ); } else { $selection_mode = isset( $_POST['tse_has_row_selection'] ); $include_lookup = array(); if ( $selection_mode && isset( $_POST['include_rows'] ) && is_array( $_POST['include_rows'] ) ) { foreach ( $_POST['include_rows'] as $line => $include_flag ) { $line = absint( $line ); if ( $line > 0 && '1' === (string) $include_flag ) { $include_lookup[ $line ] = true; } } } $duplicate_actions = array(); if ( isset( $_POST['duplicate_actions'] ) && is_array( $_POST['duplicate_actions'] ) ) { foreach ( $_POST['duplicate_actions'] as $line => $action_choice ) { $line = absint( $line ); if ( $line < 1 ) { continue; } $action_choice = sanitize_key( wp_unslash( $action_choice ) ); $duplicate_actions[ $line ] = in_array( $action_choice, array( 'ignore', 'update' ), true ) ? $action_choice : 'ignore'; } } $event_format = isset( $_POST['event_format'] ) ? tse_sp_event_csv_validate_event_format( wp_unslash( $_POST['event_format'] ) ) : 'league'; $results = tse_sp_event_csv_run_import( $preview, array( 'selection_mode' => $selection_mode, 'include_lookup' => $include_lookup, 'duplicate_actions' => $duplicate_actions, 'event_format' => $event_format, ) ); delete_transient( $key ); $messages[] = array( 'type' => 'success', 'text' => sprintf( /* translators: 1: imported count, 2: updated count, 3: skipped count, 4: excluded count. */ __( 'Import complete. Imported: %1$d. Updated: %2$d. Skipped: %3$d. Excluded: %4$d.', 'tonys-sportspress-enhancements' ), (int) $results['imported'], (int) $results['updated'], (int) $results['skipped'], (int) $results['excluded'] ), ); $error_lines = isset( $results['errors'] ) && is_array( $results['errors'] ) ? $results['errors'] : array(); } } } $preview_data = get_transient( $key ); ?>




/
/> () ()