How to Build a Sitemap in Laravel Using Spatie Sitemap

How to Build a Sitemap in Laravel Using Spatie Sitemap

A sitemap is a file that lists the pages and resources of your website, and helps search engines to crawl and index them more efficiently. A sitemap can also provide additional information about your website, such as the last modification date, the priority, and the change frequency of each page.

In this blog post, I will show you how to build a sitemap in Laravel using Spatie Sitemap, a package that simplifies the process of creating and generating sitemaps with ease. You will learn how to install the package, how to use it manually or automatically, and how to customize it according to your needs.

What is Spatie Sitemap?

Spatie Sitemap is a package that allows you to create and generate sitemaps with ease. It supports various types of sitemaps, such as XML, JSON, HTML, and Markdown. It also supports various types of resources, such as models, controllers, routes, views, files, images, videos, etc.

Spatie Sitemap has two methods of creating a sitemap: manual and automatic. The manual method gives you full control over what pages and resources you want to include in your sitemap. The automatic method lets Spatie Sitemap crawl your website based on internal links and generate a sitemap accordingly.

How to Install Spatie Sitemap?

To install Spatie Sitemap in your Laravel project, you need to use Composer as your dependency manager. Composer is a tool that allows you to download and manage packages for PHP projects. You can install Composer by following the instructions on its official website.

Once you have Composer installed on your system or server, you can install Spatie Sitemap by running the following command in your terminal:

composer require spatie/laravel-sitemap

This command will download the latest version of Spatie Sitemap from its GitHub repository and add it as a dependency in your composer.json file.

How to Use Spatie Sitemap Manually?

If you want to create a sitemap manually using Spatie Sitemap, you need to follow these steps:

Step 1: Add the Sitemap facade to your config/app.php file

The first step is to add the Sitemap facade to your config/app.php file. This will allow you to access the methods of Spatie Sitemap from anywhere in your code.

To do this, open your config/app.php file with any text editor or IDE of your choice. Then find the aliases array under the config key. Add an entry for Spatie\\Sitemap\\Sitemap under this array with an empty value:

'aliases' => [
    //...
    'Spatie\\Sitemap\\Sitemap' => '',
],

Save the file and close it.

Step 2: Implement the Spatie\\Sitemap\\Contracts\\Sitemapable interface in your models

The next step is to implement the Spatie\\Sitemap\\Contracts\\Sitemapable interface in your models that represent pages or resources that you want to include in your sitemap. This interface requires you to define two methods: toSitemapTag() and toXml(). These methods are responsible for returning an array or an XML string that represents each page or resource in terms of its URL path.

For example, if you have a model called Post, which represents blog posts on your website, you can implement this interface like this:

use Illuminate\Database\Eloquent\Model;
use Spatie\Sitemap\Contract\Sitemapable;

class Post extends Model implements Sitemapable
{
    public function __construct()
    {
        parent::__construct();
        $this->table('posts');
    }

    public function getRouteKeyName()
    {
        return 'slug';
    }

    public function getRouteAttribute($key)
    {
        return route('posts.show', $this->$key);
    }

    public function getRouteName($key)
    {
        return route('posts.show', $this->$key)->name;
    }

    public function getSlugAttribute($value)
    {
        return $value ?? '';
    }

    public function getPublishedAtAttribute($value)
    {
        return $value ?? null;
    }

    public function getUpdatedAtAttribute($value)
    {
        return $value ?? null;
    }

    public function getPublishedAt(): Carbon
    {
        return $this->published_at ?? null;
    }

    public function getUpdatedAt(): Carbon
    {
        return $this->updated_at ?? null;
    
     }

     public function scopePublished($query)
     {
         return $query->where('published_at', '>=', now());
     }
}

This code defines some properties and methods for the Post model.

// These methods implement the Sitemapable interface
    public function toSitemapTag(): array
    {
        return [
            'url' => $this->route,
            'lastmod' => $this->updated_at,
            'changefreq' => 'weekly',
            'priority' => 0.8,
        ];
    }

    public function toXml(): string
    {
        return <<
            {$this->route}
            {$this->updated_at->toAtomString()}
            weekly
            0.8
        
        XML;
    }
}

This code defines some properties and methods for the Post model that are relevant for the sitemap. The getRouteKeyName() method returns the slug attribute as the key for the route binding. The getRouteAttribute() method returns the URL path for each post based on the slug attribute. The getRouteName() method returns the name of the route for each post based on the slug attribute. The getSlugAttribute() method returns the slug attribute or an empty string if it is null. The getPublishedAtAttribute() and getUpdatedAtAttribute() methods return the published_at and updated_at attributes or null if they are null. The getPublishedAt() and getUpdatedAt() methods return the published_at and updated_at attributes as Carbon instances. The scopePublished() method adds a query scope to filter only the published posts.

The toSitemapTag() method returns an array that represents the sitemap tag for each post. It includes the URL, the last modification date, the change frequency, and the priority of each post. The toXml() method returns an XML string that represents the sitemap tag for each post. It uses a heredoc syntax to create a multiline string.

You can implement the Sitemapable interface in any other model that you want to include in your sitemap, such as Category, Tag, User, etc. Just make sure to define the appropriate methods and properties for each model.

Step 3: Create a sitemap using the Sitemap facade

The final step is to create a sitemap using the Sitemap facade. You can do this in any controller, middleware, or command that you want. You can also use the Sitemap facade in your views or blade templates.

To create a sitemap, you need to use the create() method of the Sitemap facade. This method returns an instance of the Spatie\\Sitemap\\Sitemap class, which has various methods to add pages and resources to the sitemap.

For example, you can add all the published posts to the sitemap using the add() method:

use Spatie\Sitemap\Sitemap;

$sitemap = Sitemap::create();

$posts = Post::published()->get();

foreach ($posts as $post) {
    $sitemap->add($post);
}

This code creates a new sitemap instance and loops through all the published posts. For each post, it calls the add() method and passes the post as an argument. The add() method accepts any object that implements the Sitemapable interface, and calls its toSitemapTag() method to get the sitemap tag array.

You can also add other types of pages and resources to the sitemap using the add() method. For example, you can add a static page, such as the home page, using the Spatie\\Sitemap\\Tags\\Url class:

use Spatie\Sitemap\Sitemap;
use Spatie\Sitemap\Tags\Url;

$sitemap = Sitemap::create();

$sitemap->add(Url::create('/')
    ->setLastModificationDate(now())
    ->setChangeFrequency('daily')
    ->setPriority(1.0)
);

This code creates a new URL instance and sets its properties using the fluent methods. Then it adds it to the sitemap using the add() method.

You can also add other types of resources, such as images, videos, files, etc. using the Spatie\\Sitemap\\Tags\\* classes. For example, you can add an image using the Spatie\\Sitemap\\Tags\\Image class:

use Spatie\Sitemap\Sitemap;
use Spatie\Sitemap\Tags\Image;

$sitemap = Sitemap::create();

$sitemap->add(Image::create('/images/logo.png')
    ->setCaption('Logo')
    ->setTitle('Logo')
    ->setGeoLocation('Nairobi, Kenya')
    ->setLicense('https://creativecommons.org/licenses/by/4.0/')
);

This code creates a new Image instance and sets its properties using the fluent methods. Then it adds it to the sitemap using the add() method.

You can add as many pages and resources as you want to the sitemap using the add() method. You can also chain multiple add() methods together for convenience.

Step 4: Generate and save the sitemap

After you have added all the pages and resources that you want to include in your sitemap, you need to generate and save the sitemap. You can do this using the writeToFile() method of the Sitemap class. This method accepts a file path as an argument and writes the sitemap to that file.

For example, you can generate and save the sitemap to the public/sitemap.xml file using this code:

$sitemap->writeToFile(public_path('sitemap.xml'));

This code writes the sitemap to the public/sitemap.xml file, which is accessible from the web. You can use any file path that you want, as long as it is writable by your web server.

Alternatively, you can generate and return the sitemap as a response using the render() method of the Sitemap class. This method returns a Symfony\\Component\\HttpFoundation\\Response instance, which you can return from your controller or middleware.

For example, you can generate and return the sitemap as a response using this code:

return $sitemap->render();

This code returns the sitemap as a response, which you can view in your browser or any other client.

How to Use Spatie Sitemap Automatically?

If you want to create a sitemap automatically using Spatie Sitemap, you need to follow these steps:

Step 1: Publish the configuration file

The first step is to publish the configuration file of Spatie Sitemap. This file contains various options that you can customize to suit your needs.

To publish the configuration file, you need to run the following command in your terminal:

php artisan vendor:publish --provider="Spatie\\Sitemap\\SitemapServiceProvider" --tag="config"

This command will copy the config/sitemap.php file from the vendor directory to your project directory. You can open this file with any text editor or IDE of your choice and modify it as you wish.

Step 2: Configure the crawler

The next step is to configure the crawler that Spatie Sitemap uses to crawl your website and generate the sitemap. The crawler is an instance of the Spatie\\Crawler\\Crawler class, which is a wrapper around the [Guzzle HTTP client].

You can configure the crawler using the crawler key in the config/sitemap.php file. This key accepts a closure that receives the crawler instance as an argument and allows you to set various options and callbacks for the crawler.

For example, you can configure the crawler to crawl only the pages that match a certain pattern using the setCrawlProfile() method:

'crawler' => function (Spatie\Crawler\Crawler $crawler) {
    $crawler->setCrawlProfile(new Spatie\Crawler\CrawlSubdomains(config('app.url')));
},

This code sets the crawl profile of the crawler to an instance of the Spatie\\Crawler\\CrawlSubdomains class, which accepts the base URL of your website as an argument and crawls only the pages that belong to the same domain or subdomain.

You can also configure the crawler to limit the number of concurrent requests using the setConcurrency() method:

'crawler' => function (Spatie\Crawler\Crawler $crawler) {
    $crawler->setConcurrency(10);
},

This code sets the concurrency of the crawler to 10, which means that the crawler will send at most 10 requests at the same time.

You can also configure the crawler to ignore certain pages or resources using the setShouldCrawl() method:

'crawler' => function (Spatie\Crawler\Crawler $crawler) {
    $crawler->setShouldCrawl(function (Spatie\Crawler\Url $url) {
        return $url->segment(1) !== 'admin';
    });
},

This code sets the should crawl callback of the crawler to a closure that receives the URL instance as an argument and returns a boolean value. The closure returns false if the first segment of the URL is admin, which means that the crawler will ignore any pages or resources under the admin directory.

You can also configure the crawler to modify the sitemap tag for each page or resource using the setSitemapTagModifier() method:

'crawler' => function (Spatie\Crawler\Crawler $crawler) {
    $crawler->setSitemapTagModifier(function (Spatie\Sitemap\Tags\Url $url) {
        if ($url->segment(1) === 'posts') {
            $url->setPriority(0.9);
        }
        return $url;
    });
},

This code sets the sitemap tag modifier callback of the crawler to a closure that receives the URL instance as an argument and returns a modified URL instance. The closure checks if the first segment of the URL is posts, and if so, it sets the priority of the URL to 0.9. This means that the crawler will give more importance to the blog posts in the sitemap.

You can also configure the crawler to add additional information to the sitemap tag for each page or resource using the addSitemapTagData() method:

'crawler' => function (Spatie\Crawler\Crawler $crawler) {
    $crawler->addSitemapTagData(function (Spatie\Crawler\Url $url) {
        return [
            'images' => [
                [
                    'url' => $url->path() . '/images/cover.jpg',
                    'title' => 'Cover image',
                    'caption' => 'Cover image',
                    'geo_location' => 'Nairobi, Kenya',
                    'license' => 'https://creativecommons.org/licenses/by/4.0/',
                ],
            ],
        ];
    });
},

This code sets the sitemap tag data callback of the crawler to a closure that receives the URL instance as an argument and returns an array of additional data. The closure returns an array that contains an images key, which is an array of images that are associated with the URL. Each image is an array that contains the URL, the title, the caption, the geo location, and the license of the image. This means that the crawler will add these images to the sitemap tag for each URL.

You can configure the crawler to suit your needs using any of the methods and options that are available in the Spatie\\Crawler\\Crawler class. You can find more information about the crawler on [its GitHub repository].

Step 3: Run the sitemap generator command

The final step is to run the sitemap generator command that Spatie Sitemap provides. This command will use the crawler to crawl your website and generate the sitemap according to your configuration.

To run the sitemap generator command, you need to use the artisan command-line tool that Laravel provides. You can run the artisan command from your terminal or from your web browser.

The sitemap generator command has the following syntax:

php artisan sitemap:generate {url} {--config=} {--output=}

The command accepts the following arguments and options:

  • url: The base URL of your website that you want to crawl and generate the sitemap for. This argument is required.
  • --config: The name of the configuration file that you want to use for the sitemap generation. This option is optional. If you omit this option, the command will use the default config/sitemap.php file.
  • --output: The file path where you want to save the generated sitemap. This option is optional. If you omit this option, the command will save the sitemap to the public/sitemap.xml file.

For example, you can run the sitemap generator command for your website using this command:

php artisan sitemap:generate https://example.com

This command will crawl your website starting from the https://example.com URL and generate the sitemap using the default configuration file. It will save the sitemap to the public/sitemap.xml file.

You can also run the sitemap generator command using a custom configuration file and output file using this command:

php artisan sitemap:generate https://example.com --config=config/custom.php --output=storage/sitemap.xml

This command will crawl your website starting from the https://example.com URL and generate the sitemap using the config/custom.php configuration file. It will save the sitemap to the storage/sitemap.xml file.

You can run the sitemap generator command as often as you want to keep your sitemap updated. You can also schedule the command to run automatically using the Laravel scheduler. You can find more information about the Laravel scheduler on [its official documentation].

How to Customize Spatie Sitemap?

Spatie Sitemap is highly customizable and flexible. You can customize it in various ways to suit your needs and preferences.

Some of the ways that you can customize Spatie Sitemap are:

  • You can use different types of sitemaps, such as XML, JSON, HTML, and Markdown. You can specify the type of the sitemap using the type key in the config/sitemap.php file. You can also create your own custom sitemap types by implementing the Spatie\\Sitemap\\Contracts\\Sitemap interface and registering them using the Spatie\\Sitemap\\Sitemap::registerType() method.
  • You can use different types of sitemap tags, such as URL, Image, Video, News, etc. You can specify the type of the sitemap tag using the type key in the config/sitemap.php file. You can also create your own custom sitemap tags by implementing the Spatie\\Sitemap\\Contracts\\Sitemapable interface and registering them using the Spatie\\Sitemap\\Sitemap::registerTag() method.
  • You can use different types of sitemap writers, such as XML, JSON, HTML, and Markdown. You can specify the type of the sitemap writer using the type key in the config/sitemap.php file. You can also create your own custom sitemap writers by implementing the Spatie\\Sitemap\\Contracts\\Writer interface and registering them using the Spatie\\Sitemap\\Sitemap::registerWriter() method.
  • You can use different types of sitemap renderers, such as XML, JSON, HTML, and Markdown. You can specify the type of the sitemap renderer using the type key in the config/sitemap.php file. You can also create your own custom sitemap renderers by implementing the Spatie\\Sitemap\\Contracts\\Renderer interface and registering them using the Spatie\\Sitemap\\Sitemap::registerRenderer() method.

You can find more information about how to customize Spatie Sitemap on [its GitHub repository].

Conclusion

In this blog post, I have shown you how to build a sitemap in Laravel using Spatie Sitemap, a package that simplifies the process of creating and generating sitemaps with ease. You have learned how to install the package, how to use it manually or automatically, and how to customize it according to your needs.

I hope you have found this blog post useful and informative. If you have any questions or feedback, please feel free to leave a comment below. Thank you for reading and happy coding!