Crea una fantastica esperienza di editing di WordPress e risparmia tempo con Gutenberg InnerBlocks

Pubblicato: 2023-02-12

Non ripeterti

Per gli sviluppatori, la pigrizia può essere una virtù. Un componente ben fatto e riutilizzabile fa risparmiare tempo e consente un riutilizzo efficiente e coerenza. Ciò si presta bene alla creazione di esperienze di modifica in WordPress, poiché la coerenza genera familiarità e conoscenza per coloro che utilizzano un sito Web quotidianamente.

WordPress ha fatto molto rumore con il rilascio dell'editor di blocchi Gutenberg, ora noto semplicemente come "The Editor". Per la modifica, la stesura e la pubblicazione dei contenuti, offre un'esperienza eccellente, di gran lunga migliore rispetto ai vecchi WYSIWYG. In qualità di sviluppatore, voglio fornire la migliore esperienza di editing ai miei clienti, voglio sfruttare le funzionalità di base e non voglio reinventare la ruota. Fortunatamente, WordPress ci consente di fare tutte queste cose con blocchi personalizzati.

Inserisci InnerBlocks

InnerBlocks è un'ottima funzionalità nell'editor di WordPress. Gli sviluppatori possono utilizzare blocchi fondamentali come il paragrafo, le intestazioni e i pulsanti per creare un'esperienza coerente per un cliente. Invece di riscrivere sezioni di testo e dichiarare nuovamente i campi, il cliente ottiene un'esperienza con cui acquisisce familiarità; modificare e combinare gli stessi blocchi. Diamo un'occhiata a un blocco che potremmo aver bisogno di creare per un cliente e vediamo come InnerBlocks può aiutarci a raggiungerlo.

Costruire un blocco con InnerBlocks

Un esempio di Call to Action Block con collegamenti a titoli, paragrafi e pulsanti
Figura: un esempio di Call to Action Block. Ciò include un titolo, un paragrafo e alcuni collegamenti a pulsanti.

Esaminiamo questo blocco e consideriamo come potremmo costruirlo. Uno strumento comune che utilizziamo quando creiamo blocchi è Advanced Custom Fields (ACF). ACF Pro aggiunge il supporto per blocchi personalizzati, che consente agli sviluppatori di scrivere blocchi in PHP per l'editor e il front-end. Ci consente anche di utilizzare campi personalizzati, un paradigma con cui molti sviluppatori di WordPress hanno familiarità. ACF supporta InnerBlocks, il che significa che possiamo creare un blocco personalizzato, ma non avremo nemmeno bisogno di scrivere codice personalizzato per quell'intestazione, paragrafo o pulsanti.

Con ACF Blocks, possiamo sfruttare i blocchi principali per creare un'esperienza di modifica eccezionale per tutto il testo che vediamo in questo blocco. Un'altra potenziale opzione sarebbe quella di utilizzare i modelli di blocco, ma come sviluppatori e curatori di una fantastica esperienza WordPress, la creazione di un blocco personalizzato raggiunge l'obiettivo desiderato.

Codice di registrazione del blocco

Ecco il codice per registrare il nostro blocco ACF personalizzato. Maggiori informazioni sull'utilizzo della funzione acf_register_block_type qui.

 <?php /** * Template for registering an ACF powered custom block. * * More info: https://www.advancedcustomfields.com/resources/blocks/ */ /** * Register the block. */ add_action( 'acf/init', function() { /** * ACF block registration options here: https://www.advancedcustomfields.com/resources/acf_register_block_type/ */ acf_register_block_type( array( 'name' => 'call-to-action-demo', // JS will register as: acf/{block-name}. 'title' => __( 'Call to Action ACF Demo', 'locale' ), 'description' => __( 'A custom ACF Call to Action block.', 'locale' ), 'render_template' => 'partials/blocks/call-to-action-demo.php', // Change to block template. 'category' => 'design', // Category in the block inserter. 'keywords' => array( 'action', 'buttons', 'cta' ), // Searchable keywords. 'supports' => array( 'align' => false, // Disable support for align. 'anchor' => true, // Enable support for anchor. 'jsx' => true, // Enable support for JSX. 'mode' => false, // Disable ACF block edit/preview mode switching as we are only using InnerBlocks for editable content. ), ) ); } );

Analizziamo il codice. Stiamo usando la funzione acf_register_block_type per registrare il nostro blocco e stiamo passando una serie di argomenti che definiscono il nostro blocco e attivano e disattivano la funzionalità.

  • Si noti che stiamo seguendo la procedura consigliata per aggiungere un nome univoco per il nostro blocco, nonché un titolo e una descrizione leggibili dall'uomo. Indichiamo un modello di rendering, dove in seguito imposteremo il nostro modello PHP per il blocco. Abbiamo anche aggiunto una categoria in cui vogliamo che il nostro blocco sia raggruppato nel Block Inserter.
  • Abbiamo parole chiave ricercabili per rendere più facile la ricerca del blocco nell'inseritore.
  • Aggiungiamo un array "supports" per abilitare funzionalità come l'impostazione di un ancoraggio HTML e abbiamo disattivato l'allineamento poiché questo blocco si troverà sempre al centro della pagina.
  • Che supporta l'array è dove accendiamo la magia di InnerBlocks! L'impostazione di 'jsx' su true indica ad ACF che supporteremo il rendering del modello jsx di React all'interno del nostro blocco.

Rivediamo il contenuto di cui abbiamo bisogno nel nostro blocco:

  • Intestazione
  • Testo del paragrafo
  • Pulsanti per agire!

Ora, normalmente assegneremmo campi al nostro blocco, come descritto qui. Ma in questo caso, non è necessario: possiamo sfruttare i blocchi fondamentali per ottenere tutto questo. Se il blocco necessita di uno sfondo immagine, ad esempio, l'aggiunta di un campo immagine ACF al blocco potrebbe essere un ottimo modo per ottenerlo. Per ora, però, atteniamoci al nostro esempio InnerBlocks e passiamo al modello.

Modello di blocco

Ecco il modello per il nuovo blocco. Assicurati di indirizzare la registrazione del blocco alla posizione del modello di blocco. Una pratica comune è metterli in una cartella partial nel tema.

 <?php /** * ACF Call to Action example block template. * * More info: https://www.advancedcustomfields.com/resources/acf_register_block_type/ * * @param array $block The block settings and attributes. * @param string $content The block inner HTML (empty). * @param bool $is_preview True during AJAX preview. * @param (int|string) $post_id The post ID this block is saved to. * */ // Create id attribute allowing for custom "anchor" value. $block_ . $block['id']; if ( ! empty( $block['anchor'] ) ) { $block_id = $block['anchor']; } // Create class attribute allowing for custom "className" and "align" values. $class_name = 'acf-call-to-action-demo'; if ( ! empty( $block['className'] ) ) { $class_name .= ' ' . $block['className']; } if ( ! empty( $block['align'] ) ) { $class_name .= ' align' . $block['align']; } ?> <div class="<?php echo esc_html( $class_name ); ?>"> <div class="cta__inner"> <?php // Set up innerBlocks and provide a template. // Restrict InnerBlocks to allowed block list. $allowed_blocks = array( 'core/heading', 'core/paragraph', 'core/buttons' ); // Start InnerBlocks with a template. $template = array( array( 'core/heading', array( 'placeholder' => __( 'CTA Heading', 'locale' ), 'align' => 'center', 'level' => '2', ), ), array( 'core/paragraph', array( 'placeholder' => __( 'Add CTA text here', 'locale' ), 'align' => 'center', ), ), array( 'core/buttons', array( 'placeholder' => __( 'Add CTA buttons here', 'locale' ), 'align' => 'center', ), array( array( 'core/button', array( 'text' => __( 'Take action', 'locale' ), ), ), array( 'core/button', array( 'text' => __( 'Learn more', 'locale' ), ), ), ), ), ); // Echo out our JSX InnerBlocks compoennt for the editor. echo '<InnerBlocks allowedBlocks="' . esc_attr( wp_json_encode( $allowed_blocks ) ) . '" template="' . esc_attr( wp_json_encode( $template ) ) . '" templateLock="false" />'; ?> </div> </div>

Analizziamo questo codice.

  • All'inizio, abbiamo un modello standard di blocco generico che ACF fornisce nella sua guida al blocco, come il supporto per un'ancora e un nome di classe personalizzato.
  • Il componente InnerBlocks può ricevere proprietà. Ne stiamo usando tre in questo modello.
    • Blocchi consentiti: aggiungiamo una serie di blocchi consentiti da curare. Solo questi blocchi saranno disponibili per la selezione all'interno dello spazio InnerBlocks del nostro blocco personalizzato.
    • Modello: possiamo passare un array di blocchi e possiamo passare gli attributi di blocco per i blocchi con cui iniziare quando vengono caricati per la prima volta nell'editor.
      • Si noti che possiamo passare attributi di blocco per impostare i nostri utenti per il successo. L'intestazione ha già il livello 2 impostato e il paragrafo è centrato.
      • Nota: i blocchi principali verranno sempre indicati in JavaScript come {plugin}/blockname. Nel nostro caso, stiamo usando i blocchi core, ma se volessi usare un blocco ACF personalizzato, dovresti scrivere 'acf' davanti al nome del blocco. Ricorda, quando utilizziamo InnerBlocks, passiamo questo componente all'editor di WordPress, che utilizza React. Ecco perché stiamo pensando in JS qui.
      • Un'altra nota: nota che il blocco core/pulsanti utilizza lo stesso InnerBlocks! In realtà stiamo passando un array di due blocchi core/pulsanti all'interno!
    • Template Locking: templateLock è impostato sul componente InnerBlocks. Se lo impostiamo su 'all', nessuno dei blocchi nel nostro modello fornito a InnerBlocks potrebbe essere spostato o rimosso. Se lo impostiamo su 'insert', i blocchi all'interno potrebbero essere solo spostati, nessun blocco potrebbe essere rimosso e nessun nuovo blocco potrebbe essere aggiunto. Se lo impostiamo su 'false', l'istanza InnerBlocks verrà sbloccata e verrà sbloccata indipendentemente da qualsiasi blocco del modello padre (maggiori informazioni su questo più avanti). Maggiori informazioni sui modelli di blocco nel manuale dell'editor di blocchi di WordPress. Parleremo più del blocco dei blocchi.

Abbiamo un nuovo blocco! Dopo tutto questo, e un po' di stile, ovviamente, il blocco di esempio appare così nell'editor:

Il blocco di invito all'azione con il blocco di intestazione selezionato.
Figura: il blocco Call to Action nell'editor. Il blocco di intestazione è selezionato.

Nidificazione più profonda: curare l'esperienza ancora di più con Nested InnerBlocks

Abbiamo un ottimo blocco e non abbiamo dovuto impostare un WYSIWYG o gestire campi personalizzati nel nostro modello. Ma se volessimo curare e perfezionare ulteriormente questa esperienza per il cliente? Diciamo che riceviamo una richiesta per assicurarci che l'intestazione sia sempre presente, quindi c'è sempre un blocco di intestazione, ma il contenuto dopo è flessibile e potrebbe anche includere un elenco o un altro tipo di blocco. Il nostro obiettivo è raggiungere tale flessibilità, preservando al tempo stesso la coerenza.

Consideriamo alcune regole quando si lavora con InnerBlocks:

  • Un singolo blocco può avere solo un'istanza di InnerBlocks all'interno.
  • Più blocchi all'interno di InnerBlocks possono utilizzare i propri componenti InnerBlocks.
  • InnerBlocks può essere bloccato tramite la proprietà templateLock, ma le istanze di InnerBlocks più in profondità all'interno di una struttura di blocchi annidati possono essere nuovamente sbloccate impostando templateLock su false.

Una soluzione è creare un nuovo blocco che funga da wrapper per InnerBlocks. Includeremmo quel blocco nel nostro modello di blocco padre e lo bloccheremmo, ma sbloccheremmo esplicitamente il nostro blocco wrapper all'interno impostando 'templateLock' su false. Potremmo anche voler assicurarci che questo speciale blocco wrapper sia disponibile solo all'interno del blocco genitore che scegliamo, impostando un genitore per il nostro blocco. Potremmo consentire a più tipi di blocco all'interno di quello spazio di offrire elenchi di editor e altro, pur consentendo solo l'intestazione, i pulsanti e il nostro blocco wrapper nel blocco principale Call to Action.

Blocco blocco individuale

Una nuova funzionalità di WordPress 5.9 è la possibilità di bloccare singoli blocchi in un modello. Questa è un'altra possibile soluzione al nostro problema flessibile ma coerente.

Ecco come appare il nostro modello con alcuni singoli blocchi bloccati:

 <?php /** * ACF Call to Action example block template. * * More info: https://www.advancedcustomfields.com/resources/acf_register_block_type/ * * @param array $block The block settings and attributes. * @param string $content The block inner HTML (empty). * @param bool $is_preview True during AJAX preview. * @param (int|string) $post_id The post ID this block is saved to. * */ // Create id attribute allowing for custom "anchor" value. $block_ . $block['id']; if ( ! empty( $block['anchor'] ) ) { $block_id = $block['anchor']; } // Create class attribute allowing for custom "className" and "align" values. $class_name = 'acf-call-to-action-demo'; if ( ! empty( $block['className'] ) ) { $class_name .= ' ' . $block['className']; } if ( ! empty( $block['align'] ) ) { $class_name .= ' align' . $block['align']; } ?> <div class="<?php echo esc_html( $class_name ); ?>"> <div class="cta__inner"> <?php // Set up innerBlocks and provide a template. // Restrict InnerBlocks to allowed block list. $allowed_blocks = array( 'core/heading', 'core/paragraph', 'core/buttons' ); // Start InnerBlocks with a template. $template = array( array( 'core/heading', array( 'placeholder' => __( 'Heading', 'locale' ), 'align' => 'center', 'level' => '2', 'lock' => array( 'move' => true, // Block may nto be moved. 'remove' => true, // Block may not be removed. ), ), ), array( 'core/paragraph', array( 'placeholder' => __( 'Add CTA text here', 'locale' ), 'align' => 'center', ), ), array( 'core/buttons', array( 'placeholder' => __( 'Add CTA buttons here', 'locale' ), 'align' => 'center', 'lock' => array( 'move' => true, // Block may not be moved. 'remove' => true, // Block may not be removed. ), ), array( array( 'core/button', array( 'text' => __( 'Take action', 'locale' ), ), ), array( 'core/button', array( 'text' => __( 'Learn more', 'locale' ), ), ), ), ), ); // Echo out our JSX InnerBlocks compoennt for the editor. echo '<InnerBlocks allowedBlocks="' . esc_attr( wp_json_encode( $allowed_blocks ) ) . '" template="' . esc_attr( wp_json_encode( $template ) ) . '" />'; ?> </div> </div>

I blocchi di intestazione e pulsanti non dovrebbero più essere spostati o rimossi. Assicurati di aggiornare l'editor, rimuovere e quindi aggiungere nuovamente il blocco per ottenere le modifiche ai modelli.

Bonus: creare lo stesso blocco in modo nativo

Una volta che hai un processo di compilazione in atto, creare blocchi WordPress nativi con React è sorprendentemente facile e non troppo diverso dal creare un modello di un blocco in php. La configurazione di un ambiente di sviluppo a blocchi esula dallo scopo di questo articolo, ma ci sono una serie di risorse per iniziare, come il Manuale dell'editor di blocchi di WordPress. Una volta che sei in grado di includere blocchi personalizzati, puoi creare rapidamente blocchi utilizzando InnerBlocks.

Ecco un esempio del nostro blocco Call to Action index.js in React. Vedrai la stessa strategia che abbiamo discusso sopra con ACF applicata qui.

 import { __ } from '@wordpress/i18n'; import { registerBlockType } from '@wordpress/blocks'; import { InnerBlocks } from '@wordpress/block-editor'; import { useBlockProps } from '@wordpress/block-editor'; /** * Block Name. * Create an example Call to Action Block * Uses InnerBlocks for editable content within. */ export const blockName = 'call-to-action'; /** * Block Config. * Set basic params for controlling the editor. */ export const BLOCK_CONFIG = { // Set up the block template. CTA_TEMPLATE: [ [ 'core/heading', { placeholder: __('CTA Headline', 'locale'), align: 'center', level: 2, lock: { move: true, remove: true, }, }, ], [ 'core/paragraph', { placeholder: 'Optional CTA text', align: 'center', lock: { move: true, }, }, ], [ 'core/buttons', { lock: { move: true, remove: true, }, className: 'is-content-justification-center', align: 'center', // __experimentalLayout - https://github.com/WordPress/gutenberg/blob/trunk/packages/block-library/src/buttons/block.json layout: { type: 'flex', justifyContent: 'center', }, }, [ [ 'core/button', { text: 'Apply now', lock: { move: true, remove: true, }, }, ], ['core/button', { text: 'Learn more' }], ], ], ], // Set up the allowed blocks. ALLOWED_BLOCKS: ['core/paragraph', 'core/heading', 'core/buttons'], }; // Register the block via WP func. Change 'myplugin' to your plugin or theme. registerBlockType(`myplugin/${blockName}`, { title: __('Call to Action', 'locale'), // Change 'locale' to your locale for internationalization. description: __( 'Call to action block with headline and buttons', 'locale' ), keywords: [__('call'), __('action'), __('cta')], category: 'design', supports: { anchor: true, defaultStylePicker: false, html: false, align: false, }, attributes: { anchor: { type: 'string', default: '', }, }, transforms: {}, variations: [], edit: (props) => { const blockProps = useBlockProps({ className: `wp-block-myplugin-${blockName}`, }); return ( <div {...blockProps}> <div className="cta__inner"> <div className="cta__inner-blocks-wrapper"> <InnerBlocks template={BLOCK_CONFIG.CTA_TEMPLATE} allowedBlocks={BLOCK_CONFIG.ALLOWED_BLOCKS} renderAppender={false} /> </div> </div> </div> ); }, save: () => { return ( <div> <div className="cta__inner"> <InnerBlocks.Content /> </div> </div> ); }, });

Vai avanti e costruisci!

Risorse addizionali

  • L'articolo di Bill Erickson su InnerBlocks
  • Gli articoli di Bill Erickson sul Block Editor
  • Guida ai blocchi ACF
  • Documentazione del tipo di blocco del registro ACF
  • Manuale dell'editor di blocchi di WordPress
  • Manuale dell'editor di blocchi di WordPress: creare un tutorial sui blocchi