Continuando con esta serie sobre bloques y la Interactivity API, vamos a agregar más complejidad y explorar las opciones que esta nueva herramienta nos ofrece. En este caso, crearemos un carrusel utilizando el bloque core/gallery
y la Interactivity API para gestionar la navegación en el frontend.
Creación del bloque
Nuevamente creamos nuestro bloque con @wordpress/create-block
, en la carpeta wp-content/plugins
:
npx @wordpress/create-block Carousel --template @wordpress/create-block-interactive-template cd carousel npm start
Uso de InnerBlocks
Utilizaremos el bloque core/gallery
en el editor. Idealmente, no necesitaremos realizar modificaciones en el editor, ya que nos enfocaremos en el frontend con la Interactivity API. El uso de InnerBlocks
nos simplifica esta parte, ya que obtenemos un bloque completamente funcional y podemos aprovechar todas las opciones de los bloques de core.
En el archivo src/edit.js
, agregamos lo siguiente:
import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor'; export default function Edit( { attributes, setAttributes } ) { const blockProps = useBlockProps(); const innerBlocksProps = useInnerBlocksProps( blockProps, { allowedBlocks: [ 'core/gallery' ], template: [ [ 'core/gallery' ], ], } ); return ( <div { ...blockProps }> <div className="container" > <div {...innerBlocksProps} className="carousel-container"></div> </div> </div> ); }
Aquí importamos useInnerBlocksProps
para poder utilizarlo y definimos las propiedades allowedBlocks
y template
, configurándolas con 'core/gallery'
. Luego, lo aplicamos en el return
del componente.
Guardado de contenido
Al igual que en el ejemplo anterior, agregamos la función save
para almacenar las imágenes seleccionadas en el contenido. En src/save.js
:
import { InnerBlocks, useBlockProps } from '@wordpress/block-editor'; export default function save() { return ( <div { ...useBlockProps.save() }> <InnerBlocks.Content /> </div> ); }
y en src/index.js:
import save from './save'; registerBlockType( metadata.name, { /** * @see ./edit.js */ edit: Edit, save, } );
Hasta acá, nada nuevo.
Frontend
Ahora viene la parte divertida: estructurar el render.php
para mostrar nuestro carrusel:
<div <?php echo get_block_wrapper_attributes(); ?> data-wp-interactive="create-block" <?php echo wp_interactivity_data_wp_context( array( "slideIndex" => 0 ) ); ?> > <section class="slider-wrapper"> <button class="slide-arrow prev" data-wp-on--click="actions.prevSlide"> ‹ </button> <button class="slide-arrow next" data-wp-on--click="actions.nextSlide"> › </button> <ul class="slides-container" data-wp-watch--update="callbacks.updateSliderPosition"> <?php $gallery = $block->parsed_block['innerBlocks'][0]['innerBlocks']; foreach ( $gallery as $i => $slide ) { ?> <li class="slide"> <?php echo $slide['innerHTML']; ?> </li> <?php } ?> </ul> </section> </div>
Acá definimos la estructura del carrusel, los botones de navegación y la lista con las imágenes de la galería. Para acceder a las imágenes, utilizamos la variable expuesta $block
y mostramos su innerHTML
directamente.
Estilos
Estos son los estilos que aplicaremos al carrusel. No entraremos en detalles, ya que están explicados en el tutorial en el que me basé, con algunas modificaciones menores:
.wp-block-create-block-carrousel { .slider-wrapper { margin: 1rem; position: relative; overflow: hidden; } .slides-container { height: calc(100vh - 2rem); width: 100%; display: flex; list-style: none; margin: 0; padding: 0; overflow-x: scroll; overflow-y: hidden; scroll-behavior: smooth; scrollbar-width: none; /* Firefox */ -ms-overflow-style: none; /* Internet Explorer 10+ */ &::-webkit-scrollbar { width: 0; height: 0; } } .slide { width: 100%; height: 100%; flex: 1 0 100%; display: flex; align-items: center; background-color: beige; figure{ width: 100%; img { width: 100%; } } } .slide-arrow { position: absolute; display: flex; top: 0; bottom: 0; margin: auto; height: 4rem; background-color: white; border: none; width: 2rem; font-size: 3rem; padding: 0; cursor: pointer; opacity: 0.5; transition: opacity 100ms; &:hover, &:focus { opacity: 1; } &.next { right: 0; padding-left: 0.75rem; border-radius: 2rem 0 0 2rem; } &.prev { left: 0; padding-left: 0.25rem; border-radius: 0 2rem 2rem 0; } } }
En el div
inicial, agregamos la directiva data-wp-interactive="create-block"
para indicar que activamos la Interactivity API en el contenido. El namespace por defecto es "create-block"
, aunque podemos cambiarlo para identificar mejor nuestro plugin.
Para los botones de navegación, asignamos acciones con la directiva data-wp-on
:
data-wp-on--click="actions.prevSlide"
data-wp-on--click="actions.nextSlide"
En el contenedor de la lista de imágenes, agregamos:
data-wp-watch--update="callbacks.updateSliderPosition"
Esto ejecutará el callback al crear el nodo y cada vez que se actualice el contexto declarado en:
wp_interactivity_data_wp_context( array( "slideIndex" => 0 ) )
Acciones y callbacks
Agregamos las acciones y callbacks al src/view.js: Incrementamos y decrementamos el slideIndex en cada acción de los botones de navegación y en el callback usamos la propiedad de javascript scrollLeft del contenedor para mover el carrousel según el slideIndex.
import { store, getContext, getElement } from '@wordpress/interactivity'; const { state } = store( 'create-block', { actions: { nextSlide: () =>{ const context = getContext(); context.slideIndex += 1 }, prevSlide: () => { const context = getContext(); context.slideIndex -= 1 }, }, callbacks: { updateSliderPosition: () => { const context = getContext(); const { ref } = getElement(); ref.scrollLeft = context.slideIndex * ref.children[context.slideIndex].clientWidth; }, }, } );
La función getContext()
nos permite acceder a las variables locales del bloque, mientras que getElement()
nos permite acceder al nodo que está vinculado a ese callback.
Inicio y fin de los botones
Por último, vamos a agregar la lógica a los botones para deshabilitarlos cuando no haya más imágenes para seguir navegando.
En render.php
agregamos la directiva data-wp-bind a los botones y un nuevo atributo para poder indicar que llego a la ultima imagen, la primera ya la tenemos:
<?php echo wp_interactivity_data_wp_context( array( "slideIndex" => 0, "lastSlide" => 0 ) ); ?> > <section class="slider-wrapper"> <button class="slide-arrow prev" data-wp-on--click="actions.prevSlide" data-wp-bind--disabled="!context.slideIndex"> ‹ </button> <button class="slide-arrow next" data-wp-on--click="actions.nextSlide" data-wp-bind--disabled="context.lastSlide"> › </button>
por otro lado en view.js actualizaos el atributo de context lastSlide
para que devuelva true cuando slideIndex tiene el mismo valor de scrollWidth
menos un ancho de slide clientWidth
updateSliderPosition: () => { const context = getContext(); const { ref } = getElement(); ref.scrollLeft = context.slideIndex * ref.children[context.slideIndex].clientWidth; context.lastSlide = ref.children.length - 1 === context.slideIndex; }
Generar el plugin
Finalmente, para generar el archivo ZIP del plugin e instalarlo en otro sitio, ejecutamos: