Let's say you have a requirement to load items into Sitecore from an external source. And each item would represent a page complete with a title and content and other fields. Trouble is, your pages are built with SXA and things like the content need to go in a Rich Text component stored in the Data
folder under each component. How do you do it?
With ease, as it turns out.
Setup
The Branch Template
The first thing that we will need is a Branch Template, one that has all the appropriate components already loaded onto a page that they will be associated with.
In our case, we have a Two Column Content Page with an associated Rich Text component added into the Data folder. Nothing crazy.
Root Node For Content
Now we need a location for where the content can be loaded into. In our case, we're just loading it into this Articles
subfolder.
Coding The Import
Creating The Item
Now, I'm not going to focus on how the content is obtained, but rather what we do with it after. So in our case, we've imported the data via an API, obtained the JSON data and converted it to a List<Article>
.
Perhaps we even have an additional requirement that each article is loaded into a subfolder designated by the year that it was published and that the Name
be associated with the article's ID from the source. Your requirements may vary.
You might be asking, why not use a Bucket
? Well, if we loaded into a bucket, in my experience, the synch process actually disassociates the SXA components stored in the Data
folder from the item and creates a mess. Hence why we're going about it this way.
public void CreateItems(List<Article> articleList, Item rootItem, Database db)
{
//Disable the indexing
IndexCustodian.PauseIndexing();
// Disable security to allow for importing
using (new SecurityDisabler())
{
if (db != null && rootItem != null)
{
// Get the item of the branch template
BranchItem template = db.GetItem(new ID(Templates.Article.TemplateID));
if (template != null)
{
foreach (Article article in articleList)
{
// Ensure we are generating a safe to use name.
var itemName = ItemUtil.ProposeValidItemName(article.Identifier);
// Get year of article to know where it should go
// 'GetYearFolder' returns the item of the folder - if it doesn't exist, it creates it
DateTime release = GetReleaseDateTime(article);
var year = release.Year.ToString();
var parentItem = GetYearFolder(rootItem, year, db);
// Check if article already exists
Item doesItemExist = db.GetItem(parentItem.Paths.Path + "/" + itemName);
if (doesItemExist != null) continue;
// Create item
Item newItem = parentItem?.Add(itemName, template);
// Update item and related items
UpdateItem(newItem, article, db);
// Update the Rich Text
UpdateRichText(newItem, article, db);
}
}
}
}
// Resume indexing
IndexCustodian.ResumeIndexing();
}
Next up we will look at the code for updating the primary item, i.e. article.
Updating The Item
Here's we're simply updating the appropriate fields for each article. In our case we have to update the Title
, Content
(which we're using to store the summary of the article to improve Solr search results), Aritlce ID
, and Date
. With regard to the Content
field; due to the fact we're storing our main body of the article in an SXA component in the Data folder, Solr by default doesn't pick that up. We would have to create a computed field or extension to update the appropriate Solr index information.
public void UpdateItem(Item item, Article article, Database db)
{
using (new SecurityDisabler())
{
//Enter into the item editing state
item.Editing.BeginEdit();
//Now you can edit the item field values as belwo
item["Title"] = article.Title;
item["Content"] = article.Summary;
item["Article ID"] = article.Identifier;
item.Fields["Date"].Value = GetReleaseDateTime(article).ToString("yyyyMMddTHHmmssZ");
//once you are done with the editing, come out of editing satate then
item.Editing.EndEdit();
}
}
If you're curious about what is happening inside GetReleaseDateTime
I've attached that as well, but it's more of a proprietary function based upon the format of the date that's coming in.
private DateTime GetReleaseDateTime(Article article)
{
string releaseDateStr = article.ReleaseDateTime; //2021-09-23T17:19:24Z
DateTime releaseDateTime = DateTime.ParseExact(releaseDateStr, "yyyy-MM-dd'T'HH:mm:ss'Z'", CultureInfo.InvariantCulture);
return releaseDateTime;
}
Next up is updating the Rich Text
item in the Data
folder.
Update The Rich Text Component
As we are using the Branch Template
as the "template" for which to generate each item from, and it already has a Rich Text item in the Data folder, each item we create will also have that same item with the same name. Hence we can update it in the following manner.
public void UpdateRichText(Item item, Article article, Database db)
{
using (new SecurityDisabler())
{
// Point to the Rich Text item
Item rtItem = db.GetItem(item.Paths.Path + "/Data/Rich Text");
//Enter into the item editing state
rtItem.Editing.BeginEdit();
// Add the article content
rtItem["Text"] = article.Content;
rtItem.Editing.EndEdit();
}
}
Result
We can run this import in a number of ways, i.e. through Tasks
, Api Controllers
, etc but we can cover that in another article. I want to show you how it looks after it's run.
You can see here that each article is loaded into a subfolder, designated by the year of the article and the Rich Text item is loaded with the appropriate content. In my case, "Test content".
And that's all it takes. Nothing crazy. You certainly might have more fields to fill or might have a more complicated sub-structure or heaven forbid a more complicated API interface to get the data. The main thing is, it's very easy to dynamically generate items utilizing page branches and having them associated with SXA components with the corresponding information.