I recently wrote a console app to migrate data from Drupal to Kentico Xperience 13 using the Xperience APIs.
As part of this, I was required to recreate pages in Xperience so that they had the same URL as their counterpart in Drupal.
My approach was to, for each page in my Drupal data source, create a new instance of the TreeNode
object and set its values based on the values stored for that page in Drupal.
I also set the NodeAlias
value of the TreeNode
object at this point so that it matched the page's "page alias" (aka slug) in Drupal.
I then called Insert() on my object instance to create the page in Xperience.
Page URLs work differently in Xperience 13
Now in the old days of Kentico CMS, this would have been good enough as each page's URL was based off of its NodeAliasPath
but in Xperience 13 the URL of a page is controlled separately and is managed by an editor via the URLs tab in Kentico.
I found that when I called Insert()
, the slug was being auto generated based on the DocumentName
of the page, rather than just copying the NodeAlias
.
I now needed a way to update the slug.
In search of a solution for updating the slug
Off I went in search of slugs (that's the first time I've ever said that...I promise) and I found they were stored in the PageUrlPathUrlPath
column (try and say that 10 times in quick succession) within the CMS_PageUrlPath
database table with a foreign key to the NodeID
of the page in question.
My immediate thought was that I could retrieve the relevant PageUrlPathInfo
object, update the slug et voilà! But no luck.
It's then that I noticed there is a hash stored against each PageUrlPath
record and that this must be updated in conjunction with updating the slug.
Usually when you see a hash against a record in Kentico, it means there's some helper method somewhere which you can use to update the record and manage the hash at the same time. It's just a case of finding this helper method.
Having exhausted my friends Google and Kentico devnet, I guessed that the underlying aspx page which is providing the functionality for editors to update the slug in the URLs tab must be using such a method.
How to update the URL slug
Having found said aspx page in the CMS Visual Studio project CMSModules/Content/CMSDesk/Properties/Urls.aspx
I followed the code through and found the PageUrlPathSlugUpdater
which does exactly the job I needed.
Here's the code to update the slug:
PageUrlPathSlugUpdater pageUrlPathSlugUpdater = new PageUrlPathSlugUpdater(page, Culture);
IEnumerable<CollisionData> collidingPaths;
pageUrlPathSlugUpdater.TryUpdate(newSlug, out collidingPaths);
if (collidingPaths.Count() == 0)
{
// Slug was updated
}
else
{
// Slug wasn't updated
}
Pros and Cons of separating page URL from NodeAliasPath
One of the limitations of the NodeAlias
property is that there is a 70 character max limit. This was a problem as some of the page aliases for pages in Drupal were longer than this so they were being truncated.
Luckily, there is no such limit on URL slugs, so I was able to replicate the URLs from Drupal into Kentico without issue.
One disadvantage now is that when you retrieve the data for a page in code, you now need to, in addition, use PageUrlRetriever.Retrieve(nodeAliasPath)
to get the URL of the page, which generates another (if not more) calls to the database. Previously, you just needed to ensure you were retrieving the NodeAliasPath when getting the page data.
There's no way to retrieve URLs for pages in bulk either, so you can imagine in code that creates, say, website navigation where you are in a foreach loop scenario, some developers may end up calling this method for each iteration and, subsequently, generating a tonne of SQL queries.
Luckily there is a way to get around this. More on that in my next post.
Top comments (0)