Sitemap news (pour google)

Bonjour,

J'ai vu que l'on pouvait créer un sitemap particulier pour les actualités (pour google), j'ai donc créé un news.php basé sur sitemap.php qui génère ce fichier. Il se limite à afficher les infos des articles de moins de 2 jours (c'est ce que demande Google) dans le bon format.

La source est sur gitlab et le voila en action (j'ai volontairement changé la durée de validité pour que vous puissiez avoir un résultat)

Enjoy :)

Les news de zeolia.chat sont propulsées par PluXml

Mots clés:

Réponses

  • bazooka07bazooka07 PluXml Lead Developer, Moderator

    Bonjour,

    Bonne idée !

    Tu peux faire le test sur la date dans la boucle foreach. Et calculer la date butoir en dehors de la boucle. Cela évite de remplir le tableau $array d'articles inutiles. Au final cela donne ceci :

    <?php
    const PLX_ROOT = './';
    const PLX_CORE = PLX_ROOT .'core/';
    
    include(PLX_ROOT.'config.php');
    include(PLX_CORE.'lib/config.php');
    
    # On verifie que PluXml est installé
    if(!file_exists(path('XMLFILE_PARAMETERS'))) {
        header('Location: install.php');
        exit;
    }
    
    # On inclut les librairies nécessaires
    include(PLX_CORE.'lib/class.plx.date.php');
    include(PLX_CORE.'lib/class.plx.glob.php');
    include(PLX_CORE.'lib/class.plx.utils.php');
    include(PLX_CORE.'lib/class.plx.capcha.php');
    include(PLX_CORE.'lib/class.plx.erreur.php');
    include(PLX_CORE.'lib/class.plx.record.php');
    include(PLX_CORE.'lib/class.plx.motor.php');
    include(PLX_CORE.'lib/class.plx.plugins.php');
    
    # On impose le charset
    header('Content-Type: text/xml; charset='.PLX_CHARSET);
    
    # Creation de l'objet principal et lancement du traitement
    $plxMotor = plxMotor::getInstance();
    
    # Détermination de la langue à utiliser (modifiable par le hook : Index)
    $lang = $plxMotor->aConf['default_lang'];
    
    # Hook Plugins
    if(eval($plxMotor->plxPlugins->callHook('SitemapBegin'))) return;
    
    # chargement du fichier de langue
    loadLang(PLX_CORE.'lang/'.$lang.'/core.php');
    
    # On démarre la bufferisation
    ob_start();
    ob_implicit_flush(0);
    
    $plxMotor->prechauffage();
    $plxMotor->demarrage();
    
    # Entête XML
    echo '<?xml version="1.0" encoding="'.strtolower(PLX_CHARSET).'" ?>'.PHP_EOL;
    ?>
    <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9">
    <?php
    # Les articles
    if($aFiles = $plxMotor->plxGlob_arts->query('/^[0-9]{4}.(?:[0-9]|home|,)*(?:'.$plxMotor->activeCats.'|home)(?:[0-9]|home|,)*.[0-9]{3}.[0-9]{12}.[a-z0-9-]+.xml$/','art','rsort', 0, false, 'before')) {
        $limiteDate = (int)date('Ymd', strtotime('-2 days'));
        $plxRecord_arts = false;
        $array=array();
        foreach($aFiles as $k=>$v) { # On parcourt tous les fichiers
            $art = $plxMotor->parseArticle(PLX_ROOT.$plxMotor->aConf['racine_articles'].$v);
            if($art['date_update'] < $limiteDate) {
                $array[ $k ] = $art;
            }
        }
        # On stocke les enregistrements dans un objet plxRecord
        $plxRecord_arts = new plxRecord($array);
        if($plxRecord_arts) {
    
            # On boucle sur nos articles
            while($plxRecord_arts->loop()) {
                $num = intval($plxRecord_arts->f('numero'));
    ?>
        <url>
            <loc><?= $plxMotor->urlRewrite("?article".$num."/".plxUtils::strCheck($plxRecord_arts->f('url'))) ?></loc>
            <news:news>
                <news:publication>
                    <news:name>News !!!</news:name>
                    <news:language><?= $lang ?></news:language>
                </news:publication>
                <news:publication_date><?= plxDate::formatDate($plxRecord_arts->f('date_update'),'#num_year(4)-#num_month-#num_day') ?></news:publication_date>
                <news:title><?= $plxRecord_arts->f('title') ?>"</news:title>
            </news:news>
        </url>
    <?php
            }
        }
    }
    eval($plxMotor->plxPlugins->callHook('SitemapArticles')); # Hook Plugins
    ?>
    </urlset>
    <?php
    
    # Récuperation de la bufférisation
    $output = ob_get_clean();
    
    eval($plxMotor->plxPlugins->callHook('SitemapEnd')); # Hook Plugins
    
    # Restitution écran
    echo $output;
    

    Je n'ai pas testé mais cela devrait le faire.

  • bazooka07bazooka07 PluXml Lead Developer, Moderator

    La limite de 2 jours parait arbitraire.
    Peut-être vaudrait mieux se limiter aux X derniers articles.
    Ce qui te permettra de ne rien publier pendant plus de 2 jours sans que tes visiteurs se retrouvent devant une page blanche.

  • CrazyCatCrazyCat Member
    29 oct. modifié

    Concernant la boucle: effectivement j'ai été fainéant, mon but était surtout de valider la création du xml propre et accepté par google, mais je vais appliquer ta recommandation.
    En ce qui concerne la limite de 2 jours, c'est bien une préconisation de google (qui est le seul à exploiter ce format), comme dit sur https://developers.google.com/search/docs/crawling-indexing/sitemaps/news-sitemap

    N'incluez que les URL récentes correspondant aux articles créés au cours des deux derniers jours. Une fois que les articles datent de plus de deux jours, supprimez ces URL du sitemap Google Actualités ou supprimez de votre sitemap les métadonnées des anciennes URL.
    Si vous choisissez de supprimer les anciennes URL de votre sitemap Google Actualités, votre sitemap pourra rester vide pendant un certain temps (par exemple, si vous n'avez pas publié de nouveaux articles au cours des derniers jours). Il est possible qu'un avertissement "Sitemap vide" s'affiche dans la Search Console, mais il s'agit juste de vérifier que cela était intentionnel de votre part. Si le fichier est vide, cela ne posera aucun problème dans la recherche Google.

    Et deux petits points dans ton code (que je n'ai pas testé):

    • il faut formater date_update au même format que limiteDate
    • la condition pour ajouter dans le tableau des articles est que date_update soit supérieure à limiteDate

    Je ferai des tests ce soir pour créer un code plus propre.

    Les news de zeolia.chat sont propulsées par PluXml

  • bazooka07bazooka07 PluXml Lead Developer, Moderator
    3 nov. modifié

    Merci pour le lien vers Google.

    Il me semble plus pertinent de filtrer les articles par date de publication plutôt que par date de mise à jour.
    Cela simplifie le process puisque la date de publication fait partie du nom du fichier article.
    Il y a déjà des utilisateurs de PluXml qui se plaignent de la limite de 9999 artcles dans PluXml. Google fixe une limite à 1000 articles. Modestement on peut fixer la limite à 50 articles publiés sur 2 jours.
    Pour la date de publication, il me parait pertinent d'ajouter l'heure et les minutes.
    Au final, on arrive à ce code :

    <?php
    # See https://developers.google.com/search/docs/crawling-indexing/sitemaps/news-sitemap?hl=fr
    const PLX_ROOT = './';
    const PLX_CORE = PLX_ROOT .'core/';
    
    include(PLX_ROOT.'config.php');
    include(PLX_CORE.'lib/config.php');
    
    # On verifie que PluXml est installé
    if(!file_exists(path('XMLFILE_PARAMETERS'))) {
        header('Location: install.php');
        exit;
    }
    
    # On inclut les librairies nécessaires
    include(PLX_CORE.'lib/class.plx.date.php');
    include(PLX_CORE.'lib/class.plx.glob.php');
    include(PLX_CORE.'lib/class.plx.utils.php');
    include(PLX_CORE.'lib/class.plx.capcha.php');
    include(PLX_CORE.'lib/class.plx.erreur.php');
    include(PLX_CORE.'lib/class.plx.record.php');
    include(PLX_CORE.'lib/class.plx.motor.php');
    include(PLX_CORE.'lib/class.plx.plugins.php');
    
    # Creation de l'objet principal et lancement du traitement
    $plxMotor = plxMotor::getInstance();
    
    # Détermination de la langue à utiliser (modifiable par le hook : Index)
    $lang = $plxMotor->aConf['default_lang'];
    
    # Hook Plugins
    if(eval($plxMotor->plxPlugins->callHook('SitemapBegin'))) return;
    
    # chargement du fichier de langue
    loadLang(PLX_CORE.'lang/'.$lang.'/core.php');
    
    # On démarre la bufferisation
    ob_start();
    ob_implicit_flush(false);
    
    $plxMotor->prechauffage();
    $plxMotor->demarrage();
    
    # On impose le charset
    header('Content-Type: text/xml; charset=' . PLX_CHARSET);
    
    # Entête XML
    echo '<?xml version="1.0" encoding="' . strtolower(PLX_CHARSET) . '" ?>' . PHP_EOL ;
    
    ?>
    <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9">
    <?php
    if($aFiles = $plxMotor->plxGlob_arts->query('/^\d{4}\.(?:\d{3},|home,)*(?:' . $plxMotor->activeCats . ')(?:,\d{3}|,home)*\.\d{3}\.\d{12}\.[\w-]+\.xml$/', 'art', 'rsort', 0, 50, 'before')) {
        # les articles sont triés par odre de publication inversé. On se limite aux derniers 50 articles publiés.
        # Google impose une limite de 1000 articles
        $limiteDateStr = date('YmdHi', strtotime('-2 days'));
        $array=array();
        foreach($aFiles as $k=>$v) { # On parcourt tous les fichiers
            $filename = PLX_ROOT . $plxMotor->aConf['racine_articles'] . $v;
            $tmp = $plxMotor->artInfoFromFilename($filename);
            if($tmp['artDate'] >= $limiteDateStr) {
                $array[$k] = $plxMotor->parseArticle($filename);
            } else {
                # Les articles suivants sont trop anciens
                break;
            }
        }
        # On stocke les enregistrements dans un objet plxRecord
        $plxRecord_arts = new plxRecord($array);
    
        if($plxRecord_arts) {
            $name = $plxMotor->aConf['title'];
            # On boucle sur nos articles
            while($plxRecord_arts->loop()) {
                $num = intval($plxRecord_arts->f('numero'));
    ?>
        <url>
            <loc><?= $plxMotor->urlRewrite('?article' . $num . '/' . plxUtils::strCheck($plxRecord_arts->f('url'))) ?></loc>
            <news:news>
                <news:publication>
                    <news:name><?= $name ?></news:name>
                    <news:language><?= $lang ?></news:language>
                </news:publication>
                <news:publication_date><?= plxDate::formatDate($plxRecord_arts->f('date'), '#num_year(4)-#num_month-#num_dayT#hour:#minute:00TZD') ?></news:publication_date>
                <news:title><?= $plxRecord_arts->f('title') ?></news:title>
            </news:news>
        </url>
    <?php
            }
        }
    }
    ?>
    </urlset>
    <?php
    
    # Récuperation de la bufférisation
    $output = ob_get_clean();
    
    # Restitution écran
    echo $output;
    

    Je ne saisis pas trop l'intérêt de news:name vs news:title.
    Tu peux m'éclairer sur ce point ?
    Peut-être utiliser le nom de l'auteur ou de la catégorie ?

  • CrazyCatCrazyCat Member
    3 nov. modifié

    Merci pour l'optimisation du code qui fonctionne très bien.

    La différence entre news:name et news:title est simple: name est le nom du média (donc le site) quand title est le titre de l'article. J'imagine que c'est pour simplifier le travail de Google dans son rôle d'aggrégateur de nouvelles, chaque actu contient le nom du site plutôt que d'avoir le nom du site de manière globale et de devoir retraiter les données pour accoler cette information. Ils peuvent ainsi régurgiter directement les news avec un effort moindre. Ils sont presque aussi fainéant que moi ;)

    Attention, tu as une double-quote inutile dans:
    <news:title><?= $plxRecord_arts->f('title') ?>"</news:title>

    Les news de zeolia.chat sont propulsées par PluXml

Connectez-vous ou Inscrivez-vous pour répondre.