# Quickly create a Sitemap for your Laravel site

Hi guys,

Today I'm gonna share to you my snippet to generate a whole sitemap. Quick and reliable.

Creating a sitemap is easy and you don't have to install any dependencies (probably you will googling like "laravel sitemap").

Let's get started.

FYI I suppose you would know what is the "sitemap" and its benefits for SEO, so I won't explain it here.

## Sitemap Structure

```xml
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
    <url>
        <loc>http://localhost:3000</loc>
        <changefreq>always</changefreq>
        <priority>1</priority>
        <lastmod>2023-01-20T14:59:42.000000Z</lastmod>
    </url>
</urlset>
```

So, a normal view render of Laravel would get the job done easily, or if you prefer the OOP way, you can use `SimpleXML` of PHP.

## SimpleXML for Sitemap

This requires the `simplexml` extension from PHP.

First I will create an entity class to hold the information of the `url`

```php
class SitemapNode
{
    public const CHANGE_FREQUENCY_ALWAYS = 'always';
    public const CHANGE_FREQUENCY_DAILY = 'daily';

    public function __construct(
        public string $url,
        public string $changeFrequency,
        public float $priority = 1,
        public ?Carbon $lastModifiedDate = null
    ) {
    }

    public static function make(): SitemapNode
    {
        return new self(...func_get_args());
    }

    public function appendSitemap(SimpleXMLElement $element): self
    {
        $url = $element->addChild('url');

        $url->addChild('loc', $this->url);
        $url->addChild('changefreq', $this->changeFrequency);
        $url->addChild('priority', $this->priority);

        $this->lastModifiedDate
            && $url->addChild('lastmod', $this->lastModifiedDate->toISOString());

        return $this;
    }
}
```

FYA my application only needs `daily` or `always` option, feel free to add more for your use cases.

Then, I create a Collection like this (from my command, so I registered a cron job for every 12 hours, it will render the sitemap) and append all the URLs of my application, including:

* Static pages (home page, about us, contact us,...)
    
* Dynamic pages (with slug)
    

```php
$urls = collect([
    SitemapNode::make(
        $this->getWebUrl(), 
        SitemapNode::CHANGE_FREQUENCY_ALWAYS
    ),
    SitemapNode::make(
        $this->getWebUrl('about-us'), 
        SitemapNode::CHANGE_FREQUENCY_ALWAYS)
    ),
    // add more URLs here, eg dynamic pages,...
]);
```

Okay then let's render and store it:

```php
$xml = new SimpleXMLElement('<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" />');

$urls->each(fn (SitemapNode $node) => $node->appendSitemap($xml));

// parse to string
$xmlString = $xml->asXML();

// store to any places
file_put_contents(
    public_path('sitemap.xml'),
    $xmlString
);
```

A mix between OOP and Func-programming, it looks super clean, isn't it? 😆

## Blade

Easiest solution without any dependencies too. So you will need an array to hold the `urls` with the needful information: `loc`, `changefreq`, `priority` and `lastmod` , eg:

```php
$urls = [
    [
        'loc' => 'https://sethphat.dev', 
        'changefreq' => 'always',
        'priority' => 1,
        // lastmod can be null or unexists
        'lastmod' => Carbon::now(),
    ],
    // .... more
];
```

Then render it via blade:

```php
// sitemap.blade.php
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" />
    @foreach ($urls as $url)
        <url>
            <loc>{!! $url['loc'] !!}</loc>
            <changefreq>{{ $url['changefreq'] }}</changefreq>
            <priority>{{ $url['priority'] }}</priority>
            @if (isset($url['lastmod']))
                <lastmod>{{ $url['lastmod']->toISOString() }}</lastmod>
            @endif
        </url>
    @endforeach
</urlset>
```

Get the rendered string:

```php
use Illuminate\Support\Facades\View;

$renderedSitemap = View::make('sitemap', compact('urls'))->render();

// STORE TO DISK    
```

That's all :p

## Conclusion

Well, that's simply that, things don't have to be **much more complicated** and you don't need to **install** any **dependency**.

Fewer dependencies, happier/easier life & maintenance.

Not to mention, everything above is testable under unit testing too.

Cheers!
