All posts by admin

Building Variant Card Components in Sitecore XM Cloud with Next.js

As more organizations move towards headless architecture, Sitecore XM Cloud paired with Next.js offers an excellent combination for building modern, scalable websites. One of the key benefits of Sitecore XM Cloud is its ability to dynamically manage content while Next.js provides fast rendering, client-side routing, and flexibility.

In this tutorial, we’ll walk through an example of how to create reusable and dynamic card components in Sitecore XM Cloud using Next.js. We will explore different variations of the same card component: a default card, a static card, and a card with an image.

Prerequisites

To follow along, you need the following:

  • A Sitecore XM Cloud instance with JSS setup.
  • A Next.js application connected to the Sitecore XM Cloud instance.

Step 1: Define the Card Component

First, let’s define a base card component in React. This component will receive fields and params as props, which represent the content data (fields) and the rendering parameters (params) from Sitecore.

Here’s a cleaned-up version of the card component:

import React from 'react';
import { Text, Field, RichText, Image as JssImage, Link as JssLink, ImageField, LinkField } from '@sitecore-jss/sitecore-jss-nextjs';

interface Fields {
  heading: Field<string>;
  body: Field<string>;
  link: LinkField;
  image: ImageField;
  index?: number;
}

export type CardProps = {
  params: { [key: string]: string };
  fields: Fields;
  index: number;
};

const CardDefaultComponent = (props: CardProps): JSX.Element => (
  <div className={`component card ${props.params.styles}`}>
    <div className="component-content">
      <span className="is-empty-hint">Card</span>
    </div>
  </div>
);

This is a simple CardDefaultComponent that acts as a fallback when no data is available. It can be used when fields are missing or in the process of building a card variant.

Step 2: Create the Default Card Variant

In this step, we’ll create a default card variant. The card will render the heading and body from the provided Sitecore fields.

export const Default = (props: CardProps): JSX.Element => {
  const id = props.params.RenderingIdentifier;
  if (props.fields) {
    return (
      <div className={`component card ${props.params.styles}`} id={id ? id : undefined}>
        <div className="article-wrapper">
          <article>
            <div className="article-body">
              <h3>
                <Text field={props.fields.heading} />
              </h3>
              <RichText field={props.fields.body} />
            </div>
          </article>
        </div>
      </div>
    );
  }
  return <CardDefaultComponent {...props} />;
};

In this default card, we are displaying:

  • The heading as an H3 element.
  • The body as rich text (using Sitecore’s RichText component).

Step 3: Create the Static Card Variant

The static card variant will have a structured layout with a header, body, and footer. This variant is useful for cards with a more predefined and fixed structure.

export const Static = (props: CardProps): JSX.Element => {
  const id = props.params.RenderingIdentifier;
  if (props.fields) {
    return (
      <div className={`component card ${props.params.styles}`} id={id ? id : undefined}>
        <div className="card-header">
          <Text field={props.fields.heading} />
        </div>
        <div className="card-body">
          <h5 className="card-title">
            <RichText field={props.fields.body} />
          </h5>
          <div className="card-text">
            <RichText field={props.fields.body} />
          </div>
        </div>
        <div className="card-footer">Contact number:</div>
      </div>
    );
  }
  return <CardDefaultComponent {...props} />;
};

This variant adds a bit more structure by:

  • Displaying a card-header with the heading.
  • Displaying a card-body with the title and body content.
  • Adding a card-footer for additional information.

Step 4: Create the Card with Image Variant

This variant introduces an image, making it useful for cards that require a visual element along with the text content.

export const CardWithImage = (props: CardProps): JSX.Element => {
  const id = props.params.RenderingIdentifier;
  if (props.fields) {
    return (
      <div className={`component card ${props.params.styles}`} id={id ? id : undefined}>
        <div className="article-wrapper">
          <article>
            <figure>
              <JssImage field={props.fields.image} />
            </figure>
            <div className="article-body">
              <h3>
                <Text field={props.fields.heading} />
              </h3>
              <RichText field={props.fields.body} />
              <JssLink field={props.fields.link} className="read-more">
                Read more <span className="sr-only">about <Text field={props.fields.heading} /></span>
                <svg xmlns="http://www.w3.org/2000/svg" className="icon" viewBox="0 0 20 20" fill="currentColor">
                  <path fillRule="evenodd" d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z" clipRule="evenodd" />
                </svg>
              </JssLink>
            </div>
          </article>
        </div>
      </div>
    );
  }
  return <CardDefaultComponent {...props} />;
};

Here we:

  • Add a <figure> to display the image using JssImage from Sitecore.
  • Include a link (JssLink) to allow users to navigate to more detailed content.
  • Use an SVG icon to enhance the link visually.

Step 5: Use the Card Components in the Next.js Application

Once you’ve created these variants, you can now use them within your Next.js application. Sitecore’s JSS platform will allow you to switch between these card components dynamically based on the rendering parameters or content structure defined in Sitecore.

You can map the card component variants to Sitecore renderings and configure them from the Experience Editor. This flexibility enables you to control how each card should appear, giving marketers the ability to swap between card layouts or content effortlessly.

Live demo: https://nona-local.vercel.app/ND-Test-Page

CSS and JS issues when deploying Sitecore XM Cloud to Vercel

When I first started working with XM Cloud and Vercel, I quickly realized how much there was to learn, especially when it came to the specifics of deployment and environment configurations. I followed the official documentation to set up my site and configured Vercel for deployment, but I encountered a frustrating issue: the theme — both the CSS and JavaScript files — wasn’t loading correctly on the user interface. The site looked broken, with no styles or scripts applied, making it impossible to move forward.

After spending some time troubleshooting and scouring the internet for solutions, I came across a very helpful and detailed blog post. It outlined several common pitfalls with deploying to Vercel and how to address them. The problem I was facing was that the assets weren’t loading because the PUBLIC_URL environment variable hadn’t been set properly.

The solution turned out to be simple but effective: I needed to set the PUBLIC_URL environment variable in Vercel and point it to the production deployment URL. Once I made that change, the issue was resolved, and both the CSS and JavaScript files started loading correctly, restoring the site’s appearance and functionality.

This experience highlighted the importance of understanding how environment variables like PUBLIC_URL work in cloud deployments and how they directly affect asset loading, especially when working with tools like Vercel.

GlassMapper update

Sitecore Upgrade to 10 – Glass.Mapper 5 and Windsor

If you use WindsorContainer and upgrading Glass Mapper to 5, you need to change the registration to the container

 public class ContextInstaller : IWindsorInstaller
 {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
             container.Register(
                Component.For<IRequestContext>().ImplementedBy<RequestContext>().LifestylePerWebRequest(),
                Component.For<IMvcContext>().ImplementedBy<MvcContext>().LifestylePerWebRequest(),
                Component.For<IWebFormsContext>().ImplementedBy<WebFormsContext>().LifestylePerWebRequest(),
                );
        }
}

The GlassMapperScCustom need to be extended to install the ContextInstaller. This should be done in CreateResolver() method

var container = new Castle.Windsor.WindsorContainer();
container.Install(new ContextInstaller());
GlobalConfiguration.Configuration.Services.Replace(typeof(System.Web.Http.Dispatcher.IHttpControllerActivator),
               new WindowsControllerActivator(container));
           System.Web.Mvc.ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(container.Kernel));

For more information upgrading Sitecore, see this post.

How to upgrade GlassMapper is described in this post. However, here is the official page.

My experience preparing for XM Cloud Developer certification exam

I recently took the XM Cloud Developer Certification exam, and I think sharing my experience to the public will help them cover the exam

About the Exam

50 questions for 100 minutes to finish it.

To pass and obtain certification, minimum score of 80% is required

Pre-requisites

This exam is intended for Sitecore XM Cloud developers. You should be familiar with Sitecore Cloud portal and XM Cloud application. It will be good to have some basic experience with Sitecore JSS as well.

Exam Competencies

The exam covers a wide range of topics, including:

  1. XM Cloud Architecture and Developer Workflow – 12%
  2. Deployment of XM Cloud Projects – 16%
  3. Renderings and Layout – 14%
  4. Sitecore Content Serialization – 14%
  5. Sitecore APIs & Webhooks – 10%
  6. XM Cloud Pages – 10%
  7. Security for Developers – 10%
  8. Data Modeling – 14%

How to Prepare for the Exam

  • Sitecore e-learning platform, is where you should start.
  •  XM Cloud documentation for developers contains detailed information for each topic.
  • If possible, spend time on XM Cloud portal to navigate trhough different sections, to understand each topic in real exams
  • Sitecore Videos are in a great help.
  • I’ve generated 81 different questions with possible answers and created Google Forms with them. I’ve divided the questions by competency so each colleague can test specific areas, rather than answering all the questions. If you would like to test your competencies, send me a message, and I will provide you with the link to the form.

Cleaning Up Unused Data Sources in Sitecore with PowerShell

As Sitecore developers and content managers, we often encounter situations where unused data sources clutter our content tree. This can happen after restructuring or deleting items, leaving behind orphaned data sources that are no longer in use. To keep our Sitecore instance clean and efficient, it’s essential to identify and remove these unused data sources. In this post, I’ll walk you through a PowerShell script designed to find and remove unused data sources within a specific content path.

The Challenge

When working with Sitecore, especially in large content trees, managing data sources can become cumbersome. Unused data sources not only waste storage space but can also lead to confusion when searching for relevant items. The goal of the script is to traverse a specified path, check each item for referrers, and remove those without any references.

The PowerShell Script

Here’s a cleaned-up and more professional version of the PowerShell script that accomplishes this task:

# Navigate to the specified path in the master database
cd 'master:/sitecore/content/[Your-Site-Path]'

# Get all items under the specified path, recursively
$itemsToProcess = Get-ChildItem -Recurse

if ($itemsToProcess -ne $null) {
    # Process each item to check for referrers
    $itemsToProcess | ForEach-Object {
        $referrers = Get-ItemReferrer -Item $_ | Measure-Object

        if ($referrers.Count -gt 0) {
            Write-Host "Item ID: $($_.ID), Referrers: YES, Name: $($_.Name)"
        } else {
            Write-Host "Item ID: $($_.ID), Referrers: NO, Name: $($_.Name)"
            # Uncomment the following line to remove unused items
            # $_ | Remove-Item -Force
        }
    }
} else {
    Write-Host "No items found to process."
}

How the Script Works

  1. Navigating to the Path: The script begins by navigating to the specified content path in the master database where the data sources are located.
  2. Retrieving Items: It retrieves all items under the specified path recursively.
  3. Checking for Referrers: For each item, the script checks if there are any referrers using the Get-ItemReferrer command. This command returns the items that reference the current item.
  4. Outputting Results:
    • If the item has referrers, it outputs the item’s ID, name, and states that it has referrers.
    • If the item does not have any referrers, it indicates that the item can be considered for removal.
  5. Removal (Optional): The line responsible for removing the item is commented out by default for safety. You can uncomment it when you are ready to perform the deletion.

Conclusion

This PowerShell script provides a straightforward way to clean up unused data sources in Sitecore, helping maintain an organized content structure. Remember to review the items carefully before removal, especially in production environments.

Before running the removal command, consider taking a backup of your Sitecore instance or using a staging environment to ensure that no important data is lost.

Final Note

Always test scripts in a safe environment before executing them in production, and customize the path and parameters as necessary for your specific use case. Happy scripting!

Celebrating Achievements at Our Success Sharing Event

On March 20, 2024, we hosted a successful Success Sharing event at our Sofia office, dedicated to recognizing outstanding achievements within our team. This year, I had the honor of nominating our talented Sitecore developers for their remarkable contributions over the past year, showcasing their dedication and expertise in the Sitecore ecosystem.

I felt an immense sense of pride as two of our exceptional team members from the Sitecore group took the stage as speakers. Their insights and experiences not only highlighted their individual accomplishments but also reflected the collective strength and innovation of our team. Their ability to share knowledge and inspire others is a testament to our commitment to excellence in Sitecore development.

The event served as a fantastic platform to celebrate not only individual achievements but also the collaborative spirit that drives our success. As we continue to grow and excel in our Sitecore endeavors, I look forward to seeing more of our developers recognized as Sitecore MVPs, reflecting their hard work and dedication to the community.

You can see pictures from the event here.

Troubleshooting Site Language Configuration Issues in Sitecore SXA

In the world of Sitecore development, issues related to site configurations can often arise, particularly when managing multiple languages for a single site. A recent support case highlights a common problem faced by developers, the process of seeking help from Sitecore support, and how it can be resolved effectively.

Background

As a developer managing an SXA site with multiple site grouping definitions, each corresponding to a different language, I encountered a significant challenge. In this particular case, there were two site groupings:

  • Site 1: English Version
  • Site 2: Chinese Version

The challenge was that the Chinese URL was unexpectedly displaying English content from Site 1 instead of the intended Chinese content from Site 2.

Seeking Assistance

To resolve this issue, I contacted Sitecore support for expert assistance. The support team promptly reviewed the configuration and identified that the problem was linked to the disableTrailingWildcard setting within Sitecore. This setting affects how the site definitions match incoming requests. By default, when set to false, it allows for more flexible matching of hostnames. However, in this scenario, it was causing the Chinese site to incorrectly resolve to the English site.

Diagnosis and Resolution

Following the guidance from Sitecore support, the following steps were taken:

  1. Update Site Definition: I was instructed to open the site definition items for both site groupings and add the property disableTrailingWildcard=true in the Other Properties field.
  2. Publish Changes: After updating the site definitions, it was essential to publish the changes to ensure they were reflected in the live environment.
  3. Testing: With the updates made, I tested the site again to verify that the Chinese URL was now resolving correctly to the intended language content.

Conclusion

This support case not only illustrates the complexities involved in managing multiple languages in Sitecore SXA but also emphasizes the importance of reaching out for expert help when needed. By properly configuring site definitions and utilizing properties like disableTrailingWildcard, developers can effectively troubleshoot and resolve similar issues.

The experience underlines the value of Sitecore support in navigating challenges within the platform. If you find yourself encountering language resolution problems in your Sitecore projects, consider reaching out to Sitecore support for guidance. Often, the solution lies in the details, and expert insights can lead to quick resolutions.

Sitecore Database broken after upgrade

Sitecore database broken after running Sitecore.UpdateApp 1.2

We followed Sitecore documentation for upgrading databases from 8.2 to 10.2. Steps you can find described here.

When we ran the Sitecore.UpdateApp tool, and try to open Sitecore Backend, we got following error:

[ArgumentNullException: The path "{E18F4BC6-46A2-4842-898B-B6613733F06F}" was not found.
[ArgumentNullException: The path "{E18F4BC6-46A2-4842-898B-B6613733F06F}" was not found.

After further research, this item is a /sitecore/layout/Devices item. It sounds that the database is incomplete, or broken.

I discovered that the upgraded solution includes a configuration patch file, which points to another \Data folder, hard-coded path to (C:\sites\local.sc.com\Data), which is not my local website\Data.

So Sitecore could not find the resources (now items as resources) and throws the error. I’ve commented the configuration file , and now it points to correct website\data folder and the issue is resolved.

GlassMapper update

Sitecore Upgrade to 10.2 – GlassMapper upgrade from 4 to 5

SitecoreContext

SitecoreContext is no longer available in GlassMapper 5+ and need to be replaced with MvcContext (used mainly in Controllers) or RequestContext (used outside Controllers).

So for every piece of code

private readonly ISitecoreContext _sitecoreContext

should be changed to

private readonly IRequestContext _sitecoreContext;

or

private readonly IMvcContext _sitecoreContext;

Note that GetItem method and etc need to be called from SitecoreService.

_sitecoreContext.GetItem<Item>("{8A1AC22A-EADC-46CE-9954-88BB2680AB83}")

should be changed to

_sitecoreContext.SitecoreService.GetItem<Item>("{8A1AC22A-EADC-46CE-9954-88BB2680AB83}")

Another example is where in the class method the SitecoreContext is initialized

For example

var context = new SitecoreContext();

need to be changed to

var context = new RequestContext(new SitecoreService(Sitecore.Context.Database)).SitecoreService;

GetHomeItem

_sitecoreContext.GetHomeItem<ISiteRoot>();

will be changed to

 context.SitecoreService.GetItem<ISiteRoot>(Sitecore.Context.Site.StartPath)

GlassView is obsolete

All views need to be updated as follow:

@inherits Glass.Mapper.Sc.Web.Mvc.GlassView<MyNamespace.MyViewModel>

 @Editable(Model, x => x.Item.Title)

to

@model MyNamespace.MyViewModel
@Html.Glass().Editable(Model, x => x.Item.Title)

GetCurrentItem

The new version GetCurrentItem is marked obsolete and replaced by GetContextItem method

 Item = _sitecoreContext.GetCurrentItem<MyModel>()

should be changed as follow, note that _sitecoreContext is now IMvcContext

 Item = _sitecoreContext.GetContextItem<MyModel>()

Sitecore Managed Cloud Lunch and Learn: Troubleshooting and Architecture Deep Dive


On February 20, I organized a Lunch and Learn session on Sitecore Managed Cloud. I presented the platform and covered common topics, including its architecture and troubleshooting techniques.

Agenda Overview

During the session, we covered a variety of topics aimed at enhancing our understanding of Sitecore Managed Cloud, from its core architecture to real-world troubleshooting.Introduction to Sitecore Managed Cloud
We kicked off with an overview of Sitecore Managed Cloud and how it benefits businesses hosting on Azure. The discussion focused on its scalability, performance, and cost-efficiency.

-Benefits of Hosting on Azure: We touched on the advantages of Azure’s globally distributed infrastructure, highlighting how it ensureshigh availability and resilience, making it perfect for enterprise-scale Sitecore deployments.

  • Key Azure Services Used by Sitecore Managed Cloud
    Next, we explored the key Azure services that power Sitecore Managed Cloud, ensuring smooth performance and effective deployment.

-Azure App Service: Hosts the Sitecore web apps.
-Azure Redis Cache: Handles session state storage and caching.
-Azure Publishing Service: Supports content publishing in scaled environments.
-Azure Kudu: A powerful tool for deployments and diagnostics within the App Service environment.

  • Architecture Overview
    We then took a deeper dive into the architectural layout of Sitecore on Azure Managed Cloud. This section explained how the different components work together to deliver a seamless cloud experience.

-App Service & Redis: We focused on how these two services interact, ensuring that Sitecore runs smoothly and scales effectively in the cloud.

  • Development Tools: App Service Editor & Kudu
    For developers working in Sitecore Managed Cloud,App Service Editor andKudu are must-know tools for troubleshooting and deployments.

-App Service Editor: We explored how it enables quick file edits within the Sitecore environment.
-Kudu: We took a detailed look at how to use Kudu for diagnostics and debugging, with a focus on accessingdeployment logs and using itsconsole for troubleshooting.

  • Monitoring and Analytics with Application Insights
    One of the most powerful tools at our disposal isApplication Insights, which allows for real-time monitoring and diagnostics.

-Key Features: We explored how to use Application Insights to monitor Sitecore applications, diagnose errors, and track performance.
-App Map: I demonstrated how to use theApp Map feature to visualize dependencies and identify potential bottlenecks or system failures.

  • Common Issues
    We also discussed some of the most frequent issues users encounter with Sitecore Managed Cloud. Here are the details:

-Application Crashes and Exceptions: We discussed how to diagnose and resolve crashes by reviewing logs and exceptions.
-Module Initialization Issues: A walkthrough on how to identify and resolve initialization problems with Sitecore modules.
-Identity Server Troubleshooting: I explained how to resolve integration challenges with Active Directory and identity server setups.

  • Advanced Troubleshooting Tools
    We went beyond the basics by introducing advanced tools to tackle more complex issues.

-Snapshot Debugger: We discussed how to use this tool to debug live applications without interrupting service.
-Health Check: I demonstrated how to monitor your Sitecore instance’s health using Azure’s built-in health check features.

  • Load Balancing and Affinity
    To round off the session, we explored the importance ofARR Affinity Cookies in managing user sessions across multiple servers in a load-balanced environment. This is key for understanding session management and ensuring consistent user experiences in a scaled Sitecore setup.

Q&A Session

You can see our post here .

Presentation is available on request.