Copied to clipboard

Flag this post as spam?

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


  • Peter Maslin 1 post 71 karma points
    Apr 08, 2024 @ 07:35
    Peter  Maslin
    0

    Identifying where a Block is being used

    Hi

    we are using the block list option and have created a large number of blocks for our site to allow content editors to build various pages without developer input.

    one thing we have not been able to do is find a way to identify where or if a block is being used we have tried tools like diplo.godmode etc.

    but nothing we have found can give us a break down on where a block is being used, if we could produce a report somehow to show a blocks usage that would be great but any other tool/plugin would be useful.

    we are on umbraco 12 and use an on premises installation.

    Peter

  • Marc Goodson 2157 posts 14432 karma points MVP 9x c-trib
    Apr 09, 2024 @ 08:39
    Marc Goodson
    0

    Hi Peter

    How have you setup the reusable blocks?

    Are they items in the content tree that the editors pick?

    So you have a 'Shared Content Block' and the editors pick a reusable content block from the tree? if so then this will create a Relation between the reusable block, and you can see where they are used on the 'info' tab of the reusable content item.

    eg

    enter image description here

    But if you are talking about the usage of 'Block Types', eg where has the Video Block Type been used, then, because that is stored in a big blob of JSON in the database for the Block List property editor it can be difficult to determine!

    If this is just a 'one off audit' - You can query the database umbracoPropertyData table, to look at the stored database for the Block List raw data and the ids of the different Element Types...

    or similarly if you have uSync installed you can export all the content of the site into XML files and search them...

    But if its for more of an ongoing thing, then you could create in the Relations section a new Relation Type called Block Type Usage.

    enter image description here

    This creates a place to store, ermm relations between DocTypes and Documents (content nodes).

    Then you could tap into the ContentService's notifications:

    https://docs.umbraco.com/umbraco-cms/reference/notifications/contentservice-notifications

    and handle the Saving event, see which blocks are on the page that is being saved, and use the RelationService to create a relation between them under the new relation type

    https://docs.umbraco.com/umbraco-cms/reference/management/services/relationservice

    similarly for the deleting event, removing any relations...

    Then you could build a custom dashboard, https://docs.umbraco.com/umbraco-cms/tutorials/creating-a-custom-dashboard that used the RelationService to pull back all the relations from the Relation Type and group together by 'Document Type' listing all the content items that use that particular Doc Type!

    regards

    Marc

  • npack 66 posts 374 karma points
    1 week ago
    npack
    0

    I have been creating custom health checks that give me reports of pages meeting certain criteria. One that I built today was a report that displays all the pages that each of my blocks is used on.

    I'll include the source here, but the output looks something like this: enter image description here

    using System.Text;
    using Umbraco.Cms.Core.HealthChecks;
    using Umbraco.Cms.Core.Models.PublishedContent;
    using Umbraco.Cms.Core.PublishedCache;
    using Umbraco.Cms.Core.Services;
    using Umbraco.Cms.Core.Services.Navigation;
    
    namespace MyCompany.Public.Web.Utilities.CustomHealthChecks
    {
    
        [HealthCheck("9988fe74-f738-4e73-9ae6-f88dc302ce05", "Grid Block Usage", Description = "See Grid Block Usage", Group = "Page Setup")]
        public class GridBlockUsageHealthCheck : ContentHealthCheck
        {
            public GridBlockUsageHealthCheck(IDocumentNavigationQueryService documentQuery, IDocumentCacheService documentCache, ServiceContext serviceContext, IVariationContextAccessor variationContextAccessor) : base(documentQuery, documentCache, serviceContext, variationContextAccessor)
            {
            }
    
            public async override Task<IEnumerable<HealthCheckStatus>> GetStatus()
            {
                var statuses = new List<HealthCheckStatus>();
                var blockUsage = new Dictionary<String, List<IPublishedContent>>();
    
                // Collect the Usage Stats
                foreach (var page in await GetAllDocuments<IPublishedContent>())
                {
                    var blocks = GetGridBlocks(page.Properties);
    
                    foreach (var block in blocks)
                    {
                        if (block != null)
                        {
                            var blockName = block.Content.ContentType.Alias;
    
                            if (!blockUsage.ContainsKey(blockName))
                            {
                                blockUsage.Add(blockName, new List<IPublishedContent>());
                            }
                            if (!blockUsage[blockName].Contains(page))
                            {
                                blockUsage[blockName].Add(page);
                            }
                        }
    
                    }
    
                }
    
    
                // Build the report
                foreach (var blockName in blockUsage.Keys.OrderBy(k => k))
                {
                    var title = $"\"{blockName}\"";
                    var sb = new StringBuilder();
                    sb.AppendLine(title);
                    sb.Append("<ul>");
                    foreach (var page in blockUsage[blockName].OrderBy(p => p.Name))
                    {
                        sb.AppendLine($"<li>{GetPageLinkDetails(page, page.Name)}</li>");
    
                    }
                    sb.Append("</ul>");
                    statuses.Add(new HealthCheckStatus(sb.ToString())
                    {
                        ResultType = StatusResultType.Success
                    });
                }
                return statuses.AsEnumerable();
            }
    
    
        }
    }
    
    
    using System.IO.Enumeration;
    using Umbraco.Cms.Core.HealthChecks;
    using Umbraco.Cms.Core.Models.Blocks;
    using Umbraco.Cms.Core.Models.PublishedContent;
    using Umbraco.Cms.Core.PublishedCache;
    using Umbraco.Cms.Core.Services;
    using Umbraco.Cms.Core.Services.Navigation;
    
    namespace MyCompany.Public.Web.Utilities.CustomHealthChecks
    {
        public abstract class ContentHealthCheck : Umbraco.Cms.Core.HealthChecks.HealthCheck
        {
            private readonly IDocumentNavigationQueryService documentQuery;
            private readonly IDocumentCacheService documentCache;
            private readonly ServiceContext serviceContext;
            private readonly IVariationContextAccessor variationContextAccessor;
    
            public ContentHealthCheck(IDocumentNavigationQueryService documentQuery, IDocumentCacheService documentCache, ServiceContext serviceContext, IVariationContextAccessor variationContextAccessor)
            {
                this.documentQuery = documentQuery;
                this.documentCache = documentCache;
                this.serviceContext = serviceContext;
                this.variationContextAccessor = variationContextAccessor;
            }
    
    
            public override HealthCheckStatus ExecuteAction(HealthCheckAction action)
            {
                throw new InvalidOperationException("FolderAndFilePermissionsCheck has no executable actions");
            }
    
            public async Task<List<T>> GetAllDocuments<T>()
            {
                var allDocuments = new List<T>();
                if (this.documentQuery.TryGetRootKeys(out var rootKeys))
                {
                    foreach (var rootKey in rootKeys)
                    {
                        if (this.documentQuery.TryGetDescendantsKeys(rootKey, out var documentKeys))
                        {
                            foreach (var documentKey in documentKeys)
                            {
                                var document = await this.documentCache.GetByKeyAsync(documentKey);
    
                                if (document != null)
                                {
                                    if (typeof(T).IsAssignableFrom(document.GetType()))
                                    {
                                        allDocuments.Add((T)document!);
                                    }
                                }
                            }
                        }
                    }
    
                }
                return allDocuments;
            }
    
            protected string GetPageLinkDetails(IPublishedContent page, string message, string defaultEditTabName = "")
            {
    
                var viewLink = $"<a href='{page.Url()}' target='_blank'>View</a>";
                var editLink = $"<a href='/umbraco/section/content/workspace/document/edit/{page.Key}/invariant/tab/{defaultEditTabName}' target='_blank'>Edit</a>";
    
                return $"<b>\"{message}\"</b> ({page.Url()}) {viewLink} {editLink}";
            }
    
    
    
    
            protected List<KeyValuePair<string, string>> GetPropertyValues(IEnumerable<IPublishedProperty> properties, List<string> propertyNameFilters)
            {
                // Recursively searches through any properties or block grids for properties of a given name
                var descriptions = new List<KeyValuePair<string, string>>();
    
                foreach (var property in properties)
                {
                    if (property.PropertyType?.DataType.EditorAlias == "Umbraco.TextBox") // Currently only supports short string textboxes. Add a parameter for a data type if needed
                    {
                        if (Matches(property.Alias, propertyNameFilters))
                        {
    
    
                            var propValue = property.Value(new PublishedValueFallback(this.serviceContext, this.variationContextAccessor));
                            string stringValue = propValue?.ToString() ?? "";
                            descriptions.Add(new KeyValuePair<string, string>(property.Alias, stringValue));
    
                        }
                    }
                    else if (property.PropertyType?.DataType.EditorAlias == "Umbraco.BlockGrid")
                    {
                        if (property.PropertyType?.ClrType?.Name == "BlockGridModel")
                        {
                            foreach (var item in property.Value<BlockGridModel>(new PublishedValueFallback(serviceContext, variationContextAccessor))!)
                            {
                                var blockDescriptions = GetPropertyValues(item.Content.Properties, propertyNameFilters);
                                descriptions.AddRange(blockDescriptions);
    
    
                                foreach (var area in item.Areas)
                                {
    
                                    foreach (var blockInArea in area)
                                    {
                                        if (blockInArea != null)
                                        {
                                            var areaDescriptions = GetPropertyValues(blockInArea.Content.Properties, propertyNameFilters);
                                            descriptions.AddRange(areaDescriptions);
                                        }
                                    }
    
                                }
                            }
                        }
                    }
    
    
                }
                return descriptions;
    
            }
    
    
            protected List<BlockGridItem> GetGridBlocks(IEnumerable<IPublishedProperty> properties)
            {
                // Recursively searches through any properties for blocks
                var blocks = new List<BlockGridItem>();
    
                foreach (var property in properties)
                {
                    if (property.PropertyType?.DataType.EditorAlias == "Umbraco.BlockGrid")
                    {
                        if (property.PropertyType?.ClrType?.Name == "BlockGridModel")
                        {
                            foreach (var item in property.Value<BlockGridModel>(new PublishedValueFallback(serviceContext, variationContextAccessor))!)
                            {
                                blocks.Add(item);
                                blocks.AddRange(GetGridBlocks(item.Content.Properties));
    
                                foreach (var area in item.Areas)
                                {
    
                                    foreach (var blockInArea in area)
                                    {
                                        if (blockInArea != null)
                                        {
                                            blocks.Add(blockInArea);
                                            blocks.AddRange(GetGridBlocks(blockInArea.Content.Properties));
                                        }
                                    }
    
                                }
                            }
                        }
                    }
                }
                return blocks;
    
            }
    
    
            private bool Matches(string alias, List<string> propertyNameFilters)
            {
                foreach (var filter in propertyNameFilters)
                {
                    if (FileSystemName.MatchesSimpleExpression(filter, alias))
                    {
                        return true;
                    }
                }
    
                return false;
            }
    
        }
    }
    
Please Sign in or register to post replies

Write your reply to:

Draft