Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Paul Sterling 718 posts 1534 karma points MVP 8x admin c-trib
    Sep 18, 2023 @ 23:18
    Paul Sterling
    0

    Work with Blocklist Properties using the Umbraco Content Service - v12

    From an UmbracoAuthorizedApiController I would like to use an Umbraco service Api (ContentService) to manipulate property data contained in BlockList components. So far, while non-BlockList properties are available using the ContentService, all Blocklist properties are not. This snippet will write all non-BlockList properties but omits the BlockList ones

                    var contentType = _contentTypeService.Get("blogPost");
                    var contentOfType = _contentService.GetPagedOfType(contentType.Id, 0, int.MaxValue, out long totalArchive, null);
    
                    foreach (var content in contentOfType)
                    {
                        foreach(var property in  content.Properties)
                            Debug.WriteLine($"Content Property Alias: {property.Alias}");
    ...
    

    I've found plenty of docs covering how to create a BlockList and already use custom BlockList views with Umbraco.Cms.Web.Common.Views.UmbracoViewPage<Umbraco.Cms.Core.Models.Blocks.BlockListItem> but I'm stuck on this one.

    Feel like I'm missing something obvious...tips or pointers much appreciated!

  • Paul Sterling 718 posts 1534 karma points MVP 8x admin c-trib
    Sep 20, 2023 @ 00:41
    Paul Sterling
    100

    The solution I ended up with was not at all what I had originally envisioned. While I do use the ContentService to get the content, the actual updates are done using more generic methods and serializing/deserializing Json. For what it's worth, here is what is working for me to get BlockList content, do some simple find and replace, then update and save the BlockList content. I've added a way to handle both single content and nested content (eg, Lists of BlockList content). I'm sure that can be refactored to be cleaner.

    I am more than open to a better way to do this!

    private readonly IContentService _contentService;
    ...
    public FindAndReplaceApiController(IContentService contentService)
    {
        _contentService = contentService;
    }
    ...
    // your content id
    var content = _contentService.GetById(0000);  
    // the property alias for the BlockList content from the Document Type
    var rawJsonBlock = content.GetValue("content").ToString(); 
    // the entire BlockList Json block
    BlockValue blockValue = JsonConvert.DeserializeObject<BlockValue>(rawJsonBlock);
    // Note: using System.Text.Json throws exceptions when deserializing OR returns an empty object, I don't know why
    
    foreach (var column in blockValue.ContentData)
    {
        foreach (var columnProperty in column.RawPropertyValues)
        {
            // the Value is a text string, unless it's a BlockList, in which case it's a Json object
            var block = columnProperty.Value; 
    
            if (block == null) continue;
    
            // check if the Value is a BlockList, for repeating BlockList items
            if (block.ToString().Contains("Umbraco.BlockList", StringComparison.InvariantCultureIgnoreCase))
            {
                // if it is, we can deserialize it to a BlockValue since we have nested content
                var innerBlock = JsonConvert.DeserializeObject<BlockValue>(columnProperty.Value.ToString());
    
                foreach (var innerBlockValue in innerBlock.ContentData)
                {
                    foreach(var blockProperty in innerBlockValue.RawPropertyValues)
                    {
                        Debug.WriteLine($"Inner Block Value: {blockProperty.Value}");
    
                        if (blockProperty.Value.ToString().Contains("some old value", StringComparison.InvariantCultureIgnoreCase))
                        {
                            // replace the old with the new!
                            innerBlockValue.RawPropertyValues[blockProperty.Key] = blockProperty.Value.ToString()
                                                                                    .Replace("some old value"
                                                                                    , "some new value"
                                                                                    , StringComparison.InvariantCultureIgnoreCase);
                            // serialize the updated value to Json for storage
                            column.RawPropertyValues[columnProperty.Key] = JsonConvert.SerializeObject(innerBlock);
                            content.Properties["content"].SetValue(JsonConvert.SerializeObject(blockValue));
                        }
                    }
                }
            }
            else
            {
                // in this case, the block content is not nested
                Debug.WriteLine($"Top Level Block Value: {block}");
    
                if(block.ToString().Contains("some old value", StringComparison.InvariantCultureIgnoreCase))
                {
                    // update the block object directly
                    block = block.ToString().Replace("some old value", "some new value", StringComparison.InvariantCultureIgnoreCase);
                    // serialize the updated value to Json for storage
                    column.RawPropertyValues[columnProperty.Key] = block;
                    content.Properties["content"].SetValue(JsonConvert.SerializeObject(blockValue));
                }
            }
        }
    }
    
    if (content.IsDirty())
    {
        // save the updates, if any
        _contentService.SaveAndPublish(content);
    }
    ...
    
Please Sign in or register to post replies

Write your reply to:

Draft