Environment Setup

When I did this theme I thought about my usual workflow… what I consider essential to speed up my development phase. I love gulp to handle template file tasks for each type of file there is a different processing. For example sass files are compiled into css, javascript files are transpiled and minified with uglify and babel, while imagemin takes care of image optimization. Gulp can also create the pot file for the translations and convert the images of the whole /upload/* folder to the “webp” format.

I hope this theme can be a good starting point for developers, theme hackers and for everyone who want a starter template to personalize freely.

To Customize the template just follow this instructions, you will first need to install NodeJS on your development machine or on your server, then install the packages needed for the development.

warning DEV ZONE! This theme has been thought to be modified in deep to avoid unnecessary overrides. But if you don’t need to change the template you can go to directly to the next section.

Install NodeJS

First you need to download and install NodeJS from the link below:


After this step, you can check if NodeJS and NPM were installed with the command:

node -v && npm -v

How use Gulp tasks

Into the theme folder with the command line type:

npm i -g gulp-cli && npm i

This command installs all the packages needed for development and Gulp will be ready to run tasks for you!

Gulp built-in tasks

There are some predefined and useful Gulp tasks built-in with this template. To run them, go with the command line inside the theme/child theme folder, then type this commands:

gulp style
Runs (once) the Sass compile task on style.scss, the autoprefixer and then creates the sourcemap.

gulp scripts
Traspile es6 to javascript (if needed) then uglify (minify), concat (merge all files into one) and creates the sourcemap.

gulp optimizeThemeImg
Minify images (PNG, JPEG, GIF and SVG) from assets/src/img then copy to assets/dist/img folder. Automatically creates a copy of each file in webp format

gulp optimizeWPUploads
Minify images (PNG, JPEG, GIF and SVG) from /wp-content/uploads. Automatically creates a copy of each file in webp format

gulp zipRelease
Zip all theme files into /releases/$version, it can be useful if you want to “package” the theme for upload purpose.

gulp createPot
Parse all php files into theme folder and generates the pot files for WordPress translations.

gulp watch
You have to run this command during development, and this command will be your best friend 🙂 It runs a file watcher on sass, scripts, and images folders and when triggered run the needed gulp task. It uses the latest version of gulp which allows these tasks to run in parallel, in order to have very short compilation times.

gulp build
To finalize the theme… for first run clean and removes all development files. Then compile with a set of options suitable for publication (in watch task instead the compilation speed is privileged and also the css is not minified)

gulp buildRelease
Same as build task but furthermore removes some unwanted files (Thumbs.db, DS_Store, ...) and zip the template files

SASS Variables

Since i moved many variables to CSS Custom Properties there are few sass variables to set but If you want to personalize your template you must edit the variables scss file (wp-content/themes/modul-r/assets/src/scss/utils/vars.scss), I choose the sassy way instead of the customizer because it creates a faster site with a more compact code.

Here you will find everything you need to customize your template colors fonts sizes and much more! And don’t forget to run the gulp task “gulp style” to re-compile stylesheets.

$color__icons: #888888;

$animations__lenght : .35s;

$base_unit: 8px;
$size__margin: $base_unit;
$size__padding: $base_unit * 8;

$size__padding-resp: $base_unit * 2.5;

$size__site-width: 1500px;
$size__side-padding: 300px;
$size__nav-line-height: 2.2;
$size__nav-responsive-line-height: 2.5;
$size__responsive-menu-max-width: 360px;

$head__responsive_breakpoint-width: 960px;

$hamburger__size: 30px;
$hamburger__weight: 3px;

$scrollbar-border-radius: 2px;

$avatar_size: 64px;
$comments__avatar-size: 64px;

$button__height: 36px;

$blockquote__icon-size: 60px;

If you use the child theme instead, a unique file will be created from the parent’s and the child’s style (so only the child style will be enqueued).

Theme Defaults

This is something you will find more useful with child template but for completeness I would like to quote also this… at the top of functions.php you will find an array with all the default values used into customizer, but occasionally you may to want to change this dataset for example if you want to add a new font or lock the customizer possibilities for a customer. Whatever your reason for doing this, happy hacking! 😉

$modul_r_defaults = array(
    'colors' => array(
        'primary' => '#6f4cad',
        'secondary' => '#16bebb',
        'white' => '#ffffff',
        'white-smoke' => '#fafafa',
        'gray-light' => '#e3e3e3',
        'gray' => '#888888',
        'gray-dark' => '#4e4e4e',
        'black' => '#222222',
    'style' => array(
        'background' => 'white-smoke',
        'title-color' => 'primary',
        'text-color' => 'gray-dark',
        'header-color' => 'gray-dark',
        'header-title-color' => 'primary',
        'header-text-color' => 'white',
        'footer-color' => 'gray-dark',
        'footer-bottom-color' => 'black',
        'footer-text-color' => 'white-smoke',
    'customizer_options' => array(
        'font_family' => array(
            'Montserrat' => array('name'=> 'Montserrat', 'weights' => array(100,200,300,400,500,600,700,800,900) ),
            'Source+Sans+Pro' => array('name'=> 'Source Sans Pro', 'weights' => array(200,300,400,600,700,900) ),
            'Roboto+Condensed' => array('name'=> 'Roboto Condensed', 'weights' => array(300,400,700) ),
            'Oswald' => array('name'=> 'Oswald', 'weights' => array(200,300,400,500,600,700) ),
            'Arvo' => array('name'=> 'Arvo', 'weights' => array(400,700) ),
            'Exo+2'=> array('name'=> 'Exo 2', 'weights' => array(100,200,300,400,500,600,700,800,900) ),
            'Titillium+Web' => array('name'=> 'Titillium Web', 'weights' => array(200,300,400,600,700,900) ),
            'Lato' => array('name'=> 'Lato', 'weights' => array(100,300,400,700,900) ),
            'Open+Sans'=> array('name'=> 'Open Sans', 'weights' => array(300,400,500,600,700,800) ),
            'Roboto' => array('name'=> 'Roboto', 'weights' => array(100,300,400,500,700,900) ),
            'Merriweather' => array('name'=> 'Merriweather', 'weights' => array(300,400,700,900) ),
            'Nunito' => array('name'=> 'Nunito', 'weights' => array(200,300,400,600,700,800,900) ),
            'Raleway' => array('name'=> 'Raleway', 'weights' => array(100,200,300,400,500,600,700,800,900) ),
            'Roboto+Mono' => array('name'=> 'Roboto Mono', 'weights' => array(100,200,300,400,500,600,700) ),
            'Roboto+Slab' => array('name'=> 'Roboto Slab', 'weights' => array(100,200,300,400,500,600,700,800,900) ),
            'Ubuntu' => array('name'=> 'Ubuntu', 'weights' => array(300,400,500,700) ),
            'Lobster' => array('name'=> 'Lobster', 'weights' => array(400) ),
            'Michroma' => array('name'=> 'Michroma', 'weights' => array(400) ),
            'Pacifico' => array('name'=> 'Pacifico', 'weights' => array(400) ),
            'Permanent+Marker' => array('name'=> 'Permanent Marker', 'weights' => array(400) ),
            'Parisienne' => array('name'=> 'Parisienne', 'weights' => array(400) ),
        'font_styles' => array(
            "title_font-family" => array( 'name' => 'font-family', 'default' => 'Montserrat', 'input' => 'select', 'type' => 'font_family', 'for' => 'title' ),
            "title_font-weight" => array( 'name' => 'font-weight', 'default' => 600, 'input' => 'select', 'type' => 'font_weight', 'for' => 'title' ),
            "text_font-family" => array( 'name' => 'font-family', 'default' => 'Montserrat', 'input' => 'select', 'type' => 'font_family', 'for' => 'text' ),
            "text_bold" => array( 'name' => 'bold', 'default' => 600, 'input' => 'select', 'type' => 'font_weight', 'for' => 'text' ),
            "text_regular" => array( 'name' => 'regular', 'default' => 400, 'input' => 'select', 'type' => 'font_weight', 'for' => 'text' ),
            "text_light" =>  array( 'name' => 'light', 'default' => 300, 'input' => 'select', 'type' => 'font_weight', 'for' => 'text' )
        'typography' => array(
            array( 'name' => 'line-height', 'default' => 1.3, 'input' => 'number', 'input_type' => 'float' ),
            array( 'name' => 'line-height--wide', 'default' => 1.7, 'input' => 'number', 'input_type' => 'float' ),
            array( 'name' => 'font-size--xs', 'default' => 12, 'input' => 'number', 'input_type' => 'int', 'unit' => 'px' ),
            array( 'name' => 'font-size--s', 'default' => 14, 'input' => 'number', 'input_type' => 'int', 'unit' => 'px' ),
            array( 'name' => 'font-size--m', 'default' => 17, 'input' => 'number', 'input_type' => 'int', 'unit' => 'px' ),
            array( 'name' => 'font-size--l', 'default' => 22, 'input' => 'number', 'input_type' => 'int', 'unit' => 'px' ),
            array( 'name' => 'font-size--xl', 'default' => 26, 'input' => 'number', 'input_type' => 'int', 'unit' => 'px' ),
            array( 'name' => 'font-size--xxl', 'default' => 40, 'input' => 'number', 'input_type' => 'int', 'unit' => 'px' ),
            array( 'name' => 'font-size--xxxl', 'default' => 56, 'input' => 'number', 'input_type' => 'int', 'unit' => 'px' ),
        'social_media_enabled' => array( 'Facebook', 'Instagram', 'Twitter', 'Linkedin', 'YouTube', 'www' ),
        'color_variance' => 0.3,
        'layout' => array(
            'baseunit' => 8,
            'content_width' => 900,
            'content_width_wide' => 1500,
            'hero_height_home' => 70,
            'hero_height_default' => 50,
        'header_sizes' => array(
            array( 'name' => 'branding--max-width', 'default' => 350, 'input' => 'number', 'input_type' => 'int', 'unit' => 'px' ),
            array( 'name' => 'branding--height', 'default' => 80, 'input' => 'number', 'input_type' => 'int', 'unit' => 'px' ),
            array( 'name' => 'logo--height', 'default' => 80, 'input' => 'number', 'input_type' => 'int', 'unit' => '%' ),
            array( 'name' => 'nav--height', 'default' => 60, 'input' => 'number', 'input_type' => 'int', 'unit' => 'px' ),
        'sizes' => array(
            array( 'name' => 'sidebar--width', 'default' => 420, 'input' => 'number', 'input_type' => 'int', 'unit' => 'px' ),
            array( 'name' => 'footer-widget--width', 'default' => 300, 'input' => 'number', 'input_type' => 'int', 'unit' => 'px' )

Why use SASS when we got CSS Custom Properties or Customizer?
Because Sass is much more than variables, it’s a powerful Turing compete language, it’s more maintainable and has a clearer syntax. Having a stylesheet written in sass means that you have the possibility of modifying this project and expanding it as you wish without any limitations.

Too many customizer options can lower the TTFB of your website and that’s the reason why I have chosen a different approach to many other templates, using custom properties handled with a SASS stylesheet. And that the reason why we have the possibility to split the style in two parts, the layout and the UI. Only the first ones are loaded before the “above the fold” injecting that CSS directly as text into the header, the rest will be added at the end of the page, freeing the critical loading path from the usual crap.

For optimal performance, I also recommend to install an optimisation tool (e.g. Autoptimize) and a caching plugin (e.g. WP SuperCache).

Post navigation

You might be interested in...

No comments yet, be the first!


Your email address will not be published. Required fields are marked *