{"id":172043,"date":"2018-06-05T13:00:30","date_gmt":"2018-06-05T13:00:30","guid":{"rendered":"https:\/\/premium.wpmudev.org\/blog\/?p=172043"},"modified":"2022-03-08T04:58:14","modified_gmt":"2022-03-08T04:58:14","slug":"creating-a-hybrid-single-page-app-wordpress-with-vuejs","status":"publish","type":"post","link":"https:\/\/wpmudev.com\/blog\/creating-a-hybrid-single-page-app-wordpress-with-vuejs\/","title":{"rendered":"Creating a Hybrid Single Page App in WordPress with VueJS"},"content":{"rendered":"<p>Power your WordPress application with Vue.js &#8211; the progressive JavaScript framework that now shares the stage with the likes of React and Angular.<\/p>\n<p>In this article, I&#8217;ll show you how to integrate a Single Page Search App within your existing WordPress application with <a href=\"https:\/\/vuejs.org\/v2\/guide\/index.html#What-is-Vue-js\" rel=\"noopener\" target=\"_blank\">Vue.js<\/a> &#8211; an extremely popular JavaScript framework for developing rich user interfaces. I&#8217;ll walk you through the entire process of building a Vue app from the ground up, interacting with the WordPress REST API and creating a search app with Vue&#8217;s reusable components.<\/p>\n<p>Continue reading, or jump ahead using these links:<\/p>\n<ul>\n<li><a href=\"#overview\">Overview of the Vue SPA in WordPress<\/a><\/li>\n<li><a href=\"#vue-spa-overview\">Anatomy of the Vue Single Page Search App<\/a><\/li>\n<li><a href=\"#using-wpcli\">Using Vue-CLI to Set Up a Local Development Workflow<\/a><\/li>\n<li><a href=\"#scaffolding\">Scaffolding a Vue app with Vue-CLI<\/a><\/li>\n<li><a href=\"#integrating\">Integrating the Vue SPA with WordPress<\/a><\/li>\n<li><a href=\"#building-wordpress\">Building the Single Page Search App in WordPress<\/a><\/li>\n<li><a href=\"#building-vue\">Building the Search App with Vue Single-File Components<\/a><\/li>\n<\/ul>\n<p>If you&#8217;ve never worked with Vue or other modern JavaScript frameworks\/libraries, it&#8217;s a great time to jump in. While the sheer number of frameworks urging you to up your JavaScript game can be quite overwhelming, Vue makes the journey nothing less than enjoyable.<\/p>\n<p><strong>Note: This article is intended for intermediate-advanced WordPress developers and assumes that you have a working knowledge of PHP, JavaScript, Vue.js and the <a href=\"https:\/\/developer.wordpress.org\/rest-api\/\" rel=\"noopener\" target=\"_blank\">WordPress REST API<\/a>. If you\u2019d like a refresher, I recommend that you read through the following:<\/strong><\/p>\n<ul>\n<li><a href=\"https:\/\/wpmudev.com\/blog\/loading-javascript-wordpress\/\" target=\"_blank\" rel=\"noopener\">JavaScript for WordPress Developers<\/a><\/li>\n<li><a href=\"https:\/\/www.wpsuperstars.net\/wordpress-rest-api\/\" rel=\"noopener\" target=\"_blank\">A Quick Start Guide To The WordPress REST API<\/a><\/li>\n<li><a href=\"https:\/\/wpmudev.com\/blog\/javascript-rest-api-jargon\/\" target=\"_blank\" rel=\"noopener\">JavaScript and the WordPress REST API: Understanding the Jargon<\/a><\/li>\n<\/ul>\n<p>Familiarity with <a href=\"https:\/\/vuejs.org\/v2\/guide\/comparison.html#Learning-Curve\" rel=\"noopener\" target=\"_blank\">Vue.js (2.x)<\/a> is also essential. The Single Page App (SPA) uses many of Vue&#8217;s features such as single-file components, custom events, computed properties, lifecycle hooks, as well as Axios to interact with the WordPress REST API. If you&#8217;re new to Vue, it&#8217;s really easy to pick up, and you can get started in just a couple of hours with these tutorials:<\/p>\n<ul>\n<li><a href=\"https:\/\/www.youtube.com\/playlist?list=PL55RiY5tL51p-YU-Uw90qQH419BM4Iz07\" rel=\"noopener\" target=\"_blank\">Vue.js 2 &#8211; Getting Started by Academind<\/a><\/li>\n<li><a href=\"https:\/\/www.vuemastery.com\/courses\/intro-to-vue-js\/vue-instance\" rel=\"noopener\" target=\"_blank\">Introduction to Vue.js by Vue Mastery<\/a><\/li>\n<\/ul>\n<p>Although Vue apps can be written in pure ES5 syntax, I will be using some new features of JavaScript introduced in versions ES6 and ES7. If you need to get up to speed with ES6, take a look at the following:<\/p>\n<ul>\n<li><a href=\"https:\/\/www.youtube.com\/watch?v=IEf1KAcK6A8&amp;t=2270s\" rel=\"noopener\" target=\"_blank\">ES6 JavaScript &#8211; The Basics<\/a><\/li>\n<li><a href=\"https:\/\/deliciousbrains.com\/wordpress-developers-guide-es2015-es6\/\" rel=\"noopener\" target=\"_blank\">The WordPress Developer\u2019s Guide To ES2015 (ES6)<\/a><\/li>\n<\/ul>\n<p>Whether you need to use modern JavaScript or Vue.js will completely depend on your requirements and preferences. My goal is to help you explore the possibilities of integrating Single Page Applications in WordPress with a practical Search app. So let&#8217;s get started!<\/p>\n<h2 id=\"overview\">Overview of the Vue SPA in WordPress<\/h2>\n<p>For this article, I&#8217;ve built a Single Page Search app in WordPress with Vue.js using a child theme of the Twenty Seventeen WordPress theme. You can <a href=\"https:\/\/github.com\/nuancedesignstudio\/wordpress-vuejs-search\" rel=\"noopener\" target=\"_blank\">download the child theme from here<\/a> to follow along with the article.<\/p>\n<p>The Search app can be rendered on any WordPress page using <a href=\"https:\/\/developer.wordpress.org\/themes\/template-files-section\/page-template-files\/#creating-custom-page-templates-for-global-use\" rel=\"noopener\" target=\"_blank\">Custom Page Templates<\/a>. The Page Template basically provides the Vue instance with an existing DOM element to mount on.<\/p>\n<div  class=\"wpdui-pic-regular  \">\n<figure class=\"wp-caption alignnone\" data-caption=\"true\"><img loading=\"lazy\" decoding=\"async\" class=\"attachment-600x600 size-600x600\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2018\/05\/integrating-vue-with-wordpress.png\" alt=\"Integrating a Vue app in WordPress\" width=\"600\" height=\"471\" \/><figcaption class=\"wp-caption-text\">Integrating a Vue.js App in WordPress with Custom Page Templates<\/figcaption><\/figure>\n<\/div>\n<p>The app thus adopts a hybrid or a mixed approach, where a server-side application (WordPress) also serves the frontend, but portions of it are rendered with a client-side application like Vue. This is different from a pure SPA that may use a headless or a decoupled CMS, where the server-side engine is only responsible for providing the content (through an API) and does not generate the HTML for rendering it.<\/p>\n<h3>Enhancing Search Experience with Vue.js<\/h3>\n<p>In a traditional search scenario, each request to the server causes the page to reload. However, with Vue.js or an SPA approach, the page is dynamically updated as the user interacts with the search but without the constant reloads. This makes for a very pleasing user experience.<\/p>\n<p>In fact, you can try out the pen I&#8217;ve created <a href=\"https:\/\/codepen.io\/karannagupta\/pen\/jxQrMo\" rel=\"noopener\" target=\"_blank\">right here<\/a>.<\/p>\n<p>My Vue Search app builds on the example from the pen I&#8217;ve linked to above. So, let&#8217;s get a sense of the inner workings of the Search app before diving into the code.<\/p>\n<h2 id=\"vue-spa-overview\">Anatomy of the Vue Single Page Search App<\/h2>\n<p>The following infographic explains how the Search App is composed using several <a href=\"https:\/\/vuejs.org\/v2\/guide\/components.html#Reusing-Components\" rel=\"noopener\" target=\"_blank\">reusable components<\/a> that interact with each other.<\/p>\n<div  class=\"wpdui-pic-regular  \">\n<figure class=\"wp-caption alignnone\" data-caption=\"true\"><img loading=\"lazy\" decoding=\"async\" class=\"attachment-600x600\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2018\/05\/internal-strucutre-vue-search-spa-600x600.png\" alt=\"vue search spa internal structure\" width=\"600\" height=\"600\" \/><figcaption class=\"wp-caption-text\">Internals of the Vue Single Page Search App<\/figcaption><\/figure>\n<\/div>\n<p>At a high-level, here&#8217;s what the various components do:<\/p>\n<ul>\n<li><code>AppNavigation<\/code> provides the router links for Vue Router to render the <code>AppQuickSearch<\/code> and <code>AppCustomSearch<\/code> components.<\/li>\n<li><code>AppQuickSearch<\/code> and <code>AppCustomSearch<\/code> work as parent components to <code>AppFilterSwitches<\/code> and <code>AppGetPosts<\/code>. However, they result in two completely independent Search applications, each equipped with its own of data, methods and properties.<\/li>\n<li><code>AppFilterSwitches<\/code> renders input toggle switches that may either be checkboxes or radio buttons depending on the parameters passed to it.<\/li>\n<li><code>AppGetPosts<\/code> fetches data from the WordPress REST API and filters it using the search key and toggle inputs. It then calls the <code>AppDisplayPost<\/code> component for each post in the filtered result.<\/li>\n<li><code>AppDisplayPost<\/code> renders the markup for an individual post item and displays it in the search results.<\/li>\n<\/ul>\n<p>All of this takes place inside a Custom Page Template assigned to a specific page(s) in WordPress.<\/p>\n<h3>Using Vue Single-File Components<\/h3>\n<p>You may have seen many examples of Vue components created with the <code><a href=\"https:\/\/vuejs.org\/v2\/api\/#Vue-component\" rel=\"noopener\" target=\"_blank\">Vue.component<\/a><\/code> syntax that use in-DOM templates or JavaScript template strings. However, to build the Search app in WordPress, I&#8217;ve made use of Vue&#8217;s powerful <a href=\"https:\/\/vuejs.org\/v2\/guide\/single-file-components.html#Introduction\" rel=\"noopener\" target=\"_blank\">single-file components<\/a> instead.<\/p>\n<p>Single-file components have many inherent advantages &#8211; the ability to provide <a href=\"https:\/\/vuejs.org\/v2\/guide\/deployment.html#Pre-Compiling-Templates\" rel=\"noopener\" target=\"_blank\">pre-compiled JavaScript<\/a> (render functions) to the browser, syntax highlighting, case-insensitive component selectors, and <a href=\"https:\/\/vue-loader.vuejs.org\/guide\/scoped-css.html\" rel=\"noopener\" target=\"_blank\">component-scoped CSS<\/a> to name a few. They also allow me to write modular and manageable code by splitting the codebase into multiple (.Vue) files.<\/p>\n<p>Now that you have a fair idea of how things work, let&#8217;s start building the app.<\/p>\n<h2 id=\"using-wpcli\">Using Vue-CLI to Set Up a Local Development Workflow<\/h2>\n<p>Splitting the code into multiple (.Vue) files with single-file components will require the use of development tools like Vue Loader, Webpack, Babel etc. However, don&#8217;t let this throw you off as I&#8217;m going to keep things very simple and not deal with configuration files.<\/p>\n<p>With the <a href=\"https:\/\/github.com\/vuejs\/vue-cli\" rel=\"noopener\" target=\"_blank\">Vue-CLI<\/a> you can quickly scaffold a Vue app that&#8217;s pre-configured with the best build tools for a modern frontend workflow. So, let&#8217;s set up the CLI first.<\/p>\n<h3>Step 1: Install Node.js<\/h3>\n<p>To use the Vue-CLI, you&#8217;ll require <a href=\"https:\/\/nodejs.org\/en\/\" rel=\"noopener\" target=\"_blank\"> Node.js<\/a> ( 8.x preferred, npm version 3+) installed on your system. You can download the installer for your platform from the <a href=\"https:\/\/nodejs.org\/en\/download\/\" rel=\"noopener\" target=\"_blank\">Node.js downloads page here<\/a>. Once you&#8217;ve set that up, test that the following commands work:<\/p>\n<ul>\n<li><code>node --version<\/code> and <code>npm --version<\/code><\/li>\n<\/ul>\n<h3>Step 2: Install Vue-CLI<\/h3>\n<p>Next, open your system&#8217;s terminal (PowerShell in my case), and install the Vue-CLI (2.x) globally by running the <code>npm install -g vue-cli<\/code> command. Once complete, test that it works by running the <code>vue --version<\/code> command.<\/p>\n<div  class=\"wpdui-pic-regular  \">\n<figure class=\"wp-caption alignnone\" data-caption=\"true\"><img loading=\"lazy\" decoding=\"async\" class=\"attachment-600x600\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2018\/05\/setting-up-vue-cli-2.png\" alt=\"setting up vue cli 2\" width=\"494\" height=\"569\" \/><figcaption class=\"wp-caption-text\">Setting up Vue-CLI (2.x) for creating Vue apps<\/figcaption><\/figure>\n<\/div>\n<p>In the image above, you&#8217;ll notice that I&#8217;ve also installed <code><a href=\"https:\/\/eslint.org\/docs\/user-guide\/getting-started\" rel=\"noopener\" target=\"_blank\">ESLint<\/a><\/code> globally with <code>npm install -g eslint<\/code>. This is because I use the <code><a href=\"https:\/\/code.visualstudio.com\/\" rel=\"noopener\" target=\"_blank\">Visual Studio Code<\/a><\/code> editor and its plugins to format and lint my JavaScript. You can use any code editor of your choice but configuring one with a JavaScript linter is highly recommended.<\/p>\n<p>With the basic setup done, let&#8217;s create an app in WordPress with the Vue-CLI.<\/p>\n<h2 id=\"scaffolding\">Scaffolding a Vue app with Vue-CLI<\/h2>\n<p>To create the Vue app, I&#8217;ve used the official <a href=\"https:\/\/github.com\/vuejs-templates\/webpack-simple\" rel=\"noopener\" target=\"_blank\">webpack-simple<\/a> vuejs-template. However, you may want to use a more sophisticated template based on your requirements.<\/p>\n<p>The template sets up a Vue project with Webpack and configures it with a development server and other modern build tools. This provides us with an elaborate development workflow. Among other things, it allows us to write code using NextGen (ES6\/ES7) JavaScript during development, but ship the compiled JavaScript bundle in ES5 for better browser compatibility.<\/p>\n<h3>Step 1: Set up the Vue app inside WordPress<\/h3>\n<p>To set up the Vue project, navigate to your WordPress theme or child theme using your system&#8217;s terminal. Here, I am using PowerShell (in Windows 10) integrated with the Visual Studio Code editor.<\/p>\n<div  class=\"wpdui-pic-regular  \">\n<figure class=\"wp-caption alignnone\" data-caption=\"true\"><img loading=\"lazy\" decoding=\"async\" class=\"attachment-600x600\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2018\/05\/navigate-to-wordpress-theme.png\" alt=\"navigate to wordpress theme\" width=\"515\" height=\"302\" \/><figcaption class=\"wp-caption-text\">Navigate to the directory of your WordPress theme<\/figcaption><\/figure>\n<\/div>\n<h3>Step 2: Create a Vue app with the Webpack-Simple template<\/h3>\n<p>Next, run the command <code>vue init webpack-simple project-name<\/code>, substituting <code>project-name<\/code> with the name of your project (spa in my example), and follow the on-screen instructions.<\/p>\n<div  class=\"wpdui-pic-regular  \">\n<figure class=\"wp-caption alignnone\" data-caption=\"true\"><img loading=\"lazy\" decoding=\"async\" class=\"attachment-600x600\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2018\/05\/scaffolding-with-vue-init.png\" alt=\"vue app with vue init and webpack template\" width=\"600\" height=\"442\" \/><figcaption class=\"wp-caption-text\">Scaffolding a Vue app with vue init and a Webpack template<\/figcaption><\/figure>\n<\/div>\n<p>Note: Skip this step if you&#8217;re following along with <a href=\"https:\/\/github.com\/nuancedesignstudio\/wordpress-vuejs-search\" rel=\"noopener\" target=\"_blank\">my vuetwentyseventeen child theme<\/a>. It already contains the app in the <code>spa<\/code> project folder.<\/p>\n<p>This creates the Vue project inside the <code>&lt;project-name&gt;<\/code> directory with configurations for modern build tools.<\/p>\n<h3>Step 3: Install Development Dependencies<\/h3>\n<p>If you head over to your WordPress theme using your code editor, and look inside the newly created project folder, among the many new files, you&#8217;ll notice a file called <code>package.json<\/code>. It basically lists all the development tools that the app will require. These tools still need to be installed though, and to do so, run the following:<\/p>\n<ul>\n<li><code>cd project-name<\/code>(substitue <em>project-name<\/em> with your project-folder)<\/li>\n<li><code>npm install<\/code><\/li>\n<\/ul>\n<p><a href=\"https:\/\/www.npmjs.com\/\" rel=\"noopener\" target=\"_blank\">NPM<\/a> will then download and install all the required dependencies in a folder called <code>node_modules<\/code><\/p>\n<div  class=\"wpdui-pic-regular  \">\n<figure class=\"wp-caption alignnone\" data-caption=\"true\"><img loading=\"lazy\" decoding=\"async\" class=\"attachment-600x600\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2018\/05\/installing-dev-dependencies.png\" alt=\"installing dev dependencies\" width=\"600\" height=\"167\" \/><figcaption class=\"wp-caption-text\">Installing development dependencies with NPM<\/figcaption><\/figure>\n<\/div>\n<p>Note that we won&#8217;t be deploying any of these downloaded files in WordPress. They are only required during the development phase.<\/p>\n<h3>Step 4: Run the Webpack Dev Server alongside WordPress<\/h3>\n<p>The final step involves running the Webpack development server that was installed in the previous step. It may seem strange at first, but you have to run the development server (installed in the previous step), and keep it running along with your local WordPress server (XAMP, WAMP, VVV etc.).<\/p>\n<p>Even though the Vue SPA is a client-side application, it initially needs to be served by a server, and the Webpack server will do this for us. Only when development is complete, will we serve the final JavaScript bundle through WordPress.<\/p>\n<p>To start the development server, run the command <code>npm run dev<\/code> from the Vue project folder. You will then see the starter Vue app automatically open at <code>localhost:8080<\/code> in your browser.<\/p>\n<div  class=\"wpdui-pic-regular  \">\n<figure class=\"wp-caption alignnone\" data-caption=\"true\"><img loading=\"lazy\" decoding=\"async\" class=\"attachment-600x600\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2018\/05\/running-development-server-600x600.png\" alt=\"running webpack development server\" width=\"600\" height=\"600\" \/><figcaption class=\"wp-caption-text\">Running the Webpack development server<\/figcaption><\/figure>\n<\/div>\n<h3>The Vue Bundle (build.js)<\/h3>\n<p>If you look at the page source of the starter app in your browser, you&#8217;ll notice that the page contains only a single script file &#8211; <code>build.js<\/code>. This is because when you ran the development server, Webpack <a href=\"https:\/\/vuejs.org\/v2\/guide\/installation.html#Development-vs-Production-Mode\" rel=\"noopener\" target=\"_blank\">automatically compiled<\/a> the Vue app and bundled it with the Vue library, and any other dependencies into a single JavaScript file.<\/p>\n<p>However, do note that the file does not physically exist on your system, and is dynamically generated by Node and Webpack at runtime.<\/p>\n<div  class=\"wpdui-pic-regular  \">\n<figure class=\"wp-caption alignnone\" data-caption=\"true\"><img loading=\"lazy\" decoding=\"async\" class=\"attachment-600x600\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2018\/05\/in-memory-javascript-bundle-generated-by-webpack.png\" alt=\"in memory javascript bundle generated by webpack\" width=\"600\" height=\"448\" \/><figcaption class=\"wp-caption-text\">The JavaScript bundle dynamically generated at runtime by Webpack<\/figcaption><\/figure>\n<\/div>\n<p>To generate a physical build file that you can ship with your app, you have to run <code>npm run build<\/code>, which we will see at a later stage.<\/p>\n<p>At this stage, we have a fully functional Vue app served by a development server from inside the WordPress theme folder. However, it has nothing to do with WordPress yet. So, let&#8217;s look at how you can integrate the Vue app with your WordPress theme.<\/p>\n<h2 id=\"integrating\">Integrating the Vue SPA with WordPress<\/h2>\n<p>Integrating the Vue app with WordPress essentially requires three things:<\/p>\n<ul>\n<li>A DOM element in WordPress for the Vue app to mount on<\/li>\n<li>Enqueueing the Vue bundle in WordPress<\/li>\n<li>Informing Vue about the DOM mount point in WordPress<\/li>\n<\/ul>\n<h3>Providing the DOM Element in WordPress for Vue<\/h3>\n<p>You may want to hook the Vue app on a single WordPress page or multiple pages, or conditionally. All Vue needs is a DOM element that exists on your WordPress page of choice.<\/p>\n<p>For this, you can make use of the WordPress <code><a href=\"https:\/\/developer.wordpress.org\/themes\/basics\/template-hierarchy\/#visual-overview\" rel=\"noopener\" target=\"_blank\">Template Hierarchy<\/a><\/code> to decide the necessary template file that needs to be edited. In my example, I want the Search app to appear on any WordPress page that uses a specific Custom Page Template. You may instead want to use regular <a href=\"https:\/\/developer.wordpress.org\/themes\/template-files-section\/page-template-files\/\" rel=\"noopener\" target=\"_blank\">Page Templates<\/a> to target specific pages based on your requirements.<\/p>\n<p>The Custom Page Template <code>templates\/vue-search-app-template.php<\/code> of my example child theme provides the DOM element, <code>#wp-vue-app<\/code> for Vue.<\/p>\n<div class=\"gist\" data-gist=\"fc6ec65077819aad1a33615eec47ddf9\" data-gist-file=\"vue-search-app-template.php\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/fc6ec65077819aad1a33615eec47ddf9.js?file=vue-search-app-template.php\">Loading gist fc6ec65077819aad1a33615eec47ddf9<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div>\n<h3>Registering the Vue App in WordPress<\/h3>\n<p>To let WordPress know about the Vue app, you have to <a href=\"https:\/\/developer.wordpress.org\/reference\/functions\/wp_enqueue_script\/\" rel=\"noopener\" target=\"_blank\">register\/enqueue<\/a> the Vue bundle in WordPress. However, it is not feasible to generate a build file after every modification during development. For this, we can take advantage of the dynamic build that you saw earlier.<\/p>\n<p>For as long as the Webpack development server is running, we can use the dynamic build path <code>http:\/\/localhost:8080\/dist\/build.js<\/code> to register the Vue script in WordPress.<\/p>\n<p>The Webpack server will also automatically re-compile the Vue bundle and <a href=\"https:\/\/webpack.js.org\/guides\/hot-module-replacement\/\" rel=\"noopener\" target=\"_blank\">update the page<\/a> as the app is modified.<\/p>\n<div  class=\"wpdui-pic-regular  \">\n<figure class=\"wp-caption alignnone\" data-caption=\"true\"><img loading=\"lazy\" decoding=\"async\" class=\"attachment-600x600\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2018\/05\/npm-run-dev.png\" alt=\"register dynamic build during development script\" width=\"511\" height=\"244\" \/><figcaption class=\"wp-caption-text\">Registering the dynamic build path in WordPress during development<\/figcaption><\/figure>\n<\/div>\n<p>This is the reason you have to run both the local WordPress server and the Webpack server during your development. When development is complete, you will have to modify the path to reflect the physical file that&#8217;s generated by running <code>npm run build<\/code>.<\/p>\n<div  class=\"wpdui-pic-regular  \">\n<figure class=\"wp-caption alignnone\" data-caption=\"true\"><img loading=\"lazy\" decoding=\"async\" class=\"attachment-600x600\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2018\/05\/npm-run-build.png\" alt=\"register build after development script\" width=\"514\" height=\"246\" \/><figcaption class=\"wp-caption-text\">Registering the physical build file in WordPress after development<\/figcaption><\/figure>\n<\/div>\n<p>Also note, except for the final Vue bundle, none of the files in the Vue project folder needs to be shipped with your WordPress theme. They are required only during development, and when you have to make modifications to regenerate the Vue bundle.<\/p>\n<p>In my theme example, I&#8217;ve registered the Vue bundle in the <code>includes\/enqueue-scripts.php<\/code><\/p>\n<div class=\"gist\" data-gist=\"e786b9c302896b22ee4001a8d57aa02c\" data-gist-file=\"enqueue-scripts.php\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/e786b9c302896b22ee4001a8d57aa02c.js?file=enqueue-scripts.php\">Loading gist e786b9c302896b22ee4001a8d57aa02c<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div>\n<h3>Informing Vue About the Mount Point in WordPress<\/h3>\n<p>Finally, to load the Vue app in WordPress, all that is required is to tell Vue where to mount itself. This is done by specifying the WordPress DOM element with the <code><a href=\"https:\/\/vuejs.org\/v2\/api\/#el\" rel=\"noopener\" target=\"_blank\">el<\/a><\/code> option in <code>main.js<\/code> of your Vue project. Alternatively, you can also use the <code><a href=\"https:\/\/vuejs.org\/v2\/api\/#vm-mount\" rel=\"noopener\" target=\"_blank\">$mount<\/a><\/code> method instead.<\/p>\n<p>In my example, I mount the app on the <code>#wp-vue-app<\/code> DIV container of my Custom Page Template.<\/p>\n<div  class=\"wpdui-pic-regular  \">\n<figure class=\"wp-caption alignnone\" data-caption=\"true\"><img loading=\"lazy\" decoding=\"async\" class=\"attachment-600x600\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2018\/05\/specifying-mount-point-in-vue.png\" alt=\"specifying the mount point in vue\" width=\"553\" height=\"249\" \/><figcaption class=\"wp-caption-text\">Specifying the mount point in Vue using the &#8216;el&#8217; option<\/figcaption><\/figure>\n<\/div>\n<p>And just like that, the starter Vue app will be rendered in WordPress.<\/p>\n<div  class=\"wpdui-pic-regular  \">\n<figure class=\"wp-caption alignnone\" data-caption=\"true\"><img loading=\"lazy\" decoding=\"async\" class=\"attachment-600x600\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2018\/05\/injecting-vue-in-wordpress-600x600.png\" alt=\"injecting vue in wordpress\" width=\"600\" height=\"600\" \/><figcaption class=\"wp-caption-text\">Rendering the starter Vue app in WordPress<\/figcaption><\/figure>\n<\/div>\n<p>Great, with the Vue starter app successfully injected into WordPress, you can now build pretty much anything with Vue. So, let&#8217;s get into the details of my Vue Search app.<\/p>\n<h2 id=\"building-wordpress\">Building the Single Page Search App in WordPress<\/h2>\n<p>If you look at the <a href=\"#vue-spa-overview\">flowchart in the beginning of the article<\/a>, you&#8217;ll be able to relate to the final Search app shown below:<\/p>\n<div  class=\"wpdui-pic-regular  \">\n<figure class=\"wp-caption alignnone\" data-caption=\"true\"><img loading=\"lazy\" decoding=\"async\" class=\"attachment-600x600\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2018\/05\/vue-search-app-wordpress.png\" alt=\"vue search app wordpress\" width=\"525\" height=\"597\" \/><figcaption class=\"wp-caption-text\">Building a Vue Search App in WordPress<\/figcaption><\/figure>\n<\/div>\n<h3>The Project Folder Structure<\/h3>\n<p>To build this, I simply used the Vue starter app as a base. I got rid of <code>spa\/index.html<\/code> and <code>src\/assets<\/code> from the Vue project, and arrived at the following folder structure:<\/p>\n<div  class=\"wpdui-pic-regular  \">\n<figure class=\"wp-caption alignnone\" data-caption=\"true\"><img loading=\"lazy\" decoding=\"async\" class=\"attachment-600x600\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2018\/05\/vue-folder-structure-in-wordpress-600x600.png\" alt=\"vue folder structure in wordpress\" width=\"600\" height=\"600\" \/><figcaption class=\"wp-caption-text\">Folder structure of the Vue Search app in WordPress<\/figcaption><\/figure>\n<\/div>\n<p>If you&#8217;re wondering about the <code>includes<\/code> folder in the child theme, it&#8217;s because I use <code>functions.php<\/code> only to specify the <code><a href=\"https:\/\/developer.wordpress.org\/reference\/hooks\/\" rel=\"noopener\" target=\"_blank\">WordPress Hooks<\/a><\/code>, and define the respective callbacks in individual PHP files under <code>includes\/<\/code>. I prefer this approach to dumping everything in a single <code>functions.php<\/code> file.<\/p>\n<div class=\"gist\" data-gist=\"cf0d04aa7e77a50d479beedb25d4e650\" data-gist-file=\"functions.php\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/cf0d04aa7e77a50d479beedb25d4e650.js?file=functions.php\">Loading gist cf0d04aa7e77a50d479beedb25d4e650<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div>\n<h3>Adding Additional Dependencies for ESLint and ECMAScriptNext Features (Optional)<\/h3>\n<p>If you intend to use ESLint (which I highly recommend) or ESNext features like Async\/Await, you&#8217;ll have to add some additional development packages to your project.<\/p>\n<h4>Configuring ESLint for WordPress and Vue<\/h4>\n<p>To configure ESLint, I&#8217;ve installed the <code><a href=\"https:\/\/github.com\/vuejs\/eslint-plugin-vue\" rel=\"noopener\" target=\"_blank\">eslint-plugin-vue<\/a><\/code> plugin and the <code><a href=\"https:\/\/github.com\/WordPress-Coding-Standards\/eslint-config-wordpress\" rel=\"noopener\" target=\"_blank\">eslint-config-wordpress<\/a><\/code> configuration. To do this, stop the development server (Ctrl+C), and run the following from inside your Vue project folder:<br \/>\n<code> npm install --save-dev eslint eslint-plugin-vue <\/code><br \/>\n<code> npm install --save-dev eslint-config-wordpress <\/code><\/p>\n<p>Next, add the following to your <code><a href=\"https:\/\/eslint.org\/docs\/user-guide\/configuring\" rel=\"noopener\" target=\"_blank\">.eslintrc.json<\/a><\/code> file:<br \/>\n<code>\"extends\": [\"eslint:recommended\", \"wordpress\", \"plugin:vue\/recommended\"]<\/code><\/p>\n<p>This will setup the <a href=\"https:\/\/make.wordpress.org\/core\/handbook\/best-practices\/coding-standards\/javascript\/\" rel=\"noopener\" target=\"_blank\">JavaScript Coding Standards<\/a> for WordPress, and the <code><a href=\"https:\/\/github.com\/vuejs\/eslint-plugin-vue#gear-configs\" rel=\"noopener\" target=\"_blank\">vue\/strongly-recommended<\/a><\/code> pre-defined linting rules for Vue. With modern editors like VS Code, this immensely helps me to catch and fix errors on the fly:<\/p>\n<div  class=\"wpdui-pic-regular  \">\n<figure class=\"wp-caption alignnone\" data-caption=\"true\"><img loading=\"lazy\" decoding=\"async\" class=\"attachment-600x600\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2018\/05\/configuring-eslint-for-vue-wordpress.png\" alt=\"configuring eslint for vue wordpress\" width=\"548\" height=\"402\" \/><figcaption class=\"wp-caption-text\">Catching errors with ESLint in Visual Studio Code<\/figcaption><\/figure>\n<\/div>\n<h4>Adding Babel Presets for Async\/Await<\/h4>\n<p>Babel presets are out of the scope of this article, but the following will basically allow you to use ES7 Async\/Await in your Vue app. For this, you have to add <code><a href=\"https:\/\/github.com\/vuejs\/babel-preset-vue-app\" rel=\"noopener\" target=\"_blank\">babel-preset-vue-app<\/a><\/code> by running:<br \/>\n<code> npm install --save-dev babel-preset-vue-app <\/code><\/p>\n<p>Then, add the preset <code>vue-app<\/code> to the <code>.babelrc<\/code> file in your Vue project folder:<br \/>\n<code> \"presets\": [[\"env\", { \"modules\": false }], \"stage-3\", \"vue-app\"] <\/code><\/p>\n<p>When you&#8217;re done, don&#8217;t forget to start the development server with <code>npm run dev<\/code>. My example Vue child theme has all of this already configured for you, so you only need to install the packages by running <code>npm install<\/code> from within the <code>spa<\/code> directory.<\/p>\n<h3>Making Local WordPress Data Available to Vue<\/h3>\n<p>Vue is ultimately JavaScript that runs in your browser, and so, it won&#8217;t have access to any data in WordPress. To make local WordPress data available to the Vue app, you&#8217;ll have to use the good old <code><a href=\"https:\/\/developer.wordpress.org\/reference\/functions\/wp_localize_script\/\" rel=\"noopener\" target=\"_blank\">wp_localize_script<\/a><\/code> WordPress function.<\/p>\n<p>I&#8217;ve done this in the <code>includes\/enqueue-scripts.php<\/code> of my <code>vuetwentyseventeen<\/code> child theme.<\/p>\n<div class=\"gist\" data-gist=\"3160a325086acd89fc39fcc56685df4a\" data-gist-file=\"enqueue-scripts.php\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/3160a325086acd89fc39fcc56685df4a.js?file=enqueue-scripts.php\">Loading gist 3160a325086acd89fc39fcc56685df4a<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div>\n<p>The gist above should be pretty self-explanatory with all my comments, so I&#8217;ll instead focus on the data that I&#8217;ve made available to my Vue app:<\/p>\n<ul>\n<li><code>wpData.template_directory_uri<\/code> &#8211; to build the file path for static assets (like images) in the theme folder<\/li>\n<li><code>wpData.rest_url<\/code> &#8211; URL to retrieve posts from the WP REST API<\/li>\n<li><code>wpData.app_path<\/code> &#8211; the SPA WordPress page to build relative links<\/li>\n<li><code>wpData.post_categories<\/code> &#8211; to render checkboxes for filtering posts<\/li>\n<\/ul>\n<p>With this out of the way, let&#8217;s finally explore the single-file components of the Search app.<\/p>\n<h2 id=\"building-vue\">Building the Search App with Vue Single-File Components<\/h2>\n<p>With the <a href=\"#vue-spa-overview\">Search app structure<\/a> chalked out, the first component that I actually built was the <code>AppDisplayComponent<\/code>. I started off with a very basic component to display only post titles using the JavaScript <code><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Fetch_API\/Using_Fetch\" rel=\"noopener\" target=\"_blank\">Fetch API<\/a><\/code>and the WordPress <code><a href=\"https:\/\/developer.wordpress.org\/rest-api\/reference\/#rest-api-developer-endpoint-reference\" rel=\"noopener\" target=\"_blank\">Posts resource<\/a><\/code> &#8211; <code>\/wp\/v2\/posts<\/code>.<\/p>\n<h4>A Basic Version of the AppDisplayPost Component<\/h4>\n<div  class=\"wpdui-pic-regular  \">\n<figure class=\"wp-caption alignnone\" data-caption=\"true\"><img loading=\"lazy\" decoding=\"async\" class=\"attachment-600x600 size-600x600\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2018\/06\/basic-component-get-started-600x600.png\" alt=\"a basic component to get started\" width=\"600\" height=\"600\" \/><figcaption class=\"wp-caption-text\">A very basic version of the AppDisplayPost component to get started<\/figcaption><\/figure>\n<\/div>\n<p>And to render it on the WordPress page, I deleted all of the starter content in <code>App.vue<\/code>, and invoked the <code>AppDisplayPost<\/code> component as shown below:<\/p>\n<div  class=\"wpdui-pic-regular  \">\n<figure class=\"wp-caption alignnone\" data-caption=\"true\"><img loading=\"lazy\" decoding=\"async\" class=\"attachment-600x600\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2018\/06\/initial-app-component.png\" alt=\"initial version of app.vue component\" width=\"483\" height=\"490\" \/><figcaption class=\"wp-caption-text\">A very basic App.vue to render the AppDisplayPost Component<\/figcaption><\/figure>\n<\/div>\n<p>However, not everything worked on the first try (or even a few after that), which is when the Chrome extension of the <a href=\"https:\/\/github.com\/vuejs\/vue-devtools#installation\" rel=\"noopener\" target=\"_blank\">Vue DevTools<\/a> came to my rescue. I&#8217;d suggest you have it installed as well, as it will allow you to debug and inspect your Vue application with a more user-friendly interface rather than just logging everything to the console.<\/p>\n<div  class=\"wpdui-pic-regular  \">\n<figure class=\"wp-caption alignnone\" data-caption=\"true\"><img loading=\"lazy\" decoding=\"async\" class=\"attachment-600x600\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2018\/06\/debugging-with-vue-devtools-600x600.png\" alt=\"debugging with vue devtools\" width=\"600\" height=\"600\" \/><figcaption class=\"wp-caption-text\">Debugging Vue applications with Vue Devtools<\/figcaption><\/figure>\n<\/div>\n<p>I&#8217;d also recommend that you use a tool like <code><a href=\"https:\/\/www.getpostman.com\/apps\" rel=\"noopener\" target=\"_blank\">Postman<\/a><\/code> to interact with the WP REST API. It&#8217;ll save you a lot of time understanding the API response, and provides the data in a format that&#8217;s much easier to view. This is what I mean:<\/p>\n<div  class=\"wpdui-pic-regular  \">\n<figure class=\"wp-caption alignnone\" data-caption=\"true\"><img loading=\"lazy\" decoding=\"async\" class=\"attachment-600x600\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2018\/06\/using-postman-with-wp-rest-api.png\" alt=\"rest client postman interacting with wordpress rest api\" width=\"487\" height=\"332\" \/><figcaption class=\"wp-caption-text\">Using a REST client like Postman to interact with the WordPress REST API<\/figcaption><\/figure>\n<\/div>\n<p>Rendering posts from WordPress in the Vue app did take me a while to set up initially, but after a few rounds between the Vue DevTools and Postman, I was good to go. At this point, I also decided to extend the API response to add custom content.<\/p>\n<h4>Extending the WordPress REST API for Custom Content<\/h4>\n<p>The default response from the REST API is pretty comprehensive; however, it&#8217;s likely that it may not satisfy all your requirements.<\/p>\n<p>For example, you may want to display information such as the author name, comments and the featured image of a post. If you make a <code><a href=\"https:\/\/developer.wordpress.org\/rest-api\/extending-the-rest-api\/glossary\/#resource\" rel=\"noopener\" target=\"_blank\">GET request to the posts route<\/a><\/code> in Postman (or your preferred REST client), you&#8217;ll notice that these are not directly available in the default response. While extending the API is an option here, you can also retrieve these by simply adding the <code><a href=\"https:\/\/developer.wordpress.org\/rest-api\/using-the-rest-api\/global-parameters\/#_embed\" rel=\"noopener\" target=\"_blank\">_embed=true<\/a><\/code> parameter to the resource &#8211; <code>wp\/v2\/posts?_embed=true<\/code>. With <code><a href=\"https:\/\/developer.wordpress.org\/rest-api\/using-the-rest-api\/linking-and-embedding\/#embedding\" rel=\"noopener\" target=\"_blank\">_embed<\/a><\/code>, the API will collate all metadata marked with <code>embeddable: true<\/code> in the post response.<\/p>\n<p>For my Vue Search app, I decided to extend the API instead, and added the following custom content:<\/p>\n<div  class=\"wpdui-pic-regular  \">\n<figure class=\"wp-caption alignnone\" data-caption=\"true\"><img loading=\"lazy\" decoding=\"async\" class=\"attachment-600x600\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2018\/06\/extending-wordpress-rest-api.png\" alt=\"extending the wordpress rest api\" width=\"557\" height=\"360\" \/><figcaption class=\"wp-caption-text\">Extending the default response of the WordPress REST API<\/figcaption><\/figure>\n<\/div>\n<p>If you look at the final version of the <code>AppDisplayPost<\/code> component in my child theme, you&#8217;ll notice that I&#8217;ve used a field <code>vue_meta<\/code> which is not part of the default response. It was added with the <code><a href=\"https:\/\/developer.wordpress.org\/reference\/functions\/register_rest_field\/\" rel=\"noopener\" target=\"_blank\">register_rest_field<\/a><\/code> function in <code>includes\/extend-api.php<\/code> of the child theme. The code in there is fairly basic, and to know more about extending the API, take a look at the <code><a href=\"https:\/\/developer.wordpress.org\/rest-api\/extending-the-rest-api\/modifying-responses\/\" rel=\"noopener\" target=\"_blank\">Modifying Reponses<\/a><\/code> section of the <code><a href=\"https:\/\/developer.wordpress.org\/rest-api\/\" rel=\"noopener\" target=\"_blank\">REST API Handbook<\/a><\/code>.<\/p>\n<p>With this, I then moved the logic for retrieving posts to the <code>AppGetPosts<\/code> component, and only used <code>AppDisplayPost<\/code> for rendering the required content of individual post items.<\/p>\n<h4>The AppGetPosts Component to Consume Data from the REST API<\/h4>\n<p>Separating the logic for data retrieval also meant passing the <code>Posts<\/code> array to <code>AppDisplayPosts<\/code> via <code><a href=\"https:\/\/vuejs.org\/v2\/guide\/components-props.html\" rel=\"noopener\" target=\"_blank\">props<\/a><\/code>.<\/p>\n<div class=\"gist\" data-gist=\"f325f3c11e7031247866eff6874fd69d\" data-gist-file=\"AppDisplayPost.vue\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/f325f3c11e7031247866eff6874fd69d.js?file=AppDisplayPost.vue\">Loading gist f325f3c11e7031247866eff6874fd69d<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div>\n<p>Then, in <code>AppGetPosts<\/code> I invoked <code>AppDisplayPost<\/code> for each post in the posts array.<\/p>\n<div class=\"gist\" data-gist=\"34a0c96a19385944b4a1c7b5ca83af32\" data-gist-file=\"AppGetPosts.vue\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/34a0c96a19385944b4a1c7b5ca83af32.js?file=AppGetPosts.vue\">Loading gist 34a0c96a19385944b4a1c7b5ca83af32<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div>\n<p>I also decided to use <code><a href=\"https:\/\/github.com\/axios\/axios\" rel=\"noopener\" target=\"_blank\">Axios<\/a><\/code> instead of the native Fetch API to retrieve posts from the WordPress REST API. I&#8217;m more comfortable using <a href=\"https:\/\/vuejs.org\/v2\/cookbook\/using-axios-to-consume-apis.html\" rel=\"noopener\" target=\"_blank\">Axios to consume data from APIs<\/a> but you can also choose to use <code><a href=\"https:\/\/developer.wordpress.org\/reference\/functions\/wp_enqueue_script\/#default-scripts-included-and-registered-by-wordpress\" rel=\"noopener\" target=\"_blank\">jQuery<\/a><\/code> (which is already included in WordPress) to make <code><a href=\"http:\/\/api.jquery.com\/jquery.ajax\/\" rel=\"noopener\" target=\"_blank\">AJAX<\/a><\/code> calls.<\/p>\n<p>Note: To use Axios, you&#8217;ll have to <a href=\"https:\/\/github.com\/axios\/axios#installing\" rel=\"noopener\" target=\"_blank\">install it as a production dependency<\/a> by running <code>npm install axios<\/code> in your Vue project folder.<\/p>\n<h4>Retrieving only Specific Fields from the WordPress REST API<\/h4>\n<p>I recently discovered that you can use the <code><a href=\"https:\/\/make.wordpress.org\/core\/2018\/05\/09\/gutenberg-and-the-rest-api-early-may\/\" rel=\"noopener\" target=\"_blank\">_fields<\/a><\/code> parameter to <a href=\"https:\/\/core.trac.wordpress.org\/changeset\/41744\" rel=\"noopener\" target=\"_blank\">retrieve only the required fields<\/a> from the API response. This significantly reduces the payload size, especially when you don&#8217;t want the post content in the JSON response. To do this, simply add the <code>_fields<\/code> parameter with a comma-separated list of field-names as values &#8211; <code>wp\/v2\/posts?_fields=id,title,excerpt<\/code><\/p>\n<div  class=\"wpdui-pic-regular  \">\n<figure class=\"wp-caption alignnone\" data-caption=\"true\"><img loading=\"lazy\" decoding=\"async\" class=\"attachment-600x600\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2018\/06\/retrieve-specific-fields-rest-api.png\" alt=\"retrieve specific fields rest api\" width=\"528\" height=\"600\" \/><figcaption class=\"wp-caption-text\">Using the _fields parameter to selectively include fields in response JSON<\/figcaption><\/figure>\n<\/div>\n<p>The <code>_fields<\/code> parameter still needs to find its way into the REST API Handbook, so you might want to keep an eye on it.<\/p>\n<h4>Retrieving All Posts from the WordPress REST API<\/h4>\n<p>Currently, there is no way to retrieve all posts from the WordPress REST API. To do this, you&#8217;ll have to run a loop and make multiple requests to the API until the required data has been fetched.<\/p>\n<p>To calculate the number of API requests, I made use of the <a href=\"https:\/\/developer.wordpress.org\/rest-api\/using-the-rest-api\/pagination\/#pagination-parameters\" rel=\"noopener\" target=\"_blank\">Pagination Parameter<\/a> <code>per_page=100<\/code> and the <code>X-WP-Total<\/code> header field, which provides the total number of records in the collection. The <code>per_page<\/code> parameter is currently capped at at 100 records, which is why we need to make multiple requests to the API when there are more than 100 posts. You&#8217;ll see this in action in the <code>get_posts<\/code> method of the <code>AppGetPosts<\/code> component in the gist below:<\/p>\n<div class=\"gist\" data-gist=\"8b67f44c78687f9322ebebb31b697517\" data-gist-file=\"AppGetPosts.vue\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/8b67f44c78687f9322ebebb31b697517.js?file=AppGetPosts.vue\">Loading gist 8b67f44c78687f9322ebebb31b697517<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div>\n<p>In the gist above, <code>get_posts<\/code> is automatically invoked when the component is mounted. I&#8217;ve made use of the <code><a href=\"https:\/\/www.youtube.com\/watch?v=9YkUCxvaLEk\" rel=\"noopener\" target=\"_blank\">ES7 Async\/Await<\/a><\/code> feature to mark the method as an <code><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Statements\/async_function\" rel=\"noopener\" target=\"_blank\">aynchronous function <\/a><\/code> that contains <code>await<\/code> expressions.<\/p>\n<p>You&#8217;ll notice that the very first <code>Axios<\/code> request is marked with <code>await<\/code> &#8211;<br \/>\n<code>const response = await axios( ... ) <\/code>. This prevents the subsequent lines of code from executing until the request is resolved. I did this to retrieve the <code>x-wp-total<\/code> header to calculate the required number of API requests.<\/p>\n<p>The second usage of <code>await<\/code> is at the end, where it waits for all <code>Promises<\/code> to resolve with <code><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Promise\/all\" rel=\"noopener\" target=\"_blank\">Promise.all<\/a><\/code> before rendering the data on the page. However, you can also render data as soon as it&#8217;s available like this:<\/p>\n<div class=\"gist\" data-gist=\"9bb57f1b71e4f903a1bb512b4299a43a\" data-gist-file=\"get_posts.js\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/9bb57f1b71e4f903a1bb512b4299a43a.js?file=get_posts.js\">Loading gist 9bb57f1b71e4f903a1bb512b4299a43a<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div>\n<p>With the required data available, I then added the search input box and filter logic in a <a href=\"https:\/\/vuejs.org\/v2\/guide\/computed.html\" rel=\"noopener\" target=\"_blank\">computed property<\/a>. In the gist below, notice how <code>FilteredResults<\/code> replaced <code>wpPosts<\/code> to invoke the <code>AppDisplayPost<\/code> component.<\/p>\n<div class=\"gist\" data-gist=\"5f65b73b38e9f45bc34e0bca8cd3a446\" data-gist-file=\"AppGetPosts.vue\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/5f65b73b38e9f45bc34e0bca8cd3a446.js?file=AppGetPosts.vue\">Loading gist 5f65b73b38e9f45bc34e0bca8cd3a446<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div>\n<h4>The AppQuickSearch and AppFilterSwitches Components<\/h4>\n<p>With <code>AppGetPosts<\/code> nicely taking care of the data retrieval and filtering, I then moved the user input to the parent component <code>AppQuickSearch<\/code> and used props to pass the data down the chain.<\/p>\n<p>I created a new component <code>AppFilterSwitches<\/code> to render category filters using the localized WordPress <code>wpData<\/code> object. The component <code><a href=\"https:\/\/vuejs.org\/v2\/guide\/components.html#Emitting-a-Value-With-an-Event\" rel=\"noopener\" target=\"_blank\">emits<\/a><\/code> a custom event <code>onFilterToggle<\/code> that the parent component <code>AppQuickSearch<\/code> must listen to.<\/p>\n<p>Finally, all the components were amalgamated in <code>AppQuickSearch<\/code><\/p>\n<div class=\"gist\" data-gist=\"bf1f0e523d685910a115cad858c087b0\" data-gist-file=\"AppQuickSearch.vue\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/bf1f0e523d685910a115cad858c087b0.js?file=AppQuickSearch.vue\">Loading gist bf1f0e523d685910a115cad858c087b0<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div>\n<p>In the end, I simply enqueued the final build generated by running <code>npm run build<\/code>.<\/p>\n<div  class=\"wpdui-pic-regular  \">\n<figure class=\"wp-caption alignnone\" data-caption=\"true\"><img loading=\"lazy\" decoding=\"async\" class=\"attachment-600x600\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2018\/06\/genrating-final-app-build.png\" alt=\"generating final app build\" width=\"600\" height=\"561\" \/><figcaption class=\"wp-caption-text\">Generating the final build with npm run build<\/figcaption><\/figure>\n<\/div>\n<p>If you&#8217;ve come this far, you should feel comfortable exploring the rest of the app on your own. The final versions of the components do have a lot more but they are built on all that you just saw.<\/p>\n<h4>Exploring Routing and Keep-Alive Components<\/h4>\n<p>While I could have ended the app with just the quick search, I&#8217;ve added another component <code>AppCustomSearch<\/code> for you to explore <a href=\"https:\/\/vuejs.org\/v2\/guide\/routing.html\" rel=\"noopener\" target=\"_blank\">Vue routing<\/a>, and how the various components can be reused easily with the help of props.<\/p>\n<p>The <code><a href=\"https:\/\/router.vuejs.org\/\" rel=\"noopener\" target=\"_blank\">Vue Router<\/a><\/code> is beyond the scope of this article, but you can find the functionality for routing in <code>spa\/src\/app-routes.js<\/code>. It provides the mapping between the <code>AppQuickSearch<\/code>, <code>AppCustomSearch<\/code> and the navigation links. If you do end up using the Vue router on a WordPress page, just remember that Vue will use the <code><a href=\"https:\/\/router.vuejs.org\/guide\/essentials\/history-mode.html#html5-history-mode\" rel=\"noopener\" target=\"_blank\">URL '#'<\/a><\/code> to simulate a page, so that it doesn&#8217;t reload when you switch between the router links. If you try to exclude the hash (see my comments in <code>app-routes.js<\/code>), the <a href=\"https:\/\/codex.wordpress.org\/Function_Reference\/WP_Rewrite\" rel=\"noopener\" target=\"_blank\">WordPress Rewrite API<\/a> will take over, and you&#8217;ll end up with a 404 not found.<\/p>\n<p>The <code>App.vue<\/code> component hosts the <code>AppNavigation<\/code> and <code><a href=\"https:\/\/router.vuejs.org\/api\/#router-view\" rel=\"noopener\" target=\"_blank\">router-view<\/a><\/code> components. You&#8217;ll also notice that the <code>router-view<\/code> is wrapped with <code><a href=\"https:\/\/vuejs.org\/v2\/api\/#keep-alive\" rel=\"noopener\" target=\"_blank\">keep-alive<\/a><\/code> to preserve the component states and avoids re-rendering of the <code>AppQuickSearch<\/code> and <code>AppCustomSearch<\/code> when you switch between them.<\/p>\n<p>That&#8217;s it!<\/p>\n<h2>Summing Up<\/h2>\n<p>I hope you&#8217;ve found this article useful. Feel free to play around with my Vue Search app which you can <a href=\"https:\/\/github.com\/nuancedesignstudio\/wordpress-vuejs-search\" rel=\"noopener\" target=\"_blank\">download as part of the twenty-seventeen child theme here<\/a>. You can use it as a playground to practice and grow your skills in WordPress and modern JavaScript.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Power your WordPress application with Vue.js &#8211; the progressive JavaScript framework that now shares the stage with the likes of React and Angular. In this article, I&#8217;ll show you how to integrate a Single Page Search App within your existing WordPress application with Vue.js &#8211; an extremely popular JavaScript framework for developing rich user interfaces. [&hellip;]<\/p>\n","protected":false},"author":573954,"featured_media":201008,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"blog_reading_time":"","wds_primary_category":0,"wds_primary_tutorials_categories":0,"footnotes":""},"categories":[557,263],"tags":[10919,10425],"tutorials_categories":[],"class_list":["post-172043","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development","category-tutorials","tag-vue-js","tag-wordpress-rest-api"],"_links":{"self":[{"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/posts\/172043","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/users\/573954"}],"replies":[{"embeddable":true,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/comments?post=172043"}],"version-history":[{"count":545,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/posts\/172043\/revisions"}],"predecessor-version":[{"id":218416,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/posts\/172043\/revisions\/218416"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/media\/201008"}],"wp:attachment":[{"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/media?parent=172043"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/categories?post=172043"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/tags?post=172043"},{"taxonomy":"tutorials_categories","embeddable":true,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/tutorials_categories?post=172043"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}