// =========================================================================
// 38. SHORTCODE: Player Contracts /contracts/
// =========================================================================
add_shortcode('otg_rangers_contracts', 'otg_render_rangers_contracts_shortcode');
function otg_get_waiver_status( $player_id, $season, $wpdb ) {
// 1. Fetch player details
$player = $wpdb->get_row( $wpdb->prepare(
"SELECT ID, nhl_id, Birthday, Position FROM otg_players WHERE ID = %s OR ID = (SELECT player_id FROM otg_rangers_contracts WHERE contract_id = %s LIMIT 1)",
$player_id,
$player_id
) );
if ( ! $player || empty( $player->Birthday ) ) {
return [ 'exempt' => true, 'label' => 'Exempt (Data Pending)' ];
}
// 2. Fetch first contract date and check for slide reduction flag
$contract = $wpdb->get_row( $wpdb->prepare(
"SELECT first_contract_date, slide_contract FROM otg_rangers_contracts WHERE player_id = %s AND first_contract_date IS NOT NULL AND CAST(first_contract_date AS CHAR) != '' AND first_contract_date > '1000-01-01' ORDER BY first_contract_date ASC LIMIT 1",
$player->ID
) );
if ( ! $contract || empty( $contract->first_contract_date ) ) {
$fallback_year = $wpdb->get_var( $wpdb->prepare(
"SELECT season FROM otg_rangers_contract_years WHERE player_id = %s ORDER BY season ASC LIMIT 1",
$player->ID
));
if ( !empty( $fallback_year ) ) {
$base_contract_year = intval( explode( '-', $fallback_year )[0] );
$first_contract_date_approx = $base_contract_year . '-09-15';
$slide_contract_val = 0;
} else {
return [ 'exempt' => true, 'label' => 'Exempt (Data Pending)' ];
}
} else {
$first_contract_date_approx = $contract->first_contract_date;
$slide_contract_val = isset( $contract->slide_contract ) ? intval( $contract->slide_contract ) : 0;
}
$signing_year = intval( date( 'Y', strtotime( $first_contract_date_approx ) ) );
// 3. Determine Waiver Age (Dec 31 of contract year + Sept 15 rule)
$birth_date_obj = new DateTime( $player->Birthday );
$dec31_obj = new DateTime( $signing_year . '-12-31' );
$calendar_waiver_age = $birth_date_obj->diff( $dec31_obj )->y;
$birth_month_day = $birth_date_obj->format( 'm-d' );
if ( $calendar_waiver_age == 18 ) {
$waiver_age = ( $birth_month_day >= '09-16' && $birth_month_day <= '12-31' ) ? 19 : 18;
} else {
$waiver_age = $calendar_waiver_age;
}
if ( $waiver_age >= 25 ) {
$waiver_age = 25;
}
// 4. Gather NHL Game Stats & First-Season GP
$is_goalie = ( stripos( $player->Position, 'Goaltender' ) !== false );
$nhl_id = $player->nhl_id;
$total_nhl_gp = 0;
$first_season_gp = 0;
if ( !empty( $nhl_id ) ) {
$stats_table = $is_goalie ? 'otg_goalie_seasonal_stats' : 'otg_player_seasonal_stats';
$nhl_seasons_games = $wpdb->get_results( $wpdb->prepare(
"SELECT season, SUM(games_played) as total_gp FROM {$stats_table} WHERE nhl_id = %s AND league_name = 'NHL' GROUP BY season ORDER BY season ASC",
$nhl_id
) );
foreach ( $nhl_seasons_games as $stat_row ) {
$season_start_year = intval( explode( '-', $stat_row->season )[0] );
$gp = intval( $stat_row->total_gp );
if ( $season_start_year == $signing_year ) {
$first_season_gp = $gp;
}
$total_nhl_gp += $gp;
}
}
// 5. Look up Base Limits based on Position and Waiver Age
$max_seasons = 0;
$max_gp = 0;
if ( ! $is_goalie ) {
switch ( $waiver_age ) {
case 18:
$max_seasons = ( $first_season_gp >= 11 ) ? 3 : 5;
$max_gp = 160;
break;
case 19:
$max_seasons = ( $first_season_gp >= 11 ) ? 3 : 4;
$max_gp = 160;
break;
case 20:
$max_seasons = 3;
$max_gp = 160;
break;
case 21:
$max_seasons = 3;
$max_gp = 80;
break;
case 22:
$max_seasons = 3;
$max_gp = 70;
break;
case 23:
$max_seasons = 3;
$max_gp = 60;
break;
case 24:
$max_seasons = 2;
$max_gp = 60;
break;
default:
$max_seasons = 1;
$max_gp = 0;
break;
}
} else {
switch ( $waiver_age ) {
case 18:
$max_seasons = ( $first_season_gp >= 11 ) ? 4 : 6;
$max_gp = 80;
break;
case 19:
$max_seasons = ( $first_season_gp >= 11 ) ? 4 : 5;
$max_gp = 80;
break;
case 20:
$max_seasons = 4;
$max_gp = 80;
break;
case 21:
$max_seasons = 4;
$max_gp = 60;
break;
case 22:
$max_seasons = 4;
$max_gp = 60;
break;
case 23:
$max_seasons = 3;
$max_gp = 60;
break;
case 24:
$max_seasons = 2;
$max_gp = 60;
break;
default:
$max_seasons = 1;
$max_gp = 0;
break;
}
}
// Apply slide_contract penalty if it equals -1
if ( $slide_contract_val === -1 ) {
$max_seasons = max( 1, $max_seasons - 1 );
}
// 6. Calculate Seasons Elapsed (Ordinal distance from signing year)
$current_season_year = intval( explode( '-', $season )[0] );
$seasons_elapsed = max( 0, $current_season_year - $signing_year );
// 7. Final Threshold & Remaining Calculation
if ( $max_gp > 0 && $total_nhl_gp >= $max_gp ) {
return [ 'exempt' => false, 'label' => 'Requires Waivers' ];
}
if ( $seasons_elapsed >= $max_seasons ) {
return [ 'exempt' => false, 'label' => 'Requires Waivers' ];
}
$seasons_left = $max_seasons - $seasons_elapsed;
if ( $seasons_left <= 0 ) {
return [ 'exempt' => false, 'label' => 'Requires Waivers' ];
}
return [
'exempt' => true,
'label' => sprintf( 'Exempt (%d %s Left)', $seasons_left, ( $seasons_left == 1 ? 'Season' : 'Seasons' ) )
];
}
function otg_render_rangers_contracts_shortcode($atts) {
global $wpdb;
// 1. Exact raw table names
$years_table = 'otg_rangers_contract_years';
$contracts_table = 'otg_rangers_contracts';
$players_table = 'otg_players';
$games_table = 'otg_rangers_games';
$settings_table = 'otg_rangers_season_settings';
// Helper function to generate status icon HTML based on roster status
$get_status_icon_html = function($roster_status) {
$status_upper = strtoupper(trim($roster_status));
$icon_url = '';
$alt_text = '';
if ($status_upper === 'IR') {
$icon_url = 'https://outsidethegarden.com/wp-content/uploads/2026/07/IR.png';
$alt_text = 'Injured Reserve';
} elseif ($status_upper === 'LTIR') {
$icon_url = 'https://outsidethegarden.com/wp-content/uploads/2026/07/LTIR.png';
$alt_text = 'Long-Term Injured Reserve';
} elseif ($status_upper === 'SUSPENDED') {
$icon_url = 'https://outsidethegarden.com/wp-content/uploads/2026/07/suspended.png';
$alt_text = 'Suspended';
} elseif ($status_upper === 'NON-ROSTER' || $status_upper === 'NON ROSTER') {
$icon_url = 'https://outsidethegarden.com/wp-content/uploads/2026/07/non-roster.png';
$alt_text = 'Non-Roster';
} elseif ($status_upper === 'RETIRED') {
// No image icon output for retired status as requested
$icon_url = '';
$alt_text = '';
}
if (!empty($icon_url)) {
return ' ';
}
return '';
};
// 2. Fetch distinct seasons for the filter dropdown
$seasons_query = "SELECT DISTINCT season FROM {$years_table} WHERE season IS NOT NULL AND season != '' ORDER BY season DESC";
$raw_seasons = $wpdb->get_col($seasons_query);
// 3. Default to the season where active_season = 'y' from otg_rangers_season_settings, falling back to most recent if not found
$table_active_season = $wpdb->get_var($wpdb->prepare("SELECT season FROM {$settings_table} WHERE active_season = %s LIMIT 1", 'y'));
$default_season = !empty($table_active_season) ? $table_active_season : (!empty($raw_seasons) ? $raw_seasons[0] : '2026-27');
// 4. Sanitize filter & view inputs
$selected_season = isset($_GET['con_season']) ? sanitize_text_field($_GET['con_season']) : $default_season;
$selected_status = isset($_GET['con_status']) ? sanitize_text_field($_GET['con_status']) : '';
$selected_fa_type = isset($_GET['con_fa_type']) ? sanitize_text_field($_GET['con_fa_type']) : '';
$selected_player = isset($_GET['con_player']) ? sanitize_text_field($_GET['con_player']) : '';
$current_view = isset($_GET['view']) ? sanitize_text_field($_GET['view']) : 'season';
// In summary view, if a specific metric season isn't requested via query string, use the default/latest season for top metrics
$metric_season = ($current_view === 'summary')
? (isset($_GET['metric_season']) ? sanitize_text_field($_GET['metric_season']) : $default_season)
: $selected_season;
// Determine if the selected/metric season is a future season relative to the current live date
$current_live_season_start_year = intval(explode('-', $default_season)[0]);
$target_season_start_year = intval(explode('-', $metric_season)[0]);
$is_future_season = ($target_season_start_year > $current_live_season_start_year);
// 5. Build query conditions for main query (Season View) - Adjusted to pull from contracts base so unsigned FAs appear in their fa_season
$where_clauses = ["(T2.season = %s OR (T2.season IS NULL AND T1.fa_season = %s))"];
$params = [$selected_season, $selected_season];
if (!empty($selected_status)) {
$where_clauses[] = "T2.roster_status = %s";
$params[] = $selected_status;
}
if (!empty($selected_fa_type)) {
if (strtoupper($selected_fa_type) === 'RFA') {
$where_clauses[] = "(T1.free_agent_type = 'RFA' OR T1.free_agent_type LIKE 'RFA-%' OR T1.free_agent_type LIKE 'RFA%')";
} else {
$where_clauses[] = "T1.free_agent_type = %s";
$params[] = $selected_fa_type;
}
}
if (!empty($selected_player)) {
$where_clauses[] = "(T1.player_id LIKE %s OR p.Name LIKE %s)";
$params[] = '%' . $selected_player . '%';
$params[] = '%' . $selected_player . '%';
}
$where_sql = implode(" AND ", $where_clauses);
$query = $wpdb->prepare("
SELECT
COALESCE(T2.player_id, T1.player_id) AS profile_id,
COALESCE(T2.player_id, T1.player_id) AS player_id,
T1.aav,
T1.free_agent_type,
T1.fa_season,
COALESCE(T2.season, T1.fa_season) AS season,
T2.cap_hit,
T2.clause,
T2.roster_status,
p.Name AS player_name,
p.position AS player_position
FROM {$contracts_table} AS T1
LEFT JOIN {$years_table} AS T2 ON T1.contract_id = T2.contract_id AND T2.season = %s
LEFT JOIN {$players_table} AS p ON COALESCE(T2.player_id, T1.player_id) = p.ID
WHERE {$where_sql}
ORDER BY T2.cap_hit DESC
", array_merge([$selected_season], $params));
$results = $wpdb->get_results($query);
// Fetch season settings banner data using metric_season
$settings = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM {$settings_table} WHERE season = %s",
$metric_season
));
// Fallback active settings row if active_season = 'y' is needed for league minimum lookup
$active_settings = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM {$settings_table} WHERE active_season = %s LIMIT 1",
'y'
));
$league_minimum_val = ($active_settings && !empty($active_settings->league_minimum)) ? floatval($active_settings->league_minimum) : ($settings && !empty($settings->league_minimum) ? floatval($settings->league_minimum) : 775000);
// 6. Calculate Top Box Metrics & Date Calculations based on $metric_season
$salary_cap = $settings && !empty($settings->salary_cap) ? floatval($settings->salary_cap) : 88000000;
$all_season_query = $wpdb->prepare("
SELECT T2.cap_hit, T2.roster_status, T2.player_id, T1.aav, T2.clause
FROM {$years_table} AS T2
LEFT JOIN {$contracts_table} AS T1 ON T2.contract_id = T1.contract_id
WHERE T2.season = %s
", $metric_season);
$all_season_records = $wpdb->get_results($all_season_query);
$season_start = ($settings && !empty($settings->regular_season_start)) ? $settings->regular_season_start : $metric_season . '-10-01';
$season_end = ($settings && !empty($settings->regular_season_end)) ? $settings->regular_season_end : (intval(explode('-', $metric_season)[0]) + 1) . '-04-15';
$season_start_ts = strtotime($season_start);
$season_end_ts = strtotime($season_end);
$current_date_ts = current_time('timestamp');
$total_season_days = max(1, round(($season_end_ts - $season_start_ts) / 86400));
$elapsed_days = 0;
if ($current_date_ts >= $season_start_ts) {
$elapsed_days = min($total_season_days, round((min($current_date_ts, $season_end_ts) - $season_start_ts) / 86400));
}
$remaining_days = max(0, $total_season_days - $elapsed_days);
$total_allocated_cap = 0;
$total_buried_relief = 0;
foreach ($all_season_records as $rec) {
$status_lower = strtolower(trim($rec->roster_status));
$clause_upper = strtoupper(trim($rec->clause));
// Retired 35+ contracts do not count against the active cap allocation
if ($status_lower === 'retired' && ($clause_upper === '35+' || $clause_upper === '35 PLUS' || strpos($clause_upper, '35+') !== false)) {
continue;
}
// Check if player's contract is buried (status is exactly "minors" or contains "minors")
if ($status_lower === 'minors' || $status_lower === 'minors/buried' || $status_lower === 'buried' || strpos($status_lower, 'minor') !== false) {
$player_aav = !empty($rec->cap_hit) ? floatval($rec->cap_hit) : (!empty($rec->aav) ? floatval($rec->aav) : 0);
$diff = max(0, $player_aav - $league_minimum_val);
$total_buried_relief += $diff;
$total_allocated_cap += $diff;
} elseif ($status_lower !== 'minors/buried' && $status_lower !== 'minors' && $status_lower !== 'buried') {
$total_allocated_cap += floatval($rec->cap_hit);
}
}
$projected_cap_space = $salary_cap - $total_allocated_cap;
$deadline_date_str = '';
if ($settings && !empty($settings->trade_deadline)) {
$deadline_date_str = $settings->trade_deadline;
} elseif ($settings && !empty($settings->regular_season_end)) {
$deadline_date_str = date('Y-m-d', strtotime($settings->regular_season_end . ' - 40 days'));
} else {
$deadline_date_str = date('Y-m-d', strtotime('+40 days'));
}
$deadline_timestamp = strtotime($deadline_date_str);
$days_to_deadline = max(0, ($deadline_timestamp - $season_start_ts) / 86400);
$daily_accrual_space = ($projected_cap_space > 0) ? ($projected_cap_space / $total_season_days) * min($days_to_deadline, $total_season_days) : 0;
$deadline_space = $projected_cap_space + $daily_accrual_space;
$calculate_actual_days = function($row) use ($is_future_season, $elapsed_days) {
if ($is_future_season) {
return '';
}
$status = strtolower(trim($row->roster_status));
if ($status === 'retired') {
return '';
}
if (in_array($status, ['minors/buried', 'minors', 'buried']) || strpos($status, 'minor') !== false) {
return 0;
}
return intval($elapsed_days);
};
$calculate_projected_days = function($row) use ($is_future_season, $elapsed_days, $remaining_days) {
if ($is_future_season) {
return '';
}
$status = strtolower(trim($row->roster_status));
if ($status === 'retired') {
return '';
}
if (in_array($status, ['minors/buried', 'minors', 'buried']) || strpos($status, 'minor') !== false) {
return 0;
}
if (in_array($status, ['roster', 'ir', 'ltir'])) {
return intval($elapsed_days + $remaining_days);
}
return intval($elapsed_days);
};
// Helper function for mapping clause tooltip descriptions and button styles
$get_clause_details = function($raw_clause) {
$trimmed = trim($raw_clause);
$upper = strtoupper($trimmed);
$desc = $trimmed;
if ($upper === 'ELC') {
$desc = 'Entry Level Contract';
} elseif ($upper === '35+' || $upper === '35 PLUS') {
$desc = '35+ Contract';
} elseif ($upper === 'NM') {
$desc = 'No Movement Clause';
} elseif ($upper === 'NM NT' || $upper === 'NMN/T' || $upper === 'NMN-T') {
$desc = 'No Movement Clause and No Trade Clause';
} elseif (preg_match('/^NM\s+NT(\d+)$/i', $trimmed, $matches)) {
$x = $matches[1];
$desc = 'No Movement Clause and ' . $x . ' Team No Trade Clause';
} elseif (preg_match('/^NT(\d+)$/i', $trimmed, $matches)) {
$x = $matches[1];
$desc = $x . ' Team No Trade Clause';
}
// Color styling rules: 'ELC' -> green, '35+' -> silver/gray (#c0c0c0), anything with 'NM' -> darker orange
$bg_color = 'rgba(241, 196, 15, 0.1)';
$border_color = 'rgba(241, 196, 15, 0.3)';
$text_color = '#f1c40f';
if ($upper === 'ELC' || strpos($upper, 'ELC') !== false) {
$bg_color = 'rgba(46, 204, 113, 0.15)';
$border_color = 'rgba(46, 204, 113, 0.4)';
$text_color = '#2ecc71';
} elseif ($upper === '35+' || $upper === '35 PLUS' || strpos($upper, '35+') !== false) {
$bg_color = 'rgba(192, 192, 192, 0.15)';
$border_color = 'rgba(192, 192, 192, 0.4)';
$text_color = '#c0c0c0';
} elseif (strpos($upper, 'NM') !== false) {
$bg_color = 'rgba(211, 84, 0, 0.18)';
$border_color = 'rgba(211, 84, 0, 0.45)';
$text_color = '#e67e22'; // Darker orange tone
}
return [
'desc' => $desc,
'style' => 'background: ' . $bg_color . '; border: 1px solid ' . $border_color . '; color: ' . $text_color . '; padding: 1px 4px; border-radius: 3px; font-size: 0.65em; font-weight: bold; text-align: center; justify-self: center; white-space: nowrap;',
'button_style' => 'background: ' . $bg_color . '; border: 1px solid ' . $border_color . '; color: ' . $text_color . '; padding: 2px 6px; border-radius: 4px; font-size: 0.7em; font-weight: bold; display: inline-block; text-align: center; text-transform: uppercase;'
];
};
// 7. UI Styling & Layout Wrapper
$input_style = 'width: 100%; height: 34px; padding: 0 8px; background: #222; border: 1px solid #444; color: #fff; border-radius: 4px; box-sizing: border-box; font-size: 0.85em;';
$html = '
';
// Inject CSS for hover states on top view buttons
$html .= '';
$html .= '
New York Rangers Player Contracts
';
// View Toggles Styles
$btn_selected = 'background: #0073aa; color: #000000; border: 1px solid #0073aa;';
$btn_unhighlighted = 'background: #181818; color: #0073aa; border: 1px solid #0073aa;';
$season_style = ($current_view === 'season') ? $btn_selected : $btn_unhighlighted;
$summary_style = ($current_view === 'summary') ? $btn_selected : $btn_unhighlighted;
$html .= '
';
$html .= '
';
if ($current_view === 'summary') {
$html .= '
';
$html .= 'Metrics Season: ';
$html .= '';
foreach ($raw_seasons as $s_opt) {
$opt_url = esc_url(add_query_arg('metric_season', $s_opt));
$is_selected = selected($metric_season, $s_opt, false);
$html .= '' . esc_html($s_opt) . ' ';
}
$html .= ' ';
$html .= '
';
}
$html .= '
';
// Top Three Summary Metric Boxes
$html .= '
';
$html .= '
';
$html .= '
Salary Cap (' . esc_html($metric_season) . ')
';
$html .= '
$' . number_format($salary_cap, 0) . '
';
$html .= '
';
$cap_space_color = $projected_cap_space >= 0 ? '#2ecc71' : '#e74c3c';
$html .= '
';
$html .= '
Projected Cap Space
';
$html .= '
$' . number_format($projected_cap_space, 0) . '
';
$html .= '
';
$html .= '
';
$html .= '
Deadline Cap Space
';
$html .= '
$' . number_format($deadline_space, 0) . '
';
$html .= '
Deadline: ' . esc_html($deadline_date_str) . '
';
$html .= '
';
$html .= '
';
if ($settings) {
$html .= '
';
$html .= 'League Minimum: $' . number_format($league_minimum_val, 0) . ' ';
if (!empty($settings->regular_season_start) && !empty($settings->regular_season_end)) {
$html .= ' | Regular Season: ' . esc_html($settings->regular_season_start) . ' to ' . esc_html($settings->regular_season_end) . ' ';
}
if (!empty($settings->trade_deadline)) {
$html .= ' | Trade Deadline: ' . esc_html($settings->trade_deadline) . ' ';
}
$html .= '
';
}
// 8. Render Selection Filter Form (Only shown in Season View)
if ($current_view !== 'summary') {
$current_url = strtok($_SERVER["URI"] ?? $_SERVER['REQUEST_URI'], '?');
$html .= '
';
}
if ($current_view !== 'summary' && empty($results)) {
$html .= '
No contract records found matching the selected criteria.
';
$html .= '
';
return $html;
}
// 9. Categorize and Group Records (Handling Retired 35+ contracts separately)
$forwards = [];
$defense = [];
$goalies = [];
$bought_out = [];
$retained = [];
$bonuses = [];
$retired_35_plus = [];
$non_roster_forwards = [];
$non_roster_defense = [];
$non_roster_goalies = [];
$non_roster_other = [];
$table_total_cap_hit = 0;
foreach ($results as $row) {
$status = strtolower(trim($row->roster_status));
$clause = strtoupper(trim($row->clause));
$pos = trim($row->player_position);
// Check for Retired 35+ contract
if ($status === 'retired' && ($clause === '35+' || $clause === '35 PLUS' || strpos($clause, '35+') !== false)) {
$retired_35_plus[] = $row;
// Retired 35+ contracts do not count toward table_total_cap_hit or active salary allocations
continue;
}
if ($status === 'buyout' || strpos($status, 'buyout') !== false) {
$bought_out[] = $row;
$table_total_cap_hit += floatval($row->cap_hit);
continue;
}
if ($status === 'retained' || strpos($status, 'retained') !== false) {
$retained[] = $row;
$table_total_cap_hit += floatval($row->cap_hit);
continue;
}
if ($status === 'bonus' || strpos($status, 'bonus') !== false || strpos($status, 'bonus charge' ) !== false || $status === 'bonus carryover' || strpos($status, 'carryover') !== false) {
$bonuses[] = $row;
$table_total_cap_hit += floatval($row->cap_hit);
continue;
}
// Exclude other deceased or retired statuses from active/non-roster regular tables
if (in_array($status, ['deceased', 'retired'])) {
continue;
}
$is_non_roster = ($status === 'minors/buried' || $status === 'minors' || $status === 'buried' || strpos($status, 'minor') !== false);
if ($is_non_roster) {
if (in_array($pos, ['C', 'L', 'R', 'Center', 'Left Wing', 'Right Wing'])) {
$non_roster_forwards[] = $row;
} elseif (in_array($pos, ['D', 'Defenseman'])) {
$non_roster_defense[] = $row;
} elseif (in_array($pos, ['G', 'Goaltender'])) {
$non_roster_goalies[] = $row;
} else {
$non_roster_other[] = $row;
}
} else {
$table_total_cap_hit += floatval($row->cap_hit);
if (in_array($pos, ['C', 'L', 'R', 'Center', 'Left Wing', 'Right Wing'])) {
$forwards[] = $row;
} elseif (in_array($pos, ['D', 'Defenseman'])) {
$defense[] = $row;
} elseif (in_array($pos, ['G', 'Goaltender'])) {
$goalies[] = $row;
} else {
$forwards[] = $row;
}
}
}
$render_fa_badge = function($raw_fa_type) {
$fa_raw_trimmed = trim($raw_fa_type);
$fa_upper = strtoupper($fa_raw_trimmed);
if (empty($fa_upper)) return '-';
$fa_color = '';
$is_rfa = (strpos($fa_upper, 'RFA') !== false);
$is_ufa = (strpos($fa_upper, 'UFA') !== false);
if ($is_rfa) {
$fa_color = '#e74c3c';
} elseif ($is_ufa) {
$fa_color = '#3498db';
}
if (!empty($fa_color)) {
$badge_style = 'background: ' . $fa_color . '; color: #fff; padding: 2px 5px; border-radius: 3px; font-size: 0.75em; font-weight: bold; display: inline-flex; align-items: center; justify-content: center; gap: 3px; line-height: 1.2; width: 58px; box-sizing: border-box; text-align: center;';
$badge_html = '';
$has_arbitration = ($fa_upper === 'RFA-A' || $fa_upper === 'RFA (A)' || preg_match('/^RFA[\s\-\(]+A[\)]?$/i', $fa_raw_trimmed));
if ($has_arbitration) {
$badge_html .= 'RFA ';
} else {
$badge_html .= esc_html($fa_upper);
}
$badge_html .= '';
return $badge_html;
}
return esc_html($fa_raw_trimmed);
};
// ==========================================
// MULTI-YEAR SUMMARY LOGIC & RENDER
// ==========================================
if ($current_view === 'summary') {
$all_players_query = "SELECT DISTINCT player_id FROM {$years_table} WHERE player_id IS NOT NULL AND player_id != ''";
$all_player_ids = $wpdb->get_col($all_players_query);
if (!empty($all_player_ids)) {
$ids_str = implode("','", array_map('esc_sql', $all_player_ids));
$future_query = "
SELECT
T2.player_id AS profile_id,
T2.player_id,
T1.aav,
T1.free_agent_type,
T1.fa_season,
T2.season,
T2.cap_hit,
T2.clause,
T2.roster_status,
p.Name AS player_name,
p.position AS player_position
FROM {$years_table} AS T2
LEFT JOIN {$contracts_table} AS T1 ON T2.contract_id = T1.contract_id
LEFT JOIN {$players_table} AS p ON T2.player_id = p.ID
WHERE T2.player_id IN ('$ids_str')
";
$future_records = $wpdb->get_results($future_query);
} else {
$future_records = [];
}
$player_future_years = [];
$player_meta = [];
foreach ($future_records as $fr) {
$pid = $fr->player_id;
// Check if player's roster status in this year view is deceased or retired (excluding retired 35+ contracts which have their own section)
$status_check = strtolower(trim($fr->roster_status));
$clause_check = strtoupper(trim($fr->clause));
$is_ret_35 = ($status_check === 'retired' && ($clause_check === '35+' || $clause_check === '35 PLUS' || strpos($clause_check, '35+') !== false));
if ($status_check === 'deceased' || ($status_check === 'retired' && !$is_ret_35)) {
continue;
}
if (!isset($player_future_years[$pid])) {
$player_future_years[$pid] = [];
}
// Fetch one_way from contract years or contracts table for image checking
$one_way_val = $wpdb->get_var($wpdb->prepare(
"SELECT one_way FROM {$years_table} WHERE player_id = %s AND season = %s LIMIT 1",
$pid,
$fr->season
));
if ($one_way_val === null) {
$one_way_val = $wpdb->get_var($wpdb->prepare(
"SELECT one_way FROM {$contracts_table} AS T1 JOIN {$years_table} AS T2 ON T1.contract_id = T2.contract_id WHERE T2.player_id = %s AND T2.season = %s LIMIT 1",
$pid,
$fr->season
));
}
// Calculate adjusted cap hit for multi-year view if buried or retired 35+
$effective_cap_hit = floatval($fr->cap_hit);
if ($is_ret_35) {
$effective_cap_hit = 0; // Retired 35+ contracts count as 0 against cap totals
} elseif ($status_check === 'minors' || $status_check === 'minors/buried' || $status_check === 'buried' || strpos($status_check, 'minor') !== false) {
$p_aav = $effective_cap_hit > 0 ? $effective_cap_hit : (!empty($fr->aav) ? floatval($fr->aav) : 0);
$effective_cap_hit = max(0, $p_aav - $league_minimum_val);
}
$player_future_years[$pid][$fr->season] = [
'cap_hit' => $effective_cap_hit,
'raw_cap_hit' => floatval($fr->cap_hit),
'clause' => $fr->clause,
'fa_type' => $fr->free_agent_type,
'one_way' => $one_way_val,
'roster_status' => $fr->roster_status
];
if (!isset($player_meta[$pid])) {
$player_meta[$pid] = $fr;
}
}
$min_season = null;
$max_season = null;
foreach ($future_records as $fr) {
if (!empty($fr->season)) {
if ($min_season === null || strcmp($fr->season, $min_season) < 0) {
$min_season = $fr->season;
}
if ($max_season === null || strcmp($fr->season, $max_season) > 0) {
$max_season = $fr->season;
}
}
}
if ($min_season === null) $min_season = $default_season;
if ($max_season === null) $max_season = $default_season;
$inc_season = function($s) {
$p = explode('-', $s);
if (count($p) == 2) {
return ($p[0]+1) . '-' . str_pad(($p[1]+1), 2, '0', STR_PAD_LEFT);
}
return $s;
};
$display_seasons = [];
$curr = $min_season;
while (strcmp($curr, $max_season) <= 0) {
$display_seasons[] = $curr;
$curr = $inc_season($curr);
}
if (!in_array($max_season, $display_seasons)) {
$display_seasons[] = $max_season;
}
// Fetch Salary Cap per season from settings table for the bottom summary breakdown
$season_caps = [];
$caps_results = $wpdb->get_results("SELECT season, salary_cap FROM {$settings_table}");
foreach ($caps_results as $cr) {
$season_caps[$cr->season] = floatval($cr->salary_cap);
}
$sum_forwards = [];
$sum_defense = [];
$sum_goalies = [];
$sum_bought_out = [];
$sum_retained = [];
$sum_bonuses = [];
$sum_retired_35_plus = [];
$sum_non_roster_forwards = [];
$sum_non_roster_defense = [];
$sum_non_roster_goalies = [];
$sum_non_roster_other = [];
foreach ($player_meta as $pid => $row) {
$status = strtolower(trim($row->roster_status));
$clause = strtoupper(trim($row->clause));
$pos = trim($row->player_position);
$is_ret_35 = ($status === 'retired' && ($clause === '35+' || $clause === '35 PLUS' || strpos($clause, '35+') !== false));
if ($status === 'deceased' || ($status === 'retired' && !$is_ret_35)) {
continue;
}
if ($is_ret_35) {
$sum_retired_35_plus[] = $row;
continue;
}
if ($status === 'buyout' || strpos($status, 'buyout') !== false) {
$sum_bought_out[] = $row;
continue;
}
if ($status === 'retained' || strpos($status, 'retained') !== false) {
$sum_retained[] = $row;
continue;
}
if ($status === 'bonus' || strpos($status, 'bonus') !== false || strpos($status, 'bonus charge') !== false || $status === 'bonus carryover' || strpos($status, 'carryover') !== false) {
$sum_bonuses[] = $row;
continue;
}
$is_non_roster = ($status === 'minors/buried' || $status === 'minors' || $status === 'buried' || strpos($status, 'minor') !== false);
if ($is_non_roster) {
if (in_array($pos, ['C', 'L', 'R', 'Center', 'Left Wing', 'Right Wing'])) {
$sum_non_roster_forwards[] = $row;
} elseif (in_array($pos, ['D', 'Defenseman'])) {
$sum_non_roster_defense[] = $row;
} elseif (in_array($pos, ['G', 'Goaltender'])) {
$sum_non_roster_goalies[] = $row;
} else {
$sum_non_roster_other[] = $row;
}
} else {
if (in_array($pos, ['C', 'L', 'R', 'Center', 'Left Wing', 'Right Wing'])) {
$sum_forwards[] = $row;
} elseif (in_array($pos, ['D', 'Defenseman'])) {
$sum_defense[] = $row;
} elseif (in_array($pos, ['G', 'Goaltender'])) {
$sum_goalies[] = $row;
} else {
$sum_forwards[] = $row;
}
}
}
$total_cols = count($display_seasons) + 1; // Player column + season columns
$html .= '';
$html .= '
';
$html .= '';
$html .= ' ';
foreach ($display_seasons as $s) {
$html .= ' ';
}
$html .= ' ';
// Main Header Row
$html .= '';
$html .= 'Player ';
foreach ($display_seasons as $s) {
$html .= '' . esc_html($s) . ' ';
}
$html .= ' ';
$render_summary_section = function($title, $rows, $is_first_section = false) use ($player_future_years, $display_seasons, $inc_season, $render_fa_badge, $total_cols, $get_clause_details, $get_status_icon_html) {
if (empty($rows)) return ['', array_fill_keys($display_seasons, 0)];
usort($rows, function($a, $b) use ($player_future_years) {
$a_max = 0;
if (isset($player_future_years[$a->player_id])) {
$a_max = max(array_column($player_future_years[$a->player_id], 'cap_hit'));
}
$b_max = 0;
if (isset($player_future_years[$b->player_id])) {
$b_max = max(array_column($player_future_years[$b->player_id], 'cap_hit'));
}
return $b_max <=> $a_max;
});
// Added top margin spacing if not the very first section
$top_border_style = $is_first_section ? 'border-top: 2px solid #333;' : 'border-top: 15px solid #0b0b0b; border-bottom: 1px solid #333;';
$sec_html = '' . esc_html($title) . ' ';
$season_totals = array_fill_keys($display_seasons, 0);
foreach ($rows as $row) {
$display_name = !empty($row->player_name) ? $row->player_name : $row->player_id;
$profile_link = esc_url(home_url('/profile/?player_id=' . intval($row->profile_id)));
$sec_html .= '';
$p_data = isset($player_future_years[$row->player_id]) ? $player_future_years[$row->player_id] : [];
$p_max_season = '';
$latest_fa_type = $row->free_agent_type;
foreach ($p_data as $s => $data) {
if (strcmp($s, $p_max_season) > 0) {
$p_max_season = $s;
}
if (!empty($data['fa_type'])) {
$latest_fa_type = $data['fa_type'];
}
}
if (empty($p_max_season)) {
$p_max_season = $row->season;
}
$current_row_status = isset($p_data[$p_max_season]['roster_status']) ? $p_data[$p_max_season]['roster_status'] : (isset($row->roster_status) ? $row->roster_status : '');
$player_status_icon = $get_status_icon_html($current_row_status);
$sec_html .= '' . esc_html($display_name) . ' ' . $player_status_icon . ' ';
$fa_season_target = $inc_season($p_max_season);
foreach ($display_seasons as $s) {
$sec_html .= '';
if (isset($p_data[$s])) {
$ch = $p_data[$s]['cap_hit'];
$clause = $p_data[$s]['clause'];
$one_way_val = $p_data[$s]['one_way'];
$season_totals[$s] += $ch;
$sec_html .= '';
$left_group = '
';
if (!empty($clause)) {
$c_info = $get_clause_details($clause);
$left_group .= '
' . esc_html($clause) . ' ';
}
if ($one_way_val !== null && strtolower(trim((string)$one_way_val)) === 'n') {
$left_group .= '
';
}
$left_group .= '
';
$sec_html .= $left_group;
$sec_html .= '
$' . number_format($ch, 0) . ' ';
$sec_html .= '
';
} elseif ($s === $fa_season_target) {
$sec_html .= '' . $render_fa_badge($latest_fa_type) . '
';
} else {
$sec_html .= '-
';
}
$sec_html .= ' ';
}
$sec_html .= ' ';
}
$sec_html .= '';
$sec_html .= '' . esc_html($title) . ' Total: ';
foreach ($display_seasons as $s) {
$sec_html .= '';
if ($season_totals[$s] > 0) {
$sec_html .= '$' . number_format($season_totals[$s], 0) . '
';
} else {
$sec_html .= '-';
}
$sec_html .= ' ';
}
$sec_html .= ' ';
return [$sec_html, $season_totals];
};
list($f_html, $f_totals) = $render_summary_section('Forwards', $sum_forwards, true);
list($d_html, $d_totals) = $render_summary_section('Defensemen', $sum_defense, false);
list($g_html, $g_totals) = $render_summary_section('Goaltenders', $sum_goalies, false);
list($bo_html, $bo_totals) = $render_summary_section('Bought Out Contracts', $sum_bought_out, false);
list($re_html, $re_totals) = $render_summary_section('Retained Salary Transactions', $sum_retained, false);
list($bn_html, $bn_totals) = $render_summary_section('Salary Bonus Charges', $sum_bonuses, false);
list($r35_html, $r35_totals) = $render_summary_section('Retired 35+ Contracts', $sum_retired_35_plus, false);
// ==========================================
// SEASON-BY-SEASON TOTAL SUMMARY BLOCK
// ==========================================
$summary_block_html = 'Season Summary Breakdown ';
$render_summary_row_html = function($label, $totals_arr, $highlight = false, $custom_color = '#fff') use ($display_seasons) {
$row_bg = $highlight ? '#1c1c1c' : '#121212';
$r_html = '';
$r_html .= '' . esc_html($label) . ' ';
foreach ($display_seasons as $s) {
$val = isset($totals_arr[$s]) ? $totals_arr[$s] : 0;
$r_html .= '';
if ($val > 0) {
$r_html .= '$' . number_format($val, 0) . '
';
} else {
$r_html .= '-
';
}
$r_html .= ' ';
}
$r_html .= ' ';
return $r_html;
};
// 1. Total Salary (Forwards + Defensemen + Goaltenders)
$total_salary_totals = [];
foreach ($display_seasons as $s) {
$total_salary_totals[$s] = (isset($f_totals[$s]) ? $f_totals[$s] : 0) +
(isset($d_totals[$s]) ? $d_totals[$s] : 0) +
(isset($g_totals[$s]) ? $g_totals[$s] : 0);
}
$summary_block_html .= $render_summary_row_html('Total Salary:', $total_salary_totals, false, '#ccc');
// 2. Total Buyout
$summary_block_html .= $render_summary_row_html('Total Buyout:', $bo_totals, false, '#ccc');
// 3. Total Retained
$summary_block_html .= $render_summary_row_html('Total Retained:', $re_totals, false, '#ccc');
// 4. Total Bonus Carryover
$summary_block_html .= $render_summary_row_html('Total Bonus Carryover:', $bn_totals, false, '#ccc');
// 5. Retired 35+ Contracts Total Line
$summary_block_html .= $render_summary_row_html('Retired 35+ Contracts:', $r35_totals, false, '#ccc');
// 6. Total Cap Hit (Sum of relevant lines, excluding Retired 35+ contracts which are 0)
$total_cap_hit_totals = [];
foreach ($display_seasons as $s) {
$total_cap_hit_totals[$s] = (isset($total_salary_totals[$s]) ? $total_salary_totals[$s] : 0) +
(isset($bo_totals[$s]) ? $bo_totals[$s] : 0) +
(isset($re_totals[$s]) ? $re_totals[$s] : 0) +
(isset($bn_totals[$s]) ? $bn_totals[$s] : 0);
}
$summary_block_html .= $render_summary_row_html('Total Cap Hit:', $total_cap_hit_totals, true, '#fff');
// 7. Salary Cap
$salary_cap_totals = [];
foreach ($display_seasons as $s) {
$salary_cap_totals[$s] = isset($season_caps[$s]) ? $season_caps[$s] : $salary_cap;
}
$summary_block_html .= $render_summary_row_html('Salary Cap:', $salary_cap_totals, false, '#3498db');
// 8. Cap Space
$cap_space_totals = [];
foreach ($display_seasons as $s) {
$cap_space_totals[$s] = $salary_cap_totals[$s] - $total_cap_hit_totals[$s];
}
$space_row_bg = '#1c1c1c';
$summary_block_html .= '';
$summary_block_html .= 'Cap Space: ';
foreach ($display_seasons as $s) {
$c_space = $cap_space_totals[$s];
$space_color = $c_space >= 0 ? '#2ecc71' : '#e74c3c';
$summary_block_html .= '';
$summary_block_html .= '$' . number_format($c_space, 0) . '
';
$summary_block_html .= ' ';
}
$summary_block_html .= ' ';
// Append active roster sections, retired 35+, and the summary block first
$html .= $f_html . $d_html . $g_html . $bo_html . $re_html . $bn_html . $r35_html . $summary_block_html;
// Render Non-Roster sections at the BOTTOM in Summary view
if (!empty($sum_non_roster_forwards) || !empty($sum_non_roster_defense) || !empty($sum_non_roster_goalies) || !empty($sum_non_roster_other)) {
list($nrf_html, $nrf_totals) = $render_summary_section('Non-Roster Forwards', $sum_non_roster_forwards, false);
list($nrd_html, $nrd_totals) = $render_summary_section('Non-Roster Defensemen', $sum_non_roster_defense, false);
list($nrg_html, $nrg_totals) = $render_summary_section('Non-Roster Goaltenders', $sum_non_roster_goalies, false);
list($nro_html, $nro_totals) = $render_summary_section('Non-Roster Other', $sum_non_roster_other, false);
$non_roster_block_html = 'Non-Roster Players
';
$non_roster_block_html .= $nrf_html . $nrd_html . $nrg_html . $nro_html;
$html .= $non_roster_block_html;
}
$html .= '
';
} else {
// ==========================================
// SEASON VIEW LOGIC & RENDER
// ==========================================
$active_total_cap = 0;
$render_section_table = function($title, $rows, &$total_sum, $selected_season, $wpdb, $league_minimum_val, $is_retired_block = false) use ($calculate_actual_days, $calculate_projected_days, $render_fa_badge, $get_clause_details, $get_status_icon_html, $contracts_table, $years_table) {
if (empty($rows)) return '';
$section_sum = 0;
if (!$is_retired_block) {
foreach ($rows as $r) {
if (!empty($r->cap_hit)) {
$status_lower = strtolower(trim($r->roster_status));
if ($status_lower === 'minors' || $status_lower === 'minors/buried' || $status_lower === 'buried' || strpos($status_lower, 'minor') !== false) {
$p_aav = floatval($r->cap_hit);
$section_sum += max(0, $p_aav - $league_minimum_val);
} else {
$section_sum += floatval($r->cap_hit);
}
}
}
$total_sum += $section_sum;
}
$html = '' . esc_html($title) . '
';
$html .= '';
$html .= '
';
$html .= '';
$html .= ' ';
$html .= ' ';
$html .= ' ';
$html .= ' ';
$html .= ' ';
$html .= ' ';
$html .= ' ';
$html .= ' ';
$html .= ' ';
$html .= ' ';
$html .= '';
$html .= 'Player ';
$html .= 'Position ';
$html .= 'Cap Hit ';
$html .= 'Status ';
$html .= 'Actual Days ';
$html .= 'Projected Days ';
$html .= 'FA Type ';
$html .= 'FA Season ';
$html .= 'Waivers ';
$html .= ' ';
foreach ($rows as $row) {
$display_name = !empty($row->player_name) ? $row->player_name : $row->player_id;
$profile_link = esc_url(home_url('/profile/?player_id=' . intval($row->profile_id)));
$actual_days = $calculate_actual_days($row);
$projected_days = $calculate_projected_days($row);
// Fetch Waiver Status
$waiver_status = otg_get_waiver_status( $row->player_id, $selected_season, $wpdb );
$badge_bg = $waiver_status['exempt'] ? 'rgba(46, 204, 113, 0.15)' : 'rgba(231, 76, 60, 0.15)';
$badge_border = $waiver_status['exempt'] ? '#2ecc71' : '#e74c3c';
$badge_color = $waiver_status['exempt'] ? '#2ecc71' : '#e74c3c';
$player_status_icon = $get_status_icon_html($row->roster_status);
$html .= '';
$html .= '' . esc_html($display_name) . ' ' . $player_status_icon . ' ';
$html .= '' . esc_html($row->player_position) . ' ';
$html .= '';
if (!empty($row->cap_hit)) {
$contract_info = $wpdb->get_row($wpdb->prepare(
"SELECT one_way FROM {$contracts_table} WHERE player_id = %s OR contract_id = (SELECT contract_id FROM {$years_table} WHERE player_id = %s AND season = %s LIMIT 1) LIMIT 1",
$row->player_id,
$row->player_id,
$selected_season
));
$one_way_val = $contract_info ? $contract_info->one_way : null;
if ($one_way_val === null) {
$one_way_val = $wpdb->get_var($wpdb->prepare(
"SELECT one_way FROM {$years_table} WHERE player_id = %s AND season = %s LIMIT 1",
$row->player_id,
$selected_season
));
}
$status_lower = strtolower(trim($row->roster_status));
$display_cap_val = floatval($row->cap_hit);
if ($is_retired_block) {
$display_cap_val = floatval($row->cap_hit); // Show contract AAV/cap hit on row, but totals are unaffected
} else {
$is_buried_contract = ($status_lower === 'minors' || $status_lower === 'minors/buried' || $status_lower === 'buried' || strpos($status_lower, 'minor') !== false);
if ($is_buried_contract) {
$display_cap_val = max(0, floatval($row->cap_hit) - $league_minimum_val);
}
}
$html .= '';
$left_group = '
';
if (!empty($row->clause)) {
$c_info = $get_clause_details($row->clause);
$left_group .= '
' . esc_html($row->clause) . ' ';
}
if ($one_way_val !== null && strtolower(trim((string)$one_way_val)) === 'n') {
$left_group .= '
';
}
$left_group .= '
';
$html .= $left_group;
$cap_display_text = '$' . number_format($display_cap_val, 0);
$html .= '
' . $cap_display_text . ' ';
$html .= '
';
} else {
$html .= '- ';
}
$html .= ' ';
$html .= '' . (!empty($row->roster_status) ? esc_html($row->roster_status) : 'Free Agent') . ' ';
$html .= '' . (!empty($row->cap_hit) && $actual_days !== '' ? $actual_days : '-') . ' ';
$html .= '' . (!empty($row->cap_hit) && $projected_days !== '' ? $projected_days : '-') . ' ';
// Right-justified FA badge container
$html .= '' . $render_fa_badge($row->free_agent_type) . '
';
$html .= '' . esc_html($row->fa_season) . ' ';
$html .= '' . esc_html($waiver_status['label']) . ' ';
$html .= ' ';
}
$html .= '';
$html .= '' . esc_html($title) . ' Total: ';
$html .= '-
';
$html .= ' ';
$html .= ' ';
$html .= '
';
return $html;
};
$render_non_roster_table = function($title, $rows, $selected_season, $wpdb, $league_minimum_val) use ($calculate_actual_days, $calculate_projected_days, $render_fa_badge, $get_clause_details, $get_status_icon_html, $contracts_table, $years_table) {
if (empty($rows)) return '';
$html = '' . esc_html($title) . '
';
$html .= '';
$html .= '
';
$html .= '';
$html .= ' ';
$html .= ' ';
$html .= ' ';
$html .= ' ';
$html .= ' ';
$html .= ' ';
$html .= ' ';
$html .= ' ';
$html .= ' ';
$html .= ' ';
$html .= '';
$html .= 'Player ';
$html .= 'Position ';
$html .= 'Cap Hit ';
$html .= 'Status ';
$html .= 'Actual Days ';
$html .= 'Projected Days ';
$html .= 'FA Type ';
$html .= 'FA Season ';
$html .= 'Waivers ';
$html .= ' ';
$non_roster_sum = 0;
foreach ($rows as $row) {
if (!empty($row->cap_hit)) {
$status_lower = strtolower(trim($row->roster_status));
if ($status_lower === 'minors' || $status_lower === 'minors/buried' || $status_lower === 'buried' || strpos($status_lower, 'minor') !== false) {
$p_aav = floatval($row->cap_hit);
$non_roster_sum += max(0, $p_aav - $league_minimum_val);
} else {
$non_roster_sum += floatval($row->cap_hit);
}
}
$display_name = !empty($row->player_name) ? $row->player_name : $row->player_id;
$profile_link = esc_url(home_url('/profile/?player_id=' . intval($row->profile_id)));
$actual_days = $calculate_actual_days($row);
$projected_days = $calculate_projected_days($row);
// Fetch Waiver Status
$waiver_status = otg_get_waiver_status( $row->player_id, $selected_season, $wpdb );
$badge_bg = $waiver_status['exempt'] ? 'rgba(46, 204, 113, 0.15)' : 'rgba(231, 76, 60, 0.15)';
$badge_border = $waiver_status['exempt'] ? '#2ecc71' : '#e74c3c';
$badge_color = $waiver_status['exempt'] ? '#2ecc71' : '#e74c3c';
$player_status_icon = $get_status_icon_html($row->roster_status);
$html .= '';
$html .= '' . esc_html($display_name) . ' ' . $player_status_icon . ' ';
$html .= '' . esc_html($row->player_position) . ' ';
$html .= '';
if (!empty($row->cap_hit)) {
$contract_info = $wpdb->get_row($wpdb->prepare(
"SELECT one_way FROM {$contracts_table} WHERE player_id = %s OR contract_id = (SELECT contract_id FROM {$years_table} WHERE player_id = %s AND season = %s LIMIT 1) LIMIT 1",
$row->player_id,
$row->player_id,
$selected_season
));
$one_way_val = $contract_info ? $contract_info->one_way : null;
if ($one_way_val === null) {
$one_way_val = $wpdb->get_var($wpdb->prepare(
"SELECT one_way FROM {$years_table} WHERE player_id = %s AND season = %s LIMIT 1",
$row->player_id,
$selected_season
));
}
$status_lower = strtolower(trim($row->roster_status));
$display_cap_val = floatval($row->cap_hit);
$is_buried_contract = ($status_lower === 'minors' || $status_lower === 'minors/buried' || $status_lower === 'buried' || strpos($status_lower, 'minor') !== false);
if ($is_buried_contract) {
$display_cap_val = max(0, floatval($row->cap_hit) - $league_minimum_val);
}
$html .= '';
$left_group = '
';
if (!empty($row->clause)) {
$c_info = $get_clause_details($row->clause);
$left_group .= '
' . esc_html($row->clause) . ' ';
}
if ($one_way_val !== null && strtolower(trim((string)$one_way_val)) === 'n') {
$left_group .= '
';
}
$left_group .= '
';
$html .= $left_group;
$cap_display_text = '$' . number_format($display_cap_val, 0);
$html .= '
' . $cap_display_text . ' ';
$html .= '
';
} else {
$html .= '- ';
}
$html .= ' ';
$html .= '' . (!empty($row->roster_status) ? esc_html($row->roster_status) : 'Free Agent') . ' ';
$html .= '' . (!empty($row->cap_hit) && $actual_days !== '' ? $actual_days : '-') . ' ';
$html .= '' . (!empty($row->cap_hit) && $projected_days !== '' ? $projected_days : '-') . ' ';
// Right-justified FA badge container
$html .= '' . $render_fa_badge($row->free_agent_type) . '
';
$html .= '' . esc_html($row->fa_season) . ' ';
$html .= '' . esc_html($waiver_status['label']) . ' ';
$html .= ' ';
}
$html .= '';
$html .= '' . esc_html($title) . ' Total: ';
$html .= '$' . number_format($non_roster_sum, 0) . '
';
$html .= ' ';
$html .= ' ';
$html .= '
';
return $html;
};
// Render active roster sections first
$html .= $render_section_table('Forwards', $forwards, $active_total_cap, $selected_season, $wpdb, $league_minimum_val);
$html .= $render_section_table('Defensemen', $defense, $active_total_cap, $selected_season, $wpdb, $league_minimum_val);
$html .= $render_section_table('Goaltenders', $goalies, $active_total_cap, $selected_season, $wpdb, $league_minimum_val);
$html .= $render_section_table('Bought Out Contracts', $bought_out, $active_total_cap, $selected_season, $wpdb, $league_minimum_val);
$html .= $render_section_table('Retained Salary Transactions', $retained, $active_total_cap, $selected_season, $wpdb, $league_minimum_val);
$html .= $render_section_table('Salary Bonus Charges', $bonuses, $active_total_cap, $selected_season, $wpdb, $league_minimum_val);
// Render Retired 35+ contracts block in Season view if present
if (!empty($retired_35_plus)) {
$html .= $render_section_table('Retired 35+ Contracts', $retired_35_plus, $active_total_cap, $selected_season, $wpdb, $league_minimum_val, true);
}
// Render Non-Roster sections at the BOTTOM in Season View
if (!empty($non_roster_forwards) || !empty($non_roster_defense) || !empty($non_roster_goalies) || !empty($non_roster_other)) {
$html .= 'Non-Roster players
';
$html .= $render_non_roster_table('Non-Roster Forwards', $non_roster_forwards, $selected_season, $wpdb, $league_minimum_val);
$html .= $render_non_roster_table('Non-Roster Defensemen', $non_roster_defense, $selected_season, $wpdb, $league_minimum_val);
$html .= $render_non_roster_table('Non-Roster Goaltenders', $non_roster_goalies, $selected_season, $wpdb, $league_minimum_val);
$html .= $render_non_roster_table('Non-Roster Other', $non_roster_other, $selected_season, $wpdb, $league_minimum_val);
}
$html .= '';
$html .= 'Total Cap Hit Allocation: ';
$html .= '$' . number_format($active_total_cap, 0) . ' ';
$html .= '
';
}
$html .= '';
return $html;
}
Adam Johnson Death – Manslaughter? – NHL – OutsideTheGarden Boards
Skip to content