Is there a way to automatically create Vue components using the data from custom fields in WordPress?

I am currently in the process of constructing a website using vue with nuxt, which involves loading data from a wordpress site via the rest api.

One of my goals is to empower the client to customize page templates using custom fields. As a result, I need to dynamically generate my vue templates with vue components that adjust based on the custom fields inserted within the wordpress page editor.

To illustrate this concept simply, if a client designs a page with three custom fields:

[custom-field type='hero']
[custom-field type='slider']
[custom-field type='testimonial']

I can extract the field information through the rest api in a json object structured like this:

page: {
  acf: [
    {field 1: {
      {type: 'hero'},
      {content: '...'} 
    },
    {field 2: {
      {type:'slider'},
      {content: '...'} 
    },
    {field 3: {
      {type:'testimonial'},
      {content: '...'} 
    }
  }
}

Subsequently, I will import this into my vue app and then require the template to generate dynamically from a grouping of potential components associated with the custom field types. The example above would produce:

<template>
  <Hero ... />
  <Slider ... />
  <Testimonial ... />
</template>

Would it be feasible to accomplish this by utilizing the v-is directive (https://v2.vuejs.org/v2/guide/components-dynamic-async.html) in this manner:

<component v-for="field in custom-fields" v-is="field.type" :data="field.data"/>? 

Is this approach achievable? Any guidance provided would be immensely valued.

Answer №1

Incorporating dynamic component registration and display in Nuxt can be a valuable feature, but it does come with its own set of challenges as well.

Approach 1 - Compatible with SSR & SSG

This approach facilitates the dynamic registration of components while preserving Server-Side Rendering/Static Site Generation functionality within Nuxt. The only downside is that you are required to specify the names and file paths of all potential imported components. Although manageable for specific use cases (especially when dealing with a limited number of ACF fields), creating an entire component library using this method might become laborious.

<template>
  <div>
    <div v-for="field in page.acf" :key="field.uniqueId">
      <component :is="field.type" :my-prop="field.content" />
    </div>
  </div>
</template>

<script>
export default {
  components: {
    hero: () => import('~/components/hero.vue'),
    slider: () => import('~/components/slider.vue'),
    testimonial: () => import('~/components/testimonial.vue')
  },
  data() {
    return {
      page: {
        acf: [
          {
            uniqueId: 1,
            type: 'hero',
            content: '...'
          },
          {
            uniqueId: 2,
            type: 'slider',
            content: '...'
          },
          {
            uniqueId: 3,
            type: 'testimonial',
            content: '...'
          }
        ]
      }
    }
  }
}
</script>

Approach 2 - Limited to Client-Side Rendering

This method empowers you to dynamically register component names and their respective file locations programmatically. While saving you from enumerating each individual component manually, this technique does not support SSR or SSG. However, it could be the preferred choice if your project follows a Single Page Application (SPA) paradigm.

<template>
  <div>
    <div v-for="field in page.acf" :key="field.uniqueId">
      <no-ssr>
        <component :is="field.type" :my-prop="field.content" />
      </no-ssr>
    </div>
  </div>
</template>

<script>
import Vue from 'vue'

export default {
  data() {
    return {
      page: {
        acf: [
          {
            uniqueId: 1,
            type: 'hero',
            content: '...'
          },
          {
            uniqueId: 2,
            type: 'slider',
            content: '...'
          },
          {
            uniqueId: 3,
            type: 'testimonial',
            content: '...'
          }
        ]
      }
    }
  },
  mounted() {
    const sections = this.page.acf
    for (let i = 0; i < sections.length; i++) {
      Vue.component(sections[i].type, () =>
        import(`~/components/${sections[i].type}.vue`)
      )
    }
  }
}
</script>

It's worth noting that the <no-ssr> tag is becoming deprecated, and if you're working with Nuxt versions above v2.9.0, you should consider using <client-only> instead.

Tips Regarding Your Query

  1. While I appreciate your attempt to streamline the data architecture, looping through your JSON object may pose a challenge due to the changing keys within each array object. Also, unnecessary objects in the data structure can complicate matters. I've restructured the data method to offer a simplified view for better comprehension.

  2. To effectively implement the v-for loop, ensure that the component is nested inside an HTML tag with a v-for attribute, as exemplified above.

  3. Consider sanitizing the data obtained from the WordPress API to prevent instances where WordPress provides a module that doesn't correspond to any existing component. Failing to align the supplied type with an actual component could disrupt the entire project build process.

I hope this clarifies things for you!

P.S. If anyone has insights on a methodology that enables setting component name and file location programmatically while still supporting SSG, I'd love to hear about it!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Failing to retrieve data from Ajax response

When handling requests in a servlet, the following code snippet processes the request received: Gson gson = new Gson(); JsonObject myObj = new JsonObject(); LoginBean loginInfo = getInfo(userId,userPwd); JsonElement loginObj = gson.toJsonTree(loginInfo) ...

Exploring different pages in an Ionic and AngularJS mobile application

I am brand new to the world of Ionic and AngularJS. I have just started working on a simple project but have hit a roadblock. My goal is, To create a login page and a register page. When a user clicks the register button on the login page, they should be ...

Determining the number of words in every line within a textarea

I am looking to determine the number of words per line in a textarea. The width of the textarea is variable. Check out this code snippet that calculates the number of rows: http://jsfiddle.net/2tcygj9e/ ...

Error encountered post Vue.use during installation using <script> tag

I must include vue-native-websocket using the following script tags: <script src="{% static 'js/vue.js' %}"></script> <script src="{% static 'js/vue-native-websocket.min.js' %}"></script> <script src="{ ...

Using Python to scrape the contents of a webpage that contains JavaScript, potentially utilizing the Selenium library

Looking to analyze the contents of a webpage that contains JavaScript. Any suggestions for a more efficient method than using Selenium? If not, when the page is loaded in a browser, it contains the following elements: <div class="js-container"> ...

What is the process for retrieving a static file from the current directory in Express?

I am having trouble accessing a static file from the same directory. The issue is that the image is not loading on the live server. app.use('/static',express.static('/public')) In the 'public' directory, I have created ' ...

Uploading multiple files via AJAX without any files being uploaded

I have been attempting to upload multiple files with just one AJAX request. However, I am encountering some issues, including: UPDATE No files are being successfully uploaded to the server It appears that multiple AJAX requests are being triggered due t ...

What steps can be taken to prevent "object Object" from displaying instead of the actual object?

I'm facing an issue with a JavaScript code that I can't seem to figure out. Here's the script in question: var proxyUrl = 'https://cors-anywhere.herokuapp.com/', targetUrl = 'https://api.darksky.net/forecast/[key]/[latitu ...

Local directory system for organizing users' files and folders

My website is built using mean-stack technology. I utilize the File System to create folders and write files on servers. Here is an example of the backend code: router.post('/httpOnly/mkdir', function (req, res, next) { var fs = require(&apo ...

Is there a way to add the store_id of the current v-for element to the apiUrl? Your assistance is greatly appreciated

<div v-for="store in order_stores"> <order-products-table :order_url="this.apiUrl + store.store_id"></order-products-table> </div> I am looking to combine the store_id from the current element with this.apiUrl. ...

What is the solution for fixing an error that says "There is no 'style' property on the 'Element' type"?

I'm struggling to fix an error in my JavaScript code. I created a script to display a tab indicator when a tab is clicked, but I keep getting the error message: "Property 'style' doesn't exist on type 'Element'". The tabs them ...

The JS file is being loaded successfully, however, the CSS file is not being loaded

While working on my local server environment, I encountered an issue where the js file in my `index.html` was loading, but the css file was not. After investigating in the `access_log` file, I discovered that the server was sending the css file with a 200 ...

React blogging site's administrative dashboard

https://i.sstatic.net/M6fUJ.png I am currently in the process of developing a blogging platform using MERN technology. Specifically, I am focused on creating a restful API with Node.js, Express, and MongoDB. The frontend, built with React, consists of thr ...

jQuery: add to either element

What is the most efficient way to use .appendTo for either one element or another based on their existence in the DOM? For instance, I would like to achieve the following: Preferred Method: .appendTo($('#div1') || $('#div2')); Less ...

Tips for interacting with the focused InputElement using a button

I am facing an issue with my custom JavaScript numpad input. I need to fill in two inputs but want the input to go to the InputElement only when focused. However, when using the button on my own numpad, the input is being entered into both inputs. How can ...

Updating user attributes as an administrator using the Cognito SDK

Currently, I am in the process of developing an Angular application and I aim to integrate authentication using AWS Cognito (my experience with AWS is fairly limited). So far, I have successfully incorporated features such as sign-up, sign-in, sign-out, MF ...

Challenges with Performance in IONIC Mobile Applications

Currently, we are in the final stages of developing a high-profile mobile application for one of our clients using the IONIC framework. The application performs well when accessed through a Web/Mobile Browser. However, once it is ported into a mobile appli ...

Guide on integrating Vuex into a Vue 2.6.14 project

Initially, I started working on a Vue project without using Vuex. However, upon realizing the necessity of Vuex for the project, I went ahead and added Vuex using npm. Subsequently, I populated a file named store.js with Vuex boilerplate code. Despite the ...

How can I set up automatic language selection for Google Translate's menu indexing feature?

My goal is to implement an automatic page translation feature using Google Translate's Library. I have been following the instructions provided in this link: The issue lies in the code snippet below, where the select menu creation works fine, but acc ...

How to create a gelatin-like effect on a rectangle using HTML5 canvas

Currently, I'm working on a platformer game project in JavaScript. The concept involves players as rectangles jumping on and off platforms. While the basic functionality is set up, I'm now aiming to incorporate a unique 'gelatine effect&apos ...