Sitemap XML for Sitecore

The simplest description of a Sitemap is a file that list all the URL’s on a site for a Search Engine to crawl. Traditionally web crawlers would follow links on pages within a site and rely on them to discover new pages and index them. Sitemaps add a layer of intelligence to this by providing a list of URL’s up front and also adding additional metadata such as when the page was last updates, how often it changes and how important the page is.

For more information on Sitemaps have a look at sitemaps.org

Introducing Sitemap XML for Sitecore

Out of the box Sitecore doesn’t provide any built in functionality for auto generating a sitemap, but a good module on the Sitecore Marketplace is Sitemap XML (https://marketplace.sitecore.net/en/Modules/Sitemap_XML.aspx). This module will generate a schema compliant sitemap file in the root of your site on each publish of the site.

There are a couple of issue you might experience when trying to use it:

Publishing Error

Once you’ve installed the module and attempted a full site publish you will likely get an error like this…

Job started: Publish to 'web'|Items created: 0|Items deleted: 0|Items updated: 78|Items skipped: 15877|#Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.NullReferenceException: Object reference not set to an instance of an object.
 at Sitecore.Modules.SitemapXML.SitemapManager.BuildSiteMap(String sitename, String sitemapUrlNew)
 at Sitecore.Modules.SitemapXML.SitemapManager..ctor()
 at Sitecore.Modules.SitemapXML.SitemapHandler.RefreshSitemap(Object sender, EventArgs args)
 at Sitecore.Events.Event.EventSubscribers.RaiseEvent(String eventName, Object[] parameters, EventResult result)
 at Sitecore.Events.Event.RaiseEvent(String eventName, Object[] parameters)
 at Sitecore.Publishing.Publisher.NotifyEnd()
 at Sitecore.Publishing.Publisher.Publish()
 --- End of inner exception stack trace ---
 at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
 at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
 at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
 at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
 at (Object , Object[] )
 at Sitecore.Pipelines.CorePipeline.Run(PipelineArgs args)
 at Sitecore.Jobs.Job.ThreadEntry(Object state)

Going by the comments on the Sitecore marketplace this happens to quite a lot of people and unfortunately the limited documentation for the module doesn’t explain the cause.

When you install the module it will create a config file called SitemapXML.config within App_Config\Include. By default that config will have the following 2 lines:

<site name="website_1" filename="sitemap1.xml" serverUrl="www.site1domain.com" /> 
<site name="website_2" filename="sitemap2.xml" serverUrl="www.site2domain.com"/> 

These websites don’t exist which is what causes the error. So to fix simply change the name of your website and the URL can be left blank. e.g.

<site name="website" filename="sitemap.xml" serverUrl="" /> 

Multiple Server Setup

If you’re Sitecore installation is using separate servers for content management and content delivery you’ll notice that your only generating sitemaps on your content management server.

To set up your content delivery server to start generating the files update the event node in the config file from

<event name="publish:end">

to

<event name="publish:end:remote">

and also make sure you have both the SitemapXML.dll file and config file on your content deliver server.

Advertisements

Responsive Images in Sitecore

By default, when you add an image to a page in Sitecore using the <sc:Image > control it will render height and width attributes on the resulting html. These are based on the images dimensions or any height and width properties you may have set server side.

The benefit of doing this is that when the browser renders the page, it already knows what space the image will take up before the image has loaded. This reduces the number of repaints the browser has to make and ultimately speeds up the page rendering time. If the height and width weren’t specified then a repaint would happen after the image was loaded as the size would now be known.

However this can cause an issue when you are producing a responsive site that changes its layout based on the size of a device or width of a browser window. Because responsive design is done though CSS media tags the server does not know what the height and width of the image will be, unfortunately there’s also no built in way to tell Sitecore to stop rendering the height and width tags. Not very good when you want to size your image to 100% width of an area that can change size.

The solution is to create a Pipeline. Pipelines are Sitecores way of enabling you change how Sitecore works and their not overly complex to implement.

To create a pipeline that will affect the way an Image field is rendered your first need to create a GetImageFieldValueResponsive class as follows. The name of the class can be anything you want but I’ve called it GetImageFieldValueResponsive as it will be called after Sitecores GetImageFieldValue class.

namespace SitecoreCustomization.Pipelines.RenderField
{
    public class GetImageFieldValueResponsive
    {
        public void Process(RenderFieldArgs args)
        {
            if (args.FieldTypeKey != "image")
                return;
            if (args.Parameters.ContainsKey("responsive"))
            {
                string imageTag = args.Result.FirstPart;
                imageTag = Regex.Replace(imageTag, @"(<img[^>]*?)\s+height\s*=\s*\S+", "$1", RegexOptions.IgnoreCase);
                imageTag = Regex.Replace(imageTag, @"(<img[^>]*?)\s+width\s*=\s*\S+", "$1", RegexOptions.IgnoreCase);
                imageTag = Regex.Replace(imageTag, @"(<img[^>]*?)\s+responsive\s*=\s*\S+", "$1", RegexOptions.IgnoreCase);
                args.Result.FirstPart = imageTag;
                
            }
        }
    }
}

The process function in the class is what will get called as the control is rendered. First it will check that the field type is an image and then will look to see if there is a parameter called responsive. This will allow us to control when Sitecore should output height and width tags and when it shouldn’t. Lastly some Regex is used to remove the height, width and responsive properties from the image tag that will already have been generated by this point.

Next we need to tell Sitecore to start using this pipeline. We do this by creating a RenderField.config file and placing it in the App_Config\Include folder of your Sitecore solution.

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <pipelines>
      <renderField>
        <processor
            patch:after="*[@type='Sitecore.Pipelines.RenderField.GetImageFieldValue, Sitecore.Kernel']"
            type="SitecoreCustomization.Pipelines.RenderField.GetImageFieldValueResponsive, DLLNameOfWhereYouCreatedTheClass"/>
      </renderField>
    </pipelines>
  </sitecore>
</configuration>

Lastly your control will need to have an attribute to say it should be responsive. For an xslt rendering your code will look like this:

<sc:image field="Image" responsive="1" />

And for an ascx sublayout it will look like this:

<sc:Image runat="server" Field="Image" Parameters="responsive=1" />