Barba.js WordPress

Barba.js with WordPress

Interactive websites are the in-thing today because they add the oomph factor to a bland and drab looking website. I came across this popular library barba.js.

Barba.js is a lightweight JavaScript library which adds slick transitions when navigating between pages and reduces HTTP requests over the server.

Despite their easy to read documentation, there’s a dearth of good and comprehensive tutorial on how to get it running. I had issues getting it up and running out of the box on my WordPress website, so I thought I would document the issues and their fixes as I came across them.

Basic Tutorial

1 To install Barba.js on a WordPress website is pretty straightforward. The following code needs to be added to the functions.php file to register and enqueue barba.js and gsap (if that’s what you want to use for animation):

/**
 ** Enqueue scripts
 **/
function zr139821_scripts() {

     wp_enqueue_script( 'barba-js', 'https://unpkg.com/@barba/core' );
     wp_enqueue_script( 'gsap-js', 'https://unpkg.com/gsap@latest/dist/gsap.min.js' );
	
}
add_action( 'wp_enqueue_scripts', 'zr139821_scripts' );

2 The second step according to barba.js documentation is to modify index.php and all base template (pages.php, search.php, archive.php, etc..) files to incorporate the following changes:

<body data-barba="wrapper">
  <!-- put here content that will not change
  between your pages, like <header> or <nav> -->

  <main data-barba="container" data-barba-namespace="home">
    <!-- put here the content you wish to change
    between your pages, like your main content <h1> or <p> -->
  </main>

  <!-- put here content that will not change
  between your pages, like <footer> -->
</body>
So to modify the body tag, we would have to edit header.php and as the main tag is in all the base templates (index, search, page), we will need to go to each file to modify the main tag. Since I did not want to modify all the templates, I created div wrapper in header.php file with the end div tag in footer.php file.

Header.php:
<body <?php body_class(); ?> data-barba="wrapper">
  <div id="barba-container" data-barba="container">	
Footer.php
   </div><!-- #barba-container -->
</div><!-- #page -->

3 Then, we need to add/modify the gsap transitions in the JavaScript file. Here’s a simple transition given in barba.js documentation:

      barba.init({
        transitions: [{
          name: 'opacity-transition',
          leave(data) {
            return gsap.to(data.current.container, {
              opacity: 0
            });
          },
          enter(data) {
            return gsap.from(data.next.container, {
              opacity: 0
            });
          }
        }]
      });

The Problem

WordPress assigns classes to the body tag depending on what type of template it is and because we are adding data-barba=”wrapper” attribute to the body, by design of barba.js, the wrapper tag doesn’t change the classes on page transition.

The Solution

To fix this issue, we need to use barba hooks to swap the body classes and then manually set the relevant CSS/JS links for the current container during the page transitions. We will be using the following function[1] to load the CSS/JS files:
function loadjscssfile(filename, filetype) {
  if (filetype == "js") {
    //if filename is a external JavaScript file
    const existingScript = document.querySelector('script[src="${filename}"]');
    if (existingScript) {
      existingScript.remove();
    }
    var fileref = document.createElement("script");
    fileref.setAttribute("type", "text/javascript");
    fileref.setAttribute("src", filename);
  } else if (filetype == "css") {
    //if filename is an external CSS file
    const existingCSS = document.querySelector(`link[href='${filename}']`);
    if (existingCSS) {
      existingCSS.remove();
    }
    var fileref = document.createElement("link");
    fileref.setAttribute("rel", "stylesheet");
    fileref.setAttribute("type", "text/css");
    fileref.setAttribute("href", filename);
  }
  if (typeof fileref != "undefined")
    document.getElementsByTagName("head")[0].appendChild(fileref);
}
Next we will be using a function[2] to initialise on every page transition to detect which template is the current container and then re-load the relevant script or style files:
var scripts = {
    init: function () {
        if (document.getElementsByTagName("body")[0].classList.contains("home")) {
          console.log("This is home page");
          this.homepage();
        }
        else if (document.getElementsByTagName("body")[0].classList.contains("blog")) {
          console.log("This is blog page");
       	  this.blog();
        }
    },
    homepage: function () {
           const homepageCSS = "custom-homepage.css";
           loadjscssfile(homepageCSS, "css");
    },
    blog: function () {
          const blogCSS = "blog.css";
          loadjscssfile(blogCSS, "css");
    }
};
Now this is the where we bring it all together using barba.hooks.beforeEnter :
barba.hooks.beforeEnter((data) => {
    console.log("Hello there");

   if (data.current.container) {
      // only run during a page transition - not initial load
      let nextHtml = data.next.html;
      let parser = new DOMParser();
      let htmlDoc = parser.parseFromString(nextHtml.replace(/(<\/?)body( .+?)?>/gi, '$1notbody$2>', nextHtml), 'text/html');
      let bodyClasses = htmlDoc.querySelector('notbody').getAttribute('class');
      document.getElementsByTagName("body")[0].setAttribute('class', bodyClasses);

       scripts.init();

    }

});
That’s it! Your app.js file should look like this:
function loadjscssfile(filename, filetype) {
  if (filetype == "js") {
    //if filename is a external JavaScript file
    const existingScript = document.querySelector('script[src="${filename}"]');
    if (existingScript) {
      existingScript.remove();
    }
    var fileref = document.createElement("script");
    fileref.setAttribute("type", "text/javascript");
    fileref.setAttribute("src", filename);
  } else if (filetype == "css") {
    //if filename is an external CSS file
    const existingCSS = document.querySelector(`link[href='${filename}']`);
    if (existingCSS) {
      existingCSS.remove();
    }
    var fileref = document.createElement("link");
    fileref.setAttribute("rel", "stylesheet");
    fileref.setAttribute("type", "text/css");
    fileref.setAttribute("href", filename);
  }
  if (typeof fileref != "undefined")
    document.getElementsByTagName("head")[0].appendChild(fileref);
}

var scripts = {
    init: function () {
        if (document.getElementsByTagName("body")[0].classList.contains("home")) {
          console.log("This is home page");
          this.homepage();
        }
        else if (document.getElementsByTagName("body")[0].classList.contains("blog")) {
          console.log("This is blog page");
       	  this.blog();
        }
    },
    homepage: function () {
           const homepageCSS = "custom-homepage.css";
           loadjscssfile(homepageCSS, "css");
    },
    blog: function () {
          const blogCSS = link to your custom blog css file;
          loadjscssfile(blogCSS, "css");
    }
};

barba.hooks.beforeEnter((data) => {
    console.log("Hello there");

   if (data.current.container) {
      // only run during a page transition - not initial load
      let nextHtml = data.next.html;
      let parser = new DOMParser();
      let htmlDoc = parser.parseFromString(nextHtml.replace(/(<\/?)body( .+?)?>/gi, '$1notbody$2>', nextHtml), 'text/html');
      let bodyClasses = htmlDoc.querySelector('notbody').getAttribute('class');
      document.getElementsByTagName("body")[0].setAttribute('class', bodyClasses);

       scripts.init();

    }

});

barba.init({
        transitions: [{
          name: 'opacity-transition',
          leave(data) {
            return gsap.to(data.current.container, {
              opacity: 0
            });
          },
          enter(data) {
            return gsap.from(data.next.container, {
              opacity: 0
            });
          }
        }]
});

The Problem

What if you want to assign different namespace to each template file to customise the page transitions accordingly?

The Solution

To assign different namespaces to templates, create a function[3] in functions.php file returning the template type:
/**
 ** Get current template
 **/
function get_current_template() {
  global $template;
  return basename($template, '.php');
}
Then, modify header.php to call the current template:
<body <?php body_class(); ?> data-barba="wrapper">
	<div id="barba-container" data-barba="container" data-barba-namespace="<?php echo get_current_template() ?>">

That’s it. I hope this has been easy to understand.

Have you used or are trying to use Barba.js on your website? How easy or difficult did you find to incorporate this library to your website? Comment below!

[1] Create smooth page transitions using Barba.js w/ WordPress, Elementor & Gravity Forms by Advantage.
[2] Implement barba.js with WordPress by Feras Jobeir.
[3] Credit goes to @luruke for this Github comment.

Helpful Resources

One thought on “Barba.js with WordPress

  1. Thank you very much! now i see my classes are updating on each page. But the scripts are loading only when using some website url… Is there a way to link scripts that are in
    a computer folder? like this for example?

    homepage: function () {
    const homepageJS = “../scripts/js/my-script.js”;
    loadjscssfile(homepageJS, “js”);

    I’m new to web.dev, thank you in advance…

Leave a Reply

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

Zo

This website is handcrafted with these tools:

  • Underscores
  • Barba.js
  • PHP