Generate Sitemap in Symfony in 2 simple steps

What is a Sitemap?

A Sitemap is a XML file that contains a list of URLs on your website that help the Search Engines discover and crawl your website more effectively. Generating a Sitemap in Symfony is one of the trivial tasks one might encounter. There are a few bundles that might help you, although the process & configuration could be tricky, especially for beginners.
Sitemap in symfony
This tutorial aims at generating a sitemap in symfony using nothing but a simple controller action and moreover it is compatible with all major Symfony Versions (3.x+, 4.x+)

XML SiteMap Format:

<urlset> Container element/tag that defines the namespace and that encompasses all urls .
<url> URL container element that encompasses each individual <loc> tag.
<loc> tag is the only mandatory and contains the actual URL.
<lastmod>tag is optional. Includes the date when the content at the given URL was last modified.
<changefreq> Optional. Includes the frequency at which the content at the given URL changes.
– <priority> tag is optional. It is a range between 0.1 – 1.0 indicating the priority of the given URL.
(*Ref)

1. Sitemap in Symfony – Create the Controller:

Create a controller class, for instance SitemapController.php that contains a function showAction(). It will be responsible for generating the sitemap. We will only generate sitemap in XML format since it is the most widely used format, however, you can have it generated in JSON/HTML by changing a few parameters.

// AppBundle/SitemapController.php

namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class SitemapController extends Controller
{
    /**
     * @Route("/sitemap/sitemap.xml", name="sitemap", defaults={"_format"="xml"})
     */
    public function showAction(Request $request) {
        $em = $this->getDoctrine()->getManager();
        $urls = array();
        $hostname = $request->getSchemeAndHttpHost();

        // add static urls
        $urls[] = array('loc' => $this->generateUrl('home'));
        $urls[] = array('loc' => $this->generateUrl('contact_us'));
        $urls[] = array('loc' => $this->generateUrl('privacy_policy'));
        
        // add static urls with optional tags
        $urls[] = array('loc' => $this->generateUrl('fos_user_security_login'), 'changefreq' => 'monthly', 'priority' => '1.0');
        $urls[] = array('loc' => $this->generateUrl('cookie_policy'), 'lastmod' => '2018-01-01');
        
        // add dynamic urls, like blog posts from your DB
        foreach ($em->getRepository('BlogBundle:post')->findAll() as $post) {
            $urls[] = array(
                'loc' => $this->generateUrl('blog_single_post', array('post_slug' => $post->getPostSlug()))
            );
        }

        // add image urls
        $products = $em->getRepository('AppBundle:products')->findAll();
        foreach ($products as $item) {
            $images = array(
                'loc' => $item->getImagePath(), // URL to image
                'title' => $item->getTitle()    // Optional, text describing the image
            );

            $urls[] = array(
                'loc' => $this->generateUrl('single_product', array('slug' => $item->getProductSlug())),
                'image' => $images              // set the images for this product url
            );
        }
      

        // return response in XML format
        $response = new Response(
            $this->renderView('sitemap/sitemap.html.twig', array( 'urls' => $urls,
                'hostname' => $hostname)),
            200
        );
        $response->headers->set('Content-Type', 'text/xml');

        return $response;

    }

}

2. Sitemap in Symfony – Create the View

We create a twig template to handle the View. We set the correct XML namespaces and the correct XML structure required to conform to the rules of sitemaps. Then, we loop over each url in the urls[] Array and print the necessary tags completing the XML tree.

<?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" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">

    {% for url in urls %}
        <url>{# check if hostname is not alreay in url#}
            <loc>{%if url.loc|replace({hostname:''}) == url.loc%}{{hostname}}{{url.loc}}{%else%}{{url.loc}}{%endif%}</loc>
            {% if url.lastmod is defined %}
                <lastmod>{{url.lastmod}}</lastmod>
            {% endif %}
            {% if url.changefreq is defined %}
                <changefreq>{{url.changefreq}}</changefreq>
            {% endif %}
            {% if url.priority is defined %}
                <priority>{{url.priority}}</priority>
            {% endif %}
            {% if url.image is defined and url.image is not empty %}
                <image:image>
                    <image:loc>{%if url.image.loc|replace({hostname:''}) == url.image.loc%}{{hostname}}{{url.image.loc}}{%else%}{{url.image.loc}}{%endif%}</image:loc>
                    <image:title>{{ url.image.title }}</image:title>
                </image:image>
            {% endif %}
        </url>
    {% endfor %}

</urlset>

If you followed everything correctly, the sitemap in symfony would now be accessible at http://yourhost/sitemap/sitemap.xml.

Finishing Up

You can Validate your generated sitemap at Validate XML Sitemap.
A live example of a sitemap generated by following this tutorial is found at MemoryHawk. Lastly, do not forget to update your robots.txt file with the path to your sitemap.

# robots.txt 
# www.robotstxt.org/

User-agent: *
Sitemap: https://yourhost/sitemap/sitemap.xml

Your robots.txt file tells crawlers and search engines about the location of your Sitemap.
Concluding, you can have your sitemap generated automatically each time in a simple and efficient manner. Nonetheless, if you insist on using Bundles to achieve the same, here are 2 bundles PrestaSitemapBundle or Dpn’s Sitemap Bundle that could get you going.
Hope this helps 🙂


References