記事の方もReact使って書けないかと考えてみる。

 エディタがGutenbergになってReact使えるようになったけど、記事の中身にReactを使えるわけではないみたい。せっかくBlockのエディタ側で使えるのだから、そのままブログ記事の方でReactを使えないか実験。

ゴール

 今回は出来上がったら、記事のなかにReactのコンポーネント「gromment アナログ時計」をこんな感じで表示できるBlockが使えるようになります。

準備

ベースにするBlockを作成

Block ジェネレータに、これ「create-guten-block」を使っています。

pluginsフォルダに移動

ターミナルを開いて、自分のwordpressのpluginsフォルダで実行します。私の場合、こんな感じのフォルダ。

cd /var/www/html/wp-content/plugins

Blockを作成

移動したら、「create-guten-block」コマンドで、pluginのテンプレートをジェネレート

npx create-guten-block my-block
cd my-block

ここまで行ったら、次のコマンドを打って、自動ビルドをSTARTします。

npm start

ファイル構成

 ベースのBlockを作ったあと、記事用のjavascriptファイルをビルドするためのフォルダを front という名前で作成します。

 このフォルダの中身は、エディタ用のBlockとは別にwebpackでビルドします。(※ 前回の記事「Webpackでnode_modulesを一つのファイルにする」でwebpackの使い方を書いています)

Frontを実装

中身はこんな感じで実装します。

index.js

 最後の方の、ReactDOM.renderで、’clock’ を指定しています。このjavascriptファイルを使うためには、 <div id=”clock”></div> のような感じで id に’clock’ を指定した html が必要になります。これは、あとでBlockのEditorの方で作ります。

import React from "react";
import ReactDOM from "react-dom";
import { Box, Grommet, Clock } from "grommet";
import { grommet } from "grommet/themes";

const AnalogClock = () => (
  <Grommet theme={grommet}>
    <Box align="center" justify="start" pad="large">
      <Clock type="analog" />
    </Box>
  </Grommet>
);

ReactDOM.render(
  <AnalogClock />,
  document.getElementById('clock')
);

package.json

{
  "name": "front",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "grommet": "^2.2.1",
    "react": "^16.7.0",
    "react-dom": "^16.7.0",
    "styled-components": "^4.1.3"
  },
  "devDependencies": {
    "@babel/core": "^7.2.2",
    "@babel/preset-env": "^7.2.3",
    "@babel/preset-react": "^7.0.0",
    "babel-loader": "^8.0.5",
    "webpack": "^4.28.3",
    "webpack-cli": "^3.2.1"
  }
}

webpack.config.js

module.exports = {
  entry:  __dirname + "/index.js",
  output: {
    path: __dirname + "/dist",
    filename: "bundle.js"
  },

  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        query: {
          presets: ['@babel/preset-env','@babel/preset-react']
        }
      }
    ]
  },
}

Frontをビルド

 frontフォルダの package.jsonのあるフォルダに移動して、こんな感じで、npm、webpackと順番にコマンドを打っていきます。distフォルダと、その下にbundle.jsonというファイルが出来上がれば、OKです。

npm install
npx webpack

Editorを実装

 editor側はこの二つのファイルを実装していきます。エディタ側のinit.phpで「wp_enqueue_script」を使って上のFrontでビルドしたbundle.jsをブログ記事で読み込むようにしています。

  • my-block/src/block.js
  • my-block/src/init.php

block.js

 ここは、frontのbundle.jsにある ‘clock’ をidに持ったDivを save: に、edit: の方は、ただ文字「Analog Clock」と表示するようにします。

/**
 * BLOCK: my-block
 *
 * Registering a basic block with Gutenberg.
 * Simple block, renders and saves the same content without any interactivity.
 */

//  Import CSS.
import './style.scss';
import './editor.scss';

const { __ } = wp.i18n; // Import __() from wp.i18n
const { registerBlockType } = wp.blocks; // Import registerBlockType() from wp.blocks

registerBlockType( 'cgb/block-my-block', {
	// Block name. Block names must be string that contains a namespace prefix. Example: my-plugin/my-custom-block.
	title: __( 'my-block - CGB Block' ), // Block title.
	icon: 'shield', // Block icon from Dashicons → https://developer.wordpress.org/resource/dashicons/.
	category: 'common', // Block category — Group blocks together based on common traits E.g. common, formatting, layout widgets, embed.
	keywords: [
		__( 'my-block — CGB Block' ),
		__( 'CGB Example' ),
		__( 'create-guten-block' ),
	],

	edit: function( props ) {
		// Creates a <p class='wp-block-cgb-block-my-block'></p>.
		return (
			<div className={ props.className }>
				<p>Analog Clock</p>
			</div>
		);
	},

	save: function( props ) {
		return (
			<div id="clock"/>
		);
	},
} );

init.php

 wp_enqueue_scriptの引数は、一番最後のscriptをfooterにというところをちゃんとtrueで指定しておかないと、<div id=’clock’> が読み込まれる前に、jsが実行されてしまい、react minified error が出るので注意。

<?php
/**
 * Blocks Initializer
 *
 * Enqueue CSS/JS of all the blocks.
 *
 * @since   1.0.0
 * @package CGB
 */

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}


function my_block_cgb_block_assets() { // phpcs:ignore
	wp_enqueue_script(
		'my_block-cgb-block-js', // Handle.
		plugins_url( '/front/dist/bundle.js', dirname( __FILE__ ) ),
		'',
		'',
		true// Enqueue the script in the footer.
	);
}

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


function my_block_cgb_editor_assets() { // phpcs:ignore
	wp_enqueue_script(
		'my_block-cgb-block-js', // Handle.
		plugins_url( '/dist/blocks.build.js', dirname( __FILE__ ) ), // Block.build.js: We register the block here. Built with Webpack.
		array( 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-editor' ), // Dependencies, defined above.
		'',
		true // Enqueue the script in the footer.
	);
}

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

Blockを確認

 wordpressの設定画面で、pluginをactivateしたあと、記事の投稿でBlockが使えるようになっていれば完成です。(※ Plugin名、Block名は、ジェネレーターで作成されたものをそのまま使っていれば、my-block と言う名前になっていると思います。)

投稿画面