In questo tutorial impareremo a creare un blocco Gutenberg personalizzato.
Ci sono diversi modi di creare blocchi, per semplificare la procedura e renderla comprensibile a tutti utilizzeremo plain JavaScript. Abbiamo scelto di seguire questo metodo e non utilizzare JSX per evitare la compilazione.
Per riuscire a seguire questo tutorial devi solo avere conoscenze di base di JavaScript, HTML e CSS.
Non farti intimorire dalla documentazione attuale sullo sviluppo dei blocchi, che non aiuta molto, specie se non vuoi usare JSX. Ti mostrerò come iniziare subito a creare i primi blocchi, usando solo un editor di codice e un’installazione locale di WordPress.
Iniziamo.
Table of Contents
Cos’è un blocco Gutenberg?
Con Gutenberg la creazione di pagine e articoli per i siti web avviene componendo il contenuto attraverso i blocchi. Un blocco, quindi, rappresenta qualsiasi elemento all’interno della nostra pagina.
Nella documentazione di WordPress i blocchi Gutenberg vengono definiti come unità di markup che, combinate insieme, formano il contenuto o il layout di una pagina web.
Alcuni dei blocchi predefiniti sono:
- paragrafi
- titoli
- immagini
- video
- file
- elenco puntato.
A differenza del classic editor di WordPress, in cui il contenuto degli articoli viene creato in un’unica finestra, i blocchi ci permettono di suddividere il contenuto in parti più piccole.
Il vantaggio della creazione a blocchi è che il singolo blocco può essere spostato facilmente in un’altra posizione. Nello specifico possiamo modificare i singoli blocchi, riordinarli, spostarli e duplicarli con maggiore facilità.
JSX VS JavaScript
Per creare un blocco Gutenberg possiamo utilizzare JavaScript o JSX. Nel nostro caso utilizzeremo JavaScript, in questo modo non ci servirà ricompilare il codice con npm.
JavaScript è un linguaggio di scripting derivato da Java che viene usato per rendere le pagine interattive. I JavaScript vengono eseguiti direttamente dal browser al momento del caricamento della pagina e non hanno bisogno di essere compilati.
JSX (JavaScript XML) è un’estensione della sintassi di JavaScript che viene usata per creare componenti di React ed è simile al linguaggio HTML. Le espressioni JSX devono essere compilate per diventare funzioni JavaScript.
Scegliere uno dei due metodi porta allo stesso risultato. La differenza è che usando JavaScript non abbiamo bisogno di compilare. Seguire questo metodo rende possibile creare un blocco anche ai meno esperti.
Il nostro ambiente di sviluppo
Nel nostro caso abbiamo scelto di utilizzare plain JavaScript e non JSX. Questa scelta nasce dall’intento di creare un tutorial adatto a tutti.
Ci basterà a utilizzare:
- local con cui installeremo WordPress in locale;
- un editor di codice, per esempio Visual Studio Code.
Se avessimo utilizzato JSX avremmo avuto bisogno di un ambiente di sviluppo più complesso. In quel caso ci sarebbe servito installare:
- Node.js, un framework che si usa per creare applicazioni in JavaScript;
- npm, il gestore di pacchetti di Node.
Com’è impostato questo tutorial
In questo tutorial voglio spiegare come creare un blocco personalizzato, iniziando da un blocco base per introdurre i primi concetti.
Aggiungerò dei passaggi in ogni blocco in modo da introdurre altri concetti e migliorare in questo modo il nostro blocco Gutenberg un passo alla volta, nella speranza di rendere il più chiaro possibile il tutto.
Puoi seguire il tutorial passo passo, copiando il codice creando un nuovo plugin per ogni blocco, oppure scaricare il codice da GitHub.
Ho deciso di creare un plugin separato per ogni blocco per (spero) maggiore chiarezza, ovviamente sarebbe stato possibile creare un unico plugin per tutti i blocchi.
Senza dire altro, iniziamo creando il nostro primo blocco, creando un blocco molto basilare, che ci servirà a capire la struttura base del blocco.
Il nostro primo blocco, iniziamo dalla base
Entriamo quindi nel vivo del nostro tutorial, e iniziamo a sporcarci le mani col codice.
Abbiamo il nostro sito WordPress installato in locale, ed un editor di codice (a me personalmente piace Visual Studio Code da quando GitHub ha mandato in pensione Atom).
Non ci serve altro.
Iniziamo col creare una cartella per il nostro plugin, che chiameremo “supporthost-block-1”.
Al suo interno creiamo un file php chiamato supporthost-block-1.php (lo stesso nome della cartella, ma ovviamente con estensione php).
Nel nostro file php inseriamo questo codice:
<?php /** * Plugin Name: SupportHost block 01 */ function supporthost_block_01_register_block() { register_block_type( __DIR__ ); } add_action( 'init', 'supporthost_block_01_register_block' );
In pratica nel commento in alto diamo un nome al nostro plugin, e tramite l’action hook “init” chiamiamo la funzione register_block_type alla quale ci basta passare la posizione della cartella che contiene il file block.json, che adesso dobbiamo creare.
Creiamo il file block.json che contiene le informazioni del nostro blocco Gutenberg:
{ "apiVersion": 2, "title": "SupportHost: 01", "name": "supporthost-blocks/supporthost-01", "category": "layout", "icon": "admin-generic", "editorScript": "file:./block.js" }
Cosa significa? Queste sono le impostazioni base del nostro blocco, vediamole una per una:
- apiVersion: la versione API del blocco.
- title: il titolo del blocco che viene mostrato quando scegliamo il blocco.
- name: il nome univoco che definisce il nostro blocco.
- category: la categoria in cui il blocco viene inserito (text, media, design, widgets, theme, embed). I blocchi vengono divisi in categorie quando clicchiamo sul + azzurro in alto a sinistra per aprire l’inserter dei blocchi.
- icon: la dashicon che vogliamo mostrare come icona del nostro blocco.
- editorScript: lo script che vogliamo caricare nell’editor per il nostro blocco.
Come probabilmente hai notato, nell’ultima riga del file block.json chiamiamo un file block.js, ma questo file ancora non esiste.
Creiamolo, incolliamo il codice qui sotto e vediamo come funziona.
( function ( blocks, element ) { var el = element.createElement; blocks.registerBlockType( 'supporthost-blocks/supporthost-01', { edit: function () { return el( 'p', {}, 'Hello World (from the editor).' ); }, save: function () { return el( 'p', {}, 'Hola mundo (from the frontend).' ); }, } ); } )( window.wp.blocks, window.wp.element );
Questo file viene caricato in automatico nell’editor, e contiene 3 elementi importanti:
- name: alla riga 4 vediamo che si usa lo stesso “name” che abbiamo inserito nel file block.json.
- edit: la funzione che viene chiamata dentro l’editor, ci permette di vedere il blocco nell’editor e nei prossimi esempi conterrà un codice che ci permette la modifica del contenuto del blocco.
- save: questa funzione viene chiamata al momento in cui salviamo in nostro contenuto. WordPress salva nel database il codice HTML che viene creato tramite questa funzione.
Come sicuramente hai notato, quando aggiungi questo blocco Gutenberg (che ovviamente non è modificabile, ancora) nell’editor vedi un testo, mentre nel frontend vedi un testo diverso. Puoi vedere il risultato nella schermata alla fine di questo paragrafo.
Questo succede perché abbiamo indicato al nostro blocco di mostrare un “p” nell’editor, ma quando salviamo, la funzione save salva un “p” con un testo diverso nel database, e quindi viene mostrato un testo diverso nel frontend.
Adesso possiamo andare alla schermata dei plugin e attivare il nostro primo plugin.
Andando a creare un nuovo post dovremmo vedere il nuovo blocco, eppure non è presente. Come mai? Mancano le dipendenze.
Nella documentazione di WordPress leggiamo:
Per registrare il blocco è necessario un file php per gli asset, nella stessa cartella della cartella usata in register_block_type() e deve iniziare con il nome del file dello script.
In pratica dobbiamo creare un file block.asset.php nella stessa cartella, con questo codice:
<?php return array( 'dependencies' => array( 'wp-blocks', 'wp-element', 'wp-block-editor', 'wp-polyfill' ), 'version' => '0.1' );
Una nota sul ricaricare la pagina. Quando lavori a un blocco, e i files (css e js) cambiano, è ideale eliminare il blocco, salvare e fare un hard refresh per ricaricare eventuali files in cache. Su Mac per fare hard refresh basta premere maiusc+cmd+r
Adesso puoi ricaricare la pagina dell’header ed aggiungere il primo blocco personalizzato nel tuo post.
Ovviamente per adesso è abbastanza inutile, nel senso che possiamo aggiungere un blocco, che viene mostrato in due modi diversi su editor e frontend, e non possiamo modificarlo.
Ma questo è solo un primo passo. Aggiungiamo il primo mattoncino per dare al nostro blocco Gutenberg una grafica migliore: il CSS.
Aggiungiamo il CSS al nostro blocco
Duplichiamo la cartella supporthost-block-1 chiamandola supporthost-block-2.
Rinominiamo allo stesso modo supporthost-block-1.php in supporthost-block-2.php e modifichiamo il codice al suo interno in questo modo:
<?php /** * Plugin Name: SupportHost block 02 */ function supporthost_block_02_register_block() { register_block_type( __DIR__ ); } add_action( 'init', 'supporthost_block_02_register_block' );
In pratica sostituendo il numero 1 con il numero 2.
Nel file block.json aggiungiamo due righe rispetto al file del plugin precedente:
{ "apiVersion": 2, "title": "SupportHost: 02", "name": "supporthost-blocks/supporthost-02", "category": "layout", "icon": "admin-generic", "editorScript": "file:./block.js", "editorStyle": "file:./editor.css", "style": "file:./style.css" }
- editorStyle: indichiamo il percorso del file css che verrà caricato nell’editor. Tieni presente che questo file viene caricato dopo il foglio di stile del blocco, quindi serve per mostrare degli stili differenti nell’editor.
- style: qui indichiamo il percorso del foglio di stile del blocco, questo file verrà caricato sia nel frontend che nel backend, come ho detto sopra viene caricato prima del foglio di stile dell’editor.
Ho anche cambiato il title e il name del blocco, in modo che siano diversi dal primo blocco che abbiamo creato, e WordPress non faccia confusione tra i blocchi. Allo stesso modo dobbiamo cambiare il name del blocco nel file block.js
Dal momento che chiamiamo due files css, creaiamoli e aggiungiamo il codice necessario.
editor.css:
/* green background */ .wp-block-supporthost-blocks-supporthost-02 { background: #090; color: white; padding: 20px; }
style.css:
/* red background */ .wp-block-supporthost-blocks-supporthost-02 { background: #900; color: white; padding: 20px; }
Adesso attiviamo il plugin e aggiungiamo il blocco su Gutenberg, ovviamente dopo aver fatto un hard refresh della pagina.
Sicuramente hai notato che i css non hanno effetto, nonostante i files vengano caricati correttamente.
Questo perché dobbiamo aggiungere una classe al “p“, sia nell’editor che nel frontend.
Per farlo dobbiamo modificare il file block.js in questo modo:
( function ( blocks, element, blockEditor ) { var el = element.createElement; blocks.registerBlockType( 'supporthost-blocks/supporthost-02', { edit: function ( props ) { var blockProps = blockEditor.useBlockProps(); return el( 'p', blockProps, 'Hello World (from the editor, with css).' ); }, save: function () { var blockProps = blockEditor.useBlockProps.save(); return el( 'p', blockProps, 'Hello World (from the frontend, with css).' ); }, } ); } )( window.wp.blocks, window.wp.element, window.wp.blockEditor );
In pratica usiamo blockEditor.useBlockProps() per aggiungere una classe al blocco. La classe che viene aggiunta è il nome (name) del blocco che usa il simbolo “-” al posto dello slash “/”, si tratta di una semplice convenzione.
Nella documentazione di WordPress viene mostrato anche un secondo modo per dare uno stile inline al blocco, non ho intenzione si spiegarlo qui, primo perché è semplice, secondo perché a breve i nostri fogli di stile diventeranno complessi e non ha senso usare gli stili inline in quel caso.
Ovviamente abbiamo modificato la parte grafica, ma il nostro blocco è del tutto inutile se non possiamo modificare il testo dall’editor.
Vediamo come funzionano gli attributi e i campi modificabili.
Attributi e campi modificabili
Come per il blocco precedente, duplichiamo la cartella di uno dei blocchi, modifichiamo i vari nomi in 3 per avere dei nomi univoci.
Attiviamo il plugin SupportHost block 03 ed iniziamo a modificare i nostri files in modo da creare un blocco modificabile.
Il file da modificare è il file block.js
Iniziamo aggiungendo gli attributi. In pratica definiamo degli attributi del nostro blocco Gutenberg, in questo caso solo “content”, in un esempio successivo ne aggiungeremo più di uno.
attributes: { content: { type: 'string', source: 'html', selector: 'p', }, },
In pratica stiamo creando un attributo chiamato content, che è una string di testo, dentro un tag html “p”.
source
indica la sorgente da cui prendiamo il valore dell’attributo, in questo caso prendiamo il valore dall’HTML che viene salvato nel database dalla funzione save.
Dobbiamo anche definire “example”, che definisce i dati di default per l’anteprima quando cerchiamo di aggiungere il blocco tramite l’inserter.
Non è obbligatorio definire example, se non lo facciamo vediamo un messaggio che indica che l’anteprima non è disponibile.
Per definire un esempio dobbiamo indicare dei valori di default per ogni attributo che abbiamo creato, in questo modo (vedrai altri esempi nei prossimi blocchi):
example: { attributes: { content: 'Hello World', }, },
Nota che gli attributi e gli esempi possono essere inseriti anche nel file block.json, per mantenere una certa coerenza tra i vari blocchi che creiamo in questo tutorial, li aggiungo nel file block.js
La funzione edit cambia molto rispetto agli esempi precedenti, dal momento che adesso usiamo richtext, vediamola insieme:
edit: function ( props ) { var blockProps = useBlockProps(); var content = props.attributes.content; function onChangeContent( newContent ) { props.setAttributes( { content: newContent } ); } return el( RichText, Object.assign( blockProps, { tagName: 'p', onChange: onChangeContent, value: content, placeholder: 'Insert text here...', } ) ); },
Innanzitutto abbiamo una nuova variabile chiamata content, che prende il valore dell’attributo content.
Poi abbiamo una funzione “onChangeContent” che ad ogni modifica del contenuto del blocco, assegna un nuovo valore alla variabile content.
Infine il nostro return, che fa il return di un richtext, qui vediamo:
- blockProps: un oggetto JavaScript che contiene in questo caso la classe che assegniamo al paragrafo.
- tagName: il tag html del blocco che stiamo creando, o di questa sezione del blocco.
- onChange: che richiama la funzione “onChangeContent”. In questo modo ogni volta che eseguiamo una modifica questa viene registrata nella variabile e mostrata come valore.
- value: Il valore del campo modificabile, in questo caso il valore del campo di testo.
- placeholder: il testo da mostrare quando aggiungiamo il blocco, come tutti i placeholder, sparisce per lasciare spazio al testo appena iniziamo a scrivere il nostro testo.
La funzione save a questo punto dovrebbe spiegarsi da sola, qui il risultato finale del nostro file block.js:
( function ( blocks, blockEditor, element ) { var el = element.createElement; var RichText = blockEditor.RichText; var useBlockProps = blockEditor.useBlockProps; blocks.registerBlockType( 'supporthost-blocks/supporthost-03', { attributes: { content: { type: 'string', source: 'html', selector: 'p', }, }, example: { attributes: { content: 'Hello World', }, }, edit: function ( props ) { var blockProps = useBlockProps(); var content = props.attributes.content; function onChangeContent( newContent ) { props.setAttributes( { content: newContent } ); } return el( RichText, Object.assign( blockProps, { tagName: 'p', onChange: onChangeContent, value: content, placeholder: 'Insert text here...', } ) ); }, save: function ( props ) { var blockProps = useBlockProps.save(); return el( RichText.Content, Object.assign( blockProps, { tagName: 'p', value: props.attributes.content, } ) ); }, } ); } )( window.wp.blocks, window.wp.blockEditor, window.wp.element );
Diamo una grafica al nostro blocco, col file style.css:
.wp-block-supporthost-blocks-supporthost-03 { border-left: 7px solid #6754e2; padding: 10px 10px 10px 1.5em; font-style: italic; margin: 3em 0; box-shadow: 0 2px 12px 0 rgb(0 0 0 / 5%), 0 0 35px 0 rgb(0 0 0 / 5%), 0 30px 100px -40px rgb(0 0 0 / 15%); }
Mentre possiamo lasciare in bianco il file editor.css.
Abbiamo creato un blocco come questo, per aggiungere una nota in evidenza nel nostro blog.
È arrivato il momento di dare un po’ di colore al nostro blocco.
Gutenberg block supports
In modo semplicissimo possiamo aggiungere il supporto per dei colori base (testo, sfondo e link) per il nostro blocco.
Per farlo, come prima duplichiamo la cartella per supporthost-block-3 facendolo diventare 4, poi modifichiamo il file block.json in modo che abbia questo codice:
{ "apiVersion": 2, "title": "SupportHost: 04", "name": "supporthost-blocks/supporthost-04", "category": "layout", "icon": "admin-generic", "editorScript": "file:./block.js", "editorStyle": "file:./editor.css", "style": "file:./style.css", "supports": { "color": { "text": true, "background": true, "link": true }, "typography": { "fontSize": true, "lineHeight": true }, "align": true, "spacing": { "margin": true, "padding": true, "blockGap": true } } }
Definiamo “supports” nel file json, vediamo a cosa servono queste voci:
- color: hai la possibilità di scegliere diversi colori, in questo caso ho abilitato la possibilità di scegliere il colore del testo, il colore di sfondo e il colore dei link.
- typography: ci dà la possibilità di scegliere la dimensione del font e l’altezza dell’interlinea.
- align (allinea): aggiunge la possibilità di impostare la larghezza del blocco, questo controllo non si trova nella sidebar, ma nella toolbar direttamente dentro l’editor.
- spacing (dimensioni): ci permette di aggiungere degli strumenti per margine, padding e gap per il nostro blocco.
Per maggiori dettagli e altre opzioni supportate controlla la documentazione di WordPress, qui ho inserito soltanto quelle che ritengo le più comuni e utili.
È importante modificare il nome del selettore nel file style.css in modo che funzioni correttamente con questo blocco Gutenberg.
Allineamento del testo
Duplichiamo ancora una volta l’ultimo blocco Gutenberg che abbiamo creato, modifichiamo il numero da 4 a 5 e aggiungiamo una ulteriore funzione, che ci permetterà di controllare l’allineamento del testo.
Come prima cosa dobbiamo aggiungere un attributo che chiameremo “alignment”:
attributes: { content: { type: 'string', source: 'html', selector: 'p', }, alignment: { type: 'string', default: 'left', }, },
Aggiungiamo il valore nell’example:
example: { attributes: { content: 'Hello World', alignment: 'left', }, },
All’interno della funzione save creiamo una variabile per “alignment” e una funzione per impostare il nuovo valore della variabile quando viene modificato l’allineamento.
var alignment = props.attributes.alignment; function onChangeAlignment( newAlignment ) { props.setAttributes( { alignment: newAlignment === undefined ? 'left' : newAlignment, } ); }
Infine all’interno del return della funzione edit dobbiamo aggiungere un blocco, in questo caso il return della funzione si complica perché dobbiamo ritornare dei “nested divs”
return el( 'div', blockProps, el( BlockControls, { key: 'controls' }, el( AlignmentToolbar, { value: alignment, onChange: onChangeAlignment, } ) ), el( RichText, { key: 'richtext', tagName: 'p', style: { textAlign: alignment }, onChange: onChangeContent, value: content, } ) );
Per la funzione “save” invece usiamo l’attributo alignment per aggiungere una classe, poi tramite il file style.css impostiamo l’allineamento in modo corretto.
save: function ( props ) { var blockProps = useBlockProps.save(); return el( 'div', blockProps, el( RichText.Content, { tagName: 'p', className: 'supporthost-block-align-' + props.attributes.alignment, value: props.attributes.content, } ) ); },
E aggiungiamo al file style.css questo codice:
.supporthost-block-align-left { text-align: left; } .supporthost-block-align-center { text-align: center; } .supporthost-block-align-right { text-align: right; }
Come per gli altri blocchi, possiamo attivare il plugin, fare un hard refresh dell’editor e usare il blocco, in questo caso il blocco SupportHost 05.
Ma come possiamo avere più campi, per creare un blocco Gutenberg più complesso?
Un blocco per le recensioni
Prendiamo come esempio i box che usiamo nel sito di SupportHost per le recensioni:
Per fare qualcosa di simile, quello che farei è usare il blocco colonne di Gutenberg, poi creare un blocco con 3 diversi input, uno per il nome, uno per la posizione/professione ed uno per la recensione.
Vediamo come possiamo creare un blocco di questo tipo.
Prima di tutto duplichiamo il nuovo plugin e cambiamo i vari nomi in modo di passare da 5 a 6, questo sarà il nostro blocco numero 6.
Come prima dobbiamo aggiungere 2 nuovi attributi, uno per il nome e uno per la posizione:
attributes: { name: { type: 'string', source: 'html', selector: '.supporthost-testimonial-name', }, position: { type: 'string', source: 'html', selector: '.supporthost-testimonial-position', }, content: { type: 'string', source: 'html', selector: '.supporthost-testimonial-content', }, alignment: { type: 'string', default: 'center', }, },
Come probabilmente hai notato, in questo caso come “selector” non usiamo un elemento HTML, ma una classe, in modo che da avere un selettore univoco per ogni attributo.
Come abbiamo fatto prima aggiungiamo le voci al nostro esempio:
example: { attributes: { name: 'Ivan', position: 'SupportHost', content: 'Lorem ipsum dolor sit amet..', alignment: 'center' }, },
Ho accorciato il valore di content per semplicità in questo esempio.
Adesso dobbiamo andare a modificare le funzioni edit e save, aggiungendo come prima cosa le variabili per name e position, e le funzioni per l’aggiornamento del valore con la funzione onChange:
var name = props.attributes.name; var position = props.attributes.position; function onChangeName( newName ) { props.setAttributes( { name: newName } ); } function onChangePosition( newPosition ) { props.setAttributes( { position: newPosition } ); }
Quindi aggiungiamo il codice nel return:
el( RichText, { key: 'richtext', tagName: 'p', style: { textAlign: alignment }, onChange: onChangeName, value: name, placeholder: 'Insert name here...' } ), el( RichText, { key: 'richtext', tagName: 'p', style: { textAlign: alignment }, onChange: onChangePosition, value: position, placeholder: 'Insert position here...' } ),
Facciamo lo stesso anche per la funzione save, in questo modo:
el( RichText.Content, { tagName: 'p', className: 'supporthost-testimonial-name supporthost-block-align-' + props.attributes.alignment, value: props.attributes.name, } ), el( RichText.Content, { tagName: 'p', className: 'supporthost-testimonial-position supporthost-block-align-' + props.attributes.alignment, value: props.attributes.position, } ),
Il codice completo di block.js risulta essere:
( function ( blocks, element, blockEditor ) { var el = element.createElement; var RichText = blockEditor.RichText; var useBlockProps = blockEditor.useBlockProps; var BlockControls = blockEditor.BlockControls; var AlignmentToolbar = blockEditor.AlignmentToolbar; blocks.registerBlockType( 'supporthost-blocks/supporthost-06', { attributes: { name: { type: 'string', source: 'html', selector: '.supporthost-testimonial-name', }, position: { type: 'string', source: 'html', selector: '.supporthost-testimonial-position', }, content: { type: 'string', source: 'html', selector: '.supporthost-testimonial-content', }, alignment: { type: 'string', default: 'center', }, }, example: { attributes: { name: 'Ivan', position: 'SupportHost', content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec egestas semper feugiat. Proin tempus sem nec sapien pulvinar tristique vitae ac odio. Ut laoreet ligula id auctor hendrerit. Aliquam rutrum eu enim quis sollicitudin. Donec ut bibendum nisl. Etiam tempor, dolor id interdum vehicula, metus tortor vestibulum lorem, nec volutpat eros odio id orci. Donec vitae suscipit orci. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Ut malesuada luctus lectus, at ullamcorper dolor tempor in. Sed sed ex ullamcorper, convallis elit et, interdum elit. Etiam massa magna, cursus eget lorem vel, varius malesuada nibh. Donec non enim interdum, pellentesque enim efficitur, scelerisque turpis. Fusce lacus nulla, consectetur sed orci quis, luctus interdum nisi.', alignment: 'center' }, }, edit: function ( props ) { var blockProps = useBlockProps(); var name = props.attributes.name; var position = props.attributes.position; var content = props.attributes.content; var alignment = props.attributes.alignment; function onChangeName( newName ) { props.setAttributes( { name: newName } ); } function onChangePosition( newPosition ) { props.setAttributes( { position: newPosition } ); } function onChangeContent( newContent ) { props.setAttributes( { content: newContent } ); } function onChangeAlignment( newAlignment ) { props.setAttributes( { alignment: newAlignment === undefined ? 'center' : newAlignment, } ); } return el( 'div', blockProps, el( BlockControls, { key: 'controls' }, el( AlignmentToolbar, { value: alignment, onChange: onChangeAlignment, } ) ), el( RichText, { key: 'richtext', tagName: 'p', style: { textAlign: alignment }, onChange: onChangeName, value: name, placeholder: 'Insert name here...' } ), el( RichText, { key: 'richtext', tagName: 'p', style: { textAlign: alignment }, onChange: onChangePosition, value: position, placeholder: 'Insert position here...' } ), el( RichText, { key: 'richtext', tagName: 'p', style: { textAlign: alignment }, onChange: onChangeContent, value: content, placeholder: 'Insert review here...' } ) ); }, save: function ( props ) { var blockProps = useBlockProps.save(); return el( 'div', blockProps, el( RichText.Content, { tagName: 'p', className: 'supporthost-testimonial-name supporthost-block-align-' + props.attributes.alignment, value: props.attributes.name, } ), el( RichText.Content, { tagName: 'p', className: 'supporthost-testimonial-position supporthost-block-align-' + props.attributes.alignment, value: props.attributes.position, } ), el( RichText.Content, { tagName: 'p', className: 'supporthost-testimonial-content supporthost-block-align-' + props.attributes.alignment, value: props.attributes.content, } ) ); }, } ); } )( window.wp.blocks, window.wp.element, window.wp.blockEditor );
Abbiamo bisogno di alcuni aggiustamenti al file style.css in modo che il blocco abbia una grafica accattivante. Diamo una dimensione del font superiore al nome, mentre riduciamo la dimensione del font della posizione e del testo delle recensione:
.wp-block-supporthost-blocks-supporthost-06 { border-top: 5px solid #fca249; padding: 25px; transition-property: all; transition-duration: 0.5s; box-shadow: 0 5px 6px 0 rgb(0 0 0 / 23%); } .supporthost-testimonial-name { margin-top: 30px; font-weight: 700; font-size: 1.25em; } .supporthost-testimonial-position { margin-top: 15px; opacity: 0.75; font-size: 0.75em; } .supporthost-testimonial-content { margin-top: 15px; font-size: 0.75em; } .wp-block-supporthost-blocks-supporthost-06:hover { transform: scale(1.05,1.05); } .supporthost-block-align-left { text-align: left; } .supporthost-block-align-center { text-align: center; } .supporthost-block-align-right { text-align: right; }
E siamo pronti ad usare il blocco, ovviamente solo dopo aver attivato il plugin e fatto un hard refresh della pagina dell’editor.
E se vogliamo aggiungere un’immagine?
Creare un blocco con una immagine
Se vogliamo aggiungere un’immagine a un blocco Gutenberg, dobbiamo aggiungere 2 diversi attributi, uno per l’ID dell’immagine e uno per l’url.
Dovremo aggiungere una nuova dipendenza nel file block.js, components.
E ovviamente modificare le funzioni edit e save.
Iniziamo.
Dopo che abbiamo duplicato il plugin e modificato i nomi per dargli un nuovo numero, aggiungiamo la nuova dipendenza in questo modo:
( function ( blocks, element, blockEditor, components ) { ... } )( window.wp.blocks, window.wp.element, window.wp.blockEditor, window.wp.components );
Aggiungiamo i 2 attributi che ci servono per l’immagine:
attributes: { mediaID: { type: 'number', }, mediaURL: { type: 'string', source: 'attribute', selector: 'img', attribute: 'src', }, name: { type: 'string', source: 'html', selector: '.supporthost-testimonial-name', }, position: { type: 'string', source: 'html', selector: '.supporthost-testimonial-position', }, content: { type: 'string', source: 'html', selector: '.supporthost-testimonial-content', }, alignment: { type: 'string', default: 'center', }, },
E come negli altri casi aggiungiamo gli stessi dati nell’example:
example: { attributes: { name: 'Ivan', position: 'SupportHost', content: 'Lorem ipsum dolor sit amet...', alignment: 'center', mediaID: 1, mediaURL: 'https://images.unsplash.com/photo-1549150712-1d243024db80?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1480&q=80', }, },
In questo caso ho usato un link verso un’immagine su unsplash da mostrare nell’anteprima, sperando che non verrà eliminata, in caso nell’anteprima si vedrà un’immagine mancante.
Anche qui ho accorciato il contenuto di content, per semplificare il codice.
Adesso andiamo ad aggiungere la variabile e la funzione per l’immagine all’interno della funzione edit:
var mediaID = props.attributes.mediaID; var mediaURL = props.attributes.mediaURL; var onSelectImage = function ( media ) { return props.setAttributes( { mediaURL: media.url, mediaID: media.id, } ); };
Il prossimo passo è aggiungere il codice nel return della funzione edit per mostrare il bottone per aggiungere un’immagine direttamente nel blocco.
Ho deciso di mostrare un’immagine prima del nome, la foto della persona che lascia la recensione.
el( 'div', { className: 'supporthost-testimonial-image', style: { textAlign: alignment }, }, el( MediaUpload, { onSelect: onSelectImage, allowedTypes: 'image', value: mediaID, render: function ( obj ) { return el( components.Button, { className: mediaID ? 'image-button' : 'button button-large', onClick: obj.open, }, ! mediaID ? 'Upload Image' : el( 'img', { src: mediaURL } ) ); }, } ) ),
Allo stesso modo dobbiamo modificare il return della funzione save:
el( 'div', { className: 'supporthost-testimonial-image supporthost-block-align-' + props.attributes.alignment, }, el( 'img', { src: props.attributes.mediaURL } ) ),
Per questioni di semplicità ti consiglio di scaricare il file da GitHub per controllare il codice completo.
Per avere un effetto grafico più carino ho aggiunto del codice css al file style.css precedente, nel dettaglio ho aggiunto:
.supporthost-testimonial-image img { border-radius: 100%; max-width: 125px; border: 3px solid #000; }
E per sistemare al meglio l’immagine nell’editor ho aggiunto nel file editor.css:
.supporthost-testimonial-image img { margin-top: 50%; }
Questo è l’aspetto dei due blocchi che abbiamo creato per le recensioni. Quello a sinistra è l’esempio precedente, senza immagine, e quello a destra è quello in cui abbiamo inserito l’immagine.
Ecco come vediamo i nostri due blocchi nell’editor:
E qui ti mostro i blocchi Gutenberg che abbiamo creato con un esempio in cui abbiamo inserito testo e immagini:
Inoltre, non so se avevi notato che nel blocco precedente il nome, la posizione e il testo della recensione non avevano uno stile, in questo blocco ho risolto aggiungendo le diverse classi in questo modo nell’HTML dell’editor.
className: 'supporthost-testimonial-name',
Fino ad ora abbiamo creato dei blocchi statici, ma come possiamo prendere dei dati dal database in tempo reale e creare dei blocchi dinamici?
Ad esempio, come possiamo fare se vogliamo mostrare la lista degli ultimi 10 post?
Creare un blocco dinamico
Per creare un blocco dinamico non serve la funzione save. I dati infatti vengono presi in tempo reale dal database, e non avrebbe senso scrivere la lista degli ultimi 10 post nel database.
Iniziamo col creare una cartella che chiameremo “supporthost-block-8” e il relativo file “supporthost-block-8.php”.
Il file php avrà questo codice:
<?php /** * Plugin Name: SupportHost block 08 */ function supporthost_block_dynamic_render_callback( $block_attributes, $content ) { $recent_posts = wp_get_recent_posts( array( 'numberposts' => 3, 'post_status' => 'publish', ) ); if ( count( $recent_posts ) === 0 ) { return 'No posts yet'; } $return = '<ul>'; foreach ( $recent_posts as $post ) { $return .= sprintf( '<li><a class="wp-block-my-plugin-latest-post" href="%1$s">%2$s</a></li>', esc_url( get_permalink( $post['ID'] ) ), esc_html( get_the_title( $post['ID'] ) ) ); } $return .= '</ul>'; return $return; } function supporthost_block_08_register_block() { register_block_type( __DIR__ , array( 'render_callback' => 'supporthost_block_dynamic_render_callback' ) ); } add_action( 'init', 'supporthost_block_08_register_block' );
La prima funzione “supporthost_block_dynamic_render_callback” è la funzione callback.
In altre parole è la funzione che cerca gli ultimi post nel database, e restituisce il codice HTML che visualizzeremo nell’editor e nel frontend del sito.
La funzione “supporthost_block_08_register_block”, come per gli altri blocchi, serve a registrare il blocco, chiamando il file block.json con la differenza che qui passiamo nel secondo paragrafo un array per chiamare la funzione di callback.
Creiamo il file block.asset.php ed inseriamo questo codice:
<?php return array( 'dependencies' => array( 'wp-blocks', 'wp-element', 'wp-block-editor', 'wp-polyfill', 'wp-server-side-render' ), 'version' => '0.1' );
Dal momento che vogliamo usare serverSideRender per vedere il widget identico sia nell’editor che nel frontend.
Creiamo il file block.json, che come per gli altri blocchi contiene le informazioni del blocco, nel nostro caso specifico:
{ "apiVersion": 2, "title": "SupportHost: 08", "name": "supporthost-blocks/supporthost-08", "category": "layout", "icon": "admin-generic", "editorScript": "file:./block.js", "editorStyle": "file:./editor.css", "style": "file:./style.css" }
Dal momento che sto chiamando i files style.css e editor.css, li creo ma li lascio vuoti per il momento.
Creo il file block.js con il seguente codice:
( function ( blocks, element, serverSideRender, blockEditor ) { var el = element.createElement, registerBlockType = blocks.registerBlockType, ServerSideRender = serverSideRender, useBlockProps = blockEditor.useBlockProps; registerBlockType( 'supporthost-blocks/supporthost-08', { edit: function ( props ) { var blockProps = useBlockProps(); return el( 'div', blockProps, el( ServerSideRender, { block: 'supporthost-blocks/supporthost-08', attributes: props.attributes, } ) ); }, } ); } )( window.wp.blocks, window.wp.element, window.wp.serverSideRender, window.wp.blockEditor );
In pratica abbiamo soltanto la funzione edit, che restituisce il codice che generiamo con la funzione php di callback.
Se hai seguito il tutorial fino a qui, questo codice dovrebbe spiegarsi da solo.
Definiamo delle variabili e abbiamo un return per la funzione edit.
Conclusioni
In questo tutorial abbiamo imparato come creare dei blocchi Gutenberg personalizzati usando JavaScript. Siamo partiti da un esempio basilare per comprendere la struttura di un blocco.
Con esempi via via più complessi abbiamo visto quali sono le potenzialità dei blocchi e cosa ci permettono di fare.
Adesso dovresti avere le basi per creare i blocchi in base alle tue esigenze.
È tutto chiaro? Sei riuscito a seguire il tutorial e a creare dei nuovi blocchi? Fammi sapere con un commento.
Lascia un commento