Skip to content

Templates: Rename "Master Template" to "Layout Template"#21743

Merged
AndyButland merged 6 commits into
v18/devfrom
v18/improvement/rename-master-template-to-layout
May 4, 2026
Merged

Templates: Rename "Master Template" to "Layout Template"#21743
AndyButland merged 6 commits into
v18/devfrom
v18/improvement/rename-master-template-to-layout

Conversation

@nul800sebastiaan

@nul800sebastiaan nul800sebastiaan commented Feb 12, 2026

Copy link
Copy Markdown
Member

Description

Renames "Master Template" terminology to "LayoutTemplate" throughout the codebase, aligning with ASP.NET MVC conventions.

The term "Master Template" is inherited from when Umbraco was based on ASP.NET Web Forms. We should have adopted "Layout", which was introduced with the Razor View Engine in MVC 3.0 back in 2011(!) - this change is long overdue.

I could have simply updated the translation file to change the UI label, but I've submitted this as a complete fix since we're 14 years late to the party.

Summary

  • Renames "Master Template" terminology to "Layout Template" across C# models, services, repositories, Management API, and backoffice frontend
  • Since Umbraco switched from WebForms to MVC, the "Master" template terminology has been incorrect — in Razor/MVC the parent template is called a "Layout", not a "Master page"
  • Old names (MasterTemplateAlias, MasterTemplateId, IsMasterTemplate, etc.) are preserved as [Obsolete] members delegating to the new names, scheduled for removal in Umbraco 20
  • The Management API response includes both layoutTemplate (new) and masterTemplate (deprecated) properties for backward compatibility
  • Package XML import supports both old <Master> and new <LayoutTemplate> element names
  • Only en.ts localization updated — other languages fall back to English until native speakers provide translations

Breaking changes

  • ITemplate interface: IsLayoutTemplate and LayoutTemplateAlias are now the required members (implementors of ITemplate must add these — the old names became default-implementation compat shims)
  • Named argument usage on ITemplateService/ITemplateRepository/IFileService parameter renames (masterTemplateIdlayoutTemplateId)

Test plan

  • Solution builds with 0 errors
  • 75 template unit tests pass
  • 133 template integration tests pass
  • Backoffice UI shows "Layout template: No layout" instead of "Master template: No master"
  • Verify OpenAPI spec regeneration includes both layoutTemplate and masterTemplate fields
  • Verify acceptance tests pass against running instance

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings February 12, 2026 15:43
@nul800sebastiaan nul800sebastiaan force-pushed the v18/improvement/rename-master-template-to-layout branch from 50365f9 to 13a1841 Compare February 12, 2026 15:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates Umbraco’s template terminology from “Master Template” to “Layout Template” across the backend (models/services/repositories), Management API contracts, and the backoffice UI, while preserving backwards compatibility via [Obsolete] shims and deprecated API fields.

Changes:

  • Renames template parent/relationship concepts from MasterTemplate* to LayoutTemplate*, including operation statuses and parsing logic.
  • Updates Management API response models and generated frontend API types to include layoutTemplate (new) alongside masterTemplate (deprecated).
  • Adjusts tests (unit/integration/acceptance) and backoffice UI to reflect the new terminology and UI bindings.

Reviewed changes

Copilot reviewed 37 out of 37 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tests/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/TemplateBuilderTests.cs Updates builder test assertions to use layout template properties.
tests/Umbraco.Tests.UnitTests/Umbraco.Core/Models/TemplateTests.cs Updates clone behavior assertions to layout template properties.
tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/TemplateServiceTests.cs Updates integration expectations from master to layout template alias/status.
tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/FileServiceTests.cs Updates FileService integration assertions to layout template alias.
tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/TemplateRepositoryTest.cs Updates repository tests to set layout template alias/id directly.
tests/Umbraco.Tests.Integration/ManagementApi/Template/Tree/ChildrenTemplateTreeControllerTests.cs Updates Management API tree tests to use layout template properties.
tests/Umbraco.Tests.Common/Builders/TemplateBuilder.cs Adds AsLayoutTemplate builder API and obsoletes AsMasterTemplate.
tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Settings/Template/Templates.spec.ts Renames acceptance test descriptions and switches assertions to layoutTemplate.
src/Umbraco.Web.UI.Client/src/packages/templating/templates/workspace/template-workspace.context.ts Renames workspace context state/observables and persistence to layoutTemplate.
src/Umbraco.Web.UI.Client/src/packages/templating/templates/workspace/template-workspace-editor.element.ts Renames UI state/handlers/IDs and localization keys to layout template.
src/Umbraco.Web.UI.Client/src/packages/templating/templates/types.ts Introduces layoutTemplate and keeps masterTemplate as deprecated optional.
src/Umbraco.Web.UI.Client/src/packages/templating/templates/repository/detail/template-detail.server.data-source.ts Updates scaffold and server mapping to use layoutTemplate.
src/Umbraco.Web.UI.Client/src/packages/core/backend-api/types.gen.ts Updates generated API type to include layoutTemplate and deprecate masterTemplate.
src/Umbraco.Web.UI.Client/src/mocks/data/template/template.data.ts Updates mock template data shape and labels for layout template.
src/Umbraco.Web.UI.Client/src/assets/lang/en.ts Adds new layouttemplate / noLayout strings while retaining legacy keys.
src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TemplateRepository.cs Renames repository APIs and mapping logic to layout template terminology.
src/Umbraco.Infrastructure/Persistence/Mappers/TemplateMapper.cs Updates node parent mapping from MasterTemplateId to LayoutTemplateId.
src/Umbraco.Infrastructure/Persistence/Factories/TemplateFactory.cs Updates DTO/entity mapping to use layout template id/flags.
src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs Supports both <Master> and <LayoutTemplate> while importing templates.
src/Umbraco.Core/Services/TemplateService.cs Renames core service logic/status handling to layout template naming.
src/Umbraco.Core/Services/TemplateContentParserService.cs Renames parser API to LayoutTemplateAlias and updates docs accordingly.
src/Umbraco.Core/Services/OperationStatus/TemplateOperationStatus.cs Introduces layout-template statuses and obsoletes old master-template ones.
src/Umbraco.Core/Services/ITemplateService.cs Renames children/descendants APIs and parameter names to layout template.
src/Umbraco.Core/Services/ITemplateContentParserService.cs Adds LayoutTemplateAlias and keeps MasterTemplateAlias as obsolete shim.
src/Umbraco.Core/Services/IFileService.cs Renames template-related method parameter names to layout template.
src/Umbraco.Core/Services/FileService.cs Updates FileService template methods to forward using layout template parameters.
src/Umbraco.Core/Services/EntityXmlSerializer.cs Switches serialization guard to layout template id while keeping <Master> elements.
src/Umbraco.Core/Persistence/Repositories/ITemplateRepository.cs Renames repository APIs from master-template to layout-template naming.
src/Umbraco.Core/Models/Template.cs Renames model fields/properties and adds obsolete compatibility members.
src/Umbraco.Core/Models/ITemplate.cs Makes layout-template members primary and keeps master-template members as obsolete defaults.
src/Umbraco.Core/IO/ViewHelper.cs Uses LayoutTemplateAlias when ensuring inherited layout content.
src/Umbraco.Cms.Api.Management/ViewModels/Template/TemplateResponseModel.cs Adds LayoutTemplate and keeps MasterTemplate as obsolete alias.
src/Umbraco.Cms.Api.Management/Mapping/Template/TemplateViewModelMapDefinition.cs Updates mapping docs to reflect layout template members.
src/Umbraco.Cms.Api.Management/Factories/TemplatePresentationFactory.cs Populates LayoutTemplate reference based on LayoutTemplateAlias.
src/Umbraco.Cms.Api.Management/Controllers/Template/TemplateControllerBase.cs Updates problem details mapping to layout-template operation statuses/messages.
src/Umbraco.Cms.Api.Management/Controllers/Template/Item/ItemTemplateItemController.cs Updates inline comments from “master template” to “layout template”.
Comments suppressed due to low confidence (15)

tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/FileServiceTests.cs:33

  • Call to obsolete method CreateTemplateWithIdentity.
    tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/FileServiceTests.cs:34
  • Call to obsolete method CreateTemplateWithIdentity.
    tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/FileServiceTests.cs:47
  • Call to obsolete method CreateTemplateWithIdentity.
    tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/FileServiceTests.cs:48
  • Call to obsolete method CreateTemplateWithIdentity.
    tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/FileServiceTests.cs:65
  • Call to obsolete method CreateTemplateWithIdentity.
    tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/FileServiceTests.cs:66
  • Call to obsolete method CreateTemplateWithIdentity.
    tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/FileServiceTests.cs:67
  • Call to obsolete method CreateTemplateWithIdentity.
    tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/FileServiceTests.cs:84
  • Call to obsolete method CreateTemplateWithIdentity.
    tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/FileServiceTests.cs:85
  • Call to obsolete method CreateTemplateWithIdentity.
    tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/FileServiceTests.cs:86
  • Call to obsolete method CreateTemplateWithIdentity.
    tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/FileServiceTests.cs:113
  • Call to obsolete method CreateTemplateWithIdentity.
    tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/FileServiceTests.cs:114
  • Call to obsolete method CreateTemplateWithIdentity.
    tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/FileServiceTests.cs:115
  • Call to obsolete method CreateTemplateWithIdentity.
    tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/FileServiceTests.cs:117
  • Call to obsolete method GetTemplates.
    tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/FileServiceTests.cs:126
  • Call to obsolete method CreateTemplateWithIdentity.

Comment thread src/Umbraco.Core/Services/EntityXmlSerializer.cs Outdated
Comment thread src/Umbraco.Core/Services/TemplateService.cs
Comment thread src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs Outdated
Since Umbraco switched from WebForms to MVC, the "Master" template
terminology has been incorrect — in Razor/MVC the parent template is
called a "Layout", not a "Master page". This renames the concept across
C# models, services, repositories, the Management API, and the
backoffice frontend while preserving backward compatibility via
[Obsolete] members scheduled for removal in Umbraco 20.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@nul800sebastiaan nul800sebastiaan force-pushed the v18/improvement/rename-master-template-to-layout branch from 13a1841 to 5e5b6ff Compare February 12, 2026 15:53

@AndyButland AndyButland left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great @nul800sebastiaan, thanks for taking the time to to do this, it's well overdue. I just had a couple of comments for you to have a look at.

Just to understand what may still need doing, how much manual testing have you done with this please? We should check:

  • Can install a clean site, and all functionality relating to creating and editing templates works as expected.
  • A package can be created that includes templates with layouts, the data deleted and the import works as expected.
  • A package can be created from Umbraco 17 that includes templates with layouts, and the import works as expected.

Comment thread src/Umbraco.Core/Services/EntityXmlSerializer.cs Outdated
Comment thread src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs Outdated
@nul800sebastiaan

Copy link
Copy Markdown
Member Author

Just to understand what may still need doing, how much manual testing have you done with this please? We should check:

I have now ran those checks manually!
Then I thought I should probably write some integration tests for them, but I did run into a small surprise around that: #21743 (comment)

Good other finds and I'll adjust those once we decide what to do with the package.xml as noted there!

@nul800sebastiaan

Copy link
Copy Markdown
Member Author

Also tagging @ronaldbarendse here as we'll probably need some Deploy adjustments.

As well as @KevinJump who was already aware of my first attempt at this but since I had to make it breaking he still has a few versions to adjust his code :)

@nul800sebastiaan

Copy link
Copy Markdown
Member Author

I've attached the test I did with the package.xml that was generated and a NuGet that can be installed to create the template (3 levels deep) and a doctype that has relinked the template after install as well.

TemplateTest.zip

image

The serializer code that wrote <Master>/<MasterAlias> elements was never
executed because Lazy<int>.IsValueCreated was always false after loading
from the database. The corresponding import code that read these elements
was equally dead since no package.xml ever contained them. Template
parent-child hierarchy is resolved from Razor Layout directives instead.

Also renames 4 test methods from "Master" to "Layout" to match the
updated terminology.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ronaldbarendse

Copy link
Copy Markdown
Contributor

@nul800sebastiaan Looks like a sensible change and should be easy to pick up in Deploy as part of the v18 breaking changes 👍🏻

However, I've seen quite a few problems caused by the way templates are currently tracked:

  • The template files need to exist on disk, which is the reason why the default project template ships with CopyRazorGenerateFilesToPublishDirectory=true. However, with the push to compile views at build time (by not shipping with a dependency on the runtime compilation package), editing these files in the backoffice doesn't make a lot of sense anymore. In most cases, the template editor will be read-only anyway due to this.
  • We're also keeping track of templates in the database, which can become out-of-sync (requiring you to re-save a template in the backoffice to create a corresponding database entry).
  • If multiple templates are saved at the same time (e.g. when running a package migration or a Deploy schema deployment), the ITemplateContentParserService can be called in the wrong order and not yet find the master/layout in the database, causing it to fail with TemplateOperationStatus.MasterTemplateNotFound.

As far as I can tell, the templates from the database are only used when configuring a content type, so you don't have to browse through all views (as templates don't include partial views and any layouts).

Just fetching the views from a populated ViewsFeature and only including files on disk when runtime compilation is available (the Umbraco.Cms.DevelopmentMode.Backoffice package is installed) should be very easy to implement and require way less code to maintain. It will even correctly support precompiled views by default, even if they are shipped inside a Razor Class Library (which would even allow for re-usable/distributable views).

The following code will render a list of all compiled views. We can easily filter out views from the Views/Partials directory, file names starting with an underscore and maybe some other conventions, so you end up with a similarly small list of allowed templates to pick in the content type editor:

@using Microsoft.AspNetCore.Mvc.Razor.Compilation
@inject Microsoft.AspNetCore.Mvc.ApplicationParts.ApplicationPartManager applicationPartManager
@{
    var viewsFeature = new ViewsFeature();
    applicationPartManager.PopulateFeature(viewsFeature);
    var paths = viewsFeature.ViewDescriptors.Select(x => x.RelativePath).ToHashSet(StringComparer.OrdinalIgnoreCase);
}
<ul>
    @foreach (var path in paths)
    {
        <li>@path</li>
    }
</ul>

@AndyButland

Copy link
Copy Markdown
Contributor

Thanks @ronaldbarendse - though maybe you could move those comments into a discussion on the topic of template storage in the database? I wouldn't expect Seb to address that as part of this PR.

@AndyButland

Copy link
Copy Markdown
Contributor

I've just done some testing, creating a package with two templates, one the layout of the other, and then creating a package migration to import it.

It works, although there is a confusing message in the log:

[10:41:35 INF] Starting package migration for Test Template [Timing 5b890f4]
[10:41:35 INF] Starting 'Test Template'...
[10:41:35 INF] At origin
[10:41:35 INF] Execute MigrateToPackageData
[10:41:35 INF] Template 'testLayout' has an invalid Layout 'null', so the reference has been ignored.
[10:41:35 INF] Package migration executed. Summary: Conflicting templates found, they will be overwritten: testLayout, testTemplateWithLayout

However it's exactly the same on v18/dev, so it doesn't seem related to these changes:

[10:43:36 INF] Starting package migration for Test Template [Timing ca745ad]
[10:43:36 INF] Starting 'Test Template'...
[10:43:36 INF] At origin
[10:43:36 INF] Execute MigrateToPackageData
[10:43:36 INF] Template 'testLayout' has an invalid Master 'null', so the reference has been ignored.
[10:43:37 INF] Package migration executed. Summary: Conflicting templates found, they will be overwritten: testLayout, testTemplateWithLayout

@nul800sebastiaan

Copy link
Copy Markdown
Member Author

@AndyButland yeah that looks like a pre-existing confusing message! Of course the Layout file itself can legitimately have Layout = null in it, in which case we don't really need to log that as it could be confusing (as it is now).
Up to you what you want to do, happy to ignore Layout = null and only log if there's a problem with a non-null referenced layout.

@AndyButland

Copy link
Copy Markdown
Contributor

That sounds better to me - but it's an existing issue so not one you have to tackle in this PR unless you are minded to.

@nul800sebastiaan nul800sebastiaan added the status/needs-docs Requires new or updated documentation label Apr 30, 2026
Sebastiaan Janssen and others added 2 commits April 30, 2026 15:51
…name-master-template-to-layout

# Conflicts:
#	src/Umbraco.Cms.Api.Management/ViewModels/Template/TemplateResponseModel.cs
#	src/Umbraco.Core/Services/FileService.cs
#	src/Umbraco.Core/Services/IFileService.cs
#	src/Umbraco.Core/Services/OperationStatus/TemplateOperationStatus.cs
#	src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TemplateRepository.cs
#	src/Umbraco.Web.UI.Client/mocks/data/sets/default/template.data.ts
#	src/Umbraco.Web.UI.Client/src/packages/templating/templates/workspace/template-workspace-editor.element.ts
#	tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/FileServiceTests.cs
A null Layout is legitimate for root layout files (e.g. `Layout = null;`)
and shouldn't be reported as "invalid". Only log when a non-null Layout
was referenced but couldn't be resolved in the import.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@nul800sebastiaan

Copy link
Copy Markdown
Member Author

Alright, I have updated this PR now as a lot of obsolete stuff had been removed (YAY!) and that led to loads of merge conflicts. It should build again now and me and Uncle Claude also addressed the layout is null spam. Should be good to go now!

@AndyButland AndyButland left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have updated the test helpers (we could more easily do this now, as they've been moved into this repository). Otherwise given it a re-test, creating and updating templates and layouts, and all works as it should.

There's needs-docs label on the PR @nul800sebastiaan - can I ask if you plan to pick that up too please? There's an "18" folder in the docs repository now for updating.

@AndyButland AndyButland merged commit 101acdd into v18/dev May 4, 2026
32 checks passed
@AndyButland AndyButland deleted the v18/improvement/rename-master-template-to-layout branch May 4, 2026 08:01
@nul800sebastiaan

Copy link
Copy Markdown
Member Author

Great!! Thanks @AndyButland - yes I should've linked to the Docs PR I'm working on: umbraco/UmbracoDocs#8025

@ronaldbarendse will you and team Deploy pick this up? I think there might actually not be much to do, it "just" creates different aliases/template files, I don't think Deploy cares at all.. right?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

category/breaking release/18.0.0 status/needs-docs Requires new or updated documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants