Starting the Project - FadiZahhar/umbraco8showandtell GitHub Wiki

Why Create a Site Settings Document Type in Umbraco?

1. Centralized Global Settings

  • Purpose: Store content and configuration that is relevant across the whole site, not just for one page.

  • Examples:

    • Site logo

    • Social media links

    • Footer content

    • Contact details

    • SEO metadata defaults

    • Google Analytics scripts

2. Editor-Friendly

  • Editors can update key settings (e.g., change the logo or contact info) without developer intervention or having to hunt through templates or config files.

  • All global settings are easily accessible in one place in the backoffice.

3. Separation of Concerns

  • Keeps content separate from configuration: Page content lives in content nodes; site-wide settings live in the settings node.

  • Avoids hard-coding values or spreading “global” content across multiple templates or pages.

4. Easier Maintenance and Scalability

  • Centralized updates: Change once, reflected everywhere.

  • Less risk of mistakes or inconsistencies (e.g., multiple versions of a phone number).

  • When you add new global features, you have a clear place to manage them.

5. Reusability and Clean Code

  • Templates and partial views can reference settings from a single location (e.g., Model.Root().DescendantOrSelf("siteSettings")).

  • If you ever run a multi-site install, you can set up one settings node per site.

6. Makes Content Migration & Deployment Easier

  • Easier to export/import global settings during migration.

  • Clean separation between dynamic content and static/global configuration.


How It Typically Works

  • Create a Site Settings Document Type (often with an icon like a gear or cog).

  • Add relevant properties (logo, company info, etc.).

  • Place a single Site Settings node under the root of your Content tree (often hidden from navigation).

  • Reference these settings in your Razor templates (header, footer, etc.).


Sample Structure

Content
├── Home
├── About Us
├── Contact
├── Site Settings  <-- Not a page, but a node for global settings

Summary Table

Benefit Description
Centralized management One place for all global settings
Editor empowerment No need for developer for simple global changes
Clean templates No hard-coded or repeated values
Future-proofing Easy to add more settings as your site grows
Consistency Prevents inconsistencies across the site

Step 1: Create the “Site Settings” Document Type

A. In the Umbraco Backoffice

  1. Go to: Settings > Document Types
    Click Create Document Type.

  2. Name:
    Site Settings

  3. Icon:
    Choose something like a gear ⚙️ or a toolbox.

  4. Permissions:

    • Allow as root: Yes

    • Can be composed into other types: No

  5. Add Properties (Tabs/Groups & Fields):

    General Tab:

    • Logo (Type: Media Picker, Alias: logo)

    • Site Name (Type: Textstring, Alias: siteName)

    Social Tab:

    • Facebook URL (Type: Textstring, Alias: facebookUrl)

    • Instagram URL (Type: Textstring, Alias: instagramUrl)

    • Twitter URL (Type: Textstring, Alias: twitterUrl)


site settings 1

Site Settings 2

site settings 3

Site Settings 4

Site Settings 5

Site Settings 6

Permission

Allow as root


Page Content

Page Content

Permission Is Element Type

Page Content is Element Type


Content Page

Content Page 1

Content Page 2

Content Page 3

Content Page 4

Content Page 5


Verify

Verify


Useful Link

Useful Link

Useful Link 2

Permission

Useful Links Permissions


What is a Composition Document Type in Umbraco 8?

Compositions in Umbraco 8 are a way to create reusable sets of fields (properties) that can be “mixed in” to multiple Document Types—kind of like adding “traits” or “features” to different content blueprints.

Think of it Like This:

  • Normal Document Types:
    Define the fields for a single content type (e.g., Blog Post, Product, Content Page).

  • Composition Document Types:
    Define a set of fields (like a “component” or “mixin”) that can be reused by multiple Document Types.


Why Use Compositions?

  • DRY Principle: Avoid repeating the same fields across multiple Document Types.

  • Consistency: Ensure fields like SEO, Hero Section, or Metadata are always the same everywhere they’re used.

  • Maintainability: Update the composition in one place, and all Document Types using it get the change.


Real-World Example

Let’s say you want every page on your site to have SEO fields (Meta Title, Meta Description, Open Graph Image).
Instead of adding these fields manually to every Document Type (Home, About, Blog, etc.), you:

  1. Create a “SEO” Composition Document Type

    • Add fields: Meta Title, Meta Description, OG Image.

  2. Attach the SEO Composition to any Document Type that needs SEO settings.

Now, each page that uses this composition automatically gets the SEO fields—no copy-pasting, no extra work.


How to Create and Use a Composition in Umbraco 8

  1. Create a New Document Type (Composition):

    • Go to Settings > Document Types.

    • Click “Create new Document Type.”

    • Name: “SEO” (or “Hero Section”, “Metadata”, etc.)

    • Set “Allow as root” to No (this keeps it out of the content tree—it’s just for composing).

    • Add your reusable fields (properties).

  2. Add the Composition to Another Document Type:

    • Edit any Document Type (e.g., Blog Post, Content Page).

    • Go to the Compositions tab.

    • Select your SEO Composition.

    • Save.
      Now, this Document Type will include all the fields from the SEO Composition!


Visual Analogy

  • Compositions are like Lego bricks:

    • Build a brick (e.g., SEO fields).

    • Attach that brick to any model (Document Type) you want.

    • You can reuse the same brick in lots of places—just “click it in.”


Typical Use Cases

  • SEO properties (meta fields, OG image)

  • Hero sections (title, subtitle, background image)

  • Common settings (visibility, publish date, tags)

  • Social media fields


Summary Table

Term Used For Shows in Content Tree? Typical Example
Document Type Pages, blocks, main content Yes Blog Post, Product
Composition Reusable field sets, shared by many types No SEO, Hero Section

Key Points

  • Compositions = reusable field groups for Document Types.

  • Keeps your site DRY, organized, and maintainable.

  • Update in one place; affect many types.


Composition Call To Action

Composition Call To Action

Composition Call To Action 2


Composition Hero

Composition Hero

Composition Hero 2


Composition Navigation

Composition Navigation


Composition Useful Links

Composition Useful Links


Contact Form

Contact Form

Contact Form 2

Contact Forms

Contact Forms

Contact Forms List View

Contact Forms

Contact Forms List Views 2

Contact Forms List Views 3

Contact Forms List Views 4

Contact Forms List Views 5


Email

Email 1

Email 2

Email 3

Emails

Emails

Emails Template Same List Content

Emails Same List Content Default

Permis

Emails Allow child nodes sion

Email Template 1

Email Template 2

Email Templates

Email Templates Same List Content

Email Templates Same List Content Default

Permission

Email Templates Allow child noe Emails


Login , Logout , My Account

Login

Logout

Register

Reset Password

My Account


Search

Search

Search 2


Useful Link

Useful Link

Useful Link 2

News Article

News Article 1

News Article 2

News Article 3

News Articles

News Articles 2

Permission

News Articles Allow Child Nodes

Data

Data

Permission

Data Child

Home

Home

Permission

Home Allow As Root

Home Allow Child Nodes


Step 2: Add the Site Settings Node

  1. Go to: Content

  2. Create a new node at the root, choose Site Settings.

  3. Fill in the logo and social links.


Step 3: Hide from Navigation

To prevent editors from accidentally publishing the Site Settings as a page:

  • Set permissions so only admins can access/edit.

  • (Optional) Use a property like “Hide from Navigation” if your navigation renders all root nodes by default.


Step 4: Use Site Settings in Razor Templates

Here’s how you fetch and use Site Settings values in your views (e.g., header, footer).

A. Fetch the Site Settings Node

@{
    // Get the root node (homepage or site root)
    var root = Model.Root();
    // Find the Site Settings node by document type alias
    var siteSettings = root.DescendantsOrSelf("siteSettings").FirstOrDefault();
}

B. Render the Logo

@if (siteSettings != null && siteSettings.HasValue("logo"))
{
    var logoMedia = siteSettings.Value<IPublishedContent>("logo");
    <img src="@logoMedia?.Url" alt="Site Logo" />
}

C. Render Social Links

@if (siteSettings != null)
{
    <ul class="social-links">
        @if (!string.IsNullOrEmpty(siteSettings.Value<string>("facebookUrl")))
        {
            <li><a href="@siteSettings.Value<string>("facebookUrl")" target="_blank">Facebook</a></li>
        }
        @if (!string.IsNullOrEmpty(siteSettings.Value<string>("instagramUrl")))
        {
            <li><a href="@siteSettings.Value<string>("instagramUrl")" target="_blank">Instagram</a></li>
        }
        @if (!string.IsNullOrEmpty(siteSettings.Value<string>("twitterUrl")))
        {
            <li><a href="@siteSettings.Value<string>("twitterUrl")" target="_blank">Twitter</a></li>
        }
    </ul>
}

Summary Table

Property Type Alias Example Value
Logo Media Picker logo /media/1234/logo.png
Site Name Textstring siteName My Awesome Site
Test Mode boolean Test mode state true
Facebook URL Textstring facebookUrl https://facebook.com/mysite
Instagram URL Textstring instagramUrl https://instagram.com/mysite
Twitter URL Textstring twitterUrl https://twitter.com/mysite

Your Views Folder Structure should be as following Views folder:

Views/
  About.cshtml
  Home.cshtml
  main.cshtml
  Web.config
  /Partials
    NavBar.cshtml
    Footer.cshtml
    /Grid
      Bootstrap3.cshtml
      Bootstrap3-Fluid.cshtml
      /Editors
        Base.cshtml
        Embed.cshtml
        Macro.cshtml
        Media.cshtml
        Rte.cshtml
        Textstring.cshtml

You’re using:

  • A main layout file: main.cshtml

  • Partials: NavBar.cshtml, Footer.cshtml

  • Grid/Editors: for advanced content—these are fine as-is for the layout tutorial


How to Apply the Tutorial to Your Project’s Files

Here’s a step-by-step guide customized to your actual folder and file names.


1. Use main.cshtml as Your Master Layout

File: Views/main.cshtml
This is your _Layout.cshtml equivalent!

A. Add Third-Party Libraries to <head> and Before </body>

Add these lines to the <head> section of main.cshtml:

<!-- Bootstrap 4 CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" />
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css?family=Roboto:400,700&display=swap" rel="stylesheet" />
<!-- Font Awesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" />

Just before </body>, add:

<!-- Scripts: jQuery, Popper, Bootstrap -->
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>

<script> // Cookie Consent Logic $(document).ready(function () { if (!localStorage.getItem('cookieConsentAccepted')) { $('#cookieConsent').fadeIn(); } $('#acceptCookies').on('click', function () { localStorage.setItem('cookieConsentAccepted', 'true'); $('#cookieConsent').fadeOut(); }); }); </script>


2. Render Shared Components (Partials) Inside Your Layout

In main.cshtml, replace any static navigation/footer HTML with calls to your partials:

@Html.Partial("Partials/NavBar")
...
@RenderBody()
...
@Html.Partial("Partials/Footer")
...
@Html.Partial("Partials/CookieConsent") <!-- (You'll need to add this file, see below) -->

3. Create the Cookie Consent Partial

File: Views/Partials/CookieConsent.cshtml

@inherits Umbraco.Web.Mvc.UmbracoViewPage

<div class="cookie-consent" id="cookieConsent" style="display:none;position:fixed;bottom:0;width:100%;background:#333;color:#fff;padding:1rem;z-index:1000;"> This website uses cookies to ensure you get the best experience. <button class="btn btn-primary btn-sm" id="acceptCookies">Accept</button> </div>


4. Use Your Layout in Page Templates

In each template (e.g., Views/Home.cshtml, Views/About.cshtml), set:

@{
    Layout = "main.cshtml";
}

Write your page-specific content below that.


5. Navigation and Footer

A. Navigation (Views/Partials/NavBar.cshtml)

Enhance if needed to loop through your root nodes, for example:

@inherits Umbraco.Web.Mvc.UmbracoViewPage

<nav class="navbar navbar-expand-lg navbar-light bg-light"> <a class="navbar-brand" href="/">@Umbraco.Field("siteName", recursive: true)</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"> @{ var root = Umbraco.ContentAtRoot().FirstOrDefault(); if (root != null) { foreach (var page in root.Children().Where(x => x.IsVisible())) { <li class="nav-item"> <a class="nav-link" href="@page.Url">@page.Name</a> </li> } } } </ul> </div> </nav>

B. Footer (Views/Partials/Footer.cshtml)

Enhance as needed; for example:

@inherits Umbraco.Web.Mvc.UmbracoViewPage

<footer class="bg-dark text-light text-center py-4 mt-5"> <div> <span>&copy; @DateTime.Now.Year @Umbraco.Field("siteName", recursive: true) | All rights reserved.</span> </div> <div> <a href="#" class="text-light mx-2"><i class="fab fa-facebook"></i></a> <a href="#" class="text-light mx-2"><i class="fab fa-instagram"></i></a> <a href="#" class="text-light mx-2"><i class="fab fa-twitter"></i></a> </div> </footer>


6. (Optional) Style Adjustments

You can keep your CSS in the <style> tag in main.cshtml or add a custom CSS file and link it in the head.


Summary Table (Your Project’s Structure)

File Location Purpose
Views/main.cshtml Main layout (“master page”)
Views/Partials/NavBar.cshtml Navigation bar partial
Views/Partials/Footer.cshtml Footer partial
Views/Partials/CookieConsent.cshtml Cookie consent popup partial
Views/Home.cshtml, etc. Actual page templates

What to Do Next (Step-by-Step, In Your Project):

  1. Edit main.cshtml:

    • Add the library references in <head> and before </body>.

    • Insert @Html.Partial for NavBar, Footer, and CookieConsent in the correct spots.

  2. Create CookieConsent.cshtml in /Views/Partials/ with the code above.

  3. Check NavBar and Footer:

    • If needed, update their code per examples to support Bootstrap and dynamic site data.

  4. Set the Layout in all page templates (Home.cshtml, About.cshtml, etc.):

    @{
        Layout = "main.cshtml";
    }
    
  5. Test the site to make sure the layout, navigation, footer, and cookie consent show as expected.


Final: /Views/main.cshtml

@inherits Umbraco.Web.Mvc.UmbracoViewPage

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>
        @if (Umbraco.Field("title", recursive: true).HasValue())
        {
            @Umbraco.Field("title", recursive: true)
        }
        else
        {
            @Umbraco.Field("siteName", recursive: true)
        }
    </title>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    
    <!-- Bootstrap 4 CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" />

    <!-- Google Fonts -->
    <link href="https://fonts.googleapis.com/css?family=Roboto:400,700&display=swap" rel="stylesheet" />

    <!-- Font Awesome -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" />

    <style>
        body { font-family: 'Roboto', Arial, sans-serif; }
        .cookie-consent { position: fixed; bottom: 0; width: 100%; background: #333; color: #fff; padding: 1rem; display: none; z-index: 1000; }
        .cookie-consent button { margin-left: 1rem; }
    </style>
    @RenderSection("Head", required: false)
</head>
<body>

    <!-- NAVIGATION -->
    @Html.Partial("Partials/NavBar")

    <!-- PAGE CONTENT -->
    <main class="container my-4">
        @RenderBody()
    </main>

    <!-- FOOTER -->
    @Html.Partial("Partials/Footer")

    <!-- COOKIE CONSENT -->
    @Html.Partial("Partials/CookieConsent")

    <!-- SCRIPTS -->
    <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
    <script>
        // Cookie Consent Logic
        $(document).ready(function () {
            if (!localStorage.getItem('cookieConsentAccepted')) {
                $('#cookieConsent').fadeIn();
            }
            $('#acceptCookies').on('click', function () {
                localStorage.setItem('cookieConsentAccepted', 'true');
                $('#cookieConsent').fadeOut();
            });
        });
    </script>
    @RenderSection("Scripts", required: false)
</body>
</html>

What Else You Need

1. /Views/Partials/CookieConsent.cshtml

Create this file if it does not exist:

@inherits Umbraco.Web.Mvc.UmbracoViewPage

<div class="cookie-consent" id="cookieConsent">
    This website uses cookies to ensure you get the best experience.
    <button class="btn btn-primary btn-sm" id="acceptCookies">Accept</button>
</div>

2. Link Layout in Pages

At the top of each of your page templates (e.g., Home.cshtml, About.cshtml):

@{
    Layout = "main.cshtml";
}

3. NavBar and Footer

  • The partials already exist:

    • /Views/Partials/NavBar.cshtml
    • /Views/Partials/Footer.cshtml
  • Make sure they use Bootstrap classes and pull dynamic data as needed (see earlier examples for dynamic navigation and footer).


4. Test

  • Start your site.

  • You should see:

    • Bootstrap/Font Awesome styling
    • Your navigation and footer
    • Page content in the main container
    • Cookie consent banner on first visit (should disappear on click and not return after reload)

1. Navigation Partial: /Views/Partials/NavBar.cshtml

Checklist for a Good Bootstrap Navigation in Umbraco:

  • Uses Bootstrap 4 markup and classes.
  • Loops through children of the root node to build top-level navigation.
  • Hides nodes not meant for navigation (IsVisible()).
  • Highlights the current page (optional, but a nice touch).

Review/Upgrade Example:

@inherits Umbraco.Web.Mvc.UmbracoViewPage

<nav class="navbar navbar-expand-lg navbar-light bg-light">
  <a class="navbar-brand" href="/">
    @Umbraco.Field("siteName", recursive: true)
  </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">
      @{
          var root = Umbraco.ContentAtRoot().FirstOrDefault();
          if (root != null)
          {
              foreach (var page in root.Children().Where(x => x.IsVisible()))
              {
                  var isActive = page.Id == Model.Id ? "active" : "";
                  <li class="nav-item @isActive">
                      <a class="nav-link" href="@page.Url">@page.Name</a>
                  </li>
              }
          }
      }
    </ul>
  </div>
</nav>

What this does:

  • Gets the root node (your homepage or site root).
  • Loops through all visible children (i.e., pages set to show in navigation).
  • Renders each as a Bootstrap navigation item.
  • Adds the active class if the item matches the current page.

2. Footer Partial: /Views/Partials/Footer.cshtml

Checklist for a Good Footer:

  • Uses Bootstrap for layout.
  • Dynamically displays the site name and current year.
  • Optionally links to social networks—ideally, these would be pulled from Site Settings (see earlier tutorial), but can be hard-coded as placeholders.

Review/Upgrade Example:

@inherits Umbraco.Web.Mvc.UmbracoViewPage

<footer class="bg-dark text-light text-center py-4 mt-5">
    <div>
        <span>&copy; @DateTime.Now.Year @Umbraco.Field("siteName", recursive: true) | All rights reserved.</span>
    </div>
    <div>
        <a href="#" class="text-light mx-2"><i class="fab fa-facebook"></i></a>
        <a href="#" class="text-light mx-2"><i class="fab fa-instagram"></i></a>
        <a href="#" class="text-light mx-2"><i class="fab fa-twitter"></i></a>
    </div>
</footer>

3. Does This Adapt to Your Content?

  • If your content tree is:

    Content
    ├─ Home
    ├─ About
    ├─ Contact
    ├─ (others)
    

    All pages under root (and set to “Show in navigation”) will automatically appear in the navigation bar.

  • The site name will always pull from the root node (ensure your Home/root node has the siteName property).


How to Test:

  1. Add pages in the Content tree, set “Show in navigation.”
  2. Reload the site—they should appear in the navigation, styled by Bootstrap.
  3. Footer always shows the current year and site name.
  4. Mobile? Resize your window—the Bootstrap nav should collapse into a hamburger menu.

If You Want Dynamic Social Links in Footer:

Update the footer to pull from your Site Settings node, like this (if you set those up):

@{
    var root = Umbraco.ContentAtRoot().FirstOrDefault();
    var siteSettings = root?.DescendantsOrSelf("siteSettings").FirstOrDefault();
}
<footer class="bg-dark text-light text-center py-4 mt-5">
    <div>
        <span>&copy; @DateTime.Now.Year @Umbraco.Field("siteName", recursive: true) | All rights reserved.</span>
    </div>
    <div>
        @if (siteSettings != null)
        {
            if (!string.IsNullOrWhiteSpace(siteSettings.Value<string>("facebookUrl")))
            {
                <a href="@siteSettings.Value<string>("facebookUrl")" class="text-light mx-2" target="_blank"><i class="fab fa-facebook"></i></a>
            }
            // Repeat for instagramUrl, twitterUrl, etc.
        }
    </div>
</footer>

(Replace "siteSettings", "facebookUrl" etc. with your actual Document Type and field aliases)


Summary

  • Your current partials do adapt to your content tree if they use the above Razor code.
  • Bootstrap 4 ensures navigation/footer are responsive and styled.
  • The footer and navigation update automatically as you add, remove, or rename nodes in the backoffice.

Assumptions

  • You have a Site Settings Document Type (alias: siteSettings) in your Content tree.

  • It has fields like:

    • facebookUrl
    • instagramUrl
    • twitterUrl
  • The settings node is typically under the root of your Content tree.


Final /Views/Partials/Footer.cshtml

@inherits Umbraco.Web.Mvc.UmbracoViewPage

@{
    var root = Umbraco.ContentAtRoot().FirstOrDefault();
    var siteSettings = root?.DescendantsOrSelf("siteSettings").FirstOrDefault();
}

<footer class="bg-dark text-light text-center py-4 mt-5">
    <div>
        <span>&copy; @DateTime.Now.Year @Umbraco.Field("siteName", recursive: true) | All rights reserved.</span>
    </div>
    <div>
        @if (siteSettings != null)
        {
            if (!string.IsNullOrWhiteSpace(siteSettings.Value<string>("facebookUrl")))
            {
                <a href="@siteSettings.Value<string>("facebookUrl")" class="text-light mx-2" target="_blank" rel="noopener">
                    <i class="fab fa-facebook"></i>
                </a>
            }
            if (!string.IsNullOrWhiteSpace(siteSettings.Value<string>("instagramUrl")))
            {
                <a href="@siteSettings.Value<string>("instagramUrl")" class="text-light mx-2" target="_blank" rel="noopener">
                    <i class="fab fa-instagram"></i>
                </a>
            }
            if (!string.IsNullOrWhiteSpace(siteSettings.Value<string>("twitterUrl")))
            {
                <a href="@siteSettings.Value<string>("twitterUrl")" class="text-light mx-2" target="_blank" rel="noopener">
                    <i class="fab fa-twitter"></i>
                </a>
            }
        }
    </div>
</footer>

How this works:

  • Finds the Site Settings node (siteSettings), starting from the root.

  • Checks if each social link is present (not empty or null).

  • Outputs a link/icon only if the value exists.

  • Best practice:

    • Uses target="_blank" and rel="noopener" for security when opening new tabs.

Now in Umbraco Backoffice:

  • Go to your Site Settings node.
  • Enter your Facebook, Instagram, Twitter URLs.
  • If a field is empty, its icon won’t appear in the footer.

1. The Basics: How Razor Views Access Content in Umbraco 8

A. The Default Model: @Model

  • In a standard Umbraco Razor view, the @Model variable represents the current content node being rendered.

  • By default, @Model is of type Umbraco.Web.Models.RenderModel.

  • The actual content data is stored in @Model.Content, which is of type IPublishedContent.

Typical access pattern (without Models Builder):

@inherits Umbraco.Web.Mvc.UmbracoViewPage

@{ var pageTitle = Model.Content.GetPropertyValue("title"); } <h1>@pageTitle</h1>

or using the shortcut:

@Umbraco.Field("title")

Or:

@Model.Content.GetValue<string>("title")

2. The Problem with Dynamic Access

  • Dynamic API (GetPropertyValue, GetValue, Umbraco.Field) is flexible, but:

    • Error-prone: Property names are strings (easy to mistype).

    • No compile-time checking or IntelliSense.

    • Refactoring is harder (renaming fields won’t break code until runtime).


3. The Solution: Models Builder (Strongly-Typed Models)

Umbraco Models Builder is a code generation tool that turns your document types into C# classes.
With it enabled, you get strongly-typed models for your content nodes!

How it works:

  • For every Document Type you define in Umbraco, Models Builder generates a class (e.g., if you have a document type called "HomePage", you get a HomePage class).

  • Each property on your Document Type becomes a property in the class (e.g., public string Title { get; }).

Benefits:

  • IntelliSense and compile-time checking in Razor views.

  • Easy refactoring.

  • Clearer, cleaner code: @Model.Title vs. @Model.GetValue<string>("title")


4. Strongly-Typed Views with Models Builder

A. How Do You Use It?

  1. Enable Models Builder (default in Umbraco 8):

    • It will generate models in /App_Data/Models/ by default.

    • You can also configure it to generate models in a different folder, or use API-only mode.

  2. Change Your View to Use the Model:

    • Instead of inheriting from the generic UmbracoViewPage, inherit from UmbracoViewPage<HomePage> (if your document type is HomePage).

    @inherits Umbraco.Web.Mvc.UmbracoViewPage<YourNamespace.Models.HomePage>
    

    <h1>@Model.Title</h1> <p>@Model.ContentText</p>

    • Here, @Model.ContentText is a strongly-typed property, representing the "contentText" property on your "HomePage" document type.

    • If you have a property named "contentText" in the backoffice, Models Builder creates:

      public string ContentText { get; }
      

B. Property Access Comparison Table

Access Pattern Example Compile-Time Safety? IntelliSense? Recommended?
Dynamic (string key) @Model.Content.GetValue("foo") For quick tests
Umbraco.Field shortcut @Umbraco.Field("foo") For simple cases
Strongly Typed (Models Builder) @Model.Foo

TL;DR

  • Models Builder generates C# classes for your content types for strongly-typed, safer, and easier-to-maintain code.

  • Use @Model.PropertyName instead of @Model.GetValue<string>("propertyName") whenever possible.

  • @Model.ContentText is available if your Document Type has a property called contentText and you use the strongly-typed model in your view.


Dynamic Navbar in Umbraco 8 — Step-by-Step


1. Understand the Content Tree Structure

In Umbraco, navigation menus are usually based on the root node’s children—the main pages at the top of your Content tree.

Example Content tree:

Content
├─ Home (root)
├─ About
├─ Services
├─ Contact
├─ ... (others)

Only the pages set to “Show in navigation” (via IsVisible()) will appear in the navbar.


2. Locate or Create NavBar.cshtml

Location:
/Views/Partials/NavBar.cshtml


3. Bootstrap 4 Navbar Razor Code (Dynamic & Responsive)

Paste or update the following code:

@inherits Umbraco.Web.Mvc.UmbracoViewPage

<nav class="navbar navbar-expand-lg navbar-light bg-light"> <a class="navbar-brand" href="/"> @Umbraco.Field("siteName", recursive: true) </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"> @{ // Get the root node (e.g., Home) var root = Umbraco.ContentAtRoot().FirstOrDefault(); if (root != null) { // Loop through each visible child (top-level nav items) foreach (var page in root.Children().Where(x => x.IsVisible())) { // Add "active" class if this is the current page var isActive = (page.Id == Model.Id) ? "active" : ""; <li class="nav-item @isActive"> <a class="nav-link" href="@page.Url">@page.Name</a> </li> } } } </ul> </div> </nav>


4. Explanation and Best Practices

  • Umbraco.ContentAtRoot().FirstOrDefault(): Gets the root of your site (usually "Home").

  • .Children().Where(x => x.IsVisible()): Loops only through pages set to show in navigation.

  • page.Id == Model.Id: Highlights the current page as active for user feedback.

  • @Umbraco.Field("siteName", recursive: true): Uses your global Site Name for the brand link.


5. Add to Your Master Layout

In your /Views/main.cshtml (master layout), include the navbar like this:

@Html.Partial("Partials/NavBar")

6. How to Add Dropdowns or More Levels

For most sites, top-level navigation is enough. If you want dropdowns for child pages, add inside the loop:

@if (page.Children().Any(x => x.IsVisible()))
{
    // Render dropdown menu
}

But keep it simple at first—expand later if you have a lot of subpages.


7. To Update Navigation:

  • Just add, rename, or re-order pages in Umbraco’s Content section.

  • Set “Show in navigation” for any page you want in the menu.

  • The navigation updates automatically—no code changes needed.


8. Summary Table

Step File Action
Dynamic Nav /Views/Partials/NavBar.cshtml Use code above for dynamic nav
Add to Layout /Views/main.cshtml @Html.Partial("Partials/NavBar")
Control Nav Umbraco Content section (backoffice) Use “Show in navigation” toggle

9. Result

  • Responsive Bootstrap navbar

  • Reflects real-time Content tree

  • Highlights current page

  • Zero hard-coded links!


Step-by-Step: Cookie Consent with CookieConsent.js in Umbraco 8


1. Create the Partial for Cookie Consent

Location:
/Views/Partials/CookieConsent.cshtml

Code:

@inherits Umbraco.Web.Mvc.UmbracoViewPage

<div class="cookie-consent" id="cookieConsent" style="display:none;position:fixed;bottom:0;width:100%;background:#333;color:#fff;padding:1rem;z-index:1000;"> This website uses cookies to ensure you get the best experience. <button class="btn btn-primary btn-sm" id="acceptCookies">Accept</button> </div>


2. Create the JavaScript File

Location suggestion:
/wwwroot/js/CookieConsent.js
(or wherever you keep your static files; for Umbraco 8, ~/js/ or /Scripts/ is common)

Code:

// /js/CookieConsent.js

document.addEventListener("DOMContentLoaded", function () { // Only show if not previously accepted if (!localStorage.getItem('cookieConsentAccepted')) { var consent = document.getElementById('cookieConsent'); if (consent) consent.style.display = "block"; } var acceptBtn = document.getElementById('acceptCookies'); if (acceptBtn) { acceptBtn.addEventListener('click', function () { localStorage.setItem('cookieConsentAccepted', 'true'); var consent = document.getElementById('cookieConsent'); if (consent) consent.style.display = "none"; }); } });


3. Reference the Partial and Script in Your Layout

In /Views/main.cshtml:

  1. Add the partial where you want the popup (usually before </body>):

    @Html.Partial("Partials/CookieConsent")
    
  2. Add the script tag after jQuery/Bootstrap and before </body>:

    <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
    <script src="~/js/CookieConsent.js"></script>
    

    (Adjust the path to where you put the JS file.)


4. Result and Best Practices

  • The cookie consent bar appears at the bottom of the page only if the user hasn’t accepted before.

  • Clicking Accept stores the flag in localStorage and hides the bar.

  • The logic is now modular and can be maintained/extended easily (translations, expiry, etc).


Summary Table

Step File/Location What to Do
Partial /Views/Partials/CookieConsent.cshtml Create the HTML structure
JS File /js/CookieConsent.js Add JS logic for showing/hiding on user action
Reference /Views/main.cshtml Add @Html.Partial and <script src=...> tags

Extra

  • For full compliance (GDPR, etc.), you may want to link a “Learn more” to your privacy policy, or use a cookie management library in production.

⚠️ **GitHub.com Fallback** ⚠️