Inicio / Creando plugins para WordPress / Creando bloques para Gutenberg, el nuevo editor de WordPress.
15 mayo,2018
0
creando bloques para gutenberg
mayo 15, 2018| Escrito por | | en Creando plugins para WordPress

Creando bloques para Gutenberg, el nuevo editor de WordPress.

Creando bloques para Gutenberg, el nuevo editor de WordPress.
1 5

Con esta guía pretendemos mostrar cómo crear bloques para Gutenberg, recordemos que el proyecto gutenberg cambiara el editor TinyMCE  de WordPress  por un nuevo editor que le dara al usuario final la posibilidad de maquetar sus páginas visualmente.

Todos los contenidos se podrán cargar desde bloques, hablamos de un párrafo, una imagen, un botón, video , audio, todo dependerá de la creatividad de los desarrolladores. Los bloques serán la nueva unidad de información que le permitirá al webmaster maquetar su página web.

Cómo crear un bloque personalizado para Gutenberg

Los bloques para el nuevo editor de WordPress se desarrollan principalmente en los lenguajes de JavaScript ES5 y ESNext y esto podrìa intimidar a cualquier desarrollador WordPress. En este momento no hay mucha documentación  para construir bloques personalizados, pero recopilando distintos articulos que mencionaremos al final logramos construir un bloque personalizado para un perfil de Usuario. Aprenderemos mucho en el proceso.

El Bloque de perfil presentara una imagen, un nombre, un título, la biografía y enlaces de redes sociales. Este bloque podrá ser “Editable” por el usuario,  con controles personalizados y opciones de inspector.  Esencialmente, utiliza todos los aspectos de los bloques.

El plugin de “Bloque de perfil” está disponible en Github y en el directorio de plugins de WordPress. Este Bloque de perfil requiere el complemento Gutenberg activo en este momento.Esto hasta que el nuevo editor de WordPress se integre oficialmente.

Creando bloques para Gutenberg con ES5.

Construir bloques para gutenberg usando ES5 ( JavaScript) tiene almenos 2 ventajas. Primero, es lo más fácil de entender  para los desarrolladores WordPress que no tienen mucha experiencia con javascript. En segundo lugar, ES5 es compatible con navegadores modernos. Entonces, los programadores WordPress pueden desarrollarse localmente sin necesidad de un compilador como Babel.

Antes de profundizar en el código, es importante observar  la estructura general de archivos que tendra nuestro plugin. Por si no lo sabian, debemos crear un plugin que habilite un nuevo bloque personalizado en gutenberg. Esto nos dará una mejor comprensión de los componentes necesarios que componen un bloque.

Listado de archivos y carpetas para crear un bloque personalizado para gutenberg

  1. organic-profile-block.php : Registro de  nuestro plugin y llamar a nuestros archivos de bloque.
  2. includes : Carpeta para cualquier recurso de bloque global. En este caso, nuestras fuentes.
  3. fonts : Carpeta para archivos de fuentes Font Awesome.
  4. block:  Carpeta para bloques personalizados.
  5. perfil : Carpeta para el bloque de perfil.
  6. block.js : El archivo JavaScript donde registramos nuestro bloque personalizado.
  7.  editor.css: Los estilos para ver el bloque dentro del editor de Gutenberg.
  8. font-awesome.css : Los estilos para nuestros iconos de Font Awesome.
  9. index.php – El archivo para encolar los activos del bloque.
  10.  style.css: los estilos para la apariencia de front-end del bloque.

crear bloques para gutenberg

Enconlando Scripts y estilos.

Comenzaremos por poner en cola nuestros scripts y estilos en el archivo index.php. Este es el grueso de PHP con el que trabajaremos.
Primero, encolaremos nuestro archivo personalizado  block.js y los estilos para ver el bloque dentro  del editor:

function organic_profile_block_editor_assets() {
	// Scripts.
	wp_enqueue_script(
		'organic-profile-block', // Handle.
		plugins_url( 'block.js', __FILE__ ), // Block.js: We register the block here.
		array( 'wp-blocks', 'wp-i18n', 'wp-element' ), // Dependencies, defined above.
		filemtime( plugin_dir_path( __FILE__ ) . 'block.js' ) // filemtime — Gets file modification time.
	);

	// Styles.
	wp_enqueue_style(
		'organic-profile-block-editor', // Handle.
		plugins_url( 'editor.css', __FILE__ ), // Block editor CSS.
		array( 'wp-edit-blocks' ), // Dependency to include the CSS after it.
		filemtime( plugin_dir_path( __FILE__ ) . 'editor.css' ) // filemtime — Gets file modification time.
	);
} // End function organic_profile_block_editor_assets().

// Hook: Editor assets.
add_action( 'enqueue_block_editor_assets', 'organic_profile_block_editor_assets' );

A continuación, encolaremos los estilos para el front-end:

function organic_profile_block_block_assets() {
	// Styles.
	wp_enqueue_style(
		'organic-profile-block-frontend', // Handle.
		plugins_url( 'style.css', __FILE__ ), // Block frontend CSS.
		array( 'wp-blocks' ), // Dependency to include the CSS after it.
		filemtime( plugin_dir_path( __FILE__ ) . 'style.css' ) // filemtime — Gets file modification time.
	);
	wp_enqueue_style(
		'organic-profile-block-fontawesome', // Handle.
		plugins_url( 'font-awesome.css', __FILE__ ) // Font Awesome for social media icons.
	);
} // End function organic_profile_block_block_assets().

// Hook: Frontend assets.
add_action( 'enqueue_block_assets', 'organic_profile_block_block_assets' );

Registrando el bloque

Dentro del archivo block.js, comenzaremos envolviendo nuestro bloque en una función con sus dependencias. Las dependencias deben coincidir con lo que se definió previamente en nuestro archivo index.php:

 function( blocks, i18n, element ) {

	// Our custom block code.

} )(
	window.wp.blocks,
	window.wp.i18n,
	window.wp.element,
);

A continuación, importaremos los componentes necesarios para nuestro bloque. Hay muchos componentes disponibles. Lamentablemente, no encontramos una biblioteca que enumere todos los componentes con descripciones. Entonces, encontrar y usar los componentes correctos ha sido un proceso de prueba y error.

( function( blocks, i18n, element ) {
	var el = element.createElement;
	var children = blocks.source.children;
	var BlockControls = wp.blocks.BlockControls;
	var AlignmentToolbar = wp.blocks.AlignmentToolbar;
	var MediaUploadButton = wp.blocks.MediaUploadButton;
	var InspectorControls = wp.blocks.InspectorControls;
	var TextControl = wp.blocks.InspectorControls.TextControl;
  
 } )(
	window.wp.blocks,
	window.wp.i18n,
	window.wp.element,
);

Registrando el bloque personalizado.

blocks.registerBlockType( 'organic/profile-block', { // The name of our block. Must be a string with prefix. Example: my-plugin/my-custom-block.
	title: i18n.__( 'Profile' ), // The title of our block.
	icon: 'businessman', // Dashicon icon for our block. Custom icons can be added using inline SVGs.
	category: 'common', // The category of the block.
	attributes: { // Necessary for saving block content.
		title: {
			type: 'array',
			source: 'children',
			selector: 'h3',
		},
		subtitle: {
			type: 'array',
			source: 'children',
			selector: 'h5',
		},
		bio: {
			type: 'array',
			source: 'children',
			selector: 'p',
		},
		mediaID: {
			type: 'number',
		},
		mediaURL: {
			type: 'string',
			source: 'attribute',
			selector: 'img',
			attribute: 'src',
		},
		href: {
			type: 'url',
		},
		alignment: {
			type: 'string',
			default: 'center',
		},
		facebookURL: {
			type: 'url',
		},
		twitterURL: {
			type: 'url',
		},
		instagramURL: {
			type: 'url',
		},
		linkedURL: {
			type: 'url',
		},
		emailAddress: {
			type: 'string',
		}
	},

} );

Editar y guardar

Ahora que hemos registrado nuestro bloque personalizado, necesitamos construir la interfaz. La interfaz de bloque se compone de 2 partes. La función de edición es la interfaz para el bloque  dentro del editor. La función de guardar guarda la salida del bloque para el front-end. Si eres como yo,  y JavaScript no es tu fortaleza, puede ser más fácil pensar en definir los elementos de la misma forma que lo harías con las etiquetas para HTML. Por ejemplo, tomemos este elemento de bloque simple:

el( 'div', { className: 'components-block-description' },
  el( 'p', {}, i18n.__( 'Add links to your social media profiles.' ) ),
),

Es esencialmente lo mismo que este HTML:


<div class="components-block-description">

<p>Add links to your social media profiles.</p>

</div>

La función de edición

Voy a dividir la función de edición en 4 partes: declarar variables, controles de bloque, controles de inspector y los elementos de nuestro bloque.
Primero, configuraremos nuestra función de edición y declararemos las variables:

edit: function( props ) {

	var focus = props.focus;
	var focusedEditable = props.focus ? props.focus.editable || 'title' : null;
	var alignment = props.attributes.alignment;
	var attributes = props.attributes;
	var facebookURL = props.attributes.facebookURL;
	var twitterURL = props.attributes.twitterURL;
	var instagramURL = props.attributes.instagramURL;
	var linkedURL = props.attributes.linkedURL;
	var emailAddress = props.attributes.emailAddress;

	var onSelectImage = ( media ) => {
		props.setAttributes( {
			mediaURL: media.url,
			mediaID: media.id,
		} );
	};
	var onSetHref = ( value ) => {
		props.setAttributes( {
			href: value,
		} );
	};

	function onChangeAlignment( newAlignment ) {
		props.setAttributes( { alignment: newAlignment } );
	}
	
	return [

		// We build the editor interface of our block here.
		
	];
},

A continuación, configuremos nuestros controles de bloque. Esta sección define los controles disponibles dentro del editor  TinyMCE para el bloque. En este caso, estamos agregando controles de alineación de contenido y un botón de carga multimedia para agregar y cambiar nuestra imagen de perfil:

focus && el( // Display controls when the block is clicked on.
    blocks.BlockControls,
    { key: 'controls' },
    el(
        blocks.AlignmentToolbar,
        {
            value: alignment,
            onChange: onChangeAlignment,
        }
    ),
    el( 'div', { className: 'components-toolbar' },
        el(
            blocks.MediaUploadButton,
            {
                buttonProps: {
                    className: 'components-icon-button components-toolbar__control',
                    'aria-label': i18n.__( 'Edit image' ),
                },
                onSelect: onSelectImage,
                onChange: onSetHref,
                type: 'image',
                url: attributes.href,
            },
            el( 'svg', { className: 'dashicon dashicons-edit', width: '20', height: '20' },
                el( 'path', { d: "M2.25 1h15.5c.69 0 1.25.56 1.25 1.25v15.5c0 .69-.56 1.25-1.25 1.25H2.25C1.56 19 1 18.44 1 17.75V2.25C1 1.56 1.56 1 2.25 1zM17 17V3H3v14h14zM10 6c0-1.1-.9-2-2-2s-2 .9-2 2 .9 2 2 2 2-.9 2-2zm3 5s0-6 3-6v10c0 .55-.45 1-1 1H5c-.55 0-1-.45-1-1V8c2 0 3 4 3 4s1-3 3-3 3 2 3 2z" } )
            )
        )
    )
),

Opciones de bloque adicionales

A continuación, agregaremos nuestros controles de inspector. Estas son las opciones de bloque adicionales que se pueden configurar  haciendo clic en la pestaña “Bloque” dentro del editor. Para el Bloque de perfil, los enlaces de las redes sociales se agregan dentro de los controles del inspector:

focus && el(
    blocks.InspectorControls,
    { key: 'inspector' },
    el( 'div', { className: 'components-block-description' }, // A brief description of our block in the inspector.
        el( 'p', {}, i18n.__( 'Add links to your social media profiles.' ) ),
    ),
    el( 'h2', {}, i18n.__( 'Social Media Links' ) ), // A title for our social media link options.
    el(
        TextControl,
        {
            type: 'url',
            label: i18n.__( 'Facebook URL' ),
            value: facebookURL,
            onChange: function( newFacebook ) {
                props.setAttributes( { facebookURL: newFacebook } );
            },
        }
    ),
    el(
        TextControl,
        {
            type: 'url',
            label: i18n.__( 'Twitter URL' ),
            value: twitterURL,
            onChange: function( newTwitter ) {
                props.setAttributes( { twitterURL: newTwitter } );
            },
        }
    ),
    el(
        TextControl,
        {
            type: 'url',
            label: i18n.__( 'Instagram URL' ),
            value: instagramURL,
            onChange: function( newInstagram ) {
                props.setAttributes( { instagramURL: newInstagram } );
            },
        }
    ),
    el(
        TextControl,
        {
            type: 'url',
            label: i18n.__( 'LinkedIn URL' ),
            value: linkedURL,
            onChange: function( newLinkedIn ) {
                props.setAttributes( { linkedURL: newLinkedIn } );
            },
        }
    ),
    el(
        TextControl,
        {
            type: 'url',
            label: i18n.__( 'Email Address' ),
            value: emailAddress,
            onChange: function( newEmail ) {
                props.setAttributes( { emailAddress: newEmail } );
            },
        }
    ),
),

Ahora, construiremos los elementos de bloque dentro del editor:

el( 'div', { className: props.className },
  el( 'div', {
    className: attributes.mediaID ? 'organic-profile-image image-active' : 'organic-profile-image image-inactive',
    style: attributes.mediaID ? { backgroundImage: 'url('+attributes.mediaURL+')' } : {}
  },
    el( blocks.MediaUploadButton, {
      buttonProps: {
        className: attributes.mediaID
          ? 'image-button'
          : 'components-button button button-large',
      },
      onSelect: onSelectImage,
      type: 'image',
      value: attributes.mediaID,
    },
      attributes.mediaID
        ? el( 'img', { src: attributes.mediaURL } )
        : 'Upload Image'
    ),
  ),
  el( 'div', {
    className: 'organic-profile-content', style: { textAlign: alignment } },
    el( blocks.Editable, {
      tagName: 'h3',
      inline: false,
      placeholder: i18n.__( 'Profile Name' ),
      value: attributes.title,
      onChange: function( newTitle ) {
        props.setAttributes( { title: newTitle } );
      },
      focus: focusedEditable === 'title' ? focus : null,
      onFocus: function( focus ) {
        props.setFocus( _.extend( {}, focus, { editable: 'title' } ) );
      },
    } ),
    el( blocks.Editable, {
      tagName: 'h5',
      inline: false,
      placeholder: i18n.__( 'Subtitle' ),
      value: attributes.subtitle,
      onChange: function( newSubtitle ) {
        props.setAttributes( { subtitle: newSubtitle } );
      },
      focus: focusedEditable === 'subtitle' ? focus : null,
      onFocus: function( focus ) {
        props.setFocus( _.extend( {}, focus, { editable: 'subtitle' } ) );
      },
    } ),
    el( blocks.Editable, {
      tagName: 'p',
      inline: true,
      placeholder: i18n.__( 'Write a brief bio...' ),
      value: attributes.bio,
      onChange: function( newBio ) {
        props.setAttributes( { bio: newBio } );
      },
      focus: focusedEditable === 'bio' ? focus : null,
      onFocus: function( focus ) {
        props.setFocus( _.extend( {}, focus, { editable: 'bio' } ) );
      },
    } ),
    el( 'div', { className: 'organic-profile-social' },
      attributes.facebookURL &&
      el( 'a', {
          className: 'social-link',
          href: attributes.facebookURL,
          target: '_blank',
        },
        el( 'i', { className: 'fa fa-facebook', } ),
      ),
      attributes.twitterURL &&
      el( 'a', {
          className: 'social-link',
          href: attributes.twitterURL,
          target: '_blank',
        },
        el( 'i', { className: 'fa fa-twitter', } ),
      ),
      attributes.instagramURL &&
      el( 'a', {
          className: 'social-link',
          href: attributes.instagramURL,
          target: '_blank',
        },
        el( 'i', { className: 'fa fa-instagram', } ),
      ),
      attributes.linkedURL &&
      el( 'a', {
          className: 'social-link',
          href: attributes.linkedURL,
          target: '_blank',
        },
        el( 'i', { className: 'fa fa-linkedin', } ),
      ),
      attributes.emailAddress &&
      el( 'a', {
          className: 'social-link',
          href: 'mailto:' + attributes.emailAddress,
          target: '_blank',
        },
        el( 'i', { className: 'fa fa-envelope', } ),
      ),
    ),
  ),
)

La función de guardar

Ahora, tenemos que guardar el bloque. Esta función define la salida del bloque en el front-end:

save: function( props ) {
	var attributes = props.attributes;
	var alignment = props.attributes.alignment;

	return (
		el( 'div', { className: props.className },
			attributes.mediaURL &&
			el( 'div', { className: 'organic-profile-image', style: { backgroundImage: 'url('+attributes.mediaURL+')' } },
				el( 'img', { src: attributes.mediaURL } ),
			),
			el( 'div', { className: 'organic-profile-content', style: { textAlign: attributes.alignment } },
				el( 'h3', {}, attributes.title ),
				attributes.subtitle && el( 'h5', {}, attributes.subtitle ),
				attributes.bio && el( 'p', {}, attributes.bio ),
				el( 'div', { className: 'organic-profile-social' },
					attributes.facebookURL &&
					el( 'a', {
							className: 'social-link',
							href: attributes.facebookURL,
							target: '_blank',
						},
						el( 'i', { className: 'fa fa-facebook', } ),
					),
					attributes.twitterURL &&
					el( 'a', {
							className: 'social-link',
							href: attributes.twitterURL,
							target: '_blank',
						},
						el( 'i', { className: 'fa fa-twitter', } ),
					),
					attributes.instagramURL &&
					el( 'a', {
							className: 'social-link',
							href: attributes.instagramURL,
							target: '_blank',
						},
						el( 'i', { className: 'fa fa-instagram', } ),
					),
					attributes.linkedURL &&
					el( 'a', {
							className: 'social-link',
							href: attributes.linkedURL,
							target: '_blank',
						},
						el( 'i', { className: 'fa fa-linkedin', } ),
					),
					attributes.emailAddress &&
					el( 'a', {
							className: 'social-link',
							href: 'mailto:' + attributes.emailAddress,
							target: '_blank',
						},
						el( 'i', { className: 'fa fa-envelope', } ),
					)
				)
			)
		)
	);
},

Terminando

¡Ahí tienes! Esa es la mayor parte de la creación de un bloque personalizado para el próximo editor de Gutenberg.
¡Solo agregue estilos y tendrá un bloque personalizado que funciona completamente!.

Este árticulo fue creado por los chicos de organic theme, puedes pasar y mirar su web. Disponen de themes interesantes!!.

 

 

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *