• Home
  • Blog
  • Creating a Custom WordPress Theme with Sage Roots: An Advanced Guide
Creating a Custom WordPress Theme with Sage Roots: An Advanced Guide

Creating a Custom WordPress Theme with Sage Roots: An Advanced Guide

Introduction to Sage Roots

Sage Roots, commonly known as Sage, is a WordPress starter theme and development workflow built on modern front-end tooling. It provides a foundation for creating custom WordPress themes using best practices and modern technologies, such as SCSS, JavaScript ES6+, and the Blade templating engine.

Sage streamlines the theme development process by incorporating tools like Webpack for asset compilation, Browsersync for live reloading, and Laravel's Blade for efficient template building. This approach enables developers to write cleaner, more maintainable code while leveraging the latest front-end development techniques.

Why Choose Sage?
Sage brings Laravel-style elegance to WordPress development, offering a modern MVC-like structure, powerful templating, and a build system that handles everything from SCSS compilation to JavaScript bundling.


Setting Up Your Development Environment

Before diving into Sage, ensure you have the following prerequisites installed:

1. Node.js and NPM

Sage relies on Node.js and the Node Package Manager (NPM) for managing front-end dependencies and running build scripts.

Download Node.js

2. Composer

Composer is a dependency manager for PHP, which Sage uses to install and manage WordPress-specific dependencies.

Download Composer

3. Local WordPress Setup

You'll need a local WordPress installation to develop and test your Sage theme. Popular options include:

  • 1 Local by Flywheel

  • 2 Laravel Valet

  • 3 MAMP / XAMPP

  • 4 Docker

4. Code Editor

Choose your preferred code editor with plugins for SCSS, JavaScript, and Laravel Blade syntax highlighting.

VS Code Sublime PhpStorm


Installing Sage

To install the Sage starter theme, follow these steps:

1 Navigate to Themes Directory

Open your terminal or command prompt and navigate to your WordPress installation's wp-content/themes directory.

2 Create a New Sage Project

Run the following Composer command to create a new Sage project:

composer create-project roots/sage my-sage-theme

Replace my-sage-theme with your desired theme name.

3 Navigate to Theme Directory

Once the installation is complete, navigate to the newly created theme directory:

cd my-sage-theme

4 Install Front-End Dependencies

Install the required front-end dependencies:

  • NPM

  • Yarn

npm install
yarn install

5 Build Theme Assets

Build the theme assets:

  • NPM

  • Yarn

npm run build
yarn build

Success! Your Sage theme is now set up and ready for development!


Exploring Sage's Directory Structure

Sage's directory structure differs significantly from traditional WordPress themes. Here's an overview of the essential directories and files:

Directory/File Purpose app/ Contains PHP files for theme setup, filters, and custom functionality resources/ Stores all front-end assets including SCSS, JavaScript, and views (templates) resources/assets/ Houses source CSS and JavaScript files resources/views/ Contains Blade template files organized into subdirectories dist/ Compiled theme files including minified CSS and JavaScript composer.json Manages PHP dependencies and scripts package.json Manages front-end dependencies and scripts webpack.mix.js Configuration file for Webpack asset compilation


Working with SCSS

Sage leverages Webpack for asset compilation, allowing you to write modular SCSS code using modern syntax and features.

SCSS Workflow

  1. Create new SCSS files in the resources/styles directory, following the provided structure (e.g., resources/styles/components/_buttons.scss)

  2. Import your new SCSS files into resources/styles/main.scss, which serves as the entry point for SCSS compilation

  3. Use @import statements to include partials and organize your styles

  4. Webpack will automatically compile your SCSS files into a single main.css file in the dist/styles directory

Recommended SCSS File Structure

resources/
└─ styles/
   ├─ components/
   │  ├─ _buttons.scss
   │  ├─ _cards.scss
   │  └─ _forms.scss
   ├─ layouts/
   │  ├─ _header.scss
   │  ├─ _footer.scss
   │  └─ _sidebar.scss
   ├─ utilities/
   │  ├─ _functions.scss
   │  ├─ _mixins.scss
   │  └─ _variables.scss
   ├─ vendor/
   │  └─ _bootstrap.scss
   └─ main.scss

Example: main.scss

// Utilities
@import 'utilities/functions';
@import 'utilities/mixins';
@import 'utilities/variables';

// Vendor
@import 'vendor/bootstrap';

// Components
@import 'components/buttons';
@import 'components/cards';
@import 'components/forms';

// Layouts
@import 'layouts/header';
@import 'layouts/footer';
@import 'layouts/sidebar';

Working with JavaScript

Sage leverages Webpack and Babel to support modern JavaScript syntax and features. You can organize your JavaScript files into modules and leverage ES6+ features like classes, arrow functions, and import/export statements.

JavaScript Workflow

  1. Create new JavaScript files in the resources/scripts directory (e.g., resources/scripts/components/carousel.js)

  2. Import your JavaScript modules into resources/scripts/main.js, the entry point for JavaScript compilation

  3. Take advantage of ES6+ features like classes, modules, and arrow functions

  4. Webpack will bundle and transpile your JavaScript files into a single main.js file in the dist/scripts directory

Example: Creating a Carousel Component

// resources/scripts/components/carousel.js
export default class Carousel {
  constructor(element) {
    this.carousel = element;
    this.slides = this.carousel.querySelectorAll('.slide');
    this.currentSlide = 0;
    this.initCarousel();
  }

  initCarousel() {
    this.showSlide(this.currentSlide);
    this.carousel.addEventListener('click', this.nextSlide.bind(this));
  }

  showSlide(n) {
    // Implementation here
  }

  nextSlide() {
    // Implementation here
  }
}

Example: Importing Components in main.js

// resources/scripts/main.js
import Carousel from './components/carousel';

const carousel = document.querySelector('.carousel');
if (carousel) {
  new Carousel(carousel);
}

Utilizing Blade Templating

Sage incorporates Laravel's Blade templating engine, which offers a clean and expressive syntax for building WordPress templates.

Key Blade Concepts

@extends

Define a parent layout for template inheritance

@section

Define content areas within a layout

@component

Create reusable component templates

@slot

Pass content to component slots

@if / @foreach

Built-in control structures for logic

@php

Execute raw PHP code within templates

Example: Reusable Card Component

<!-- resources/views/components/card.blade.php -->
@props([
  'title' => '',
  'content' => '',
  'link' => '',
])

<div class="card">
  <div class="card-body">
    <h5 class="card-title">{{ $title }}</h5>
    <p class="card-text">{{ $content }}</p>
    @if ($link)
      <a href="{{ $link }}" class="btn btn-primary">Read More</a>
    @endif
  </div>
</div>

Example: Using the Card Component

<!-- resources/views/page.blade.php -->
@extends('layouts.app')

@section('content')
  <div class="row">
    @foreach ($posts as $post)
      <div class="col-md-4">
        @component('components.card')
          @slot('title')
            {{ $post->post_title }}
          @endslot
          @slot('content')
            {{ $post->post_excerpt }}
          @endslot
          @slot('link')
            {{ get_permalink($post->ID) }}
          @endslot
        @endcomponent
      </div>
    @endforeach
  </div>
@endsection

Advanced Features

Sage provides a solid foundation for building advanced WordPress themes. Here are some ways to extend your theme with additional features.

AJAX and API Integrations

Utilize modern JavaScript techniques, such as the Fetch API or Axios, to make AJAX requests and integrate with third-party APIs.

// resources/scripts/components/api-integration.js
import axios from 'axios';

export default function fetchData() {
  axios.get('/wp-json/my-custom-api/v1/data')
    .then(response => {
      console.log(response.data);
    })
    .catch(error => {
      console.error(error);
    });
}
Custom Post Types

Leverage the power of custom post types and Advanced Custom Fields (ACF) to create rich content types.

// app/setup.php
add_action('init', function() {
  register_post_type('books', [
    'public' => true,
    'labels' => [
      'name' => 'Books',
      'singular_name' => 'Book',
    ],
    'supports' => ['title', 'editor', 'thumbnail'],
    'has_archive' => true,
  ]);
});

Custom Taxonomies and Meta Fields

// app/setup.php
add_action('init', function() {
  register_taxonomy('book_category', 'books', [
    'hierarchical' => true,
    'public' => true,
    'labels' => [
      'name' => 'Book Categories',
      'singular_name' => 'Book Category',
    ],
  ]);
  
  register_meta('post', 'book_author', [
    'object_subtype' => 'books',
    'type' => 'string',
    'single' => true,
    'show_in_rest' => true,
  ]);
});

Using Custom Fields in Templates

<!-- resources/views/single-book.blade.php -->
@extends('layouts.app')

@section('content')
  <h1>{{ get_the_title() }}</h1>
  <p><strong>Author:</strong> {{ get_post_meta(get_the_ID(), 'book_author', true) }}</p>
  
  <p><strong>Categories:</strong></p>
  <ul>
    @foreach (get_the_terms(get_the_ID(), 'book_category') as $category)
      <li>{{ $category->name }}</li>
    @endforeach
  </ul>
  
  {!! the_content() !!}
@endsection

Custom Gutenberg Blocks

Sage allows you to create custom Gutenberg blocks to enhance your content editing experience.

// resources/scripts/editor.js
import { registerBlockType } from '@wordpress/blocks';

registerBlockType('my-theme/testimonial', {
  title: 'Testimonial',
  icon: 'format-quote',
  category: 'common',
  attributes: {
    testimonial: {
      type: 'string',
      source: 'text',
      selector: 'blockquote',
    },
    author: {
      type: 'string',
      source: 'attribute',
      attribute: 'data-author',
      selector: 'cite',
    },
  },
  edit: ({ attributes, setAttributes }) => {
    // Edit component implementation
  },
  save: ({ attributes }) => {
    // Save component implementation
  },
});

Optimization and Performance

Image Optimization

Sage provides a built-in helper function for optimizing images, ensuring better performance and faster load times.

<img src="@asset('images/hero.jpg')?resize(800,600)&quality=80" alt="Hero Image">

This will resize the image to 800×600 pixels and compress it with 80% quality.

Critical CSS

Generate critical CSS for your theme's templates to improve initial render times.

// webpack.mix.js
mix.critical({
  enabled: mix.inProduction(),
  urls: [
    { src: 'http://localhost/about', dest: 'about' },
    { src: 'http://localhost/blog', dest: 'blog' },
  ],
  options: {
    // Critical options
  },
});

Deployment

Follow these steps to deploy your Sage theme to production:

1 Build Process

Run npm run build or yarn build to generate the latest compiled assets in the dist directory.

2 Upload to Server

Upload the entire theme directory, including the dist folder, to your live server or hosting environment.

3 Theme Activation

Log in to your WordPress admin dashboard and activate the Sage theme.

4 Clear Caches

Clear any caches (server-side, browser, or CDN) to ensure the latest changes are reflected.

Pro Tip: Consider using deployment tools like Deployer, GitHub Actions, or Laravel Forge for automated deployments.


Conclusion

Sage Roots provides a powerful and efficient workflow for building custom WordPress themes while leveraging modern front-end development practices.

By combining SCSS, JavaScript ES6+, and the Blade templating engine, Sage empowers developers to create maintainable, scalable, and high-performance themes.

Resources

Official Documentation

Roots Community

GitHub Repository

Blade Documentation

Share:
img

José Paulino

Front-end Developer based in Miami.