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