Introdução a Webpack

Webpack é um static module bundler ou numa tradução genérica um “empacotador de módulos”, mas o que isso significa? Webpack vai gerenciar a leitura de arquivos de seu projeto empacotando esse conteúdo da forma que você desejar. Ele irá funcionar de forma recursiva, um arquivo funciona como ponto de partida, a partir desse ponto inicial ele irá varrer todos os arquivos que estão conectados em sua aplicação e para cada caso teremos um tratamento específico.

Qual a vantagem disso tudo? Ainda é comum aplicações web carregando dezenas JavaScript com diferentes script tags, se você não fizer isso da maneira correta irá causa uma série de problemas de performance em sua aplicação. E o gerenciamento de módulos ataca alguns problemas de performance, por padrão Webpack trabalha apenas com o carregamento de Javascript, mas podemos instalar recursos necessários para trabalhar com CSS, imagens, arquivos SASS, LESS e TypeScript. Esses “recursos” são chamados de loaders que veremos em breve.

Atualmente na versão 4 Webpack esté entre as principais ferramentas de configuração de ambiente, anteriormente ocupadas pelo Gulp e o Grunt. O que impulsionou sua popularidade foi a adoção por grandes CLI’s do mercado, com angular-cli e create-react-app conseguimos abstrair toda a complexidade de realizar a configuração inicial de projetos com Angular ou React e Webpack é um grande responsável por toda essa mágica por trás dos CLIs.

Vale salientar que funcionamento do Webpack é um pouco diferente do Gulp e Grunt, eles são gerenciadores de tarefas enquanto o Webpack é um gerenciador de módulos, o seu foco é como os arquivos serão carregados separados por extensão, mas claro que podemos trabalhar uma série de recursos que o gulp/grunt realizam, por exemplo, toda parte de optimização, minificação, tratamento de arquivos e concatenação.

O processo de leitura com Webpack é dividido em 4 conceitos chaves:

  • Entry: qual será o nosso arquivo de entrada, o nosso ponto inicial
  • Output: nosso arquivo final gerado
  • Loaders: para cada tipo de arquivo o Webpack possui um loader devemos gerenciar este ponto no nosso arquivo de configuração
  • Plugins: Webpack disponibiliza uma série de plugins, para diferentes tipos de situações

Nas versões anteriores nos iniciávamos um projeto com o arquivo webpack.config.js nele especificamos como o Webpack ira se comportar. Na versão nova do Webpack podemos iniciar um projeto sem o arquivo de configuração, mas voce quiser realizar optimizações extra com o o webpack.config.js

Preparativos

Para esse tutorial vamos criar um projeto simples com dois arquivos, a estrutura será a seguinte, cada passo desse tutorial irei criar uma branch para voce acompanha a evolução dos arquivos, por exemplo, step-1… step-2… step-3… O nosso ponto de partida será o seguinte:

Temos um aquivo index.html e dentro da pasta SRC temos uma index.js

Antes de iniciar a instalação do Webpack, voce irá precisar de uma versão atualizada do nodeJS/NPM, podemos verificar a versão do nosso NPM com o comando em nosso terminal:

npm -v

Na raiz no nosso projeto vamos inicializar o nosso pacote NPM(step-2), nele vamos salvar todas as dependências para o nosso projeto, assim em nosso terminal executamos o comando:

npm init

Na imagem acima temos o final do passo-a-passo realizar pelo NPM init, ele ira verificar se ja temos um arquivo package.json, caso não, ele irar nos ajudar a criar um, fazendo perguntas sobre os campos necessários e ao final ele gerar uma arquivo package.json:

{
  "name": "webpack-tutorial",
  "version": "1.0.0",
  "description": "Tutorial about webpack",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/fellyph/webpack-tutorial.git"
  },
  "keywords": [
    "tutorial",
    "webpack"
  ],
  "author": "fellyph",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/fellyph/webpack-tutorial/issues"
  },
  "homepage": "https://github.com/fellyph/webpack-tutorial#readme"
}

Com o nosso package.json configurado agora vamos instalar o webpack e webpack-cli em nosso projeto(step-3), voltando para o terminal vamos executar os seguintes comandos:

npm install webpack webpack-cli --save-dev

Se tudo correr bem teremos a confirmação em nosso terminal:

Caso a versão do seu node não suporte a última versão do Webpack, voce receberá um alerta para atualizar o seu nodeJS and NPM. Agora vamos criar a determinada situação para fazer uma comparação após usarmos Webpack. Inicialmente vamos adicionar três novos scripts(content.js, header.js e footer.js) ao nosso projeto e carrega-los em nossa index.html(isso voce poderá acompanhar na branch step 4).

Simulando uma conexão lenta o resultado será o seguinte. Temos 4 requisições durando um total de 4.29 segundos.

Uma ação de melhorar a performance de um site é reduzir o numero de requisições, em browsers modernos e conexões HTTP2 isso não tao visível. Mas quando não temos esse recursos temos uma limitação de requisições em paralelo isso causa um efeito cascata aumentando o tempo de carregamento. Uma solução para isso será enviar um único bundle contendo todos os arquivos, agora vamos verificar como fazer isso com webpack primeiro vamos definir o nosso webpack.config.js:

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'
  }
};

No arquivo acima tempos temos instruções qual é o arquivo de entrada neste caso o index.js e qual arquivo será gerado dentro da pasta ‘dist’ o arquivo main.js. E nosso index.js importa os três arquivos, content.js, header.js e footer.js

var myContent = require('./js/content');
var myHeader = require('./js/header');
var myFooter = require('./js/footer');

O Webpack irá ler o arquivo index.js e varrer todos os arquivos relacionados e criar um arquivo único simulando uma conexão lenta o resultado será o seguinte:

Agora temos duas requisições 2 requisições em 4.24 segundos

Até o momento não fizemos nenhuma otimização esse post serviu como uma introdução, nos próximos posts podemos evoluir o nosso projeto e aumentar sua complexidade. O código final você encontra aqui: https://github.com/fellyph/webpack-tutorial/tree/step-5

Internacionalização com blocos Gutenberg

Se você está acessando o blog pela primeira vez esse post faz parte de uma série de posts relacionados na criação de blocos para o novo editor do WordPress Gutenberg. Caso queira conferir os posts anteriores:

Internacionalização dentro da construção de temas é o fator fundamental, nele damos a possibilidade do tema se adaptar a diversos idiomas. Essa regra também se aplica aos nossos blocos, caso queiramos criar um produto que atenda diversos idiomas, precisaremos permitir que toda saída de texto do nosso bloco se a adapte ao idioma do WordPress.

Antes do Gutenberg a internacionalização de texto era feita no back-end através da função wp_localize_script() . Agora com o Gutenberg é possível fazer a internacionalização no front-end, para isso vamos trabalhar como uma biblioteca javascript chamada wp-i18n. Se você já trabalhou com a internacionalização de temas o processo será o mesmo, precisamos especificar uma domínio para nossas String, nada mais é que um id que é adicionado no cabeçalho do nosso tema ou plugin. Após definido nosso domínio (text domain) fazemos a chama de texto da seguinte forma:

__( 'Hello, dear user!', 'my-text-domain' );

Essa função que envolve o texto será responsável por conferir se o tema ou plugin possui tradução para essa string, que será armazenado em um arquivo .pot. Ele pode ser gerado automaticamente por algumas ferramentas. No caso de blocos Gutenberg podemos utilizar o WordPress i18n babel plugin para gerar nosso arquivo .pot.

Para nosso tutorial vamos utilizar os blocos criados nos exercícios anteriores e o resultado será o seguinte:

/**
 * 1 - Criando primeiro bloco Gutenberg com ES5: parte 04
 * 	-	 internacionalizacao de blocos
 */
( function( blocks, element, editor, i18n ) {
	var el = element.createElement,
			RichText = editor.RichText;

	//registrando nosso bloco
	blocks.registerBlockType( 'fellyph/tutorial-03', {
		title: i18n.__('Bloco com cadastro de atributo', 'fellyph'),
		icon: 'smiley',
		category: 'layout',
		keywords: [
			i18n.__('Tutorial', 'fellyph'),
			i18n.__('Cadastro', 'fellyph'),
			i18n.__('Dinâmico', 'fellyph')
		],
		
		//registrando o tipo de bloco que iremos trabalhar
		attributes: {
			content: {
				type: 'string',
				source: 'html',
				selector: 'p',
			}
		},
		
		// função responsável por exibir nosso bloco no editor
		edit: function(props) {
			var content = props.attributes.content;

			// função responsável por acompanhar as mudanças do nosso atributo
			function onChangeContent( newContent ) {
				props.setAttributes( { content: newContent } );
			}
			
			// agora retornamos um elemento RichText ao invés de um parâgrafo
			return el(
				RichText,
				{
					tagName: 'p',
					className: props.className,
					onChange: onChangeContent,
					placeholder: i18n.__('Insira texto aqui', 'fellyph'),
					value: content,
				}
			);
		},

		save: function(props) {
			return el(
				RichText.Content , {
					tagName: 'p',
					className: props.className,
					value: props.attributes.content,
				}
			);
		},
	});
}(
	window.wp.blocks,
	window.wp.element,
	window.wp.editor,
	window.wp.i18n
) );

Na primeira linha adicionamos uma nova dependência o script i18n, dentro do nosso script trocamos todas as chamadas de strings que serão exibidas para o usuário, no front-end e no editor de nossa aplicação pela função i18n.__() , nela vamos passar o texto original e o text domain para tradução como parâmetros.

Para aumentar a quantidade de texto eu adicionei uma nova propriedade em nosso bloco keywords, ela ajudar na busca de nossos componentes, no caso adicionamos 3 keywords em um array: Tutorial, Cadastro e Dinâmico com isso quando realizamos uma consulta as keywords podem ser um critério para achar o nosso bloco como podemos ver na imagem abaixo:

A keyword ajuda a achar o nosso bloco

O resultado do nosso bloco será praticamente o mesmo, com uma diferença que o nosso texto agora está localizado:

Podemos ver nos detalhes do nosso bloco que estamos carregando o título que cadastramos e no bloco podemos ver o nosso placeholder.

O último passo será criar o nosso arquivo de tradução o .poc, temos duas opções, a primeira seria gerando com software especifico o poedit, caso você queira evitar tooling com Babel e Webpack:

A seguida opção com o pacote nodeJS @wordpress/babel-plugin-makepot, para isso precisamos figuração de nosso projeto com babel e Webpack isso vai demandar um post específico dai entramos na criação de blocos com JSX.

O código completo você irá encontrar em meu github: https://github.com/fellyph/Gutenberg-tutorials/tree/tutoriais/gutenberg-04

Até o próximo post!

Gutenberg: Trabalhando com atributos em blocos customizados

Esse post é o terceiro de uma série de posts sobre o blocos Gutenberg customizados. Nesse tutorial vamos abordar como trabalhar com atributos em posts customizados. Nos posts anteriores vimos como registrar o nosso bloco customizado e adicionar um estilo ao nosso markup. Agora vamos entender como os atributos funcionam dentro do WordPress. Caso ainda não viu os posts anteriores você confere aqui:

Atributos

Até o momento, nos posts anteriores, quando registramos o nosso primeiro bloco passamos apenas um paragrafo estático, mas caso queiramos dar a possibilidade para o usuário cadastrar uma informação dinamicamente através do editor como serão os próximos passos? Vimos durante a chamada da função edit podemos receber um objeto com propriedades relacionadas ao nosso bloco e uma dessas informações é a propriedade attributes. Para trabalhar com a edição de conteúdo vamos trabalhar com alguns componentes do WordPress.

Componentes

Os blocos muitas vezes repetem a mesma complexidade, isso nos permite aplicar a reutilização de certos recursos, para simplificar a edição de conteúdo, o core do WordPress tem uma série componentes React que realizam tarefas específicas, mas não se assuste você não precisa aprender React para utilizar esse recursos. Mas meu conselho se você que trabalhar de forma mais produtiva é uma tecnologia que ajuda bastante, mas o foco desse tutorial vamos trabalhar com EcmaScript5, Dentro dos componentes vamos abordar dois componentes:

RichText

Ele irá renderizar para nos um input editável com a possibilidade de inclusa de texto e links. Dentro do componente RichText temos as seguintes propriedades:

  • value: espera um valor do tipo string, será o conteúdo armazenado ate o momento, podendo ser texto ou markup valido.
  • onChange: esse atributo espera uma função, será o callback responsável quando o valor do atributo sofre uma alteração
  • placeholder: O valor do campo quando estiver vazio. isso é válido tanto para o input text ou textarea o valor será o mesmo
  • multiline: Se o bloco irá permitir que o usuário cadastre multiplas linhas quando presionar enter, quando desabilitado o cada enter irá criar um novo bloco.

BlockControls

Quando nosso bloco é renderizado dentro do editor, uma barra de ferramentas é exibida com algumas opções relacionadas ao bloco selecionado, por exemplo, caso queiramos exibir opções de alinhamento de texto ao nosso bloco passamos o elemento responsável por alinhamento. O BlockControls espera o seguinte:

  • icon: slug do dashicon para ser mostrado na barra de controle
  • title: um título será exibido em forma de tooltip para o usuário
  • subscript: Um texto opcional para ser exibido adjacente ao ícone da barra de controle
  • isActive: um booleano para definir se o barra de controle será selecionada ou não por default.

Para esse tutorial vamos registrar dois blocos, primeiro exemplo(script.js) apenas com um richText component e o segundo bloco fazendo o uso do blockControl e richText(script-controls.js).

script.js

/**
 * 1 - Criando primeiro bloco Gutenberg com ES5: parte 03
 * 	-	 carregando atributos
 */
( function( blocks, element, editor ) {
	var el = element.createElement,
	RichText = editor.RichText;

	//registrando nosso bloco
	blocks.registerBlockType( 'fellyph/tutorial-03', {
		title: 'Primeiro bloco Gutenberg: Parte 03',
		icon: 'smiley',
		category: 'layout',
		
		//registrando o tipo de bloco que iremos trabalhar
		attributes: {
			content: {
				type: 'string',
				source: 'html',
				selector: 'p',
			}
		},
		
		// função responsável por exibir nosso bloco no editor
		edit: function(props) {
			var content = props.attributes.content;

			// função responsável por acompanhar as mudanças do nosso atributo
			function onChangeContent( newContent ) {
					props.setAttributes( { content: newContent } );
			}
			
			// agora retornamos um elemento RichText ao invés de um parâgrafo
			return el(
				RichText,
				{
					tagName: 'p',
					className: props.className,
					onChange: onChangeContent,
					value: content,
				}
			);
		},

		save: function(props) {
			return el(
				RichText.Content , {
					tagName: 'p',
					className: props.className,
					value: props.attributes.content,
				}
			);
		},
	});
}(
	window.wp.blocks,
	window.wp.element,
	window.wp.editor
) );

Como podemos ver no código acima, vamos ter mais uma dependência a classe editor do WordPress presente no script wp-editor, nela vamos encontrar os componentes relacionados a edição de conteúdo. Próximo passo adicionamos em uma variável nosso RichText, seguindo nosso código dentro do registerBlockType temos algumas alterações, adicionamos uma nova propriedade attributes ele é responsável pela configuração do nosso atributo. Ela merece um post específico só falando sobre

Mas voltando para o nosso tutorial definimos a configuração do atributo content esse nome pode ser qualquer um, por exemplo, “conteúdo”. Para esse atributo passamos um objeto de configuração como o tipo do dado(type), a fonte que iremos receber do editor(source), valores padrões(default) entre outras informações.

Dentro da função do edit, o nosso elemento RichText definimos os atributos tagName, className, onChange, value. Também criamos uma função onChangeContent ela é necessária por conta de um conceito do React de controle de estado, precisamos implementar um controlled component para isso, um resumo bem grosseiro, precisamos conectar o valor do input com o estado do component.

Index.php

Algumas diferenças na implementação do index.php, são o registro de dois blocos e quando registramos nosso script precisar adicionar a dependência ao ‘wp-editor’.

<?php

/**
 * Plugin Name: Gutenberg tutorial
 * Plugin URI: https://github.com/fellyph/gutenberg-tutorials
 * Description: Este tutorial ensina como criar um bloco gutenberg https://blog.fellyph.com.br/wordpress-2/criando-seu-proprio-bloco-gutenberg/.
 * Version: 1.3
 * Author: fellyph
 */

defined( 'ABSPATH' ) || exit;

/**
 * 1 - Criando nosso primeiro bloco: Parte 03
 *    1.1 - Adicionando o recurso de cadastrar atributos
 * 		1.2 - Adicionando o bloco com block control
 */

function meu_primeiro_bloco_gutenberg_parte_03 () {

	if ( ! function_exists( 'register_block_type' ) ) {
		// Checamos se temos suporte a função register_block_type antes de tudo.
		return;
	}

	wp_register_script(
		'tutorial-03',
		plugins_url( 'script.js', __FILE__ ),
		array( 'wp-blocks', 'wp-element', 'wp-editor' ),
		filemtime( plugin_dir_path( __FILE__ ) . 'script.js' )
	);

	wp_register_script(
		'tutorial-03-alinhamento',
		plugins_url( 'script-controls.js', __FILE__ ),
		array( 'wp-blocks', 'wp-element', 'wp-editor' ),
		filemtime( plugin_dir_path( __FILE__ ) . 'script-controls.js' )
	);

	wp_register_style(
		'style-editor',
		plugins_url( 'editor-style.css', __FILE__ ),
		array('wp-edit-blocks'),
		filemtime( plugin_dir_path( __FILE__ ) . 'editor-style.css' )
	);

	wp_register_style(
		'style-frontend',
		plugins_url( 'style.css', __FILE__ ),
		filemtime( plugin_dir_path( __FILE__ ) . 'style.css' )
	);

	register_block_type( 'fellyph/tutorial-03', array(
		'style' => 'style-frontend',
		'editor_script' => 'tutorial-03',
		'editor_style' => 'style-editor'
	));

	register_block_type( 'fellyph/tutorial-03-alinhamento', array(
		'style' => 'style-frontend',
		'editor_script' => 'tutorial-03-alinhamento',
		'editor_style' => 'style-editor'
	));
}

add_action( 'init', 'meu_primeiro_bloco_gutenberg_parte_03' );

Um ponto importante em nosso script, quando registramos um novo id(fellyph/tutorial-03-alinhamento e fellyph/tutorial-03) para nosso bloco precisamos atualizar o nosso seletores CSS:

.wp-block-fellyph-tutorial-03-alinhamento,
.wp-block-fellyph-tutorial-03 {
  background: #12c2e9;
  border: 3px solid #666;
  box-shadow: 0 0 0 #666;
}

.wp-block-fellyph-tutorial-03-alinhamento:hover,
.wp-block-fellyph-tutorial-03:hover {
  transform: rotate3d(0, 0, 0, 0);
}

script-controls.js

/**
 * 1 - Criando primeiro bloco Gutenberg com ES5: parte 03
 * 	-	 carregando atributos com BlockControls
 */
( function( blocks, element, editor ) {
	var el = element.createElement,
	RichText = editor.RichText,
	AlignmentToolbar = editor.AlignmentToolbar,
	BlockControls = editor.BlockControls;

	//registrando nosso bloco
	blocks.registerBlockType( 'fellyph/tutorial-03-alinhamento', {
		title: 'Bloco com controle de alinhamento',
		icon: 'welcome-view-site',
		category: 'layout',
		
		//registrando os atributos que iremos trabalhar
		attributes: {
			content: {
				type: 'string',
				source: 'html',
				selector: 'p'
			},
			alinhamento: {
				type: 'string',
				default: 'none'
			},
		},
		
		// unção responsável por exibir nosso bloco no editor
		edit: function(props) {
			var content = props.attributes.content;
			var alinhamento = props.attributes.alinhamento;

		// função responsável por acompanhar as mudanças do nosso atributo
		function onChangeContent( newContent ) {
					props.setAttributes( { content: newContent } );
			}

			function onChangeAlignment (nextAlign ) {
				props.setAttributes( { alinhamento: nextAlign } );
			}

		// agora retornamos um array por que estamos utilizando dois componentes
		return [
			el( BlockControls, 
				{ key: 'controls' },
				el( AlignmentToolbar, {
							value: alinhamento,
							onChange: onChangeAlignment
					})
        ),
				el(
					RichText,
					{
						key: 'richtext',
						tagName: 'p',
						style: { textAlign: alinhamento },
						className: props.className,
						onChange: onChangeContent,
						value: content,
						placeholder: 'Insira seu nome aqui'
					}
			),
			];
		},

		save: function(props) {

			return el(
				RichText.Content , {
					tagName: 'p',
					className: props.className,
					style: { textAlign: props.attributes.alinhamento },
					value: props.attributes.content,
				}
			);
		},
	});
}(
	window.wp.blocks,
	window.wp.element,
	window.wp.editor
) );

No código acima temos alguns pontos importantes diferente do primeiro código, em atributos adicionamos um novo valor, “alinhamento” ele será do tipo string e terá um valor padrão ‘none’.

Dentro da função edit adicionamos uma função para acompanhar as mudanças desse componente onChangeAlignment onde atualizamos o valor do atributo referente ao alinhamento.

Agora quando retornamos o nosso bloco utilizamos um array para passar mais de um componente, por que precisamos de um blockControls para passar as configurações necessárias e um RichText para o usuário cadastrar um texto.

Dentro do nosso blockControls podemos também passar uma série de outros componentes relacionados a configurações mas para esse caso vamos utilizar apenas o AlignmentToolbar :

Em seguida conectamos o valor do aligmentToolbar ao nosso RichText, tanto no preview na função edit quando no nosso front-end na função save, definindo o atributo style: { textAlign: alinhamento }.

E esse será o resultado dos dois blocos que criamos aqui:

Exemplo de RichText
bloco utilizando placeholder
Exemplo com BlockControls e AligmentToolbar

O código desse tutorial você irá encontrar no meu git, para cada tutorial estou criando uma branch:

https://github.com/fellyph/Gutenberg-tutorials/tree/tutoriais/gutenberg-03

Qualquer feedback deixe aqui seu comentário e até o próximo tutorial

Referências:

Criando seu próprio bloco Gutenberg: Parte 2

No post anterior vimos como trabalhar com blocos customizados, conceitos básicos de como registrar nosso bloco como um plugin e criar um markup básico com JavaScript. Nesse post vamos evoluir o nosso bloco todo código está disponível no Github. Primeiro passo vamos ver como os blocos trabalham com estilo externo.

Carregando estilo externo

Primeiro passo será criar nossos arquivos CSS, um arquivo para o front-end de nossa aplicação e o segundo para nosso editor.

style.css(front-end e editor):

.wp-block-fellyph-tutorial-02 {
  background: linear-gradient(45deg, #12c2e9, #c471ed, #f64f59);
  padding: 2em;
  color: white;
  font-size: 20px;
  box-sizing: border-box;
  transform: rotate3d(0, 0, 0, 0);
  transition: all 200ms ease-out;
  box-shadow: 3px 3px 3px #666;
  text-align: center;
}

.wp-block-fellyph-tutorial-02:hover {
  transform: rotate3d(1, 1, 1, -4deg);
}

editor-style.css(somente editor)

.wp-block-fellyph-tutorial-02 {
  background: #12c2e9;
  border: 3px solid #666;
  box-shadow: 0 0 0 #666;
}

.wp-block-fellyph-tutorial-02:hover {
  transform: rotate3d(0, 0, 0, 0);
}

Temos acima os dois códigos que iremos carregar em nossa aplicação, dois pontos importantes, um o nome da classe ela sempre irá iniciar com ‘wp-block-‘ mais o nome que registramos o nosso bloco, nesse caso o ‘fellyph/tutorial-02‘ irá se transformar em fellyph-tutorial-02, assim temos a classe wp-block-fellyph-tutorial-02.

Segundo ponto, quando trabalhamos com a função register_block_type ela espera 4 parâmetros:

  • style
  • script
  • editor_style
  • editor_script

As propriedades script e style representam os arquivos que serão carregados no editor e front-end da aplicação, enquanto editor_style e editor_script serão carregados apenas no editor do WordPress. Nesse caso o estilo no arquivo editor-style irá sobrescrever o estilo do arquivo style.css. Para ficar mais claro vamos ver o print do resultado desses dois estilos:

Estilo aplicado em nosso front-end
Estilo aplicado em nosso editor

Temos um spoiler de como ficará esse nosso bloco, mas como podemos observar, o bloco no editor herda todas as propriedades do bloco do front-end, por exemplo, alinhamento, padding e a cor da fonte, essas características foram de no arquivo style.css.

index.php

Agora vamos dar uma olhada em nosso arquivo principal:

<?php

/**
 * Plugin Name: Gutenberg tutorial
 * Plugin URI: https://github.com/fellyph/Gutenberg-tutorials
 * Description: Este tutorial ensina como criar um bloco gutenberg https://blog.fellyph.com.br/wordpress-2/criando-seu-proprio-bloco-gutenberg/.
 * Version: 1.2
 * Author: fellyph
 */

defined( 'ABSPATH' ) || exit;

/**
 * 1 - Criando nosso primeiro bloco: Parte 02
 *    - Carregando arquivo externo para nosso estilo
 */
function meu_primeiro_bloco_gutenberg_parte_02 () {

	if ( ! function_exists( 'register_block_type' ) ) {
		// Checamos se temos suporte a função register_block_type antes de tudo.
		return;
	}

	wp_register_script(
		'tutorial-02',
		plugins_url( 'script.js', __FILE__ ),
		array( 'wp-blocks', 'wp-element' ),
		filemtime( plugin_dir_path( __FILE__ ) . 'script.js' )
	);

	wp_register_style(
		'style-editor',
		plugins_url( 'editor-style.css', __FILE__ ),
		array('wp-edit-blocks'),
		filemtime( plugin_dir_path( __FILE__ ) . 'editor-style.css' )
	);

	wp_register_style(
		'style-frontend',
		plugins_url( 'style.css', __FILE__ ),
		filemtime( plugin_dir_path( __FILE__ ) . 'style.css' )
	);

	register_block_type( 'fellyph/tutorial-02', array(
		'style' => 'style-frontend',
		'editor_script' => 'tutorial-02',
		'editor_style' => 'style-editor'
	) );
}

add_action( 'init', 'meu_primeiro_bloco_gutenberg_parte_02' );

Não vamos abordar todas as partes desse código caso não tenha visto a primeira parte dessa séria aqui está o link: https://blog.fellyph.com.br/wordpress-2/criando-seu-proprio-bloco-gutenberg.

Comparado ao tutorial anterior, acrescentamos duas funções wp_register_style, uma para estilo geral e outra para o estilo do nosso editor e por fim passamos como parâmetro na função register_block_type.

script.js

Em nosso script agora temos o seguinte código:

( function( blocks, element ) {
	var el = element.createElement;


	blocks.registerBlockType( 'fellyph/tutorial-02', {
		title: 'Primeiro bloco Gutenberg: Parte 02',
		icon: 'smiley',
    category: 'layout',
  
		edit: function(props) {
			return el(
				'p',
				{ className: props.className },
				'Este conteúdo será exibido no editor.'
			);
		},
		save: function(props) {
			return el(
				'p',
				{ className: props.className },
				'Este conteúdo será exibido para o usuário final.'
			);
		},
	} );
}(
	window.wp.blocks,
	window.wp.element
) );

Comparado a versão anterior passamos nas funções dentro das propriedades edit e save uma propriedade chamada props, ela contém informações referente ao nosso bloco e uma delas é o nome dessa classe, não obrigatório passar o className dinamicamente poderíamos passar um valor estático, mas para facilitar a manutenção e evitar conflitos com outros blocos utilizamos o nome de classe dinamicamente.

Uma observação sobre a propriedade “icon” caso queira saber os ícones disponíveis dentro do WordPress, só acessar o link: https://developer.wordpress.org/resource/dashicons/#smiley lá você irá encontrar uma série de ícones separados por categoria.

Na página de dashicons você pode conferir o id para cada ícone

No meu caso eu selecionei o ícone smiley, como podemos ver na imagem abaixo, quando clico no ícone temos seu id e como utiliza-lo em nosso CSS ou HTML, mas eu só irei precisar do id ‘dashincons-smiley’ em nosso script usamos ‘dashicons-‘ apenas smiley.

A nível de curiosidade eu alterei a função edit para ver quais são os valores passados dentro de props(você não precisa implementar isso).

edit: function(props) {
	var test = 'Este conteúdo será exibido no editor. / ';
	for(var key in props) {
		test += key + " : " + props[key] + ' / ';
	}

	return el(
		'p',
		{ className: props.className },
		test
		);
	},

O resultado foi o seguinte:

Dentro do objeto props temos as seguintes propriedades e funções:

  • name
  • isSelected
  • attributes
  • setAttributes (function)
  • insertBlocksAfter (function)
  • onReplace (function)
  • mergeBlocks (function)
  • clientId
  • isSelectionEnabled
  • toggleSelection (function)
  • className

Para a estilização de nosso bloco poderíamos trabalhar com atributos dinâmicos, mas esse será assunto para um próximo post. Caso queira saber mais sobre como trabalhar com estilo em blocos customizados só deixar um comentário.

O código desse tutorial você irá encontrar na branch(tutorais/gutenberg-02) do repositório: https://github.com/fellyph/Gutenberg-tutorials/tree/tutoriais/gutenberg-02

Criando seu próprio bloco Gutenberg

Continuando a série sobre o Gutenberg nesse post vamos criar o nosso primeiro bloco Gutenberg, para esse exercício vamos nos basear no repositório oficial do WordPress, lá vamos encontrar uma série de exemplos de como trabalhar com blocos Gutenberg.

No desenvolvimento de blocos temos a possibilidade de criar blocos com EcmaScript 5 e ESNext. Neste tutorial vamos abordar os exemplos com ES5.

Escrevendo o primeiro bloco

Vamos partir do principio mais básico, exibir um bloco estático HTML. Essa função pode ser útil caso desejamos criar uma bloco de assinatura ou contato por exemplo. Nos posts seguintes vamos incrementando essa solução.

Para esse bloco temos dois conceitos importantes, o primeiro ele será adicionado como um plugin é uma técnica recomendada pela documentação, o segundo ponto toda o conteúdo HTML será definido por uma JavaScript. Então com essas premissas vamos ter dois arquivos base em nosso exemplo, o PHP(index.php) que irá inicializar nosso plugin e o Script(primeiro-bloco.js) responsável pelo conteúdo.

index.php

No index.php vamos gerenciar os passos necessários do nosso plugin que irá criar o nosso bloco Gutenberg, nele temos uma atenção especial para duas funções register_block_type e wp_register_script. 

Register_block_type será responsável por registrar o nosso dentro do WordPress como parâmentro ele espera, quais serão os scripts e estilos necessários para executar esse bloco, tanto dentro de editor como para o usuário final no front-end de nossa aplicação.

Wp_register_script será responsável por a tarefa de carregar o script do nosso bloco para o WordPress, assim o WordPress sabe a hora exata de carregar o script e qual serão suas dependências de script dentro da aplicação. Para ficar mais claro vamos ao nosso exemplo:

<?php

/**
 * Plugin Name: Gutenberg tutorial
 * Plugin URI: https://github.com/fellyph/Gutenberg-tutorials
 * Description: Este tutorial ensina como criar um bloco Gutenberg https://blog.fellyph.com.br/wordpress-2/criando-seu-proprio-bloco-gutenberg/.
 * Version: 1.0
 * Author: fellyph
 */

defined( 'ABSPATH' ) || exit;

/**
 * 1 - Criando nosso primeiro bloco
 *    1.1 - precisamos registrar nosso script para ser adicionado na função register_block
 *    1.2 - registramos nosso block type passando nosso script
 */
function meu_primeiro_bloco_gutenberg () {

	if ( ! function_exists( 'register_block_type' ) ) {
		// Checamos se temos suporte a função register_block_type antes de tudo.
		return;
	}

	wp_register_script(
		'tutorial-gutenberg-01',
		plugins_url( 'primeiro-bloco.js', __FILE__ ),
		array( 'wp-blocks', 'wp-element' ),
		filemtime( plugin_dir_path( __FILE__ ) . 'primeiro-bloco.js' )
	);

	register_block_type( 'fellyph/tutorial-01', array(
		'editor_script' => 'tutorial-gutenberg-01',
	) );
}

add_action( 'init', 'meu_primeiro_bloco_gutenberg' );

Notem quando registramos nosso script temos duas dependências wp-blocks e wp-element são requisitos mínimos para trabalhar com blocos, para entender mais sobre essas duas dependências:

  • wp-blocks inclui registro de tipos de blocos e mêcanica como os itens são armazenados formulários e funções relacionadas para cada evento específico quando o bloco é salvo ou exibido em nosso front-end
  • wp-element inclui uma camada de abstração pada os blocos Gutenberg, trás a renderização desses elementos do nosso back-end para nosso front-end.

JavaScript do nosso bloco

/**
 * 1 - primeiro bloco Gutenberg com ES5
 */
( function( blocks, element ) {
	var el = element.createElement;

	// criando estilo para nosso editor
	var blockStyle = {
		backgroundColor: 'green',
		color: 'white',
    padding: '2em',
    border: '3px solid black'
	};

//criando estilo para nosso front-end
	var blockStyleFront = {
		backgroundColor: 'blue',
		color: 'white',
    padding: '2em',
    border: '3px solid black'
	};

	blocks.registerBlockType( 'fellyph/tutorial-01', {
		title: 'Primeiro bloco Gutenberg',
		icon: 'universal-access-alt',
    category: 'layout',
  
		edit: function() {
			return el(
				'p',
				{ style: blockStyle },
				'Este conteúdo será exibido no editor.'
			);
		},
		save: function() {
			return el(
				'p',
				{ style: blockStyleFront },
				'Este conteúdo será exibido para o usuário final.'
			);
		},
	} );
}(
	window.wp.blocks,
	window.wp.element
) );

Lendo nosso código fica evidente a importância de nossas dependências vamos agora passar por alguns pontos chaves. O código Javascript temos o uso de IIFE para garantir que iremos rodar nosso script quando tivemos acesso aos scripts carregados pelo WordPress que estarão disponíveis globalmente por window.wp.blocks e window.wp.element

Dentro de nossa função armazenamos a função createElement responsável por criar nosso markup em uma variável “el” e na sequência criamos dois objetos responsáveis pelo estilo do nosso bloco blockStyle e blockStyleFront.

Com a inicialização de nossas variáveis vamos agora utilizar o wp-blocks, será carregado como blocks dentro do nosso script, assim, chamamos a função blocks.registerBlockType responsável por criar nosso bloco nela passamos o id do nosso bloco ele precisa ser único para evitar conflitos dentro de nossa aplicação, título(title), ícone(icon), categoria(category), a função que será chamada no editor(edit) e a função que será salva no front-end de nossa aplicação(save).

Ativando nosso primeiro bloco Gutenberg

Com os nosso plugin/bloco Gutenberg pronto, chegou a hora de ativa-lo, primeiramente devemos armazenar os dois arquivos em uma pasta para fazer a instalação como plugin.

Adicionamos a pasta de nosso plugin em wp-content / plugins

No meu caso eu criei a pasta gutenberg-tutoriais mas pode ser qualquer nome para essa pasta. Após a adição da pasta em minha aplicação WordPress precisamos instalar o nosso plugin.

Se tudo ocorrer bem vamos visualizar nosso plugin em nosso dashboard. Agora vamos ativar e testar o nosso plugin

Como será exibido o nosso bloco

Nosso bloco ativado irá aparecer na categoria layout como definimos em nosso script e podemos ver as outras configurações como o título “primeiro bloco gutenberg”.

Quando adicionamos o bloco ele irá aparecer da seguinte forma:

Nosso bloco Gutenberg em nosso editor.

Salvando o nosso bloco o resultado será o seguinte:

Notem que as cores dos nossos blocos mudam de uma para outros isso foi adicionado de forma proposital. Podemos adicionar markups e estilos diferentes para o bloco que será exibido no editor e no front-end de nossa aplicação.

Fechamos por aqui nosso primeiro post, vamos evoluindo nossos exercícios a partir desse ponto. Para acompanhar os exercícios só seguir o repositório no github: https://github.com/fellyph/Gutenberg-tutorials

Teoria sobre blocos no Gutenberg

Gutenberg está transformando o modo de se trabalhar com WordPress , onde você utiliza blocos para compor o seu conteúdo atualmente temos uma série de diferentes elementos para compor nosso conteúdo: títulos, parágrafos, conteúdo embedado, HTML, listas, images, galeria de imagem entre outros elementos.

A otimização do Gutenberg foi realizado de forma progressiva, isso significa que temos compatibilidade com o formato de conteúdo anterior com o novo editor. O Gutenberg oferece uma nova forma de se trabalhar com conteúdo distribuído em blocos e com um simples clique e arraste podemos alterar a ordem do conteúdo a qual será apresentado para os nosso usuários. Criando uma real experiencia WYSIWYG.

Blocos

Bloco é a unidade abstrata para organização do conteúdo, com um grupo de blocos montamos o nosso post. Podemos criar hierarquia de blocos, isso significa, podemos ter blocos com blocos filhos. Por exemplo, um bloco de duas colunas possuem um bloco filho pra cada coluna.

Para manter compatibilidade com versões anteriores armazenamos os blocos no banco de dados dentro da coluna wp_content como o WordPress armazena normalmente, com uma pequena diferença os blocos são representados por comentários em um formato entendido pelo back-end do WP se o site desativar o Gutenberg o conteúdo não será exposto para o usuário final. Um exemplo de bloco de paragrafo:

Por exemplo:

<!– wp:paragraph {“key” : “value”} –>
<p>Este é um bloco do gutenberg.</p>
<! — /wp:paragraph –>

No código acima quando o Gutenberg estiver ativado ele vai reconhecer como um bloco, caso não esteja ele será renderizado como um comentário HTML normal.

Blocos possuem duas categorias estáticos e dinâmicos, por exemplo, blocos estáticos apenas exibem um markup sem nenhuma edição no editor, apenas conseguimos definir a ordem dos elementos. Já os blocos dinâmicos exigem dados do banco e renderiza os elementos dinamicamente.

Cada Bloco contém seus atributos ou configurações, cada elemento pode ser alimentado por HTML puro, meta data ou diferentes origens. Uma feature do Gutenberg é a possibilidade criar blocos e copias dos tais, preservando o conteúdo ou apenas o markup. Mas podemos também limitar a quantidade de blocos que serão utilizados nos posts ou fixa-los em uma região específica.

Categorias de blocos

Quando acionamos o Block Inserter, abrimos um pop up com os blocos disponiveis, cada bloco terá um titulo e uma categoria. Podemos ter blocos nativos ou blocos customizados por plugins ou tema.

Blocos Reutilizáveis

Nos da a possibilidade de reutilizar blocos e repetir partes de um determinado conteúdo. Qualquer edição feita em um bloco reutilizável será replicado em todas suas cópias.

Templates

O Gutenberg tenta abstrair a estrutura HTML e permitir que o usuário foque apenas no conteúdo a nível técnico sua estrutura abstrai toda estrutura de um template único no formato clássico para uma coleção de elementos reutilizáveis e independentes.

Para entender como os blocos operam a nível de estrutura de dados, precisamos pensar na prensa de impressão de Johannes Gutenberg. A página era montada a partir de caracteres individuais até montar um texto, após a finalização do página os caracteres eram armazenados para serem utilizados em uma nova página.

fonte: https://infograph.venngage.com/p/148195/renaissance-innovations-project-the-first-printing-press-johannes-gutenberg

Nessa estrutura o conteúdo final não está atrelado a impressora, é só uma ferramenta base criação do conteúdo o resultado final não importa. Por muito tempo no desenvolvimento do temas clássico os templates eram páginas completas, agora esse paradigma mudou estamos em estruturas mais unitárias. Podemos recriar um tipo de layout sem precisar rescrever o template do zero.

O ponto principal dos blocos não é definir o resultado final mas sim agilizar o processo de criação de conteúdo.

Árvore de blocos

Além do conteúdo armazenado dentro da coluna post_content para manter a estrutura de correta dos blocos o WordPress criar uma descrição semântica em JSON chamada Tree of blocks ou árvore de blocos. Durante a execução, os blocos são mantidos na memória. Nesse momento, uma postagem do Gutenberg não é HTML, mas uma árvore de objetos e atributos associados. O Gutenberg se baseia em um modelo de dados que preserva a estrutura, de modo que os editores e visualizações para tipos específicos de blocos possam permanecer independentes do HTML final renderizado.

Exemplo:

[
{
type: “core/cover-image”,
attributes: {
url: “my-hero.jpg”,
align: “full”,
hasParallax: false,
hasBackgroundDim: true
},
children: [“Gutenberg posts aren’t HTML”]
},
{
type: “core/paragraph”,
children: [“Lately I’ve been hearing plen…”]
}
];

Como podemos ver existe muita coisa por trás do novo editor uma arquitetura complexa, mas que irá trazer um ganho muito grande para a plataforma. Espero detalhar mais pontos sobre o Gutenberg. Para não ficar uma leitura longa vamos finalizando por aqui nos próximos posts irei trazer mais conceitos chaves dentro do Gutenberg.

Esse post tomou como referencia o Handbook do WordPress leitura extremamente recomendada para você que trabalha com desenvolvimento de temas e plugins na plataforma.

Finalmente Gutenberg

No começo de dezembro de 2018 foi lançada a versão 5.0 do WordPress, posso falar de longe essa foi a versão mais controversa que eu já vi durante esses 10 anos que acompanho a plataforma. O ponto em questão foi o editor Gutenberg um update que muda toda a forma de se trabalhar com conteúdo dentro do WordPress. 

A nova forma de gerenciamento de conteúdo, vem com grandes mudanças devido a necessidade simples: evolução da plataforma, esse trabalho vem sendo realizado durante 2 anos, diversos testes e updates foram feitos. O projeto já venho acompanhando desde 2017, mas fiquei curioso para ver como seria a aceitação no twitter muitas e o resultado foi muitas pessoas reclamaram sobre o novo update. Um resumo do que eu vi durante essa semana foi:

1 – “comunidade” não foi ouvida

Muitas das reclamações no twitter foram que o update foi feito sem eles ouvirem a comunidade, se você esta mesmo engajado na comunidade, você deve ter ouvido falar do projeto Gutenberg a dois anos atrás, no último WordCamp US um dos temas chaves foi o Gutenberg, chats sobre updates eram realizados eram realizados. A resposta sim a comunidade foi ouvida. Muitas pessoas não sabem onde participar, isso é normal, outras só lembram do forum quando a coisa da ruim. Mas caso você queira participar: Meetups, WordCamps, Slack, forum são as formas oficiais de participar da comunidade. Twitter e facebook não são canais oficiais mas como o Mat Mullenweg falou no último WordCamp US comentários relevantes foram lidos nessas plataformas.

2 – Voce não é a maioria

Muito complicado quando entramos numa bolha pensamos que todo o mundo está no mesmo nível técnico que nós. Nos primeiros minutos da apresentação do Matt Mullenweg mostrou testes com usuários tentando colocar uma imagem ao lado de um texto, pode ser uma simples tarefa para você que sabe HTML e WP. Mas os testes mostram quão complexo é para um simples usuário e isso corresponde a +90% da internet. As principais mudanças do Gutenberg focam nesse grupo que mantem a plataforma.

3 – Acomodação

O conceitos de blocos é algo que afeta diretamente o ecossistema, está visível para todos os usuários diferente de uma REST API que funciona por trás das cortinas, um cliente normalmente não vai pedir uma REST API, Gutenberg vai estar lá para o usuário final vai ser comum clientes começarem a pedir blocos customizados. Aprender Gutenberg vai passar a ser algo relevante, mas a palavra aprender pode ser motivante para alguns devs e extremamente frustrante para outros. Uma pequena parte desse grupo que não gosta de atualizações, simplesmente lutam contra e fazem bastante barulho parecendo um grupo ainda maior. Dois anos atrás Matt veio na apresentação e disse estudem JavaScript e hoje o Gutenberg está ai com uma série de novas tecnologias que precisamos dominar, Dois pontos chave React e JavaScript e outras secundárias como EcmaScript 6, babel e Webpack. Já estão aparecendo soluções para simplificar nossa vida mas considero extremamente importante você ter uma base nessas tecnologias.

4 – Uma estrela não é contribuição

Uma chuva de reviews negativos no Gutenberg plugin, mas esse plugin foi diponibilizado para teste, essa era ideia os usuários testarem identificarem problemas. Era esperado que o plugin apresentasse algum erro, o usuário reportava a issue para ser corrigida. Marcar com uma estrela o plugin sem nenhum feedback não ajuda a plataforma. 

5 – Está tudo bem, você pode usar o editor clássico

O Gutenberg está ai mas você não é obrigado a utilizar, o desespero de muitos usuário poderia se resolvido com um simples clique para instalar o editor clássico novamente. O editor clássico não morreu vai estar disponível por mais dois anos. Gutenberg não está 100% tem muito para evoluir, esse update é um shift que vai revolucionar a plataforma, muita coisa ainda não está clara até o Matt Mullenweg, mencionou em sua palestra no WordCamp US, no decorrer do ano muita coisa vai ser definida, não por ele mas pela comunidade, como será feita a adoção, como os usuários irão reagir as mudanças.

A fase dois do Gutenberg já foi definido: https://make.wordpress.org/core/2018/10/05/gutenberg-phase-2-leads/

Caso queira acompanhar os updates do Gutenberg só manter o plugin instalado, as novas features serão criadas na versão do editor como plugin: https://wordpress.org/plugins/gutenberg/