SEO: Implement a sitemap generator for your Laravel site and optimize your SEO

No image preview
Tutorials /
PHP Programming/

#laravel

#web

#dev

#seo


 

Generate a sitemap for dynamic URLs with a scheduled generator and keep your sitemap updated and site optimized for search engines.

 

 

 

Note!  roumen/sitemap is compatible ONLY with Laravel 8 or lower, use spatie/laravel-sitemap for Laravel 9 or higher. The setup is identical for both packages, I have labeled code necessary for each one.

 


 

 

The sitemap will help your site to set a higher position on search engines, for instance, once you submit your sitemap to the Google search console your pages will have higher priority on Google to be served to clients.
 

 

 

Packets, packets

 

 

We will use a Laravel generator called roumen/sitemap OR spatie/laravel-sitemap, we need to install this packet to our project and we can do that with the composer.

Add this line to the console and execute it.
 

 

 

 

Laravel 8 or lower:

composer require roumen/sitemap

 

 

Laravel 9^:

composer require spatie/laravel-sitemap

 

 

 

Configuration 

 

 

After installation is done we will create a Controller named SitemapBuilder and add our new packet to the project config/app.php providers array.
Just add this line at the bottom of the providers and save the file. Not required for the spatie/laravel-sitemap.
 

 

 

//...other providers...,
Roumen\Sitemap\SitemapServiceProvider::class,

 

 


Now publish the package with this line.

 

 


Laravel 8 or lower:

php artisan vendor:publish 

 

 

 

Create the model or controller for our builder class with the console command, we will create the controller for this example.

 

 

 

php artisan make:controller SitemapBuilder

 



Code and setup

 

 

Now go to the controller and create a function to catch all static and dynamic links. We have queried all posts and we will rewrite the file every week using automation, we could just update the file and fill the posts from the last post entered into a sitemap, but since our slugs are created from posts titles we will overwrite the file just to keep everything updated. 


It is a good idea to add a URL field to the post table so the URL never changes and gets updates that are not explicit, it will prevent shared links to become invalid once we update the title. In our case, it does not matter since all our posts are queried by post (id) and will provide the correct response no matter what we write after "id", for instance, number “11/”. eg. https://techtoapes.com/post/11/some_optional _text.


If you do not want to include all routes then just add them manually and do not use a loop for routes.

 

 


 Laravel 8 or lower:

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

use App\Models\Post;

class SitemapBuilder extends Controller
{
    public static function handle($token){
    
       	if (app()->runningInConsole() == false || $token != env('SITEMAP_TOKEN')) {
            return false;
        }
        $posts = Post::all();
        $routes = Route::getRoutes();
        $sitemap = App::make("sitemap");
            
        foreach ($routes as $route) {
          $sitemap->add($route->uri, '1.0', 'weekly');
        }
        foreach ($posts as $post) {
            $url = urlencode($post->title);
            $sitemap->add($url, $post->updated_at, '1.0', 'weekly');
        }
        $sitemap->store('xml', 'sitemap.xml', public_path());
            
        return true;
    }
}

 

 

 

Laravel 9^:

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Models\Post;
use Spatie\Sitemap\SitemapGenerator;
use Spatie\Sitemap\Sitemap;


class SitemapBuilder extends Controller
{
    public static function handle($token){  
        if (app()->runningInConsole() == false || $token != env('SITEMAP_TOKEN')) {
            return false;
        }

        $posts = Post::all();
        $routes = Route::getRoutes();
        $sitemap = Sitemap::create();

        foreach ($routes as $route) {
            $sitemap->add($route->uri);
        }

        foreach ($posts as $post) {
            $url = urlencode($post->title);
            $sitemap->add(("/post/{$post->id}/{$url}"), $post->updated_at, '1.0', 'weekly');
        }
        $sitemap->writeToFile(public_path('sitemap.xml'));
        return true;
    }
}

 

 

 

Now, we could add an authorization check for who can make the sitemap by a user authorization but since we will set this builder to execute every week as the automated method that approach would not be too practical so we use the $token we have created in our .env file just for this.

Add to the .env file this line.

 

 

 

SITEMAP_TOKEN="your_token_9SDA18329DA34DASDSDAVA23323FDS"

 

 

 

Great, we have finished the builder, only thing left is to automate this so we never ever need to think about it while it does its task for us.

 

 

 

Automate builder 

 

 

Open the App/Console/kernel.php file and create a schedule for the sitemap builder to execute every week.
 

 

 

 

    $schedule->call(function () {
    	SitemapBuilder::handle(env('SITEMAP_TOKEN'));         
    })->weekly();

 

 

 


 Alternatively, we could use a custom Cronjob but this seems practical enough and easy to customize and works on the same principle. 
 

 

 

Console Commands

 

 

For the first time, we can use the console to call our builder, we will create a Laravel command for it.

 

 

 

php artisan make:command SitemapBuilderCommand

 

 

 

Now in App/Console/commands/ edit this file.

 

 

 

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use App\Http\Controllers\SitemapBuilder;

class SitemapBuildCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'sitemap-build';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Build sitemap of the site and store it in the public folder as .xml file.';

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        SitemapBuilder::handle(env('SITEMAP_TOKEN'));
        return Command::SUCCESS;
    }
}

 

 

 

Execute this command in the console for the first time, later it will run on schedule without the need for human action. We can check the content of our file sitemap.xml stored in the public/ directory. 
 

 

 

php artisan sitemap-build

 

 

 

Schedule test

 


To check that schedule automation is working you can run the following command or change weekly() to everyMinute() and wait.

Should list at least one cronjob.

 

 

php artisan schedule:list

 

 

 

This will open the schedule console interface, write the function listed to the console, it probably will be named Callback, and then press ENTER.

 

 

 

php artisan schedule:test

 

 

Callback

 

 

 

Check your sitemap.xml file. It should be all there.

 

 

Stay online. 

 

 

[root@techtoapes]$ whoami
[root@techtoapes]$ Author Luka

Login to comment.

Admin Luka #1
“ The biggest battle is the war against ignorance. ” — Mustafa Kemal Atatürk