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

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: How To Unlock Everything In MyRise
1 months ago By 尊渡假赌尊渡假赌尊渡假赌

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)

Making Your First Custom Svelte Transition Making Your First Custom Svelte Transition Mar 15, 2025 am 11:08 AM

The Svelte transition API provides a way to animate components when they enter or leave the document, including custom Svelte transitions.

Working With GraphQL Caching Working With GraphQL Caching Mar 19, 2025 am 09:36 AM

If you’ve recently started working with GraphQL, or reviewed its pros and cons, you’ve no doubt heard things like “GraphQL doesn’t support caching” or

Show, Don't Tell Show, Don't Tell Mar 16, 2025 am 11:49 AM

How much time do you spend designing the content presentation for your websites? When you write a new blog post or create a new page, are you thinking about

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

How do you use CSS to create text effects, such as text shadows and gradients? How do you use CSS to create text effects, such as text shadows and gradients? Mar 14, 2025 am 11:10 AM

The article discusses using CSS for text effects like shadows and gradients, optimizing them for performance, and enhancing user experience. It also lists resources for beginners.(159 characters)

Creating Your Own Bragdoc With Eleventy Creating Your Own Bragdoc With Eleventy Mar 18, 2025 am 11:23 AM

No matter what stage you’re at as a developer, the tasks we complete—whether big or small—make a huge impact in our personal and professional growth.

What the Heck Are npm Commands? What the Heck Are npm Commands? Mar 15, 2025 am 11:36 AM

npm commands run various tasks for you, either as a one-off or a continuously running process for things like starting a server or compiling code.

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:

See all articles