loadXML($raw)) { throw new RuntimeException('Flux WordPress illisible (XML invalide)'); } $xpath = new DOMXPath($doc); $xpath->registerNamespace('atom', 'http://www.w3.org/2005/Atom'); $selfLinks = $xpath->query('/rss/channel/atom:link[@rel="self"]'); if ($selfLinks->length === 0) { throw new RuntimeException('Reponse inattendue : pas un flux RSS'); } foreach ($selfLinks as $selfLink) { $selfLink->setAttribute('href', SELF_URL); } // WordPress emet \n\thourly\t : on retire // les blancs parasites autour des valeurs. $xpath->registerNamespace('sy', 'http://purl.org/rss/1.0/modules/syndication/'); foreach ($xpath->query('/rss/channel/sy:*') as $node) { $node->textContent = trim($node->textContent); } // Pages suivantes : un echec (ou une page vide) arrete simplement la // pagination, la premiere page suffit a servir un flux valide. $channel = $xpath->query('/rss/channel')->item(0); $seen = []; foreach ($xpath->query('/rss/channel/item/guid') as $g) { $seen[trim($g->textContent)] = true; } for ($page = 2; $page <= NEWS_PAGES; $page++) { try { $more = new DOMDocument(); $raw = http_get(NEWS_FEED_URL . '?paged=' . $page, ['Accept: application/rss+xml, application/xml']); if (!@$more->loadXML($raw)) { break; } } catch (Throwable $e) { break; } $added = 0; $moreXpath = new DOMXPath($more); foreach ($moreXpath->query('/rss/channel/item') as $item) { // Le tri de WordPress n'est pas stable entre articles de meme // date : on dedoublonne par guid aux jonctions de pages. $guid = trim($moreXpath->evaluate('string(guid)', $item)); if ($guid === '' || isset($seen[$guid])) { continue; } $seen[$guid] = true; $channel->appendChild($doc->importNode($item, true)); $added++; } if ($added === 0) { break; } } return $doc->saveXML(); } serve_cached_feed('actualites', 'build_news_feed');