I have a BlockGrid property that allows multiple blocks as content. Some of these have their own areas that allow some of the same blocks.
I would love to write an extension for IPublishedContent that would allow me to extract all blocks of a specific kind… something I could use like this:
@inherits UmbracoViewPage<AnimalCage>
@{
var cage = Model;
var dinos = cage.Dinosaurs; // the BlockGrid's blocks
var raptors = cage.GetRaptors(); // ideally `IEnumerable<BlockGridItem>`
}
@if (raptors.Any()) {
<section class="warning"> ... </section>
}
(This is not my use case but I hope it makes it clear what I’m looking for )
I’m well-versed in “normal” extension for simple structures, but with all the .Content, .Areas etc. I can’t wrap my head around it.
These are recursive, so blocks have areas, areas have blocks, those can have areas too. You need to walk the tree, not just .Where() at the top level.
public static IEnumerable<BlockGridItem> Flatten(this BlockGridModel? grid)
{
if (grid is null) yield break;
foreach (var item in grid)
{
yield return item;
foreach (var area in item.Areas)
foreach (var nested in ((BlockGridModel?)null is var _ ? area : area).Flatten())
yield return nested;
}
}
Both BlockGridModel and BlockGridArea are IEnumerable<BlockGridItem>, so you just foreach over them. Then:
I couldn’t get it to work properly (but you did say it wasn’t tested) but it got me on the right path to write the needed extensions – basically this:
public static IEnumerable<BlockGridItem> Flatten(this BlockGridArea? area) {
if (area is not null) {
foreach (var item in area) {
yield return item;
}
}
}
public static IEnumerable<BlockGridItem> Flatten(this BlockGridModel? grid) {
if (grid is null) return Enumerable.Empty<BlockGridItem>();
return grid
.SelectMany(item =>
new[] { item }
.Concat(item.Areas.SelectMany(area => area.Flatten()))
);
}
public static IEnumerable<BlockGridItem> GetRaptors(this IPublishedContent cage) {
return cage.Value<BlockGridModel>("Dinosaurs").Flatten().Where(d => d.Content.ContentType.Alias == "raptor");
}
So thanks — I can now warn the visitors if there are raptors close by