Smart Systems
connecting Businesses

Article

Kooboo Tips and Tricks

Synopsis

A modern, web Content Management System is a tool that allows users to build complex websites, drawing in content from a multitude of disparate data sources and presenting them in ever more elegant ways.

In order to cater for changing data schemas and evolving presentation techniques, a good CMS needs to provide fairly low-level access for developers to dig deep into the heart of the system and achieve their goals. However, providing developers with this power often means that they are trying new techniques that are not documented anywhere and can take time to implement correctly.

Once these new techniques are demonstrated the popular ones can be encapsulated into plugins or extensions to standardise and simplify their reuse. Until that happens though, each technique remains something that a developer must spend time researching and defining.

Below are some of these techniques that I have used in the past with Kooboo CMS v4.3. They are shared here for the Kooboo community to freely re-use, and refine.

Layouts

  • As far as I am aware, Layouts do not support Parameters or Nested Layouts.
  • For performance reasons it is advised (https://developer.yahoo.com/blogs/ydnfiveblog/high-performance-sites-rule-6-move-scripts-bottom-7200.html) to have script references at the foot of the page, not in the header. However if you tell a Kooboo Site to include jQuery then that script is automatically added to the html <head> section, regardless of where in the HTML you tell the scripts to render. Combine that with the difficulty in controlling the jQuery version used, and the fact that you may want to use an external CDN version and I have found it best to tell sites to not include jQuery in the page, and for me to instead manually include it myself at the foot of the page.
  • A CMS site usually uses a single consistent <doctype> across the board, however often also has multiple layout templates, sometimes dozens. For consistency and single point of maintenance, I sometimes move these to a separate view.
  • The tags included inside the html <head> section usually contain a lot of consistent across layouts, with the differences implemented on a page level. To keep things clean and simple I usually put these in a separate view.
  • To follow best-practice (https://developer.yahoo.com/performance/rules.html#js_bottom), I render the '@Html.FrontHtml().RegisterScripts()' at the bottom of the page. However it is not uncommon for some scripts to come from third party content delivery networks. These are best held in a single view and rendered with the scripts hosted within the CMS.
  • The outcome of these pieces of advice is a layout that at its most basic looks like:
    @Html.FrontHtml().RenderView("Layout.DocTypeAndHtml",ViewData)
    <head>
    @Html.FrontHtml().RenderView("Layout.HtmlHead",ViewData)
    </head>
    <body>
    	<div class="main-wrap">
    		<div id="main-content">
    			@Html.FrontHtml().Position("Main")
    		</div>
    	</div>
    @Html.FrontHtml().RenderView("Layout.CdnScripts",ViewData)
    @Html.FrontHtml().RegisterScripts()
    </body>
    </html>
    

Views

  • Within Kooboo the only place to dynamically write logic is within Views. Creating logic in the presentation component goes against the core aims of the MVC design pattern. The correct location for logic is within a compiled plugin or module. However for practical reasons I've found it faster and more flexible to create the code required in a view and move it into a plugin / module once it is complete. For this reason, you will need to be familiar with creating helper methods (https://weblogs.asp.net/scottgu/asp-net-mvc-3-and-the-helper-syntax-within-razor) and functions (https://dotnetslackers.com/articles/aspnet/Razor-Functions-and-Helpers.aspx) within Razor views.
  • Kooboo DataRules allow simple access to data items and collections. Sometimes though it is useful to directly query for content within the view. An example of how to do this is below:
    @{
    	var countryFolder = ContentHelper.TextFolder("Country");
    	var countries = countryFolder.CreateQuery().WhereEquals("Published",true).OrderBy("Name").ToArray();
    	var countryCount = countryFolder.CreateQuery().Count();
    }
    
  • For people in the Content Management role, Kooboo's concept of 'Categories' works well; selecting one or more values from a pre-defined list is always more satisfying that manually typing in a custom value each time. Retrieving that data within a View is less obvious. Take an example where a Content Manager was adding a series of Cities and had to select a Country Category for each. The data could then be retrieved and displayed in a view like below:
    var countryFolder = ContentHelper.TextFolder("Country");
    var cityFolder = ContentHelper.TextFolder("Cities");
    var countries = countryFolder.CreateQuery().WhereEquals("Published",true).OrderBy("Name").ToArray();
    foreach (var country in countries) {
    	var citiesByCountry = cityFolder.CreateQuery().WhereEquals("Published",true).WhereCategory((IContentQuery<TextContent>)countryFolder.CreateQuery().WhereEquals("UUID",country.UUID)).OrderBy("Name");
    	foreach (var city in citiesByCountry) {
    		// Each city....
    	}
    }
    

Content

  • When defining your content types, your field names should avoid certain words so that they do not conflict with the internal CMS system fields. In the past I have had conflicts with obvious ones such as 'Id'. I generally avoid all of the following though to be on the safe side: Id, UUID, Repository, FolderName, UserKey, UtcCreationDate, UtcLastModificationDate, Published, OriginalUUID, SchemaName, ParentFolder, ParentUUID, UserId, OriginalRepository, OriginalFolder, IsLocalized, Sequence.
  • When defining a content field, make full use of the 'Tooltip' field. All too often the person managing the content is not the one who defined the content types. The 'Tooltip' field is about the only place these two different people meet and the single opportunity to convey intent.
  • People are lazy, it's a fact. When faced with tasks like filling in a series of text fields, we tend to do the bare minimum. With a content management system however the value of the system lies in the content. Omit a piece of content and you devalue the system. For this reason I try to make fields mandatory unless these is a very good reason for a field to be optional. A side effect of this approach is that the render logic of views are simpler and the appearance of pages have a more consistent layout.

Configuration & Deployment

  • For enterprise level deployments, the full DTAP environment is advised. However this can be too cumbersome for many smaller projects. I've yet to encounter a project that at the very least requires a development and a production system.
  • This next point is mentioned directly in the Kooboo CMS documentation (https://www.kooboo.com/docs/kooboo-cms/switching-content-database). However it's significant enough that I feel it warrants mentioning again; for live deployments do not use the standard xml file persistence provider. Instead look for a database provider. Without this change your site performance will be terrible for users and resource intensive for the server.
  • If you review the http headers received with a response from Kooboo CMS, by default it will include an entry for 'X-KoobooCMS-Version'. If you want to remove this either for security or performance reasons then track down the below line in the web.config file and delete it:
    <add name="KoobooCMSResponseHeader" type="Kooboo.CMS.Sites.Web.KoobooCMSResponseModule,Kooboo.CMS.Sites" />
    
  • Like-wise the server and asp version headers can be removed as explained here: https://blogs.msdn.com/b/varunm/archive/2013/04/23/remove-unwanted-http-response-headers.aspx
  • Do not forget to change the default username and password for the site admin section. Ideally disable the 'admin' user completely to make your deployment even more secure.