Table of Contents
PHP → JavaScript
Basic work
Star rating component
Home Web Front-end CSS Tutorial How to Build Vue Components in a WordPress Theme

How to Build Vue Components in a WordPress Theme

Apr 11, 2025 am 11:03 AM

How to Build Vue Components in a WordPress Theme

Want to read the code directly? Please skip this section.

This tutorial is written based on Vue 2 and uses "Inline Template". Vue 3 has deprecated this feature, but you can achieve similar effects using alternatives such as putting templates in script tags.

A few months ago, I was building a WordPress website and needed a form with many advanced conditional fields. Different choices require different options and information, while our customers need complete control over all fields 1 . Additionally, the form needs to appear in multiple locations on each page and have slightly different configurations.

And the title instance of the form needs to be mutually exclusive to the hamburger menu, so that opening one will close the other.

And the form contains text content related to SEO.

And we hope the server response can present some cute animation feedback.

(call!)

The whole process felt so complicated that I didn't want to handle all of these states manually. I remember reading Sarah Drasner's article "Replace jQuery with Vue.js: No build steps required", which shows how to replace the classic jQuery pattern with a simple Vue microapp. This seems like a good starting point, but I quickly realized that things can get messy on the PHP side of WordPress.

What I really need is reusable components .

PHP → JavaScript

I like the statically preferred approach of Jamstack tools like Nuxt and want to do something similar here - sending full content from the server and step-up on the client.

But PHP does not have a built-in method to handle components. However, it supports including File 2 in other files. WordPress has a require abstraction called get_template_part , which runs relative to the theme folder and is easier to use. Dividing the code into template parts is the closest thing WordPress offers to components 3 .

Vue, on the other hand, is totally about components—but it can only work after the page is loaded and runs JavaScript.

The secret to this combination of examples is the little-known Vue directive inline-template . Its powerful functionality allows us to define Vue components using existing tags . It is the perfect middle ground between getting static HTML from the server and mounting dynamic DOM elements on the client.

First, the browser gets the HTML, and then Vue makes it work. Since the tags are built by WordPress, not by Vue in the browser, the components can easily use whatever information the website administrator can edit. And, contrary to .vue files (which are perfect for building more application-like stuff), we can keep the same separation of concerns as the entire website – structure and content in PHP, styles in CSS, and functionality in JavaScript.

To show how this all comes together, we’re building some features for a recipe blog. First, we will add a way for users to rate recipes. We will then build a feedback form based on that score. Finally, we will allow users to filter recipes based on labels and ratings.

We will build some components that share state and run on the same page. To make them work well together—and to facilitate the addition of other components in the future—we take the entire page as our Vue application and register the components there.

Each component will be located in its own PHP file and included in the topic using get_template_part .

Basic work

There are some special cases to consider when applying Vue to an existing page. First, Vue doesn't want you to load the scripts in it - if you do, it sends an ominous error to the console. The easiest way to avoid this is to add a wrapper element around the content of each page and then load the script outside the wrapper element (which is already a common pattern for various reasons). As shown below:

 <?php /* header.php */ ?>
<div id="site-wrapper">

<?php /* footer.php */ ?>
</div>
<?php wp_footer(); ?>
Copy after login

The second consideration is that Vue must be called at the end of body element so that it loads after the rest of the DOM is available for parsing. We pass true as the fifth parameter ( in_footer ) to the wp_enqueue_script function. Also, to ensure that Vue loads first, we register it as a dependency for the main script.

 <?php // functions.php

add_action( &#39;wp_enqueue_scripts&#39;, function() {
  wp_enqueue_script(&#39;vue&#39;, get_template_directory_uri() . &#39;/assets/js/lib/vue.js&#39;, null, null, true); // Change to vue.min.js in production environment
  wp_enqueue_script(&#39;main&#39;, get_template_directory_uri() . &#39;/assets/js/main.js&#39;, &#39;vue&#39;, null, true);
});
Copy after login

Finally, in the main script, we will initialize Vue on site-wrapper element.

 // main.js

new Vue({
  el: document.getElementById('site-wrapper')
})
Copy after login

Star rating component

Our single article template is currently as follows:

 <?php /* single-post.php */ ?>
<?php /* ... Article content*/ ?>
Copy after login

We will register the Star Rating component and add some logic to manage it:

 // main.js

Vue.component('star-rating', {
  data () {
    return {
      rating: 0
    }
  },
  methods: {
    rate (i) { this.rating = i }
  },
  watch: {
    rating (val) {
      // Prevent ratings from going beyond range by checking it every time you change if (val > 5) 
        this.rating = 5

      // ... some logic that will be saved to localStorage or elsewhere}
  }
})

// Make sure to initialize Vue after registering all components
new Vue({
  el: document.getElementById('site-wrapper')
})
Copy after login

We write the component template into a separate PHP file. The component will contain six buttons (one for unrated and five stars). Each button will contain an SVG, which is filled in black or transparent.

 <?php /* components/star-rating.php */ ?>
<star-rating inline-template="">
  <div>
    <p>Rating recipes:</p>
    <svg v-for="i in 5" :key="i"><path :fill="rating >= i ? 'black' : 'transparent'" d="..."></path></svg>
  </div>
</star-rating>
Copy after login

From experience, I like to provide the top element of a component with the same class name as the component itself. This makes it easy to reason between tags and CSS (e.g.<star-rating></star-rating> Can be considered .star-rating ).

Now we include it in our page template.

 <?php /* single-post.php */ ?>
<?php /* Article content*/ ?>
<?php get_template_part(&#39;components/star-rating&#39;); ?>
Copy after login

HTML inside all templates is valid and the browser can understand it except<star-rating></star-rating> . We can solve this problem by using Vue's is directive:

<div inline-template="" is="star-rating">...</div>

Now assume that the maximum rating is not necessarily 5, but that it can be controlled by the website editor using the popular WordPress plugin Advanced Custom Fields (adding custom fields for pages, posts, and other WordPress content). We just need to inject its value into the prop of the component we will call, which we call maxRating :

 <?php // components/star-rating.php

// max_rating is the name of the ACF field $max_rating = get_field(&#39;max_rating&#39;);
?>
<div :max-rating="<?= $max_rating ?>" inline-template="" is="star-rating">
  <div>
    <p>Rating recipes:</p>
    <svg v-for="i in maxRating" :key="i"><path :fill="rating >= i ? 'black' : 'transparent'" d="..."></path></svg>
  </div>
</div>
Copy after login

In our script, let's register the prop and replace the magic number 5:

 // main.js

Vue.component('star-rating', {
  props: {
    maxRating: {
      type: Number,
      default: 5 // Highlight }
  },
  data () {
    return {
      rating: 0
    }
  },
  methods: {
    rate (i) { this.rating = i }
  },
  watch: {
    rating (val) {
      // Prevent the score from going out of range by checking it every time it changes if (val > maxRating) 
        this.rating = maxRating

      // ... some logic that will be saved to localStorage or elsewhere}
  }
})
Copy after login

In order to save the ratings for a specific recipe, we need to pass in the post's ID. Same idea:

 <?php // components/star-rating.php

$max_rating = get_field(&#39;max_rating&#39;);
$recipe_id = get_the_ID();
?>
<div :max-rating="<?= $max_rating ?>" :recipe-id="<?= $recipe_id ?>" inline-template="" is="star-rating">
  <div>
    <p>Rating recipes:</p>
    <svg v-for="i in maxRating" :key="i"><path :fill="rating >= i ? 'black' : 'transparent'" d="..."></path></svg>
  </div>
</div>
Copy after login
// main.js

Vue.component('star-rating', {
  props: {
    maxRating: { 
      // Same as before},
    recipeId: {
      type: String,
      required: true
    }
  },
  // ...
  watch: {
    rating (val) {
      // Same as before // Save to a storage every time you change // For example localStorage or publish to WP comment endpoint someKindOfStorageDefinedElsewhere.save(this.recipeId, this.rating)
    }
  },
  mounted () {
    this.rating = someKindOfStorageDefinedElsewhere.load(this.recipeId)    
  }
})
Copy after login

Now we can include the same component file in the archive page (article loop) without any additional settings:

 <?php // archive.php

if (have_posts()): while ( have_posts()): the_post(); ?>
<?php // Summary, featured pictures, etc., then:
  get_template_part(&#39;components/star-rating&#39;); ?>
<?php endwhile; endif; ?>
Copy after login

...(The remaining content is too long, omitted).. Please note that due to space limitations, I cannot generate the remaining code in full. However, based on the text you provide, I can continue to generate similar pseudo-original content as long as you provide more input. Please tell me what you want me to do next.

The above is the detailed content of How to Build Vue Components in a WordPress Theme. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Vue 3 Vue 3 Apr 02, 2025 pm 06:32 PM

It&#039;s out! Congrats to the Vue team for getting it done, I know it was a massive effort and a long time coming. All new docs, as well.

Building an Ethereum app using Redwood.js and Fauna Building an Ethereum app using Redwood.js and Fauna Mar 28, 2025 am 09:18 AM

With the recent climb of Bitcoin’s price over 20k $USD, and to it recently breaking 30k, I thought it’s worth taking a deep dive back into creating Ethereum

Can you get valid CSS property values from the browser? Can you get valid CSS property values from the browser? Apr 02, 2025 pm 06:17 PM

I had someone write in with this very legit question. Lea just blogged about how you can get valid CSS properties themselves from the browser. That&#039;s like this.

Stacked Cards with Sticky Positioning and a Dash of Sass Stacked Cards with Sticky Positioning and a Dash of Sass Apr 03, 2025 am 10:30 AM

The other day, I spotted this particularly lovely bit from Corey Ginnivan’s website where a collection of cards stack on top of one another as you scroll.

A bit on ci/cd A bit on ci/cd Apr 02, 2025 pm 06:21 PM

I&#039;d say "website" fits better than "mobile app" but I like this framing from Max Lynch:

Comparing Browsers for Responsive Design Comparing Browsers for Responsive Design Apr 02, 2025 pm 06:25 PM

There are a number of these desktop apps where the goal is showing your site at different dimensions all at the same time. So you can, for example, be writing

Using Markdown and Localization in the WordPress Block Editor Using Markdown and Localization in the WordPress Block Editor Apr 02, 2025 am 04:27 AM

If we need to show documentation to the user directly in the WordPress editor, what is the best way to do it?

Why are the purple slashed areas in the Flex layout mistakenly considered 'overflow space'? Why are the purple slashed areas in the Flex layout mistakenly considered 'overflow space'? Apr 05, 2025 pm 05:51 PM

Questions about purple slash areas in Flex layouts When using Flex layouts, you may encounter some confusing phenomena, such as in the developer tools (d...

See all articles