Skip to content

Roots Sage 10 to Sage 11 Upgrade Guide

This guide will show you how to upgrade a site running the Sage 10 theme by Roots to Sage 11.  This guide is based on my own personal setup of Sage 10, so some steps may vary for you depending on how you’ve configured your Sage 10 theme.  For instance, on my sites I don’t use Tailwind and I do use SCSS, which is not enabled by default with Sage 10 but is an optional add-on.  Hopefully you will find this upgrade guide useful.  If you do, or if you have questions, please leave a comment below or contact me.

Project Assumptions:

As mentioned, my project may vary from yours.  Since this guide was based on my own personal experience, I’m making the following assumptions about your project:

  • You’re running Sage 10 on a website that’s also using Bedrock
  • You may or may not be using Tailwind
  • You may or may not be using optional Sage 10 features, such as SCSS or jQuery
  • You have the Composer package manager installed, either via a tool like Lando or on your local system

Starting The Upgrade:

For this guide, I’ll assume that you’re using Lando as your local environment.  Thus, you may see some terminal commands prefixed with lando, such as lando composer update.  If you’re not using Lando, you can use the same commands but remove the lando prefix.  For more information, see my Sage 11 / Sage 10 installation tutorial, which uses Lando for running Composer and Node commands.

Updating Acorn:

The first step in upgrading to Sage 11 is to upgrade the version of Acorn that’s installed in your project.  If you’re running Bedrock then Acorn is likely installed at the root level of your project.  In your project’s composer.json file, find the Acorn version and ensure it’s at version 5.0 or greater, like so:

"roots/acorn": "^5.0",

After you have updated Acorn, from the root of your project run a composer update command.  If you’re using Lando, it will look like this:

lando composer update

Updating The Theme’s Dependencies:

Switch directories to your theme.  This should be located under the web > app > themes directory.  First, find the composer.json file in your theme’s directory.  Ensure that the laravel/pint version listed is at least at version 1.20, like so:

"require-dev": {
   "laravel/pint": "^1.20"
 },

Run a composer update (or lando composer update) command again to update the theme and dependencies.

Updating package.json:

Find the package.json file for your theme.  We’ll need to make some updates to the package.json file so that we can replace the Bud build engine with Vite, which is the new build engine for Sage 11.

In your package.json file, find the “scripts” and “devDependencies” sections and remove them.  You will want to replace those with the following:

"scripts": {
    "dev": "vite",
    "build": "vite build",
    "translate": "npm run translate:pot && npm run translate:update",
    "translate:pot": "wp i18n make-pot . ./resources/lang/sage.pot --include=\"theme.json,patterns,app,resources\"",
    "translate:update": "for file in ./resources/lang/*.po; do wp i18n update-po ./resources/lang/sage.pot $file; done",
    "translate:compile": "npm run translate:mo && npm run translate:js",
    "translate:js": "wp i18n make-json ./resources/lang --pretty-print",
    "translate:mo": "wp i18n make-mo ./resources/lang ./resources/lang"
  },
  "devDependencies": {
    "@roots/vite-plugin": "^1.0.2",
    "@tailwindcss/vite": "^4.0.9",
    "laravel-vite-plugin": "^1.2.0",
    "tailwindcss": "^4.0.9",
    "vite": "^6.2.0"
  }

The above is the default configuration for a Sage 11 theme and assumes you’re using Tailwind.  If you’re instead using SCSS without Tailwind, your devDependencies will look like this:

"devDependencies": {
    "@roots/vite-plugin": "^1.0.2",
    "laravel-vite-plugin": "^1.2.0",
    "sass": "^1.85.1",
    "vite": "^6.2.0"
  },

Create vite.config.js File:

At the root of your theme, create a new file named vite.config.js.  If you’re using Tailwind, your file will look something like this:

import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite';
import laravel from 'laravel-vite-plugin'
import { wordpressPlugin, wordpressThemeJson } from '@roots/vite-plugin';

export default defineConfig({
  base: '/app/themes/demo-theme/public/build/',
  plugins: [
    tailwindcss(),
    laravel({
      input: [
        'resources/styles/app.css',
        'resources/scripts/app.js',
        'resources/styles/editor.css',
        'resources/scripts/editor.js',
      ],
      refresh: true,
    }),

    wordpressPlugin(),

    // Generate the theme.json file in the public/build/assets directory
    // based on the Tailwind config and the theme.json file from base theme folder
    wordpressThemeJson({
      disableTailwindColors: false,
      disableTailwindFonts: false,
      disableTailwindFontSizes: false,
    }),
  ],
  resolve: {
    alias: {
      '@scripts': '/resources/js',
      '@styles': '/resources/css',
      '@fonts': '/resources/fonts',
      '@images': '/resources/images',
    },
  },
})

If, however, you’re not using Tailwind and are instead using SCSS, your vite.config.js file will look more like this:

import { defineConfig } from 'vite'
import laravel from 'laravel-vite-plugin'
import { wordpressPlugin, wordpressThemeJson } from '@roots/vite-plugin';

export default defineConfig({
  base: '/app/themes/demo-theme/public/build/',
  plugins: [
    laravel({
      input: [
        'resources/styles/app.scss',
        'resources/scripts/app.js',
        'resources/styles/editor.scss',
        'resources/scripts/editor.js',
      ],
      refresh: true,
    }),

    wordpressPlugin(),

    // Generate the theme.json file in the public/build/assets directory
    // based on the Tailwind config and the theme.json file from base theme folder
    wordpressThemeJson({
      disableTailwindColors: true,
      disableTailwindFonts: true,
      disableTailwindFontSizes: true,
    }),

  ],
  resolve: {
    alias: {
      '@scripts': '/resources/js',
      '@styles': '/resources/css',
      '@fonts': '/resources/fonts',
      '@images': '/resources/images',
    },
  },
})

In either case, make sure your base parameter is updated to use the correct folder path for your theme.  Replace demo-theme with the name of the folder for your theme:

base: '/app/themes/demo-theme/public/build/',

Installing SCSS:

At this point, if you want to use SCSS in your project you’ll need to re-install it.  If you’re using Lando, you can run the following commands to get to a node prompt.  You’ll want to be in the root of your theme in your terminal.

lando ssh -s node

Once you are at a prompt where you can run node, run the following command to install SCSS:

npm install -D sass

Installing Build Dependencies:

You should now be able to run a yarn command from the terminal to install build dependencies.  You can then run a yarn build command to compile your CSS and JS.  This might fail at this point though as we need to update the site’s Javascript files.

Find your resources > scripts > app.js file.  Remove the following:

import domReady from '@roots/sage/client/dom-ready';

Replace With:

import.meta.glob([
  '../images/**',
  '../fonts/**',
]);

Also remove the following:

/**
 * Application entrypoint
 */
domReady(async () => {
  // ...
});

/**
 * @see {@link https://webpack.js.org/api/hot-module-replacement/}
 */
if (import.meta.webpackHot) import.meta.webpackHot.accept(console.error);

Now try running yarn build from your terminal again.  Hopefully your CSS and JS will build without issues at this point.

Updating Your Theme’s setup.php File:

Locate the app > setup.php file.  Find and remove the following:

/**
* Register the theme assets.
*
* @return void
*/
add_action('wp_enqueue_scripts', function () {
   bundle('app')->enqueue();
}, 100);


/**
* Register the theme assets with the block editor.
*
* @return void
*/
add_action('enqueue_block_editor_assets', function () {
   bundle('editor')->enqueue();
}, 100);

Replace the removed code with the following code.  If you are using SCSS instead of CSS, be sure to replace any .css references with .scss instead.

/**
* Inject styles into the block editor.
*
* @return array
*/
add_filter('block_editor_settings_all', function ($settings) {
   $style = Vite::asset('resources/styles/editor.css');


   $settings['styles'][] = [
       'css' => Vite::isRunningHot()
           ? "@import url('{$style}')"
           : Vite::content('resources/styles/editor.css'),
   ];


   return $settings;
});


/**
* Inject scripts into the block editor.
*
* @return void
*/
add_filter('admin_head', function () {
   if (! get_current_screen()?->is_block_editor()) {
       return;
   }


   $dependencies = json_decode(Vite::content('editor.deps.json'));


   foreach ($dependencies as $dependency) {
       if (! wp_script_is($dependency)) {
           wp_enqueue_script($dependency);
       }
   }


   echo Vite::withEntryPoints([
       'resources/scripts/editor.js',
   ])->toHtml();
});


/**
* Add Vite's HMR client to the block editor.
*
* @return void
*/
add_action('enqueue_block_assets', function () {
   if (! is_admin() || ! get_current_screen()?->is_block_editor()) {
       return;
   }


   if (! Vite::isRunningHot()) {
       return;
   }


   $script = sprintf(
       <<<'JS'
       window.__vite_client_url = '%s';


       window.self !== window.top && document.head.appendChild(
           Object.assign(document.createElement('script'), { type: 'module', src: '%s' })
       );
       JS,
       untrailingslashit(Vite::asset('')),
       Vite::asset('@vite/client')
   );


   wp_add_inline_script('wp-blocks', $script);
});


/**
* Use the generated theme.json file.
*
* @return string
*/
add_filter('theme_file_path', function ($path, $file) {
   return $file === 'theme.json'
       ? public_path('build/assets/theme.json')
       : $path;
}, 10, 2);

In setup.php, also find the following:

use function Roots\bundle;

Replace with:

use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Vite;

Injecting WYSIWYG Styles:

If you want to inject your CSS into the WYSIWYG editor used by WordPress, you will also want to add the following code to your setup.php file.  This is useful if you want custom fonts to load in your WYSIWYG editor.

/* Add the theme styles into the WYSIWYG editor */

add_theme_support('editor-style');

add_action('after_setup_theme', function () {
    add_editor_style(Vite::asset('resources/styles/app.scss'));
}, 20);

Updating Layout Files:

To properly load your CSS and Javascript inside of your blade views, you need to update your layout files.  These are located under the resources > views > layouts folder.  By default there is only one layout file, app.blade.php.  Add the following code to each of your layouts, right before the closing </head> tag:

@vite(['resources/styles/app.css', 'resources/scripts/app.js'])

If you are using SCSS, you will need to ensure you’re loading the SCSS file, so you would instead use:

@vite(['resources/styles/app.scss', 'resources/scripts/app.js'])

Be sure to update each of your layout files.

After you have completed this step, you should be able to run a yarn build command and see your site’s CSS and JS present on the front end.  However, there are some post-upgrade cleanup items that you may need to take care of depending on how your theme was built:

Post Upgrade Clean Up Items:

Items that may potentially be broken by the upgrade include the loading of custom fonts, custom images or icons and the loading of jQuery if you are using a theme that relies on jQuery as a dependency.  Here is how to solve those issues:

Issues With Fonts Not Loading:

If fonts are not loading, ensure you have the font files in the resources > fonts folder and that you’re loading your fonts using the @fonts directive in your CSS, like so:

@font-face {
  font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
  font-family: 'Libre Franklin';
  font-style: normal;
  font-weight: 200;
  src: url('@fonts/libre-franklin-v14-latin-200.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}

Images or Icons Not Loading:

If you were using the @images directive in Sage 10 to load images or icons in CSS, note that the syntax has changed slightly.  Find all of the following in your project’s CSS:

url("~@images/icons/carat.svg")

Replace with:

url("@images/icons/carat.svg")

Note that the tilde (~) character is no longer used.

Restoring jQuery:

If your theme used jQuery and you would like to bring it back, here’s how you can.  First, from your terminal you’ll want to be somewhere where you can run node.  On Lando, that’s done via the lando ssh -s node command we’ve run before.  Then you’ll want to run:

npm install jquery

Then in your vite.config.js file at the top add the following import statement:

import $ from 'jquery';

Then install the plugin injection npm package:

npm install @rollup/plugin-inject --save-dev

Lastly, back in your vite.config.js file add jQuery as a plugin, like so:

plugins: [
    laravel({
      input: [
        'resources/styles/app.scss',
        'resources/scripts/app.js',
        'resources/styles/editor.scss',
        'resources/scripts/editor.js',
      ],
      refresh: true,
    }),

    wordpressPlugin(),

    // Generate the theme.json file in the public/build/assets directory
    // based on the Tailwind config and the theme.json file from base theme folder
    wordpressThemeJson({
      disableTailwindColors: true,
      disableTailwindFonts: true,
      disableTailwindFontSizes: true,
    }),

    inject({
      $: 'jquery',
      jQuery: 'jquery',
    }),

  ],

Need Help With Sage or WordPress?

If you need help with upgrading your site from Sage 10 to Sage 11, or WordPress development, I am available for paid developer mentorship where I would be happy to work with you to upgrade your site or answer any WordPress or Web Development questions you may have.

I am also available for hire, so if you’re interested in working with me on your next project contact me or schedule a free consultation.

Leave a Reply

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