• 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.

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. Visit https://nodejs.org to download and install the latest LTS version.

  2. Composer: Composer is a dependency manager for PHP, which Sage uses to install and manage WordPress-specific dependencies. Install Composer by following the instructions at https://getcomposer.org.

  3. Local WordPress Setup: You'll need a local WordPress installation to develop and test your Sage theme. Popular options include Local by Flywheel, DesktopServer, or a local development environment like MAMP or XAMPP.

  4. Code Editor: Choose your preferred code editor, such as Visual Studio Code, Sublime Text, or PhpStorm. Consider installing plugins or extensions for SCSS, JavaScript, and Laravel Blade syntax highlighting and autocompletion.

Installing Sage

To install the Sage starter theme, follow these steps:

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

  2. 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. Once the installation is complete, navigate to the newly created theme directory:

    cd my-sage-theme
  4. Install the required front-end dependencies by running:

    npm install

    Alternatively, you can use Yarn by running:

    yarn install
  5. Build the theme assets by running the following command: Or, if you're using Yarn:

    yarn run build

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

Exploring Sage's Structure

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

  • app/ : Contains PHP files for theme setup, filters, and custom functionality.

  • resources/ : Stores all front-end assets, including SCSS, JavaScript, and views (templates).

    • assets/ : Houses compiled CSS and JavaScript files.

    • views/ : Contains Blade template files organized into subdirectories for better organization.

  • dist/ : The compiled theme files, including minified CSS and JavaScript, are output here.

  • 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 and JavaScript in Sage

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

SCSS

  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.

Here's an example of how you can structure your SCSS files:

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

In main.scss, you can import all the necessary files:

// 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';

JavaScript

  1. Create new JavaScript files in the resources/scripts directory, adhering to the provided structure (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/script directory.

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.

// 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) {
    // ...
  }

  nextSlide() {
    // ...
  }
}

In resources/scripts/main.js, you can import and instantiate your components:

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. Here's an overview of using Blade in Sage:

  1. Create new template files (e.g., page.blade.php) in the resources/views

    directory or its subdirectories.

  2. Use @extends to define a parent layout and @section to define content areas within that layout.

  3. Create reusable components using @component and @slot

    directives.

  4. Pass data from PHP to your Blade templates using the @php directive or by creating a custom $data array in your theme's app/setup.php file.

  5. Leverage Blade's built-in control structures ( @if, @foreach, etc.) and template inheritance for efficient code organization.

Here's an example of creating a 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>

You can then use this component in your templates:

{{-- 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

Customizing Your Theme with Advanced Features

Sage provides a solid foundation for building advanced WordPress themes. Here are some examples of how you can 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 or your custom WordPress API endpoints.

// 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 => {
      // Handle API response
      console.log(response.data);
    })
    .catch(error => {
      // Handle error
      console.error(error);
    });
}

Custom Post Types and Advanced Custom Fields

Leverage the power of custom post types and Advanced Custom Fields (ACF) to create rich content types and enhance your theme's functionality.

// app/setup.php
add_action('init', function() {
  register_post_type('books', [
    'public' => true,
    'labels' => [
      'name' => 'Books',
      // ...
    ],
    // ...
  ]);
});
{{-- resources/views/single-book.blade.php --}}
@extends('layouts.app')

@section('content')
  <h1>{{ get_the_title() }}</h1>
  <p>{{ the_field('book_description') }}</p>
@endsection

Custom Taxonomies and Meta Fields

Sage makes it easy to register custom taxonomies and meta fields for your post types. In app/setup.php, you can define your custom taxonomies and meta fields:

// app/setup.php
use Roots\Sage\Setup;

// Custom Taxonomy
Setup::roadTermMenu('Book Categories', 'book_category', 'book', [
  'hierarchical' => true,
  'public' => true,
]);

// Custom Meta Field
Setup::postMeta('Book Author', 'book_author', 'book', [
  'type' => 'string',
  'single' => true,
  'show_in_rest' => true,
]);

You can then use these custom taxonomies and meta fields in your templates:

{{-- resources/views/single-book.blade.php --}}
@extends('layouts.app')

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

Custom Gutenberg Blocks

Sage allows you to create custom Gutenberg blocks to enhance your content editing experience. You can define your block in resources/scripts/editor.js:

// 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 }) => {
    // ...
  },
  save: ({ attributes }) => {
    // ...
  },
});

Then, in your template files, you can render the block:

{{-- resources/views/single.blade.php --}}
@extends('layouts.app')

@section('content')
  @while(have_posts()) @php(the_post())
    {!! apply_filters('the_content', get_the_content()) !!}
  @endwhile
@endsection

Optimizing and Deploying Your Theme

Optimization
Image Optimization

Sage provides a built-in helper function for optimizing images, ensuring better performance and faster load times. In your templates, you can use the @asset directive:

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

This will optimize the hero.jpg image, resizing it to 800x600 pixels and compressing it with a quality of 80%.

Critical CSS

To improve initial render times, you can generate critical CSS for your theme's templates. Sage includes a critical mix task that generates critical CSS files for each template:

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

The generated critical CSS files will be included in your template's <head> section, ensuring faster initial render times.

Deployment

  1. Build Process: Before deploying, run npm run build or yarn run 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: After activating the theme, clear any caches (server-side, browser, or CDN) to ensure the latest changes are reflected.

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.

Explore the Sage community and resources, such as the official documentation (https://roots.io/sage/) and the Roots Discord

img

José Paulino

Front-end Developer based in Miami.