Como crear un bloque con InnerBlocks y controles personalizados (JS) en WordPress

Contents

Introducción

Este artículo explica paso a paso cómo crear un bloque personalizado para WordPress usando InnerBlocks y controles personalizados en JavaScript. Cubriremos la estructura del proyecto, el registro del bloque, el desarrollo del componente de edición con InnerBlocks, controles en la barra lateral (InspectorControls) y la renderización de la salida con InnerBlocks.Content. También incluimos ejemplos completos de código para cada archivo necesario.

Requisitos previos

  • WordPress 5.0 (mejor con 5.8 )
  • Node.js y npm instalados
  • Conocimientos básicos de ESNext, React/JSX y la API de bloques de Gutenberg
  • Herramientas de compilación: recomendamos @wordpress/scripts para simplificar

Estructura del proyecto

Un plugin simple para este bloque podría tener la siguiente estructura:

  • my-innerblocks-block/
    • block.json
    • src/
      • index.js
      • edit.js
      • save.js
    • build/ (generado)
    • plugin.php
    • style.css (opcional)
    • editor.css (opcional)

1. block.json (metadatos)

Usar block.json facilita el registro del bloque con register_block_type_from_metadata. Define atributos, estilos, y scripts a enlazar.

{
  apiVersion: 2,
  name: mi-plugin/innerblocks-con-controles,
  title: Sección con InnerBlocks y Controles,
  category: layout,
  icon: columns,
  description: Bloque que permite anidar bloques con controles personalizados,
  supports: {
    html: false
  },
  editorScript: file:./build/index.js,
  editorStyle: file:./build/editor.css,
  style: file:./build/style.css,
  attributes: {
    backgroundColor: {
      type: string,
      default: #ffffff
    },
    showTitle: {
      type: boolean,
      default: true
    },
    columns: {
      type: number,
      default: 2
    }
  }
}

2. plugin.php (registro en PHP)

Archivo principal del plugin que registra el bloque usando los metadatos y encola los assets compilados.


3. index.js (entrada JS)

Archivo de entrada que registra la edición y la save. Importa edit y save desde src.

import { registerBlockType } from @wordpress/blocks
import edit from ./edit
import save from ./save
import metadata from ../block.json

registerBlockType( metadata.name, {
    ...metadata,
    edit,
    save,
} )

4. edit.js (componente de edición con InnerBlocks y controles)

Este es el núcleo: muestra la interfaz de edición con InnerBlocks, Panel lateral con controles y controles en la barra del bloque. Usamos componentes de @wordpress/block-editor y @wordpress/components.

import { __ } from @wordpress/i18n
import { useBlockProps, InnerBlocks, InspectorControls, BlockControls } from @wordpress/block-editor
import { PanelBody, ToggleControl, RangeControl, ToolbarGroup, ToolbarButton } from @wordpress/components
import { Fragment } from @wordpress/element
import { useState } from @wordpress/element

const ALLOWED_BLOCKS = [ core/heading, core/paragraph, core/image, core/gallery ]

export default function Edit( props ) {
    const { attributes, setAttributes, clientId } = props
    const { backgroundColor, showTitle, columns } = attributes

    const blockProps = useBlockProps( {
        style: {
            backgroundColor: backgroundColor,
            padding: 1rem,
        },
        className: mi-innerblocks-block columns-{ columns },
    } )

    const template = [
        [ core/heading, { placeholder: Título de la sección, level: 3 } ],
        [ core/paragraph, { placeholder: Escribe el contenido... } ],
    ]

    return (
        
            
                
                     setAttributes( { showTitle: val } ) }
                    />
                     setAttributes( { columns: val } ) }
                        min={ 1 }
                        max={ 4 }
                    />
                
            

            
                
                     setAttributes( { showTitle: ! showTitle } ) }
                    />
                
            

            
{ showTitle

Título de sección

}
) }

Explicación clave del edit.js

  • useBlockProps: aplica atributos y estilos al wrapper del bloque de forma compatible con la API.
  • InspectorControls: panel lateral donde colocamos ToggleControl y RangeControl para modificar atributos.
  • BlockControls: controla la barra superior del bloque con botones personalizados.
  • InnerBlocks: permite anidar bloques aquí se pasan allowedBlocks, template, templateLock y renderAppender.

5. save.js (salida del bloque)

En la función save usamos InnerBlocks.Content para serializar el contenido anidado y produce la salida HTML final que se guarda en el contenido de la entrada.

import { useBlockProps, InnerBlocks } from @wordpress/block-editor

export default function Save( props ) {
    const { attributes } = props
    const { backgroundColor, showTitle, columns } = attributes

    const blockProps = useBlockProps.save( {
        style: {
            backgroundColor: backgroundColor,
            padding: 1rem,
        },
        className: mi-innerblocks-block columns-{ columns },
    } )

    return (
        
{ showTitle

Título de sección

}
) }

6. estilo básico (editor y front-end)

Ejemplo de CSS para columnas adaptables y espaciado.

.mi-innerblocks-block {
  box-sizing: border-box
}
.mi-innerblocks-block .mi-seccion-titulo {
  margin-top: 0
}
.mi-innerblocks-block.columns-1 > .wp-block {
  width: 100%
}
.mi-innerblocks-block.columns-2 > .wp-block {
  width: 50%
}
.mi-innerblocks-block.columns-3 > .wp-block {
  width: 33.3333%
}
.mi-innerblocks-block.columns-4 > .wp-block {
  width: 25%
}

/ Asegúrate de que los bloques hijos se comporten como elementos en fila /
.mi-innerblocks-block > .wp-block {
  display: inline-block
  vertical-align: top
}

7. Compilar con @wordpress/scripts

Configura package.json con scripts para compilación:

{
  name: mi-innerblocks-block,
  version: 1.0.0,
  scripts: {
    build: wp-scripts build,
    start: wp-scripts start
  },
  devDependencies: {
    @wordpress/scripts: ^25.0.0
  }
}

Coloca la entrada en src/index.js y configura block.json para apuntar a build/index.js. Ejecuta npm run build o npm run start mientras desarrollas.

8. Buenas prácticas y consejos

  • Usa atributos en block.json para que Gutenberg pueda serializarlos correctamente.
  • Prefiere InnerBlocks.Content en save para dejar que Gutenberg serialice los bloques hijos.
  • Si necesitas controlar la estructura inicialmente, usa template. Si quieres bloquear completamente la estructura, usa templateLock: all.
  • Define allowedBlocks para evitar que se inserten bloques no deseados.
  • Para estilos personalizados en el editor, registra editor.css y asegúrate de compilarlo en build/editor.css.
  • Prueba la accesibilidad y la edición con diferentes tamaños de pantalla.

9. Ejemplo avanzado: renderAppender personalizado

Puedes quitar el renderizador por defecto y usar uno propio para ofrecer un botón con etiqueta personalizada.

import { InnerBlocks } from @wordpress/block-editor
import { Button } from @wordpress/components

function CustomAppender() {
    return (
        
) } // En el edit:

10. Consideraciones sobre compatibilidad y rendimiento

  1. Evita ejecutar lógica costosa en el componente de edición guarda lo mínimo necesario en atributos.
  2. Si necesitas contenido dinámico (p. ej. basado en visitas o consultas), usa renderizado del lado servidor (server-side render) con render_callback en PHP.
  3. Usa className y estilos en CSS en lugar de inline cuando puedas, para facilitar la cache y la separación de responsabilidades.

Conclusión

Crear un bloque con InnerBlocks y controles personalizados en JS te permite construir secciones flexibles y potentes para editores de contenido en WordPress. La clave es entender la separación entre edición (edit.js) y salida (save.js), usar InnerBlocks para la anidación y aprovechar InspectorControls y BlockControls para exponer configuraciones al usuario. Con block.json y @wordpress/scripts la experiencia de desarrollo es mucho más sencilla y estandarizada.



Acepto donaciones de BAT's mediante el navegador Brave 🙂



Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *