How to generate a sitemap for a Laravel website

Laravel sitemap generator

Sitemaps are very important, search engines such as Google read the sitemap file to crawl your site more efficiently. Sitemaps tell which pages and files, you think are important in your website but how can we create a sitemap in a Laravel website.

It’s so easy to code your sitemap generator in Laravel without needing a package. We will create a route for the sitemap and a controller for preparing all the URLs and information we need for passing them to a view that will generate an XML file.

XML schema for the Sitemap protocol

Let’s see the XML schema for the Sitemap protocol.

<?xml version="1.0" encoding="UTF-8"?>

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">

   <url>

      <loc>http://www.example.com/</loc>

      <lastmod>2021-01-28</lastmod>

      <changefreq>weekly</changefreq>

      <priority>0.8</priority>

   </url>

</urlset> 
  • <url> The parent tag for each URL entry and it’s required.
  • <loc> The URL of the page. This URL must begin with http / https and it’s required.
  • <lastmod> The date of last modification of the file using YYYY-MM-DD format and it’s optional.
  • <changefreq> How frequently the page is likely to change, values are (always – hourly – daily – weekly – monthly – yearly – never) and it’s optional.
  • <priority> The priority of this URL relative to other URLs on your site, values range from 0.0 to 1.0 and it’s optional. But note that the position of your URLs in a search engine’s result pages will not be effected with the priority here.

Creating Laravel sitemap

Now, we understand the information we need to generate the sitemap, we need to create a sitemap controller.

php artisan make:controller SitmapController

let’s create the route in web.php on your Laravel application for the sitemap, the URL search engines need for your sitemap.

use App\Http\Controllers\SitmapController;


//
Route::get('/sitemap',[SitmapController::class, 'index'])->name('sitemap');
//

In SitmapController, we will add the index function, and inside it, we will get all the routes we need for the sitemap, In Laravel, we have basic routes that take no parameters such as (/contact, /about) we will right them manually or we can get them via app('router')->getRoutes() and we have routes that take a parameter such as (/posts/{slug}) that are mostly coming from databases so we will use an Eloquent model.

This is how should be our controller.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Post;
class SitmapController extends Controller
{
   public function index(){

    $routes = app('router')->getRoutes();
    $posts = Post::all();


//  return  $arrays=(array) $routes; /*uncomment to test $routes*/
    return response()->view('sitmap', [
        'routes' =>$routes,
        'posts' =>$posts,
    ])->header('Content-Type', 'text/xml');
   }
}

We won’t return a normal Laravel view, we will return an XML file so we used the response() and changed the header Content-Type to text/xml. here is what our sitmap.blade.php should look like.

<?php echo '<?xml version="1.0" encoding="UTF-8"?>'; ?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml">
    
    <url>
        <loc>https://example.com/</loc>
        <lastmod>2021-01-28</lastmod>
        <changefreq>monthly</changefreq>
        <priority>0.9</priority>
    </url>

    <url>
        <loc>https://example.com/contact</loc>
        <lastmod>2021-01-28</lastmod>
        <changefreq>monthly</changefreq>
        <priority>0.9</priority>
    </url>


    @foreach ($routes as $item)
    @if($item->action['prefix'] =="/html" ||  $item->action['prefix'] =="/css")
    <url>
        <loc>{{url('/'.$item->uri)}}</loc>
        <lastmod>2021-01-28</lastmod>
        <changefreq>yearly</changefreq>
        <priority>0.9</priority>
    </url>
    @endif
    @endforeach

    @foreach ($posts as $post)
    
    <url>
        <loc>{{url('posts/'.$post->slug)}}</loc>
        <lastmod>{{$post->updated_at}}</lastmod>
        <changefreq>yearly</changefreq>
        <priority>0.9</priority>
    </url>

    @endforeach
</urlset>

I give you some different ideas about how we generate our URLs and how we filter our routes, treat the view as a normal blade with @foreach and @if to reach the result you want. I hope I could help.