--- myst: html_meta: "description": "" "property=og:description": "" "property=og:title": "" "keywords": "" --- # Theme Package II: Build Your Diazo-Based Theme In the previous section we {doc}`prepared our setup for our custom theme package `. Now we will adjust the skeleton we got using `bobtemplates.plone` and build our Diazo theme. You can start with the example files in the theme folder. Change the {file}`index.html` and {file}`custom.less` files to customize the default theme to your needs. As stated above it's the Plone 5 default {term}`Barceloneta` theme plus some custom files you can use to to override or write CSS/Less. ## Use Your Own Static Mockup If you got a static mockup from your designer or from a website like (where the example template came from), you can use this without customization and just apply the Diazo rules to it. Another way is to change the static mockup a little bit to use mostly the same CSS id's and classes like Plone does. This way it is easier to reuse CSS/Less from Barceloneta and Plone add-ons if needed. ## Download And Prepare A Static Theme Let's start with an untouched static template, such as this Twitter Bootstrap based one: https://startbootstrap.com/theme/business-casual. The latest version of that template uses a beta version of Twitter Bootstrap 4. We are going to use the latest release which uses Twitter Bootstrap 3. Download it from https://github.com/StartBootstrap/startbootstrap-business-casual/releases/tag/v3.3.7 and extract it into the theme folder. Replace the {file}`index.html` with the one from the downloaded template. The content of your theme folder should now look like this: ```console tree -L 2 src/ploneconf/theme/theme/ src/ploneconf/theme/theme/ ├── HOWTO_DEVELOP.rst ├── LICENSE ├── README.md ├── about.html ├── backend.xml ├── barceloneta │   └── less ├── barceloneta-apple-touch-icon-114x114-precomposed.png ├── barceloneta-apple-touch-icon-144x144-precomposed.png ├── barceloneta-apple-touch-icon-57x57-precomposed.png ├── barceloneta-apple-touch-icon-72x72-precomposed.png ├── barceloneta-apple-touch-icon-precomposed.png ├── barceloneta-apple-touch-icon.png ├── barceloneta-favicon.ico ├── blog.html ├── contact.html ├── css │   ├── bootstrap.css │   ├── bootstrap.min.css │   └── business-casual.css ├── fonts │   ├── glyphicons-halflings-regular.eot │   ├── glyphicons-halflings-regular.svg │   ├── glyphicons-halflings-regular.ttf │   ├── glyphicons-halflings-regular.woff │   └── glyphicons-halflings-regular.woff2 ├── form-handler-nodb.php ├── form-handler.php ├── img │   ├── bg.jpg │   ├── intro-pic.jpg │   ├── slide-1.jpg │   ├── slide-2.jpg │   └── slide-3.jpg ├── index.html ├── js │   ├── bootstrap.js │   ├── bootstrap.min.js │   └── jquery.js ├── less │   ├── custom.less │   ├── plone.toolbar.vars.less │   ├── roboto │   ├── theme-compiled.css │   ├── theme.less │   └── theme.local.less ├── manifest.cfg ├── node_modules │   └── bootstrap ├── package-lock.json ├── package.json ├── preview.png ├── rules.xml ├── template-overrides ├── tinymce-templates │   └── image-grid-2x2.html └── views └── slider-images.pt.example 13 directories, 45 files ``` ### Preparing The Template To make the given template {file}`index.html` more useful, we customize it a little bit. Right before the second box which contains: ```html

Build a website worth visiting

``` Add this: ```html
``` And then move the main content (the box 2 and box 3 including the parent `div` with the class `row`) into the `content-container`. It should now look like this: ```{code-block} html :emphasize-lines: 1-3,35-38

Build a website worth visiting



The boxes used in this template are nested inbetween a normal Bootstrap row and the start of your column layout. The boxes will be full-width boxes, so if you want to make them smaller then you will need to customize.

A huge thanks to Death to the Stock Photo for allowing us to use the beautiful photos that make this template really come to life. When using this template, make sure your photos are decent. Also make sure that the file size on your photos is kept to a minumum to keep load times to a minimum.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc placerat diam quis nisl vestibulum dignissim. In hac habitasse platea dictumst. Interdum et malesuada fames ac ante ipsum primis in faucibus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.


Beautiful boxes to showcase your content


Use as many boxes as you like, and put anything you want in them! They are great for just about anything, the sky's the limit!

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc placerat diam quis nisl vestibulum dignissim. In hac habitasse platea dictumst. Interdum et malesuada fames ac ante ipsum primis in faucibus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.

``` ```{note} We added the portlet columns *after* the main content. Using the correct Twitter Bootstrap grid classes we can later *push* the 1st portlet column visually before the main content. ``` ### Include Theme CSS Next we need to include the CSS from the template into our {file}`theme.less` file. We will add the include of the CSS the template provides in {file}`theme/css/business-casual.css` after the `END OF UTILS` marker, but before the `custom.less` include: ```{code-block} less :emphasize-lines: 89 // theme.less file that will be compiled /* ### PLONE IMPORTS ### */ @barceloneta_path: "barceloneta/less"; // Core variables and mixins @import "@{barceloneta_path}/fonts.plone.less"; @import "@{barceloneta_path}/variables.plone.less"; @import "@{barceloneta_path}/mixin.prefixes.plone.less"; @import "@{barceloneta_path}/mixin.tabfocus.plone.less"; @import "@{barceloneta_path}/mixin.images.plone.less"; @import "@{barceloneta_path}/mixin.forms.plone.less"; @import "@{barceloneta_path}/mixin.borderradius.plone.less"; @import "@{barceloneta_path}/mixin.buttons.plone.less"; @import "@{barceloneta_path}/mixin.clearfix.plone.less"; // @import "@{barceloneta_path}/mixin.gridframework.plone.less"; //grid Bootstrap @import "@{barceloneta_path}/mixin.grid.plone.less"; //grid Bootstrap @import "@{barceloneta_path}/normalize.plone.less"; @import "@{barceloneta_path}/print.plone.less"; @import "@{barceloneta_path}/code.plone.less"; // Core CSS @import "@{barceloneta_path}/grid.plone.less"; @import "@{barceloneta_path}/scaffolding.plone.less"; @import "@{barceloneta_path}/type.plone.less"; @import "@{barceloneta_path}/tables.plone.less"; @import "@{barceloneta_path}/forms.plone.less"; @import "@{barceloneta_path}/buttons.plone.less"; @import "@{barceloneta_path}/states.plone.less"; // Components @import "@{barceloneta_path}/breadcrumbs.plone.less"; @import "@{barceloneta_path}/pagination.plone.less"; @import "@{barceloneta_path}/formtabbing.plone.less"; //pattern @import "@{barceloneta_path}/views.plone.less"; @import "@{barceloneta_path}/thumbs.plone.less"; @import "@{barceloneta_path}/alerts.plone.less"; @import "@{barceloneta_path}/portlets.plone.less"; @import "@{barceloneta_path}/controlpanels.plone.less"; @import "@{barceloneta_path}/tags.plone.less"; @import "@{barceloneta_path}/contents.plone.less"; // Patterns @import "@{barceloneta_path}/accessibility.plone.less"; @import "@{barceloneta_path}/toc.plone.less"; @import "@{barceloneta_path}/dropzone.plone.less"; @import "@{barceloneta_path}/modal.plone.less"; @import "@{barceloneta_path}/pickadate.plone.less"; @import "@{barceloneta_path}/sortable.plone.less"; @import "@{barceloneta_path}/tablesorter.plone.less"; @import "@{barceloneta_path}/tooltip.plone.less"; @import "@{barceloneta_path}/tree.plone.less"; // Structure @import "@{barceloneta_path}/header.plone.less"; @import "@{barceloneta_path}/sitenav.plone.less"; @import "@{barceloneta_path}/main.plone.less"; @import "@{barceloneta_path}/footer.plone.less"; @import "@{barceloneta_path}/loginform.plone.less"; @import "@{barceloneta_path}/sitemap.plone.less"; // Products @import "@{barceloneta_path}/event.plone.less"; @import "@{barceloneta_path}/image.plone.less"; @import "@{barceloneta_path}/behaviors.plone.less"; @import "@{barceloneta_path}/discussion.plone.less"; @import "@{barceloneta_path}/search.plone.less"; /* ### END OF PLONE IMPORTS ### */ /* ### UTILS ### */ // import bootstrap files: @bootstrap_path: "node_modules/bootstrap/less"; @import "@{bootstrap_path}/variables.less"; @import "@{bootstrap_path}/mixins.less"; @import "@{bootstrap_path}/utilities.less"; @import "@{bootstrap_path}/grid.less"; @import "@{bootstrap_path}/type.less"; @import "@{bootstrap_path}/forms.less"; @import "@{bootstrap_path}/navs.less"; @import "@{bootstrap_path}/navbar.less"; @import "@{bootstrap_path}/carousel.less"; /* ### END OF UTILS ### */ @import (less) "../css/business-casual.css"; // include our custom css/less @import "custom.less"; ``` We include the CSS file here as a {term}`Less` file. This way we can extend parts of the CSS in our theme (we will do this with the `.box` class in the next section). ```{note} Don't forget to run {command}`grunt compile` in your package root after you changed the {term}`Less` files. You can use {command}`grunt watch` to automatically compile your {term}`Less` files to CSS whenver they are changed. ``` ## Using Diazo Rules To Map The Theme With Plone Content Now that we have the static theme, we need to apply the Diazo rules in {file}`rules.xml` to map the Plone content elements to the theme. First let me explain what we mean when we talk about *content* and *theme*. *Content* is usually the dynamic generated content on the Plone site, and the *theme* is the static template site. For example: ```xml ``` This rule will replace the element with the CSS id `#headline` in the theme with the element with CSS id `#firstHeading` from the generated Plone content. To inspect the content side, you can open another Browser tab, but instead of , use . In this tab Diazo is disabled, allowing you to use your browser's Inspector or Developer tools to view the DOM structure of the default, unthemed Plone content. This *unthemed host name* is managed in the {guilabel}`Theming Control Panel` under {guilabel}`Advanced Settings`, where more domains can be added. For more details on how to use Diazo rules, take a look at and . With our theme generated from {py:mod}`bobtemplates.plone` we already got a fully functional rule set based on the Plone 5 default Theme: ```xml col-xs-12 col-sm-6 col-xs-12 col-sm-9 col-xs-12 col-sm-9 col-xs-12 col-sm-12
``` As you probably noticed, the theme does not look like it should right now and is missing some important parts like the toolbar. That is because we are using an HTML template which has a different HTML structure than the one Plone's default theme is using. We can either change our theme's template to use the same structure and naming for classes and id's, or we can change our rule set to work with the theme template like it is. We will use the second approach and customize our rule set to work with the provided theme template. In fact, if you use a better theme template then this one - where more useful CSS classes and id's are used and the grid is defined in CSS/Less and not in the HTML markup itself - it is a lot easier to work with without touching the template. But we decided to use this popular template as an example and therefor we have to make changes to the template itself. ## Customizing The Ruleset In this section we will adjust the Diazo rules to place the Plone content into the predefined template sections. ### Plone Toolbar We start with the toolbar since it is the most important part of the Plone site (for logged in users). So let's first make sure we have it in our theme template. We already have the required Diazo rule in our {file}`rules.xml`: ```xml ``` The only thing we need is the corresponding HTML part in our theme template: ```{code-block} html :emphasize-lines: 2
``` You can add it right after the opening body tag in your {file}`index.html`. ### Unthemed Backend If the only thing you want to do is theme your frontend, and use the default Barceloneta theme for your backend (edit, folder contents, settings), you can include Barceloneta's {file}`backend.xml`. To only have your frontend theme rules active when you visit the frontend part of your site, you can wrap the existing rules into another `rules` block: ```{code-block} xml :emphasize-lines: 1-4,6-7,14 ... ``` Note that we include the file from the theme directly, and don't use the one we got from {py:mod}`bobtemplates.plone`. ### Login Link & Co If you want to have a login link for your users, you can put this placeholder in your theme template where you want the link to display. You can always login into the Plone site by adding `/login` to the Plone url, so it's optional. You can add it right before the tag `
Business Casual
` in your {file}`index.html`. ```{code-block} html :emphasize-lines: 3
Business Casual
``` The necessary rule to fill this with the Plone login link is already in our rules.xml. But because the id for the anonymous tools in Plone changed in one of the recent versions, we have to update it (change `#portal-personaltools-wrapper` to `#portal-anontools`): ```xml ``` This will replace your placeholder with `#portal-anontools` from Plone (for example the login link). The link will only be inserted if the user is not already logged in. ### Top Navigation In the next step we will replace the menu placeholder with the real Plone top-navigation links. To do this we adjust this rule from Barceloneta: ```xml ``` Change the rule to the following: ```xml ``` Here we take the list of links from Plone and replace the placeholder links in the theme. The Barceloneta rule copies the whole navigation container into the theme, but we only need to copy the links over. ### Breadcrumbs & Co Plone provides some viewlets like the breadcrumbs (showing the current path) which are rendered in the *above the content* area. We already have the required rule to insert the Plone above-content viewlets into the theme: ```xml ``` All we have to do to get this into the theme layout is to add a placeholder with the CSS id `#above-content` to the theme's {file}`index.html`. We can add this for example as a first element in the main container with the CSS class `.container`, after the main navigation: ```{code-block} html :emphasize-lines: 8-10
... ``` This will bring over everything from the `viewlet-above-content` block from Plone. It also includes the breadcrumbs bar. Because our current theme does not provide a breadcrumbs bar, we can drop it from the Plone content, like this: ```xml ``` If you only want to drop this for non-administrators, you can do it like this: ```{code-block} xml :emphasize-lines: 2 ``` Or for anonymous users only: ```{code-block} xml :emphasize-lines: 2 ``` ```{note} The classes like *userrole-anonymous* are provided by Plone in the `body` tag. ``` ### Slider Only On Front Page We want the slider in the template to be only visible on the front page. To make this easier, we add the CSS-ID `#front-page-slider` to the outer row `div`-tag which contains the slider: ```{code-block} html :emphasize-lines: 1

Welcome to

Business Casual


By Start Bootstrap

``` Now we can drop it if we are not on the front page and also in some other situations: ```xml ``` Currently the slider is still static, but we will change that later in {ref}`create-dynamic-slider-content-in-plone`. ### Title And Description The front page with the slider gives us a nice structure we can use for our title and description. We will use the `

` tag with the class `brand-name` for the title and the following `

` tag for the description. There is also an `

` tag with the class `brand-before` which we don't need, so we will remove it. The resulting block of rules can be wrapped into a separate `rules` tag with the `css:if-content` condition, so we only have to write this once: ```xml ``` If we are on the front page, the Plone title will be placed inside the tag with the class `brand-name`. For all other pages, the title and description stay at their place in the content area. ### Status Messages Plone will render status messages in an element with the CSS-ID `#global_statusmessage`. To show the messages in our theme, we have to add another placeholder into our theme template (e.g. next to the `above-content` viewlets): ```{code-block} html :emphasize-lines: 2
``` The necessary rule is already available: ```xml ``` To test that the status messages are working, you can for example edit the front page and then click on cancel or save, which will give you a confirmation message from Plone. ### Main Content Area To make the Plone content area flexible and containing the correct Twitter Bootstrap grid classes, we use an inline {term}`XSLT` snippet. This is already available in our {file}`rules.xml` file, but it needs some customization for our theme: 1. We need to wrap the grid columns into an element with the class `box` and `clearfix`. 2. We have to adjust the CSS class depending on the available portlets. ```{code-block} xml :emphasize-lines: 5-13,24,28,31,35 col-xs-12 col-sm-12 col-md-6 col-md-push-3 col-xs-12 col-sm-12 col-md-9 col-xs-12 col-sm-12 col-md-9 col-md-push-3 col-xs-12 col-sm-12
``` This code will add the correct Twitter Bootstrap grid classes to the content columns, depending on a one-, two- or three-column-layout. We had to adjust the column classes (we added `col-md-push-3`) to push the main content (visually) after the 1st portlet column, if this one is available. For our template we also need to wrap the content and the viewlets showing below the content in a `
` tag with the CSS class `box`. This will add the shiny white transparent background. ```{hint} We also changed the column classes to use the `col-sm-*` size for small screens to use the full width and the `col-md-*` size for mid-size screens to use a column layout. This fits better on smaller screen sizes. ``` ### Left And Right Columns We already added the necessary placeholders `column1-container` and `column2-container` for the two portlet columns to our template. The next set of rules will add the left and right portlet columns from Plone into the theme, and also change their markup to be an `