In the previous post, We saw how we could use two different ways of patching for the use case. Today I am here to share how to do it Next.Js way !!!!
Background
Considering our lookout path string is `/sitecore/media library/Files` and any link field or rich text has a reference to this path then we would need to make sure those links when clicked go through our custom API route `/api/custom`.
Example: One of the Links has been linked to a file at this path /sitecore/media library/Files/lorem-ipsum.pdf
, then what we would need is when that link is clicked it gets routed to /api/custom
, so the user won’t see the actual path of the pdf but rather our API does business logic and serves it when logic passes.
Next.js Solution
This solution involves extending the default plugin file normal-mode.ts under lib/page-props-factory/plugins under your Next.Js app.
We would need to do 2 things :
- Create a new Custom Plugin for our logic to execute.
- Change export type plugin from default (new NormalModePlugin() )to our new Custom plugin name (new CustomNormalModePlugin() )
So below how it looks like, it’s exactly similar to the original plugin except for our changes that are marked bold in the code snippet below.
class CustomNormalModePlugin extends NormalModePlugin {
private rewriteLayoutService: LayoutService;
private rewriteDictionaryService: DictionaryService;
order = -1;
constructor() {
super();
this.rewriteLayoutService = layoutServiceFactory.create();
this.rewriteDictionaryService = dictionaryServiceFactory.create();
}
async exec(props: SitecorePageProps, context: GetServerSidePropsContext | GetStaticPropsContext) {
if (context.preview) return props;
const path = extractPath(context.params);
props.locale = context.locale ?? pkg.config.language;
props.layoutData = await this.rewriteLayoutService.fetchLayoutData(
path,
props.locale,
// eslint-disable-next-line prettier/prettier
isServerSidePropsContext(context) ? (context as GetServerSidePropsContext).req : undefined,
isServerSidePropsContext(context) ? (context as GetServerSidePropsContext).res : undefined
);
const EDGE_CDN_URL = process.env.EDGE_CDN_URL || '';
const needle = `${EDGE_CDN_URL}${'/sitecore/media library/Files'}`;
let layoutStringData = JSON.stringify(props.layoutData, null);
layoutStringData = layoutStringData.replace(new RegExp(needle, 'gi'), '/api/custom');
props.layoutData = JSON.parse(layoutStringData);
if (!props?.layoutData?.sitecore?.route) {
props.notFound = true;
}
props.dictionary = await this.rewriteDictionaryService.fetchDictionaryData(props.locale);
return props;
}
}
export const normalModePlugin = new CustomNormalModePlugin();
Explanation :
Because the response from layout service wouldn’t be just a relative URL for files under Media library but rather prefixed by Edge CDN URL prefixed with file, we have EDGE_CDN_URL from the environment variable and form complete URL as we already have our second part of URL which would be /sitecore/media library/Files.
The next line of code just stringifies the layout data from the props and once we have layoutStringData we just use a simple regex to replace it with our API route.
So now every time a front-end user loads a page they would just see https://[domain]/api/custom if it matches our criteria of any file being referenced from /sitecore/media library/Files instead of exposing the path itself.
That’s it! Happy Headless Sitecoring !!!