GutenbergでPrism.jsを使う

お久しぶりです。あけましておめでとうございます。今年もよろしくお願いします。

2019年になりましたが、このサイトは開設1周年を迎えることが出来ました。去年までは「Shall we band」のサブドメインを使って運営していたのですが、今年からは新しく「Hobbby.net」というドメインを取得して、再出発いたしました。センスがないのは去年から変わっていません。

さて、そのドメイン変更に伴い、レンタルサーバーもロリポップ!からCore Serverに移行しました。

その時に、テーマも一緒に変更しちゃえということでね、テーマをLuxeritasからCocoonにしたんです。

そしたら、LuxeritasではPrism.jsをショートコードで使えたのに、Cocoonでは使えなくなっちゃったんです。

CocoonはデフォルトでHighLight.jsが使えるようになっているのですが、そのデザイン等が気に入らなかったので、Prism.jsに移行することにしました。

今回はその手順を説明します!

前置きが長くなってしまいましたね、すみません。

① 手動で設定する方法

プラグインなどを用いずに、手動でPrism.jsを設定します。

まず、Prism.jsの公式サイトから、Prism.jsのソースコードをダウンロードします。

https://prismjs.com/download.html

テーマや言語はお好きなのをお選びください。

そして、それをヘッダーで読み込ませます。テーマごとに手順は違いますが、ここではCocoonでの利用方法について解説します。前提として、テーマのファイルを書き換えられるくらいの知識は必要です。

Prism.jsとPrism.cssを配置する

テーマのトップディレクトリにPrism.jsとPrism.jsを配置してください。

テーマのディレクトリ内であればほかの場所でも構いませんが、その場合はこの先のパスを適宜読み替えてください。

functions.phpにコードを追加

wp_enqueue_style('cocoon-child-style-prism', get_stylesheet_directory_uri() . '/prism.css');
wp_enqueue_script('cocoon-child-script-prism', get_stylesheet_directory_uri() . '/prism.js');

この二行を追加してください。一つ目の引数は、ほかのプラグインやテーマなどと被らなければ任意の値に変更可能です。二つ目の引数で、パスを変更できます。

Cocoonの圧縮を無効化

なぜかCocoonで圧縮してしまうと、うまく表示されないので、Cocoonの「高速化」設定から、無効にします。

すべてを無効にするのではなく、この二つを除外するだけで大丈夫です。

ブロックの設定でクラスを追加する

高度な設定の追加CSSクラスに、language-XXX を設定してください。XXXは、使用する言語名です。

以上で設定は完了です。このサイトでは、Prismの追加プラグインline-numbersも使用しているので、line-numbersも追加クラスに設定しています。

② プラグインでブロックを追加する

今度はさっきより高度なことをします。プラグイン作成などに慣れている人には簡単かもしれませんが、僕には大変な作業でした、、、。

慣れていない方は①でやった方が幸せかもしれません。

それではやっていきます。

追記

githubにもっと良さげなのあったので置いておきます。設定の仕方が良くわからないけど、このやり方よりはましかと。

https://github.com/mkaz/code-syntax-block/releases

プラグインの雛形を作成

今回は、wp-cliのscaffoldを使います。もしwp-cliをインストールしていない場合は、手動で作ってください。

wp scaffold plugin prism-blocks

WordPressがインストールされているディレクトリで実行してください。

すると、こんな風にファイルが生成されています。

prism-blocks-v2になってますが、prism-blocksに読み替えてください。

ここにディレクトリ「language-php」を作成します。これも任意です。今回はサンプルとしてphpですがほかの言語でもかまいません。その中に、「index.php」と「block.js」を作成してください。

Babelのインストール

正直自分はここが一番めんどくさかったです。npmが使いにくい。そしてBabelのバージョンが面倒。Webpackもよくわかんない。

https://qiita.com/kurudrive/items/5b0d763367e4177eefbb

このサイトがわかりやすいのでここを参考にさせて頂きました。ありがとうございます。

npmがインストールされていることが前提です。

npm i babel-core babel-loader babel-plugin-transform-react-jsx babel-preset-env cross-env webpack

これでモジュールのインストールは完了です。

それぞれの設定

npmの設定

package.jsonの設定をします。

{
  "name": "prism-blocks",
  "version": "0.1.0",
  "author": "naoki1510",
  "license": "GPL-2.0-or-later",
  "main": "block.js",
  "devDependencies": {
    "babel-core": "^6.25.0",
    "babel-loader": "^7.1.1",
    "babel-plugin-transform-react-jsx": "^6.24.1",
    "babel-preset-env": "^1.6.0",
    "cross-env": "^5.0.1",
    "webpack": "^3.1.0"
  },
  "scripts": {
    "build": "cross-env BABEL_ENV=default NODE_ENV=production webpack",
    "dev": "cross-env BABEL_ENV=default webpack --watch"
  }
}

「scripts」に「”dev”: “cross-env BABEL_ENV=default webpack –watch”」を追加すれば大丈夫だと思います。上の行にコンマをつけるのを忘れずに。

webpackの設定

webpack.config.jsを作成し編集します。

module.exports = [
	{
		entry: './language-php/block.js', //最初に作ったblock.jsのパス
		output: {
			path: __dirname + '/language-php', //最初に作ったディレクトリ
			filename: 'block.build.js',
		},
		module: {
			loaders: [
				{
					test: /.js$/,
					loader: 'babel-loader',
					exclude: /node_modules/,
				},
			],
		},
	}
];

こんな感じですね。複数の言語を扱う場合は、

module.exports = [
	{
		entry: './language-php/block.js',
		output: {
			path: __dirname + '/language-php',
			filename: 'block.build.js',
		},
		module: {
			loaders: [
				{
					test: /.js$/,
					loader: 'babel-loader',
					exclude: /node_modules/,
				},
			],
		},
	}, {
		entry: './language-markup/block.js',
		output: {
			path: __dirname + '/language-markup',
			filename: 'block.build.js',
		},
		module: {
			loaders: [{
				test: /.js$/,
				loader: 'babel-loader',
				exclude: /node_modules/,
			}, ],
		},
	}
];

こんな感じで追加してください。

Babelの設定

.babelrcというファイルを作成し、編集します。

{
    "presets": [
        [
            "env",
            {
                "modules": false
            }
        ]
    ],
    "plugins": [
        [
            "transform-react-jsx",
            {
                "pragma": "wp.element.createElement"
            }
        ]
    ]
}

これは特に解説なしです。僕もよくわかってないので。動けばいいんだ。(だめ

ビルドのテスト

npm run build

...(省略)

WARNING in configuration
    The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
    You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/
    
    ERROR in ./language-php/block.js
    Module build failed (from ./node_modules/babel-loader/lib/index.js):
    Error: Cannot find module '@babel/core'
     babel-loader@8 requires Babel 7.x (the package '@babel/core'). If you'd like to use Babel 6.x ('babel-core'), you should install 'babel-loader@7'.
        at Function.Module._resolveFilename (internal/modules/cjs/loader.js:603:15)
        at Function.Module._load (internal/modules/cjs/loader.js:529:25)
        at Module.require (internal/modules/cjs/loader.js:657:17)
        at require (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/v8-compile-cache/v8-compile-cache.js:159:20)
        at Object.<anonymous> (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/babel-loader/lib/index.js:10:11)
        at Module._compile (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/v8-compile-cache/v8-compile-cache.js:178:30)
        at Object.Module._extensions..js (internal/modules/cjs/loader.js:732:10)
        at Module.load (internal/modules/cjs/loader.js:620:32)
        at tryModuleLoad (internal/modules/cjs/loader.js:560:12)
        at Function.Module._load (internal/modules/cjs/loader.js:552:3)
        at Module.require (internal/modules/cjs/loader.js:657:17)
        at require (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/v8-compile-cache/v8-compile-cache.js:159:20)
        at loadLoader (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/loader-runner/lib/loadLoader.js:13:17)
        at iteratePitchingLoaders (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/loader-runner/lib/LoaderRunner.js:169:2)
        at runLoaders (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/loader-runner/lib/LoaderRunner.js:362:2)
        at NormalModule.doBuild (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/webpack/lib/NormalModule.js:280:3)
        at NormalModule.build (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/webpack/lib/NormalModule.js:427:15)
        at Compilation.buildModule (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/webpack/lib/Compilation.js:633:10)
        at moduleFactory.create (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/webpack/lib/Compilation.js:1019:12)
        at factory (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/webpack/lib/NormalModuleFactory.js:405:6)
        at hooks.afterResolve.callAsync (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/webpack/lib/NormalModuleFactory.js:155:13)
        at AsyncSeriesWaterfallHook.eval [as callAsync] (eval at create (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/tapable/lib/HookCodeFactory.js:32:10), <anonymous>:6:1)
        at AsyncSeriesWaterfallHook.lazyCompileHook (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/tapable/lib/Hook.js:154:20)
        at resolver (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/webpack/lib/NormalModuleFactory.js:138:29)
        at process.nextTick (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/webpack/lib/NormalModuleFactory.js:342:9)
        at process.internalTickCallback (internal/process/next_tick.js:70:11)
npm ERR! code ELIFECYCLE
npm ERR! errno 2
npm ERR! prism-blocks-v2@0.1.0 build: `cross-env BABEL_ENV=default NODE_ENV=production webpack`
npm ERR! Exit status 2
npm ERR! 
npm ERR! Failed at the prism-blocks-v2@0.1.0 build script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

エラーじゃん

なんかwebpack@4はめんどくさそうで情報も少なかったのでwebpack@3を入れなおします。

npm uninstall webpack
npm install webpack@3

そしてまたビルド。

npm run build

...(省略)

         Asset     Size  Chunks             Chunk Names
    block.build.js  5.48 kB       0  [emitted]  main
       [0] ./language-php/block.js 3.01 kB {0} [built] [failed] [1 error]
    
    ERROR in ./language-php/block.js
    Module build failed: Error: Cannot find module '@babel/core'
     babel-loader@8 requires Babel 7.x (the package '@babel/core'). If you'd like to use Babel 6.x ('babel-core'), you should install 'babel-loader@7'.
        at Function.Module._resolveFilename (internal/modules/cjs/loader.js:603:15)
        at Function.Module._load (internal/modules/cjs/loader.js:529:25)
        at Module.require (internal/modules/cjs/loader.js:657:17)
        at require (internal/modules/cjs/helpers.js:22:18)
        at Object.<anonymous> (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/babel-loader/lib/index.js:10:11)
        at Module._compile (internal/modules/cjs/loader.js:721:30)
        at Object.Module._extensions..js (internal/modules/cjs/loader.js:732:10)
        at Module.load (internal/modules/cjs/loader.js:620:32)
        at tryModuleLoad (internal/modules/cjs/loader.js:560:12)
        at Function.Module._load (internal/modules/cjs/loader.js:552:3)
        at Module.require (internal/modules/cjs/loader.js:657:17)
        at require (internal/modules/cjs/helpers.js:22:18)
        at loadLoader (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/loader-runner/lib/loadLoader.js:13:17)
        at iteratePitchingLoaders (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/loader-runner/lib/LoaderRunner.js:169:2)
        at runLoaders (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/loader-runner/lib/LoaderRunner.js:362:2)
        at NormalModule.doBuild (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/webpack/lib/NormalModule.js:182:3)
        at NormalModule.build (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/webpack/lib/NormalModule.js:275:15)
        at Compilation.buildModule (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/webpack/lib/Compilation.js:157:10)
        at moduleFactory.create (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/webpack/lib/Compilation.js:460:10)
        at factory (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/webpack/lib/NormalModuleFactory.js:243:5)
        at applyPluginsAsyncWaterfall (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/webpack/lib/NormalModuleFactory.js:94:13)
        at /var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/webpack/node_modules/tapable/lib/Tapable.js:268:11
        at NormalModuleFactory.params.normalModuleFactory.plugin (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/webpack/lib/CompatibilityPlugin.js:52:5)
        at NormalModuleFactory.applyPluginsAsyncWaterfall (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/webpack/node_modules/tapable/lib/Tapable.js:272:13)
        at resolver (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/webpack/lib/NormalModuleFactory.js:69:10)
        at process.nextTick (/var/www/html/wp-content/plugins/prism-blocks-v2/node_modules/webpack/lib/NormalModuleFactory.js:196:7)
        at process.internalTickCallback (internal/process/next_tick.js:70:11)
npm ERR! code ELIFECYCLE
npm ERR! errno 2
npm ERR! prism-blocks-v2@0.1.0 build: `cross-env BABEL_ENV=default NODE_ENV=production webpack`
npm ERR! Exit status 2
npm ERR! 
npm ERR! Failed at the prism-blocks-v2@0.1.0 build script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

エラーじゃん(二回目)

babel-loader@8はbabel-core@7が必要なので、バージョンをさげろということらしいです。

npm install babel-loader@7

これでどうだ!

npm run build

...(省略)

             Asset     Size  Chunks             Chunk Names
    block.build.js  4.02 kB       0  [emitted]  main
       [0] ./language-php/block.js 1.55 kB {0} [built]

できたー!感動!多分これにまる一日かかった。

やっと中身のblock.jsに取り掛かれる。

block.jsの作成

const { __, setLocaleData } = wp.i18n;
const { registerBlockType } = wp.blocks;
const { PlainText } = wp.editor;

registerBlockType( 'prism-blocks/prism-blocks-php', {
	title: __( 'prism-blocks-php', 'prism-blocks' ), #名前
	icon: 'editor-code', #アイコン
	category: 'formatting', #カテゴリ
	attributes: { # ここはよくわかんない
		content: {
			type: 'string',
			source: 'text',
			selector: 'code',
		},
	},

	supports: { #これもよくわかんない
		html: false,
	},

	transforms: { #エンター押しても改行されないようにするのかな?
		from: [
			{
				type: 'enter',
				regExp: /^```$/,
				transform: () => createBlock( 'core/code' ),
			},
			{
				type: 'raw',
				isMatch: ( node ) => (
					node.nodeName === 'PRE' &&
					node.children.length === 1 &&
					node.firstChild.nodeName === 'CODE'
				),
				schema: {
					pre: {
						children: {
							code: {
								children: {
									'#text': {},
								},
							},
						},
					},
				},
			},
		],
	},

	edit: ( props ) => { # Gutenbergのまるまんまコピー
		const { attributes, setAttributes, className } = props;
		return (
			<PlainText
				value={ attributes.content }
				onChange={ ( content ) => setAttributes( { content } ) }
				placeholder={ __( 'Write code…' ) }
				aria-label={ __( 'Code' ) }
			/>
		);
	},
	save: ( props ) => { # ここが重要!className='language-php'が重要!
		return <pre className={ props.className }><code className='language-php'>{ props.attributes.content }</code></pre>
	},
} );

こんな感じですね。

WordPress公式のGutenbergのGitHubから、コードを持ってきました。

https://github.com/WordPress/gutenberg/blob/master/packages/block-library/src/code/index.js

ここですね。

ブロックを登録

prism-blocks.phpを編集します。

<?php
/**
 * Plugin Name:     Prism Blocks
 * Plugin URI:      PLUGIN SITE HERE
 * Description:     PLUGIN DESCRIPTION HERE
 * Author:          YOUR NAME HERE
 * Author URI:      YOUR SITE HERE
 * Text Domain:     prism-blocks
 * Domain Path:     /languages
 * Version:         0.1.0
 *
 * @package         Prism_Blocks
 */

defined('ABSPATH') || exit;

/**
 * Load all translations for our plugin from the MO file.
 */
add_action('init', 'prism_blocks_load_textdomain');

function prism_blocks_load_textdomain()
{
    load_plugin_textdomain('prism-blocks', false, basename(__DIR__) . '/languages');
}

wp_enqueue_script('prism-blocks-script', plugins_url('prism.js', __FILE__), [], '1.15.0', false);
// スクリプト読み込み
wp_enqueue_style('prism-blocks-styles', plugins_url('prism.css', __FILE__), [], '1.15.0', 'all');
// スタイルシート読み込み

include 'language-php/index.php';

次にlanguage-php/index.phpの編集

<?php
/**
 * Registers all block assets so that they can be enqueued through Gutenberg in
 * the corresponding context.
 *
 * Passes translations to JavaScript.
 */
function prism_blocks_php_register_block() {

	if ( ! function_exists( 'register_block_type' ) ) {
		// Gutenberg is not active.
		return;
	}

	wp_register_script(
		'prism-blocks-php',
		plugins_url( 'block.build.js', __FILE__ ),
		array( 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-editor' ),
		filemtime( plugin_dir_path( __FILE__ ) . 'block.build.js' )
	);

	register_block_type( 'prism-blocks/prism-blocks-php', array(
		'editor_script' => 'prism-blocks-php',
	) );
}
add_action( 'init', 'prism_blocks_php_register_block' );

もう面倒なのであんまり詳しい解説はしません。これで動くと思います!!

動かなかったら必ずエラーを添えてコメントください!

プラグイン有効化!

で、WordPressのダッシュボードから、prism-blocksを有効化します。

で、ブロックの「フォーマット」カテゴリにprism-blocks-phpがあれば成功です!お疲れ様でした!!

絶対①のほうが楽だよなこれ。

別の言語を追加する方法

「php」をすべてその言語に置き換えればできます。

index.phpに、

include 'language-XXX/index.php';

と追記してください。

あ、<?phpのphpは書き換えちゃだめですよ。

Gutenbergのブロック作成は大変だった

もう面倒。これからもう少し使いやすくするために、オプションで言語を選べるようにとか、line-highlightを使ったりとか考えてたけど疲れた。今度。

Gutenbergのブロックを追加するプラグインのダウンロード

注意!

  • 何か損害を与えても、ウイルスが入っていても全く責任を取りません!
  • node_modulesも含まれています。
  • デバッグできる環境なので、通常利用には不要なファイルが含まれています。必要に応じて消去してください。
  • 素人が書いたくそみたいなコードです。サイトが重くなっても真っ白になっても知りません。

脅迫文みたいなこと書きましたが、あまり利用は推奨しません。自分で作った方が安全なんじゃないかと。