Concrete CMS Bedrock: A Foundation for Concrete and Concrete Themes.

In Concrete CMS 8.5.x and below, we don’t make any opinionated decisions about how themes should behave, what assets they should include, etc… Yes, since we include Bootstrap 3 with the core for the editing toolbar and the Dashboard, it’s become pretty common to use Bootstrap 3 as the building block for a theme, but it’s not required. We do define grid frameworks, but we have several of them.

In Version 9, Concrete is going to become a bit more opinionated. No, we’re not going to mandate that themes be built a certain way. But if a theme builds on the Concrete Asset Bedrock (which is really just a superset of Bootstrap 5) then that means all the default blocks will look really nice in it, and shared elements in the Containers and Boards model will look great as well. Marketplace developers can even build standalone templates for features and boards that utilize the asset bedrock, and any user who has a theme that takes advantage of it will know that the templates will be nice and interoperable.

Definition: Asset Bedrock

The Concrete Asset Bedrock is a list of list of third party libraries like Bootstrap 5, jQuery UI, jQuery, Vue and more, coupled with custom SASS and JS/ES6 code from the core. It is installed via npm, and in turn installs its dependencies via npm. It is the bedrock of the three different domains in Concrete – the frontend, the CMS and the backend.

The Concrete and Dashboard themes that ship with Concrete are built on the Asset Bedrock. Additionally, the Asset Bedrock contains the Minimal asset for all features that ship with the core. If functionality ships with the core (like the Calendar), there needs to be a minimal version of its required assets that also come with the core. A theme could enhance or supersede that functionality, but if it doesn’t, and the core needs to employ that functionality, the minimal JS and CSS provided by the Asset Bedrock will be used.

Goals

  • To make it easier to build Concrete themes: all the assets necessary are delivered together, bundled in sensible ways, and easily includable. Just include the asset bedrock in your Concrete theme project, and import JS and SCSS files into your theme files.
  • To improve performance: we’re cutting down on extraneous view.js and view.css files in the core.
  • To add flexibility: themes can specify exactly what features they provide specific support for, and let the asset fallback work in the core for those they don’t support.

NPM Modules

In all previous versions of Concrete, Concrete’s CSS and JS code is contained within the main Concrete project repository. In later versions of Concrete, much of this code was separate out into a separate build folder, so it could be minified and compiled before delivery. This even included third party dependencies like jQuery.

In version 9, we’re going move our entire asset system into npm, so it can be included in the core as though it were a third party dependency. The main reason for this? Third party theme developers can also include it in their themes as a dependency, making it easier to include the Asset bedrock without a lot of copy and pasting.

Using the Asset Bedrock in Your Theme

Using the Asset Bedrock in your theme consists of the following steps.

First, in your theme’s package.json file, include the bedrock as a dependency:

npm i laravel-mix
npm i @concretecms/bedrock

Setup your webpack.mix.js to build whatever SCSS and JS files you need (this is outside the scope of this document.)

In your JS files, include the frontend foundation with

import 'concretecms-bedrock/assets/bedrock/js/frontend' 

at the top.

In your SCSS file, include the frontend foundation with

@import "~concretecms-bedrock/assets/bedrock/scss/frontend"; 

at the top.

If webpack gives errors of not finding ~concretecms-bedrock modules, make a resolve alias pointing to @concretecms/bedrock instead inside webpack.mix.js:

.webpackConfig({
    module: {
        rules: [
            {
                resolve: {
                    alias: {
                        "concretecms-bedrock": "@concretecms/bedrock"
                    }
                }
            }
        ],
    },
})

Wrap every other @import statement in your scss file within div.ccm-page

Make sure your PageTheme class uses the BedrockThemeTrait This will register your theme as requiring jQuery and Font Awesome (which are automatically provided by the Concrete Asset System), and it will force you to implement getSupportedFeatures, which lets you determine which Concrete features your theme supports natively (and, by definition, which will need to use the minimal fallback in order to function.)

How does Asset Feature Fallback Work?

Themes include support for features like calendar, imagery, etc... If a theme supports that feature, it returns the features that it supports. Here is the list of features that the Elemental theme supports explicitly:

public function getThemeSupportedFeatures()
{
    return [
        Features::BASICS,
        Features::CALENDAR,
        Features::CONVERSATIONS,
        Features::FAQ,
        Features::NAVIGATION,
        Features::IMAGERY,
        Features::FORMS,
        Features::SEARCH,
        Features::TESTIMONIALS,
        Features::TAXONOMY,
    ];
}

Block types will be able to define what features they require. For example, the Image Slider block will define imagery as a feature. The Content block will define imagery as well. The Testimonials block will define testimonials, and so on. This will largely take the place of the Asset system.

When a block type is used on a page, we query the theme to see if it supports that feature. If it does, we don’t include anything. If it doesn’t, we include the fallback code found in the asset bedrock.

Note: only accessory features are referenced in this way. We don’t need to mark the Image block as requiring Files, for example.

Do I have to include JS and CSS?

Yes! For example, if you want to say that your theme has full support for calendars, you need to ensure that the JS and the CSS to render the calendar blocks nicely is present in the stylesheets you include in your header and footer.

Fortunately, you won’t have to guess too much at this. If you want to skin the calendar but keep its JS the same, just include its frontend JS bundle in your main JS file, and include customizations to the calendar in your SCSS. It’s perfectly acceptable (and probably preferable) to include the base JS versions; but if you want to go above and provide your own JS implementation, you’re able to do so.

Example of Including a Feature SCSS and JS in Your Theme

The main.js and main.scss files of Elemental provide a good example for how to use the Asset Bedrock in your theme. Let’s say you want to mark that your theme provides support for the Calendar assets. First, modify page_theme.php and mark that your theme provides the calendar asset by implementing

public function getThemeSupportedFeatures()
{
    return [
        Features::CALENDAR,
    ];
}

This will make it so that the frontend calendar JS and CSS are no longer included by the core. That means, all calendar-related functionality will look bad and probably not function until you include them in your SCSS and JS files.

main.js

Below your import of the bedrock code, import the calendar JS:

import 'concretecms-bedrock/assets/calendar/js/frontend';

main.scss

Below your import of the bedrock SCSS code, import a new _calendar.scss file in your theme. This helps to keep your SCSS file clean:

@import "./features/calendar/calendar";

You’ll have to make this file:

features/calendar/_calendar.scss

This file will actually include the core feature code, and then any custom code you have in your theme to make the calendar look nice:

// Import base stylesheets
@import "~concretecms-bedrock/assets/calendar/scss/frontend/frontend";
// Import theme customizations
@import "calendar-block";

Line 2 above imports the asset bedrock calendar SCSS code, while our calendar block customizations are included within _calendar-block.scss. Now add your customizations to _calendar-block.scss