[Vuejs]-How do i dynamically generate vue components from wordpress custom fields

1👍

You can dynamically register and display components in Nuxt but there are some caveats.

Method 1 – SSR & SSG Support

This method will register your components dynamically and maintain the integrity of Server Side Rendering/Static Site Generation.

The only trade-off here is that you will need to list the names and file locations of all potential imported components. This shouldn’t be too cumbersome for your use-case (I don’t imagine you have too many ACF fields) but it could be a lengthy job if you’re intending to build an entire component library from it.

<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>

Method 2 – Client Side Only Rendering

This method allows you to programmatically register the component’s name and file location. This saves you from writing out each component one by one, but comes at the cost of no SSR or SSG support. However, this may be preferable if you’re going the SPA route.

<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>

Be aware that the <no-ssr> tag is being deprecated and if you are using Nuxt above v2.9.0, you should use <client-only> instead.

Notes On Your Question

  1. I understand you’ve tried to simplify your data architecture but your JSON object would be rather difficult to loop through since the key changes on each object in array. You’ve also got unnecessary objects in the data structure. I’ve simplified the structure in the data method so you can understand the concept.

  2. To get the v-for loop working, you need to nest the component inside a HTML tag that has a v-for attribute (as demonstrated above).

  3. You may want to sanitise the data you get from the WordPress API by ensuring that WordPress doesn’t supply you with a module that doesn’t correspond to a component. If the API supplies a type that doesn’t correspond to a component, the whole build will fail.

Hope this helps!

P.S If anyone knows of a method that allows you to programatically set the component name and component file location while maintaining SSG – please let me know!

Leave a comment