Integrate Smoothstate.js to WordPress Portfolio

How I structured my CSS and modified my Child Theme to get that snazzy Single-Page Application transition.

Stevanus Satria
11 min readSep 26, 2020

I have always used WordPress for my personal website/portfolio. I started with the SaaS version that is WordPress.com, before transitioning into WordPress.org earlier this year. Like many have told me, WordPress.org indeed opened up a lot more possibilities compared to WordPress.com, courtesy of its mature theme and plugin ecosystem, as well as better access to HTML and CSS customizations. It was truly a state of “whatever you can think of, you can build”.

A traditional WordPress site, where the whole page refreshes on navigation into another page. (Credit: https://perkcoffee.co/)

However, for the longest time, I thought a WordPress site would always be that: a WordPress site. I thought there was no way I could get the transition that modern site builders offer, where only part of the page refreshes on navigation into another page.

What we are aiming for! As you can see, only the “difference” is re-rendered; the rest (in this case the header) is unchanged. (Credit: https://thedieline.com/)

Until I came across a certain JavaScript library called Smoothstate.js (and its close competitor, Barba.js).

I looked at tutorials on how to integrate Smoothstate.js into WordPress, and truthfully it looked simple. However, none of the tutorials provide a comprehensive guide on how to organize your WordPress site in order to ensure that everything works as it was prior to Smoothstate.js integration. After spending a whole weekend overcoming the obstacles I came across and ironing out small kinks here and there, I decided to write the whole process out with the hope that others who encounter similar struggles may benefit from this documentation.

Creating a Child Theme

First things first, like many of the tutorials I found, I recommend creating a child theme to host all the customizations we will be doing, unless you built your own theme from scratch. The reason being that any customizations made to the parent theme would be lost when it is updated to the latest version, and updating all your 3rd party dependencies is highly recommended to patch up any possible security vulnerabilities.

I won’t go into the details of creating a child theme, but should you need help you can find plenty of tutorials online. I would recommend following the steps provided by the 3rd party theme you selected. For example, Astra has great documentation on this and even provides a tool to generate the child theme for you! Once you are done, activate that child theme and we’ll be good to start!

Aggregating Your Custom CSS

The next thing we need to do is to aggregate any custom CSS you may have written into a single file that will be enqueued on the initial load of your site, regardless of which page it’s loaded from. Whereas inline CSS added directly into your HTML will still be rendered properly with Smoothstate.js, the same cannot be said with styles applied through a class attribute. I believe if you use a plugin like Autoptimize that has the option to aggregate your CSS into a single file, you may be able to skip this step. However, should you decide to do it anyway, let me share with you the two ways this can be done:

  1. Adding all your CSS directly in WordPress Customizer’s built-in CSS editor. You can access this through Appearance → Customize → Additional CSS. The advantage of doing it this way is that you can preview your changes live, as long as you’ve added the respective classes into your HTML in each page.
  2. Adding all your CSS into the stylesheet of your child theme. You can access this Appearance → Theme Editor. Select your child theme, and edit the style.css file. You won’t be able to see the changes live if you take this route, but I personally decided to do it this way because I installed a plugin called HTML Editor Syntax Highlighter, which color codes my classes and CSS attributes nicely.
The two methods to aggregate all CSS: Customizer’s Built-In Editor (Top) or Theme Editor’s Stylesheet (Bottom).

Adding Smoothstate.js into Your Site

Finally, the steps we are all here for! For integrating Smoothstate.js into WordPress, I followed the steps outlined by this tutorial. I liked this one more than the others simply because it skipped the creation of a wrapper div tag in the HTML, which may not be easy to do if you use a 3rd party theme. Both the element with “page” as an id and the element with “site-content” class seemed to be universal WordPress elements, but I might be wrong (my Astra theme do have them). If upon following this tutorial Smoothstate.js does not work, you may want to inspect your HTML in your browser.

For reference, the element with “page” as an id on my site is the div tag which is the direct child of the body tag, and the element with “site-content” class is the sibling of the header tag, located directly after the latter.

The first thing to do is to download the latest Smoothstate.js. Then, add the downloaded script file and another file containing the script gist below into the same folder. I personally prefer adding them both in assets/js under my child theme folder, because they will then appear under the Theme Editor together with the child theme’s stylesheet and PHP files, making editing that much easier. To do so, use your hosting provider’s FTP client.

The opening of the script above is slightly different than the tutorial’s because I opted to use the jQuery bundled with WordPress, which has use-strict enabled.

Once the above is done, all that’s left are to enqueue the scripts and add some CSS. For the latter, you may adopt and modify the tutorial’s CSS, as the classes it affects are not changed in the script above. Or you may copy my version below which does not include the sliding animation.

Remember to add the CSS the same way following the way CSS is aggregated in the previous section. With that out of the way, open Appearance → Theme Editor and add the following lines to the functions.php file:

You need to replace your-child-theme with the name of your child theme. However, if you decided to place your scripts elsewhere then you need to trace the directory accordingly.

Save your changes, and run your site to see Smoothstate.js applying partial update when you navigate around your site!

Ironing Out Kinks

So are we done? Unfortunately not, unless you don’t use any other plugins in your site then probably you are done (then you might want to go straight to the next section). However, if you do use any other plugins to generate your site’s content, then chances are they don’t work or render properly. The reason is that when applying the changes, Smoothstate.js does not reload any stylesheet or run functions specific to that page, because technically the page is not reloaded; it’s just “updated”.

Personally, none of the content-generating plugins I use require any scripts to run on load. If the same applies to you, then it’s a matter of enqueuing the required CSS file on the initial load of your site. To know what stylesheet needs to be enqueued, you can follow these simple steps:

  1. Open an incognito tab on your browser.
  2. Launch the browser’s developer console (you can do a quick Google on how to do this since the instructions are specific to each browser).
  3. Click on the Network tab of the developer console, and apply the “CSS” filter.
  4. Now, launch your site’s homepage and see what files are loaded by the browser. Take note of them.
  5. Once that’s done, open a new incognito page and repeat steps 2 to 4.
  6. If you notice any file being loaded that was not on the previous list, click on that file in the developer console and then click on the Headers tab.
  7. Look at the Request URL. It will point out where that file is fetched from. Take note of the path from “wp-content” onwards.
A screenshot of Chrome’s developer console, showing one of the CSS files fetched on this page. Notice the highlighted path? That is what you should take note of.

Do this for any page where you notice a rendering issue. Once you got all the additional stylesheets’ paths, head to Appearance → Theme Editor and open up the functions.php file. Now, see if there is already a stylesheet enqueuing function there. If not, create a new one and enqueue it following the snippet below:

For every path you noted down, apply the code written in line number 8. Replace my-missing-theme-name with the stylesheet name, my-missing-theme-path with the stylesheet path, and my-missing-theme-version with the stylesheet version, if any (otherwise leave it as ‘’). Click on “Update File”, and try launching and navigating around your site again. Hopefully, all the rendering issues are now fixed.

The above fix is only applicable to fix the missing stylesheets issue. If your plugin requires one or more functions to be run on page load, then according to this blogpost you will need to call that function again by adding it to the onAfter property of the Smoothstate.js setting.

Adding a Loader

By this stage, I hope you have a revamped site with Smoothstate.js properly integrated. If you host your site on a managed hosting plan with excellent bandwidth, then chances are you would not need this. However, if like me, you host your site on a shared hosting plan, then sometimes your site might take longer than expected to transition from one page to another. This is where the loader comes to the rescue!

The idea of a loader is to provide an indicator to the user that the site is not broken. I believe that showing a visitor something is better than nothing. Yet, having a loader shown in each page transition will also be annoying to the user. Hence it’s important to tune the tolerance time before the loader is displayed.

As our site now applies Smoothstate.js transitions, this loader will only be shown when a visitor is already inside your site and is transitioning between pages. It will not be shown on the initial load of your site.

As we are transitioning the div tag with the “site-content” class, we will need to add the loader as a sibling to this element. We will also need to ensure that the loader takes up only the remaining space below the header, which remains unchanged throughout the visitor’s visit to the site.

To do this, we would need to modify the child theme’s header.php file. However, chances are the child theme you created did not come with a header.php file. If so, all you need to do is copy the parent theme’s header.php file into the child theme using your hosting provider’s FTP client. Once that’s done, you can go to Appearance → Theme Editor and access the child theme’s header.php file. There, look for the HTML tag with the “site-content” class.

Before modifying the header.php file, browser the web for or design yourself a good pure CSS loader. If you prefer adopting someone’s design, I recommend getting one from loading.io. The 12 designs shown in the hyperlink are all CC0 licensed and can thus be used freely.

Copy your choice loader’s HTML tags right above the HTML tag with the “site-content” class. Give an id property to your loader so that we can easily refer to it in our script later on. You can refer to the snippet below for reference. Don’t forget to add the CSS into the aggregated CSS file following the steps in the previous section.

As you can see, the loader is initialized with an inline “display: none” style attribute. We will handle the display and hiding of both the content and loader with some jQuery by augmenting the custom script we did above.

With that said, head to the custom script file in the assets/js folder (or wherever you put yours just now) and prepare to do some modifications. The first thing we need to do is to tell Smoothstate.js to do something while the page is rendering. This is done by adding an onProgress property to its settings object. During onProgress, we would display the loader and hide the content. And then, in onAfter we would do the reverse.

However, as discussed before, we do not want the loader to display right away all the time. Hence, we need to set a tolerance window. Only when loading takes more than the tolerance window will we show the loader to alert the visitor of the unfortunate delay. We can easily do this by calling the “setTimeout” function provided by JavaScript.

However, now comes another problem! Imagine we provide a tolerance window of 1 second (1000ms). When the page is refreshing, the onProgress state initialized an internal timer to show the loader after 1 second. However, the page actually loads after 700ms, during which the onAfter procedure takes place. If we do not tell the code to stop and reset the internal timer, the loader will be shown after the page is loaded, which is wrong! Hence, we also need to modify the onAfter by adding a “clearTimeout” to reset any initiated timer before rendering the page.

With all that said, the complete code can be seen in the snippet below:

In the sample above, we assign a tolerance window of 1 second (1000ms). When the page is loading, the set an internal timer and assign it to the loaderTimer variable. If the page is loaded before the tolerance window, the check on if loaderTimer exists would return true and we would reset the internal timer. However, if the page takes more than 1 second to load, the internal timer would render the loader, which would be removed once the page is rendered.

Adding (or Restoring) Google Analytics

With the above implemented properly, your site’s UI/UX should look snazzy and modern. Unfortunately, if you’ve incorporated Google Analytics into your WordPress site, it will not work correctly anymore.

The reason being that when readers navigate around your site, the Analytics script is fired only once during the initial page load. Any navigation afterwards results in only partial updates of the HTML body tag. As such, scripts that normally run when page reload completes will not be run.

In order to make Google Analytics track page navigations within your website again, we will need to use Autotrack, which is the official Google plugin to make Analytics work on AJAX-based website. Thus, we need to make the following changes:

  1. If you use the Google Site Kit plugin (which, you should if you haven’t), head to Settings → Analytics and switch off the “Let Site Kit place code on your site” feature.
  2. Before we re-insert the analytics script back into our site manually, we will create another custom JavaScript file (see the analytics-autotrack.js file in the gist above) and add it to our child theme’s assets/js folder.
    That script is basically a modification of the default script provided by Google. You can actually keep the default script if all you are interested in is the page view.
  3. Finally, let’s head to the functions.php file of the child theme and add the following code to enqueue the custom script above together with the analytics.js and autotrack.js files into our site’s header file.

With the above changes, when an AJAX call is fired to navigate reader to a new page, this information will be sent to Google Analytics, thus providing you with accurate data again. What’s also nice is that any other event tracker added into the custom JavaScript file above will also be sent to Google Analytics as and when they are triggered. Neat!

Phew! That was rather long. If you’ve made it to the end, congratulations, and I hope you’ve successfully applied Smoothstate.js to your WordPress site! If you read through it all but have yet to give it a go, I would strongly recommend you to do so. It is not as difficult as it looks 😄 And if you need more encouragement to do it, I hope my portfolio website will do just that!

The end product of all the steps above, so worth it! As you can see, I am on a rather slow network, and the loader helped provide that “I’m working, please wait” feedback to the visitor.

--

--

Stevanus Satria

Full-time developer, part-time designer, casual pianist and gamer. Currently coding the Future of Travel @amadeusapac