Extend Page Props Factory in Sitecore XM Cloud to Inject Custom Data into the Layout Service

Hello everyone! In this blog, we'll explore how to extend the page props factory plugin to add our own custom fields. We will take a realistic example to understand the concepts.

XM Cloud is based on the SXA framework. In SXA, there was an option to add and manage the favicon directly from the CMS. However, this functionality is not available in XM Cloud. Instead, the favicon is typically placed in the public directory of your Next.js application to ensure public accessibility. If you want the favicon to be managed exclusively through the CMS, what approach can be taken to achieve this?

So let's get started with CMS changes.First Step will be to add favIcon template with favIcon field. Second will be to add that template as base template for your main Settings item. Follow the below screenshot.

Let's see the FE changes that we need to do.

Create a new file called CustomContextResolver.ts under lib --> page-props-factory --> plugins

Add the below code. Check your Settings path and update it accordingly in your code.

       
import { SitecorePageProps } from 'lib/page-props';
import { Plugin } from '..';
import { GetServerSidePropsContext, GetStaticPropsContext } from 'next';
import fetchSettings from 'lib/fetchSettings';

class CustomContextResolver implements Plugin {
  order = 3;

  async exec(props: SitecorePageProps, context: GetServerSidePropsContext | GetStaticPropsContext) {
    console.log('CustomContextResolver Plugin executed', context);
    if (!props.layoutData.sitecore.route) return props;
    const siteName = props.site.name;
    const language = props.layoutData.sitecore.context.language ?? 'en';
    if (!siteName) return props;
    let sitefolder = '';
    if (siteName.toLowerCase().includes('{}')) {
      sitefolder = '{}';
    } else {
      sitefolder = '{}';
    }
    const contentRootPath = `/sitecore/content/{}/{}/${sitefolder}/${siteName}/Settings`;

    const result = await Promise.all([fetchSettings(contentRootPath, language)]);
    console.log('Fetched Settings:', JSON.stringify(result));
    const faviconurl = result[0]?.settingItem?.favIcon?.jsonValue?.value?.src;
    console.log('FavIcon:', faviconurl);
    props.layoutData.sitecore.context.favIcon = {
      faviconurl: faviconurl || '',
    };

    return props;
  }
}

export const customContextResolverPlugin = new CustomContextResolver();

	   

Now create another fetchSettings.ts which will be having the actual GQL call to get the needed data.

       
import { GraphQLRequestClient } from '@sitecore-jss/sitecore-jss-nextjs/graphql';
import { ImageField } from '@sitecore-jss/sitecore-jss-nextjs';
import config from 'temp/config';

const getSettings = `query Settings($path: String!, $language: String!) {
  settingItem: item(path: $path, language: $language) {
		... on JSSSettings_34595534b4034816ba9fb4ca9d100eb5{
      favIcon: field(name:"favIcon")
      {
        jsonValue
      }
    }
  }
}`;

type SettingGraphQLResponse = {
  settingItem: {
    favIcon: {
      jsonValue: ImageField;
    };
  };
};
const fetchSettings = (path: string, language: string) => {
  const gqlClient = new GraphQLRequestClient(config.graphQLEndpoint, {
    apiKey: config.sitecoreApiKey,
  });
  const response = gqlClient.request<SettingGraphQLResponse>(getSettings, {
    path,
    language,
  });
  console.log('response', response);
  return response;
};

export default fetchSettings;
       
	   

Now use the injected favIcon property wherever you have implemented favIcon logic in head tag using SitecoreContext.

       
// Create type
interface FavIcon {
  faviconurl?: string;
} 

//Use SitecoreContext hook to read the faviconurl
const { sitecoreContext } = useSitecoreContext();
const favIconUrl = (sitecoreContext?.favIcon as FavIcon)?.faviconurl;
console.log('Favicon URL from context:', favIconUrl as string); 

//Use the favicon url in head section of your page
 <link rel="icon" href={favIconUrl} />
	   

Verify your results.

Also you can improve performance of your page by referring below blog which explains how you can implement caching in next js. Thanks for reading and keep learning

You can check my other blogs too if interested. Blog Website

References:

  • https://ravivadher.tech.blog/2025/04/25/part-2-optimizing-sitecore-context-injection-with-caching/

Comments

Popular posts from this blog

Sitecore XM Cloud Form Integration with Azure Function as Webhook

Sitecore 10.2 Installation using Windows PowerShell

Automate RSS Feed to Sitecore XM Cloud: Logic App, Next.js API & Authoring API Integration