Hi. Super easy fix would be to just setup a 301 redirect for the page you are deleting.
-John
And to further extend on John's advice, this job can become even easier if you install and use the Geta 404 Handler. https://github.com/Geta/404handler it is one of the most widely used Epierver community addons, and will enable you or the customer to do all of this type of management through the interface without needing to do any development work.
A late answer but perhaps someone else migth get use of it. Since links witin CMS are stored in a format based on the ContentGuid one trick could be to first get the guid of the page that is to be deleted. Then the delete the page (you have to really delete it, not just moving it to wastebasket). Then create a new page but before saving it assign IContent.ContentGuid to the same guid that the previous (now deleted) page had.
The trick is that since the new page now has the same Guid based identifier as the previous one had then all other pages that was previously linked to the old page ill now link to the new page automatically (since the ContentGuid is the same).
I've done following with success:
First get all references of the page you're deleting:
var repository = EPiServer.ServiceLocation.ServiceLocator.Current.GetInstance<IContentRepository>(); var referenceList = repository.GetReferencesToContent(new ContentReference(oldPageId), true)
Then loop over it and for each page/block loop over it's properties, change all places where there's a reference to old page and save.
var oldPageId = 5; var newPageId = 20; foreach (var reference in referenceList) { var content = _repository.Get<IContent>(reference.OwnerID); var original = _repository.Get(reference.OwnerID, reference.OwnerLanguage); var clone = (ContentData)original.CreateWritableClone(); foreach (var property in content.Property) { var prop = property.Name; if (typeof(ContentReference) == type && (ContentReference)original[prop] == new ContentReference(oldPageId)) { clone[prop] = new ContentReference(newPageId); } else if (typeof(PageReference) == type && (PageReference)original[prop] == new PageReference(oldPageId)) { clone[prop] = new PageReference(newPageId); } } _repository.Save((IContent)clone, SaveAction.Publish, AccessLevel.NoAccess); }
I would do this inside a Controller that I access protect with something like this:
[GuiPlugIn( Area = PlugInArea.AdminMenu, Url = "/ReplaceReferences", DisplayName = "Replace references")] [Authorize(Roles = "CmsAdmins, WebAdmins, Administrators")]
I've also replaced references inside XHTML fields, let me know if you need code for this as well. :)
Hello Goran. I'm having issues updating old references all over the website (including XHTML). Can you please provide your solution for XHTML please? :)
Also, I was able to update some of the references but somehow if I try to delete the old page, I still got the popup alerting me that it has references to it even if those blocks were updated. Any idea why this is happening?
Here's code for XHTML and to update references as well. Darren helped me with reference updating by altering the save action (https://world.episerver.com/forum/developer-forum/-Episerver-75-CMS/Thread-Container/2018/9/publishing-from-code-doesn39t-update-references/), so please vote up his answer if it's working. It didn't for me though.
var oldPageId = 5; var newPageId = 20; foreach (var reference in referenceList) { var content = _repository.Get<IContent>(reference.OwnerID); var original = _repository.Get(reference.OwnerID, reference.OwnerLanguage); var clone = (ContentData)original.CreateWritableClone(); var oldLink = _repository.Get<PageData>(new ContentReference((oldPageId)))).LinkURL; var replaceLink = _repository.Get<PageData>(new ContentReference(newPageId)).LinkURL; foreach (var property in content.Property) { var prop = property.Name; if (typeof(ContentReference) == type && (ContentReference)original[prop] == new ContentReference(oldPageId)) { clone[prop] = new ContentReference(newPageId); } else if (typeof(PageReference) == type && (PageReference)original[prop] == new PageReference(oldPageId)) { clone[prop] = new PageReference(newPageId); } else if (typeof(XhtmlString) == type && ((XhtmlString)original[prop]).ToHtmlString().Contains(oldLink)) { var html = ((XhtmlString)original[prop]).ToHtmlString().Replace(oldLink, replaceLink); (XhtmlString)clone[prop] = html; } } var saveAction = SaveAction.CheckIn | SaveAction.Publish | SaveAction.ForceNewVersion; _repository.Save((IContent)clone, saveAction, AccessLevel.NoAccess); }
Thank you Goran. Your solution works like a charm. The problem with references still found after update remains. I checked the other thread and none of them are working for me.
Awesome! :)
It might be a bug in Episerver 11. Make sure to follow the other thread. I will update it when I have new findings. :)
I made it work with some guidance from Johan here: https://world.episerver.com/forum/developer-forum/-Episerver-75-CMS/Thread-Container/2018/9/publishing-from-code-doesn39t-update-references/. And you can also mark my reply as Answer. :)
Hey Goran. I just found out a bug here. When the page you want to migrate from has a shortcut set, the LinkURL returned by episerver will be the link of the page that is redirected to. This means that no xhtml content will be updated.
Also, i found out that the internal link used by episerver to set the references is actually based on the Guid of the PageData. So, i was able to create this small workaround
oldLink = "/link/" + sourcePage.ContentGuid.ToString().Replace("-", "") + ".aspx"; replaceLink = "/link/" + targetPage.ContentGuid.ToString().Replace("-", "") + ".aspx";
This way, the oldLink will be the link used in xhtml to reference the shortcut page, not the link of the shortcut target.
Here is what I had before:
No shortcut set: /link/4ca5846ddb63408a9715db78932790de.aspx
Shortcut set: /link/5c99680f22e9491cbb4492260ba3bc28.aspx
Thanks Alex! That is indeed better, to handle the shortcuts as well. Good job! :)
Hi Loic!
Like the code shows you must iterate over all properties and check each one.
foreach (var property in content.Property)
I'm trying to update all the references to a page we'd like to delete to another page, in order not to break any link on the website once the page is removed.
In order to do so, I created a scheduled job where I first get all the pages and blocks with a reference to the page to delete, using the GetReferencesToContent method, but I'm then unable to update the property as I don't know which property of the element contains the reference.
Is there a way to achieve that properties update or is there an easier way to update the links to a page without having to use a scheduled job or doing the modification manually ?
Thanks in advance !
Loïc