';
}
if ($hasModelStrip) {
$stripLabel = isset($modelStrip['label']) ? trim((string)$modelStrip['label']) : '';
$stripLabelEsc = $stripLabel !== '' ? htmlspecialchars($stripLabel, ENT_QUOTES, 'UTF-8') : '';
$stripIcon = isset($modelStrip['icon']) ? trim((string)$modelStrip['icon']) : '';
$stripImgClass = 'sportwtf-pred-card-model-strip-img';
if (!empty($modelStrip['icon_class'])) {
$stripImgClass .= ' ' . trim((string)$modelStrip['icon_class']);
}
$out .= '
';
if ($stripIcon !== '') {
if (strpos($stripImgClass, 'sportwtf-pred-card-model-strip-img--api-sports') !== false) {
$out .= '
 . ')
';
} else {
$out .= '
 . ')
';
}
}
if ($stripLabelEsc !== '') {
$out .= '
' . $stripLabelEsc . '';
}
$out .= '
';
$out .= '
';
}
$out .= '
';
$out .= '
';
if (!empty($hl)) {
$out .= '
' . htmlspecialchars($ha, ENT_QUOTES, 'UTF-8') . '';
} else {
$out .= '
' . htmlspecialchars($ha, ENT_QUOTES, 'UTF-8') . '';
}
$out .= '
0.0%';
$out .= '
';
if (!empty($al)) {
$out .= '
' . htmlspecialchars($aa, ENT_QUOTES, 'UTF-8') . '';
} else {
$out .= '
' . htmlspecialchars($aa, ENT_QUOTES, 'UTF-8') . '';
}
$out .= '
0.0%';
$out .= '
';
$out .= '
DRAW0.0%
';
if ($hasModelStrip) {
$out .= '
';
}
$out .= $outerClose;
return $out;
}
}
$predictionsRoot = (int)$modx->getOption('predictionsRoot', $scriptProperties, 0);
if ($predictionsRoot <= 0) {
$predictionsRoot = (int)$modx->getOption('sportwtf_predictions_parent_id', null, 0);
}
$predictionTplId = (int)$modx->getOption('predictionTemplateId', $scriptProperties, 9);
$limit = (int)$modx->getOption('limit', $scriptProperties, 300);
if ($limit < 1) {
$limit = 300;
}
if ($limit > 500) {
$limit = 500;
}
if (!$modx->resource) {
return '';
}
$currentId = (int)$modx->resource->get('id');
$useFlat = ((int)$modx->getOption('flatList', $scriptProperties, 0) === 1)
|| ($predictionsRoot > 0 && $currentId === $predictionsRoot);
$layout = strtolower(trim((string)$modx->getOption('layout', $scriptProperties, '')));
if ($layout === '') {
$layout = ($useFlat ? 'compare' : 'feed');
}
if (!in_array($layout, array('compare', 'feed'), true)) {
$layout = 'compare';
}
if (!$useFlat) {
$layout = 'feed';
}
$claudeLeagues = array(39, 140, 135, 78, 61, 235);
$dataDir = rtrim($modx->getOption('core_path', null, ''), '/') . '/data/sportwtf/';
$assetsUrl = rtrim($modx->getOption('assets_url', null, '/assets/'), '/');
$claudeMarkUrl = $assetsUrl . '/images/claude-analyst.svg';
$apiSportsLogoUrl = $assetsUrl . '/images/api-sports-logo.png';
/* ---------- Режим compare: insight JSON + friendlies + fixtures ---------- */
if ($layout === 'compare' && $useFlat) {
$friendliesMap = sportwtf_predictions_hub_merge_friendlies($dataDir);
$insightGl = @glob(rtrim($dataDir, '/') . '/predictions_claude/insight_*.json');
if (!is_array($insightGl)) {
$insightGl = array();
}
$insights = array();
foreach ($insightGl as $ip) {
$ir = @file_get_contents($ip);
if ($ir === false || $ir === '') {
continue;
}
$idec = @json_decode($ir, true);
if (!is_array($idec) || empty($idec['fixture_id']) || empty($idec['text'])) {
continue;
}
$lid = isset($idec['league_id']) ? (int)$idec['league_id'] : 0;
if (!in_array($lid, $claudeLeagues, true)) {
continue;
}
$fid = (int)$idec['fixture_id'];
$insights[] = $idec;
}
if ($insights === array()) {
return '
Прогнозов ИИ пока нет (нет insight_*.json).
';
}
usort($insights, function ($a, $b) {
$ta = 0;
$tb = 0;
foreach (array('fixture_date', 'date') as $k) {
if (!empty($a[$k]) && $ta === 0) {
$ta = @strtotime((string)$a[$k]);
}
if (!empty($b[$k]) && $tb === 0) {
$tb = @strtotime((string)$b[$k]);
}
}
if ($ta === false) {
$ta = 0;
}
if ($tb === false) {
$tb = 0;
}
return (int)$tb - (int)$ta;
});
$insights = array_slice($insights, 0, $limit);
$dialogs = array();
ob_start();
?>
isset($idec['home']) ? $idec['home'] : '—', 'logo' => '');
$away = isset($m['teams']['away']) ? $m['teams']['away'] : array('name' => isset($idec['away']) ? $idec['away'] : '—', 'logo' => '');
} else {
$home = array('name' => isset($idec['home']) ? $idec['home'] : '—', 'logo' => '');
$away = array('name' => isset($idec['away']) ? $idec['away'] : '—', 'logo' => '');
}
$pkey = (string)$fixtureId;
$apiRow = (!empty($friendliesMap[$pkey]) && is_array($friendliesMap[$pkey])) ? $friendliesMap[$pkey] : null;
$cPredUrl = sportwtf_predictions_force_https_url(isset($idec['prediction_url']) ? trim((string)$idec['prediction_url']) : '');
$hasClaudePct = isset($idec['p_home'], $idec['p_draw'], $idec['p_away']);
$claudeHtml = '';
if ($hasClaudePct) {
$predRowClaude = array(
'p_home' => (float)$idec['p_home'],
'p_draw' => (float)$idec['p_draw'],
'p_away' => (float)$idec['p_away'],
);
$cDlgId = 'sportwtf-claude-dlg-hub-' . $fixtureId;
$claudeHtml = sportwtf_predictions_hub_render_pred_card($home, $away, $predRowClaude, array(
'data_dlg' => $cPredUrl === '' ? $cDlgId : '',
'prediction_url' => $cPredUrl,
'root_class' => 'sportwtf-pred-card--claude-pct',
'aria_label' => 'Claude: оценка исходов',
'model_strip' => array(
'label' => 'CLAUDE',
'icon' => $claudeMarkUrl,
),
));
}
$apiHtml = '';
if ($apiRow !== null) {
$apiHtml = sportwtf_predictions_hub_render_pred_card($home, $away, $apiRow, array(
'aria_label' => 'Прогноз API Sports (API-Football predictions)',
'root_class' => 'sportwtf-pred-card--api-sports-pred',
'model_strip' => array(
'label' => 'API SPORTS',
'icon' => $apiSportsLogoUrl,
'icon_class' => 'sportwtf-pred-card-model-strip-img--api-sports',
),
));
}
$kickTs = false;
if ($m && !empty($m['fixture']['date'])) {
$kickTs = @strtotime((string)$m['fixture']['date']);
}
if ($kickTs === false) {
$kickTs = !empty($idec['fixture_date']) ? @strtotime((string)$idec['fixture_date']) : false;
}
$kickLabel = ($kickTs !== false && $kickTs > 0) ? date('d.m H:i', $kickTs) : '';
$leagueLabel = sportwtf_predictions_hub_league_id_label(isset($idec['league_id']) ? $idec['league_id'] : 0);
if ($cPredUrl === '' && $hasClaudePct && !empty($idec['text'])) {
$cDlgId = 'sportwtf-claude-dlg-hub-' . $fixtureId;
$dialogs[] = array(
'id' => $cDlgId,
'home' => isset($idec['home']) ? $idec['home'] : $home['name'],
'away' => isset($idec['away']) ? $idec['away'] : $away['name'],
'text' => (string)$idec['text'],
);
}
?>
Нет оценки Claude (PCT_JSON) для этого матча
Нет блока API (запустите cron_friendlies_predictions или проверьте predictions_friendlies_*.json)
';
$sectionHtml .= '';
$sectionHtml .= '
' . htmlspecialchars($dlg['home'], ENT_QUOTES, 'UTF-8') . ' — ' . htmlspecialchars($dlg['away'], ENT_QUOTES, 'UTF-8') . '
';
$sectionHtml .= '
' . nl2br(htmlspecialchars($dlg['text'], ENT_QUOTES, 'UTF-8')) . '
';
$sectionHtml .= '
Оценка исходов на карточке — субъективная; не гарантия результата.
';
$sectionHtml .= '';
}
if ($dialogs !== array()) {
$sectionHtml .= '';
}
$sectionHtml .= '';
return $sectionHtml;
}
/* ---------- Режим feed (MODX-ресурсы) ---------- */
$rowsOut = array();
if ($useFlat && $predictionsRoot > 0 && $predictionTplId > 0) {
$c = $modx->newQuery('modResource');
$c->where(array(
'template' => $predictionTplId,
'published' => 1,
'deleted' => 0,
));
$c->sortby('publishedon', 'DESC');
$all = $modx->getCollection('modResource', $c);
foreach ($all as $res) {
if (!sportwtf_predictions_hub_under_root($modx, $res, $predictionsRoot)) {
continue;
}
$uri = trim((string)$res->get('uri'), '/');
if ($uri !== '' && stripos($uri, 'football/predictions/') !== 0) {
continue;
}
$pub = (int)$res->get('publishedon');
$title = trim((string)$res->get('pagetitle'));
if ($title === '') {
continue;
}
$rowsOut[] = array(
'id' => (int)$res->get('id'),
'title' => $title,
'published' => $pub,
'league_label' => sportwtf_predictions_hub_league_label($uri),
);
}
usort($rowsOut, function ($a, $b) {
return (int)$b['published'] - (int)$a['published'];
});
$rowsOut = array_slice($rowsOut, 0, $limit);
} else {
$c = $modx->newQuery('modResource');
$c->where(array(
'parent' => $currentId,
'published' => 1,
'deleted' => 0,
));
$collection = $modx->getCollection('modResource', $c);
if (empty($collection)) {
return '
В этом разделе пока нет страниц.
';
}
$rows = array_values($collection);
usort($rows, function ($a, $b) {
$fa = (int)$a->get('isfolder');
$fb = (int)$b->get('isfolder');
if ($fa !== $fb) {
return $fb - $fa;
}
if (!$fa && !$fb) {
return (int)$b->get('publishedon') - (int)$a->get('publishedon');
}
return strcasecmp((string)$a->get('pagetitle'), (string)$b->get('pagetitle'));
});
foreach ($rows as $r) {
$id = (int)$r->get('id');
$isFolder = (bool)$r->get('isfolder');
$pub = (int)$r->get('publishedon');
$title = trim((string)$r->get('pagetitle'));
if ($title === '') {
continue;
}
$uri = trim((string)$r->get('uri'), '/');
$rowsOut[] = array(
'id' => $id,
'title' => $title,
'published' => $pub,
'league_label' => $isFolder ? 'Раздел' : sportwtf_predictions_hub_league_label($uri),
);
}
}
if ($rowsOut === array()) {
return '
Прогнозов пока нет.
';
}
ob_start();
?>
0 ? date('d.m H:i', $r['published']) : '';
$label = $r['league_label'];
?>
-