How to include Vue components directly to PHP template and pass them data without API calls

Best feature of Vue is that you don’t have to make SPA. You can use it as little or as much as you need. Let say you have a WordPress site and you want to add a complex search results page and use Vue to render it.

You could ofcouse mount Vue to some element and fetch data via WordPress REST API. This is viable option, but not the best of performance since WordPress REST API is slow. How about we just pass search results directly to Vue component from our search.php template? Yes it is possible.

What you need to do is to make certain area of your DOM a Vue app and pass it components you want to use. Note that you are not mounting them (and replace the html element with your Vue app) so the original HTML element still renders.

import Vue from 'vue';
import VueResource from 'vue-resource';
import Searchresults from './vue/searchresults.vue';

Vue.use(VueResource);

// Include Vue components you want to be available inside certain html element.

$( document ).ready(function() {

  if(document.getElementById('searchResults')){
      new Vue({
          el: '#searchResults',
          components:
          {Searchresults},      
        })
  }
});

Now you are able to render your Vue component directly in your PHP template like this. You can then pass your search results (or whatever data you happen to have in your case) as a props to your Vue component. If you pass an array you need to put ‘:’ in front of propname. Also propnames have to be all small letters. Note also that component names can’t be camelcased either.

<?php
$results = $data->posts;
?>

    <div class="searchResults" id="searchResults">
      <Searchresults :results='<?php echo json_encode($results);?>'></Searchresults>
    </div>

Then at your Vue component you can simply receive props normally. Remember to tell what data type you are expecting.

<template>
  <div class="vueSearchResults">
    <div class="searchResultHeader" />
    <ul class="searchResultsContainer">
      <h1 class="searchHeading">Results for search: '{{searchText}}'</h1>
      <li v-for="result in results">
        <a v-bind:href="result.link">
          <h2>{{result.title}}</h2>
        </a>
      </li>
    </ul>
  </div>
</template>

<script>

export default {
  data() {
    return {
      searchText: ""
    };
  },
  props: {
    results: Array
  },

  methods: {
    getParams() {
      const url_string = window.location.href;
      const newUrl = new URL(url_string);
      let s = newUrl.searchParams.get("s");
      this.searchText = s;
    }
  },
  mounted() {
    this.getParams();
  }
};
</script>