Module: Page Builder

5 of 15 Pages

Define the template's properties

Now that we have view models to determine the product template’s data, let’s add properties, so that editors can configure its appearance.

The properties will utilize dropdowns fed by the dropdown provider we created earlier in this series, so start by defining enumerations for different color scheme and corner style options.

Decorate options with the Description attribute to provide user-friendly names.

  • In the ~/Features/Shared/OptionProviders/ColorScheme directory:

    C#
    ColorSchemeOption.cs
    
          using System.ComponentModel;
    
          namespace TrainingGuides.Web.Features.Shared.OptionProviders.ColorScheme;
    
          public enum ColorSchemeOption
          {
              [Description("Light background, dark text")]
              Light1 = 1,
    
              [Description("Light background, dark text 2")]
              Light2 = 2,
    
              [Description("Light background, dark text 3")]
              Light3 = 3,
    
              [Description("Transparent background, dark text")]
              TransparentDark = 4,
    
              [Description("Transparent background, medium text")]
              TransparentMedium = 5,
    
              [Description("Transparent background, light text")]
              TransparentLight = 6,
    
              [Description("Dark background, light text")]
              Dark1 = 7,
    
              [Description("Dark background, light text 2")]
              Dark2 = 8
          }
      
  • In the ~/Features/Shared/OptionProviders/CornerStyle directory:

    C#
    CornerStyleOption.cs
    
          using System.ComponentModel;
    
          namespace TrainingGuides.Web.Features.Shared.OptionProviders.CornerStyle;
    
          public enum CornerStyleOption
          {
              [Description("Sharp corners")]
              Sharp = 0,
              [Description("Round corners")]
              Round = 1,
              [Description("Very round corners")]
              VeryRound = 2,
          }
      

Next, create a properties class for the ProductPage content type that utilizes these dropdowns in the ~/Features/Products folder.

C#
ProductPagePageTemplateProperties.cs

    using Kentico.PageBuilder.Web.Mvc.PageTemplates;
    using Kentico.Xperience.Admin.Base.FormAnnotations;
    using TrainingGuides.Web.Features.Shared.OptionProviders;
    using TrainingGuides.Web.Features.Shared.OptionProviders.CornerStyle;
    using TrainingGuides.Web.Features.Shared.OptionProviders.ColorScheme;

    namespace TrainingGuides.Web.Features.Products;

    public class ProductPagePageTemplateProperties : IPageTemplateProperties
    {
        [DropDownComponent(
            Label = "Color scheme",
            ExplanationText = "Select the color scheme of the template.",
            DataProviderType = typeof(DropdownEnumOptionProvider<ColorSchemeOption>),
            Order = 20)]
        public string ColorScheme { get; set; } = nameof(ColorSchemeOption.TransparentDark);

        [DropDownComponent(
            Label = "Corner style",
            ExplanationText = "Select the corner type of the template.",
            DataProviderType = typeof(DropdownEnumOptionProvider<CornerStyleOption>),
            Order = 30)]
        public string CornerStyle { get; set; } = nameof(CornerStyleOption.Round);
    }

Set up the template

With the view models and service in place, we can create the page template, register it, and serve it from a controller.

Find more details here

This section briefly goes over processes covered in Build a page template step of our Kickstart series. Please refer to it if you’d like more detailed steps and information in the context of a different example.

Note these sections in particular:

Define the view

With the view model and properties in place, you can create a view under ~/Features/Products.

Use the GetTemplateModel method to retrieve structured data and display it in a view. We’ll expand on this in the future. For now, let’s keep it simple.

cshtml
ProductPagePageTemplate.cshtml

    @using TrainingGuides.Web.Features.Products.Models
    @using TrainingGuides.Web.Features.Products

    @model TemplateViewModel<ProductPagePageTemplateProperties>

    @{
        var templateModel = Model.GetTemplateModel<ProductPageViewModel>();
    }

    <div>
        <div>
            <h3>@templateModel.NameHtml</h3>
            <p>@templateModel.ShortDescriptionHtml</p>
        </div>
        
        <div>
            <img src="@templateModel.Media.FirstOrDefault()?.FilePath" alt="@templateModel.Media.FirstOrDefault()?.Description"/>
        </div>
    </div>

Register the template

Create a new file called ProductPagePageTemplate.cs in the ~/Features/Products folder, and use it to house the registration attribute for the page template.

C#
ProductPagePageTemplate.cs

    using Kentico.PageBuilder.Web.Mvc.PageTemplates;
    using TrainingGuides;
    using TrainingGuides.Web.Features.Products;

    [assembly: RegisterPageTemplate(
        identifier: ProductPagePageTemplate.IDENTIFIER,
        name: "Product page template",
        propertiesType: typeof(ProductPagePageTemplateProperties),
        customViewName: "~/Features/Products/ProductPagePageTemplate.cshtml",
        ContentTypeNames = [ProductPage.CONTENT_TYPE_NAME],
        IconClass = "xp-box")]

    namespace TrainingGuides.Web.Features.Products;
    public static class ProductPagePageTemplate
    {
        public const string IDENTIFIER = "TrainingGuides.ProductPageTemplate";
    }

Create the controller

  1. In the ~/Features/Products folder, add a file called ProductPageController.
  2. Use an IContentItemRetriever<ProductPage> to get the product data from Xperience.
  3. Use an instance of the IProductPageService we defined earlier to convert the ProductPage to a ProductPageViewModel.
  4. Add a new ProductFeatureViewModel containing the product’s price, so that it appears in the table.
C#
ProductPageController.cs

    using Kentico.Content.Web.Mvc;
    using Kentico.Content.Web.Mvc.Routing;
    using Kentico.PageBuilder.Web.Mvc.PageTemplates;
    using Microsoft.AspNetCore.Mvc;
    using TrainingGuides;
    using TrainingGuides.Web.Features.Products.Models;
    using TrainingGuides.Web.Features.Products.Services;
    using TrainingGuides.Web.Features.Shared.Services;

    [assembly: RegisterWebPageRoute(
        contentTypeName: ProductPage.CONTENT_TYPE_NAME,
        controllerType: typeof(TrainingGuides.Web.Features.Products.ProductPageController))]

    namespace TrainingGuides.Web.Features.Products;

    public class ProductPageController : Controller
    {
        private readonly IWebPageDataContextRetriever webPageDataContextRetriever;
        private readonly IContentItemRetrieverService<ProductPage> contentItemRetriever;
        private readonly IProductPageService productPageService;

        public ProductPageController(
            IWebPageDataContextRetriever webPageDataContextRetriever,
            IContentItemRetrieverService<ProductPage> contentItemRetriever,
            IProductPageService productPageService)
        {
            this.webPageDataContextRetriever = webPageDataContextRetriever;
            this.contentItemRetriever = contentItemRetriever;
            this.productPageService = productPageService;
        }
        public async Task<IActionResult> Index()
        {
            var context = webPageDataContextRetriever.Retrieve();

            var productPage = await contentItemRetriever.RetrieveWebPageById
                (context.WebPage.WebPageItemID,
                ProductPage.CONTENT_TYPE_NAME,
                3);

            var model = await productPageService.GetProductPageViewModel(productPage);
            model.Features.Add(
                    new ProductFeatureViewModel
                    {
                        Key = "price-from-product-content-item",
                        Name = "Price",
                        LabelHtml = new("Price"),
                        Price = model.Price,
                        ValueHtml = new(string.Empty),
                        FeatureIncluded = false,
                        ValueType = ProductFeatureValueType.Number,
                        ShowInComparator = true,
                    });

            return new TemplateResult(model);
        }
    }

Check your progress

We’ve been focused on code for a while, so let’s double-check that everything is working on the site.

  1. Log into the Xperience admin and open the Training guides pages channel.
  2. Choose one of the Product page pages under the Products page in the tree, and edit the page on the Page Builder tab.
  3. Click the page icon in the bottom left corner of the Page Builder frame to configure the Page Builder properties.
  4. Choose the Product page template, and see how the data from the product page is now displayed according to your templates.

If you’re not seeing any output, make sure the product page type is included in the UsePageBuilder call during the application’s startup sequence, try putting breakpoints in the controller and view. If one or both of them is not being hit, it could indicate an issue in one of the registration attributes for the controller or page template.