Dynamic Block Settings Panels with Vue and Gutenberg: A Deep Dive

WordPress Gutenberg’s block editor offers incredible flexibility, but its default settings panels can sometimes feel limited. For complex blocks requiring dynamic behavior and sophisticated UI elements, integrating Vue.js offers a powerful solution. This blog post will guide you through building dynamic block settings panels using Vue and Gutenberg, providing a comprehensive example with detailed explanations.

We’ll create a custom Gutenberg block that displays a list of items. The settings panel will allow users to:

  • Add new items: With a dynamic form that adds new input fields as needed.
  • Edit existing items: Modifying the text of each list item directly within the settings panel.
  • Delete items: Removing unwanted items from the list.
  • Select a list style: Choosing between different CSS classes to alter the list’s appearance.

This example goes beyond simple text input; it demonstrates managing an array of objects within the block’s attributes, highlighting the power of Vue’s reactivity and Gutenberg’s data handling capabilities.

1. Setting up the Development Environment:

Before we start, ensure you have Node.js and npm (or yarn) installed. We’ll use the @wordpress/scripts package to manage our Gutenberg block development.

npm install --global @wordpress/create-gutenberg-block

Create a new Gutenberg block:

wp create gutenberg-block dynamic-list-block

Navigate to the newly created block directory:

cd dynamic-list-block

Install Vue:

npm install vue

2. The Vue Component (src/components/vue-settings-panel.js):

This Vue component will handle the dynamic UI for our settings panel.

import Vue from 'vue';

Vue.component('dynamic-list-settings', {
  props: ['attributes', 'setAttributes'],
  data: function() {
    return {
      listItems: this.attributes.listItems || [],
      selectedStyle: this.attributes.listStyle || 'list-style-1',
      styles: [
        { value: 'list-style-1', label: 'Style 1' },
        { value: 'list-style-2', label: 'Style 2' },
        { value: 'list-style-3', label: 'Style 3' },
      ],
    };
  },
  watch: {
    listItems: {
      handler: function(newVal) {
        this.setAttributes({ listItems: newVal });
      },
      deep: true,
    },
    selectedStyle: {
      handler: function(newVal){
        this.setAttributes({listStyle: newVal});
      }
    }
  },
  methods: {
    addItem() {
      this.listItems.push({ text: '' });
    },
    removeItem(index) {
      this.listItems.splice(index, 1);
    },
  },
  template: `
    <div>
      <p>List Items:</p>
      <ul>
        <li v-for="(item, index) in listItems" :key="index">
          <input type="text" v-model="item.text">
          <button @click="removeItem(index)">Remove</button>
        </li>
      </ul>
      <button @click="addItem">Add Item</button>
      <p>Select List Style:</p>
      <select v-model="selectedStyle">
        <option v-for="style in styles" :key="style.value" :value="style.value">{{ style.label }}</option>
      </select>
    </div>
  `,
});

export default Vue;

This component utilizes Vue’s reactivity system. Changes to listItems and selectedStyle automatically update the block’s attributes through setAttributes, ensuring the data is synchronized with Gutenberg.

3. Integrating Vue into the Gutenberg Block (src/index.js):

We now need to integrate our Vue component into the Gutenberg block’s edit function.

import './style.scss';
import './editor.scss';
import icon from './icon';
import Vue from './components/vue-settings-panel';

const { __ } = wp.i18n;
const { registerBlockType } = wp.blocks;
const { InspectorControls } = wp.editor;
const { PanelBody, TextControl } = wp.components;

registerBlockType('dynamic-list-block/dynamic-list', {
    title: __('Dynamic List Block'),
    icon: icon,
    category: 'common',
    attributes: {
        listItems: {
            type: 'array',
            default: [],
        },
    listStyle: {
      type: 'string',
      default: 'list-style-1',
    }
    },
    edit: ({ attributes, setAttributes }) => {
        const app = new Vue({
            el: '#vue-app',
            data: {
                attributes: attributes,
                setAttributes: setAttributes,
            },
        });

        return (
            <div>
                <InspectorControls>
                    <PanelBody title="List Settings">
                        <div id="vue-app"></div>
                    </PanelBody>
                </InspectorControls>
                <ul className={attributes.listStyle}>
                    {attributes.listItems.map((item, index) => (
                        <li key={index}>{item.text}</li>
                    ))}
                </ul>
            </div>
        );
    },
    save: ({ attributes }) => {
        return (
            <ul className={attributes.listStyle}>
                {attributes.listItems.map((item, index) => (
                    <li key={index}>{item.text}</li>
                ))}
            </ul>
        );
    },
});

Crucially, we create a Vue instance within the edit function, mounting it to a div with the ID vue-app. We pass the attributes and setAttributes functions as data, allowing Vue to interact directly with Gutenberg’s data management system. The save function simply renders the list based on the attributes.

4. Styling (src/editor.scss and src/style.scss):

Add some basic styles to your src/editor.scss and src/style.scss files. For example:

// src/editor.scss
#vue-app {
  margin-bottom: 20px;
}
// src/style.scss
.list-style-1 {
  list-style-type: disc;
}

.list-style-2 {
  list-style-type: square;
}

.list-style-3 {
  list-style-type: circle;
}

5. Building and Running:

Compile your block using:

npm run build

Activate the block in your WordPress installation.

This comprehensive example showcases the power of combining Vue’s dynamic UI capabilities with Gutenberg’s block architecture. The use of watch within the Vue component ensures data synchronization, while the clear separation of concerns between the Vue component and the Gutenberg block code promotes maintainability and scalability. This approach can be extended to create significantly more complex and interactive block settings panels, enabling the creation of sophisticated and user-friendly WordPress blocks. Remember to adapt and extend this code to fit your specific needs and add error handling and more robust functionality as required. You can add features like validation, input sanitization, and more advanced UI elements to enhance your block’s capabilities. This detailed example provides a strong foundation for building dynamic and engaging Gutenberg blocks using Vue.js. Further exploration of Vue’s component system and Gutenberg’s API will allow you to create increasingly sophisticated and feature-rich WordPress blocks.

Leave a Reply

Your email address will not be published. Required fields are marked *

Trending