How to have a fallback OpenGraph image in Sitecore SXA?

We recently had a request to have a single image as a fallback image to be set as for OpenGraph Image field.

The simplest answer to this as Sitecore professional was to set it in Standard Values on the Page template for the Project.

We tried the above and it miserably failed as the OpenGraphMetadataRepository was not creating the og:field meta tag based on the Standard Values. We decided to write the same logic we have for Title field.

So we took the approach of overidding the same OpenGraphMetadataRepository logic by our new Repo.

You can just create a new Template for the OpenGraph Image field, similar to the one in the below screenshot.

Create an item under Settings and name it OpenGraph.

Now that we have this item ready, we need to write the logic for OpenGraphMetadataRepository to override in a way – if a Content Author has set an image on the page level then that image should be rendered as og:image else it should render the one that we have set.

using Sitecore.XA.Feature.SiteMetadata.Repositories.BrowserTitle;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Sitecore.Data;
using Sitecore.Data.Items;
using Sitecore.XA.Feature.SiteMetadata.Models;
using System.Web.UI.WebControls;
using Sitecore.Data.Fields;

namespace Test.Feature.MetaData.Repositories
{
    public class OpenGraphMetadataRepository : Sitecore.XA.Feature.SiteMetadata.Repositories.OpenGraphMetadata.OpenGraphMetadataRepository
    {
        public OpenGraphMetadataRepository()
        {
            this.Mapping = new Dictionary<string, ID>()
            {
                {
                  "fb:app_id",
                  Sitecore.XA.Feature.SiteMetadata.Templates._OpenGraphMetadata.Fields.OpenGraphAppId
                },
                {
                  "og:description",
                  Sitecore.XA.Feature.SiteMetadata.Templates._OpenGraphMetadata.Fields.OpenGraphDescription
                },
                {
                  "og:type",
                  Sitecore.XA.Feature.SiteMetadata.Templates._OpenGraphMetadata.Fields.OpenGraphType
                },
                {
                  "og:site_name",
                  Sitecore.XA.Feature.SiteMetadata.Templates._OpenGraphMetadata.Fields.OpenGraphSiteName
                },
                {
                  "og:admins",
                  Sitecore.XA.Feature.SiteMetadata.Templates._OpenGraphMetadata.Fields.OpenGraphAdmins
                },
                {
                  "og:image",
                  Sitecore.XA.Feature.SiteMetadata.Templates._OpenGraphMetadata.Fields.OpenGraphImageUrl
                }
            };
        }

        protected override IEnumerable<MetaTagModel> GetMetaTags()
        {
            Item currentItem = this.PageContext.Current;
            List<MetaTagModel> list = this.BuildModelMapping().ToList<MetaTagModel>();
            list.Add(new MetaTagModel()
            {
                Property = "og:title",
                Content = this.GetTitle(this.PageContext.Current)
            });
            list.Add(new MetaTagModel()
            {
                Property = "og:url",
                Content = this.LinkGenerator.GetExternalUrl(this.PageContext.Current)
            });
            if (string.IsNullOrEmpty(currentItem[Sitecore.XA.Feature.SiteMetadata.Templates._OpenGraphMetadata.Fields.OpenGraphImageUrl]))
            {
                list.Add(new MetaTagModel()
                {
                    Property = "og:image",
                    Content = this.GetImage(currentItem)
                });
            }
            return list.Where<MetaTagModel>((Func<MetaTagModel, bool>)(metaTagModel => metaTagModel != null));
        }

        protected virtual string GetImage(Item currentItem)
        {
            string imageUrl = string.Empty; 
            Database db = Sitecore.Context.Database;
            Item ogItem = db.GetItem(Constants.ItemIds.OpenGraph);
            Sitecore.Data.Fields.ImageField imgField = ogItem != null ? ogItem.Fields[Templates.OpenGraphImage.Fields.OpenGraphImageUrl] : null;
            if (imgField != null && imgField.MediaItem != null)
            {
                MediaItem image = new MediaItem(imgField.MediaItem);

                imageUrl = Sitecore.StringUtil.EnsurePrefix('/',
                                Sitecore.Resources.Media.MediaManager.GetMediaUrl(image));
                if (!string.IsNullOrEmpty(imageUrl))
                    imageUrl = "https://" + Sitecore.Context.Site.HostName + imageUrl;

            }
            return imageUrl;
        }
    }
}

Once you have created the Repository, we will need to register it as a Service using the Config file, create new config under App_Config and use below code.

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/role">
	<sitecore>
		<services>
			<register serviceType="Sitecore.XA.Foundation.Mvc.Repositories.Base.IAbstractRepository`1[[Sitecore.XA.Feature.SiteMetadata.Models.OpenGraphRenderingModel, Sitecore.XA.Feature.SiteMetadata]], Sitecore.XA.Foundation.Mvc"
					  implementationType="Test.Feature.MetaData.Repositories.OpenGraphMetadataRepository, Test.Feature.MetaData"
					  lifetime="Singleton"
					  patch:instead="*[@serviceType='Sitecore.XA.Foundation.Mvc.Repositories.Base.IAbstractRepository`1[[Sitecore.XA.Feature.SiteMetadata.Models.OpenGraphRenderingModel, Sitecore.XA.Feature.SiteMetadata]], Sitecore.XA.Foundation.Mvc']"/>
			<register serviceType="Sitecore.XA.Feature.SiteMetadata.Repositories.OpenGraphMetadata.OpenGraphMetadataRepository, Sitecore.XA.Feature.SiteMetadata"
					  implementationType="Test.Feature.MetaData.Repositories.OpenGraphMetadataRepository, Test.Feature.MetaData"
					  lifetime="Singleton"
					  patch:instead="*[@serviceType='Sitecore.XA.Feature.SiteMetadata.Repositories.OpenGraphMetadata.OpenGraphMetadataRepository, Sitecore.XA.Feature.SiteMetadata']"/>
		</services>
	</sitecore>
</configuration>

Once you publish the above changes, you will get the expected results i.e. if the Content Editor fails to set the OpenGraph image on page level then it will be rendered from the Settings item and if the Content Editor sets it at page level then it will have the preference.

Hope it was helpful!!!

Thank you.. Keep Learning.. Keep Sitecoring… 🙂

Leave a comment