Serialize custom block with InnerBlock

What you asked for is not possible for blocks that rely on frontend javascript, this includes embeds.


It’s also not possible using the Swiper react library. The Swiper library made the questionable choice of manually inspecting child components for the SwiperSlide component name, preventing it from ever being used with child blocks.

Edit: Actually maybe it is! Since writing this, a PR was merged that may fix this and allow the code below to work as desired


It isn’t possible using jQuery either with inner blocks as it conflicts with the way React works, and will cause virtual DOM problems.

The Closest You Can Get

Instead, if we use the React Swiper library, useBlockProps, and useInnerBlocksProps, we can implement this, and have editable slides, while keeping the slider.

However, Swiper will not see the specific arrangement of components it needs and will place them after the slider container instead of inside the wrapper.

The important thing to note, is this snippet:

        const blockProps = useBlockProps();
        const innerBlocksProps = useInnerBlocksProps( blockProps, {
            allowedBlocks: [ 'tomjn/swiper-slide' ],
            template: TEMPLATE,
        });
        const params = {...};
        return (
            <div { ...innerBlocksProps }>
                <Swiper { ...params }>
                    { innerBlocksProps.children }
                </Swiper>
            </div>
        );

By using innerBlocksProps.children we eliminate the 2 containing <div> tags.

Here’s my demo:

src/index.js:

import { registerBlockType } from '@wordpress/blocks';
import {
    InnerBlocks,
    useBlockProps,
    __experimentalUseInnerBlocksProps as useInnerBlocksProps
} from '@wordpress/block-editor';

import SwiperCore, { Navigation, Pagination, Scrollbar, A11y } from 'swiper';
import { Swiper, SwiperSlide } from 'swiper/react';

// Import Swiper styles
import 'swiper/swiper-bundle.css';

// install Swiper components
SwiperCore.use([Navigation, Pagination, Scrollbar, A11y]);

const TEMPLATE = [
    [ 'tomjn/swiper-slide', {}, [
        [ 'core/paragraph', { placeholder: 'Enter slide content...' } ],
    ] ],
    [ 'tomjn/swiper-slide', {}, [
        [ 'core/paragraph', { placeholder: 'Enter slide content...' } ],
    ] ]
];

registerBlockType( 'tomjn/swiper', {
    apiVersion: 2,
    title: 'Swiper',
    category: 'layout',
    edit: () => {
        const blockProps = useBlockProps();
        const innerBlocksProps = useInnerBlocksProps( blockProps, {
            allowedBlocks: [ 'tomjn/swiper-slide' ],
            template: TEMPLATE,
        });
        const params = {
            init: true,
            paceBetween: 50,
            slidesPerView: 2,
            loop: true,
            navigation: {
                clickable: true,
            },
            spaceBetween: 30,
            pagination: {
                clickable: true,
            }
        };
        return (
            <div { ...innerBlocksProps }>
                <Swiper { ...params }>
                    { innerBlocksProps.children }
                </Swiper>
            </div>
        );
    },
    save: () => {
        return (
            <div className="swiper-container">
                <div className="swiper-wrapper">
                    <InnerBlocks.Content />
                </div>
                <div className="swiper-pagination"></div>
                <div className="swiper-button-prev"></div>
                <div className="swiper-button-next"></div>
            </div>
        );
    },
} );

registerBlockType( 'tomjn/swiper-slide', {
    apiVersion: 2,
    title: 'Swiper Slide',
    category: 'layout',
    edit: () => {
        const blockProps = useBlockProps();
        return (
            <SwiperSlide>
                <div {...blockProps}>
                    <InnerBlocks />
                </div>
            </SwiperSlide>
        );
    },
    save: () => {
        return (
            <div class="swiper-slide">
                <InnerBlocks.Content />
            </div>
        );
    },
} );

package.json:

{
    "dependencies": {
        "swiper": "^6.4.5"
    },
    "devDependencies": {
        "@wordpress/scripts": "^12.6.1"
    },
    "scripts": {
        "build": "wp-scripts build",
        "check-engines": "wp-scripts check-engines",
        "check-licenses": "wp-scripts check-licenses",
        "format:js": "wp-scripts format-js",
        "lint:css": "wp-scripts lint-style",
        "lint:js": "wp-scripts lint-js",
        "lint:md:docs": "wp-scripts lint-md-docs",
        "lint:md:js": "wp-scripts lint-md-js",
        "lint:pkg-json": "wp-scripts lint-pkg-json",
        "packages-update": "wp-scripts packages-update",
        "start": "wp-scripts start",
        "test:e2e": "wp-scripts test-e2e",
        "test:unit": "wp-scripts test-unit-js"
    }
}

plugin.php:

<?php
/**
 * Plugin Name: Toms Swiper Plugin
 * Plugin URI: https://tomjn.com
 * Description: Swiper no swiping.
 * Requires at least: 5.5
 * Requires PHP: 7.3
 * Version: 1.0.0
 * Author: Tom J Nowell
 */

defined( 'ABSPATH' ) || exit;

add_action(
    'enqueue_block_editor_assets',
    function() {
        $asset = include plugin_dir_path( __FILE__ ) . 'build/index.asset.php';

        wp_register_script(
            'tomjn-swiper-block-js',
            plugins_url( 'build/index.js', __FILE__ ),
            $asset['dependencies'],
            $asset['version'],
        );
        wp_register_style(
            'tomjn-swiper-block-css',
            plugins_url( 'build/index.css', __FILE__ ),
            [],
            $asset['version'],
        );
    }
);

/**
 * Registers all block assets so that they can be enqueued through Gutenberg in
 * the corresponding context.
 */
function tomjn_swiper_register_block() {

    if ( ! function_exists( 'register_block_type' ) ) {
        // Gutenberg is not active.
        return;
    }

    register_block_type(
        'tomjn/swiper',
        [
            'editor_script' => 'tomjn-swiper-block-js',
            'editor_style'  => 'tomjn-swiper-block-css',
        ]
    );
    register_block_type(
        'tomjn/swiperslide',
        [
            'editor_script' => 'tomjn-swiper-block-js',
            'editor_style'  => 'tomjn-swiper-block-css',
        ]
    );

}
add_action( 'init', 'tomjn_swiper_register_block' );

Leave a Comment