Fix article links and include full content in PHP feeds
Two bugs found by testing real links from the feed: - Link format was wrong (?news=<internal-id>), 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/<slug>?u=<UID> (agenda: /agenda/<slug>?u=<UID>), 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 <noreply@anthropic.com>
This commit is contained in:
+6
-5
@@ -30,13 +30,14 @@ function build_news_feed(): string
|
|||||||
$items = [];
|
$items = [];
|
||||||
foreach (fetch_all_news() as $item) {
|
foreach (fetch_all_news() as $item) {
|
||||||
$id = $item['id'] ?? '';
|
$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[] = [
|
$items[] = [
|
||||||
'title' => $item['title_fr'] ?? $item['title'] ?? '(sans titre)',
|
'title' => $title,
|
||||||
'link' => SITE . '/actualites?news=' . rawurlencode($id),
|
'link' => SITE . '/actualites/' . slugify($title) . '?u=' . rawurlencode($uid),
|
||||||
'guid' => $item['UID'] ?? $id,
|
'guid' => $uid,
|
||||||
'pubDate' => $item['effective'] ?? $item['created'] ?? null,
|
'pubDate' => $item['effective'] ?? $item['created'] ?? null,
|
||||||
'description' => $summary,
|
'description' => full_body_html($item),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
return build_rss(
|
return build_rss(
|
||||||
|
|||||||
+7
-5
@@ -51,13 +51,15 @@ function build_events_feed(): string
|
|||||||
$items = [];
|
$items = [];
|
||||||
foreach (fetch_all_events() as $item) {
|
foreach (fetch_all_events() as $item) {
|
||||||
$id = basename(rtrim($item['@id'] ?? '', '/'));
|
$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);
|
$meta = format_event_meta($item);
|
||||||
$description = implode(' | ', array_filter([$meta, $summary]));
|
$description = ($meta !== '' ? '<p>' . htmlspecialchars($meta, ENT_QUOTES, 'UTF-8') . '</p>' : '')
|
||||||
|
. full_body_html($item);
|
||||||
$items[] = [
|
$items[] = [
|
||||||
'title' => $item['title_fr'] ?? $item['title'] ?? '(sans titre)',
|
'title' => $title,
|
||||||
'link' => SITE . '/agenda?event=' . rawurlencode($id),
|
'link' => SITE . '/agenda/' . slugify($title) . '?u=' . rawurlencode($uid),
|
||||||
'guid' => $item['UID'] ?? $id,
|
'guid' => $uid,
|
||||||
'pubDate' => $item['created'] ?? $item['start'] ?? null,
|
'pubDate' => $item['created'] ?? $item['start'] ?? null,
|
||||||
'description' => $description,
|
'description' => $description,
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -98,6 +98,56 @@ function strip_html(?string $text): string
|
|||||||
return trim(preg_replace('/\s+/', ' ', $text));
|
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 .= '<p><a href="' . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . '">'
|
||||||
|
. htmlspecialchars($label, ENT_QUOTES, 'UTF-8') . '</a></p>';
|
||||||
|
}
|
||||||
|
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 !== '' ? '<p>' . htmlspecialchars($summary, ENT_QUOTES, 'UTF-8') . '</p>' : '';
|
||||||
|
}
|
||||||
|
return $body . attachments_html($item);
|
||||||
|
}
|
||||||
|
|
||||||
function rfc822(?string $isoDate): string
|
function rfc822(?string $isoDate): string
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user