Μητρώο χαρτών ιστοτόπου
Το πακέτο δημιουργεί χάρτες XML (ένα αρχείο ανά πηγή και ένα ευρετήριο) και τους εξυπηρετεί στα /sitemap.xml και /sitemap-{name}.xml. Η δημιουργία βασίζεται στο spatie/laravel-sitemap:
composer require spatie/laravel-sitemapΚαταχώριση πηγών
Καταχωρίστε ονομασμένες πηγές στο boot() ενός service provider:
use App\Models\Post;
use Rankbeam\Seo\Facades\SEO;
// A model class — every (indexable) record's getUrlForSEO()
SEO::sitemaps()->register('posts', Post::class);
// A closure returning URLs
SEO::sitemaps()->register('pages', fn () => ['/about', '/contact']);
// Any iterable of URLs
SEO::sitemaps()->register('legal', ['/imprint', '/privacy']);Κάθε πηγή αποδίδεται στο sitemap-{name}.xml· το sitemap.xml γίνεται το ευρετήριο που τις απαριθμεί όλες.
Το API του μητρώου προσφέρει επίσης has($name), names(), forget($name) και flush().
Πηγές μέσω ρυθμίσεων
Προτιμάτε τις ρυθμίσεις; Το config/seo.php δέχεται πηγές μοντέλων και στατικές URL:
'sitemap' => [
'models' => [
\App\Models\Post::class => ['priority' => 0.8, 'changefreq' => 'weekly'],
],
'static_urls' => [
['url' => '/', 'priority' => 1.0, 'changefreq' => 'daily'],
],
],Η αυτόματη ανακάλυψη δίνει προτεραιότητα στο μητρώο
Αν ένα μοντέλο καλύπτεται από ονομασμένη καταχωρισμένη πηγή, η αυτόματη ανακάλυψη το παραλείπει — η καταχώριση του 'posts' δεν θα παράγει επιπλέον ένα sitemap-post.xml.
Δημιουργία
php artisan seo:sitemapΤα αρχεία γράφονται στον δίσκο που έχει ρυθμιστεί στο seo.sitemap.disk (προεπιλογή public). Προγραμματίστε την εντολή για να διατηρούνται ενημερωμένοι οι χάρτες:
// routes/console.php or bootstrap/app.php scheduling
Schedule::command('seo:sitemap')->daily();Οι χάρτες που υπερβαίνουν το seo.sitemap.max_urls_per_sitemap (προεπιλογή 50.000 — το όριο της προδιαγραφής XML) χωρίζονται αυτόματα.
Εξυπηρέτηση
Οι διαδρομές του πακέτου εξυπηρετούν ό,τι δημιούργησε η εντολή, με κεφαλίδες XML, κεφαλίδες cache και X-Robots-Tag: noindex:
/sitemap.xml— το ευρετήριο (ή ο μοναδικός χάρτης)/sitemap-posts.xml— μια ονομασμένη πηγή
Εξυπηρετείτε δικό σας στατικά δημιουργημένο χάρτη; Απενεργοποιήστε τις διαδρομές:
// config/seo.php
'routes' => ['enabled' => false],Μορφοποιημένος χάρτης στον browser
Η μηχανή του Spatie αποδίδει ακατέργαστο XML. Ανοίξτε έναν χάρτη Rankbeam στον browser και θα δείτε μια ευανάγνωστη σελίδα με την ταυτότητα του προϊόντος — κάθε URL σε πίνακα με το lastmod της, τη συχνότητα αλλαγής, την προτεραιότητα και τα πλήθη εικόνων/εναλλακτικών, μαζί με ενσωματωμένες σημειώσεις επικύρωσης:

Λειτουργεί αναφέροντας ένα φύλλο στυλ XSL σε κάθε παραγόμενο χάρτη:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="https://your-app.test/sitemap.xsl"?>
<urlset ...>Οι μηχανές αναζήτησης αγνοούν την οδηγία, οπότε ο χάρτης παραμένει κανονικό μηχαναγνώσιμο έγγραφο XML — αλλάζει μόνο αυτό που βλέπει ένας άνθρωπος. Το ευρετήριο και κάθε επιμέρους χάρτης μορφοποιούνται με τον ίδιο τρόπο.
Ενεργό από προεπιλογή. Σε αντίθεση με τις επεκτάσεις εικόνων/hreflang, το φύλλο στυλ δεν προσθέτει δεδομένα και δεν κάνει εργασία ανά εγγραφή — είναι μία γραμμή οδηγίας που παραλείπουν οι ανιχνευτές, οπότε είναι ενεργό εξαρχής. Απενεργοποιήστε το για απλό XML:
Απαιτεί spatie/laravel-sitemap ≥ 8.1
Η οδηγία γράφεται μέσω του setStylesheet() του spatie, που προστέθηκε στο spatie/laravel-sitemap 8.1. Αν η εφαρμογή σας επιλύει παλαιότερη έκδοση (όπως συμβαίνει σε κάποιους συνδυασμούς PHP/Laravel), οι χάρτες δημιουργούνται ως απλό XML χωρίς μορφοποίηση — τίποτα δεν χαλάει. Εκτελέστε composer update spatie/laravel-sitemap για τη μορφοποιημένη προβολή.
// config/seo.php
'sitemap' => [
'stylesheet' => ['enabled' => false],
],Σημειώσεις επικύρωσης
Η αποδιδόμενη σελίδα επισημαίνει δύο πράγματα που μπορεί να ελέγξει χωρίς να φύγει από τον browser:
- URL χωρίς
lastmod— το κενό επισημαίνεται, η τιμή δεν επινοείται ποτέ. Το Google υποβαθμίζει την αξιοπιστία ενός χάρτη που παραπλανά ως προς την ενημερότητα, οπότε το φύλλο στυλ επισημαίνει το κενό αντί να το συμπληρώνει. - Μη απόλυτες URL — ένα
<loc>που δεν είναι απόλυτη URLhttp(s).
Φιλοξενία του φύλλου στυλ από εσάς
Από προεπιλογή, το πακέτο εξυπηρετεί το φύλλο στυλ από τη δική του διαδρομή /sitemap.xsl και παραπέμπει εκεί κάθε χάρτη. Οι browsers εφαρμόζουν XSLT μόνο όταν έχει ίδιο origin με τον χάρτη, οπότε αν οι χάρτες σας βρίσκονται σε άλλο origin (π.χ. CDN), δημοσιεύστε το αρχείο και κατευθύνετε τις ρυθμίσεις στο αντίγραφό σας:
php artisan vendor:publish --tag=seo-assets// config/seo.php
'sitemap' => [
'stylesheet' => [
'url' => 'https://cdn.example.com/vendor/seo/sitemap.xsl',
],
],Ασφάλεια εκ κατασκευής
Κάθε τιμή που αποδίδει το φύλλο στυλ — μαζί με τις URL — περνά από διαφυγή εξόδου XSLT και ένα <loc> γίνεται σύνδεσμος μόνο όταν είναι URL http(s), οπότε κακόβουλο περιεχόμενο URL δεν μπορεί να εισαγάγει markup ή σύνδεσμο javascript: στη σελίδα. Αν προσαρμόσετε το δημοσιευμένο .xsl, διατηρήστε αυτή την προστασία: μην προσθέσετε disable-output-escaping.
Τι περιλαμβάνεται
Οι πηγές μοντέλων περιλαμβάνουν εγγραφές που επιλύονται ως ευρετηριάσιμες· ένα μοντέλο του οποίου τα robots επιλύονται σε noindex μένει εκτός χάρτη. Οι URL προέρχονται από το getUrlForSEO() — την ίδια μέθοδο που τροφοδοτεί τις κανονικές URL, οπότε ο χάρτης και η κανονική URL δεν διαφωνούν ποτέ.
Επεκτάσεις εικόνων και hreflang
Δύο προαιρετικές επεκτάσεις εμπλουτίζουν κάθε URL μοντέλου με τα δεδομένα που το πακέτο ήδη επιλύει για αυτή την εγγραφή. Και οι δύο είναι ανενεργές από προεπιλογή — ενεργοποιήστε όποιες θέλετε στο config/seo.php:
'sitemap' => [
'images' => true, // <image:image> per URL
'alternates' => true, // <xhtml:link rel="alternate"> per URL
],Εφαρμόζονται σε μοντέλα που χρησιμοποιούν το trait HasSEO (οι τιμές προέρχονται από το πλήρως επιλυμένο seoData() του μοντέλου):
- Το
imagesπροσθέτει εγγραφή χάρτη εικόνων Google που δημιουργείται από την επιλυμένη εικόνα OG/περιεχομένου — την ίδια τιμή που αποδίδεται ωςog:image, οπότε ο χάρτης δεν διαφωνεί ποτέ με τη σελίδα. Όταν μια εγγραφή δεν έχει δική της εικόνα, αυτή είναι ηdefault_og_imageολόκληρου του ιστοτόπου, οπότε ενεργοποιήστε το μόνο αν μια εικόνα ανά URL έχει νόημα για το περιεχόμενό σας. - Το
alternatesπροσθέτει εγγραφές<xhtml:link rel="alternate" hreflang="…">από τοgetSEOAlternates()του μοντέλου — τους ίδιους συνδέσμους hreflang που αποδίδονται στο<head>της σελίδας. Επιστρέφετε απόλυτες URL:
public function getSEOAlternates(): ?array
{
return [
['hreflang' => 'en', 'href' => route('posts.show', [$this, 'locale' => 'en'])],
['hreflang' => 'fr', 'href' => route('posts.show', [$this, 'locale' => 'fr'])],
['hreflang' => 'x-default', 'href' => route('posts.show', $this)],
];
}Το hreflang πρέπει να είναι αμοιβαίο και να περιλαμβάνει την ίδια τη σελίδα
Το Google λαμβάνει υπόψη μια επισήμανση μόνο όταν κάθε γλωσσική έκδοση απαριθμεί τον εαυτό της και όλες τις άλλες και οι αναφορές είναι αμοιβαίες (κάθε σελίδα παραπέμπει πίσω). Επομένως, το getSEOAlternates() πρέπει να επιστρέφει το πλήρες σύνολο και κάθε τοπικοποιημένη παραλλαγή πρέπει να επιστρέφει το ίδιο πλήρες σύνολο. Χρησιμοποιήστε έγκυρους κωδικούς language[-Script][-REGION] ή x-default και απόλυτες URL http(s). Εγγραφές χωρίς μη κενό hreflang ή href παραλείπονται.
Η λίστα περνά από τις πολιτικές seo.hreflang πριν γραφτεί — οι κωδικοί κανονικοποιούνται σε BCP 47 (it_IT → it-IT) και τα include_self / x_default μπορούν να προσθέσουν την αναφορά στην ίδια τη σελίδα και το x-default για εσάς — και ο χάρτης περιλαμβάνει πάντα την ίδια λίστα με το <head> της σελίδας. Ο δωρεάν έλεγχος αναφέρει hreflang_invalid_code, hreflang_duplicate_code και hreflang_missing_self· η αμοιβαιότητα απαιτεί ανίχνευση (Pro).
Κόστος σε μεγάλη κλίμακα
Από τον πυρήνα 3.20.1, η συμπερίληψη μοντέλου και οι επεκτάσεις εικόνων/hreflang επαναχρησιμοποιούν το ίδιο επιλυμένο seoData() κατά τη δημιουργία κάθε URL μοντέλου. Η επαναχρησιμοποίηση τελειώνει μετά την URL, ακόμη και σε αποτυχία· μεταγενέστερη δημιουργία ή άλλο locale επιλύει νέα δεδομένα. Στην 3.20.0, με ανενεργή την cache resolver (η προεπιλογή), η συμπερίληψη μαζί με τις επεκτάσεις μπορούσε να διατρέξει την αλυσίδα προτεραιότητας δύο φορές. Κάθε επίλυση μπορεί ακόμη να κάνει λειτουργίες cache/βάσης δεδομένων και οι προσαρμοσμένοι getters getSEO*() μπορούν να προσθέσουν queries. Χρησιμοποιήστε την προγραμματισμένη εντολή seo:sitemap αντί για web αίτημα. Μετρήστε την απόδοση κοντά στο όριο των 50.000 URL και αφήστε τις επεκτάσεις ανενεργές όταν αυτές οι εγγραφές είναι περιττές.
Έχετε ήδη δημοσιεύσει ρυθμίσεις;
Το config/seo.php συγχωνεύεται ρηχά, οπότε μια εφαρμογή που δημοσίευσε το αρχείο ρυθμίσεων πριν από αυτή την έκδοση δεν θα λάβει αυτόματα τα κλειδιά sitemap.images / sitemap.alternates — οι μεταβλητές περιβάλλοντος SEO_SITEMAP_IMAGES / SEO_SITEMAP_ALTERNATES από μόνες τους δεν θα τα ενεργοποιήσουν. Προσθέστε τα δύο κλειδιά στον δημοσιευμένο πίνακα sitemap (δείτε το μπλοκ παραπάνω) ή δημοσιεύστε ξανά τις ρυθμίσεις.
Πλήρης έλεγχος: χειροποίητες ετικέτες Spatie
Για οτιδήποτε δεν καλύπτουν τα επιλυμένα δεδομένα — λεζάντες εικόνων, εγγραφές βίντεο ή ειδήσεων, ή προσαρμοσμένα σύνολα hreflang — επιστρέψτε ένα πλήρως χειροποίητο Spatie\Sitemap\Tags\Url από καταχωρισμένη πηγή. Ο builder περνά τις ετικέτες Url αυτούσιες και δεν προσθέτει ποτέ δικές του επεκτάσεις, οπότε διατηρείτε τον πλήρη έλεγχο:
use Spatie\Sitemap\Tags\Url;
SEO::sitemaps()->register('videos', fn () => Video::query()
->get()
->map(fn (Video $video) => Url::create($video->url)
->addImage($video->thumbnail_url, caption: $video->title)
->addVideo(
thumbnailLoc: $video->thumbnail_url,
title: $video->title,
description: $video->description,
contentLoc: $video->file_url,
)
->addAlternate($video->frenchUrl, 'fr')
));Η ίδια δυνατότητα παράκαμψης διατίθεται ανά εγγραφή: ένα μοντέλο που υλοποιεί το Sitemapable και του οποίου το toSitemapTag() επιστρέφει Url αποδίδεται ακριβώς όπως επιστράφηκε.