Organize page content into folders dynamically

Why do we need organized content into folders or containers?

  • As your content tree grows, it gets more difficult to locate items and performance can decrease.
  • All the items inside the folder or container are automatically organized in a logical format.

When to use dynamic folders?

  • When you need to manage large number of items in a content tree.

How to Configure dynamic folders?

  • By implementing the following code 😊

Inherit your container page type from BucketBasePageData

public class BucketBasePageData : BasePageData
{
    [Required]
    [Display(Name = "Date Pattern", GroupName = TabNames.Bucket, Order = 10)]
    public virtual string DatePattern { get; set; }

    public override void SetDefaultValues(ContentType contentType)
    {
        base.SetDefaultValues(contentType);

        DatePattern = "yyyy/MM/dd";
    }
}
[ContentType(DisplayName = "Folder",
    GUID = "8DAA5DE9-CF25-4FA5-8EFD-5CAFB3D4D40E",
    Description = "Folder to help organize content.",
    AvailableInEditMode = true)]
[ContentTypeIcon(FontAwesome.Folder)]
public class ContainerPage : PageData
{
}

Initialize the module

[InitializableModule]
[ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
public class BucketInitializationModule : IInitializableModule
{
    private const string Language = "en";
    private bool _initialized = false;
    private IContentEvents _events;
    private IContentLoader _loader;
    private IContentRepository _repository;

    public void Initialize(InitializationEngine context)
    {
        if (!_initialized)
        {
            _loader = context.Locate.ContentLoader();
            _repository = context.Locate.ContentRepository();
            _events = context.Locate.ContentEvents();
            _events.CreatedContent += Events_CreatedContent;
            _initialized = true;
        }
    }

    private void Events_CreatedContent(object sender, ContentEventArgs e)
    {
        if (e.Content is not PageData sitePage)
        {
            return;
        }

        if (e.Content is ContainerPage)
        {
            return;
        }

        var parentPage = _loader.Get<PageData>(sitePage.ParentLink);

        if (parentPage is BucketBasePageData bucketPage)
        {
            if (string.IsNullOrEmpty(bucketPage.DatePattern))
            {
                return;
            }

            var today = DateTime.Now.ToString(bucketPage.DatePattern);
            var structure = today.Split('/');
            var contentFolder = parentPage.ContentLink;

            foreach (var folder in structure)
            {
                contentFolder = GetOrCreateContainer(contentFolder, folder);
            }

            _repository.Move(sitePage.ContentLink, contentFolder, AccessLevel.NoAccess, AccessLevel.NoAccess);
        }
    }

    private ContentReference GetOrCreateContainer(ContentReference parentFolder, string folderName)
    {
        var languageSelector = new LanguageSelector(Language);
        var storedFolder = _repository.GetBySegment(parentFolder, folderName, languageSelector) as ContainerPage;

        if (storedFolder != null)
        {
            return storedFolder.ContentLink;
        }

        storedFolder = _repository.GetDefault<ContainerPage>(parentFolder, languageSelector.Language);
        storedFolder.Name = folderName;

        _repository.Save(storedFolder, SaveAction.Publish, AccessLevel.NoAccess);
        return storedFolder.ContentLink;
    }

    public void Uninitialize(InitializationEngine context)
    {        
    }
}

This is an example of what the page structure looks like. You can change the Date Pattern value for a valid DateTime format. More info here.

Leave a comment