Word Count: 1672
  • Post category:Codings
  • Post last modified:2024-08-17

Introduction

The vue-plugin-1 is a wordpress plugin template which uses the Vue JS framwork for generating the plugin admin pages in the backend. Another library Vite is used as the package bundler for development and production build.

This plugin generates one admin page and one admin sub-page. The sub-page also contains 2 tabs.

This plugin makes use of the WP REST API to add/change a record in the wp_options table in the database.

To avoid the ownerships and permissions complexity in Linux, the development is on the local PC using Laragon setup on the SSD drive named “KingstonSSD“.

Create PHP development environment

The envirnoment has thees files involved:

  • vue-plugin-1.php
    • constructor:
      • call admin_constants() in class DefineConstants for the plugin templates.
      • run the built-in register_activation_hook() to point to the method activate() method which will be run during plugin activation.
      • run the built-in register_deactivation_hook() to point to the method deactivation() which will be run during plugin deactivation. Currently deactivation is doing nothing.
      • at the plugins_loaded hook, run the init_others() method. The init_others() method is to instantiate all required classes one by one.
      • the static function init() creates a singletone instance of this class. This class is instantiated by the command Vue_plugin_1::init() at the last line of the file.
  • uninstall.php
    • WP executes this file when the plugin is being uninstalled.
    • remove the option “IvrVP1” from the wp_options table.
  • composer.json
    • define autoload of class files based on namespaces.
    • See “PHP – Autoload classes and non-classes files using Composer“.
    • Frequently used commands:
      • composer init –> create the file composer.json
      • composer dump-autoload –> create/update the vendor folder and the file autoload.php inside the folder.
  • /includes/Backend/Activate.php
    • WP executes this class file when the plugin is being activated.
    • check if the option “IvrVP1” exists, if not add this option to the wp_options table.
    • the subdirectory first character should be capitalised to conform to PSR-4.
  • /includes/Backend/CreateMenuPages.php
    • In the constructor
      • hook admin_menu is used to create the menu pages which covers the mount-point for the Vue app, the slugs for the menu pages, etc.
      • the slugs contain the ” #” sign in order to load different views for a single page application (SPA).
      • hook admin_enqueue_scripts is to register and enqueue the required scripts and style files. The URLs are pointed to the files generated by Vue in the /vueapp/dist/assets directory. The wp_locatlze_script function is used to pass PHP variables in an array to Vue.
      • filter script_loader_tag is used to add type="module" to the <script> tag of the above script. This is required to make the script acts as a javascript module.
  • /includes/Api/ApiEndPoints.php
    • this class extends the WP_REST_Controller class and defines the REST API endpoints.
    • In the constructor:
      • set the custom route with self-defined api namespace and base.
      • at the rest_api_init hook, runs the register_routes method.
    • the REST API namespace is “ivrvp1/v1“.
    • the REST API base is “settings“.
    • the complete API custom route is “http://hello.test/wp-json/ivrvp1/v1/settings”.
    • this route has 2 endpoints – (1) with method “WP_REST_Server::READABLE” which is equivalent to GET. (2) with method “WP_REST_Server::CREATABLE” which is equivalent to POST.
    • one of the register_rest_route arguments, the Permissoin Callback is run only after remote authentication is valid. The remote authentication can be done by passing a nonce to the server in the request header. The nonce is generated in CreateMenuPages.php and passed to JS via array $jsData using the wp_localize_script() function.

Create Vue JS development environment

  • activate the plugin.
  • create a vue app under the plugin root directory as per Reference 1.
    • under the plugin root directory, run npm create vite@latest vueapp -- --template vue
      • this will create the folder vueapp which is the root folder for the vue app.
    • Modify vite.config.js according to Reference 1.
      • the build.watch attribute makes the build process go into ‘watch’ state after building
      • build.rollupOptions.output removes the hash from the generated filenames during build, which is the default output. This way we can always enqueue the same filename in WordPress.
    • Modify package.json according to Ref. 1.
      • this enables the watch-after-build.
      • the --mode=dev makes vite build looks for a .env.dev file. In there we set the environment variable NODE_ENV to “development“. This way the build will be in development mode and you will still have the vue dev-tools working in your browser console.
    • Create a file named .env.dev under the vue project directory (i.e., vueapp) and add below line to the file.
      • NODE_ENV=development
    • To build the app for use by the plugin PHP, change directory to vueapp in the VS Code Terminal, then run following commands to create / update files in the /vueapp/dist directory.
      • npm install
      • npm run dev

Install Vue Router

  • at the vue root folder (vueapp), run npm install vue-router@4
  • edit package.json to add "vue-rounter": "^4.3.2" to both “dependencis” and “devDependencies“.

Vue app file structure

The directory /vueapp/src contains all the files and subdirectories for development.

  • file /vueapp/src/main.js – see below section.
  • file /vueapp/src/App.vue – the top level Single Page Application (SPA) template that will be loaded to the mount-point.
    • <router-view name="tab"> is to load the component named tab if it is defined in the components for the path.
    • <router-view> is to load the default component defined for the path.
  • file /vueapp/src/style.css – the css file for the whole app as it is unscoped.
  • directory /vueapp/src/assets – contains images, fonts and other assets.
  • directory /vueapp/src/components – are templates which will be called by the templates in /vueapp/src/views
  • directory /vueapp/src/composables – contains js scripts for functions to be reused in multiple views or components. Currently only the useFetch.js is used which is to GET an option value using the WP Rest API.
  • directory /vueapp/src/views – templates pointed by routes of router.

The master file: main.js

This file manages the operation of the vue app at the top level.

  • import the necessary functions from vue.
  • import components from directory views.
  • define the routes which maps the paths to the corresponding components for display.
  • create the router.
  • the command  createApp(App).use(router).mount("#vue-plugin-1-app") is to create the app using the template in App.vue, then apply the created router and mount the app to the mount point #vue-plugin-1-app.

Composable useFetch.js

  • composables are functions that can be reused by multiple components.
  • this javascript file with extension js makes use of the fetch() to access the API endpoint to GET an option value from the database table.
  • the fetch() sends the header X-WP-Nonce which contains the nonce for remote authentication. The nonce is generated in CreateMenuPages.php and passed to JS in array $jsData using the wp_localize_script() function.
  • note the use of 2 await in the try block. The first await is to wait for the hearder to arrive from the server and the second is to wait for the body stream completion. If the .then() approach is used, only one await is required.

Fetch & display data in ListAll.vue / ListData.vue

  • ListAll.vue has a Suspense block within which are the default template and fallback templete.
  • the default template loads the component ListData.vue. While waiting for the ListData, the fallback template displays the Loading... message.
  • ListData.vue calls the composable useFetch() which returns a Proxy object.
    • use isProxy() to check the returned result is a proxy.
    • use toRaw() to convert the proxy object to a real object.
  • note that if the component contains an await for a Promise to return, vue will not render the component and give a warning that the component should be in a Suspense boundary of the parent template. This is the reason for setting up the two views to call their own child in the /components directory.

Display and update data in AddNew.vue / DataForm.vue

  • AddNew.vue has a Suspense block within which are the default template and fallback templete.
  • the default template loads the child component DataForm.vue. While waiting for the form, the fallback template displays the Loading.... message.
  • the propose of isProxy() and toRaw() are same as the above section.

WordPress debug tips

It is possible to write message to the debug.log under the wp-content directory.

  • Enable the wp debug mode. Use the function error_log(print_r($var, true)) to log the variable to the debug.log.
  • When the print_r() second parameter is true, the function returns the result instead of printing it on screen.

Simulate fetch().catch (error)

The catch error is mainly on the network connection issue. This can be simulated by disabling the network adapter. WordPress is running on the local host without the need of network. The API endpoint is using HTTP protocal which requires network connection. The simulation is possible by disconnecting the network.

Downloads

The files downloaded from here are for development propose. For production plugin installation, all files and directories under /vueapp should be removed except the directory /vueapp/dist. The plugin files for various versions are also kept in MJ1900:\doc\projs\60-tf-practice\14-plugins-Dev\53-vue-plugin-1-template.

Click the links below to download different versions.

Reference

  1. Integrating Vue in a WordPress plugin – Michael Sperber
    • The pfd copy can be found in the plugin dev folder (60/14/53)
  2. YouTube- Load Vue.js in WordPress plugin [EASY GUIDE] by codingoblin
  3. How to use Vite with WordPress – Accreditly
  4. Good practices and Design Patterns for Vue ComposablesJakub Andrzejewski
  5. How JavaScript Promises Work – Nathan Sebhastian
  6. How to Use Async/Await in JavaScript – Nathan Sebhastian