Copied to clipboard

Flag this post as spam?

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


  • Al 8 posts 53 karma points
    Jan 24, 2023 @ 16:13
    Al
    1

    Umbraco 11 - Creating a Block Grid programmatically - Areas query

    Hi All, I'm in the process of migrating some very large U7 sites into v11 (18k+ articles on this one) . I've taken the approach of starting from scratch, and exporting my old content as XML and importing it into a clean v11 install with some custom import scripts.

    Generally it's going very well and i'm making excellent progress, which is lovely.

    I've got to the stage where I'm mapping my old DTGE content into the new Block Grid data type. I've managed to get everything from here working nicely:

    https://docs.umbraco.com/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-grid-editor#creating-a-block-grid-programmatically

    However in my v11 setup I'd like to use areas going forwards, and force all my blocks to be inside layout areas (simply 6-6 and 12. However the documentation above includes this:

    JsonProperty("areas")] // areas are omitted from this sample for abbreviation public object[] Areas { get; } = { };

    Clearly this is what I need to implement, rather than adding my data to the root grid editor I need to add them to areas, but Im struggling to find any examples of this being done. Any pointers?

    The layout is as follows:

    enter image description here

    So I'm looking to get my blocks inside those areas on import: enter image description here

    Currently they are just getting added into the root of the editor and outside of the areas.

    Does that make sense? Many thanks in advance.

  • Al 8 posts 53 karma points
    Jan 25, 2023 @ 13:01
    Al
    101

    I've managed to figure most of this out by inspecting the JSON in the database. The main issue I have remaining is that each area requires a key and it looks like that key is specific to the block grids layout block area configuration. I can't however see how I would find that key programatically.

    For now i've hard coded the area keys into the import tool, so it works and puts the blocks inside the areas now.

    As you can see beloe the blocks are correctly added to the full width area.

    enter image description here

  • Sander Los 27 posts 160 karma points
    Feb 02, 2023 @ 10:18
    Sander Los
    2

    Hi, we have been dealing with this as well. This is the way I get the data now. (we are still testing/refactoring, so the code below will be ugly/hardcoded)

    // get the layout type
    IContentType split = _contentTypeService.Get("split");
    // get the blockgrid data type
    BlockGridConfiguration blockGridDataTemp = (BlockGridConfiguration)_dataTypeService.GetDataType("Block Grid Test").Configuration;
    // filter out the block. 
    var splitLayoutBlock = blockGridDataTemp.Blocks.FirstOrDefault(x => x.ContentElementTypeKey == split.Key);
    

    With this approach you get an object in which you can get the keys for the areas.

  • Alan Draper 57 posts 140 karma points
    Feb 22, 2023 @ 19:51
    Alan Draper
    0

    Hi Al -- I'm looking at doing something very similar; any chance you could share the code for your import tool?

  • Al 8 posts 53 karma points
    Feb 23, 2023 @ 10:37
    Al
    2
                                // get the element types for spot blocks (content and settings)
    
                                // build the individual parts of the block grid data from the raw data
                                var layoutItems = new List<BlockGridLayoutItem>();
                                var areaItems = new List<BlockGridAreaItem>();
                                var gridContentData = new List<BlockGridElementData>();
                                var gridSettingsData = new List<BlockGridElementData>();
    
                                //add layout to the grid first
                                foreach (GridExportRow row in contentPage.GridExportSections!.GridExportSection!.GridExportRows!.GridExportRow!) {
                                    foreach (var area in row.GridExportItems!.GridExportItem!.GridExportAreas!.GridExportArea!) {
                                        // generate new UDIs for block content and settings
                                        var contentUdi = Udi.Create(Constants.UdiEntityType.Element, Guid.NewGuid());
                                        var settingsUdi = Udi.Create(Constants.UdiEntityType.Element, Guid.NewGuid());
                                        switch (area.Alias)
                                        {
                                            case "rte":
    
                                                // create new content data
    
                                                IContentType? blockRTEType = _contentTypeService.Get("blockGridRichtext");
                                                // create a new layout item
                                                layoutItems.Add(new BlockGridLayoutItem(contentUdi, int.Parse(area.Columns), 1, new(), settingsUdi));
                                                gridContentData.Add(new BlockGridElementData(blockRTEType!.Key, contentUdi, new Dictionary<string, object>
                                                {
                                                    { "content", area!.Rte },
                                                }));
    
                                            break;
    
                                            case "media":
                                                // generate new UDIs for block content and settings
                                                IContentType? blockImageType = _contentTypeService.Get("blockGridImage");
    
                                                // create a new layout item
                                                layoutItems.Add(new BlockGridLayoutItem(contentUdi,int.Parse(area.Columns), 1, new(), settingsUdi));
                                                //upload the image if it hasn't already been uploaded so we don't have the same image uploaded multiple times.
                                                if (area.Media !=null && area.Media.Image != "")
                                                {
                                                    var existingMediaItem = mediaFolder!.Descendants<Image>().Where(x => x.PreviousID == area.Media.Id.ToString().Trim());
                                                    if (existingMediaItem != null && existingMediaItem.Any())
                                                    {
                                                        Udi UDIMedia = Udi.Create(Constants.UdiEntityType.Media, existingMediaItem.FirstOrDefault()!.Key);
                                                        gridContentData.Add(new BlockGridElementData(blockImageType!.Key, contentUdi, new Dictionary<string, object>{
                                                            { "image", UDIMedia },
                                                        }));
                                                    }
                                                    else { 
                                                        try
                                                        {
                                                            string mainImage = "https://www.oldsitedomain.com/" + area.Media.Image;
                                                            int uploadedImageID = UploadMediaAsync(mainImage, 12345, area.Media.Id);
                                                            var primaryImage = _mediaService.GetById(uploadedImageID);
                                                            if (primaryImage != null)
                                                            {
                                                                var mediaUdi = Udi.Create(Constants.UdiEntityType.Media, primaryImage.Key);
    
                                                                gridContentData.Add(new BlockGridElementData(blockImageType!.Key, contentUdi, new Dictionary<string, object>
                                                                {
                                                                { "image", mediaUdi },
    
                                                                }));
                                                            }
                                                        }
                                                        catch
                                                        {
                                                            //logging removed
                                                        }
                                                    }
                                                }
                                                // create new content data
    
                                                break;
                                            case "quote":
                                                // generate new UDIs for block content and settings
                                                IContentType? blockQuoteType = _contentTypeService.Get("blockGridQuote");
    
                                                // create a new layout item
                                                layoutItems.Add(new BlockGridLayoutItem(contentUdi, int.Parse(area.Columns), 1, new(), settingsUdi));
                                                //upload the image
                                                if (area.Quote!.Value != "")
    
                                                    gridContentData.Add(new BlockGridElementData(blockQuoteType!.Key, contentUdi, new Dictionary<string, object>{
                                                        { "quote", area.Quote.Value },
                                                    }));
                                                }
                                                // create new content data
    
                                                break;
    
                                        }
                                    }
                                }
    
                                //setup areas
                                var areas = new List<BlockGridArea>();
    
                                foreach (var gridContent in layoutItems) {
                                    var areaItemLoop = new BlockGridAreaItem();
                                    var settingsUdi = Udi.Create(Constants.UdiEntityType.Element, Guid.NewGuid());
                                    areaItemLoop.ContentUdi = gridContent.ContentUdi;
                                    areaItemLoop.SettingsUdi = settingsUdi;
                                    areaItemLoop.Areas = new();
                                    areaItemLoop.ColumnSpan = gridContent.ColumnSpan;
                                    areaItemLoop.RowSpan = gridContent.RowSpan;
                                    areaItems.Add(areaItemLoop);
                                }
    
    
                                layoutItems.Clear();
                                //area for two col (left)
                                areas.Add(new BlockGridArea(Guid.Parse("GUIDFORLAYOUTAREA1"), new()));
                                //area for two col (right)
                                areas.Add(new BlockGridArea(Guid.Parse("GUIDFORLAYOUTAREA2"), new()));
                                //area for fullwidth col 
                                areas.Add(new BlockGridArea(Guid.Parse("GUIDFORLAYOUTAREA3"), areaItems));
    
                                //create layout area
                                var contentLayoutUdi = Udi.Create(Constants.UdiEntityType.Element, Guid.NewGuid());
                                IContentType? contentLayoutType = _contentTypeService.Get("blockGridContentLayout");
    
                                gridContentData.Add(new BlockGridElementData(contentLayoutType!.Key, contentLayoutUdi, new Dictionary<string, object>
                                {
    
                                }));
                                layoutItems.Add(new BlockGridLayoutItem(contentLayoutUdi, 12, 1, areas));
                                //new BlockGridArea(new Guid(), areaItems)
    
                                // construct the block grid data from layout, content and settings
                                var blockGridData = new BlockGridData(
                                    new BlockGridLayout(layoutItems.ToArray()),
                                    gridContentData.ToArray(),
                                    gridSettingsData.ToArray());
    
    
                                // serialize the block grid data as JSON and save it to the "blockGrid" property on the content item
                                var propertyValue = JsonConvert.SerializeObject(blockGridData);
                                content!.SetValue("content", propertyValue);
    
    
    
                            }
    
                            if (!skipItem) { 
                                _contentService.SaveAndPublish(content!, "en-GB");
    
                            }
                            if (unpublishItem) {
                                _contentService.Unpublish(content!, "en-GB");
                            }
    

    The above is very much cut down, and specifically the grid to block grid importing. Hopefully it might give you something to start off with. Our process now is: generate XML from the existing v7 site. On the new v11 site, get that xml, map it to models and create or update content items. The above section deals specfically with the block grid import. It's heavily stripped down. We have a bunch of additional DTGE mappings and other grid fields that are also migrated and inserted appropriately. We then have Hangfire running on the v11 site so we we can re run the imports as the code is amended. It's working pretty well at this point.

  • Alan Draper 57 posts 140 karma points
    Mar 07, 2023 @ 15:03
    Alan Draper
    0

    I don't see some of these classes. Maybe they were renamed?

    • BlockGridElementData
    • BlockGridAreaItem
  • Al 8 posts 53 karma points
    Feb 23, 2023 @ 10:41
    Al
    0

    This was the article that I used as a starter:

    https://codeshare.co.uk/blog/how-i-migrated-my-umbraco-v7-site-to-v8-part-2-content/ (it's to v8 but was a helpful starting point)

  • Alan Draper 57 posts 140 karma points
    Feb 23, 2023 @ 22:15
    Alan Draper
    0

    Excellent! Thank you so much.

  • Frederik Lundbeck Jørgensen 4 posts 74 karma points
    Mar 05, 2023 @ 09:43
    Frederik Lundbeck Jørgensen
    0

    I'm trying to do the exact same thing, did someone work out how to find the key?

  • Alan Draper 57 posts 140 karma points
    Mar 06, 2023 @ 21:58
    Alan Draper
    0

    This bit seems to be helping me:

        [Route("[action]")]
        public object ViewTypes()
        {
    
            return new
            {
    
                contentTypes = ContentTypeService.GetAll().Select(ct =>
                new
                {
                    ct.Key,
                    ct.Name,
                    ct.Alias,
                    ct.Id,
                    propertyTypes = ct.PropertyTypes.Select(pt => new
                    {
                        pt.Key,
                        pt.Name,
                        pt.Alias,
                        pt.Id,
                        pt.DataTypeId
                    })
                }),
                dataTypes = DataTypeService.GetAll().Select(dt => new
                {
                    dt.Name,
                    dt.Key,
                    dt.Configuration,
                    dt.EditorAlias
                })
            };
        }
    
  • Alan Draper 57 posts 140 karma points
    Mar 17, 2023 @ 14:28
    Alan Draper
    0

    I'm so frustratingly close. But after attempting an import, I get empty areas like this:

    enter image description here

    The frustrating thing is, the JSON for the property looks identical (to me) to when I create actual content in the Umbraco backoffice.

    Here's the "bad" property with the missing area content:

    {
        "layout": {
            "Umbraco.BlockGrid": [
                {
                    "contentUdi": "umb://element/6d4f25cdff2243eda4e7c9d9d9e0d9b5",
                    "areas": [
                        {
                            "key": "bd0dbcc5-7141-41d1-9f73-9a67f205aad1",
                            "items": [
                                {
                                    "contentUdi": "umb://element/2d16a0fca4ad4d08ac73a6ccba84beb8",
                                    "columnSpan": 7,
                                    "rowSpan": 1,
                                    "areas": []
                                }
                            ]
                        },
                        {
                            "key": "23461d63-60bf-42f2-ad7a-6728b5a54947",
                            "items": [
                                {
                                    "contentUdi": "umb://element/9349829067e241c4a22a67ab7c653708",
                                    "columnSpan": 5,
                                    "rowSpan": 1,
                                    "areas": []
                                }
                            ]
                        }
                    ]
                }
            ]
        },
        "contentData": [
            {
                "contentTypeKey": "f3ea7f29-4e2f-4c73-951e-7f8599ffb510",
                "udi": "umb://element/6d4f25cdff2243eda4e7c9d9d9e0d9b5"
            },
            {
                "contentTypeKey": "e888d034-69f3-4c6d-aea2-3a25b2ad7007",
                "udi": "umb://element/2d16a0fca4ad4d08ac73a6ccba84beb8",
                "overlayPosition": "[\"Bottom\"]",
                "overlayColor": "[\"Black\"]",
                "image": "[{\"key\":\"3c35c496-37a7-4b71-82ea-cf6be2e16b5a\",\"mediaKey\":\"c0c370c2-5f75-48a0-accf-9f662eca9f07\"}]",
                "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
            },
            {
                "contentTypeKey": "e888d034-69f3-4c6d-aea2-3a25b2ad7007",
                "udi": "umb://element/9349829067e241c4a22a67ab7c653708",
                "overlayPosition": "[\"Bottom\"]",
                "overlayColor": "[\"Black\"]",
                "image": "[{\"key\":\"8aea601d-5586-42e9-83cc-f6c00da39e9c\",\"mediaKey\":\"14451928-8fb2-4851-8d92-ccddc19e6b6a\"}]",
                "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
            }
        ],
        "settingsData": []
    }
    

    And here is similar "good" content that works after creating in Umbraco.

    {
        "layout": {
            "Umbraco.BlockGrid": [
                {
                    "contentUdi": "umb://element/ed7ce8f6585649db90ef4e6a5ac15dd6",
                    "areas": [
                        {
                            "key": "26b8bfdf-2cb8-4db1-926d-65b937e2f5ff",
                            "items": [
                                {
                                    "contentUdi": "umb://element/2e310cb094a84fc1ae239c9ab4e128f6",
                                    "areas": [],
                                    "columnSpan": 7,
                                    "rowSpan": 1
                                }
                            ]
                        },
                        {
                            "key": "d829fb4a-3e6c-4acd-ae67-ba24e571ce77",
                            "items": [
                                {
                                    "contentUdi": "umb://element/2e1533f349da41c6a40e6fe506209391",
                                    "areas": [],
                                    "columnSpan": 5,
                                    "rowSpan": 1
                                }
                            ]
                        }
                    ],
                    "columnSpan": 12,
                    "rowSpan": 1
                }
            ]
        },
        "contentData": [
            {
                "contentTypeKey": "f3ea7f29-4e2f-4c73-951e-7f8599ffb510",
                "udi": "umb://element/ed7ce8f6585649db90ef4e6a5ac15dd6"
            },
            {
                "contentTypeKey": "e888d034-69f3-4c6d-aea2-3a25b2ad7007",
                "udi": "umb://element/2e310cb094a84fc1ae239c9ab4e128f6",
                "image": "[{\"key\":\"eaa23e21-213f-416e-ab21-d3942a4a6879\",\"mediaKey\":\"7eff7fb9-cbab-4b5a-9d8e-77b368d050b0\"}]",
                "overlayPosition": "[\"Bottom\"]",
                "overlayColor": "[\"Black\"]",
                "text": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>"
            },
            {
                "contentTypeKey": "e888d034-69f3-4c6d-aea2-3a25b2ad7007",
                "udi": "umb://element/2e1533f349da41c6a40e6fe506209391",
                "image": "[{\"key\":\"7d5ec37d-8a51-49f3-8b61-3072a9396df8\",\"mediaKey\":\"ec690b49-1dbb-450a-a3ca-3bc9aba00fe2\"}]",
                "overlayPosition": "[\"Bottom\"]",
                "overlayColor": "[\"Black\"]",
                "text": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>"
            }
        ],
        "settingsData": []
    }
    

    I'm stumped why one works and the other doesn't.

  • Alan Draper 57 posts 140 karma points
    Mar 17, 2023 @ 15:36
    Alan Draper
    0

    I figured it out! Pays to read the spec...

    The key for the areas should be the same as the key in the config. I was creating a new one. Whoops.

  • Ben Sheridan 5 posts 85 karma points
    Jun 08, 2023 @ 15:15
    Ben Sheridan
    0

    Hi

    Trying to get the key as well I am not quite sure what you mean the same as in the config what config are you referring to

    Thanks for any help

  • Ben Palmer 180 posts 866 karma points c-trib
    Sep 23, 2024 @ 13:17
    Ben Palmer
    0

    Any chance you ever figured this out?

    I'm attempting to do the same thing and everything looks correct. For the "area" key however, I'm just generating a new Guid which sounds like it may be wrong.

    Any help would be hugely appreciated!

  • Ben Palmer 180 posts 866 karma points c-trib
    Sep 23, 2024 @ 13:41
    Ben Palmer
    0

    And in typical fashion, as soon as I asked his question the answer popped into my head. For anyone else looking to do similar:

    They key value has to match the guid of the area in your block grid data type i.e., the guid of the area shown in the example below:

    enter image description here

    I'm not sure if there's an easier way to get the guid but I created a unique name for this area e.g., migrated_area_0 and searched for this in the database table dbo.umbracoDataType. The JSON stored will have the key in it (606689e1-2a06-4a8c-9656-2fd2fe61d063 in the below example`).

    ...
    {
        "columnSpanOptions": [],
        "rowMinSpan": 1,
        "rowMaxSpan": 1,
        "allowAtRoot": true,
        "allowInAreas": false,
        "areas": [
            {
            "key": "606689e1-2a06-4a8c-9656-2fd2fe61d063",
            "alias": "migrated_area_0",
            "columnSpan": 12,
            "rowSpan": 1,
            "minAllowed": 0,
            "specifiedAllowance": []
            }
        ],
        "contentElementTypeKey": "dd98da8b-871e-4bb7-b914-068121d18f16",
        "settingsElementTypeKey": "fa4d35cf-b5c6-4c23-bc70-b06a166498d7",
        "label": "One Column",
        "editorSize": "medium",
        "inlineEditing": false,
        "forceHideContentEditorInOverlay": false,
        "groupKey": "e5f4e94c-df91-3895-92f2-129cdbfde75b"
        }
    ...
    

    Hope that's clear, took me a while to figure this out!

  • Al 8 posts 53 karma points
    Jun 08, 2023 @ 15:47
    Al
    0

    I'm about to log off but if you share what you have / where you are stuck I might well be able to point you in the right direction.

  • Al 8 posts 53 karma points
    Jun 08, 2023 @ 15:57
    Al
    1

    the key for the area needs to be the one from your layout, i got it with inspect element in the backend: (this is what i was hoping i could find programatically but in the end hard coding was fine)

    enter image description here

  • Ben Sheridan 5 posts 85 karma points
    Jun 09, 2023 @ 09:29
    Ben Sheridan
    0

    Thanks for this not sure now long it would have taken to figure out this was the exact thing I needed

Please Sign in or register to post replies

Write your reply to:

Draft