{
export const Default = (props: TitleProps): JSX.Element => {
const datasource = props.fields?.data?.datasource || props.fields?.data?.contextItem;
const { sitecoreContext } = useSitecoreContext();
-
- const text: TextField = {
- value: datasource?.field?.jsonValue?.value,
- editable: datasource?.field?.jsonValue?.editable,
- };
+ const text: TextField = datasource?.field?.jsonValue || {};
const link: LinkField = {
value: {
href: datasource?.url?.path,
title: datasource?.field?.jsonValue?.value,
- editable: true,
},
};
if (sitecoreContext.pageState !== 'normal') {
link.value.querystring = `sc_site=${datasource?.url?.siteName}`;
- if (!text.value) {
+ if (!text?.value) {
text.value = 'Title field';
link.value.href = '#';
}
@@ -84,7 +81,7 @@ export const Default = (props: TitleProps): JSX.Element => {
return (
<>
- {sitecoreContext.pageState === 'edit' ? (
+ {sitecoreContext.pageEditing ? (
) : (
diff --git a/src/sxastarter/src/lib/dictionary-service-factory.ts b/src/sxastarter/src/lib/dictionary-service-factory.ts
index 9aa53dede..8e87af4a6 100644
--- a/src/sxastarter/src/lib/dictionary-service-factory.ts
+++ b/src/sxastarter/src/lib/dictionary-service-factory.ts
@@ -20,13 +20,6 @@ export class DictionaryServiceFactory {
? new GraphQLDictionaryService({
siteName,
clientFactory,
- /*
- The Dictionary Service needs a root item ID in order to fetch dictionary phrases for the current app.
- When not provided, the service will attempt to figure out the root item for the current JSS App using GraphQL and app name.
- For SXA site(s) and multisite setup there's no need to specify it - it will be autoresolved.
- Otherwise, if your Sitecore instance only has 1 JSS App (i.e. in a Sitecore XP setup), you can specify the root item ID here.
- rootItemId: '{GUID}'
- */
/*
GraphQL endpoint may reach its rate limit with the amount of requests it receives and throw a rate limit error.
GraphQL Dictionary and Layout Services can handle rate limit errors from server and attempt a retry on requests.
@@ -39,6 +32,7 @@ export class DictionaryServiceFactory {
*/
retries: (process.env.GRAPH_QL_SERVICE_RETRIES &&
parseInt(process.env.GRAPH_QL_SERVICE_RETRIES, 10)) as number,
+ useSiteQuery: true,
})
: new RestDictionaryService({
apiHost: config.sitecoreApiHost,
diff --git a/src/sxastarter/src/lib/graphql-editing-service.ts b/src/sxastarter/src/lib/graphql-editing-service.ts
new file mode 100644
index 000000000..338a22b2a
--- /dev/null
+++ b/src/sxastarter/src/lib/graphql-editing-service.ts
@@ -0,0 +1,9 @@
+import { GraphQLEditingService } from '@sitecore-jss/sitecore-jss-nextjs/editing';
+import clientFactory from 'lib/graphql-client-factory';
+
+/**
+ * GraphQL Editing Service instance. Used to fetch editing data in Pages preview (editing) Metadata Edit Mode.
+ */
+export const graphQLEditingService = new GraphQLEditingService({
+ clientFactory,
+});
diff --git a/src/sxastarter/src/lib/middleware/plugins/personalize.ts b/src/sxastarter/src/lib/middleware/plugins/personalize.ts
index 73ed36e99..b41aafefa 100644
--- a/src/sxastarter/src/lib/middleware/plugins/personalize.ts
+++ b/src/sxastarter/src/lib/middleware/plugins/personalize.ts
@@ -7,12 +7,12 @@ import { siteResolver } from 'lib/site-resolver';
/**
* This is the personalize middleware plugin for Next.js.
- * It is used to enable Sitecore personalization of pages in Next.js.
+ * It is used to enable Sitecore personalization and A/B testing of pages in Next.js.
*
* The `PersonalizeMiddleware` will
- * 1. Make a call to the Sitecore Experience Edge to get the personalization information about the page.
- * 2. Based on the response, make a call to the Sitecore CDP (with request/user context) to determine the page variant.
- * 3. Rewrite the response to the specific page variant.
+ * 1. Call Sitecore Experience Edge to get the personalization information about the page.
+ * 2. Based on the response, call Sitecore Personalize (with request/user context) to determine the page / component variant(s).
+ * 3. Rewrite the response to the specific page / component variant(s).
*/
class PersonalizePlugin implements MiddlewarePlugin {
private personalizeMiddleware: PersonalizeMiddleware;
@@ -29,7 +29,6 @@ class PersonalizePlugin implements MiddlewarePlugin {
(process.env.PERSONALIZE_MIDDLEWARE_EDGE_TIMEOUT &&
parseInt(process.env.PERSONALIZE_MIDDLEWARE_EDGE_TIMEOUT)) ||
400,
- scope: process.env.NEXT_PUBLIC_PERSONALIZE_SCOPE,
},
// Configuration for your Sitecore CDP endpoint
cdpConfig: {
@@ -40,6 +39,8 @@ class PersonalizePlugin implements MiddlewarePlugin {
parseInt(process.env.PERSONALIZE_MIDDLEWARE_CDP_TIMEOUT)) ||
400,
},
+ // Optional Sitecore Personalize scope identifier.
+ scope: process.env.NEXT_PUBLIC_PERSONALIZE_SCOPE,
// This function determines if the middleware should be turned off.
// IMPORTANT: You should implement based on your cookie consent management solution of choice.
// You may wish to keep it disabled while in development mode.
diff --git a/src/sxastarter/src/lib/next-config/plugins/cors-header.js b/src/sxastarter/src/lib/next-config/plugins/cors-header.js
index 3a64fe417..c8aa9969d 100644
--- a/src/sxastarter/src/lib/next-config/plugins/cors-header.js
+++ b/src/sxastarter/src/lib/next-config/plugins/cors-header.js
@@ -22,15 +22,6 @@ const corsHeaderPlugin = (nextConfig = {}) => {
},
],
},
- {
- source: '/api/:path*',
- headers: [
- {
- key: 'Access-Control-Allow-Origin',
- value: config.sitecoreApiHost.replace(/\/$/, ''),
- },
- ],
- },
];
},
});
diff --git a/src/sxastarter/src/lib/page-props-factory/plugins/personalize.ts b/src/sxastarter/src/lib/page-props-factory/plugins/personalize.ts
index a71162e0a..723cee293 100644
--- a/src/sxastarter/src/lib/page-props-factory/plugins/personalize.ts
+++ b/src/sxastarter/src/lib/page-props-factory/plugins/personalize.ts
@@ -16,12 +16,16 @@ class PersonalizePlugin implements Plugin {
? context.params.path.join('/')
: context.params.path ?? '/';
- // Get variant for personalization (from path)
+ // Get variant(s) for personalization (from path)
const personalizeData = getPersonalizedRewriteData(path);
- // Modify layoutData to use specific variant instead of default
+ // Modify layoutData to use specific variant(s) instead of default
// This will also set the variantId on the Sitecore context so that it is accessible here
- personalizeLayout(props.layoutData, personalizeData.variantId);
+ personalizeLayout(
+ props.layoutData,
+ personalizeData.variantId,
+ personalizeData.componentVariantIds
+ );
return props;
}
diff --git a/src/sxastarter/src/lib/page-props-factory/plugins/preview-mode.ts b/src/sxastarter/src/lib/page-props-factory/plugins/preview-mode.ts
index 63d1f75ff..4bc6f1ed8 100644
--- a/src/sxastarter/src/lib/page-props-factory/plugins/preview-mode.ts
+++ b/src/sxastarter/src/lib/page-props-factory/plugins/preview-mode.ts
@@ -1,7 +1,15 @@
-import { SiteInfo } from '@sitecore-jss/sitecore-jss-nextjs';
-import { editingDataService } from '@sitecore-jss/sitecore-jss-nextjs/editing';
-import { SitecorePageProps } from 'lib/page-props';
import { GetServerSidePropsContext, GetStaticPropsContext } from 'next';
+import {
+ SiteInfo,
+ personalizeLayout,
+ getGroomedVariantIds,
+} from '@sitecore-jss/sitecore-jss-nextjs';
+import {
+ editingDataService,
+ isEditingMetadataPreviewData,
+} from '@sitecore-jss/sitecore-jss-nextjs/editing';
+import { SitecorePageProps } from 'lib/page-props';
+import { graphQLEditingService } from 'lib/graphql-editing-service';
import { Plugin } from '..';
class PreviewModePlugin implements Plugin {
@@ -10,7 +18,41 @@ class PreviewModePlugin implements Plugin {
async exec(props: SitecorePageProps, context: GetServerSidePropsContext | GetStaticPropsContext) {
if (!context.preview) return props;
- // If we're in preview (editing) mode, use data already sent along with the editing request
+ // If we're in Pages preview (editing) Metadata Edit Mode, prefetch the editing data
+ if (isEditingMetadataPreviewData(context.previewData)) {
+ const { site, itemId, language, version, variantIds } = context.previewData;
+
+ const data = await graphQLEditingService.fetchEditingData({
+ siteName: site,
+ itemId,
+ language,
+ version,
+ });
+
+ if (!data) {
+ throw new Error(
+ `Unable to fetch editing data for preview ${JSON.stringify(context.previewData)}`
+ );
+ }
+
+ props.site = data.layoutData.sitecore.context.site as SiteInfo;
+ props.locale = context.previewData.language;
+ props.layoutData = data.layoutData;
+ props.dictionary = data.dictionary;
+ props.headLinks = [];
+ const personalizeData = getGroomedVariantIds(variantIds);
+ personalizeLayout(
+ props.layoutData,
+ personalizeData.variantId,
+ personalizeData.componentVariantIds
+ );
+
+ return props;
+ }
+
+ // If we're in preview (editing) Chromes Edit Mode, use data already sent along with the editing request
+ // This mode is used by the Experience Editor.
+ // In Pages it's treated as a legacy mode but still supported for backward compatibility.
const data = await editingDataService.getEditingData(context.previewData);
if (!data) {
throw new Error(
diff --git a/src/sxastarter/src/pages/[[...path]].tsx b/src/sxastarter/src/pages/[[...path]].tsx
index 98c82f570..b3b3c6278 100644
--- a/src/sxastarter/src/pages/[[...path]].tsx
+++ b/src/sxastarter/src/pages/[[...path]].tsx
@@ -3,10 +3,8 @@ import { GetStaticPaths, GetStaticProps } from 'next';
import NotFound from 'src/NotFound';
import Layout from 'src/Layout';
import {
- RenderingType,
SitecoreContext,
ComponentPropsContext,
- EditingComponentPlaceholder,
StaticPath,
} from '@sitecore-jss/sitecore-jss-nextjs';
import { handleEditorFastRefresh } from '@sitecore-jss/sitecore-jss-nextjs/utils';
@@ -32,8 +30,6 @@ const SitecorePage = ({
}
const isEditing = layoutData.sitecore.context.pageEditing;
- const isComponentRendering =
- layoutData.sitecore.context.renderingType === RenderingType.Component;
return (
@@ -41,15 +37,7 @@ const SitecorePage = ({
componentFactory={componentBuilder.getComponentFactory({ isEditing })}
layoutData={layoutData}
>
- {/*
- Sitecore Pages supports component rendering to avoid refreshing the entire page during component editing.
- If you are using Experience Editor only, this logic can be removed, Layout can be left.
- */}
- {isComponentRendering ? (
-
- ) : (
-
- )}
+
);
diff --git a/src/sxastarter/src/pages/api/editing/render.ts b/src/sxastarter/src/pages/api/editing/render.ts
index 16359e719..b0936b207 100644
--- a/src/sxastarter/src/pages/api/editing/render.ts
+++ b/src/sxastarter/src/pages/api/editing/render.ts
@@ -1,26 +1,35 @@
import { EditingRenderMiddleware } from '@sitecore-jss/sitecore-jss-nextjs/editing';
/**
- * This Next.js API route is used to handle POST requests from Sitecore editors.
+ * This Next.js API route is used to handle GET and POST requests from Sitecore editors.
+ * GET requests are used with Metadata editing mode while POST ones are used with Chromes(legacy) mode.
* This route should match the `serverSideRenderingEngineEndpointUrl` in your Sitecore configuration,
- * which is set to "http://localhost:3000/api/editing/render" by default (see \sitecore\config\sxastarter.config).
+ * which is set to "http:///api/editing/render" by default (see the settings item under /sitecore/content//Settings/Site Grouping).
*
- * The `EditingRenderMiddleware` will
+ * For Metadata mode, the `EditingRenderMiddleware` will
+ * 1. Extract data about the route we need to rendr from the Sitecore editor GET request
+ * 2. Enable Next.js Preview Mode, passing the route data as preview data
+ * 3. Redirect the request to the route, passing along the Preview Mode cookies.
+ * This allows retrieval of the editing data in preview context (via an `EditingDataService`) - see `SitecorePagePropsFactory`
+ * 4. The redirected request will render the page with editing markup in place
+ *
+ * For Chromes(legacy) mode, the `EditingRenderMiddleware` will
* 1. Extract editing data from the Sitecore editor POST request
* 2. Stash this data (for later use in the page render request) via an `EditingDataService`, which returns a key for retrieval
* 3. Enable Next.js Preview Mode, passing our stashed editing data key as preview data
* 4. Invoke the actual page render request, passing along the Preview Mode cookies.
* This allows retrieval of the editing data in preview context (via an `EditingDataService`) - see `SitecorePagePropsFactory`
* 5. Return the rendered page HTML to the Sitecore editor
+ *
*/
/**
- * For Vercel deployments:
+ * [Chromes mode only] For Vercel deployments:
* if you experience crashes in editing, you may need to use VercelEditingDataCache or a custom Redis data cache implementation with EditingRenderMiddleware
* Please refer to documentation for a detailed guide.
*/
-// Bump body size limit (1mb by default) and disable response limit for Sitecore editor payloads
+// [Chromes mode only] Bump body size limit (1mb by default) and disable response limit for Sitecore editor payloads
// See https://nextjs.org/docs/api-routes/request-helpers#custom-config
export const config = {
api: {