Welcome back! In Part 1 of the series, I covered creating a VERY basic MVC site and pulling in some Kentico-hosted content. This article is going to keep the party going with applying a design, implementing the new Page Builder functionality, and setting ourselves up for some custom widget development.
TL:DR Version
- With MVC, you are open to use nearly any presentation design or framework you want. Be sure to pick one that fits your skills and needs, and then go crazy with it!
- Bundling script and design files saves valuable bandwidth and increases performance. Implementing this within your MVC sites is a quick and easy process using the ScriptBundle functionality included with ASP.NET MVC 5.
- Use page type fields to ensure your content structure matches your design, while providing a simple interface for editors.
- The Page Builder functionality is what will enable a drag-and-drop experience for your editors on your MVC pages. Be sure to register the component within your MVC site, following the documentation.
- Once the Page Builder functionality is implemented, you can add an editable area to any MVC page to allow dynamic content.
- The Page Builder is best suited for landing pages. This is because of some limitations when it comes to searching and translating content. Be sure to only use editable areas that work with these limitations.
Overview
If you followed along with Part 1 of this series, then you know we have a basic Kentico 12 MVC site with some very epic content. Our design was, let’s say minimalistic, to keeps things simple. Our next step in the process will be to jazz things up a bit with a classy, responsive look to our site.
Choosing a design
As an uber-awesome front-end designer, I, of course, have tons of great ideas when it comes to how a site should look and feel. Riiiiiiight. Chumps like me know where to get HTML templates for free and I often head over to HTML5Up for some great looking, responsive templates. For this site, I’m going with the Editorial design, which will give me a nice side nav and flow to the information.
When it comes to Kentico MVC sites, you are free to implement any design you like using most modern frameworks. Many developers opt for entire JavaScript libraries like Angular, React, or Vue. Me, I’m going to keep things simple and stick with the Editorial template. For your sites, I encourage you to explore innovative SPA designs to improve site performance.
With the design selected and downloaded, it’s time to port it over to the MVC site. I like to open up the template in Visual Studio Code (so I get color-coding) and move each piece that I need. I also open the template up in a browser, so I get an idea of where each component displays on the page.
Because this design is responsive, there’s some specific JavaScript and design files that are needed. I copy those to my MVC site and include them in the project under the Content folder to keep things organized.
Now, I need to get my “master page” looking correct and using the new files. By using the original template as a guide, I can see where the CSS and scripts files need to be loaded for the template. I add links to the new CSS and JavaScript files to the /Shared/_layout.cshtml file. I also isolate the main content area in the template and add the @RenderBody code to designate where my views will load their output.
@{
Layout = null;
}
<!DOCTYPE html>
<
head
>
<
title
>@ViewBag.Title</
title
>
<
meta
charset
=
"utf-8"
/>
<
meta
name
=
"viewport"
content
=
"width=device-width, initial-scale=1, user-scalable=no"
/>
<
link
rel
=
"stylesheet"
href
=
"/content/assets/css/main.css"
/>
</
head
>
<
body
class
=
"is-preload"
>
<!-- Wrapper -->
<
div
id
=
"wrapper"
>
<!-- Main -->
<
div
id
=
"main"
>
<
div
class
=
"inner"
>
<!-- Header -->
<
header
id
=
"header"
>
Kentico MVC Widget Showcase</
a
>
</
header
>
@RenderBody()
</
div
>
</
div
>
<!-- Sidebar -->
<
div
id
=
"sidebar"
>
<
div
class
=
"inner"
>
<!-- Search -->
<
section
id
=
"search"
class
=
"alt"
>
<
form
method
=
"post"
action
=
"#"
>
<
input
type
=
"text"
name
=
"query"
id
=
"query"
placeholder
=
"Search"
/>
</
form
>
</
section
>
<!-- Menu -->
<
nav
id
=
"menu"
>
<
header
class
=
"major"
>
<
h2
>Menu</
h2
>
</
header
>
<
ul
>
<
li
><
a
href
=
"index.html"
>Homepage</
a
></
li
>
<
li
><
a
href
=
"mvcwidgets/index.html"
>MVC Widgets</
a
></
li
>
</
ul
>
</
nav
>
<!-- Footer -->
<
footer
id
=
"footer"
>
<
p
class
=
"copyright"
>Copyright © 2004-@DateTime.Now.Year Kentico Software.</
p
>
</
footer
>
</
div
>
</
div
>
</
div
>
<!-- Scripts -->
<
script
src
=
"/content/assets/js/jquery.min.js"
></
script
>
<
script
src
=
"/content/assets/js/browser.min.js"
></
script
>
<
script
src
=
"/content/assets/js/breakpoints.min.js"
></
script
>
<
script
src
=
"/content/assets/js/util.js"
></
script
>
<
script
src
=
"/content/assets/js/main.js"
></
script
>
</
body
>
</
html
>
NOTE:
This design has a lot of other components that I want to clean, simplify, and/or omit. I clean up the sidebar, removing many of the extra links and sections, along with some areas of the main content section. I also add a new link for MVC Widgets, which is a page I’ll be adding later.
Script Bundling
Before I do any more with the design, I want to clean things up even more and ensure the site performance will be good. ASP.NET MVC 5 comes with the ScriptBundle class, which automatically bundles multiple JavaScript files into a single call, as well as minimizes the code. This reduces the amount of scripts a page request requires, as well as reducing the overall bandwidth. If you don’t want to go with ASP.NET’s functionality, you can also use frameworks such as webpack, gulp, or grunt to do the same thing.
In my MVC project, I created a new class in the /App_Start folder named BundleConfig.cs. I created a single method named RegisterThemeJSBundle to collect all the theme-related JavaScript files.
<!-- Scripts -->
@Scripts.Render(
"/bundles/themejs"
)
private
static
void
RegisterThemeJSBundle(BundleCollection bundles)
{
// create an object of ScriptBundle and
// specify bundle name (as virtual path) as constructor parameter
ScriptBundle scriptBndl =
new
ScriptBundle(
"/bundles/themejs"
);
//use Include() method to add all the script files with their paths
scriptBndl.Include(
"/content/assets/js/jquery.min.js"
,
"/content/assets/js/browser.min.js"
,
"/content/assets/js/breakpoints.min.js"
,
"/content/assets/js/util.js"
,
"/content/assets/js/main.js"
);
//Add the bundle into BundleCollection
bundles.Add(scriptBndl);
}
NOTE:
You can create multiple methods for different bundles, if needed.
In my Global.asax.cs file, I register the BundleConfig class.
protected
void
Application_Start()
{
…
// Register the script bundles
BundleConfig.RegisterBundles(BundleTable.Bundles);
…
}
Lastly, I update my Shared/_layout.cshtml file to include the new ScriptBundle object.
<!-- Scripts -->
@Scripts.Render("/bundles/themejs")
Home Page Class Update
While we could technically test the design, I want to make a quick update to the Home Page type. To match the Editorial design a little better, in my Admin site, I add Subheader and IntroText fields to the class. This will allow editors to enter this information easily, and have it match the new design.
Next, I update the Home content item with some new text.
After updating the page type, I need to click Generate Code on the Code tab to recreate the class and copy it to the MVC site.
Home View
With the new HomePage and HomePageProvider classes in my MVC project, I can update the Home view to use the new fields. Matching the design from the original template, I update the view to display the Subheader and IntroText fields.
@model CMS.DocumentEngine.Types.KenticoMVCWidgetShowcase.HomePage
@{
ViewBag.Title = "Home";
Layout = "/Views/Shared/_layout.cshtml";
}
<!-- Banner -->
<
section
id
=
"banner"
>
<
div
class
=
"content"
>
<
header
>
<
h1
>
@Model.HeaderText
</
h1
>
<
p
>!@Model.SubheaderText</
p
>
</
header
>
<
p
>@Model.IntroText</
p
>
</
div
>
@if (Model.HeaderImage.ToString() != "")
{
string headerimageurl = Url.Kentico().ImageUrl(Model.HeaderImage, SizeConstraint.MaxWidthOrHeight(400));
<
span
class
=
"image object"
>
<
img
src
=
"@headerimageurl"
alt
=
"@Model.HeaderText"
/>
</
span
>
}
</
section
>
Testing
With the new template applied, I am ready to test the site. Because the @RenderBody code is still there, the Home page should load as normal. And, man, it’s already looking good!
And here is the design on a mobile-sized browser.
By going with a pre-made responsive template, I can be sure the site will look good on any screen width.
MVC Widgets Page – Admin Site
Remember that MVC Widgets link we put in the sidebar? It’s time to create that page. Following the same process for the HomePage page type, I create a new MVCWidgetsPage page type that inherits from my ContentPage class.
Similar to the HomePage class, I add HeaderText and IntroText fields. This page won’t need a header image or subheader field, so I’ll leave those out of the configuration.
Next, I create a new page in my content tree for the MVCWidgets page and enter some basic text.
Lastly, I generate the new class to include within my MVC project.
MVC Widgets Page – MVC
With the new page type and content created, I am ready to create the page within the MVC site. I create a new controller and view for the MVCWidgets route.
The MVCWidgetsController.cs file contains some basic code to pull the content from the Admin site.
// GET: MVCWidgets
public
ActionResult Index()
{
// Gets the latest version of a single article using the generated provider
MVCWidgetsPage page = MVCWidgetsPageProvider.GetMVCWidgetsPage(
"/mvcwidgets"
,
"en-us"
,
"KenticoMVCWidgetShowcase"
);
// Returns a 404 error when the retrieving is unsuccessful
if
(page ==
null
)
{
return
HttpNotFound();
}
return
View(page);
}
And the MVCWidgets view display the HeaderText and IntroText fields. Note, the @model for the view is a MVCWidgetsPage object. This allows us to access those custom fields.
@model CMS.DocumentEngine.Types.KenticoMVCWidgetShowcase.MVCWidgetsPage
@{
ViewBag.Title = "index";
Layout = "/Views/Shared/_layout.cshtml";
}
<!-- Banner -->
<
section
id
=
"banner"
>
<
div
class
=
"content"
>
<
header
>
<
h1
>
@Model.HeaderText
</
h1
>
</
header
>
<
p
>@Model.IntroText</
p
>
</
div
>
</
section
>
Now, let’s see how the new page looks.
OK, awesome! Our new page is being displayed properly and bringing in the custom page type fields.
Implementing the Page Builder functionality
The last part of this article will cover implementing the Page Builder functionality. This component allows our editors to drag and drop content elements onto an MVC page and have much more control. This is a pretty easy process that is covered in our documentation.
Page Builder Development Documentation
In my App_Start/ApplicationConfig.cs file, I add the UsePageBuilder code to register the functionality.
public
static
void
RegisterFeatures(IApplicationBuilder builder)
{
// Enable required Kentico features
// Gets the ApplicationBuilder instance
// Allows you to enable and configure Kentico MVC features
// Enables the preview feature
ApplicationBuilder.Current.UsePreview();
ApplicationBuilder.Current.UsePageBuilder();
}
NOTE
Visual Studio updated the code to use an inline temporary variable to simplify the implementation.
Next, I add the Kentico.PageBuilder.Web.Mvc namespace to the Views/web.config file.
<
system.web.webPages.razor
>
<
host
factoryType
=
"System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
/>
<
pages
pageBaseType
=
"System.Web.Mvc.WebViewPage"
>
<
namespaces
>
…
<
add
namespace
=
"Kentico.PageBuilder.Web.Mvc"
/>
…
</
namespaces
>
</
pages
>
</
system.web.webPages.razor
>
With the Page Builder registered, I am ready to update the controller and view. First, I need to update my layout to include the Page Builder scripts and styles. In my case, this meant adding the following code to include the styles in my HEAD tag in my Views/Shared/_layout.cshtml file.
<
head
>
<
title
>@ViewBag.Title</
title
>
<
meta
charset
=
"utf-8"
/>
<
meta
name
=
"viewport"
content
=
"width=device-width, initial-scale=1, user-scalable=no"
/>
<
link
rel
=
"stylesheet"
href
=
"/content/assets/css/main.css"
/>
<
link
rel
=
"shortcut icon"
type
=
"image/x-icon"
href
=
"/favicon.ico"
/>
@Html.Kentico().PageBuilderStyles()
</
head
>
Next, I add the scripts before the closing BODY tag.
@Html.Kentico().PageBuilderScripts()
</
body
>
</
html
>
In the Home controller, I initiate the Page Builder, by passing the DocumentID to the method. This is what tells the PageBuilder which content item within the Admin site to access for the content.
// GET: Home
public
ActionResult Index()
{
// Gets the latest version of a single article using the generated provider
HomePage page = HomePageProvider.GetHomePage(
"/home"
,
"en-us"
,
"KenticoMVCWidgetShowcase"
);
// Returns a 404 error when the retrieving is unsuccessful
if
(page ==
null
)
{
return
HttpNotFound();
}
// Initializes the page builder with the DocumentID of the page
HttpContext.Kentico().PageBuilder().Initialize(page.DocumentID);
return
View(page);
}
Then, I create a new EditableArea in the Home view.
…
<
section
>
@Html.Kentico().EditableArea("area1")
</
section
>
…
Testing
Adding the EditableArea on the view tells the Kentico Admin site that there is a section of the page that editors can add dynamic content to. In order to allow this, be sure to check the Use Page tab option for the page type you are using.
In the Content module, I click the Home content item and confirm I have a functioning EditableArea.
Success! The new selection pane that pops up tells me that the Page Builder is registered properly and the Home view is ready for some MVC Widgets. There’s not much listed there for now as only the Forms widget comes out of the box. In later articles, we’ll add more widgets for the user to select.
A Few Notes about Page Builder
As I noted before, the recommended use for Page Builder is on landing pages. Here are a few important notes about using EditableAreas.
- Because the content in EditableAreas is not searchable or translated, this may introduce some issues into your site content and functionality. This means that with a free text entry widget where the user can enter custom content, that text will not be picked up by the standard Kentico search.
- The content may be picked up by a crawler search, but this may not be suitable for every site. Be sure to test this functionality fully in your applications.
- If you choose to use Page Builder in other areas, be sure the content you are loading is properly suited.
- Simple listings (of content in the content tree) may be suitable in other areas as their content will be managed within the Pages module.
We are continuing to reseach and develop more capabilities when it comes to widget content. This includes search and translation features to allow more cusotmization and use. Be sure to watch the Product Roadmap page for updates in future versions of the platform.
Wrapping Up
In this article, I showed you how to easily apply a snazzy design to your MVC site, update page types, and create new sections of your MVC project. In addition, we’ve registered the Page Builder functionality and prepared our environment for custom widgets. In the next article, we’ll create a custom widget, register it within the site, and add it to our EditableArea. See you next time!