// =========================================================================
// 26 SHORTCODE: Team Penalty Shots /penalty-shots/
// =========================================================================
add_shortcode('otg_penalty_shot_games', 'otg_penalty_shot_games_shortcode');
function otg_penalty_shot_games_shortcode() {
global $wpdb;
// Determine current page from URL parameter, default to 1
$paged = isset($_GET['ps_page']) ? max(1, intval($_GET['ps_page'])) : 1;
$per_page = 25;
$offset = ($paged - 1) * $per_page;
// Get filter inputs from URL
$selected_season = isset($_GET['ps_season']) ? sanitize_text_field($_GET['ps_season']) : '';
$selected_opp = isset($_GET['ps_opp']) ? sanitize_text_field($_GET['ps_opp']) : '';
$selected_outcome = isset($_GET['ps_outcome']) ? sanitize_text_field($_GET['ps_outcome']) : '';
$selected_shooter = isset($_GET['ps_shooter']) ? sanitize_text_field($_GET['ps_shooter']) : '';
$selected_type = isset($_GET['ps_type']) ? sanitize_text_field($_GET['ps_type']) : '';
// Base subquery defining the complete dataset with calculated fields and game type logic
$subquery = "
SELECT
combined.*,
CASE
WHEN SUBSTRING(CAST(combined.game_id AS CHAR), 6, 1) = '2' THEN 'Regular Season'
WHEN SUBSTRING(CAST(combined.game_id AS CHAR), 6, 1) = '3' THEN 'Playoffs'
ELSE 'Unknown'
END AS game_type_str,
CONCAT(
LEFT(combined.game_id, 4),
'-',
RIGHT(CAST(CAST(LEFT(combined.game_id, 4) AS UNSIGNED) + 1 AS CHAR), 2)
) AS season_str
FROM (
SELECT
'Goal' AS ps_outcome,
s.game_id,
s.period,
s.time_elapsed,
s.scorer_name AS shooter_name,
p.ID AS player_id,
g.game_date,
g.opponent_abbr,
g.rangers_score,
g.opponent_score,
g.game_outcome,
g.overtime_status,
'' AS penalty_type
FROM otg_rangers_scoring s
LEFT JOIN otg_rangers_player_boxscores b ON s.game_id = b.game_id AND s.scorer_name = b.player_name
LEFT JOIN otg_players p ON b.player_id = p.nhl_id
LEFT JOIN otg_rangers_games g ON s.game_id = g.game_id
WHERE LOWER(s.strength) IN ('ps', 'p2', 'sp')
AND s.team_abbr = 'NYR'
UNION ALL
SELECT
'Miss' AS ps_outcome,
pen.game_id,
pen.period,
pen.time_elapsed,
pen.ps_player_name AS shooter_name,
p.ID AS player_id,
g.game_date,
g.opponent_abbr,
g.rangers_score,
g.opponent_score,
g.game_outcome,
g.overtime_status,
pen.penalty_type
FROM otg_rangers_penalties pen
LEFT JOIN otg_players p ON pen.ps_player_id = p.nhl_id
LEFT JOIN otg_rangers_games g ON pen.game_id = g.game_id
WHERE pen.is_penalty_shot = 1
AND pen.team_abbr != 'NYR'
AND NOT EXISTS (
SELECT 1 FROM otg_rangers_scoring s2
WHERE s2.game_id = pen.game_id
AND s2.period = pen.period
AND s2.time_elapsed = pen.time_elapsed
AND LOWER(s2.strength) IN ('ps', 'p2', 'sp')
AND s2.team_abbr = 'NYR'
)
) combined
";
// Fetch master dataset to dynamically populate filter dropdown options and reliably parse shooter names
$master_rows = $wpdb->get_results("SELECT * FROM ({$subquery}) master_data ORDER BY game_date DESC, game_id DESC");
$available_seasons = [];
$available_opponents = []; // Will store abbreviation => full team name map
$available_shooters = [];
$processed_master = [];
foreach ($master_rows as $row) {
$current_shooter = $row->shooter_name;
$row->resolved_shooter = $current_shooter;
$processed_master[] = $row;
if (!empty($row->season_str)) {
$available_seasons[$row->season_str] = true;
}
if (!empty($row->opponent_abbr)) {
$abbr = $row->opponent_abbr;
if (!isset($available_opponents[$abbr])) {
$team_name_row = $wpdb->get_row($wpdb->prepare(
"SELECT team FROM otg_standings_nhl WHERE abbreviation = %s AND team != '' AND team IS NOT NULL LIMIT 1",
$abbr
));
$available_opponents[$abbr] = ($team_name_row && !empty($team_name_row->team)) ? $team_name_row->team : $abbr;
}
}
if (!empty($current_shooter)) {
$available_shooters[$current_shooter] = true;
}
}
krsort($available_seasons); // Sort seasons descending (newest first)
asort($available_opponents); // Sort opponents alphabetically by team name
ksort($available_shooters);
// Build dynamic SQL WHERE clause based on active filters
$filter_clauses = [];
$filter_params = [];
if (!empty($selected_season)) {
$filter_clauses[] = "season_str = %s";
$filter_params[] = $selected_season;
}
if (!empty($selected_opp)) {
$filter_clauses[] = "opponent_abbr = %s";
$filter_params[] = $selected_opp;
}
if (!empty($selected_outcome)) {
$filter_clauses[] = "ps_outcome = %s";
$filter_params[] = $selected_outcome;
}
if (!empty($selected_shooter)) {
$filter_clauses[] = "shooter_name = %s";
$filter_params[] = $selected_shooter;
}
if (!empty($selected_type)) {
$filter_clauses[] = "game_type_str = %s";
$filter_params[] = $selected_type;
}
$where_sql = "";
if (!empty($filter_clauses)) {
$where_sql = "WHERE " . implode(" AND ", $filter_clauses);
}
// Fully wrapped subquery for count and pagination
$filtered_from_where = "FROM ({$subquery}) filtered_sub {$where_sql}";
$total_rows = intval($wpdb->get_var($wpdb->prepare("SELECT COUNT(*) " . $filtered_from_where, $filter_params)));
// Calculate total successful (Goals) based on the exact same active filter criteria
$success_query = "SELECT COUNT(*) FROM ({$subquery}) filtered_sub {$where_sql}" . (empty($where_sql) ? " WHERE" : " AND") . " ps_outcome = 'Goal'";
$total_success = intval($wpdb->get_var($wpdb->prepare($success_query, $filter_params)));
$total_pages = max(1, ceil($total_rows / $per_page));
// Ensure current page does not exceed total pages if filters narrow results
if ($paged > $total_pages) {
$paged = $total_pages;
$offset = ($paged - 1) * $per_page;
}
// Fetch final paginated results
$final_query = "
SELECT *
" . $filtered_from_where . "
ORDER BY game_date DESC, game_id DESC, period ASC, time_elapsed ASC
LIMIT %d OFFSET %d
";
$query_params = array_merge($filter_params, [$per_page, $offset]);
$penalty_shots = $wpdb->get_results($wpdb->prepare($final_query, $query_params));
// Start output wrapper
$output = '
';
// Header Section
$output .= '
';
$output .= '
New York Rangers Penalty Shots
';
// Summary Count Pill Display
$success_rate = ($total_rows > 0) ? round(($total_success / $total_rows) * 100, 1) : 0;
$output .= '
';
$output .= 'Total Attempts: ' . $total_rows . ' | Successful: ' . $total_success . ' (' . $success_rate . '%)';
$output .= '
';
$output .= '
';
// Filters Section UI
$current_page_url = strtok($_SERVER["URI"] ?? $_SERVER["REQUEST_URI"], '?');
$output .= '
';
// Styles
$output .= '';
$output .= '
| Date |
Type |
Opposition |
Result |
Period |
Time |
Shooter |
Shot Result |
Box Score |
';
if (!$penalty_shots) {
$output .= '| No New York Rangers penalty shot attempts found matching the selected filters. |
';
} else {
foreach ($penalty_shots as $ps) {
$formatted_date = !empty($ps->game_date) ? date('F j, Y', strtotime($ps->game_date)) : '';
if (intval($ps->period) === 0) {
$period_name = '';
} else {
$period_name = ($ps->period == 4) ? 'Overtime' : get_ordinal($ps->period) . ' Period';
}
$outcome_label = '';
if (!empty($ps->game_outcome)) {
$raw_outcome = strtoupper($ps->game_outcome);
if ($raw_outcome === 'OTL') {
$outcome_label = 'L';
} else {
$outcome_label = $raw_outcome;
}
}
$score_part = intval($ps->rangers_score) . '-' . intval($ps->opponent_score);
$suffix_part = '';
if (!empty($ps->overtime_status)) {
$ot_status_upper = strtoupper($ps->overtime_status);
if ($ot_status_upper === 'OT' || $ot_status_upper === 'SO') {
$suffix_part = ' (' . $ot_status_upper . ')';
}
}
$result_display = trim($outcome_label . ' ' . $score_part . $suffix_part);
$shooter_name = $ps->shooter_name;
$player_id = $ps->player_id;
if ($ps->ps_outcome === 'Goal') {
$shot_result_display = 'Goal';
} else {
$shot_result_display = 'Miss';
}
// Fallback lookup if player_id wasn't populated via join
if (empty($player_id) && !empty($shooter_name)) {
$matched_player = $wpdb->get_row($wpdb->prepare(
"SELECT ID FROM otg_players WHERE Name = %s LIMIT 1",
$shooter_name
));
if ($matched_player) {
$player_id = $matched_player->ID;
}
}
if (!empty($player_id)) {
$shooter_display = '' . esc_html($shooter_name) . '';
} else {
$shooter_display = !empty($shooter_name) ? esc_html($shooter_name) : 'Unknown';
}
$time_display = (intval($ps->period) === 0) ? '' : esc_html($ps->time_elapsed);
$opponent_logo = '';
if (!empty($ps->opponent_abbr) && !empty($ps->game_id)) {
$logo_row = $wpdb->get_row($wpdb->prepare(
"SELECT logo FROM otg_standings_nhl WHERE abbreviation = %s AND season = %s LIMIT 1",
$ps->opponent_abbr,
$ps->season_str
));
if ($logo_row && !empty($logo_row->logo)) {
$opponent_logo = $logo_row->logo;
}
}
if (!empty($opponent_logo)) {
$opponent_display = '
';
} else {
$opponent_display = esc_html($ps->opponent_abbr);
}
$output .= '';
$output .= '| ' . esc_html($formatted_date) . ' | ';
$output .= '' . esc_html($ps->game_type_str) . ' | ';
$output .= '' . $opponent_display . ' | ';
$output .= '' . esc_html($result_display) . ' | ';
$output .= '' . esc_html($period_name) . ' | ';
$output .= '' . $time_display . ' | ';
$output .= '' . $shooter_display . ' | ';
$output .= '' . $shot_result_display . ' | ';
$output .= 'View Box Score | ';
$output .= '
';
}
}
$output .= '
';
// Pagination Links Output
if ($total_pages > 1) {
$output .= '';
}
$output .= '
';
return $output;
}
Doug Glatt – Activity – OutsideTheGarden Boards – Page 57
Skip to content