various improvements to make release 1 complete

This commit is contained in:
Reindl David (IT-PTR-CEN2-SL10)
2026-03-27 13:59:28 +01:00
parent 9ea962131a
commit 6b9c3fefa1
37 changed files with 7695 additions and 1803 deletions
+274 -79
View File
@@ -22,6 +22,8 @@ class Swi_Foot_Shortcodes
add_shortcode('swi_foot_match_round', array($this, 'match_round_shortcode'));
add_shortcode('swi_foot_standings', array($this, 'standings_shortcode'));
add_shortcode('swi_foot_roster', array($this, 'roster_shortcode'));
add_shortcode('swi_foot_bench', array($this, 'bench_shortcode'));
add_shortcode('swi_foot_referees', array($this, 'referees_shortcode'));
add_shortcode('swi_foot_events', array($this, 'events_shortcode'));
add_shortcode('swi_foot_match_data', array($this, 'match_data_shortcode'));
add_shortcode('swi_foot_match_home_team_logo', array($this, 'match_home_team_logo_shortcode'));
@@ -44,6 +46,26 @@ class Swi_Foot_Shortcodes
return $vars;
}
/**
* Render error message, distinguishing between "data not available" (406) and other errors
* @param WP_Error $error The error object
* @return string HTML-formatted error message
*/
private function render_error_message($error)
{
if (!is_wp_error($error)) {
return '';
}
// Check if this is a "data not yet available" error (HTTP 406)
if ($error->get_error_code() === 'data_not_available') {
return '<div class="swi-foot-data-warning">⏳ ' . __('Data not yet available', 'swi_foot_matchdata') . '</div>';
}
// For other errors, show grey "no data available" message
return '<div class="swi-foot-data-unavailable">ℹ️ ' . __('No data available', 'swi_foot_matchdata') . '</div>';
}
/**
* Handle internal requests for team logo images
* URL format: /?swi_foot_team_logo=team_id&position=home|away|event
@@ -198,7 +220,7 @@ class Swi_Foot_Shortcodes
$match_data = $this->get_match_data($atts);
if (!$match_data) {
return '<span class="swi-foot-error">' . __('Match data not available', 'swi_foot_matchdata') . '</span>';
return '<div class="swi-foot-error">' . __('Match data not available', 'swi_foot_matchdata') . '</div>';
}
ob_start();
@@ -388,6 +410,139 @@ class Swi_Foot_Shortcodes
return '';
}
/**
* Render match bench (team staff) list
* Usage: [swi_foot_bench match_id="12345"]
* Lists staff members (name and role) for both home and away teams
*/
public function bench_shortcode($atts)
{
$atts = shortcode_atts(array(
'match_id' => '',
'side' => '' // 'home' or 'away', shows both if not specified
), $atts);
$match_id = $atts['match_id'];
if (empty($match_id)) {
return '<div class="swi-foot-error">' . __('Match ID required', 'swi_foot_matchdata') . '</div>';
}
$bench = $this->api->get_match_bench($match_id);
if (is_wp_error($bench)) {
return $this->render_error_message($bench);
}
if (empty($bench)) {
return '<div class="swi-foot-notice">' . __('No bench data available', 'swi_foot_matchdata') . '</div>';
}
// Normalize side parameter
$side = strtolower(trim($atts['side']));
$show_side_filter = !empty($side) && in_array($side, array('home', 'away'), true);
ob_start();
?>
<div class="swi-foot-bench-container" data-match-id="<?php echo esc_attr($match_id); ?>">
<?php
// Group bench players by team
$home_staff = array_filter($bench, function($person) {
return isset($person['isHomeTeam']) && $person['isHomeTeam'] === true;
});
$away_staff = array_filter($bench, function($person) {
return isset($person['isHomeTeam']) && $person['isHomeTeam'] === false;
});
// If side is specified, filter to only that side
if ($show_side_filter) {
if ($side === 'home') {
$away_staff = array();
} else {
$home_staff = array();
}
}
?>
<?php if (!empty($home_staff)): ?>
<div class="bench-team bench-home">
<?php if (!$show_side_filter): ?>
<h3><?php echo esc_html($home_staff[array_key_first($home_staff)]['teamName'] ?? __('Home Team', 'swi_foot_matchdata')); ?></h3>
<?php endif; ?>
<ul class="bench-list">
<?php foreach ($home_staff as $person): ?>
<li class="bench-person">
<?php echo esc_html($person['personName'] ?? ''); ?>
<?php if (!empty($person['roleCategoryName'])): ?>
<span class="swi-foot-role">(<?php echo esc_html($person['roleCategoryName']); ?>)</span>
<?php endif; ?>
</li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
<?php if (!empty($away_staff)): ?>
<div class="bench-team bench-away">
<?php if (!$show_side_filter): ?>
<h3><?php echo esc_html($away_staff[array_key_first($away_staff)]['teamName'] ?? __('Away Team', 'swi_foot_matchdata')); ?></h3>
<?php endif; ?>
<ul class="bench-list">
<?php foreach ($away_staff as $person): ?>
<li class="bench-person">
<?php echo esc_html($person['personName'] ?? ''); ?>
<?php if (!empty($person['roleCategoryName'])): ?>
<span class="swi-foot-role">(<?php echo esc_html($person['roleCategoryName']); ?>)</span>
<?php endif; ?>
</li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
</div>
<?php
return ob_get_clean();
}
/**
* Render referees list for a match
* Usage: [swi_foot_referees match_id="12345"]
* Lists referees with their role and name formatted as: "Role: Firstname Name" (name in bold)
*/
public function referees_shortcode($atts)
{
$atts = shortcode_atts(array(
'match_id' => ''
), $atts);
$match_id = $atts['match_id'];
if (empty($match_id)) {
return '<div class="swi-foot-error">✗ ' . __('Match ID required', 'swi_foot_matchdata') . '</div>';
}
$referees = $this->api->get_match_referees($match_id);
if (is_wp_error($referees)) {
return $this->render_error_message($referees);
}
if (empty($referees)) {
return '<div class="swi-foot-data-unavailable">ℹ️ ' . __('No data available', 'swi_foot_matchdata') . '</div>';
}
ob_start();
?>
<div class="swi-foot-referees-container" data-match-id="<?php echo esc_attr($match_id); ?>">
<ul class="referees-list">
<?php foreach ($referees as $referee): ?>
<li class="referee-item">
<span class="referee-role"><?php echo esc_html($referee['refereeRoleName'] ?? ''); ?>:</span>
<strong><?php echo esc_html(($referee['firstname'] ?? '') . ' ' . ($referee['name'] ?? '')); ?></strong>
</li>
<?php endforeach; ?>
</ul>
</div>
<?php
return ob_get_clean();
}
/**
* Generic inline data point shortcode
* Extracts a specific field from match data and displays it inline
@@ -512,15 +667,16 @@ class Swi_Foot_Shortcodes
return null;
}
// Parse the matchDate string - handle multiple formats
$timestamp = strtotime($match['matchDate']);
if ($timestamp === false) {
// Extract date part from ISO datetime string (e.g., "2026-03-27T19:30:00" -> "2026-03-27")
// API provides date in Swiss time, use as-is without any timezone conversion
$date_part = substr($match['matchDate'], 0, 10);
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $date_part)) {
return null;
}
// Use WordPress date format setting
// Convert date string to WordPress format
$date_format = get_option('date_format');
return wp_date($date_format, $timestamp);
return date_i18n($date_format, strtotime($date_part));
}
/**
@@ -535,15 +691,20 @@ class Swi_Foot_Shortcodes
return null;
}
// Parse the matchDate string - handle multiple formats
$timestamp = strtotime($match['matchDate']);
if ($timestamp === false) {
// Extract time part from ISO datetime string (e.g., "2026-03-27T19:30:00" -> "19:30:00")
// API provides time in Swiss time, use as-is without any timezone conversion
if (strpos($match['matchDate'], 'T') === false) {
return null;
}
$time_part = substr($match['matchDate'], 11, 8);
if (!preg_match('/^\d{2}:\d{2}:\d{2}$/', $time_part)) {
return null;
}
// Use WordPress time format setting
// Format time string with WordPress time format setting
$time_format = get_option('time_format');
return wp_date($time_format, $timestamp);
return date_i18n($time_format, strtotime('2000-01-01 ' . $time_part));
}
private function get_match_data($atts)
@@ -616,13 +777,13 @@ class Swi_Foot_Shortcodes
), $atts);
if (empty($atts['team_id'])) {
return '<span class="swi-foot-error">' . __('Team ID required', 'swi_foot_matchdata') . '</span>';
return '<div class="swi-foot-error">' . __('Team ID required', 'swi_foot_matchdata') . '</div>';
}
$standings = $this->api->get_standings($atts['team_id']);
if (is_wp_error($standings) || empty($standings)) {
return '<span class="swi-foot-error">' . __('Standings data not available', 'swi_foot_matchdata') . '</span>';
return '<div class="swi-foot-error">' . __('Standings data not available', 'swi_foot_matchdata') . '</div>';
}
ob_start();
@@ -667,16 +828,18 @@ class Swi_Foot_Shortcodes
public function roster_shortcode($atts)
{
$atts = shortcode_atts(array(
'match_id' => '',
'team_id' => '',
'show_current' => 'false',
'side' => '',
'with_bench' => 'false'
'match_id' => '',
'team_id' => '',
'show_current' => 'false',
'side' => '',
'show_starting' => 'true',
'show_bench' => 'false',
'with_bench' => 'false' // Legacy support
), $atts);
$side = strtolower(trim($atts['side']));
if (!in_array($side, array('home', 'away'), true)) {
return '<span class="swi-foot-error">' . __('Parameter "side" must be "home" or "away"', 'swi_foot_matchdata') . '</span>';
return '<div class="swi-foot-error">' . __('Parameter "side" must be "home" or "away"', 'swi_foot_matchdata') . '</div>';
}
$match_id = $atts['match_id'];
@@ -688,27 +851,27 @@ class Swi_Foot_Shortcodes
}
if (empty($match_id)) {
return '<span class="swi-foot-error">' . __('Match ID required', 'swi_foot_matchdata') . '</span>';
return '<div class="swi-foot-error">' . __('Match ID required', 'swi_foot_matchdata') . '</div>';
}
// Parse show_starting and show_bench attributes (handle legacy with_bench)
$show_starting = strtolower($atts['show_starting']) === 'true';
$show_bench = strtolower($atts['show_bench']) === 'true';
// Legacy support: if with_bench is true and show_starting is default, show both
if (strtolower($atts['with_bench']) === 'true' && !$show_bench) {
$show_bench = true;
}
// First check if we have saved final data
$saved = $this->api->get_finished_match_data($match_id);
if ($saved) {
$players = $saved['roster']['players'] ?? array();
$bench_players = $saved['roster']['bench'] ?? array();
$players = $saved['roster']['players'] ?? array();
} else {
// Live fetch
$players = $this->api->get_match_players($match_id);
if (is_wp_error($players)) {
return '<span class="swi-foot-error">' . __('Roster data not available', 'swi_foot_matchdata') . ': ' . esc_html($players->get_error_message()) . '</span>';
}
$bench_players = array();
if (strtolower($atts['with_bench']) === 'true') {
$bench = $this->api->get_match_bench($match_id);
if (!is_wp_error($bench)) {
$bench_players = $bench;
}
return $this->render_error_message($players);
}
// Check match ended & possibly save events + roster together
@@ -722,68 +885,100 @@ class Swi_Foot_Shortcodes
if (is_array($players)) {
$this->api->save_finished_match_data(
$match_id,
array('players' => $players, 'bench' => $bench_players),
array('players' => $players),
$events
);
}
}
}
// Filter roster for side
$filtered_players = array_filter($players, function ($p) use ($side) {
// Filter players by team side
$team_players = array_filter($players, function ($p) use ($side) {
return $side === 'home' ? !empty($p['isHomeTeam']) : empty($p['isHomeTeam']);
});
$filtered_bench = array_filter($bench_players, function ($p) use ($side) {
return $side === 'home' ? !empty($p['isHomeTeam']) : empty($p['isHomeTeam']);
// Split players into starting (assignmentRoleId = 0 or 1 for captain) and bench (assignmentRoleId > 1)
$starting_players = array_filter($team_players, function ($p) {
return isset($p['assignmentRoleId']) && ((int)$p['assignmentRoleId'] === 0 || (int)$p['assignmentRoleId'] === 1);
});
$bench_players = array_filter($team_players, function ($p) {
return !isset($p['assignmentRoleId']) || ((int)$p['assignmentRoleId'] > 1);
});
// If neither option is checked, return empty div
if (!$show_starting && !$show_bench) {
return '<div class="swi-foot-error">' . __('No roster display options selected', 'swi_foot_matchdata') . '</div>';
}
ob_start();
?>
<div class="swi-foot-roster" data-match-id="<?php echo esc_attr($match_id); ?>">
<h3><?php echo esc_html(ucfirst($side) . ' ' . __('Team Roster', 'swi_foot_matchdata')); ?></h3>
<?php if (!empty($filtered_players)): ?>
<ul class="roster-list">
<?php foreach ($filtered_players as $pl): ?>
<li>
<?php
$jersey = $pl['jerseyNumber'] ?? '';
$firstname = $pl['firstname'] ?? '';
$name = $pl['name'] ?? '';
$secondName = $pl['secondName'] ?? '';
$positionName = $pl['positionName'] ?? $pl['position'] ?? '';
$displayName = trim($firstname . ' ' . $name . ' ' . $secondName);
echo esc_html($jersey . ' – ' . $displayName);
if (!empty($positionName)) {
echo ' (' . esc_html($positionName) . ')';
}
?>
</li>
<?php endforeach; ?>
</ul>
<?php else: ?>
<p><?php _e('No roster data available.', 'swi_foot_matchdata'); ?></p>
<?php if ($show_starting && !empty($starting_players)): ?>
<div class="swi-foot-roster-starting">
<h4><?php _e('Starting Squad', 'swi_foot_matchdata'); ?></h4>
<ul class="roster-list">
<?php foreach ($starting_players as $pl): ?>
<li class="roster-player<?php echo isset($pl['assignmentRoleId']) && (int)$pl['assignmentRoleId'] === 1 ? ' roster-player-captain' : ''; ?>">
<?php
$jersey = $pl['jerseyNumber'] ?? '';
$firstname = $pl['firstname'] ?? '';
$name = $pl['name'] ?? '';
$secondName = $pl['secondName'] ?? '';
$positionName = $pl['positionName'] ?? $pl['position'] ?? '';
$isCaptain = isset($pl['assignmentRoleId']) && (int)$pl['assignmentRoleId'] === 1;
$displayName = trim($firstname . ' ' . $name . ' ' . $secondName);
// Captain badge
if ($isCaptain) {
echo '<span class="swi-foot-captain-badge" title="' . esc_attr(__('Captain', 'swi_foot_matchdata')) . '">C</span> ';
}
echo esc_html($jersey . ' – ' . $displayName);
if (!empty($positionName)) {
echo ' <span class="swi-foot-position">(' . esc_html($positionName) . ')</span>';
}
?>
</li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
<?php if (!empty($filtered_bench)): ?>
<h4><?php _e('Bench', 'swi_foot_matchdata'); ?></h4>
<ul class="roster-bench-list">
<?php foreach ($filtered_bench as $pl): ?>
<li>
<?php
$jersey = $pl['jerseyNumber'] ?? '';
$firstname = $pl['firstname'] ?? '';
$name = $pl['name'] ?? '';
$secondName = $pl['secondName'] ?? '';
$positionName = $pl['positionName'] ?? $pl['position'] ?? '';
$displayName = trim($firstname . ' ' . $name . ' ' . $secondName);
echo esc_html($jersey . ' – ' . $displayName);
if (!empty($positionName)) {
echo ' (' . esc_html($positionName) . ')';
}
?>
</li>
<?php endforeach; ?>
</ul>
<?php if ($show_starting && !empty($starting_players) && $show_bench && !empty($bench_players)): ?>
<hr class="swi-foot-roster-divider" />
<?php endif; ?>
<?php if ($show_bench && !empty($bench_players)): ?>
<div class="swi-foot-roster-bench">
<h4><?php _e('Bench', 'swi_foot_matchdata'); ?></h4>
<ul class="roster-bench-list">
<?php foreach ($bench_players as $pl): ?>
<li class="roster-player">
<?php
$jersey = $pl['jerseyNumber'] ?? '';
$firstname = $pl['firstname'] ?? '';
$name = $pl['name'] ?? '';
$secondName = $pl['secondName'] ?? '';
$positionName = $pl['positionName'] ?? $pl['position'] ?? '';
$displayName = trim($firstname . ' ' . $name . ' ' . $secondName);
echo esc_html($jersey . ' – ' . $displayName);
if (!empty($positionName)) {
echo ' <span class="swi-foot-position">(' . esc_html($positionName) . ')</span>';
}
?>
</li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
<?php if (!$show_starting && !empty($bench_players) && !$show_bench): ?>
<p><?php _e('No roster data to display.', 'swi_foot_matchdata'); ?></p>
<?php elseif ($show_starting && empty($starting_players) && empty($bench_players)): ?>
<p><?php _e('No roster data available.', 'swi_foot_matchdata'); ?></p>
<?php endif; ?>
</div>
<?php
@@ -814,7 +1009,7 @@ class Swi_Foot_Shortcodes
}
if (empty($match_id)) {
return '<span class="swi-foot-error">' . __('Match ID required', 'swi_foot_matchdata') . '</span>';
return '<div class="swi-foot-error">' . __('Match ID required', 'swi_foot_matchdata') . '</div>';
}
// Try saved first
@@ -824,7 +1019,7 @@ class Swi_Foot_Shortcodes
} else {
$events = $this->api->get_match_events($match_id);
if (is_wp_error($events)) {
return '<span class="swi-foot-error">' . __('Events data not available', 'swi_foot_matchdata') . '</span>';
return $this->render_error_message($events);
}
// Check if match ended and store both data sets