Creació d'un bloc Gutenberg

Creació d’un bloc Gutenberg

Editor de Blocs WordPress. Creació de blocs.

Crearem un nou bloc de contingut dinàmic, implementant en JavaScript. En aquest exemple, el bloc serà la imatge destacada de l’entrada i un enllaç a l’article de l’entrada, podent triar l’usuari l’entrada a mostrar mitjançant una recerca o les 30 últimes entrades.

Per a això utilitzarem la funció registerBlockType. Aquesta funció és responsable d’especificar el model d’un bloc, descrivint els comportaments necessaris perquè l’editor comprengui com apareix, canvia quan s’edita i, en última instància, es guarda en el contingut de la publicació.

Els blocs han de registrar-se al servidor per assegurar-se que l’script es col·loca en cua quan es carrega l’editor. Registrarem els scripts i estils usant wp_register_script i wp_register_style, després assignarem aquests com a identificadors associats al bloc usant la configuració de registre de tipus de bloc script, style, editor_script i editor_style. Els identificadors amb prefix editor_ només es col·locaran en cua en el context de l’editor, mentre que la seqüència de comandaments i l’estil es col·locaran tant en l’editor com en el procés de visualització.

<?php
/*
 *************************************************************
 * Plugin Name: Doowebs Gutenberg blocks
 * Description: Gutenberg blocks.
 * Author: Doowebs
 * Version: 0.0
 *************************************************************
 */
function dw-guten_block_register_block() {
  wp_register_script(
        'dwguten-block',
        plugins_url('block.js',__FILE__),
        array('wp-blocks','wp-editor','wp-element','wp-components','wp-data','wp-i18n'),
        filemtime(plugin_dir_path(__FILE__).'block.js')
  );
}
add_action('init','dwguten_block_register_block');

Cal tenir en compte les dependències de l’script, per exemple:

wp-blocks, inclou registre de tipus de bloc i funcions relacionades.
wp-element, inclou l’abstracció d’elements de WordPress per descriure l’estructura dels blocs.
wp-editor, inclou el component RichText,

Registrar el bloc

Amb l’script en cua, vegem la implementació del bloc en si (arxiu block.js):

( function( blocks, editor, element, components, data, i18n ) {
    var el = element.createElement;
    var InspectorControls = editor.InspectorControls;
    var PanelBody = components.PanelBody;
    var PanelRow = components.PanelRow;
    var SelectControl = components.SelectControl;
    var TextControl = components.TextControl;
    var withSelect = data.withSelect;
    var Button = components.Button;

    blocks.registerBlockType( 'dwguten-block/post', {
        title: i18n.__('Article Link'),
        icon: 'pressthis',
        category: 'doowebs-category',

        attributes: { 
            post_id: {
                type: 'number',
                default: 0,
            },
            post_title: {
                type: 'string',
                default: '',
            },
            search_text: {
                type: 'string',
                default: '',
            },
            search_text_sel: {
                type: 'string',
                default: '',
            },
        },

        edit: withSelect(function(select,props) {
            var postToShow=30;
            var searchTextSel=props.attributes.search_text_sel;
            var query = {
                per_page: postToShow,
                search: searchTextSel,
            };
            return {
                posts:select('core').getEntityRecords('postType','post',query)
            };
        })(function(props) {
            var postId=props.attributes.post_id;
            var postTitle=props.attributes.post_title;
            if (!props.posts) {
                return i18n.__('Cargando ...');
            }
            var className=props.className;
 

            let options = [{value:0,label:i18n.__('Selecciona una entrada')}];
            var i=0;
            while (i<props.posts.length) {
                options.push({value:props.posts[i].id,label:props.posts[i].title.raw});
                i++;
            }
            i=0;
            while (i<props.posts.length&&props.posts[i].id!=props.attributes.post_id) {i++;}
            if (i<props.posts.length) {
                props.setAttributes({post_title:props.posts[i].title.raw});
            }
            return [ 
                el(InspectorControls,{},
                    el(PanelBody,
                        {
                        title: i18n.__("Selección de entrada"),
                        initialOpen: true,
                        },
                        el(PanelRow,{},
                            el(TextControl,{
                                type: 'text',
                                label: i18n.__('Buscar'),
                                onChange: function (content) {
                                    props.setAttributes({search_text:content});
                                },
                                value: props.attributes.search_text,
                            }),
                            el(Button,{
                                className: 'components-button editor-post-preview is-button is-default is-large',
                                type: 'button',
                                onClick: function () {
                                    props.setAttributes({search_text_sel:props.attributes.search_text});
                               },
                            },i18n.__('Buscar')),
                        ),
                        el(PanelRow,{},
                            el(SelectControl,{
                                label: i18n.__('Entrada'),
                                options: options,
                                onChange: function (value) {
                                    props.setAttributes({post_id:parseInt(value)});
                                },
                                value: props.attributes.post_id,
                            }),
                        ),
                    ),
                ),
                el('p',{className:className+' head'},i18n.__('Article link')),
                el('p',{className:className+' title'},postTitle),
            ];
        }),

        save: function(props) {
            return null;
        },
    } );
}(
    window.wp.blocks,
    window.wp.editor,
    window.wp.element,
    window.wp.components,
    window.wp.data,
    window.wp.i18n,
) );

Una vegada que es registra un bloc, aquest està disponible com una opció en el quadre de diàleg d’inserció de l’editor, utilitzant valors del títol, icona i categoria per organitzar la seva visualització. Podeu triar una icona de qualsevol dels inclosos en el conjunt d’icones Dashicons incorporat, o proporcionar un element svg personalitzat.

El nom d’un bloc ha de tenir com a prefix un espai de noms específic per a la seva complement. Això ajuda a evitar conflictes quan més d’un complement registra un bloc amb el mateix nom. En aquest exemple, l’espai de noms és dwguten.

Les funcions edit i save descriuen l’estructura del seu bloc en el context de l’editor i el contingut guardat per al front-end, respectivament. Podent definir la personalització del bloc a la part de l’editor i en la part del front-end.

Col·loca en cua els estils del bloc per a l’editor i el front-end.
Igual que els scripts, han de posar-se en cua els estils del bloc. S’utilitzarà el controlador editor_style per als estils que només són rellevants en l’editor, i el controlador d’estil per als estils comuns aplicats tant en l’editor com al front-end.
El codi per als estils l’editor els vam passar a l’arxiu editor.css:

.wp-block-dwguten-block-post.title {
  color:navy;
  background: paleturquoise;
  border: 1px solid #c99;
  padding: 3px;
  margin: 0;
  width: 100%;
  text-align: center;
  display: flex;
  justify-content: center;
  flex-direction: column;
  min-height: 100px;
}

i els estils per al front-end a l’arxiu style.css, que en el nostre cas ho deixarem buit.

Al fitxer del plugin (guten-plugin.php) registrem aquests fitxers

<?php
/*
 *************************************************************
 * Plugin Name: Doowebs dwguten blocks
 * Description: Gutenberg blocks.
 * Author: Doowebs
 * Version: 0.0
 *************************************************************
 */
function dwguten_block_register_block() {
  wp_register_style(
      'dwguten-block-editor',
      plugins_url( 'editor.css', __FILE__ ),
      array( 'wp-edit-blocks' ),
      filemtime( plugin_dir_path( __FILE__ ) . 'editor.css' )
  );
  wp_register_style(
      'dwguten-block-style',
      plugins_url( 'style.css', __FILE__ ),
      array( ),
      filemtime( plugin_dir_path( __FILE__ ) . 'style.css' )
  );
}
add_action( 'init', 'dwguten_block_register_block' );

Atributs

Les funcions edit i save són responsables de descriure l’estructura de l’aparença del bloc en l’editor i en front-end, respectivament. Si l’usuari canvia un bloc, aquesta estructura pot necessitar canviar-la. Per aconseguir això, l’estat d’un bloc es manté durant tota la sessió d’edició com un objecte JavaScript simple, i quan ocorre una actualització, la funció d’edició s’invoca novament. Dit d’una altra manera: l’exida d’un bloc és una funció dels seus atributs.

Un desafiament de mantenir la representació d’un bloc com un objecte JavaScript és que hem de poder extreure aquest objecte novament del contingut guardat d’una publicació. Això s’aconsegueix amb la propietat d’atributs del tipus de bloc:

       attributes: { 
            post_id: {
                type: 'number',
                default: 0,
            },
            post_title: {
                type: 'string',
                default: '',
            },
            search_text: {
                type: 'string',
                default: '',
            },
            search_text_sel: {
                type: 'string',
                default: '',
            },
        },

En registrar un nou tipus de bloc, la propietat d’atributs descriu la forma de l’objecte d’atributs que li agradaria rebre en les funcions edit i save. Cada valor és una funció font per trobar el valor desitjat del bloc.

En el fragment de codi anterior, en carregar l’editor, el valor del contingut s’extraurà de l’HTML de l’element de paràgraf en la funció edit.

Controls del bloc: barra lateral

En l’editor podem establir els components en el bloc o a la barra lateral (inspector).

La barra lateral de configuració s’utilitza per mostrar configuracions menys utilitzades o configuracions que requereixen més espai a la pantalla. La barra lateral de configuració ha d’usar-sol per a la configuració de nivell de bloc.
Si té configuracions que afecten només el contingut seleccionat dins d’un bloc. La barra lateral de configuració es mostra fins i tot quan s’edita un bloc a mode HTML, de manera que només ha de contenir configuracions de nivell de bloc.
La pestanya Bloc es mostra en lloc de la pestanya Document quan es selecciona un bloc.
De manera similar a la representació d’una barra d’eines, si inclou un element InspectorControls en el valor de retorn de la funció d’edició del seu tipus de bloc, aquests controls es mostraran a la regió de la barra lateral de configuració.

Blocs dinàmics

Els blocs dinàmics són blocs que construeixen la seva estructura i contingut sobre la marxa quan el bloc es representa al front-end.
Els blocs dinàmics es poden utilitzar per a la representació d’entrades que poden ser actualitzades o blocs en què cal fer actualització del codi (HTML, CSS, JS). Aquest és el cas d’agregació de classes o elements HTML que canviïn el disseny del front-end: això s’aconsegueix amb el usos de blocs dinàmics assegurant que aquests s’apliquin.
Per a molts blocs dinàmics, la funció save s’ha de retornar com a nul·la, la qual cosa li indica a l’editor que guardi els atributs del bloc a la base de dades. Aquests atributs després es passen a la representació del costat del servidor, perquè pugui decidir com mostrar el bloc en el front-end del lloc.
Els atributs de bloc es poden usar per a qualsevol contingut o configuració que vulgueu desar per a aquest bloc. Per exemple, els atributs es poden usar per a cada contingut que desitgi mostrar al front-end, com el text de la capçalera, el text del paràgraf, una imatge, un URL, etc.

En l’exemple de codi anterior es mostrava un tipus de bloc dinàmic per mostrar una entrada (block.js).

A causa de que és un bloc dinàmic, cal un component de servidor. El contingut en el front-end del seu lloc depèn de la funció anomenada per la propietat render_callback de register_block_type.

<?php
/*
 *************************************************************
 * Plugin Name: Doowebs dwguten blocks
 * Description: Gutenberg blocks
 * Author: Doowebs
 * Version: 0.0
 *************************************************************
 */
 
function dwguten_block_register_block() {

  register_block_type( 'dwguten-block/post', array(
    'style' => 'dwguten-block-style',
    'editor_style' => 'dwguten-block-editor',
    'editor_script' => 'dwguten-block',
    'attributes' => array(
      'post_id'     => array('type'=>'number',),
      'post_title'  => array('type'=>'string',),
      'search_text' => array('type'=>'string',),
      'search_text_sel' => array('type'=>'string',),
    ),
    'render_callback' => 'dwguten_block_dynamic_render_callback_post',
  ));
}
add_action( 'init', 'dwguten_block_register_block' );

function dwguten_block_dynamic_render_callback_post($attributes) {
    $post_id=$attributes['post_id'];
    $post=get_post($post_id);
    $category=get_the_category($post_id);
    $video=false;
    if (!empty($category)) {
      $i=0;
      while ($i<sizeof($category)) {
        if ($category[$i]->cat_name=='Vídeos') {$video=true;}
        $i++;
      }
    }
    $videost='';
    if ($video) {$videost='<img src="\wp-content\themes\tema\images\ic_playCircle.svg" class="video-logo" alt="Video-logo" />';}
    $bc=
        '<section class="article-link">'.
            '<a class="article-title-link" href="'.esc_url(get_permalink($post_id)).'">'.
                '<h2 class="article-title">'.get_the_title($post_id).'</h2>'.
            '</a>'.
            '<a class="thumbnail-link" href="'.esc_url(get_permalink($post_id)).'">'.
                '<span class="photo-overlay"></span>'. 
                get_the_post_thumbnail($post_id).
                $videost.
            '</a>'.
            '<div class="article-excerpt">'.the_excerpt_m($post_id).'</div>'.
            '<a class="article-link-btn" href="'.esc_url(get_permalink($post_id)).'">'.
                esc_html__('Ir al artículo').
            '</a>'.
        '</section>';
    return $bc;
}
 
?>

Amb la definició dels arxius guten-plugin.php, block.js, editor.css i style.css en una carpeta dins de plugins del nostre projecte WordPress haurem definit un plugin, que un cop activat, disposarem d’un nou bloc en el nostre editor gutenberg, disponible per a les nostres entrades. En aquest cas, es genera un bloc amb la imatge destacada de l’entrada, que en el cas de ser de la categoria Vídeos es mostrarà amb la icona play (tenir en compte afegir l’arxiu d’imatge ic_playCircle.svg a la ruta indicada en el codi), i un enllaç a l’entrada (Ir al artículo).

Finalment, caldria afegir el codi css per al nostre front-end a l’arxiu style.css del nostre tema WordPress, per exemple:

/* CSS Articulo link */
.article-link {
  width: 100%;
  margin: 24px 0 14px;
  background-color: #F9FBFC;
  padding: 10px 15px 50px;
}
.article-link .article-title {
  color: #25343D;
  font-family: Archia;
  font-size: 24px;
  font-weight: bold;
  line-height: 36px;
}
.article-link .article-title:hover {
  color: #71EB6C;
}
.article-link .thumbnail-link {
  display: block;
  width: 100%;
  position: relative;
}
.article-link .photo-overlay {
  background: rgba(0,0,0,0);
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  top: 0;
  margin: 0;
  z-index: 5;
}
.article-link .photo-overlay:hover {
  background: rgba(0,0,0,0.4);
}
.article-excerpt {
  width: 100%;
  margin: 0;
  background-color: #F9FBFC;
  padding: 15px 0;
  color: #25343D; 
  font-size: 16px;  
  line-height: 24px;
}
.article-link-btn {
  color: #336BEF;
  font-size: 16px;
  font-weight: bold;
  line-height: 24px;
}