Preparing the Master Page - FadiZahhar/umbraco8showandtell GitHub Wiki
-
Go to Settings > Document Types.
-
Create a new document type:
- Name: Site Settings
- Alias:
siteSettings
- Make it not allowed as a root node.
-
Add properties you need for global use. Common examples:
- Site Logo (Image Picker)
- Footer Text (Textbox/textarea)
- Copyright Notice (Textbox)
- Cookie Message (Textarea)
- Social Links (Link picker or nested content)
- In the Content section, create a new node of type Site Settings as a child (or sibling) to your Home node.
- Fill in all the values you want to display globally.
- Use Umbraco’s helper methods to retrieve this node globally (typically by querying for the first node of type
siteSettings
).
// _siteSettings = Umbraco.ContentAtRoot().First().Children().First(x => x.ContentType.Alias == "siteSettings");
Or, for a small site, you can store the node’s ID in web.config or as a constant.
- Find your
~/Views/main.cshtml
file (or create it). - Add references to your CSS and JS here:
<!DOCTYPE html>
<html>
<head>
@RenderSection("head", false)
<link rel="stylesheet" href="~/css/main.min.css" />
</head>
<body>
@RenderBody()
<script src="~/js/main.min.js"></script>
@RenderSection("scripts", required: false)
</body>
</html>
At the top of your layout, add:
@inherits Umbraco.Web.Mvc.UmbracoViewPage
@{
var home = Umbraco.ContentAtRoot().FirstOrDefault();
var siteSettings = home?.Children.FirstOrDefault(x => x.ContentType.Alias == "siteSettings");
}
Now you can use siteSettings
anywhere in your layout, e.g.
<img src="@siteSettings.Value<IPublishedContent>("siteLogo")?.Url" alt="Site Logo" />
- For Umbraco 8, you can use [Smidge](https://github.com/Shazwazza/Smidge) for bundling/minification, or pre-bundle assets using Webpack/Gulp/Grunt.
- In your layout, always reference the
.min.css
/.min.js
files. - (If you use Smidge, you can configure and render bundles using Smidge’s helpers in your layout.)
main.cshtml - Main layout view for the HighlyDeveloped.Web application.
- Inherits from UmbracoViewPage, enabling access to Umbraco content and helpers.
- Uses ClientDependency.Core.Mvc for managing CSS and JS dependencies.
- Sets Layout to null, making this a root layout.
- Retrieves the home page content using Model.AncestorOrSelf<Home>().
Head Section:
- Registers external and local CSS files (Bootstrap, Font Awesome, CookieConsent).
- Registers external and local JS files (jQuery, Popper.js, Bootstrap, Font Awesome, CookieConsent).
- Uses integrity and crossorigin attributes for CDN resources to enhance security.
- Renders all required CSS with @Html.RenderCssHere().
Body Section:
- Renders the navigation bar via a partial view ("NavBar").
- Renders the main body content with @RenderBody().
- Renders the footer via a partial view ("Footer").
- Displays a cookie consent alert with a call-to-action button.
- Renders all required JS with @Html.RenderJsHere().
Note:
- This layout is designed for use with Umbraco 8 and leverages best practices for dependency management and partial rendering.
- In Settings > Partial Views, create a new partial view called
NavBar.cshtml
.
Example for a top-level navigation:
Renders a responsive navigation bar using Bootstrap classes.
- Inherits from UmbracoViewPage to access Umbraco content features.
- Retrieves the home page node using Model.AncestorOrSelf<Home>().
- Iterates through the direct children of the home page to generate navigation links.
- Each child page is rendered as a navigation item with its name and URL.
- The navigation bar is styled with Bootstrap's dark theme and is mobile-friendly with a collapsible menu.
@inherits Umbraco.Web.Mvc.UmbracoViewPage
@{
var homePage = Model.AncestorOrSelf<Home>();
}
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container">
<a class="navbar-brand" href="#">Navbar</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ml-auto">
@foreach (var page in homePage.Children)
{
<li class="nav-item">
<a class="nav-link" href="@page.Url">@page.Name</a>
</li>
}
</ul>
</div>
</div>
</nav>
- In
main.cshtml
, place:
@Html.Partial("navBar")
where you want the navigation menu to appear.
For dropdowns or submenus, extend the logic:
<ul>
@foreach (var item in menuItems)
{
<li>
<a href="@item.Url">@item.Name</a>
@{
var children = item.Children.Where(x => x.IsVisible());
if(children.Any())
{
<ul>
@foreach (var child in children)
{
<li><a href="@child.Url">@child.Name</a></li>
}
</ul>
}
}
</li>
}
</ul>
- Keep all navigation logic in
navBar.cshtml
. - Optionally, add parameters (with
@model
) to control how deep the nav goes, styling, etc.
- In Partial Views, create
Footer.cshtml
. - Use site settings, e.g.:
@inherits Umbraco.Web.Mvc.UmbracoViewPage
@{
var home = Umbraco.ContentAtRoot().FirstOrDefault();
var siteSettings = home?.Children.FirstOrDefault(x => x.ContentType.Alias == "siteSettings");
}
<footer>
<p>@siteSettings.Value("footerText")</p>
<p>© @DateTime.Now.Year @siteSettings.Value("copyrightNotice")</p>
</footer>
- In
main.cshtml
:
@Html.Partial("Footer")
- In your layout, above the closing
</body>
tag:
<div id="cookieConsent" style="display:none;position:fixed;bottom:0;width:100%;background:#222;color:#fff;padding:1rem;text-align:center;z-index:999;">
@siteSettings.Value("cookieMessage") ?? "This website uses cookies to ensure you get the best experience."
<button onclick="acceptCookies()" style="margin-left:10px;">Accept</button>
</div>
<script>
function acceptCookies() {
document.getElementById('cookieConsent').style.display = 'none';
document.cookie = "cookieAccepted=true; path=/; max-age=31536000";
}
window.onload = function() {
if (!document.cookie.includes('cookieAccepted=true')) {
document.getElementById('cookieConsent').style.display = 'block';
}
}
</script>
You can move the script to your main.min.js
for better bundling.
- Make sure all partials are rendering as expected.
- Test the site settings, navigation, and cookie consent.
- Check responsive behavior.
Feature | File/Location | Description |
---|---|---|
Site Settings | Document Type + Node | Global values for the site |
Master Page | /Views/Shared/main.cshtml |
CSS/JS references, nav/footer |
Bundling/Minification | Bundling tool or minified files | Performance optimization |
Dynamic Navigation | Partial View navBar
|
Dynamic, multi-level nav menu |
Footer | Partial View Footer
|
Shared site footer |
Cookie Consent | Layout + JS | Cookie message with "Accept" |
Here’s what I found in your archive:
Root:
-
Web.config
-
Web.Debug.config
-
Web.Release.config
Views:
-
About.cshtml
-
main.cshtml
-
Home.cshtml
-
Web.config
(for views) -
Partials/NavBar.cshtml
-
Partials/Footer.cshtml
-
Partials/Grid/…
(various editors for grid layout)
This is a classic Umbraco 8/MVC project structure.
Now I’ll analyze the code inside your layout, navigation, and footer partials, then provide tailored implementation steps.
Let’s review your main layout to understand how scripts, styles, navigation, and footer are referenced.
Your main.cshtml
layout is already using Umbraco's ClientDependency
for script and CSS bundling and minification.
It pulls in Bootstrap, Font Awesome, a CookieConsent stylesheet, and all the JS via Html.RequiresCss
and Html.RequiresJs
.
The layout starts with:
@inherits Umbraco.Web.Mvc.UmbracoViewPage
@using ClientDependency.Core.Mvc
@{
Layout = null;
var homePage = Model.AncestorOrSelf<Home>();
}
And then bundles styles/scripts in the <head>
.
Let’s review how navigation is generated.
Your navigation partial (NavBar.cshtml
) dynamically lists all children of the home page as menu items:
@foreach (var page in homePage.Children)
{
<li class="nav-item">
<a class="nav-link" href="@page.Url">@page.Name</a>
</li>
}
This means your navigation will update automatically based on the child pages of your Home node—already dynamic!
Let’s check your footer for global, editable values or placeholders for future site settings.
Your Footer partial is simple—static social links and a copyright notice:
<ul class="list-inline-item">
<li class="list-inline-item">
<a href="https://twitter.com/hdeveloped" ...>
<i class="fab fa-twitter fa-2x text-white"></i>
</a>
</li>
</ul>
<p class="text-white">Copyright © @DateTime.Now.Year Highly Developed</p>
It could easily be improved to pull values (like copyright, social links, or footer text) from Site Settings.
You reference /css/CookieConsent.css
and probably include cookie consent logic via a script in your assets.
I'll show you how to make sure this works, and how to pull its message from Site Settings.
a. In Umbraco Backoffice:
-
Create a Site Settings document type (not allowed at root).
-
Add properties:
-
Footer Text (Textbox)
-
Copyright Notice (Textbox)
-
Cookie Message (Textarea)
-
Social Links (e.g. Nested Content or Multinode Picker)
-
-
-
In Content, add a Site Settings node under Home.
At the top of main.cshtml
, NavBar.cshtml
, and Footer.cshtml
, add:
@{
var homePage = Model.AncestorOrSelf<Home>();
var siteSettings = homePage.Children.FirstOrDefault(x => x.ContentType.Alias == "siteSettings");
}
You can now use siteSettings.Value<string>("propertyAlias")
to output values.
Edit Footer.cshtml
to use Site Settings:
@inherits Umbraco.Web.Mvc.UmbracoViewPage
@{
var homePage = Model.AncestorOrSelf<Home>();
var siteSettings = homePage.Children.FirstOrDefault(x => x.ContentType.Alias == "siteSettings");
}
<footer class="bg-dark">
<div class="container">
<div class="row">
<div class="col text-center py-4">
<!-- Example Social Links Loop -->
<ul class="list-inline-item">
@* Loop through social links if configured *@
@{
var socials = siteSettings?.Value<IEnumerable<IPublishedElement>>("socialLinks");
if (socials != null) {
foreach(var link in socials) {
<li class="list-inline-item">
<a href="@link.Value("url")" target="_blank" title="@link.Value("name")">
<i class="@link.Value("iconClass") fa-2x text-white"></i>
</a>
</li>
}
}
}
</ul>
<p class="text-white">
@siteSettings?.Value("footerText")<br/>
© @DateTime.Now.Year @siteSettings?.Value("copyrightNotice")
</p>
</div>
</div>
</div>
</footer>
Adjust the property aliases to match your Site Settings setup.
In your main.cshtml
, you already include all scripts/styles via Html.RequiresCss/Js
(bundling & minification are handled by Umbraco’s ClientDependency out of the box).
Just ensure you always retrieve siteSettings
as above, to make it available everywhere.
At the bottom of your main.cshtml
(just before </body>
), add:
<div id="cookieConsent" style="display:none;position:fixed;bottom:0;width:100%;background:#222;color:#fff;padding:1rem;text-align:center;z-index:999;">
@siteSettings?.Value("cookieMessage") ?? "This website uses cookies to ensure you get the best experience."
<button onclick="acceptCookies()" style="margin-left:10px;">Accept</button>
</div>
<script>
function acceptCookies() {
document.getElementById('cookieConsent').style.display = 'none';
document.cookie = "cookieAccepted=true; path=/; max-age=31536000";
}
window.onload = function() {
if (!document.cookie.includes('cookieAccepted=true')) {
document.getElementById('cookieConsent').style.display = 'block';
}
}
</script>
Link your CookieConsent.css
for styling.
Your NavBar.cshtml
is already dynamic.
To support sub-menus, you can enhance the loop:
@foreach (var page in homePage.Children)
{
<li class="nav-item @(page.Children.Any() ? "dropdown" : "")">
<a class="nav-link @(page.Children.Any() ? "dropdown-toggle" : "")"
href="@page.Url"
@(page.Children.Any() ? "data-toggle=\"dropdown\"" : "")>
@page.Name
</a>
@if(page.Children.Any()) {
<div class="dropdown-menu">
@foreach(var child in page.Children) {
<a class="dropdown-item" href="@child.Url">@child.Name</a>
}
</div>
}
</li>
}
Already implemented via Html.RequiresCss/Js
with ClientDependency!
To add your own assets, use:
Html.RequiresCss("/css/custom.min.css");
Html.RequiresJs("/js/custom.min.js");
Task | Where | Code/Logic |
---|---|---|
Site Settings Doc Type | Backoffice | Contains global values for use in all partials |
Site Settings in Views | Top of each Partial/Layout | var siteSettings = ... |
Dynamic Navigation | NavBar.cshtml | @foreach (var page in homePage.Children) |
Dynamic Footer | Footer.cshtml | Use siteSettings properties for copyright/socials |
Cookie Consent | main.cshtml (bottom) | Use siteSettings + JS for banner |
Bundling/Minification | main.cshtml | Html.RequiresCss/Js (ClientDependency) |