Como usar SlotFill para extender la UI del editor (JS) en WordPress

Contents

Introducción: ¿Qué es SlotFill y por qué usarlo en el editor de WordPress?

SlotFill es un patrón de diseño utilizado en Gutenberg (el editor de bloques de WordPress) que permite definir lugares (Slots) donde otros módulos o plugins pueden inyectar contenido (Fills) de forma desacoplada. Es extremadamente útil para extender la interfaz del editor sin tocar el código core ni acoplar componentes entre sí.

Con SlotFill puedes:

  • Ofrecer puntos de extensión reutilizables dentro de tu plugin o tema.
  • Permitir que terceros añadan controles o información en zonas concretas del editor.
  • Mantener componentes independientes y composables.

Arquitectura y conceptos clave

Antes de entrar en ejemplos prácticos conviene entender los elementos básicos:

  • Slot: componente que declara un punto donde se mostrará contenido externo. Puede aceptar propiedades que serán pasadas a los Fills.
  • Fill: componente que se registra para rellenar un Slot concreto. Recibe las props que haya declarado el Slot y su contenido se renderiza en el lugar del Slot.
  • Proveedor (Provider): normalmente el sistema de React de WordPress ya ofrece el contexto necesario en caso de apps React propias puede usarse un provider local para compartir estado entre fills y slots.
  • Slots core: Gutenberg expone varios Slots en su UI (p. ej. para barras laterales, menús o paneles) puedes usarlos para inyectar contenido en zonas del editor.

Preparar el plugin: registrar y encolar scripts

Para que el navegador cargue tu código JS que usa SlotFill debes encolarlo desde PHP en tu plugin o tema. A continuación un ejemplo mínimo de registro y encolado compatible con ESNext mediante build (webpack/webpack-mix, etc.).

lt?php
/
  Plugin Name: Mi Plugin SlotFill
 /

function mi_plugin_enqueue() {
    wp_enqueue_script(
        mi-plugin-editor,
        plugins_url( build/index.js, __FILE__ ),
        array( wp-plugins, wp-edit-post, wp-components, wp-element, wp-data, wp-compose, wp-hooks ),
        filemtime( plugin_dir_path( __FILE__ ) . build/index.js )
    )

    // Opcional: estilos
    wp_enqueue_style(
        mi-plugin-editor-style,
        plugins_url( build/editor.css, __FILE__ ),
        array(),
        filemtime( plugin_dir_path( __FILE__ ) . build/editor.css )
    )
}
add_action( enqueue_block_editor_assets, mi_plugin_enqueue )

Ejemplo 1 — Crear un Slot propio y un Fill que lo rellena

Este ejemplo muestra cómo en un plugin registrar una PluginSidebar que contiene un Slot llamado MiSidebarSlot. Otros módulos (incluso dentro del mismo bundle) podrán registrar Fills para ese Slot. Así se promueve la extensibilidad.

Paso A — Plugin que declara el Slot dentro de una Sidebar

import { registerPlugin } from @wordpress/plugins
import { PluginSidebar } from @wordpress/edit-post
import { Slot } from @wordpress/components
import { Fragment } from @wordpress/element

const MiSidebar = () =gt {
    return (
        ltFragmentgt
            ltPluginSidebar
                name=mi-sidebar
                title=Mi Sidebar Extensible
            gt
                { / Declaramos el Slot con nombre mi-sidebar-slot y pasamos una prop / }
                ltSlot name=mi-sidebar-slot saludo=Hola desde el Slot /gt
            lt/PluginSidebargt
        lt/Fragmentgt
    )
}

registerPlugin( mi-sidebar-plugin, { render: MiSidebar } )

Paso B — Otro módulo (o parte del mismo plugin) registra un Fill

import { Fill } from @wordpress/components
import { registerPlugin } from @wordpress/plugins

const MiFill = () =gt {
    return (
        ltFill name=mi-sidebar-slotgt
            ltdiv style={{ padding: 8px }}gt
                ltstronggtContenido añadido por un Filllt/stronggt
                ltpgtEste Fill recibe props del Slot y puede leer quotsaludoquot.lt/pgt
            lt/divgt
        lt/Fillgt
    )
}

registerPlugin( mi-sidebar-fill, { render: MiFill } )

Resultado: cuando la sidebar de Mi Sidebar Extensible esté abierta, todos los Fills registrados con name=mi-sidebar-slot se renderizarán ahí. Esto permite a múltiples componentes insertarse sin modificarse mutuamente.

Ejemplo 2 — Pasando props desde Slot a Fill y controlando el orden

Los Slots pueden pasar props a los Fills (p. ej. funciones, estados). Además, el orden de renderizado de los fills puede controlarse por prioridad si usas wrapper o lógica para ordenarlos por defecto el orden será el de registro o el definido por el renderizado React.

import { Slot, Fill } from @wordpress/components
import { registerPlugin } from @wordpress/plugins
import { Fragment, useState } from @wordpress/element

// Declarador del Slot con una prop onAction
const MiComponenteConSlot = () =gt {
    const [contador, setContador] = useState(0)
    const onAction = () =gt setContador( c =gt c   1 )

    return (
        ltdivgt
            lth4gtContador: {contador}lt/h4gt
            ltSlot name=slot-con-acciones onAction={ onAction } /gt
        lt/divgt
    )
}

export const PluginConSlot = () =gt ltMiComponenteConSlot /gt
registerPlugin( plugin-con-slot, { render: PluginConSlot } )

// Fill que recibe la prop onAction y la llama
export const FillQueAcciona = () =gt (
    ltFill name=slot-con-accionesgt
        { ( { onAction } ) =gt (
            ltbutton onClick={ onAction }gtHaz click desde Filllt/buttongt
        ) }
    lt/Fillgt
)
registerPlugin( plugin-fill-accion, { render: FillQueAcciona } )

Observa que Fill puede ser una función que recibe las props que envía Slot así se permite comunicación unidireccional desde el Slot hacia el Fill sin acoplarlos.

Usar Hooks de datos con SlotFill (useSelect / useDispatch)

A menudo los fills necesitan leer o actualizar datos del store de WordPress (p. ej. contenido del post, metadata). En estos casos emplea los hooks useSelect y useDispatch de @wordpress/data dentro de los fills. De este modo los fills se mantienen reactivos y respetan el flujo de datos global.

import { Fill } from @wordpress/components
import { useSelect, useDispatch } from @wordpress/data
import { registerPlugin } from @wordpress/plugins

const FillConData = () =gt {
    const title = useSelect( ( select ) =gt select( core/editor ).getEditedPostAttribute( title ), [] )
    const { editPost } = useDispatch( core/editor )

    const cambiarTitulo = () =gt {
        editPost( { title: title    ✨ } )
    }

    return (
        ltFill name=mi-sidebar-slotgt
            ltdivgt
                ltpgtTítulo: {title  ltvacíogt}lt/pgt
                ltbutton onClick={ cambiarTitulo }gtAgregar emoji al títulolt/buttongt
            lt/divgt
        lt/Fillgt
    )
}

registerPlugin( mi-fill-con-data, { render: FillConData } )

Slots core de Gutenberg: dónde inyectar contenido en la UI del editor

Gutenberg expone múltiples puntos de extensión (slots) a través de distintos paquetes (p. ej. @wordpress/edit-post). Algunos componentes core que facilitan inyectar UI son:

  • PluginSidebar: para barras laterales (añades un slot dentro si quieres extensibilidad interna).
  • PluginPostStatusInfo: permite añadir info al panel de estado del post.
  • PluginMoreMenuItem / PluginDocumentSettingPanel / PluginPrePublishPanel: componentes ya preparados que actúan como wrappers y que internamente usan patterns compatibles con SlotFill.

Nota: los nombres concretos y la lista completa de slots/core components pueden cambiar entre versiones. Revisa la documentación y el código fuente de @wordpress/edit-post para localizar slots core disponibles en tu versión.

Buenas prácticas, rendimiento y accesibilidad

  1. Evita renderizados costosos en fills: cada Fill se renderiza cuando la zona que contiene el Slot se actualiza. Usa memoización (React.memo) o hooks adecuados para minimizar rerenders.
  2. Separación de responsabilidades: define Slots con props claras y no expongas implementaciones internas innecesarias.
  3. Uso responsable de stores: los fills pueden usar useSelect/useDispatch, pero evita lecturas globales sin dependencia adecuada para prevenir renders infinidad de veces.
  4. Accesibilidad: asegúrate de que los elementos añadidos con Fill siguen pautas ARIA y navegación por teclado. Evita cambios bruscos de foco no anticipados.
  5. Compatibilidad: documenta el nombre del Slot y las props públicamente si otros desarrolladores van a integrarse con tu plugin.

Ejemplo completo: plugin que declara Slot y otro plugin que lo extiende (registro y CSS)

A continuación se muestra un esquema de los ficheros y código mínimo para un plugin que declara un Slot y otro plugin que añade un Fill. Incluye la parte PHP vista al principio.

/ src/index.js - declarador del Slot /
import { registerPlugin } from @wordpress/plugins
import { PluginSidebar } from @wordpress/edit-post
import { Slot } from @wordpress/components

const MiSidebar = () =gt (
    ltPluginSidebar name=mi-sidebar title=Mi Sidebar Extensiblegt
        ltSlot name=mi-sidebar-slot saludo=hola /gt
    lt/PluginSidebargt
)

registerPlugin( mi-sidebar-plugin, { render: MiSidebar } )

/ src/fill.js - Fill que se registra (puede estar en su propio bundle o en el mismo) /
import { registerPlugin } from @wordpress/plugins
import { Fill } from @wordpress/components

const MiFill = () =gt (
    ltFill name=mi-sidebar-slotgt
        ltdiv style={{ padding: 12 }}gt
            ltpgtltstronggtUn Fill internolt/stronggtlt/pgt
            ltpgtAñade controles o información aquí.lt/pgt
        lt/divgt
    lt/Fillgt
)

registerPlugin( mi-sidebar-fill, { render: MiFill } )
/ editor.css /
.mi-fill-clase {
  padding: 8px
  border-left: 2px solid rgba(0,0,0,0.06)
}

Solución de problemas comunes

  • No veo mi Fill: revisa que el Slot está montado en el árbol React cuando el editor está abierto y que ambos bundles están correctamente encolados y ejecutándose en el editor (console del navegador).
  • Props no llegan al Fill: asegúrate de que el Slot las está exponiendo y que el Fill las acepta (cuando Fill es función, recibe props como parámetro).
  • Conflictos de CSS: encapcula estilos específicos del editor con selectores o clases para evitar romper la UI de Gutenberg.
  • Rendimiento: evita cálculos pesados dentro del Fill usa useMemo y divide en componentes más pequeños.

Conclusión

SlotFill es una herramienta poderosa para extender la interfaz del editor de WordPress de manera modular y mantenible. Definir Slots bien documentados y permitir que Fills se registren de forma desacoplada permite ecosistemas de plugins más integrables y menos propensos a conflictos. Siguiendo las buenas prácticas de rendimiento y accesibilidad lograrás extensiones robustas y fáciles de mantener.

Recursos recomendados



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 *