Umbraco CMS
CloudHeartcoreDXPMarketplace
14.latest
14.latest
  • Umbraco CMS Documentation
  • Legacy Documentation
    • Our Umbraco
    • GitHub
  • Release Notes
  • Contribute
  • Sustainability Best Practices
  • Fundamentals
    • Get to know Umbraco
    • Setup
      • Requirements
      • Installation
        • Install using .NET CLI
        • Running Umbraco in Docker using Docker Compose
        • Install using Visual Studio
        • Local IIS With Umbraco
        • Install using Visual Studio Code
        • Installing Nightly Builds
        • Running Umbraco on Linux/macOS
        • Unattended Installs
      • Upgrade your project
        • Version Specific Upgrades
          • Upgrade from Umbraco 8 to the latest version
          • Migrate content to Umbraco 8
          • Minor upgrades for Umbraco 8
          • Upgrade to Umbraco 7
          • Minor upgrades for Umbraco 7
      • Server setup
        • Running Umbraco On Azure Web Apps
        • Hosting Umbraco in IIS
        • File And Folder Permissions
        • Runtime Modes
        • Umbraco in Load Balanced Environments
          • Load Balancing Azure Web Apps
          • Standalone File System
          • Advanced Techniques With Flexible Load Balancing
          • Logging With Load Balancing
    • Backoffice
      • Sections
      • Property Editors
        • Built-in Property Editors
          • Checkbox List
          • Collection
          • Color Picker
          • Content Picker
          • Document Picker
          • DateTime
          • Date
          • Decimal
          • Email Address
          • Eye Dropper Color Picker
          • File Upload
          • Image Cropper
          • Label
          • Markdown Editor
          • Media Picker
          • Member Group Picker
          • Member Picker
          • Multi Url Picker
          • Repeatable Textstrings
          • Numeric
          • Radiobutton List
          • Slider
          • Tags
          • Textarea
          • Textbox
          • Toggle
          • User Picker
          • Block Editors
            • Block Grid
            • Block List
          • Dropdown
          • Rich Text Editor
            • Rich Text Editor Configuration
            • Rich Text Editor Styles
            • Rich Text Editor Plugins
            • Blocks in Rich Text Editor
      • Login
      • Document Blueprints
      • Sidebar
      • Log Viewer
      • Language Variants
      • Settings Dashboards
    • Data
      • Defining Content
        • Default Document Types
        • Document Type Localization
      • Creating Media
        • Default Data/Media Types
      • Members
      • Data Types
        • Default Data Types
      • Scheduled Publishing
      • Using Tabs
      • Users
      • Relations
      • Dictionary Items
      • Content Version Cleanup
    • Design
      • Templates
        • Basic Razor Syntax
        • Razor Cheatsheet
      • Rendering Content
      • Rendering Media
      • Partial Views
      • Stylesheets And JavaScript
    • Code
      • Service APIs
      • Subscribing To Notifications
      • Creating Forms
      • Debugging
        • Logging
      • Source Control
  • Implementation
    • Learn how Umbraco works
    • Routing
      • Controller & Action Selection
      • Execute Request
      • Request Pipeline
    • Custom Routing
      • Adding a hub with SignalR and Umbraco
    • Controllers
    • Data Persistence (CRUD)
    • Composing
    • Integration Testing
    • Nullable Reference Types
    • Services and Helpers
      • Circular Dependencies
    • Unit Testing
  • Customizing
    • Extend and customize the editing experience
    • Project Bellissima
    • Setup Your Development Environment
      • Vite Package Setup
    • Foundation
      • Working with Data
        • Repositories
        • Context API
        • Store
        • States
      • Contexts
        • Property Dataset Context
      • Umbraco Element
        • Controllers
          • Write your own controller
      • Sorting
      • Routes
      • Icons
      • Backoffice Localization
      • Terminology
    • Extension Overview
      • Extension Registry
        • Extension Registration
        • Extension Manifest
      • Extension Types
        • Menu
        • Header Apps
        • Icons
        • Modals
          • Confirm Dialog
          • Custom Modals
          • Route Registration
        • Bundle
        • Kind
        • Backoffice Entry Point
        • Extension Conditions
        • Dashboards
        • Entity Actions
        • Entity Bulk Actions
        • Entity Create Option Action
        • Trees
        • Global Context
        • Section Sidebar
        • Section View
        • Sections
        • Workspace Context
        • Workspace Views
        • Workspace Actions
        • Localization
      • Extension Kind
      • Extension Conditions
      • Custom Extension types
    • Sections & Trees
    • Searchable Trees (ISearchableTree)
    • Property Editors
      • Property Editors Composition
        • Property Editor Schema
        • Property Editor UI
      • Property Value Converters
      • Property Actions
      • Integrate Property Editors
      • Tracking References
      • Content Picker Value Converter Example
      • Property Dataset
      • Integrate Validaction
    • Workspaces
    • Umbraco Package
    • UI Library
  • Extending
    • Build on Umbraco functionality
    • Health Check
      • Health Check Guides
        • Click-Jacking Protection
        • Content Content Security Policy (CSP)
        • Content/MIME Sniffing Protection
        • Cross-site scripting Protection (X-XSS-Protection header)
        • Debug Compilation Mode
        • Excessive Headers
        • Fixed Application Url
        • Folder & File Permissions
        • HTTPS Configuration
        • Notification Email Settings
        • SMTP
        • Strict-Transport-Security Header
    • Language Files & Localization
      • .NET Localization
    • Backoffice Search
    • Creating a Custom Database Table
    • Embedded Media Providers
    • Custom File Systems (IFileSystem)
      • Using Azure Blob Storage for Media and ImageSharp Cache
    • Configuring Azure Key Vault
    • Packages
      • Creating a Package
      • Language file for packages
      • Listing a Package on the Umbraco Marketplace
      • Good practice and defaults
      • Packages on Umbraco Cloud
      • Installing and Uninstalling Packages
      • Maintaining packages
      • Create accessible Umbraco packages
      • Example Package Repository
  • Reference
    • Dive into the code
    • Configuration
      • Basic Authentication Settings
      • Connection strings settings
      • Content Dashboard Settings
      • Content Settings
      • Data Types Settings
      • Debug settings
      • Examine settings
      • Exception filter settings
      • FileSystemProviders Configuration
      • Global Settings
      • Health checks
      • Hosting settings
      • Imaging settings
      • Indexing settings
      • Install Default Data Settings
      • Logging settings
      • Maximum Upload Size Settings
      • Models builder settings
      • NuCache Settings
      • Package Migration
      • Plugins settings
      • Request handler settings
      • Runtime settings
      • Security Settings
      • Serilog settings
      • Type finder settings
      • Unattended
      • Web routing
    • Templating
      • Models Builder
        • Introduction
        • Configuration
        • Builder Modes
        • Understand and Extend
        • Using Interfaces
        • Tips and Tricks
      • Working with MVC
        • Working with MVC Views in Umbraco
        • View/Razor Examples
        • Using MVC Partial Views in Umbraco
        • Using View Components in Umbraco
        • Querying & Traversal
        • Creating Forms
      • Macros
    • Querying & Models
      • IMemberManager
      • IPublishedContentQuery
      • ITagQuery
      • UDI Identifiers
      • UmbracoContext helper
      • UmbracoHelper
      • IPublishedContent
        • IPublishedContent Collections
        • IPublishedContent IsHelpers
        • IPublishedContent Property Access & Extension Methods
    • Routing & Controllers
      • Custom MVC controllers (Umbraco Route Hijacking)
      • Custom MVC Routes
      • Custom Middleware
      • URL Rewrites in Umbraco
      • Special Property Type aliases for routing
      • URL Redirect Management
      • Routing in Umbraco
        • FindPublishedContentAndTemplate()
        • IContentFinder
        • Inbound request pipeline
        • Outbound request pipeline
        • Published Content Request Preparation
      • Surface controllers
        • Surface controller actions
      • Umbraco API Controllers
        • Porting old Umbraco API Controllers
    • Content Delivery API
      • Custom property editors support
      • Extension API for querying
      • Media Delivery API
      • Protected content in the Delivery API
      • Output caching
      • Property expansion and limiting
      • Additional preview environments support
    • Webhooks
      • Expanding Webhook Events
    • API versioning and OpenAPI
    • Searching
      • Examine
        • Examine Management
        • Examine Manager
        • Custom indexing
        • PDF indexes and multisearchers
        • Quick-start
    • Using Notifications
      • Notification Handler
      • CacheRefresher Notifications Example
      • ContentService Notifications Example
      • Creating And Publishing Notifications
      • Determining if an entity is new
      • MediaService Notifications Example
      • MemberService Notifications Example
      • Sending Allowed Children Notification
      • Umbraco Application Lifetime Notifications
      • EditorModel Notifications
        • Customizing the "Links" box
      • Hot vs. cold restarts
    • Inversion of Control / Dependency injection
    • Management
      • Using Umbraco services
        • Consent Service
        • Media Service
        • Relation Service
        • Content Service
        • Content Type Service
        • Localization Service
        • User Service
    • Plugins
      • Creating Resolvers
      • Finding types
    • Cache & Distributed Cache
      • Accessing the cache
      • ICacheRefresher
      • IServerMessenger
      • Getting/Adding/Updating/Inserting Into Cache
      • Examples
        • Working with caching
    • Response Caching
    • Security
      • API rate limiting
      • BackOfficeUserManager and Events
      • Cookies
      • Replacing the basic username/password check
      • External login providers
      • Locking of Users and password reset
      • Reset admin password
      • Umbraco Security Hardening
      • Umbraco Security Settings
      • Sensitive data
      • Sanitizing the Rich Text Editor
      • Setup Umbraco for a FIPS Compliant Server
      • HTTPS
      • Two-factor Authentication
      • Server-side file validation
    • Scheduling
    • Common Pitfalls & Anti-Patterns
    • API Documentation
    • Debugging with SourceLink
    • Language Variation
    • UmbracoMapper
    • Distributed Locks
    • Management API
      • Setup OAuth using Postman
    • Custom Swagger API
    • Umbraco Flavored Markdown
  • Tutorials
    • Overview
    • Creating a Basic Website
      • Getting Started
      • Document Types
      • Creating Your First Template
      • CSS and Images
      • Displaying the Document Type Properties
      • Creating a Master Template
      • Creating Pages and Using the Master Template
      • Setting the Navigation Menu
      • Articles and Article Items
      • Adding Language Variants
      • Conclusions
    • Creating your First Extension
    • Creating a Custom Dashboard
      • Adding localization to the dashboard
      • Adding functionality to the Dashboard
      • Using Umbraco UI library in the Dashboard
    • Creating a Property Editor
      • Adding configuration to a Property Editor
      • Integrating context with a Property Editor
      • Custom value conversion for rendering
      • Adding server-side validation
        • Default Property Editor Schema aliases
    • Creating a Multilingual Site
    • Add Google Authentication (Users)
    • Add Microsoft Entra ID authentication (Members)
    • Creating Custom Database Tables with Entity Framework
    • The Starter Kit
      • Lessons
        • Customize the Starter Kit
        • Add a Blog Post Publication Date
          • Add a Blog Post Publication Date
          • Add a Blog Post Publication Date
        • Add Open Graph
          • Add Open Graph - Step 1
          • Add Open Graph - Step 2
          • Add Open Graph - Step 3
          • Add Open Graph - Step 4
          • Add Open Graph - Summary
        • Ask For Help and Join the Community
    • Editor's Manual
      • Getting Started
        • Logging In and Out
        • Umbraco Interface
        • Creating, Saving and Publishing Content Options
        • Finding Content
        • Editing Existing Content
        • Sorting Pages
        • Moving a Page
        • Copying a Page
        • Deleting and Restoring Pages
      • Working with Rich Text Editor
      • Version Management
        • Comparing Versions
        • Rollback to a Previous Version
      • Media Management
        • Working with Folders
        • Working with Media Types
        • Cropping Images
      • Tips & Tricks
        • Refreshing the Tree View
        • Audit Trail
        • Notifications
        • Preview Pane Responsive View
        • Session Timeout
    • Multisite Setup
    • Member Registration and Login
    • Custom Views for Block List
    • Connecting Umbraco Forms and Zapier
    • Creating an XML Sitemap
    • Implement Custom Error Pages
    • Create a custom maintenance page
    • Creating a backoffice API
      • Documenting your controllers
      • Adding a custom Swagger document
      • Versioning your API
      • Polymorphic output in the Management API
      • Umbraco schema and operation IDs
      • Access policies
Powered by GitBook
On this page
  • What does an XML sitemap look like?
  • Approach
  • 1. Create an XmlSiteMap Document Type
  • 2. Create an XmlSiteMapSettings Composition
  • 3. Add composition to all relevant Document Types
  • 4. Building the XmlSiteMap.cshtml template
  • Getting a reference to the sitemap starting point
  • Rendering a sitemap entry
  • Looping through the rest of the site
  • 5. Filter the sitemap content
  • The finished XmlSiteMap Template
  • Going further
  • Test your XML sitemap in a validation tool
Edit on GitHub
Export as PDF
  1. Tutorials

Creating an XML Sitemap

Learn how to build, configure, and add an XML sitemap to your Umbraco website.

PreviousConnecting Umbraco Forms and ZapierNextImplement Custom Error Pages

Last updated 7 months ago

An XML sitemap is a guide for search engines to discover and index your content. Each page on your site that you wish to feature will be represented by a <url> entry in the list.

Adding an XML sitemap to your site makes it easier for search engines such as Google to find and index the pages of your website. Having a sitemap will improve the Search Engine Optimization (SEO) for your website.

This tutorial will take you through the steps of building and configuring a sitemap that fits your Umbraco website.

If you are in a hurry, there is a community package that can do the job for you:

What does an XML sitemap look like?

An XML sitemap is a list of URLs for the content on your site.

See the about the XML schema, the sitemap needs to conform to.

Below is an XML sample of a typical sitemap entry:

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
    <url>
        <loc>https://www.example.com/</loc>
        <lastmod>2005-01-01</lastmod>
        <changefreq>monthly</changefreq>
        <priority>0.8</priority>
    </url>
</urlset>

Approach

There are different ways of approaching this task. The best approach will be determined by the size of your site and your preference for implementing functionality in Umbraco.

In this tutorial, we are going to write the code directly in a Template using Razor and IPublishedContent. You may want to take a different approach, like using route hijacking to write the code in an MVC controller.

Throughout this tutorial, we will:

  • Create a new Document Type called 'XmlSiteMap' that is to be used for the sitemap content page,

  • Create a Document Type composition, containing a consistent set of sitemap-related properties, and

  • Build a Razor template view to generate the sitemap entries based on different criteria and filters.

1. Create an XmlSiteMap Document Type

In this first step of the tutorial, we will be creating a new Document Type for our sitemap page.

  1. Navigate to the Settings section in the Umbraco backoffice.

  2. Create a new Document Type with Template under the Document Types folder.

  3. Name the new Document Type XmlSiteMap.

  4. Add a TextString property called Excluded Document Types (alias: excludedDocumentType).

  5. Save the XmlSiteMap Document Type.

  1. Open the Document Type used at the root of your website (Example: HomePage).

  2. Go to the Structure tab.

  3. Add the new XmlSiteMap under Allowed child node types.

  4. Save the HomePage Document Type.

  5. Navigate to the Content section.

  6. Create a new XmlSiteMap page as a subpage to the root/home page in your Content tree.

  7. Use the alias to add the XmlSiteMap Document Type to the "Excluded Document Type" list: xmlSiteMap.

2. Create an XmlSiteMapSettings Composition

In this step, we will be creating a Composition Document Type. This Document Type will be used to add sitemap options to all Document Types used to add content pages to the website.

The following options will be added:

  • Relative priority: A sitemap entry will allow you to state the relative priority of any particular page in terms of its importance within your site. A value of 1.0 is the highest level of importance and 0.1 is at the other end of the scale.

  • Change Frequency: You can add a change frequency to define how often the content on a particular page is expected to change. This will help the search engine know when to return to reindex any regularly updated content.

Create and configure the Document Type Composition by following these steps:

  1. Navigate to the Settings section in the Umbraco backoffice.

  2. Create a new Composition under the Document Types folder.

  3. Name the new Document Type XmlSiteMapSettings.

  4. Add the following properties:

Property Editor
Name
Value(s)

Slider

Search Engine Relative Priority (searchEngineRelativePriority)

MinValue: 0.1 MaxValue: 1 Step Increments: 0.1 InitialValue: 0.5

Dropdown

Search Engine Change Frequency (searchEngineChangeFrequency)

Always Hourly Daily Weekly Monthly Yearly Never

Toggle (True/False)

Hide From Xml Sitemap (hideFromXmlSitemap)

N/A

Umbraco 14 currently does not allow you to use decimals when configuring the Slider property.

Suggested replacements for the Search Engine Relative Priority property configuration:

  • MinValue: 1

  • MaxValue: 10

  • Step increments: 1

  • InitialValue: 5

3. Add composition to all relevant Document Types

Add the XmlSiteMapSettings composition to all Document Types used to create content pages in the Content section.

This will give editors the ability to set a priority and a change frequency for each page on the site. We will use the values from the parent or parent's parent page in case the values are not specified on a particular page. This enables the values to be set in one place for a particular section.

4. Building the XmlSiteMap.cshtml template

In this step, we will be building the XmlSiteMap template to display the XML schema on the sitemap page.

Editing the template can be done in two different ways:

  • Locate the XmlSiteMap Template in the Settings section of the Umbraco backoffice and use the editor to make the changes, or

  • Open and work with the Views/XmlSiteMap.cshtml file in your preferred Integrated Development Environment (IDE) on your machine.

We will start by adding the XML schema for the sitemap. Since we do not want our template to inherit any 'master' HTML layouts we will set the layout to be null.

  1. Navigate to the Settings section of the Umbraco backoffice.

  2. Find and open the XmlSiteMap Template.

  3. Set Layout to null.

  4. Add Context.Response.ContentType = "text/xml"; within the curly brackets.

  5. Add the following code snippet below the closing curly bracket in the template:

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:schemalocation="http://www.google.com/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd" 
        xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">
    // Insert sitemap content here.
</urlset>
  1. Save the template.

Getting a reference to the sitemap starting point

The sitemap should start at the homepage at the root of the site. Since our XmlSiteMap page is created as a subpage page to the root, we can use the Root() helper to define the starting point as IPublishedContent.

  1. Add IPublishedContent siteHomePage = Model.Root(); within the first set of curly brackets in the template.

  2. Save the template.

Rendering a sitemap entry

We will retrieve each page in the site as IPublishedContent and read in the SearchEngineChangeFrequency and SearchEngineRelativePriority properties. We will also read the URL of the page as well as when it was last modified.

You can include HTML markup in the body of a method declared in a code block. This is a great way to organize your razor view implementation and to avoid repeating code and HTML in multiple places.

  1. Add the following code snippet below the XML schema:

@{
    void RenderSiteMapUrlEntry(IPublishedContent node)
    {
        // The change frequency is recursive and should 'fallback to ancestor' when no value is given.
        var changeFreq = node.Value("searchEngineChangeFrequency", 
                                    fallback: Fallback.To(Fallback.Ancestors, Fallback.DefaultValue), 
                                    defaultValue: "monthly");

        // The relative priority is a per-page setting only. We will not set Fallback.ToAncestors and instead default to 0.5 if no value is set.
        var priority = node.HasValue("searchEngineRelativePriority") ? node.Value<string>("searchEngineRelativePriority") : "0.5";

        <url>
            <loc>@node.Url(mode: UrlMode.Absolute)</loc>
            <lastmod>@(string.Format("{0:s}+00:00", node.UpdateDate))</lastmod>
            <changefreq>@changeFreq</changefreq>
            <priority>@priority</priority>
        </url>
    }
}
  1. Update the XML schema to include RenderSiteMapUrlEntry(siteHomePage):

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:schemalocation="http://www.google.com/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd" 
        xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">
    @{
        RenderSiteMapUrlEntry(siteHomePage);
    }
</urlset>

We are using IPublishedContent in this example. Using ModelsBuilder instead will enable you to take advantage of the fact that the XML Sitemap Settings composition will create an interface called IXmlSiteMapSettings. This will allow you to adjust the helper to accept RenderSiteMapUrlEntry(IXmlSiteMapSettings node) and read properties without the Value helper. You would still need to create an extension method on IXmlSiteMapSettings to implement the recursive functionality we make use of on the SearchEngineChangeFrequency property.

Visit the URL of your sitemap page (http://yoursite.com/sitemap) to render a single sitemap entry for the homepage.

Looping through the rest of the site

We need to go through each page created beneath the homepage to see if they should be added to the sitemap.

We will add a RenderSiteMapUrlEntriesForChildren helper which accepts a 'Parent Page' parameter as the starting point. Then we will find the children of this Parent Page and write out their sitemap entry. Finally, we will call this same method again from itself.

  1. Add the following code snippet below the RenderSiteMapUrlEntry helper and before the closing curly bracket:

void RenderSiteMapUrlEntriesForChildren(IPublishedContent parentPage)
{
    foreach (var page in parentPage.Children)
    {
        RenderSiteMapUrlEntry(page);
        if (page.Children.Any()){
            RenderSiteMapUrlEntriesForChildren(page);
        }
    }
}
  1. Update the XML schema to include RenderSiteMapUrlEntriesForChildren(siteHomePage):

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:schemalocation="http://www.google.com/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd" 
        xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">
    @{
        RenderSiteMapUrlEntry(siteHomePage);
        RenderSiteMapUrlEntriesForChildren(siteHomePage);
    }
</urlset>

You will now see the XML sitemap rendered for the entire site.

5. Filter the sitemap content

In this step, we will use different parameters for filtering the content on the sitemap.

As everything is currently added on the sitemap, we have yet to take into account the pages that should be hidden.

We added a HideFromXmlSitemap checkbox to all Document Types via our XmlSiteMapSettings composition. This configuration needs to be included when rendering the sitemap. The helper needs to only return pages that do not have the HideFromXmlSitemap checked.

  1. Update the RenderSiteMapUrlEntriesForChildren helper as shown below:

    void RenderSiteMapUrlEntriesForChildren(IPublishedContent parentPage)
    {
        // Filter the query based on the hideFromXmlSiteMap value
        foreach (var page in parentPage.Children.Where(x =>!x.Value<bool>("hideFromXmlSiteMap")))
        {
            RenderSiteMapUrlEntry(page);
            // Filter the query based on the hideFromXmlSiteMap value
            if (page.Children.Any(x =>!x.Value<bool>("hideFromXmlSiteMap"))){
                RenderSiteMapUrlEntriesForChildren(page);
            }
        }
    }

Revisit a page in the Content tree, and check the HideFromXmlSitemap option. This page will now be excluded from the sitemap.

To further control which and how many pages are shown in the sitemap you can filter by depth. We will provide the helper with a number that defines how deep into the Content tree the sitemap should look.

  1. Navigate to the Settings section in the Umbraco backoffice.

  2. Find and open the XmlSiteMap Document Type.

  3. Add a Numeric property and call it Max Site Map Depth (alias: maxSiteMapDepth).

  4. Save the Document Type.

  5. Open the XmlSiteMap Template.

  6. Add the following line within the first set of curly brackets:

int maxSiteMapDepth = Model.HasValue("maxSiteMapDepth") ? Model.Value<int>("maxSiteMapDepth") : int.MaxValue;
  1. Update the RenderSiteMapUrlEntriesForChildren helper as shown below:

void RenderSiteMapUrlEntriesForChildren(IPublishedContent parentPage)
{
    foreach (var page in parentPage.Children.Where(f=>!f.Value<bool>("hideFromXmlSiteMap")))
    {
        RenderSiteMapUrlEntry(page);
        // Filter the query based on the maxSiteMapDepth value
        if (page.Level < maxSiteMapDepth && page.Children.Any(f=>!f.Value<bool>("hideFromXmlSiteMap"))){
            RenderSiteMapUrlEntriesForChildren(page);
        }
    }
}
  1. Navigate to the Content section in the Umbraco backoffice.

  2. Open the Sitemap page and set the Max Site Map Depth to 2.

  3. Save and publish the content.

Your sitemap will now only contain entries for the top two levels. Leaving the value blank will mean that no maximum depth restriction will be applied.

Finally, we need the helper to check the Excluded Document Types list on the XmlSiteMap Document Type.

  1. Open the XmlSiteMap Template.

  2. Add the following code snippets within the first set of curly brackets:

// Get the value from the excludedDocumentTypes property as a 'string'
string excludedDocumentTypeList = Model.Value<string>("excludedDocumentTypes");
// Separate the values into separate Document Types and add them to an 'array'
string[] excludedDocumentTypes = (!String.IsNullOrEmpty(excludedDocumentTypeList)) ? excludedDocumentTypeList.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(p => p.Trim()).ToArray() : new string[] { };
  1. Update the RenderSiteMapUrlEntriesForChildren helper as shown below to pass in the array:

void RenderSiteMapUrlEntriesForChildren(IPublishedContent parentPage)
{
    // Filter the query based on the excludedDocumentTypes value
    foreach (var page in parentPage.Children.Where(f => !excludedDocumentTypes.Contains(f.ContentType.Alias) && !f.Value<bool>("hideFromXmlSiteMap")))
    {
        RenderSiteMapUrlEntry(page);
        if (page.Level < maxSiteMapDepth && page.Children.Any(f => !f.Value<bool>("hideFromXmlSiteMap")))
        {
            RenderSiteMapUrlEntriesForChildren(page);
        }
    }
}

Visit the URL of your sitemap page (http://yoursite.com/sitemap) to render a complete sitemap for your site.

It contains an entry for each page that is

  • Not hidden,

  • Not based on an excluded Document Type, and

  • Located within the bounds of the defined depth.

The finished XmlSiteMap Template

@using Umbraco.Cms.Web.Common.PublishedModels;
@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<ContentModels.XmlSiteMap>
@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels;

@{
    Layout = null;
    Context.Response.ContentType = "text/xml";
    IPublishedContent siteHomePage = Model.Root();

    // Get the maxSiteMapDepth value as an integer if the value is not empty
    int maxSiteMapDepth = Model.HasValue("maxSiteMapDepth") ? Model.Value<int>("maxSiteMapDepth") : int.MaxValue;

    // Get the value from the excludedDocumentTypes property as a 'string'
    string excludedDocumentTypeList = Model.Value<string>("excludedDocumentTypes");
    // Separate the values into separate Document Types and add them to an 'array'
    string[] excludedDocumentTypes = (!String.IsNullOrEmpty(excludedDocumentTypeList)) ? excludedDocumentTypeList.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(p => p.Trim()).ToArray() : new string[] { };
}

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:schemalocation="http://www.google.com/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd" 
        xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">
    
    @{
        // Sitemap entry for the homepage is rendered
        RenderSiteMapUrlEntry(siteHomePage);
        // Sitemap for the rest of the site is rendered
        RenderSiteMapUrlEntriesForChildren(siteHomePage);
    }

</urlset>

@{
    // This helper is used to render the sitemap entries
    void RenderSiteMapUrlEntry(IPublishedContent node)
    {
        // The change frequency is recursive and should 'fallback to ancestor' when no value is given.
        var changeFreq = node.Value("searchEngineChangeFrequency", fallback: Fallback.To(Fallback.Ancestors, Fallback.DefaultValue), defaultValue: "monthly");
        // The relative priority is a per-page setting only. We will not set Fallback.ToAncestors and instead default to 0.5 if no value is set.
        var priority = node.HasValue("searchEngineRelativePriority") ? node.Value<string>("searchEngineRelativePriority") : "0.5";

        <url>
            <loc>@node.Url(mode: UrlMode.Absolute)</loc>
            <lastmod>@(string.Format("{0:s}+00:00", node.UpdateDate))</lastmod>
            <changefreq>@changeFreq</changefreq>
            <priority>@priority</priority>
        </url>
    }

    // This helper is used to filter which pages are shown in the sitemap
    void RenderSiteMapUrlEntriesForChildren(IPublishedContent parentPage)
    {
        // Filter the query based on the excludedDocumentTypes and hideFromXmlSiteMap values
        foreach (var page in parentPage.Children.Where(x => !excludedDocumentTypes.Contains(x.ContentType.Alias) && !x.Value<bool>("hideFromXmlSiteMap")))
        {
            RenderSiteMapUrlEntry(page);
            // Filter the query based on the maxSiteMapDepth and hideFromXmlSiteMap values
            if (page.Level < maxSiteMapDepth && page.Children.Any(x => !x.Value<bool>("hideFromXmlSiteMap")))
            {
                RenderSiteMapUrlEntriesForChildren(page);
            }
        }
    }
}

Going further

Once you have added a sitemap to your site it is recommended that you also reference it in your robots.txt file.

  1. Locate and open the robots.txt file in your preferred IDE.

  2. Add the following code snippet:

Sitemap: https://www.yourlovelysite.com/xmlsitemap
User-agent: *
  1. Save the file.

Once you introduce a sitemap for the first time, you might find yourself being crawled by multiple different search engine bots. This is expected and exactly what you want.

It can be a good idea to add a crawl-rate to the robots.txt as well. This will instruct well-behaved search engine bots to increase the time between requests to your site.

  1. Add Crawl-delay: 10 to a new line in your robots.txt file.

  2. Save the file.

Test your XML sitemap in a validation tool

Visit to test the validity of your generated XML sitemap.

SEO Tool Kit
Sitemaps XML format documentation
Xml-Sitemaps.com
View of the properties defined on the finished XmlSiteMap Document Type
View of the Content Tree after a Sitemap page has been added
Create XMLSitempaSettings Configuration
Add Compositions
Example of Sitemap
Example of Sitemap with children