Building Dynamic Video Blocks with Vue and Gutenberg: A Comprehensive Guide

WordPress, with its Gutenberg editor, offers a flexible platform for content creation. However, its built-in functionalities sometimes fall short when it comes to complex, interactive elements. This is where integrating a JavaScript framework like Vue.js shines. This blog post will guide you through building a custom Gutenberg block that leverages Vue’s power to create a dynamic video embed experience, focusing on flexibility and user-friendliness. We’ll cover everything from setting up the development environment to deploying the final block.

Part 1: Project Setup and Dependencies

Before diving into the code, we need to establish a solid foundation. This involves setting up a development environment, installing necessary packages, and creating the basic structure for our Gutenberg block.

1.1 Setting up the development environment:

We’ll use npm (or yarn) for package management and Webpack for bundling. Make sure you have Node.js and npm installed on your system. Then, create a new directory for your project:

mkdir vue-gutenberg-video-block
cd vue-gutenberg-video-block
npm init -y

1.2 Installing Dependencies:

We’ll need several packages:

  • @wordpress/scripts: Provides build tools and utilities for Gutenberg block development.
  • vue: The core Vue.js library.
  • vue-loader: Enables Vue component compilation within Webpack.
  • @wordpress/element: Provides React components and utilities for integration with Gutenberg.
npm install @wordpress/scripts vue vue-loader @wordpress/element

1.3 Project Structure:

Create the following directory structure:

vue-gutenberg-video-block/
├── src/
│   ├── block.js     // Main block file
│   ├── components/ // Vue components
│   │   └── VideoEmbed.vue  // Vue component for video embed
│   └── editor.scss // SCSS for editor styles
├── build/           // Webpack output directory
└── package.json

Part 2: Creating the Vue Component (VideoEmbed.vue)

Let’s craft the VideoEmbed.vue component, the heart of our block. This component will handle video embedding, allowing users to specify the video URL and optionally control aspects like autoplay and looping.

<!-- src/components/VideoEmbed.vue -->
<template>
  <div class="vue-video-embed">
    <div v-if="error" class="error">{{ error }}</div>
    <iframe v-else-if="url" :src="iframeSrc" :allow="allowAttributes" :allowfullscreen="allowFullscreen" frameborder="0"></iframe>
    <div v-else class="placeholder">Enter a video URL</div>
  </div>
</template>

<script>
export default {
  name: 'VideoEmbed',
  props: {
    url: {
      type: String,
      required: true
    },
    autoplay: {
      type: Boolean,
      default: false
    },
    loop: {
      type: Boolean,
      default: false
    }
  },
  computed: {
    iframeSrc() {
      // Handle different video platforms (YouTube, Vimeo, etc.)
      if (this.url.includes('youtube')) {
        return this.url.includes('embed') ? this.url : this.url.replace('watch?v=', 'embed/');
      } else if (this.url.includes('vimeo')) {
        return `https://player.vimeo.com/video/${this.url.split('/').pop()}`;
      } else {
        this.error = "Unsupported video URL";
        return "";
      }
    },
    allowAttributes() {
      return "autoplay; encrypted-media; picture-in-picture";
    },
    allowFullscreen: true
  },
  data() {
    return {
      error: null
    };
  }
};
</script>
<style scoped>
.vue-video-embed {
  width: 100%;
  aspect-ratio: 16/9; /* Maintain aspect ratio */
  position: relative;
}

.vue-video-embed iframe {
  width: 100%;
  height: 100%;
}

.vue-video-embed .error {
  color: red;
}
.vue-video-embed .placeholder{
    text-align: center;
    font-style: italic;
}

</style>

This component dynamically renders an iframe based on the provided video URL. It handles YouTube and Vimeo URLs, and displays an error message if the URL is invalid or unsupported. You can extend this to support other platforms.

Part 3: Creating the Gutenberg Block (block.js)

Now, let’s build the Gutenberg block itself. This will handle the interaction with the Gutenberg editor, using the VideoEmbed Vue component.

// src/block.js
import { registerBlockType } from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';
import { useBlockProps, RichText, InspectorControls } from '@wordpress/block-editor';
import { PanelBody, TextControl, ToggleControl } from '@wordpress/components';
import VideoEmbed from './components/VideoEmbed.vue';
import Vue from 'vue';
import VueLoaderPlugin from 'vue-loader/lib/plugin';

const { createElement: h } = wp.element;

registerBlockType('my-plugin/vue-video-block', {
    title: __('Vue Video Block'),
    icon: 'video-alt3',
    category: 'common',
    attributes: {
        url: {
            type: 'string',
            default: '',
        },
        autoplay: {
            type: 'boolean',
            default: false,
        },
        loop: {
            type: 'boolean',
            default: false,
        },
    },

    edit: ({ attributes, setAttributes }) => {
        const { url, autoplay, loop } = attributes;
        const blockProps = useBlockProps();

        return [
            <InspectorControls>
                <PanelBody title="Video Settings">
                    <TextControl
                        label="Video URL"
                        value={url}
                        onChange={(value) => setAttributes({ url: value })}
                    />
                    <ToggleControl
                        label="Autoplay"
                        checked={autoplay}
                        onChange={(value) => setAttributes({ autoplay: value })}
                    />
                    <ToggleControl
                        label="Loop"
                        checked={loop}
                        onChange={(value) => setAttributes({ loop: value })}
                    />
                </PanelBody>
            </InspectorControls>,
            <div {...blockProps}>
                <VueWrapper url={url} autoplay={autoplay} loop={loop}/>
            </div>,
        ];
    },

    save: ({ attributes }) => {
        return (
            <div>
               <VideoEmbed :url={attributes.url} :autoplay={attributes.autoplay} :loop={attributes.loop}/>
            </div>
        );
    },
});

const VueWrapper = ({ url, autoplay, loop}) => {
  const [videoComponent, setVideoComponent] = wp.element.useState(null);
  wp.element.useEffect(() => {
    const component = new Vue({
      render: (h) => h(VideoEmbed, { props: { url, autoplay, loop } }),
    }).$mount();

    setVideoComponent(component.$el);

    return () => {
      component.$destroy();
    };
  }, [url, autoplay, loop]);
  return h('div', {dangerouslySetInnerHTML: {__html: videoComponent ? videoComponent.outerHTML : ''} });
};

This block defines the attributes (URL, autoplay, loop), provides an inspector panel for settings, and renders the VideoEmbed component both in the editor and on the frontend. Note the use of useBlockProps for proper Gutenberg integration and the handling of attributes. The VueWrapper component is crucial for integrating Vue correctly into the React-based Gutenberg environment.

Part 4: Webpack Configuration (webpack.config.js)

To bundle our Vue components and integrate them with WordPress, we need a Webpack configuration file. Create a webpack.config.js file in the root directory:

// webpack.config.js
const path = require('path');
const VueLoaderPlugin = require('vue-loader/lib/plugin');

module.exports = {
    entry: './src/block.js',
    output: {
        path: path.resolve(__dirname, 'build'),
        filename: 'block.js',
    },
    module: {
        rules: [
            {
                test: /.vue$/,
                loader: 'vue-loader',
            },
            {
                test: /.scss$/,
                use: [
                    'style-loader',
                    'css-loader',
                    'sass-loader',
                ],
            },
            {
                test: /.css$/,
                use: ['style-loader', 'css-loader'],
            },
        ],
    },
    plugins: [
        new VueLoaderPlugin(),
    ],
    resolve: {
        extensions: ['.js', '.vue'],
    },
};

Part 5: Building and Deploying

Finally, let’s build our block and integrate it into WordPress:

  1. Build the block: Run npm run build (you might need to add a build script to your package.json). This will compile your code into the build directory.
  2. Create a plugin directory: Create a new directory in your /wp-content/plugins directory. Name it something descriptive (e.g., vue-video-block).
  3. Move the build files: Move the contents of the build directory into your new plugin directory.
  4. Create a plugin file: Create a vue-video-block.php file in your plugin directory with the following basic plugin header:
<?php
/**
 * Plugin Name: Vue Video Block
 * Plugin URI:  https://yourwebsite.com/
 * Description: A custom Gutenberg block that uses Vue.js to embed videos.
 * Version:     1.0.0
 * Author:      Your Name
 * Author URI:  https://yourwebsite.com/
 * License:     GPL2
 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain: vue-video-block
 */

// Include the necessary scripts and styles (adjust paths as needed)
function vue_video_block_enqueue_scripts() {
  wp_enqueue_script(
    'vue-video-block-script',
    plugins_url('build/block.js', __FILE__),
    array('wp-blocks', 'wp-element', 'wp-i18n'),
    '1.0.0',
    true
  );
}
add_action('enqueue_block_editor_assets', 'vue_video_block_enqueue_scripts');
add_action('enqueue_block_assets', 'vue_video_block_enqueue_scripts');

?>
  1. Activate the plugin: Activate the plugin in your WordPress admin panel. Your new Vue-powered video block should now be available in the Gutenberg editor.

This comprehensive guide provides a solid foundation for creating sophisticated Gutenberg blocks using Vue.js. Remember to adapt and expand upon this codebase to meet your specific needs and add features like different video platform support, advanced styling, and more robust error handling. The key takeaway is the powerful combination of Gutenberg’s ease of use with the dynamic capabilities of Vue.js, opening doors to creating highly interactive and user-friendly WordPress experiences.

Leave a Reply

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

Trending