Page Types

Last Updated: 2018-10-11

For general information on the different rules & components available when defining content types, please refer to How To Setup Content.

Page types are the content templates for your pages. Remember that this does not necessarily mean that all pages of the same Page type has to be rendered the same way, it simply means that they have the same content structure.

The preferred way of importing Page types is by using the Piranha.AttributeBuilder package. With this package you can directly mark your Page models with the Attributes needed.

Defining a Page Type

Here's a simple example of a page with a single MarkdownField as content.

using Piranha.AttributeBuilder;
using Piranha.Extend.Fields;
using Piranha.Models;

[PageType(Title = "Markdown Page")]
public class MarkdownPage : Page<MarkdownPage>
{
[Region(Title = "Main Content")]
public MarkdownField Body { get; set; }
}

To import this page type during your application startup you add the following line to your Configure method.

using Piranha.AttributeBuilder;

var builder = new PageTypeBuilder(api)
.AddType(typeof(MarkdownPage));
builder.Build();

As you can see the PageTypeAttribute allows you to set the title that will be displayed in the manager interface. If this property is left blank the class name is used.

Disable Blocks For Page Types

If you don't want to use the Block Editor you can disable this for your Page Type by adding the following to the PageTypeAttribute.

[PageType(Title = "Markdown Page", UseBlocks = false)]

Page Routing

By default, all page request are rewritten to the route /page. Since you want to load different model types for your pages, and often render them by different views you need to specify which route should handle your Page type. Let's say we have a page that also displays a banner on top.

[PageType(Title = "Markdown Page")]
[PageTypeRoute(Title = "Default", Route = "/bannerpage")]
public class BannerPage : Page<BannerPage>
{
public class BannerRegion
{
[Field]
public StringField Title { get; set; }
[Field]
public ImageField Image { get; set; }
[Field]
public TextField Body { get; set; }
}

[Region(Title = "Main Content")]
public MarkdownField Body { get; set; }

[Region]
public BannerRegion Banner { get; set; }
}

As you can see, requests for pages of this page type will now be routed to /bannerpage.

Specifying Multiple Page Routes

Let's say we would also like to use our Banner Page as the Startpage of the site, but we might want to handle it differently by adding some content from another system, or send it to a different view. We can then just add a second PageRouteAttribute to our class.

[PageType(Title = "Markdown Page")]
[PageTypeRoute(Title = "Default", Route = "/bannerpage")]
[PageTypeRoute(Title = "Start Page", Route = "/startpage")]
public class BannerPage : Page<BannerPage>
{
...
}

By adding a second route the page settings will now show a dropdown where the editor can select which route the current page should use.

A Real World Example

As an example, let's define a Page type for a typical start page of a Site. The startpage should contain a Hero with an image, title and HTML body. Then we want a section with Teasers that can be linked to other pages in the site. As main content we'll use the standard Blocks.

using System.Collections.Generic;
using Piranha.AttributeBuilder;
using Piranha.Models;
using Piranha.Extend.Fields;

public class HeroRegion
{
[Field(Placeholder = "Hero Title", Options = FieldOption.HalfWidth)]
 public StringField Title { get; set; }

 [Field(Title = "Primary Image", Options = FieldOption.HalfWidth)]
public ImageField PrimaryImage { get; set; }

[Field]
public HtmlField Body { get; set; }
}

public class TeaserRegion
{
[Field(Placeholder = "Teaser title")]
  public StringField Title { get; set; }

  [Field(Options = FieldOption.HalfWidth)]
public ImageField Image { get; set; }

  [Field(Title = "Page Link", Options = FieldOption.HalfWidth)]
public PageField PageLink { get; set; }

[Field]
public HtmlField Body { get; set; }
}

[PageType(Title = "Start Page")]
public class StartPage : Page<StartPage>
{
[Region(Description = "The main hero shown on the top of the start page.")]
public HeroRegion Hero { get; set; }

[Region(Description = "Teasers with links to other parts of the site.")]
public IList<TeaserRegion> Teasers { get; set; } = new List<TeaserRegion>();
}

This is how the view could look for rendering the page with Bootstrap given that we have Layout defined in our project. The Layout code will be omitted from the example for clarity.

@model StartPage
@{
ViewBag.Title = Model.Title;

var hasHeroImage = Model.Hero.PrimaryImage.HasValue;
var heroImageUrl = hasHeroImage ?
$"background-image: url('{ Url.Content(Model.Hero.PrimaryImage) }')" : "";
}

<div class="hero" style="@(hasHeroImage ? heroImageUrl : "")">
<div class="container">
<h1>@Model.Hero.Title</h1>
@Html.Raw(Model.Hero.Body)
</div>
</div>

@if (Model.Teasers.Count > 0)
{
<div class="teasers">
<div class="container">
<div class="row">
@foreach (var teaser in Model.Teasers)
{
<div class="col-md teaser">
<h2>@teaser.Title</h2>
@if (teaser.Image.HasValue)
{
<img src="@Url.Content(teaser.Image)">
}
@Html.Raw(teaser.Body)
@if (teaser.PageLink.HasValue)
{
<a href="@teaser.PageLink.Page.Permalink">
Read more
</a>
}
</div>
}
</div>
</div>
</div>
}

@Html.DisplayFor(m => m.Blocks)