In this example, we'll see what content-blocks are in the system, and where they are in use.
You are on portal 2 - this sample has hard-wired IDs for portal 59 (our dev-environment) and 24 (the tutorials on 2sxc.org). If one of these is detected, it will show the stats for a portal we know on that system, otherwise from the current app - which won't show much, since this tutorial app doesn't have many content-blocks.
⚠️ Code Disabled in Oqtane 💧
This code only works in DNN, so the tutorial has special conditional statements like #if NETCOREAPP which disable the code in Oqtane.
See See how to use #if
Source Code of 110-content-blocks.dnn.cshtml
@inherits Custom.Hybrid.Razor14
@using System.Collections;
@using System.Linq;
@using DotNetNuke.Entities.Modules;
@*
Tag: #DnnOnly - ATM can't work in Oqtane because it uses the Factory command and because it uses DNN objects
2sxclint:disable:no-inline-script
2sxclint:disable:no-dnn-namespaces
*@
@{
// isDev should just tell us, if we're looking at the dev-portal (while creating this demo app) or if it's running on 2sxc.org
// where we use other zoneId and appId;
var isDev = CmsContext.Site.Id == 59;
var is2sxcTutorial = CmsContext.Site.Id == 24;
var portalId = isDev ? 10 : is2sxcTutorial ? 0 : CmsContext.Site.Id;
// create array with all 2sxc modules in this portal
var allMods = GetAllModulesOfPortal(portalId);
// Get the app & views we're going to investigate the views of
var app = isDev
? ToSic.Sxc.Dnn.Factory.App(11, 35) // some app on our dev environment
: is2sxcTutorial
? ToSic.Sxc.Dnn.Factory.App(2, 2) // the 2sxc.org Content-App
: App; // fallback, use this app, but not very exciting
// all views in this specific app, sorted by name
var views = AsList(app.Data["2SexyContent-Template"]).OrderBy(t => t.Name);
// get all content blocks which have templates - skip the ones without, as they have not been initialized yet
var contentBlocks = AsList(app.Data["2SexyContent-ContentGroup"]);
// create a map of all blocks to DNN modules
var block2ModuleMap = contentBlocks.GroupJoin(allMods,
cb => cb.EntityGuid,
m => Kit.Convert.ToGuid(m.ModuleSettings[SettingsCG]),
(cb, m) => new {
Block = cb,
Modules = m
}
);
// now map all the template-IDs to the block-module map
var template2BlockModuleMap = block2ModuleMap.GroupBy(b2m => {
var templates = AsList(b2m.Block.Template as object);
return templates.Any() ? templates.First().EntityGuid : null;
});
var viewsWithBlocks = views.GroupJoin(template2BlockModuleMap,
v => v.EntityGuid,
bwm => bwm.Key,
(v, bwm) => {
var blockWithMod = bwm.SingleOrDefault();
return new {
View = v,
Blocks = blockWithMod,
ModsCount = blockWithMod != null ? blockWithMod.SelectMany(bmlist => bmlist.Modules).Count() : 0,
};
}
);
}
<h2>Statistics</h2>
<ol>
<li>We're looking at portal @portalId, Zone @app.ZoneId, App: @app.AppId </li>
<li>@views.Count() Views</li>
<li>@contentBlocks.Count() Content Blocks </li>
<li>@allMods.Count() DNN Modules in the primary language </li>
</ol>
<hr>
<h2>Views</h2>
@foreach (var set in viewsWithBlocks) {
<h3>View @set.View.Name</h3>
if (set.Blocks != null) {
<div>
Used in @set.Blocks.Count() blocks and @set.ModsCount modules
</div>
<ol>
@foreach (var blockSet in set.Blocks) {
<li>
Block: @blockSet.Block.EntityGuid (@blockSet.Block.EntityId)
in @blockSet.Modules.Count() modules: @string.Join(",", blockSet.Modules.Select(m => m.ModuleID))
</li>
}
</ol>
} else {
<text>not in use</text>
}
}
@functions {
// CONSTANTS
// this key is used in module settings
const string SettingsCG = "ToSIC_SexyContent_ContentGroupGuid";
// create array with all 2sxc modules in this portal
List<ModuleInfo> GetAllModulesOfPortal(int portalId) {
var mc = ModuleController.Instance;
var dnnMod2sxcContent = mc.GetModulesByDefinition(portalId, "2Sexy Content");
var dnnMod2sxcApp = mc.GetModulesByDefinition(portalId, "2Sexy Content App");
var mergedMods = new ModuleInfo[dnnMod2sxcContent.Count + dnnMod2sxcApp.Count];
dnnMod2sxcContent.CopyTo(mergedMods);
dnnMod2sxcApp.CopyTo(mergedMods, dnnMod2sxcContent.Count);
var allMods = mergedMods
.Where(m => m.DefaultLanguageModule == null)
.Where(m => !m.IsDeleted)
.Where(m => m.ModuleSettings.ContainsKey(SettingsCG));
return allMods.ToList();
}
}
Below you'll see the source code of the file.
Note that we're just showing the main part, and hiding some parts of the file which are not relevant for understanding the essentials.
Click to expand the code
@inherits Custom.Hybrid.Razor14
@using System.Collections;
@using System.Linq;
<!-- unimportant stuff, hidden -->
<h2>Query Content-Blocks</h2>
<p>
In this example, we'll see what content-blocks are in the system, and where they are in use.
</p>
<div class="alert alert-info">
You are on portal <strong>@CmsContext.Site.Id</strong> - this sample has hard-wired IDs for portal 59 (our dev-environment) and 24 (the tutorials on 2sxc.org). If one of these is detected, it will show the stats for a portal we know on that system, otherwise from the current app - which won't show much, since this tutorial app doesn't have many content-blocks.
</div>
@if (CmsContext.Platform.Name == "Oqtane") {
@Html.Partial("../shared/MessageOqtaneDisabled.cshtml")
} else {
@Html.Partial("110-content-blocks.dnn.cshtml")
}
@* Footer *@
@Html.Partial("../Shared/Layout/FooterWithSource.cshtml", new { Sys = Sys })
An error has occurred. This application may no longer respond until reloaded.
Reload🗙