How to Use Vue in WordPress (Without Webpack)

If you need a complex front-end feature in WordPress, don't use jQuery. Get a proper library like Vue! We will learn how to set it up in this article.

If you are making a complex front-end feature in WordPress, don’t use jQuery. Get a proper library like Vue!

It will save you lots of time and headache from maintaining it.

In this article, we will learn how to setup Vue in WordPress. This is something that I struggled with because it’s quite different compared to setting it in plain HTML.

What is Vue JS?

Vue JS is a library to create an interactive element. It is the easiest to learn compared to React or Angular.

I won’t teach you the basics of Vue. There are many people covering that already, such as this awesome tutorial from Academind:

Vue Tutorial Playlist by Academind

But those tutorials are in plain HTML. Let’s integrate it with WordPress!


Step 1: Register JavaScript

Minified Vue doesn’t give proper error messages, so during development, you need to use the expanded version.

Here’s how to set the conditional:

add_action( 'wp_enqueue_scripts', 'enqueue_vue' );

function enqueue_vue() {
  if( WP_DEBUG ) {
    wp_register_script( 'vue', 'https://cdn.jsdelivr.net/npm/vue/dist/vue.js', [], '', true );
  } else {
    wp_register_script( 'vue', 'https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js', [], '', true );
  }

  // your app code
  wp_register_script( 'my-app', get_stylesheet_directory_uri()
 . '/js/my-app.js', [], '', true );
}

Then, change the WP_DEBUG constant in your local site’s config, to true. Your live site should stay false.

...

define( 'WP_DEBUG', true );

...

Step 2: Enqueue JavaScript

You should only enqueue the script when the page requires it.

For example, we have a Vue app called Cost Calculator that is outputted with [cost-calculator] shortcode.

Here’s how to load the scripts only when the shortcode is used:

add_shortcode( 'cost-calculator', 'shortcode_cost_calculator' );

function shortcode_cost_calculator( $atts ) {
  wp_enqueue_script( 'vue' );
  wp_enqueue_script( 'my-app' );

  // ...
}

Note: If you use the app in all pages, then enqueue it right after you register it in Step 1.

Step 3: Pass in PHP Variables (if needed)

Use localize feature to pass them like shown below:

add_shortcode( 'cost-calculator', 'shortcode_cost_calculator' );

function shortcode_cost_calculator( $atts ) {
  wp_enqueue_script( 'vue' );
  wp_enqueue_script( 'cost-calculator' );

  wp_localize_script( 'cost-calculator', 'ccLocalize', [
    'API_URL' => 'https://wptips.dev/wp-json/wp/v2',
    'items' => [
      [ 'name' => 'Item 1', 'price' => 100 ],
      [ 'name' => 'Item 2', 'price' => 150 ],
    ]
  ] );

  
  return get_template_part( 'shortcode/cost-calculator' );
}

Now your script can use the variable ccLocalize that contains those values.

Step 4: Template and Script

Usually, it’s easier to write the template first.

In this example, we want to list our items with buy button and total cost at the bottom:

<div id="cost-calculator" class="cost-calculator" v-cloak>
  <h1>Cost Calculator</h1>
  <ul>
    <li v-for="i in items" :key="i.name">
      <h3>{{ i.name }}</h3>
      <p>{{ i.price }}</p>
      <a class="button" @click="addToCart( i )">Buy This</a>
    </li>
  </ul>

  <h2>Total Cost: {{ total }}</h2>
</div>

The v-cloak attribute will hide the element before it finished loading. You simply need to add this in your CSS:

[v-cloak] {
  display: none
}

Now for the script, here’s how I write it. Wrapped with self-invoking function, on-ready listener, and no jQuery in sight!

(function() { 'use strict';

document.addEventListener( 'DOMContentLoaded', onReady );
function onReady() {
  initApp();
}

function initApp() {
  new Vue({
    el: '#cost-calculator',
    data: {
      API_URL: ccLocalize.API_URL,
      items: ccLocalize.items,
      total: 0
    },
    methods: {
      addToCart( item ) {
        this.total += item.price
      },
    },
  });
}

})();

Step 5: Need Components?

Let’s say we want to split the items into Component, here’s how I would organize them:

<div id="cost-calculator" class="cost-calculator" v-cloak>
  <h1>Cost Calculator</h1>
  <ul>
    <product-item v-for="i in items" :key="i.name"
      :name="i.name"
      :price="i.price"
      @cart="onAddToCart" />
  </ul>

  <h2>Total Cost: {{ total }}</h2>
</div>

<!-- Template for ProductItem -->
<template id="item-template">
  <li>
    <h3>{{ name }}</h3>
    <p>{{ price }}</p>
    <a class="button" @click="addToCart">Buy This</a>
  </li>
</template>
(function() { 'use strict';

document.addEventListener( 'DOMContentLoaded', onReady );
function onReady() {
  initApp();
}

function initApp() {
  new Vue({
    el: '#cost-calculator',
    // register the component here
    components: {
      ProductItem: ProductItem()
    },
    data: {
      API_URL: ccLocalize.API_URL,
      items: ccLocalize.items,
      total: 0
    },
    methods: {
      onAddToCart( item ) {
        this.total += item.price
      },
    },
  });
}

// <product-item> component
function ProductItem() {
  return {
    template: '#item-template',
    props: [ 'name', 'price' ],
    data: () => { return {} },
    methods: {
      addToCart() {
        this.$emit( 'cart', this.$props );
      },
    }
  };
}

})();

I organize it this way because it’s similar to Webpack format. It will help you transition into it in the future.


Conclusion

This is a quick and dirty way to create Vue app in WordPress. It’s much tidier to use build tools like Webpack, but it’s barrier of entry can be intimidating..

My next article will be how to setup Vue in WordPress with Webpack.

Let me know in the comment if you have any question regarding this topic 🙂

Default image
Henner Setyono
A web developer who mainly build custom theme for WordPress since 2013. Young enough to never had to deal with using Table as layout.
Leave a Reply