How to Generate Dynamic XML Sitemap for Website in PHP

by Vincy. Last modified on April 7th, 2021.

I get emails daily asking me to provide links to their website, most of them are spammy websites. I really laugh them out. Those spammy backlink guys should learn and keep up with technology.

Reason being, Google is far ahead in the game. How many backlinks you got is one outdated parameter. Google has got thousands of data points to validate and rank a website. Definitely it will sieve out the spammy links easily.

If you want to help Google and rank you up, there is one good thing to do. Create a valid sitemap for your website and submit it to Google. It will help its bots to index the website and map it the way you wish, eventually ranking you high in search results. SEO win!

Sitemap

A sitemap is a mapping file that has the specification about the site page URLs and more related details. It may also map other content URLs of the posts, products, images, videos, news and more in a conventional structure.

There are conventions for the XML schema for the sitemap protocol.

It lets the search engine crawlers parse the sitemap and provide valuable details. These details are useful to optimize the web pages, content and the relationship between them.

The search engine crawlers capture the recently updated pages among the others. It will help to gain reputations based on the change frequencies.

Let’s discuss generating sitemaps for a website and its importance more in the upcoming sections.

It has an example to create a dynamic XML sitemap in PHP with a database.

Generated Sitemap Xml

What is inside?

  1. Importance of sitemap
  2. Tools to create sitemaps
  3. About this example
  4. Database script
  5. Generate sitemap dynamically in PHP
  6. Sitemap service in PHP to construct XML
  7. Output sitemap XML data format

Importance of sitemap

The sitemap is one of the key tools to let the search engine crawl bots to get the site structure. It helps search engines to index the site URLs.

With a sitemap, it increases the possibility to grab URLs which may directly affect the site readership to grow higher.

The Google-like leading search engine recommends putting a sitemap for websites. It documents the convincing reasons to tell “why the sitemap is needed?”

  1. If the site has numerous page URLs.
  2. If it has a heavy volume of page archives.
  3. If it is newly launched and negligibly (~ nill) linked by external sites.
  4. It the site has a large number of rich media files.

Tools to create sitemaps

There are online or integrable tools to generate sitemaps for websites. Also, the sitemap generators are launched as a SaaS product and provide various scales of features for their subscribers.

The XML-Sitemaps Generator is a popular online tool to create sitemaps. It creates an optimal format to be posted to the search engines like Google, Bing and more.

The linked page shows another alternative online sitemap generator tool. It generates a dynamic Image- and a multilingual sitemap.

About this example

Generating a sitemap for a website in a PHP is the purpose of this example. It implements this service with a clean code structure.

It creates configurations, model, service and DAO for systematically creating a dynamic XML sitemap generator in PHP using MySQL database.

It uses no third-party libraries or tools on which the sitemap generation process does not depend.

This is the file structure of this sitemap generation example. It may show the cleanliness and simplicity of the way it is implemented.

Generate Sitemap Files

It has the page meta in the database and creates a model to retrieve the site meta.

The sitemap generation service uses the metadata to constructs the XML schema for the sitemap protocol.

A “Generate” button in the UI triggers sitemap generation and acknowledges the user.

It generates two XML. One is the sitemap index and the other is the actual sitemap to be crawled.

It puts the generated file in the specified target and it is the root directory in this example.

Database script

This SQL file contains the database script to set up the table structure to run this example.

It contains the CREATE statement and the data of the tbl_page table. It has the records of having the page meta title, description, slug and more.

The slug is used to prepare the page URL during the sitemap XML element genration.

sql/database.sql

-- phpMyAdmin SQL Dump
-- version 5.0.3
-- https://www.phpmyadmin.net/
--
-- Host: 127.0.0.1
-- Generation Time: Mar 31, 2021 at 07:12 AM
-- Server version: 10.4.14-MariaDB
-- PHP Version: 7.2.34

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
START TRANSACTION;
SET time_zone = "+00:00";


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;

--
-- Database: `blog_example`
--

-- --------------------------------------------------------

--
-- Table structure for table `tbl_page`
--

CREATE TABLE `tbl_page` (
  `id` int(11) NOT NULL,
  `page_title` varchar(255) NOT NULL,
  `description` varchar(255) NOT NULL,
  `slug` varchar(255) NOT NULL,
  `creat_at` datetime NOT NULL DEFAULT current_timestamp()
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

--
-- Dumping data for table `tbl_page`
--

INSERT INTO `tbl_page` (`id`, `page_title`, `description`, `slug`, `creat_at`) VALUES
(1, 'about-us', 'It contain some personal information.', 'about-us', '2021-03-31 10:34:35'),
(2, 'portfolio', 'It provides clients to view your work.', 'portfolio', '2021-03-31 10:34:35'),
(3, 'contact-us', 'It includes all the standard information.', 'contact-us', '2021-03-31 10:34:35'),
(4, 'our-services', 'Descriptions of the products and services.', 'our-services', '2021-03-31 10:34:35');

--
-- Indexes for dumped tables
--

--
-- Indexes for table `tbl_page`
--
ALTER TABLE `tbl_page`
  ADD PRIMARY KEY (`id`);

--
-- AUTO_INCREMENT for dumped tables
--

--
-- AUTO_INCREMENT for table `tbl_page`
--
ALTER TABLE `tbl_page`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=8;
COMMIT;

/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

Generate Sitemap Page Table

Generate sitemap dynamically in PHP

This section has the code for displaying a UI control to trigger the sitemap generation process in PHP.

Also, it has the PHP model class code that connects DB to get the page meta from the database.

Trigger Sitemap generation from UI

index.php (HTML Template)

<html>
<head>
<title>Generate Sitemap</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="./assets/css/style.css" rel="stylesheet" />
</head>
<body>
    <div class="container">
        <div class="row">
            <a href="?action=generate" class="btn-generate"
                title="Generate">Generate Sitemap</a>
        </div>
        <div class="row">
        <?php if(!empty($success)){?>
        <div class="success"><?php echo $success;?></div>
        <?php }else if(!empty($error)){?>
        <div class="error"><?php echo $error;?></div>
        <?php }?>
        </div>
    </div>
</body>
</html>

assets/css/style.css

.container {
    -webkit-font-smoothing: antialiased;
    font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
    font-size: .9em;
    color: #1e2a28;
    width: 550px;
    margin: 0 auto;
    padding: 0px 20px 20px 20px;
    margin-top: 50px;
}

.row {
    margin: 15px 0;
    display: flex;
}

.btn-generate:hover {
    background: #353434;
}

.btn-generate {
    padding: 10px;
    background: #4C4B4B;
    border-radius: 3px;
    text-decoration: none;
    border: 1px #353434 solid;
    color: #FFF;
}

.error {
    width: 100%;
    color: #D8000C;
    background-color: #f5d7d4;
    border: 1px solid #f2ccc7;
    opacity: 0.83;
    transition: opacity 0.6s;
    padding: 10px;
    border-radius: 3px;
}

.success {
    width: 100%;
    text-align: left;
    color: #007532;
    background-color: #c1f9d8;
    border: 1px solid #bce8ce;
    padding: 10px;
    border-radius: 3px;
}

Retrieve pages from database

This is the PHP code that will get executed on clicking the Generate link at the home page.

It calls the model class to retrieve the page data. The resultant array will be sent to the sitemap generation service.

This PHP endpoint prepares response text based on the sitemap generation process net result.

index.php (PHP code)

<?php
use Phppot\Service\AppSiteMapService;
use Phppot\Page;

require_once __DIR__ . "/Service/AppSiteMapService.php";
require_once __DIR__ . '/Model/Page.php';
if (! empty($_GET["action"]) && $_GET["action"] == "generate") {
    $pageModel = new Page();
    $result = $pageModel->getAllPage();
    $appSiteMapService = new AppSiteMapService();
    $siteMapResult = $appSiteMapService->generateSiteMap($result);
    if (!empty($siteMapResult)) {
        $success = "Sitemap has been generated.";
    } else {
        $error = "Problem in generating sitemap.";
    }
}
?>

This model class connects the application DataSource to grab the page meta. The getAllPage() function returns the array of row-data of the tbl_page table.

Model/Page.php

<?php
namespace Phppot;

class Page
{

    private $ds;

    function __construct()
    {
        require_once __DIR__ . '/../lib/DataSource.php';
        $this->ds = new DataSource();
    }

    function getAllPage()
    {
        $query = "SELECT slug FROM tbl_page";
        $result = $this->ds->select($query);
        $resultArray = array();
        foreach ($result as $pages) {
            foreach ($pages as $value) {
                $resultArray[] = $value;
            }
        }
        return $resultArray;
    }
}

Sitemap service in PHP to construct XML

This example contains a configuration file that defines the root domain URL with a constant. This is used while generating the sitemap <URL> item to prepare the page location element.

lib/Config.php

<?php
namespace Phppot;

class Config
{

    const SITE_DOMAIN = "http://localhost/";
}

The AppSiteMapService class instantiate the SiteMapService in its constructor. It invokes the functions to add sitemap item and to set sitemap index by using this instant created.

This service has the function to add home page URLs exclusively. And, it adds other <URL> into the <URLSET> by iterating the page data.

After that, it calls the service to generate the sitemap index. It’s another XML for indexing the generated sitemap files of a website.

Service/AppSiteMapService.php

<?php
namespace Phppot\Service;

use Phppot\Config;

/**
 * This SiteMapGeneration Class
 * To Call method From SiteMapService to Generate Xml for sitemap
 * and also sitemap index file.
 */
class AppSiteMapService
{

    private $siteMapService;

    private $domain;

    public function __construct()
    {
        require_once __DIR__ . '/../lib/Config.php';
        $this->domain = Config::SITE_DOMAIN;
        require_once __DIR__ . '/SiteMapService.php';
        $this->siteMapService = new SiteMapService($this->domain);
    }

    private function addHomePage()
    {
        // Home Page url
        $this->siteMapService->addItem("", "", "");
    }

    private function addSitePages($result)
    {
        if (! empty($result)) {
            foreach ($result as $k => $v) {
                $this->siteMapService->addItem($result[$k]);
            }
        }
    }

    public function generateSiteMap($result)
    {
        $this->addHomePage();
        $this->addSitePages($result);
        $siteMapResult = $this->siteMapService->createSitemapIndex($this->domain, 'Now');
        if (empty($siteMapResult)) {
            $result = "1";
        } else {
            $result = "0";
        }
        return $result;
    }
}

This service is the core of the sitemap generator. It uses XMLWriter class to build the dynamic XML sitemap in PHP.

The class properties hold the writer instance, sitemap filename, the max limit of the items per sitemap and more.

It defines the getters setters for root domain, filename, path and etc. The addItem() method is used to write each <URL> element with its children into the <URLSET>.

Each item may hold more details like, the pages’ change-frequency, priority and etc.

Service/SiteMapService.php

<?php
namespace Phppot\Service;

use XMLWriter;

/**
 * SiteMap
 *
 * This class used for generating Google Sitemap files
 * Cycle: Schema added for validation, time format changed to ISO
 *
 * @package SiteMap
 * @author Cycle
 * @copyright 2018 Cycle
 * @license Cycle License
 */
class SiteMapService
{

    /**
     *
     * @var XMLWriter
     */
    private $writer;

    private $domain;

    private $path;

    private $filename = 'sitemap';

    private $current_item = 0;

    private $current_sitemap = 0;

    const EXT = '.xml';

    const SCHEMA = 'http://www.sitemaps.org/schemas/sitemap/0.9';

    const DEFAULT_PRIORITY = 0.5;

    const ITEM_PER_SITEMAP = 50000;

    const SEPERATOR = '-';

    const INDEX_SUFFIX = 'index';

    /**
     *
     * @param string $domain
     */
    public function __construct($domain)
    {
        $this->setDomain($domain);
    }

    /**
     * Sets root path of the website, starting with http:// or https://
     *
     * @param string $domain
     */
    public function setDomain($domain)
    {
        $this->domain = $domain;
        return $this;
    }

    /**
     * Returns root path of the website
     *
     * @return string
     */
    private function getDomain()
    {
        return $this->domain;
    }

    /**
     * Returns XMLWriter object instance
     *
     * @return XMLWriter
     */
    private function getWriter()
    {
        return $this->writer;
    }

    /**
     * Assigns XMLWriter object instance
     *
     * @param XMLWriter $writer
     */
    private function setWriter(XMLWriter $writer)
    {
        $this->writer = $writer;
    }

    /**
     * Returns the path of sitemaps
     *
     * @return string
     */
    private function getPath()
    {
        return $this->path;
    }

    /**
     * Sets paths of sitemaps
     *
     * @param string $path
     * @return Sitemap
     */
    public function setPath($path)
    {
        $this->path = $path;
        return $this;
    }

    /**
     * Returns the filename of the sitemap file
     *
     * @return string
     */
    private function getFilename()
    {
        return $this->filename;
    }

    /**
     * Sets filename of sitemap file
     *
     * @param string $filename
     * @return Sitemap
     */
    public function setFilename($filename)
    {
        $this->filename = $filename;
        return $this;
    }

    /**
     * Returns current item count
     *
     * @return int
     */
    private function getCurrentItem()
    {
        return $this->current_item;
    }

    /**
     * Increases item counter
     */
    private function incCurrentItem()
    {
        $this->current_item = $this->current_item + 1;
    }

    /**
     * Returns current sitemap file count
     *
     * @return int
     */
    private function getCurrentSitemap()
    {
        return $this->current_sitemap;
    }

    /**
     * Increases sitemap file count
     */
    private function incCurrentSitemap()
    {
        $this->current_sitemap = $this->current_sitemap + 1;
    }

    /**
     * Prepares sitemap XML document
     */
    private function startSitemap()
    {
        $this->setWriter(new XMLWriter());
        if ($this->getCurrentSitemap()) {
            $this->getWriter()->openURI($this->getPath() . $this->getFilename() . self::SEPERATOR . $this->getCurrentSitemap() . self::EXT);
        } else {
            $this->getWriter()->openURI($this->getPath() . $this->getFilename() . self::EXT);
        }
        $this->getWriter()->startDocument('1.0', 'UTF-8');
        $this->getWriter()->setIndent(true);
        $this->getWriter()->startElement('urlset');
        $this->getWriter()->writeAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance");
        $this->getWriter()->writeAttribute('xsi:schemaLocation', "http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd");
        $this->getWriter()->writeAttribute('xmlns', self::SCHEMA);
    }

    /**
     * Adds an item to the sitemap
     *
     * @param string $loc
     *            URL of the page. This value must be less than 2,048 characters.
     * @param string $priority
     *            The priority of this URL relative to other URLs on your SiteMapService. Valid values range from 0.0 to 1.0.
     * @param string $changefreq
     *            How frequently the page is likely to change. Valid values are always, hourly, daily, weekly, monthly, yearly and never.
     * @param string|int $lastmod
     *            The date of last modification of URL. Unix timestamp or any English textual DateTime description.
     * @return Sitemap
     */
    public function addItem($loc, $priority = self::DEFAULT_PRIORITY, $changefreq = NULL, $lastmod = NULL)
    {
        if (($this->getCurrentItem() % self::ITEM_PER_SITEMAP) == 0) {
            if ($this->getWriter() instanceof XMLWriter) {
                $this->endSitemap();
            }
            $this->startSitemap();
            $this->incCurrentSitemap();
        }
        $this->incCurrentItem();
        $this->getWriter()->startElement('url');
        if ($loc == "http://localhost/") {
            $this->getWriter()->writeElement('loc', $loc);
        } else {
            $this->getWriter()->writeElement('loc', $this->getDomain() . $loc);
        }
        if ($lastmod)
            $this->getWriter()->writeElement('lastmod', $this->getLastModifiedDate($lastmod));
        if ($changefreq)
            $this->getWriter()->writeElement('changefreq', $changefreq);
        $this->getWriter()->endElement();
        return $this;
    }

    /**
     * Prepares given a date for sitemap
     *
     * @param string $date
     *            Unix timestamp or any English textual datetime description
     * @return ISO8601 format.
     */
    private function getLastModifiedDate($date)
    {
        if (ctype_digit($date)) {
            return date('c', $date);
        } else {
            $date = strtotime($date);
            return date('c', $date);
        }
    }

    /**
     * Finalizes tags of sitemap XML document.
     */
    private function endSitemap()
    {
        if (! $this->getWriter()) {
            $this->startSitemap();
        }
        $this->getWriter()->endElement();
        $this->getWriter()->endDocument();
    }

    /**
     * Writes Google sitemap index for generated sitemap files
     *
     * @param string $loc
     *            Accessible URL path of sitemaps
     * @param string|int $lastmod
     *            The date of last modification of sitemap. Unix timestamp or any English textual datetime description.
     */
    public function createSitemapIndex($loc, $lastmod = 'Today')
    {
        $this->endSitemap();
        $indexwriter = new XMLWriter();
        $indexwriter->openURI($this->getPath() . $this->getFilename() . self::SEPERATOR . self::INDEX_SUFFIX . self::EXT);
        $indexwriter->startDocument('1.0', 'UTF-8');
        $indexwriter->setIndent(true);
        $indexwriter->startElement('sitemapindex');
        $indexwriter->writeAttribute('xmlns', self::SCHEMA);
        for ($index = 0; $index < $this->getCurrentSitemap(); $index ++) {
            $indexwriter->startElement('sitemap');
            $indexwriter->writeElement('loc', $loc . $this->getFilename() . ($index ? self::SEPERATOR . $index : '') . self::EXT);
            $indexwriter->writeElement('lastmod', $this->getLastModifiedDate($lastmod));
            $indexwriter->endElement();
        }
        $indexwriter->endElement();
        $indexwriter->endDocument();
    }
}

Output sitemap XML data format

This screenshot shows the sitemap index file. It has the reference for all the sitemap created for a  website.

It displays the sitemap file path and the modified date of each <sitemap> element.

Generated Sitemap Index Xml

Conclusion

Thus we have seen how to create a dynamic XML sitemap in PHP. It has been discussed with a suitable example to make everything clear about this process.

We have discussed the importance of the sitemap for a website. Also, we see some example tools available online to generate and manage sitemap.

This example has created the sitemap index for the number of sitemaps generated. I hope, this is helpful to get an idea about creating a custom sitemap generated by our own.

Download

Leave a Reply

Your email address will not be published. Required fields are marked *

↑ Back to Top