From 7da5a7a3e6bc927e68435262a0c90c21a2111970 Mon Sep 17 00:00:00 2001 From: para <157126561+mdegallaix@users.noreply.github.com> Date: Fri, 25 Sep 2026 23:45:55 +0200 Subject: [PATCH] Fix article links and include full content in PHP feeds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two bugs found by testing real links from the feed: - Link format was wrong (?news=), landing on the general listing instead of the article. Traced the real network call the site makes when opening an item and found the actual pattern: /actualites/?u= (agenda: /agenda/?u=), where the JS router reads the `u` query param to fetch @results?UID=...&fullobjects=1. - Description only used the short teaser (description_fr) even though the API response already includes the full rich-text body (text_fr.data) and attachments (items[].file.download) in the same call — no extra request needed, just wasn't being used. Co-Authored-By: Claude Sonnet 5 --- php/actualites.php | 11 +++++----- php/agenda.php | 12 ++++++----- php/common.php | 50 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 10 deletions(-) diff --git a/php/actualites.php b/php/actualites.php index aed86da..ab8b87d 100644 --- a/php/actualites.php +++ b/php/actualites.php @@ -30,13 +30,14 @@ function build_news_feed(): string $items = []; foreach (fetch_all_news() as $item) { $id = $item['id'] ?? ''; - $summary = strip_html($item['description_fr'] ?? $item['description'] ?? null); + $title = $item['title_fr'] ?? $item['title'] ?? '(sans titre)'; + $uid = $item['UID'] ?? $id; $items[] = [ - 'title' => $item['title_fr'] ?? $item['title'] ?? '(sans titre)', - 'link' => SITE . '/actualites?news=' . rawurlencode($id), - 'guid' => $item['UID'] ?? $id, + 'title' => $title, + 'link' => SITE . '/actualites/' . slugify($title) . '?u=' . rawurlencode($uid), + 'guid' => $uid, 'pubDate' => $item['effective'] ?? $item['created'] ?? null, - 'description' => $summary, + 'description' => full_body_html($item), ]; } return build_rss( diff --git a/php/agenda.php b/php/agenda.php index 4e68771..f2006bb 100644 --- a/php/agenda.php +++ b/php/agenda.php @@ -51,13 +51,15 @@ function build_events_feed(): string $items = []; foreach (fetch_all_events() as $item) { $id = basename(rtrim($item['@id'] ?? '', '/')); - $summary = strip_html($item['description_fr'] ?? $item['description'] ?? null); + $title = $item['title_fr'] ?? $item['title'] ?? '(sans titre)'; + $uid = $item['UID'] ?? $id; $meta = format_event_meta($item); - $description = implode(' | ', array_filter([$meta, $summary])); + $description = ($meta !== '' ? '

' . htmlspecialchars($meta, ENT_QUOTES, 'UTF-8') . '

' : '') + . full_body_html($item); $items[] = [ - 'title' => $item['title_fr'] ?? $item['title'] ?? '(sans titre)', - 'link' => SITE . '/agenda?event=' . rawurlencode($id), - 'guid' => $item['UID'] ?? $id, + 'title' => $title, + 'link' => SITE . '/agenda/' . slugify($title) . '?u=' . rawurlencode($uid), + 'guid' => $uid, 'pubDate' => $item['created'] ?? $item['start'] ?? null, 'description' => $description, ]; diff --git a/php/common.php b/php/common.php index b9eb3ac..f4a3113 100644 --- a/php/common.php +++ b/php/common.php @@ -98,6 +98,56 @@ function strip_html(?string $text): string return trim(preg_replace('/\s+/', ' ', $text)); } +/** + * Reproduit le slug d'URL genere par le site (cosmetique : le routeur + * JS de silly.be lit en realite le parametre `u` pour savoir quel item + * afficher, pas ce segment de chemin - mais autant coller a l'URL + * "officielle" telle qu'on la voit dans la barre d'adresse). + */ +function slugify(string $text): string +{ + $ascii = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $text); + if ($ascii === false) { + $ascii = $text; + } + $ascii = strtolower($ascii); + $ascii = preg_replace('/[^a-z0-9]+/', '-', $ascii); + return trim($ascii, '-'); +} + +/** + * Construit le HTML des liens vers les pieces jointes (PDF, etc.) + * renvoyees par l'API dans le champ "items" de chaque actualite/evenement. + */ +function attachments_html(array $item): string +{ + $html = ''; + foreach ($item['items'] ?? [] as $sub) { + $url = $sub['file']['download'] ?? $sub['targetUrl'] ?? null; + if (!$url) { + continue; + } + $label = $sub['title'] ?? basename($url); + $html .= '

' + . htmlspecialchars($label, ENT_QUOTES, 'UTF-8') . '

'; + } + return $html; +} + +/** + * Corps HTML complet d'un item (texte riche + pieces jointes), avec + * repli sur le resume court si le texte complet est vide. + */ +function full_body_html(array $item): string +{ + $body = trim($item['text_fr']['data'] ?? ''); + if ($body === '') { + $summary = strip_html($item['description_fr'] ?? $item['description'] ?? null); + $body = $summary !== '' ? '

' . htmlspecialchars($summary, ENT_QUOTES, 'UTF-8') . '

' : ''; + } + return $body . attachments_html($item); +} + function rfc822(?string $isoDate): string { try {