How to Automatically Generate an XML Sitemap in Laravel
Tags: laravel, sitemap, seo, xml
Published: 2022-12-11 09:38:07

**December 11, 2022・Originally published at [laraveltuts.com](https://laraveltuts.com/how-to-automatically-generate-an-xml-sitemap-in-laravel/)・8 min read**

How often should I update my sitemap? What should I include in it? Should I create a new sitemap every time. I add or remove a page from my site?

The sitemap is a file that contains links to all pages on your site. This helps search engines crawl your site better and index your pages faster.

Sitemaps are essential for SEO (search engine optimization). They allow search engines to crawl your entire site and index its contents.

We are going to create a XML Sitemap for our posts using a **spatie/laravel-sitemap** package.

Follow the below Step-by-Step Guide on how to automatically generate an XML Sitemap in Laravel Application.

## How to Automatically Generate an XML Sitemap in Laravel

- Step 1: Install Laravel Application
- Step 2: Create Database and Configure
- Step 3: Installing spatie/laravel-sitemap Package
- Step 4: Creating Post Model, Migration and Controller
- Step 5: Create Dummy Records for Post
- Step 6: Create Sitemap Command
- Step 7: Scheduled Command in Console Kernel
- Step 8: Testing

### Step 1: Install Laravel Application
Firstly, we will install a laravel application. To install a laravel application run the following code in terminal as show in figure.

```
composer create-project --prefer-dist laravel/laravel laravel-sitemap

cd laravel-sitemap
```

![Install Laravel Application](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/07qxrjnwoqicx7is3f13.png)

### Step 2: Create Database and Configure
Let create database in phpmyadmin for our project for adding posts and then we will create those posts sitemap later.

We are creating a database with name **“laravel-sitemap”** as you can see in below image.

![Create Database](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b1zg9fz2w5mtfnt72wa1.png)

After creating database we are going to configure it to our laravel application. To configure the database in laravel. First open .env from our project root directory and enter the database details as show below.

```
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel-sitemap
DB_USERNAME=root
DB_PASSWORD=
```

![Database Configure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vg2bkwr3128wlfzsicjt.png)

Now run the migration to create a default tables like users table etc.

```
php artisan migrate
```

![Database Migration](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ub6vvgnm8hnmev0s35sp.png)

### Step 3: Installing spatie/laravel-sitemap Package
We are using spatie/laravel-sitemap package to generate our posts sitemap. We are going to install the package via composer using a following command in terminal.

```
composer require spatie/laravel-sitemap
```

![Installing spatie/laravel-sitemap Package](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/94w9ufdwxotiymo9tru1.png)

The package will automatically register itself.

**Configuration Package**

You can override the default options for the crawler. First publish the configuration:

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

This will copy the default config to **config/sitemap.php** where you can edit it.

```
use GuzzleHttp\RequestOptions;
use Spatie\Sitemap\Crawler\Profile;
return [
    /*
     * These options will be passed to GuzzleHttp\Client when it is created.
     * For in-depth information on all options see the Guzzle docs:
     *
     * http://docs.guzzlephp.org/en/stable/request-options.html
     */
    'guzzle_options' => [
        /*
         * Whether or not cookies are used in a request.
         */
        RequestOptions::COOKIES => true,
        /*
         * The number of seconds to wait while trying to connect to a server.
         * Use 0 to wait indefinitely.
         */
        RequestOptions::CONNECT_TIMEOUT => 10,
        /*
         * The timeout of the request in seconds. Use 0 to wait indefinitely.
         */
        RequestOptions::TIMEOUT => 10,
        /*
         * Describes the redirect behavior of a request.
         */
        RequestOptions::ALLOW_REDIRECTS => false,
    ],
    
    /*
     * The sitemap generator can execute JavaScript on each page so it will
     * discover links that are generated by your JS scripts. This feature
     * is powered by headless Chrome.
     */
    'execute_javascript' => false,
    
    /*
     * The package will make an educated guess as to where Google Chrome is installed. 
     * You can also manually pass it's location here.
     */
    'chrome_binary_path' => '',
    /*
     * The sitemap generator uses a CrawlProfile implementation to determine
     * which urls should be crawled for the sitemap.
     */
    'crawl_profile' => Profile::class,
    
];
```

### Step 4: Creating Post Model, Migration and Controller
We are going to create posts XML sitemaps. So we are going to create post model, migration and controller for it.

By running the following command its will create all three model migration and model for post.

```
php artisan make:model Post -mc
```

**-mc** will create a migraion and controller.

![Creating Post Model, Migration and Controller](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aap65bfwnavsl860f6tm.png)

Now we are going to update it.

**app/Models/Post.php**

```
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
    use HasFactory;
    protected $fillable = [
        'title', 
        'slug', 
        'description'
    ];
}
```

![Update Post Model](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oaqu082m3w94atus5fsn.png)

**database/migrations/create_posts_table.php**

```
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->string('slug');
            $table->text('description'); 
            $table->timestamps();
        });
    }
    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('posts');
    }
};
```

![Update Post Migration](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/btlp847cgbv30dkoieu8.png)

We don’t need to update **PostController.php** file for this tutorial because we are going to add dummy records for posts using faker in our next step.

If you want to add, edit, update or to display posts you can using PostController.php. You can check out our article Laravel 9 Vue JS CRUD App using Vite Example. We had discuss the CRUD in deatils.

Run the migration to create our new post table.

```
php artisan migrate
```

### Step 5: Create Dummy Records for Post
Now we are going to add some dummy records to the post table so that we can generate a XML sitemap for posts.

You can skip this part if you already create a post.

So, now we are going to create factory for our post model using the following command.

```
php artisan make:factory PostFactory --model=Post
```

![Creating Post Factory](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ci22358qdns3yzj9d3ma.png)

Update the **database/factories/PostFactory.php** file.

```
<?php
namespace Database\Factories;
use App\Models\Post;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Post>
 */
class PostFactory extends Factory
{
    /**
     * The name of the factory's corresponding model.
     *
     * @var string
     */
    protected $model = Post::class;
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    public function definition()
    {
        return [
            'title' => $this->faker->sentence($nbWords = 6, $variableNbWords = true),
            'slug' => $this->faker->randomNumber($nbDigits = NULL, $strict = false),
            'description' => $this->faker->text($maxNbChars = 2000)
        ];
    }
}
```

![Update Post Factory](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jdo3h02rcshmg4x6cb3i.png)

Note for slug we are using some random numbers.

Now we are going to generate some random post using tinker.

```
php artisan tinker
Post::factory()->count(30)->create()
```

**_30_** is the total number of post we want to generate.

![Dummy Records Create for Post](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vlv3y210w2c47v7aflta.png)

Now you can Exit from tinker using exit command.

```
exit
```

### Step 6: Creating Sitemap Command
You can easily create an artisan command to create a sitemap and schedule it to run frequently. This will ensure that new pages and content types will be automatically picked up. To create a sitemap command run the following command.

```
php artisan make:command GenerateSitemap
```

![Create Sitemap Command](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7upl06oa42kn23v52yai.png)

Update the sitemap command with the following code.

**app/Console/Commands/GenerateSitemap.php**

```
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Spatie\Sitemap\Sitemap;
use Spatie\Sitemap\Tags\Url;
use App\Models\Post;
class GenerateSitemap extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'sitemap:generate';
    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Automatically Generate an XML Sitemap';
    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        $postsitmap = Sitemap::create();
        Post::get()->each(function (Post $post) use ($postsitmap) {
            $postsitmap->add(
                Url::create("/post/{$post->slug}")
                    ->setPriority(0.9)
                    ->setChangeFrequency(Url::CHANGE_FREQUENCY_MONTHLY)
            );
        });
        $postsitmap->writeToFile(public_path('sitemap.xml'));
    }
}
```

- sitemap:generate is our command to generate the sitemap.
- “setPriority” — set the post priority.
- “setChangeFrequency” — set the post change frequency with daily, monthly, yearly.

You can read other options at spatie/laravel-sitemap package.

![Update Sitemap Command](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w7tqhsisgv9ojkr9ugz3.png)

### Step 7: Scheduled Command in Console Kernel
Now we nee to register this command to kernel for automatically generate XML sitemap. It can be scheduled in the console kernel to be run daily.

**app/Console/Kernel.php**

```
// app/Console/Kernel.php
protected function schedule(Schedule $schedule)
{
    ...
    $schedule->command('sitemap:generate')->daily();
    ...
}
```

![Update Kernel File for Schedule Sitemap Automatically](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rbibs4gxb5gm2yhw4v1n.png)

### Step 8: Testing
We are all set, the sitemap is automatically set to be run daily. To set for now we are going to run the command to generate our sitemap manually by running the following command.

```
php artisan sitemap:generate
```

The above command will generate the sitemap.xml in public directory.

Run the following command to start the Artisan development server for laravel.

```
php artisan serve
```

And open the following link in any web browser to open the sitemap.

```
http://127.0.0.1:8000/sitemap.xml
```

![How to Automatically Generate an XML Sitemap in Laravel](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ix6o5ihgdn3u5jdbb9xs.png)

## Conclusion
This concludes our tutorial on How to Automatically Generate an XML Sitemap in Laravel. We hope you found it helpful. If you did, please share this article with your friends or family and leave us a comment to let us know what you think and stay tuned for more tutorials. If you like the tutorial please subscribe our [youtube](https://www.youtube.com/channel/UCwIbFoGoht3Dom9Q1NkOS3A) channel and follow us on social network [facebook ](https://www.facebook.com/laraveltutscom)and [instagram](https://www.instagram.com/laraveltuts/).