XM Cloud Articles / Blogs / Perficient https://blogs.perficient.com/tag/xm-cloud/ Expert Digital Insights Wed, 09 Oct 2024 20:08:15 +0000 en-US hourly 1 https://blogs.perficient.com/files/favicon-194x194-1-150x150.png XM Cloud Articles / Blogs / Perficient https://blogs.perficient.com/tag/xm-cloud/ 32 32 30508587 Three Tips for Adding a Headless Site in XM Cloud https://blogs.perficient.com/2024/10/09/three-tips-for-adding-a-headless-site-in-xm-cloud/ https://blogs.perficient.com/2024/10/09/three-tips-for-adding-a-headless-site-in-xm-cloud/#respond Wed, 09 Oct 2024 20:08:15 +0000 https://blogs.perficient.com/?p=367815

Intro 📖

In this post, I’ll cover three tips developers should consider when deploying a new headless site to XM Cloud. Having recently added a new headless site to an existing solution, I ran into a few issues. I hope to save others from similar headaches in the future (mostly myself 😉). If you’ve added a new headless site to your XM Cloud solution recently and are having trouble getting the site to appear and function properly, please read on 👇.

1. Verify the New Site’s Start Item 🚩

After deploying your new site, if you notice that the site isn’t appearing on the Sites landing page in XM Cloud (https://xmapps.sitecorecloud.io/?tab=tools&tenantName=<tentant_name>&organization=<organization>), double-check that the site’s Start item field is set. This field can be found on the site’s Site Grouping item whose path is (usually) as follows:

/sitecore/content/<site_collection>/<site>/Settings/Site Grouping/<site>

Moreover, make sure that the referenced item is physically present in the content tree. If the Start item isn’t present, the site won’t appear in XM Cloud.

Site Start Item

Verify that the Start item is set and points to an actual page.

In my particular case, I had initially misconfigured serialization for the new site and inadvertently excluded the new site’s Home item. The Start item field was set, but it didn’t point to anything in the target environment, so my new site wasn’t showing up in XM Cloud 🤦‍♂️.

2. Verify the Rendering Host Items 🤖

If your new site is appearing in XM Cloud but you can’t open any pages in Experience Editor or Preview, something could be wonky with the rendering host items.

Every XM Cloud solution includes an xmcloud.build.json file in the root directory. This is the XM Cloud build configuration file; it controls how XM Cloud builds and deploys the solution. Included in this file is a list of the rendering hosts that XM Cloud should provision and spin up as part of a deployment. Rendering hosts (also sometimes called “editing hosts” in the context of a CM) are necessary to drive Sitecore’s Experience Editor and Preview functionality. The xmcloud.build.json file is pretty important and useful; for more information on this file and what it can do, please refer to the official documentation here: https://doc.sitecore.com/xmc/en/developers/xm-cloud/the-xm-cloud-build-configuration.html.

There should be an entry in the renderingHosts property of the xmcloud.build.json file for every separate headless application in your solution. Note, however, that it is possible to run multiple headless sites with a single head application using the JSS multisite add-on. For more information on the pros and cons of either approach, check out this Sitecore developer article: https://developers.sitecore.com/learn/accelerate/xm-cloud/pre-development/project-architecture/multisite#web-application.

For the purposes of this tip, assume that there are two headless sites, each with their own headless Next.js application running different versions of Node (which also implies the need for two separate rendering hosts–one rendering host can’t run multiple versions of Node/Next.js). Let’s say the xmcloud.build.json file looks something like this:

{
    "renderingHosts": {
        "mysite1": {
            "path": "./src/rendering-mysite1",
            "nodeVersion": "16.15.1",
            "jssDeploymentSecret":"<redacted>",
            "enabled": true,
            "type": "sxa",
            "lintCommand": "lint",
            "startCommand": "start:production"
        },
        "mysite2": {
          "path": "./src/rendering-mysite2",
          "nodeVersion": "20.14.0",
          "jssDeploymentSecret":"<redacted>",
          "enabled": true,
          "type": "sxa",
          "lintCommand": "lint",
          "startCommand": "start:production"
      }
    },
    ...

When XM Cloud runs a deployment, it reads the xmcloud.build.json file, iterates through the renderingHosts property, and provisions the relevant containers behind the scenes. When the deployment completes, the rendering host items in the content tree are created and/or updated under this folder:

/sitecore/system/Settings/Services/Rendering Hosts

The rendering host items in this folder map to the rendering hosts enumerated in the xmcloud.build.json file.

One interesting thing to note is that, regardless of the name of the first rendering host the xmcloud.build.json file (e.g., mysite1 in the example above), the first rendering host in the xmcloud.build.json file will always be created in the Sitecore content tree with a name of Default. The N + 1 rendering hosts will have the names listed in the xmcloud.build.json file. For example (again, assuming the xmcloud.build.json file, above 👆), the post-deployment rendering hosts in the target XM Cloud environment would look like this:

Rendering Hosts

The resulting rendering host items from an XM Cloud deployment.

Once XM Cloud creates these items, it sets them to protected in the content tree–these items should not be modified outside of the XM Cloud deployment process.

If, for whatever reason, you’ve serialized these items and have manually overridden the items (either by making manual changes or by installing a content package), you can get into a situation where the changes and updates during XM Cloud deployments on these items are ignored because Sitecore is looking at the overridden items. This will remain an issue until the overridden serialized items are either cleaned up using the Sitecore CLI itemres cleanup command (reference: https://doc.sitecore.com/xmc/en/developers/xm-cloud/the-cli-itemres-command.html#the-cleanup-subcommand) or the overridden items are simply deleted (to be restored on the next deployment).

The TL;DR for this tip: do not serialize rendering host items corresponding to entries in the renderingHosts property in the xmcloud.build.json file–XM cloud manages these items, so you don’t have to.

3. Set the Name and Description for the Site Collection 📛

The XM Cloud Sites landing page has been updated recently but, in the past, the name of the site collection to which a site belonged would sometimes be presented as “N/A”:

Collection On Site

A site’s Collection label reading “N/A”.

It turns out that there’s a field section on site collection items that lets developers set the Name and Description for the site collection. Admittedly, initially, I was just annoyed with the “N/A” and wanted a way to set the site collection name. However, it’s generally a good idea to name and describe your site collections anyway, especially if there are (or will be) many of them. To set the Name and Description fields on a site collection item, navigate to the site collection item in the content tree and drill down to the Metadata field section to provide values for these fields:

Site Collection Name And Description

Setting the Name and Description of a site collection.

🥣 Be sure to serialize any updates to these items using the Sitecore CLI ser pull command (reference: https://doc.sitecore.com/xmc/en/developers/xm-cloud/the-cli-serialization-command.html#the-pull-subcommand). Site collection items are developer-controlled and should be consistent between environments.

Now, in the XM Cloud Sites interface (and possibly elsewhere in the future), it’ll be easier to differentiate between site collections and determine the purpose of a given site collection. ✅

Thanks for the read! 🙏

]]>
https://blogs.perficient.com/2024/10/09/three-tips-for-adding-a-headless-site-in-xm-cloud/feed/ 0 367815
XM Cloud content migration: connecting external database https://blogs.perficient.com/2024/09/13/xm-cloud-content-migration-connecting-external-database/ https://blogs.perficient.com/2024/09/13/xm-cloud-content-migration-connecting-external-database/#respond Sat, 14 Sep 2024 04:59:05 +0000 https://blogs.perficient.com/?p=369122

Historically when performing content migration with Sitecore we used to deal with database backups. In a modern SaaS world, we do not have the luxury of neither managing cloud database backups, nor the corresponding UI for doing this. Therefore, we must find an alternative approach.

Technical Challenge

Let’s assume we have a legacy Sitecore website, in my case that was XP 9.3 and we’ve been provided with only master database backup having all the content. The objective is to perform content migration from this master database into a new and shiny XM Cloud environment(s).

Without having direct access to the cloud, we can only operate locally. In theory, there could be a few potential ways of doing this:

  1. Set up a legacy XP of the desired version with the legacy content database already attached/restored to it. Then try to attach (or restore) a vanilla XM Cloud database to a local SQL Server as a recipient database in order to perform content migration into it.  Unfortunately, the given approach would not work since SQL Server version incompatibility between XM Cloud and XP 9.3. Even if that was possible, running XP 9.3 with the XM Cloud database won’t work as Xз 9.3 neither knows about XM Cloud schema nor is capable of handling Items as Resource required feature which was invented later in XP 10.1. Therefore – this option is not possible.

  2. Can we go the other way around by using the old database along with XM Cloud? This is not documented, but let’s assess it:

    1. Definitely won’t work in the cloud since we’re not given any control of DBs and their maintenance or backups.

    2. In a local environment, XM Cloud only works in Docker containers and it is not possible to use it with an external SQL Server where we have a legacy database. But what if we try to plug that legacy database inside of the local SQL Container? Sadly, there are no documented ways of achieving that.

  3. Keep two independent instances side by side (legacy XP and XM Cloud in containers) and use an external tool to connect both of them in order to migrate the content. In theory that is possible but carries on few drawbacks.
    1. The tool of choice is Razl, but this tool is not free, requires a paid license, and does not have a free trial to ever test this out.
    2. Connecting to a containerized environment may not be easy and require some additional preps
    3. You may need to have a high-spec computer (or at least two mid-level machines connected to the same network) to have both instances running side by side.

After some consideration, the second approach seems to be reasonable to try so let’s give it a chance and conduct a PoC.

Proof of Concept: local XM Cloud with external content database

Utilize the second approach we’re going to try attaching the given external legacy database to XM Cloud running in a local containerized setup. That will allow using a built-in UI for mass-migrating the content between the databases (as pictured below) along with the Sitecore PowerShell script for finalizing and fine-tuning the migrated content.

Image 20240525 194741 (1)

Step 1: Ensurу SQL Server port is externally exposed

We are connecting the external  SQL Server Management studio through a port of the SQL Server container that is exposed externally in order to make it possible. Luckily, that has been done for us already, just make sure docker-compose has:

    ports:
      - "14330:1433"

Step 2: Spin up an XM Cloud containers and confirm XM Cloud works fine for you

Nothing extraordinary here, as easy as running .\init.ps1 followed by .\up.ps1.

Step 3: Connect SQL Management Studio to SQL Server running in a container.

After you sound up containers, run SQL Management Studio and connect to SQL Server running in SQL container through an exposed port 14330, as we did at step 1:

Picture1

Step 4: Restore the legacy database

If you have a Data-Tier “backpack” file you may want to do an extra step and convert it into a binary backup for that particular version used by XMCloud before restoring. This step is optional, but in case you want to restore the backup more than once (which is likely to happen), it would make sense to take a binary backup as soon as you restore the data-tier “backpack” first time ever. Data-tier backups process much slower than binaries, so that will definitely save time in the future.

Once connected, let’s enable contained database authentication. This step is mandatory, otherwise, that would not be possible to restore a database:

EXEC sys.sp_configure N'contained database authentication', N'1'
go
exec ('RECONFIGURE WITH OVERRIDE')
go

One more challenge ahead: when performing backup and restore operations, SQL Server shows up a path local to the server engine, and not the host machine. That means, our backup should exist “inside” of SQL container. Luckily, w have this also covered. Make sure docker-compose.override.yml contains:

  mssql:
    volumes:
      - type: bind
        source: .\docker\data\sql
        target: c:\data

That means, one can locate legacy database backups into .\docker\data\sql folder of a host machine and it will magically appear within C:\datafolder when using SQL Management Studio database backup restore tool which you can perform now.

Important! Restore legacy database using the “magic name” in a format Sitecore.<DB_NAME_SUFFIX>, further down below I will be using the value RR as DB_NAME_SUFFIX.

Once got restored database in SQL Server Management Studio under the name Sitecore.RR we need to plug this database to the system. There is a naming convention hidden from our eyes within CM containers.

Step 5: Configure connection strings

Unlike in XM/XP – there is no documented way to plug an external database. The way connection strings are mapped to the actual system is cumbersome, it uses some “magic” hidden within the container itself and obfuscated from our eyes. It only tool to reach it experimental way. Here are the steps to reproduce:

  • Add environmental variable to docker-compose record for CM:

    Sitecore_ConnectionStrings_RR: Data Source=${SQL_SERVER};Initial Catalog=${SQL_DATABASE_PREFIX}.RR;User ID=${SQL_SA_LOGIN};Password=${SQL_SA_PASSWORD}
  • Add new connection string record. To do so you’ll need to create a connection strings file within your customization project as .\src\platform\<SITENAME>\App_Config\ConnectionStrings.config with the content of the connection strings file from CM container with the addition of a new string:

    <add name="rr" connectionString="user id=user;password=password;Data Source=(server);Database=Sitecore_RR" />

Please note the difference in the suffix format of both above records, that is totally fine. CM container still processes that correctly.

Step 6: Reinstantiating CM container

Simply restarting a CM container is not sufficient. You must remove it and re-create it, just killing/stopping is not sufficient.

For example, the below command will work for that purpose:

docker-compose restart cm

… not will this one:

docker-compose kill cm

The reason is that CM will not update environmental variables from docker-compose file upon restart. Do this instead:

docker-compose kill cm
docker-compose rm cm --force
docker-compose up cm -d

Step 7: Validating

  1. Inspecting CM container for environmental variables will show you this new connection string, as added:

    "Env": [
                "Sitecore_ConnectionStrings_RR=Data Source=mssql;Initial Catalog=Sitecore.RR;User ID=sa;Password=6I7X5b0r2fbO2MQfwKH"

     

  2. Inspecting connection string config (located at C:\inetpub\wwwroot\App_Config\ConnectionStrings.config on CM container) contains the newly added connection string.

Step 8: Register new database with XM Cloud

It can be done the below config patch that does this job. Save it as docker\deploy\platfo.rm\App_Config\Include\ZZZ\z.rr.config for test and later do not forget to include it in a platform customization project, so that it gets shipped with each deployment
<?xml version="1.0" encoding="UTF-8"?>
<configuration xmlns:patch="www.sitecore.net/.../">
    <sitecore>
        <eventing defaultProvider="sitecore">
            <eventQueueProvider>
                <eventQueue name="rr" patch:after="evertQueue[@name='web']" type="Sitecore.Data.Eventing.$(database)EventQueue, Sitecore.Kernel">
                    <param ref="dataApis/dataApi[@name='$(database)']" param1="$(name)" />
                    <param ref="PropertyStoreProvider/store[@name='$(name)']" />
                </eventQueue>
            </eventQueueProvider>
        </eventing>
        <PropertyStoreProvider>
            <store name="rr" patch:after="store[@name='master']" prefix="rr" getValueWithoutPrefix="true" singleInstance="true" type="Sitecore.Data.Properties.$(database)PropertyStore, Sitecore.Kernel">
                <param ref="dataApis/dataApi[@name='$(database)']" param1="$(name)" />
                <param resolve="true" type="Sitecore.Abstractions.BaseEventManager, Sitecore.Kernel" />
                <param resolve="true" type="Sitecore.Abstractions.BaseCacheManager, Sitecore.Kernel" />
            </store>
        </PropertyStoreProvider>
        <databases>
            <database id="rr" patch:after="database[@id='master']" singleInstance="true" type="Sitecore.Data.DefaultDatabase, Sitecore.Kernel">
                <param desc="name">$(id)</param>
                <icon>Images/database_master.png</icon>
                <securityEnabled>true</securityEnabled>
                <dataProviders hint="list:AddDataProvider">
                    <dataProvider ref="dataProviders/main" param1="$(id)">
                        <disableGroup>publishing</disableGroup>
                        <prefetch hint="raw:AddPrefetch">
                            <sc.include file="/App_Config/Prefetch/Common.config" />
                            <sc.include file="/App_Config/Prefetch/Webdb.config" />
                        </prefetch>
                    </dataProvider>
                </dataProviders>
                <!-- <proxiesEnabled>false</proxiesEnabled> -->
                <archives hint="raw:AddArchive">
                    <archive name="archive" />
                    <archive name="recyclebin" />
                </archives>
                <cacheSizes hint="setting">
                    <data>100MB</data>
                    <items>50MB</items>
                    <paths>2500KB</paths>
                    <itempaths>50MB</itempaths>
                    <standardValues>2500KB</standardValues>
                </cacheSizes>
            </database>
        </databases>
    </sitecore>
</configuration>

Step 9: Enabling Sitecore PowerShell Extension

Next, we’d want to enable PowerShell, if that is not yet done. You won’t be able to migrate the content using SPE without performing this step.

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/" xmlns:set="http://www.sitecore.net/xmlconfig/set/">
  <sitecore role:require="XMCloud">
    <powershell>
      <userAccountControl>
        <tokens><token name="Default"  elevationAction="Block"/>
              <token name="Console" expiration="00:55:00" elevationAction="Allow" patch:instead="*[@name='Console']"/>
              <token name="ISE" expiration="00:55:00" elevationAction="Allow" patch:instead="*[@name='ISE']"/>
              <token name="ItemSave" expiration="00:55:00" elevationAction="Allow" patch:instead="*[@name='ItemSave']"/>
            </tokens>
      </userAccountControl>
    </powershell>
  </sitecore>
</configuration>

Include the above code into a platform customization project as .\docker\deploy\platform\App_Config\Include\ZZZ\z.SPE.config. If everything is done correctly, you can run SPE commands, as below:

Image 20240525 200307 (1)

The Result

After all the above steps are done correctly, you will be able to utilize the legacy content database along with your new shiny local XM Cloud instance:
Picture2
Now you can copy items between databases just by using built-in Sitecore UI preserving their IDs and version history. You can also copy items with SPE from one database to another which are both visible to the SPE engine.
]]>
https://blogs.perficient.com/2024/09/13/xm-cloud-content-migration-connecting-external-database/feed/ 0 369122
.NET Core Renderings for XM Cloud finally gets some love https://blogs.perficient.com/2024/08/30/net-core-renderings-for-xm-cloud-finally-gets-some-love/ https://blogs.perficient.com/2024/08/30/net-core-renderings-for-xm-cloud-finally-gets-some-love/#respond Fri, 30 Aug 2024 13:10:53 +0000 https://blogs.perficient.com/?p=368432

That is not a secret – Sitecore always used to prioritize Next.Js framework as the first-class citizen for XM Cloud. All the best and finest features tend to find their way to a given framework in the first place. However, recently, there has been much activity around the .NET Core Rendering Framework which makes a lot of sense given most of us, Sitecore tech professionals, originate from the Microsoft and .NET background. More excitement – that is done on .NET 8, which is the latest LST runtime!

Starter Kit

ASP.NET Core framework was with us for a while, periodically receiving some minor updates and fixes. But let’s be honest: having an SDK on its own is one thing, but receiving a decent starter kit on top of that framework is what makes us developers actually create at scale. And that moment has just occurred – without any loud fanfare, XMC ASP.NET Core Starter Kit went public. Please be aware that this is only a PRE-RELEASE version and has its own temporal shortcomings, I gave it a try and want to share my findings with you.

What are these shortcomings? Just a few:

  • FEaaS and BYOC components are not yet supported, therefore you also cannot use Form since it leverages those
  • System.Text.Json serializer is more strict than Newtonsoft which was removed in favor of a built-in solution, thus some components may fail
  • SITECORE_EDGE_CONTEXT_ID variable is not supported

Everything else seems to work the same. There are also some expectations of XM Cloud supporting .NET Rendering at a built-in editing host at some time later in the same manner that works today along with JSS applications, but I do not work for Sitecore and can only make assumptions and guesses without any certainty to it.

First Impression

I forked the repo and cloned the forked code into my computer. Let’s take a look at what we have got there.

Vs Code

  • the code varies from what we used to see from XM Cloud Foundation Head starter kit, and that’s understood
  • at the root folder we still have xmcloud.build.json, sitecore.json and folders – .config and .sitecore
  • xmcloud.build.json is required for cloud deploy, but does not have renderingHosts root section required for editing host(s), as I explained above
  • there is headapps folder to keep the solution file along with .NET projects subfolder(s), currently just a single one – aspnet-core-starter
  • there is also local-containers folder that contains docker-compose files, .env, docker files, scripts, Traefik, and the rest of the container assets we got used to
  • another difference – authoring folder contains serialization settings and items as well as .NET framework project for CM customizations
  • however, there are no init.ps1 and up.ps1 files, but that is easy to create yourself by stealing and modifying those from XM Cloud Foundation Head

With that in mind, we can start investigating. There is a ReadMe document explaining how to deploy this codebase, but before going ahead with it I of course decided to:

Run Local Containers

There are no instructions on container setup, only for cloud deployment, but after spending a few years with Foundation Head, the very first thing that naturally comes into my mind is running this starter kit in local Docker containers. Why not?

There are a couple of things one should do first prior to spinning up containers.

  1. Modify settings in .ENV file – at least these two:
# Enter the value for SQL Server admin password:
SQL_SA_PASSWORD=SA_PASSWORD

# Provide a folder storing a Sitecore license file:
HOST_LICENSE_FOLDER=C:\Projects
  1. We need to generate Traefik SSL Certificates. To do so let’s create .\local-containers\init.ps1 script with the below content:
[CmdletBinding(DefaultParameterSetName = "no-arguments")]
Param ()
$ErrorActionPreference = "Stop";

# duplicates in Up.ps1 scrips
$envContent = Get-Content .env -Encoding UTF8
$xmCloudHost = $envContent | Where-Object { $_ -imatch "^CM_HOST=.+" }
$renderingHost = $envContent | Where-Object { $_ -imatch "^RENDERING_HOST=.+" }
$xmCloudHost = $xmCloudHost.Split("=")[1]
$renderingHost = $renderingHost.Split("=")[1]

Push-Location docker\traefik\certs
try {
    $mkcert = ".\mkcert.exe"
    if ($null -ne (Get-Command mkcert.exe -ErrorAction SilentlyContinue)) {
        # mkcert installed in PATH
        $mkcert = "mkcert"
    } elseif (-not (Test-Path $mkcert)) {
        Write-Host "Downloading and installing mkcert certificate tool..." -ForegroundColor Green
        Invoke-WebRequest "https://github.com/FiloSottile/mkcert/releases/download/v1.4.1/mkcert-v1.4.1-windows-amd64.exe" -UseBasicParsing -OutFile mkcert.exe
        if ((Get-FileHash mkcert.exe).Hash -ne "1BE92F598145F61CA67DD9F5C687DFEC17953548D013715FF54067B34D7C3246") {
            Remove-Item mkcert.exe -Force
            throw "Invalid mkcert.exe file"
        }
    }
    Write-Host "Generating Traefik TLS certificate..." -ForegroundColor Green
    & $mkcert -install
    & $mkcert "$xmCloudHost"
    & $mkcert "$renderingHost"
}
catch {
    Write-Error "An error occurred while attempting to generate TLS certificate: $_"
}
finally {
    Pop-Location
}

Write-Host "Adding Windows host"
Add-HostsEntry "$renderingHost"
Add-HostsEntry "$xmCloudHost"

Write-Host "Done!" -ForegroundColor Green

And then execute this script:

Certs

There is no up.ps1 script, so instead let’s run docker-compose directly: docker compose up -d

You may notice some new images show up, and you also see a new container: aspnet-core-starter

Docker

If everything is configured correctly, the script will execute successfully. Run Sitecore from its default hostname, as configured in .env file: https://xmcloudcm.localhost/sitecore

From there you will see no significant changes. Containers just work well! Sitecore has no content to interact with the head application. I will add the content from the template but let’s make the could deployment first.

Deploy to the Cloud

ReadMe document suggests an inconvenient way of cloud deployment:

1. Create a repository from this template. 2. Log into the Sitecore Deploy Portal. 3. Create a new project using the ‘bring your code’ option, and select the repository you created in step 1.

For the majority of us, who are on the Sitecore Partner side, there are only six environments available grouped into two projects. These allocations are priceless and are carefully shared between all XM Cloud enthusiasts and aspirants who are learning a new platform. We cannot simply “create a new project” because we don’t have that spare project, so in order to create one we have to delete the existing one. Deleting a project requires deleting all (three) of its environments in the first place, which is half of the sandbox capacity, carrying valuable work in progress for many individuals.

That is why I decided to use CLI instead. Luckily it works exactly the same as it does with Next.Js starter kits, and from .\.config\dotnet-tools.json you may see that it uses that same version. You deploy the root folder holding xmcloud.build.json file as a working directory, so there are no changes in execution.

Eventually, once deployed we navigate to XM cloud. I decided to follow the ReadMe and create a Basic site from Skate Park template. Basically, I am following steps 4-18 from the ReadMe file.

As a side exercise, you will need to remove a Navigation component from a Header partial item, located at /sitecore/content/Basic/Basic/Presentation/Partial Designs/Header. Basic site will break in the debugger if you do not delete currently incompatible rendering that has a serialization issue.

Building Dev Tunnel in Visual Studio

Next, let’s open and build the solution in the Visual Studio IDE, which refers to .\headapps\aspnet-core-starter.sln file. You may see it related to three Sitecore dependencies from Sitecore.AspNetCore.SDK.LayoutService.Client:

  • Transient: Sitecore.AspNetCore.SDK.LayoutService.Client.Interfaces.ISitecoreLayoutClient
  • Singleton: Sitecore.AspNetCore.SDK.LayoutService.Client.Serialization.ISitecoreLayoutSerialize
  • Singleton: Sitecore.AspNetCore.SDK.LayoutService.Client.Serialization.Converter.IFieldParser

Modify .\headapps\aspnet-core-starter\appsettings.json with the setting values collected from the previous steps. You will end up with something looking as:

Appsettings.json

Now let’s create a Dev Tunnel in VisualStudio:

Dev Tunnel

There will be at least two security prompts:

Dev Tunnel Authorize GithubDev Tunnel Authorize Notice

If everything goes well, a confirmation message pops up:

Dev Tunnel Created

Now you will be able to run and debug your code in Visual Studio:

Debugger Works

Make a note of the dev tunnel URL, so that we can use it to configure Rendering Host, as described at step 27 of ReadMe. You will end up with something as below:

Rendering Hosts

So far so good. You can now run the website by URL and in Experience Editor. Running in Page will however not work yet due to the below error:

No Pages Without Publish

To explain that, Experience Editor runs as a part of CM and pulls content from a GraphQL endpoint on that same CM. Pages instead is a standalone separate application, so it does not have access neither to the endpoint nor to the Rendering Hosts settings item. It only has access to Experience Edge so we must publish first. Make sure you publish the entire Site Collection. Once complete, Page works perfectly well and displays the site:

Pages Work 1 Pages Work 2

To explain what happens above: Pages app (which is a SaaS-run editor) pulls Experience Edge for the settings of the rendering editing host (which runs in a debuggable dev tunnel from Visual Studio) and renders HTML right there with the layout data and content pulled from Experience Edge.

Deploy Rendering Host to Cloud

Without much thinking, I decided to deploy the rendering host as Azure Web App, with the assumption that the .NET 8 application would be best supported in its native cloud.

Web App Configure

After the Web App is created, add the required environmental variables. The modern and shiny SITECORE_EDGE_CONTEXT_ID variable is not yet supported with .NET Core SDK, so we should go the older way:

Azure App Settings

A pleasant bonus of GitHub integration is that Azure creates GitHub Actions workflow with the default functional build and deployment. There is almost nothing to change,  I only made a single fix replacing run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/myapp with a hardcoded path since this variable contains space from “Program Files” part and is incorrectly tokenized breaking the build. After this fix, GitHub actions got built the right way and I started receiving green status:

Github Actions

… and the published site shows up from the Azure Web App powered rendering host:

Published Site

Finally, we can get rid of Dev Tunnel, replacing it with the actual “published site” hostnames:

Getting Rid Of Dev Tunnel

After republishing the Rendering Host item to Edge, we can stop the debugger and close Visual Studio. Both Experience Editor and Pages app are now working with an editing host served by the Azure Web App.

Verdict

Of course, that would be much anticipated for XM Cloud to have built-in .NET editing host capabilities same way as JSS does. But even without it, I applaud to Sitecore development team for making and keeping working on this starter kit as that is a big milestone for all of us within the .NET Community!

With this kit, we can now start building XM Cloud powered .NET app at a faster pace. I believe all the missing features will find their way to the product, and maybe later there will be some (semi)official SSG support for .NET, something like Statiq. That will allow deployments to a wider set of hosting, such as Azure Static Web Apps, Netlify, and even Vercel which does not support .NET as of today.

]]>
https://blogs.perficient.com/2024/08/30/net-core-renderings-for-xm-cloud-finally-gets-some-love/feed/ 0 368432
Full guide to enabling Headless Multisite Add-On for your XM Cloud solution https://blogs.perficient.com/2024/08/26/full-guide-to-enabling-headless-multisite-add-on-for-your-xm-cloud-solution/ https://blogs.perficient.com/2024/08/26/full-guide-to-enabling-headless-multisite-add-on-for-your-xm-cloud-solution/#respond Mon, 26 Aug 2024 22:37:35 +0000 https://blogs.perficient.com/?p=367793

Sitecore Headless Next.Js SDK recently brought the feature that makes it possible to have multiple websites from Sitecore content tree being served by the same rendering hoist JSS application. It uses Next.js Middleware to serve the correct Sitecore site based on the incoming hostname.

Why and When to Use the Multisite Add-on

The Multisite Add-on is particularly useful in scenarios where multiple sites share common components or when there is a need to centralize the rendering logic. It simplifies deployment pipelines and reduces infrastructure complexity, making it ideal for enterprises managing a portfolio of websites under a unified architecture. This approach saves resources and ensures a consistent user experience across all sites.

How it works

The application fetches site information at build-time, not at runtime (for performance reasons). Every request invokes all Next.js middleware. Because new site additions are NOT frequent, fetching site information at runtime (while technically possible) is not the best solution due to the potential impact on visitor performance. You can automate this process using a webhook to trigger automatic redeployments of your Next.js app on publish.

Sitecore provides a relatively complicated diagram of how it works (pictured below), but if you do not get it from the first look, do not worry as you’ll get the understanding after reading this article.

Uuid 8601bf89 50ab 5913 42ed 4773b05ab2c3[1]

Technical Implementation

There are a few steps one must encounter to make it work. Let’s start with the local environment.

Since multisite refers to different sites, we need to configure hostnames. The Main site operates on main.localhost hostname, and it is already configured as below:

.\.env
    RENDERING_HOST=main.localhost
.\docker-compose.override.yml
    PUBLIC_URL: "https://${RENDERING_HOST}"

For the sake of the experiment, we plan to create a second website served by second.localhost locally. To do so, let’s add a new environmental variable to the root .env file (SECOND_HOST=second.localhost) and introduce some changes to init.ps1 script:

$renderingHost = $envContent | Where-Object { $_ -imatch "^RENDERING_HOST=.+" }
$secondHost = $envContent | Where-Object { $_ -imatch "^SECOND_HOST=.+" }
$renderingHost = $renderingHost.Split("=")[1]
$secondHost = $secondHost .Split("=")[1]

down below the file we also want to create SSL certificate for this domain by adding a line at the bottom:

& $mkcert -install
# & $mkcert "*.localhost"
& $mkcert "$xmCloudHost"
& $mkcert "$renderingHost"
& $mkcert "$secondHost"

For Traefic to pick up the generated certificate and route traffic as needed, we need to add two more lines at the end of .\docker\traefik\config\dynamic\certs_config.yaml file:

tls:
  certificates:
    - certFile: C:\etc\traefik\certs\xmcloudcm.localhost.pem
      keyFile: C:\etc\traefik\certs\xmcloudcm.localhost-key.pem
    - certFile: C:\etc\traefik\certs\main.localhost.pem
      keyFile: C:\etc\traefik\certs\main.localhost-key.pem
    - certFile: C:\etc\traefik\certs\second.localhost.pem
      keyFile: C:\etc\traefik\certs\second.localhost-key.pem

If you try initializing and running – it may seem to work at first glance. But navigating to second.localhost in the browser will lead to an infinite redirect loop. Inspecting the cause I realized that occurs due to CORS issue, namely that second.localhost does not have CORS configured. Typically, when configuring the rendering host from docker-compose.override.yml we provide PUBLIC_URL environmental variable into the rendering host container, however, that is a single value and we cannot pass multiple.

Here’s the more descriptive StackOverflow post I created to address a given issue

To resolve it, we must provide the second host in the below syntax as well as define CORS rules as labels into the rendering host, as below:

labels:
  - "traefik.enable=true"
  - "traefik.http.routers.rendering-secure.entrypoints=websecure"
  - "traefik.http.routers.rendering-secure.rule=Host(`${RENDERING_HOST}`,`${SECOND_HOST}`)"
  - "traefik.http.routers.rendering-secure.tls=true"
  # Add CORS headers to fix CORS issues in Experience Editor with Next.js 12.2 and newer
  - "traefik.http.middlewares.rendering-headers.headers.accesscontrolallowmethods=GET,POST,OPTIONS"
  - "traefik.http.middlewares.rendering-headers.headers.accesscontrolalloworiginlist=https://${CM_HOST}, https://${SECOND_HOST}"
  - "traefik.http.routers.rendering-secure.middlewares=rendering-headers"

Once the above is done, you can run the PowerShell prompt, initialize, and spin up Sitecore containers, as normal, by executing init.ps1 and up.ps1 scripts.

Configuring Sitecore

Wait until Sitecore spins up, navigate to a site collection, right-click it, and add another website calling it Second running on a hostname second.localhost.

Make sure second site uses the same exact application name as main, you can configure that from /sitecore/content/Site Collection/Second/Settings item, App Name field. That ensures the purpose of this exercise is for both sites to reuse the same rendering host application.

You should also make sure to match the values of the Predefined application rendering host fields of /sitecore/content/Site Collection/Second/Settings/Site Grouping/Second and /sitecore/content/Site Collection/Main/Settings/Site Grouping/Main items.

Another important field here is Hostname, make sure to set these fields for both websites:

Hostname

 

Now you are good to edit Home item of Second site. Multisite middleware does not affect the editing mode of Sitecore, so from there, you’ll see no difference.

Troubleshooting

If you’ve done everything right, but second.localhost resolves to the Main website, let’s troubleshoot. The very first location to check is .\src\temp\config.js file. This file contains sites variable with the array of sites and related hostnames to be used for the site resolution. The important fact is that a given file is generated at the build time, not runtime.

So, you open it up and see an empty array (config.sites = process.env.SITES || '[]') that means you just need to initialize the build, for example by simply removing and recreating the rendering host container:

docker-compose kill rendering
docker-compose rm rendering -f
docker-compose up rendering -d

Also, before running the above, it helps to check SXA Site Manager, which is available under the PowerShell Toolbox in Sitecore Desktop. You must see both sites and relevant hostnames there and in the correct order – make sure to move them as high as possible, as this site chain works by “first come – first served” principle.

Multisite

After rendering host gets recreated (it may take a while for both build and spinning up steps), check the site’s definition at .\src\temp\config.js again. It should look as below:

config.sites = process.env.SITES || '[{"name":"second","hostName":"second.localhost","language":""},{"name":"main","hostName":"main.localhost","language":""}]'

The amount of SXA client site records must match the records from SXA Site Manager. Now, running second.localhost in the browser should show you rendered home page of the second site.

Another technique of troubleshooting is to inspect middleware logs. To do so, create .env.local file at the rendering host app root (if does not exist yet) and add the debugging parameter:

DEBUG=sitecore-jss:multisite

Now, rendering host container logs will expose you the insights into how multisite middleware processes your requests and resolves site contexts, and sets site cookies. Below is a sample (and correct) output of the log:

sitecore-jss:multisite multisite middleware start: { pathname: '/', language: 'en', hostname: 'second.localhost' } +8h
sitecore-jss:multisite multisite middleware end in 7ms: {
  rewritePath: '/_site_second/',
  siteName: 'second',
  headers: {
  set-cookie: 'sc_site=second; Path=/',
  x-middleware-rewrite: 'https://localhost:3000/_site_second',
  x-sc-rewrite: '/_site_second/'
},
  cookies: ResponseCookies {"sc_site":{"name":"sc_site","value":"second","path":"/"}}
} +7ms

The above log is crucial to understanding how multisite middleware works internally. The internal request comes rewrites as <https://localhost:3000/_site_second where ‘second‘ is a tokenized site name parameter. If .\src\main\src\temp\config.js file contains the corresponding site record, site gets resolved and sc_site cookie is set.

If you still have the issues of showing up the Second website that resolves to Main website despite the multisite middleware log outputs correct site resolution, that may be likely caused by conflicting with other middleware processors.  This would be your number one thing to check especially if you have multiple custom middleware. Miltisie middleware is especially sensitive to the execution order, as it sets cookies. In my case, that problem was because Sitecore Personalize Engage SDK was registered through middleware and also programmed to set its own cookie, and somehow configured with multisite middleware.

In that case, you have to play with order constant within each conflicting middleware (they are all located under .\src\lib\middleware\plugins folder) with the following restart of a rendering host.

Resources Sharing

Since the multisite add-on leverages the same rendering host app for the multiple sites that use it, all the components and layouts TSX markups, middleware, and the rest of the resources become automatically available for the second site. However, that is not true by default for the Sitecore resources. We must assign at least one website that will share its assets, such as renderings, partials, layouts, etc across the entire Site Collection. Luckily, that is pretty easy to do at the site collection level:

Site Collection

For the sake of an experiment, let’s make Second website to use Page Designs from the Main site. After the above sharing permission, they are automatically available at /sitecore/content/Site Collection/Second/Presentation/Page Designs item.

Configuring the cloud

Once we make the multisite add-on function well, let’s make the same work in the cloud.

  1. First of all, check all the changes to the code repository, and trigger the deployment, either from Deploy App, CLI, or your preferred CI/CD
  2. After your changes arrive at XM Cloud environment – let’s bring the required changes to Vercel, starting with defining the hostnames for the sites:Vercel
  3. After you define the hostnames in Vercel, change the hostname under Site Grouping item for this particular cloud environment to match the above hostname configured earlier in Vercel.
  4. Save changes and smart publish Site Collection. Publishing takes some time, so please stay patient.
  5. Finally, you must also do Vercel full re-deployment, to force regenerating \src\temp\config.js file with the hostnames from Experience Edge published at the previous step

Testing

If everything is done right in the previous steps, you can access the published Second website from Vercel by its hostname, in our case that would be https://dev-second.vercel.app. Make sure all the shared partial layouts are seen as expected.

When testing 404 and 500 you will see that these are shared between both sites automatically, but you cannot configure them individually per site. This occurs because both are located at .\src\pages\404.tsx and .\src\pages\500.tsx of the same rendering host app and use different internal mechanics rather than generic content served from Sitecore throughout .\src\pages\[[...path]].tsx route. These error pages however could be multi-lingual, if needed.

Hope you find this article useful!

 

]]>
https://blogs.perficient.com/2024/08/26/full-guide-to-enabling-headless-multisite-add-on-for-your-xm-cloud-solution/feed/ 0 367793
Fixing an XM Cloud Deployment Failure https://blogs.perficient.com/2024/06/14/fixing-an-xm-cloud-deployment-failure/ https://blogs.perficient.com/2024/06/14/fixing-an-xm-cloud-deployment-failure/#respond Fri, 14 Jun 2024 18:49:22 +0000 https://blogs.perficient.com/?p=364321

Intro 📖

Last week, I noticed that deployments to Sitecore XM Cloud were failing on one of my projects. In this blog post, I’ll review the troubleshooting steps I went through and what the issue turned out to be. To provide a bit more context on the DevOps setup for this particular project, an Azure DevOps pipeline runs a script. That script uses the Sitecore CLI and the Sitecore XM Cloud plugin’s cloud deployment command to deploy to XM Cloud. The last successful deployment was just a few days prior and there hadn’t been many code changes since. Initially, I was pretty stumped but, hey, what can you do except start from the top…

Troubleshooting 👷‍♂️

  1. Anyone that has worked with cloud-based SaaS services knows that transient faults are a thing–and XM Cloud is no exception. The first thing I tried was to simply rerun the failed stage in our pipeline to see if this was “just a hiccup.” Alas, several subsequent deployment attempts failed with the same error. Okay, fine, this wasn’t a transient issue 😞.
  2. Looking at the logs in the XM Cloud Deploy interface, the build stage was consistently failing. Drilling into the logs, there were several compilation errors citing missing Sitecore assemblies. For example: error CS0246: The type or namespace name ‘Item’ could not be found (are you missing a using directive or an assembly reference?). This suggested an issue with either the NuGet restore or with compilation more broadly.
  3. Rerunning failed stages in an Azure DevOps pipeline uses the same commit that was associated with the first run–the latest code from the branch isn’t pulled on each rerun attempt. This meant that the code used for the last successful deployment was the same code used for the subsequent attempts. In other words, this probably wasn’t a code issue (famous last words, right 😅?).
  4. Just to be sure, I diffed several recent commits on our development branch and, yeah, there weren’t any changes that could have broken compilation since the last successful deployment.
  5. To continue the sanity checks, I pulled down the specific commit locally and verified that I could:
    1. Restore NuGet packages, via both the UI and console
    2. Build/rebuild the Visual Studio solution
  6. After revisiting and diffing the XM Cloud Deploy logs, I noticed that the version of msbuild had changed between the last successful deployment and the more recent failed deployments. I downloaded the same, newer version of msbuild and verified, once again, that I could restore NuGet packages and build the solution.
  7. Finally, I confirmed that the validation build configured for the development branch (via branch policies in Azure DevOps) was running as expected and successfully building the solution each time a new pull request was created.

At this point, while I continued to analyze the deployment logs, I opened a Sitecore support ticket to have them weigh in 🙋‍♂️. I provided support with the last known working build logs, the latest failed build logs, and the list of my troubleshooting steps up to that point.

The Fix 🩹

After hearing back from Sitecore support, it turned out that Sitecore had recently made a change to how the buildTargets property in the xmcloud.build.json file was consumed and used as part of deployments. To quote the support engineer:

There were some changes in the build process, and now the build targets are loaded from the “buildTargets ” list. The previous working builds were using the “.sln” file directly.
It looks like that resulted in the build not working properly for some projects.

The suggested fix was to specifically target the Visual Studio solution file to ensure that the XM Cloud Deployment NuGet package restore and compilation worked as expected. My interpretation of the change was “XM Cloud Deploy used to not care about/respect buildTargets…but now it does.”

After creating a pull request to change the buildTargets property from this (targeting the specific, top-level project):

{
  ...
  "buildTargets": [
    "./src/platform/Project/Foo.Project.Platform/Platform.csproj"
  ]
  ...
}

…to this (targeting the solution):

{
  ...
  "buildTargets": [
    "./Foo.sln"
  ]
  ...
}

…the next deployment to XM Cloud (via CI/CD) worked as expected. ✅🎉

After asking the Sitecore support engineer where this change was documented, they graciously escalated internally and posted a new event to the Sitecore Status Page to acknowledge the change/issue: Deployment is failing to build.

If you’re noticing that your XM Cloud deployments are failing on the build step while compiling your Visual Studio solution, make sure you’re targeting the solution file (.sln) and not a specific project file (.csproj) in the buildTargets property in the xmcloud.build.json file…because it matters now, apparently 😉.

Thanks for the read! 🙏

]]>
https://blogs.perficient.com/2024/06/14/fixing-an-xm-cloud-deployment-failure/feed/ 0 364321
Sitecore 10.4 is out and here’s all you need to know about it https://blogs.perficient.com/2024/05/01/sitecore-10-4-is-out-and-heres-all-you-need-to-know-about-it/ https://blogs.perficient.com/2024/05/01/sitecore-10-4-is-out-and-heres-all-you-need-to-know-about-it/#comments Thu, 02 May 2024 04:56:38 +0000 https://blogs.perficient.com/?p=362384

That was a decent gap since 1.5 years ago Sitecore previously released a feature-full version of their XM/XP platform, namely 10.3 was released on December 1st of 2022. That is why I was very excited to look through the newest release of the vendor’s self-hosted platforms and familiarize myself with its changes.

First and foremost, the 10.4 platforms could be exclusively obtained from a new download page which has moved to its new home at Sitecore Developer Portal. I recommend bookmarking that for the current and all future releases.

 

Release Notes

There is a list of impressive 200 changes and improvements coming along with official Release Notes. I recommend going through it especially paying attention to the Deprecated and Removed sections.

So, what’s New?

From the important features and changes, I’d focus on a few:

  • XM to XM Cloud Migration Tool for migrating content, media, and users from a source XM instance to an XM Cloud environment. This tool provides an aid for the routine and sometimes recurring back-end migrations, so our customers/partners can focus on migrating and developing new front-end sites.
  • xDB to CDP Migration Tool for transferring site visitor contact facets to Sitecore’s CDP and Personalize products, and also via Sitecore Connect to external systems. This provides the ability to interwork with or eventually adopt other SaaS based innovations.
  • New /sitecore/admin/duplicates.aspx admin folder page addressing the change in media duplication behavior (now, the blobs are in fact also duplicated) – run it upon the migration to 10.4 in order to change the media items accordingly.
  • Added a new Codeless Schema Extension module, enabling business users to extend the xConnect schema without requiring code development. If that on was available earlier – it could significantly boost xDB usage by marketers. It will be generally available in mid-May 2024.
  • Improved accessibility to help content authors with disabilities.
  • Sitecore Client Content Reader role allows access into CM without the risk of breaking something – it was a frequently requested feature.
  • It is now possible to extract data from xDB and transform the schema for external analytics tools such as Power BI.
  • GraphQL is enabled by default on the CM container instance in the local dev – which totally makes sense to me.
  • Underlying dependencies updated to the latest – SQL Server 2022, latest Azure Kubernetes Service, Solr 8.11, etc.

Containers

Spinning up Sitecore in local Docker containers used to be the easiest way of starting up. However, the most important fact you have to consider for a containerized setup is that base images are only available for ltsc2022 platform, at least for now. If you are a lucky one using a Windows 11 machine – you get the best possible performance running Sitecore in Process isolation mode. Otherwise, you may struggle with Hyper-V compatibility issues.

The other thing I noticed is that SitecoreDockerTools is simply set to pull the latest version which is 10.3.40 at the time of writing.

Also, Traefik image remains on one of the older versions (not versions 3.x of Traefik, but 2.9.8 which was even older before – v2.2.0) that do not support ltsc2022 and therefore still uses Hyper-V isolation. You can however fix that manually to have each and every image running fast in Process isolation mode. As always, it helps a lot to examine the list of available published images as your own exercise as some were standardized.

Compared to previous versions, this one seems to be lightweight, with no helpful PowerShell scripts for up  & down containers (so we use docker-compose directly) as well as clean-up scripts and others. As before, it supports all three default topologies – XP0, XM1 and XP1.

Sitecore Gallery Tips:

  • Tip 1: Sitecore Gallery has recently moved from MyGet https://sitecore.myget.org/F/sc-powershell/api/v2 to Sitecore hosted NuGet https://nuget.sitecore.com/resources/v2.
  • Tip 2: don’t forget to update the PackageManagement and PowerShellGet modules from PSGallery if needed, as below:
Install-Module -Name PackageManagement -Repository PSGallery -Force -AllowClobber
Install-Module -Name PowerShellGet -Repository PSGallery -Force -AllowClobber

Containers

If for some reason you cannot or are unwilling to use containers, there are other options: SIA and manual installations from a zip archive. Over the past years, I have created a tool called Sifon that is effectively better than SIA, because it can also install all the prerequisites, such as Solr and SQL Server of the required versions, along with downloading the necessary resources from the developer portal. I will add the support for 10.4 in the next few days or a week.

10.4 dashboard

Upon the installation, you will see the Sitecore Dashboard:

Sitecore 10.4 Dashboard

Version 10.4 now operates 010422 revision:

Version 10.4

SXA

This crucial module comes in the correspondent version 10.4 along with a newer 7.0 version of Sitecore PowerShell Extensions module. The biggest news about this module is that it now supports Tailwind, in the same way as XM Cloud does:

Tailwind

Conclusion

In general, time will prove what I expect this version to be – the most mature version of Sitecore, working faster and more reliably with the updated underlying JavaScript-dependent libraries. I am impatiently waiting for the hot things such as AI integrations and the delayed feature set promised to appear later the month in May 2024 to explore and share about.

]]>
https://blogs.perficient.com/2024/05/01/sitecore-10-4-is-out-and-heres-all-you-need-to-know-about-it/feed/ 1 362384
Fixing 404 Responses for Versioned Images in Experience Edge https://blogs.perficient.com/2024/04/25/fixing-404-responses-for-versioned-images-in-experience-edge/ https://blogs.perficient.com/2024/04/25/fixing-404-responses-for-versioned-images-in-experience-edge/#respond Thu, 25 Apr 2024 17:50:22 +0000 https://blogs.perficient.com/?p=361708

Intro 📖

My team and I recently ran into an issue while working on a Sitecore XM Cloud project that turned out to be pretty interesting. The issue had to do with images published to Experience Edge not loading as expected within certain renderings. The GET requests for these images in Experience Edge would return a 404 status code rather than the expected 200. This issue only seemed to happen for recently updated images and net-new images recently published to Experience Edge. Additionally (and confusingly), older, existing images (that weren’t recently published) still loaded as expected.

For context, our XM Cloud solution features a Next.js head application hosted on Vercel using Next.js version 12.2.5 and @sitecore-jss/sitecore-jss-nextjs version 21.0.0. Our solution exclusively uses the English language (en).

Investigation 🔎

After ruling out the typical things like making sure everything was published (and republished), checking associations to data source items, verifying the GraphQL response from the layout service,  and even clearing the Experience Edge cache, we opted to open a ticket with Sitecore. I wanted to see if other members of the Sitecore community had experienced something similar, so I asked a question in the Sitecore Slack community and eventually created a corresponding question on Sitecore Stack Exchange.

While the Sitecore ticket simmered, our team continued troubleshooting the image URLs. The URL coming down from the layout service was something like this (as an example):

https://edge.sitecorecloud.io/<tenant>/media/foo.jpg?h=495&iar=0&w=692&sc_lang=en ✅ (200)

Okay, cool; that URL resolved when browsed directly. Looking at the rendered markup on the problematic pages, it was noted that only those components using responsive images (reference) exhibited the issue. The Image component (from the @sitecore-jss/sitecore-jss-nextjs package) includes a property, srcSet, to support responsive images. The rendered <img> tag looked something like this:

<img ... width="692" height="495" class="img-responsive" loading="lazy" srcset="https://edge.sitecorecloud.io/<tenant>/media/foo.jpg?mw=991 991w" src="https://edge.sitecorecloud.io/<tenant>/media/foo.jpg?h=495&amp;iar=0&amp;w=692&amp;sc_lang=en">

The src attribute’s URL resolved as expected. However, the srcset URL attribute associated to the 991 width did not resolve as expected:

https://edge.sitecorecloud.io/<tenant>/media/foo.jpg?mw=991 ❌ (404)

Interestingly, after manually appending the sc_lang parameter to the URL, it did resolve as expected:

https://edge.sitecorecloud.io/<tenant>/media/foo.jpg?mw=991&sc_lang=en ✅ (200)

Why would sc_lang be required to fetch images when it hadn’t been previously? Well, Sitecore support had an answer: a bug fix affecting versioned media items had recently been deployed to Experience Edge. Looking at the XM Cloud changelog (here), I think this was the specific update; however, I’m not certain as there are several ostensibly adjacent entries in the changelog.

If languageEmbedding is set to never in the urlbuilder.config file, mediaItem entities now return the sc_lang parameter.

The change as explained by Sitecore support:

[In Experience Edge] When a media item is published, a MediaItem entity is generated by the following method on CM: Sitecore.ExperienceEdge.Connector.EntityGenerator.MediaDeliveryEntityGenerator.GenerateMediaEntity(...)

This MediaItem entity has multiple fields containing media URLs and paths.

For versioned media items, each of these fields is expected to contain the sc_lang parameter.

Net out: As of ~2 months ago, if you want versioned images published to Experience Edge to load correctly, you have to include the sc_lang parameter. Experience Edge does not default to en and does not include a fallback otherwise–if sc_lang isn’t present, you’ll get a 404.

That change, coupled with the fact that the Image component in the @sitecore-jss/sitecore-jss-nextjs package strips out the sc_lang parameter when resolving the various srcset URLs meant that our versioned images used as responsive images weren’t loading correctly on the front-end.

It was kind of a perfect storm considering the following:

  • The Experience Edge fix for versioned media items went out presumably at some point in late February.
  • Our development team and content authors hadn’t been updating, adding, or publishing media items for a while, so the issue wasn’t immediately noticed. There weren’t a lot of versioned images being published to Experience Edge, in other words.
  • The Image component’s srcSet property was being used which transformed the URL coming down from the layout service accordingly but, in doing so, stripped off the (now required) sc_lang parameter. 😑

The Fix ⛑

Armed with the knowledge that, moving forward, versioned images published to Experience Edge require the sc_lang parameter, I set about implementing a fix for our renderings using the srcSet property of the Image component. I ended up creating a small helper function to abstract away the query string parsing and conditional inclusion of the sc_lang parameter into the array passed into the srcSet property (as recommended by Sitecore support). The helper function looked like this:

export const buildSrcSetParams = (imageSizeParameters: ImageSizeParameters[] | undefined, image: ImageField): ImageSizeParameters[] | undefined => {
  let retVal = imageSizeParameters;
  if (!image?.value?.src) {
    return retVal;
  }
  const queryParams = new URLSearchParams(image.value.src.split('?')[1]);
  const scLangParam = queryParams.get('sc_lang');
  if (retVal && scLangParam) {
    // add sc_lang parameter
    retVal = retVal.map((isp) => ({
      ...isp,
      sc_lang: scLangParam,
    }));
  }
  return retVal;
};

Previously, the Image components looked something like this:

<Image field={props?.fields?.Image} srcSet={ [ { mw: 991 } ] } ... />

Using the new helper function, they looked like this instead:

<Image field={props?.fields?.Image} srcSet={buildSrcSetParams([ { mw: 991 } ], props?.fields?.Image) } ... />

Now, instead of the srcset URL resolving to:

https://edge.sitecorecloud.io/<tenant>/media/foo.jpg?mw=991 ❌ (404)

It resolved to:

https://edge.sitecorecloud.io/<tenant>/media/foo.jpg?mw=991&sc_lang=en ✅ (200)

Closing Thoughts 💭

Obviously, having to make, test, and deploy a code change to production in response to an Experience Edge bug fix wasn’t great. Arguably, Experience Edge would fall back to a configurable default language (e.g. en) or to an unversioned image, if available.

As of 4/17/2024, Sitecore support confirmed that this scenario was reproducible using version 21.6.0 of the @sitecore-jss/sitecore-jss-nextjs package and that the product team would be taking a further look.

 

On 4/23/2024, Sitecore support recognized this issue as a bug and issued a reference number: JSS-1902.

Sitecore’s SaaS products such as XM Cloud and Experience Edge are constantly evolving and improving, which is great; in fact, it’s a major selling point when it comes to adopting XM Cloud. Ideally, our team would have somehow known about or been informed of this breaking change ahead of time. How would we have done that? I’m not sure, other than perhaps by following the XM Cloud change log a bit more closely 😅.

]]>
https://blogs.perficient.com/2024/04/25/fixing-404-responses-for-versioned-images-in-experience-edge/feed/ 0 361708
Megan Jensen represents Perficient at SUGCON Europe 2024 https://blogs.perficient.com/2024/03/31/megan-jensen-represents-perficient-at-sugcon-europe-2024/ https://blogs.perficient.com/2024/03/31/megan-jensen-represents-perficient-at-sugcon-europe-2024/#respond Mon, 01 Apr 2024 03:53:33 +0000 https://blogs.perficient.com/?p=360901

SUGCON 2024 is coming!

Some of you involved into Sitecore community have come across of Megan Jensen‘s catchy personal branding – “MJ Knows Sitecore” (and she indeed knows it!). This year Megan will prove that to the entire community by presenting her topic “Optimizing for Headless: SEO Tips, Tricks, and Special Considerations for the New Composable World” at the event’s Marketing track.

MJ goes to SUGCON

Here’s what Megan going to present from the big stage at the conference:

One of a marketer’s worst nightmares is launching a gorgeous new website and watching in horror as the page rank and traffic plummet- something that can take a lot of time and work to recover from. With the dawn of Headless Architecture and Composable DXPs, the rules of optimizing a site have fundamentally changed. It’s crucial for both marketers and developers to understand how to maximize search engine page rank, site speed, performance, organic traffic, and user satisfaction. Headless is truly a game-changer with a lot of SEO upsides and crazy fast Lighthouse speeds. Now it’s time to revisit and modernize the guidelines and best practices we’ve been implementing for years. I will also share what you need to know for successful SEO when you build with Sitecore’s DXP products like Content Hub DAM, Content Hub One, Personalize, Order Cloud, and more.

The whole agenda is available from the SUGCON Europe website.

I always claimed SUGCON being the best community events in the Sitecore ecosystem. This year I plan to attend this event and here’s my proposed track of sessions suitable for a techie like myself:

Thursday April 11th

1. Opening Key Note by Dave O’Flanagan, a new CEO of Sitecore.

2. Elevating Digital Experiences with XM Cloud in the DXP Landscape by Pieter Brinkman.

  1. The next session is not disclosed and kept in secret. Well, let it be – I’ll share what was that afterwards.

4. The Future of Developer Experience by Liz Nelson. I absolutely adore Liz’s narrative and how she approaches the topics. Liz presented twice at Sitecore Headless Development User Group and each of her presentations were so fundamental!

5. Achieving Behavioral Personalization with XM Cloud Plus by Dylan Young. I can hardly miss any presentation related to XM Cloud.

6. Journey to the Other Side: Transitioning to Sitecore NextJs Framework by Jeroen Speldekamp and Frank van Rooijen.

7. It is all about APIs by Alex Doroshenko. Alex is the key professional standing behind Sitecore Demo Team for years, so he definitely knows all the nuances of the APIs and the caveats of integrations between them

Friday April 12th

9. Unveiling the future of Platform DXP and Managed Cloud by Colin te Kempel and Peter Kapsopoulos.

10. Building for Resiliency by Andy Cohen. I simply cannot miss a session from the architect of XM Cloud, especially taken into account how expressive Andy is as a presenter.

11. Sitecore Headless Software Development Kit for Astro by Anton Tishchenko.

12. I have XM Cloud why do I need Personalize? by Sarah O’Reilly. Previously I learnt a lot from Sarah’s videos on CDP and Personalize products and definitely the expectations bar is very high for this session.

13. Risk scenarios and how to secure webhooks in XM Cloud using Auth0 by OKTA by Sandeep Pote. Used to work with Sandeep once in past together, and I remember him very attentive to the details. That is especially important when goes along security and authentication.

14. Composable Search with Edge Webhooks and GraphQL by Chris Sulham. Chris is awesome presenter, I was his room captain at SUGCON NA 2023 and that was one of the brightest presentations we had at that event. Also it was the highest knowledge density I could ever receive in just 45 minutes. Definitely looking forward to it!

15. A Game of Publishing: Sitecore’s Publishing Vision by Ivan Lieckens. Who knows Sitecore products and integrations better than Ivan? This is my “must” session, as I expect to learn a lot of technical nuances from there.

16. Sitecore Search in the world of NextJs and DevOps by Sebastian Winslow and Jesper Balle. Search is the most vibrant SaaS product  from Sitecore (well, probably after XM Cloud itself), we already have a successful implementation with it, but the product is very much configurable and there’s so much more to learn.

17. How we migrated 7 sites in 6 weeks to XM Cloud and Netlify by Katharina Luger and Emanuel Popescu. While the MVC legacy remains heavy in he volumes, migration is the mostly curious topic these days. Once upon a time, I used to work with Emanuel and am very curious to learn from his experience.

18. Walk down memory lane with Klaus Petersen.

This list looks as an impressive blast of knowledge I am anticipating to learn from the top leaders of the industry. Last but not least, I am anticipating to meet plenty of my mates from the community and have discussions about everything around Sitecore industry.

 

]]>
https://blogs.perficient.com/2024/03/31/megan-jensen-represents-perficient-at-sugcon-europe-2024/feed/ 0 360901
Using conditions with XM Cloud Form Builder https://blogs.perficient.com/2024/03/21/using-conditions-with-xm-cloud-form-builder/ https://blogs.perficient.com/2024/03/21/using-conditions-with-xm-cloud-form-builder/#respond Thu, 21 Mar 2024 14:46:53 +0000 https://blogs.perficient.com/?p=359919

If you follow the release news from Sitecore, you’ve already noted the release of highly awaited XM Cloud Forms, which however did not have a feature of adding conditional logic. Until now.

The good news is that now we can do it, and here’s how.

See it in action

Imagine you have a registration form and want to ask if your clients want to receive the email. To do so you add two additional fields at the bottom:

  • a checkbox for users to define if they want to receive these emails
  • a dedicated email input field for leaving the email address

Obviously, you want to validate the email address input as normal and make it required. At the same time you want this field to only play on with a checkbook being checked, otherwise being ignored and ideally hidden.

Once we set both Required and Hidden properties, there is a hint appears saying that we cannot have them both together as it simply creates a deadlock – something I mentioned in my earlier review of XM Cloud Forms builder

01

So, how we achieve that?

From now on, there is an additional Logic tab that you can leverage to add some additional logic to your forms.

02

Let’s see what can do with it:

  • you can add new pieces of logic
  • apply multiple conditions within the piece of logic and define if all must comply or just any of them (logical “AND” and “OR”)
  • you can create groups of conditions to combine multiple OR logic clauses to work against the same single AND condition
  • for each condition, select a particular field of application from a dropdown
  • define what requirements you want to meet with it from another dropdown, which is content-specific:
    • strict match
    • begins or ends with
    • contains
    • checked / unchecked
    • etc.
  • not just having multiple conditional logic, you can also have multiple fields logic within a single condition with the same “and / “or”

Once all conditions are met, you execute the desired action against a specified field:

04

Coming back to a form with an optional email subscription defined by a checkbox, I created the following rule:

05

The conditional logic rules engine is very much intuitive and human-readable. I do not even need to explain the above screenshot as it is naturally self-explanatory. So, how does it perform? Let’s run Preview and see it in action.

When running the form as normal, we only see a checkbox disabled by default and can submit it straight away:

06

But checking Email me updates and promotions tick enables Email field, which is Required. The form won’t submit with an invalid email address until the checkbox is checked.

07

My expectation for the conditional logic was applying conditions for multipage forms at the page level. Say, I have a first page having some sort of branching condition, so that if the user meets it – it gets to pages 2 and 3, but if not – only page 4, with both branching ending up at page 5. Unfortunately, I did not find a way of doing that. Hopefully, the development teams will add this in the future, given how progressively and persistently they introduce new features. In any case, what we’ve been given today is already a very powerful tool that allows us to create really complicated steams of input user data.

 

]]>
https://blogs.perficient.com/2024/03/21/using-conditions-with-xm-cloud-form-builder/feed/ 0 359919
Decoding the Future of Development with Sitecore and Generative AI https://blogs.perficient.com/2024/03/06/decoding-the-future-of-development-with-sitecore-and-generative-ai/ https://blogs.perficient.com/2024/03/06/decoding-the-future-of-development-with-sitecore-and-generative-ai/#respond Wed, 06 Mar 2024 19:59:57 +0000 https://blogs.perficient.com/?p=358509

In Episode 2 of Sitecore Sessions our panel of Sitecore experts explored the transformative role of generative AI in the Sitecore community, its impact on development workflows, and the future of coding practices. You can watch the whole episode here:

 

A generated summary of the above video is below:

The Dawn of Generative AI in Sitecore Development

The integration of generative AI into the development process is revolutionizing the way Sitecore experts approach coding, component creation, and overall project efficiency. In a recent discussion among Sitecore aficionados, the potential and challenges of generative AI were thoroughly examined, revealing a future where developers wield AI tools to enhance productivity and creativity significantly.

The Power of Generative AI: A Developer’s New Best Friend

David San Filippo and Martin Miles, both seasoned Sitecore MVPs, along with Matt Conley and Drew Taylor from Perficient, shared their experiences with generative AI tools like GitHub Copilot. They likened the experience to wielding wizardry – where the right ‘incantation’ or command can produce remarkable results, from generating entire components to providing insightful solutions to complex problems.

However, they also stressed that while generative AI can drastically increase productivity, it doesn’t render developers obsolete. The need for human intelligence to guide, refine, and understand the context of AI-generated code remains paramount. The conversation highlighted that with great power comes great responsibility, emphasizing the importance of developers understanding how to effectively use AI tools without becoming overly reliant on them.

Enhancing Productivity and Creativity

The panelists shared specific instances where generative AI tools significantly boosted their productivity. For example, Martin Miles recounted his experience with the GitHub Co-Pilot program, where the AI generated a complete folder structure for a Next.js project, including Tailwind and TypeScript configurations. This example illustrated the potential of AI to handle mundane tasks, allowing developers to focus on more complex and creative aspects of their projects.

The Future of Sitecore Development with AI

Looking ahead, the discussion ventured into how generative AI could evolve within the Sitecore ecosystem. The panelists envisioned a future where AI tools could automate a significant portion of the development process, from creating XM Cloud components to generating entire site structures based on high-level prompts. This would not only speed up the development process but also open up new possibilities for personalized and dynamic content creation.

Challenges and Considerations

Despite the optimism, the conversation also touched on potential challenges, such as copyright issues and the need for developers to maintain a deep understanding of their codebases. The panelists underscored the importance of balancing AI-generated code with human oversight to ensure quality, security, and compliance.

Furthermore, the need for developers to adapt and learn quickly was highlighted as a critical skill in this evolving landscape. As AI tools continue to advance, staying abreast of new technologies and understanding how to integrate them into workflows will be essential for developers looking to thrive.

Conclusion

The integration of generative AI into Sitecore development is poised to redefine the role of developers and the nature of development work. By embracing these tools, developers can enhance their productivity, foster creativity, and navigate the challenges of modern web development more effectively. However, the journey with AI is just beginning, and the future promises even more exciting possibilities as these technologies continue to evolve.

]]>
https://blogs.perficient.com/2024/03/06/decoding-the-future-of-development-with-sitecore-and-generative-ai/feed/ 0 358509
XM Cloud Forms Builder https://blogs.perficient.com/2024/01/25/xm-cloud-forms-builder/ https://blogs.perficient.com/2024/01/25/xm-cloud-forms-builder/#comments Thu, 25 Jan 2024 13:13:49 +0000 https://blogs.perficient.com/?p=353871

XM Cloud Forms Builder released

Composable Forms Builder is now available with Sitecore XM Cloud. Let’s take a look at this one of the most anticipated modules for Sitecore’s flagship hybrid headless cloud platform.

Historically, we had an external module called Web Forms for Marketers that one could install on top of their Sitecore instance in order to gain the desired functionality of collecting user input. This module was later well reconsidered and reworked, later finding its reincarnation as Sitecore Forms, an integral part of Sitecore platforms since version 9. Customers enjoyed this built-in solution provided along with their primary DXP, however with the headless architecture of XM Cloud there were no CD servers any longer, therefore no suitable place for saving the collected user input. There was clearly a need for a SaaS forms solution, and this gap if finally filled out!

An interesting fact: until the release of Forms with XM Cloud the relevant composable solution for interacting with the visitors was Sitecore Send, and because of that Sitecore logically decided to derive XM Cloud Form module from Sitecore Send codebase (as it already had plenty of the desired features), rather than from legacy Sitecore Forms.

Sitecore XM Cloud Forms

So, what we’ve got?

The main goal was to release a new Forms product as SaaS solution that integrates with any custom web front-end.  The actual challenge was to combine the ultimate simplicity of creating and publishing forms for the majority of marketing professionals along with tailoring this offering optimized for typical headless projects. In my opinion, despite the complexities, it was well achieved!

Let’s first take a look at its desired/expected capabilities:

  • Template Library
  • Work with Components Builder
  • Use external datasources for pre-populating form
  • Reporting and analytics
  • Ability to create multi-step and multi-page forms
  • Conditional logic (not available yet)

One would ask, if there’s no CD server or any managed backend at all, where does the submission go into? There might be some SaaS-provided storage along with the required interface to manage the collected input. Incorrect! There’s none. It was actually a smart move by Sitecore developers who decided to kill two birds with one stone: save effort for not building a universal UI/UX with the tool that will hardly satisfy variable needs from such a diverse range of customers/industries, that would be hardly doable. But the second reason is more legit: avoid storing any Personally Identifiable Information data, so that it won’t be processed within XM Cloud, leaving particular implementation decisions to leave to customers’ discretion.

That is done in a very composable SaaS manner, offering you to configure a webhook, passing a payload of collected data to the desired system of your choice.

Webhooks

Upon the form submission, the webhook is triggered to submit the gathered data to the configured system, it could be a database, CRM, CDP, or whichever backend is for some form. Even more, you can have shared webhooks so that multiple forms can use the same configured webhook. Similarly to the legacy forms that submitted their data into xDB, the most logical choice would be using powerful Sitecore CDP for processing this data. However with webhooks, the use case of XM Cloud forms becomes truly universal, and if you combine it with Sitecore Connect – that could span to whichever integration gets provided by it.
Webhooks come with multiple authentication options, covering any potential backend requirement.

Let’s see it in action!

The editor looks and feels like XM Cloud Pages – similar styling, layout, and UI elements:
02 03

First, let’s pick up the layout by simply dragging and dropping it on a canvas. For simplicity, I selected Full Width Layout. Once there, you can start dropping fields to a chosen layout:

04
Available Fields:
  • Action Button
  • Email
  • Phone
  • Short Text
  • Long Text
  • Select (single dropdown)
  • Multi Select (where you can define the number of options, say selected 3 of 9)
  • Date
  • Number
  • Radio
  • Checkbox (single)
  • Checkbox Group
  • Terms & Conditions
  • reCAPTCHA
Besides input-capturing elements, you can also define “passive” UI elements from underneath Basic expander:
  • Text
  • Spacer
  • Social Media – a set of clickable buttons to socials you define
  • Image, which has a pretty strong set of source options:
Media Upload options
Look at the variety of configuration options on the right panel. You can define:
  • Background Color within that field – transparent is the default one. You can even put a background image instead!
  • Settings for the field box shadows which also define Horizontal and Vertical Lengths, Blur and Spread Radiuses, and of course – the shadow color
  • Help text that is shown below and prompts some unobvious guidance you’d like a user to follow
  • For text boxes, you can set placeholder and prefill values
  • The field could be made mandatory and/or hidden by the correspondent checkboxes
  • Validation is controlled by a regex pattern and character length limit
  • Additionally, you can style pretty everything: field itself, label, placeholder, and help text, as well as set the overall padding to it

Please note, that at the current stage, the edited form is in a Draft state.  Clicking Save button suggests you run your form in a Preview before saving, and that was very helpful – in my case, I left the Full Name field as a hidden field by mistake, and preview mode immediately showed me that. After fixing the visibility, I am good to go with saving.

The Forms home screen shows all the available forms. To Activate, I need to create a Webhook first, then assign it to the form. In addition, you define the action you want to do upon webhook submission – redirect to URL, display success message, or maybe – do nothing, as well as configure failure submission message.

This time Activate button works well and my form is listed as Active. From now on you cannot edit fields anymore and you cannot change the status back from Active. Therefore always verify your form in Preview before publishing.

Weirdly, you cannot even delete a form in Active status. What you can do however is a duplicate active form into a draft one, and you could go on with fields editing from there.

Forms listing

Testing Form

The most obvious desire at this stage is to real-test your form before usage. And luckily developers took care of that as well.

Testing webhook
I also created a webhook catcher with Pipedream RequestBin. On my first go, I faced a deadlock being unable to submit the form for the test. The reason for this was that I mistakenly checked both the Hidden and Required checkboxes on a field and could bo progress from there. Even the validation message did not show on a hidden field. Another mistake was that I overlooked that on Preview and published form into the active state. Hopefully, developers will find a solution to it sooner rather than later.

I give it another try to test how validation works:

Validation in action

Once validation passes, Test Form Submission dialog shows you the JSON payload as it goes out along with HTTP headers supplied with this webhook request. Let’s hit Submit button and see the confirmation – I chose to see a confirmation message that shows up.

Webhook catcher shows all my submitted data along with HTTP headers, everything was sent and received successfully!

webhook catcher

Multipage Forms

Multipage Forms are supported and that is impressive. Pay attention to the Add Page link button in between page canvases. Once activated, it also enforces Next button on non-final page canvases that trigger switching to the next form page:
20

What’s Next? Pages Editor!

Let’s use this newly created form from XM Cloud pages. Please note a new section called Forms under the Components tab. That is where all of your active forms reside. You can simply drag-drop this form to a desired placeholder, as you normally do in the Pages editor.

Consume Forms from Pages Editor

Please note: you must have your site deployed to an editing host running on Headless (JSS) SDK version 21.6 or newer to make it work – that is when XM Cloud Forms support was added. In other case, you face this error:

BYOC error before SDK 21.6

Experience Editor and Components Builder

Surprisingly, created forms are available from Components Builder:
Forms in Components Builder
However, Experience Editor does not have a direct way of consuming XM Cloud Forms. I tried the following chain of steps in order to make it work:
  1. Create and Activate a new form from Forms editor
  2. Consume it from the Components builder into a new component using BYOC, then publish this component
  3. Open Pages app, find the component with an embedded form you’ve built at step (2) and drop it to a page, then publish
  4. Open that same page in Experience Editor

Live Demo in Action

As you know, often a video is worth a thousand words, so here it is below. I’ve recorded the whole walkthrough from explaining to showcasing it all in action up to еhe most extreme example – when you create and publish a form, then consume it from the XM Cloud Components builder, making the part of a composite component, which in turn is used Pages editor to put down on a page which also opens up successfully in the Experience Editor. Unbelievable, and it all functions well. Just take a look yourself:

 

Developers Experience

As developers, how would we integrate forms into our “head” applications? That should work with a Forms BYOC component for your Next.js App coming out of the box with SDK. I spotted some traces of XM Cloud forms a while ago as a part of Headless JSS SDK 21.6.0 a while ago when it was in a state of “Canary” build. Now it got released and among the features, one can see an import of SitecoreForm component into the sample next.js app, as part of pull request merged into this release.

The documentation is available here, but … everything is so absolutely intuitive, that you hardly need one, don’t you?

Template Library

It is worth mentioning that XM Cloud Forms contains a Template Library handful of pre-configured forms you can use straight away or slightly modify as per your needs. There is an expectation it will grow with time covering any potential scenario one could ever have.
Template Library

Licensing

Since Forms are bundled into XM Cloud they’re included with every XM Cloud subscription.

What is missing?

  • file upload feature is not supported – webhooks alone are not sufficient to handle it
  • ability for customization and extension – hopefully, it comes as there’s an empty section for custom fields

Hopefully, the product developers will implement these and more features in the upcoming releases. But even with what was released today, I really enjoyed XM Cloud Forms builder!

]]>
https://blogs.perficient.com/2024/01/25/xm-cloud-forms-builder/feed/ 2 353871
Healthcare, HIPAA, Sitecore and BAAs https://blogs.perficient.com/2024/01/24/healthcare-hipaa-and-sitecore-and-baas/ https://blogs.perficient.com/2024/01/24/healthcare-hipaa-and-sitecore-and-baas/#respond Wed, 24 Jan 2024 15:32:37 +0000 https://blogs.perficient.com/?p=354630

Before I begin, I just want to caveat everything with the fact that HIPAA is a complex regulation open to interpretation, and in the end your legal and compliance teams need to be comfortable with how you handle data and the risk associated with those methods. With that being said, I’ve had a lot of experience with healthcare companies, both payers, providers and life sciences organizations dealing with HIPAA regulations over the last decade and having seen the direction Sitecore has been moving to support healthcare companies, I wanted to share some of that knowledge and information.

Defining Protected Health Information (PHI)

When it comes to evaluating your DXP solutions against HIPAA, how you collect, process, and manage PHI is the central concern. Defining PHI is actually more complex than you may think. The HIPAA privacy rule defines PHI as individually identifiable health information that is transmitted or maintained in any form or medium (electronic, oral, or paper) by a covered entity or its business associates, excluding certain educational and employment records.

But what does identifiable mean? There was debate on whether an IP address was identifiable until HHS made it clear that it was in a memo about how website visitor tracking data is to be handled was published in late 2022.  The other part of the definition is what constitutes “health information.” While there could be clear cut cases when visitors are filling out forms on your website when they are providing “health information,” there could be other cases that are less clear cut: for example using the find a doctor feature of your site to identify a specialist, or browsing conditions or specialty related pages on your site.

There is probably not going to be clear cut guidance on how to answer these questions from HHS, so organizations will be left to evaluate the risk of managing this kind of data themselves. This is why more cautions organizations have removed analytics tracking tools like google analytics. But it’s important to realize it’s not just the software we choose that allows us to deliver HIPAA compliant solutions to patients.

There really isn’t such a thing as HIPAA compliant software.

HIPAA is a set of rules around how to process and deal with sensitive health data. There are plenty of details on how those rules guide organizations on HHS’s website.

While software can help organizations adhere to those rules, it is still up to the organization to put the processes in place to remain HIPAA compliant. Take Sitecore XP as an example. It supports an extensible “Experience Database” component that tracks visits to websites it hosts and allows you to store data you capture from visitors to enable personalization. While Sitecore XP provides the capability to manage and secure that data, it is up to the organization using that software to do it properly using the available tooling and configuration as well as putting the necessary processes in place to manage that data in order to be HIPAA compliant.

Things get more complicated when you have partners or vendors with access to systems that manage health data.  This is when you need to ensure you have a Business Association Agreement (BAA) contract in place. The BAA provides assurances that the “associate” organization will protect the PHI of your patients, and you require them to take specific actions and restrict how they may use or disclose PHI. Perficient typically signs BAA’s with clients where the project work will give them access to such data as part of a project delivery.

Sitecore’s Platform DXP Offerings including Sitecore XP are installed software, meaning you take Sitecore’s software and install it on your servers. Those servers could be on premise (in your own network) or in the cloud, but Sitecore never had access to your environments or your data. This means you do not need a business associate agreement (BAA) with Sitecore, since they don’t have access to your data.

Managed Cloud

Sitecore Managed Cloud offering consists of the Platform DXP offering deployed to a dedicated Azure subscription that is managed by Sitecore. Because Sitecore actively manages the environment, they have access to the underlying data in the system. If you are using Sitecore to store or manage health data, Managed Cloud is probably not going to meet your needs as Sitecore does not sign BAA agreements for its managed cloud offering. There was a time a couple of years ago, when Sitecore was moving toward supporting this, but as it began to pivot to focus on its composable SaaS offerings, it became clear that this was not a focus for them.

Sitecore’s SaaS Offerings

Because Sitecore’s composable solutions are all delivered in a SaaS model, using them to manage any protected health information would require Sitecore to sign a BAA. The good news is that Sitecore has indicated that it will be soon support healthcare customers by signing BAA’s around some of their offerings, namely Sitecore Personalize and CDP starting in July 2024 and XM Cloud by the end of the year. Not only has this been communicated from a general Sitecore perspective, but we have clients who have signed agreements with Sitecore to have them enact a BAA for these products within these timelines.

The relationship between XM Cloud and Sitecore CDP and Personalize make the timing of this support really interesting. XM Cloud includes a “light” version of Sitecore Personalize in XM Cloud to support the Page level personalization and analytics capabilities of XM Cloud. As a matter of fact, if a client has a license to the full versions of Sitecore Personalize and CDP they can use the same conditions and segments they define in Personalize as XM Cloud personalization rules. They can even view their XM Cloud personalization experiences and analytics directly in Sitecore Personalize and CDP. This is because under the covers it is actually using the same instance.

Given this relationship between the products, if you have a license for Sitecore Personalize and a BAA in place with Sitecore in July, you should be covered with your XM Cloud solution because the rest of XM cloud only deals with content management and should not house any data that could be classified as “protected health information.” To illustrate this, I put together the following diagram:

Xm Cloud Baa

With a BAA on Sitecore Personalize that covers the use of those related features in XM cloud, healthcare organizations can target going live on the platform starting on July 1st. All other data is managed in SaaS services that do not house or touch any protected health data.

You’ll also note that “Vercel” is depicted in the diagram as well. This is an important consideration as your front-end application is what serves the experience to your users, and data typically flows through the front-end application, including any logged visitor activity in the form of IP addresses and pages visited. Vercel has indicated that it will start signing BAA’s as early as March of this year. I have heard similarly that Netlify is also open to signing BAA’s, giving us multiple options for hosting our front-end applications within a headless architecture.

Without that in place, you would have needed to host the front end site on your own, either in Azure or AWS, both of which support healthcare organization’s needs through BAA’s.

Beyond XM Cloud and Sitecore Personalize

It’s important to note that there are other products that you may need to drive your digital experiences, and Sitecore has nine other SaaS products which probably won’t support BAA any time soon. Search is probably the most glaring gap, as most sites will require search capabilities as part of the experiences they deliver. While there are several options, we have a ton of experience with Coveo, which signs BAA’s and even has a HIPAA version of their platform.

Implementation Considerations

As mentioned earlier, software alone does not make you HIPAA compliant. Having a BAA in place with vendors that manage that software does not make you HIPAA compliant either. But with these tools and agreements, you can implement HIPAA compliant solutions for your patients. Don’t forget to fully take into consideration how you manage protected health information across your solution. Think through how you manage identity and access, how APIs are secured and all the tertiary use cases that can expose data and create vulnerabilities. Do not take it for granted that because the software can be used in a compliant way, that it will prevent you from using it incorrectly.

Perficient is here for you

At the time of this writing (January 2024), Sitecore has a clear path to supporting healthcare organizations interested in using their flagship DXP solution including both XM Cloud, Sitecore Personalize and Sitecore CDP. These tools can help drive future proof rich experiences across multiple channels while protecting the data you need to drive those experiences.

If you are looking for help in navigating HIPAA, Sitecore’s offerings and your DXP needs, please reach out to me.  You can find me on LinkedIn, Twitter or fill out our contact form.

]]>
https://blogs.perficient.com/2024/01/24/healthcare-hipaa-and-sitecore-and-baas/feed/ 0 354630