I am trying to make a scheduled job that will remove expired content from content area or xhtml string to clean up the edit mode of unused blocks, but not move it to the recycle bin because maybe someday it will be used again.
I found many posts here on World and on various blogs about getting the references to specified content but nothing that would show me the way to actually remove them. I am close but something is still missing. I also think there is more cleaner way of sloving this but couldn't find any Repository or Service that would clean up list of ReferenceInformation returned by GetReferencesToContent method.
Here is the code:
var contentLoader = ServiceLocator.Current.GetInstance<IContentLoader>();
var contentTypeRepository = ServiceLocator.Current.GetInstance<IContentTypeRepository>();
var contentRepository = ServiceLocator.Current.GetInstance<IContentRepository>();
var contentModelUsage = ServiceLocator.Current.GetInstance<IContentModelUsage>();
var contentType = contentTypeRepository.Load<MyBlockType>();
var contentUsages = contentModelUsage.ListContentOfContentType(contentType);
// get distinct content references without version
var contentReferences = contentUsages
.Select(x => x.ContentLink.ToReferenceWithoutVersion())
.Distinct()
.ToList();
// fetch data from DB
var instances = contentReferences
.Select(contentReference => contentLoader.Get<IContent>(contentReference)).Where(x => (x as IVersionable)?.StopPublish < DateTime.Now)
.Select(x => x.ContentLink);
foreach (var contentReference in instances)
{
//I assume that if the next collection of ReferenceInformation could be cleared and saved as such, it would solve the problem without looping through all page properties
var usages = contentRepository.GetReferencesToContent(contentReference, true);
foreach (var usage in usages)
{
var original = contentRepository.Get<ContentData>(usage.OwnerID, usage.OwnerLanguage);
var clone = (ContentData)original.CreateWritableClone();
var oldLink = contentRepository.Get<BlockData>(usage.ReferencedID).ToString(); // to be replaced with string.Empty if found in XhtmlString
foreach (var property in content.Property.Where(x => x.PropertyValueType == typeof(ContentArea) || x.PropertyValueType == typeof(XhtmlString)))
{
if (property.PropertyValueType == typeof(ContentArea))
{
if (((ContentArea)original[prop])?.Items?.Any(x => x.ContentLink.CompareToIgnoreWorkID(usage.ReferencedID)) ?? false)
{
//remove content area item with the contentLink as same as expired content.
}
}
if (prop.PropertyValueType == typeof(XHtmlString))
{
//parse string and replace with string.Empty if content reference to expired content was found.
}
//Here I've tried to save, check out, publish, force new version, bitwise action on enum (but this enum was not marked with [Flags] attribute so in reality not sure if it even should work.
contentRepository.Save((IContent)clone, SaveAction.Publish, AccessLevel.NoAccess);
//without next piece of code GetReferencesToContent in second for each loop returns usage as it was never tampered with.
//on top of all, ContentSoftLinkIndexer is marked as Internal API and could be changed without notice.
var contentsoftlinkindexer = ServiceLocator.Current.GetInstance<ContentSoftLinkIndexer>();
var contentSoftLinkRepo = ServiceLocator.Current.GetInstance<IContentSoftLinkStatusService>();
var links = contentsoftlinkindexer.GetLinks(content).Where(x => !x.ReferencedContentLink.CompareToIgnoreWorkID(contentreference)).ToList();
contentSoftLinkRepo.SaveLinkStatus(links);
//This resets usage of the expired content but doesn't remove it from content Area in edit mode
}
}
}