【WordPress】Prism.js(シンタックスハイライト)をショートコードで使う
HTMLやPHPなどのソースコードを見やすく表示するため、プラグイン:SyntaxHighlighter Evolvedを使用していますが、複数コードを載せた場合の処理が重たく感じます。そこで、軽快に動作するPrism.jsへと変更しました。結果、SyntaxHighlighter Evolvedと比較してかなり軽くなりました。
WordPressでPrism.jsをショートコードで表示するためにハマったポイントをまとめておきます。なお、Prism.jsについてはWordPressでプラグインを使わずにシンタックスハイライトがとても参考になりました。
- PHP
- 7.0
- WordPress
- 4.2.2
- Prism.js
- 1.6.0
Prism.js 読み込み設定
ソースコードは記事ページでのみ載せる予定ですので、ダウンロードしたprism.cssとprism.jsをsingle(記事)ページでのみ読み込むように設定します。
function set_prism_js()
{
if (is_single()) {
wp_enqueue_style('prism-style', get_template_directory_uri(). '/css/prism.css', false, '1.6.0');
wp_enqueue_script('prism-script', get_template_directory_uri(). '/js/prism.js', false, '1.6.0', true);
}
}
add_action('wp_enqueue_scripts', 'set_prism_js');
Prism.jsの使い方
例としてPrism.jsとPrism.jsプラグイン(Line Highlight、Line Numbers、Show Language)を使用した場合のWordPressテキストエディタは以下のようになります。
<pre class="line-numbers" data-line="3" data-language="functions.php">
<code class="language-php">
<?php
echo 'WordPressでPrism.js';
?>
</code>
</pre>
↑が↓と表示されます。
<?php
echo 'WordPressでPrism.js';
?>
ただ、毎回pre
とcode
の入力。そして、<>
などを特殊文字(文字実体参照)へ変換するのは面倒なので、ショートコード化します。
Prism.jsをショートコード化する
先ほどのコードを以下のショートコードで表示できるようにします。
[prism language="php" data_language="functions.php" data_line="3"]
<?php
echo 'WordPressでPrism.js';
?>
[/prism]
ショートコードの定義
ショートコードの使い方は以前に記事でまとめていますので、今回は完成したコードのみを載せておきます。
function shortcode_prism_js($atts, $content = null)
{
extract(shortcode_atts([
'language' => '',
'data_language' => '',
'data_line' => ''
], $atts));
if ($data_language) {
$data_language = ' data-language="'. esc_attr($data_language). '"';
}
if ($data_line) {
$data_line = ' data-line="'. esc_attr($data_line). '"';
}
$format = '<pre class="line-numbers"%s%s><code class="language-%s">%s</code></pre>';
return sprintf(
$format,
$data_language,
$data_line,
esc_attr($language),
htmlspecialchars(trim($content), ENT_QUOTES, 'UTF-8')
);
}
add_shortcode('prism', 'shortcode_prism_js');
ショートコード内のソースコードに余計なタグが入る
先ほどのコードでは、[prism][/prism]内のソースコードに余計な<p></p>
と<br />
が入り、意図するように表示されません。
WordPressには<p></p>
と<br />
を付加するwpautop
という関数があり、デフォルトで記事本文に適用されているようです。ですが、本来であればwpautop
は<pre>...</pre>
タグをスルーするはずです。
調べてみたところ、原因は記事本文を取得表示する関数the_content
に登録されているフィルターの優先順位にありました。ショートコードを展開するdo_shortcode
よりも先にwpautop
を実行するように優先順位が設定されてあります。
// 優先順位が省略されているので、10となる
// 小さい数字の関数から実行される
add_filter( 'the_content', 'wptexturize' );
add_filter( 'the_content', 'convert_smilies' );
add_filter( 'the_content', 'wpautop' );
add_filter( 'the_content', 'shortcode_unautop' );
add_filter( 'the_content', 'prepend_attachment' );
add_filter( 'the_content', 'wp_make_content_images_responsive' );
add_filter( 'the_content', 'do_shortcode', 11 ); // AFTER wpautop()
ですので、wpautop
実行の時点では、[prism][/prism]は単なる文字列として扱われます。当然、<pre>
では無いので、[prism][/prism]内の文字列(ソースコード)にwpautop
が適用されます。
原因がわかったのでwpautop
よりも先に[prism][/prism]を展開させます。
指定のショートコードをwpautopよりも先に展開させる
the_content
をフックして実現させます。the_content
の第3引数の数値(優先順位)にwpautop
よりも少ない数値(10未満)を設定し、指定のショートコードを先に展開させます。
// コメントアウト
// add_shortcode('prism', 'shortcode_prism_js');
add_filter('the_content', function ($content) {
// 登録されている全ショートコード
global $shortcode_tags;
// 登録されているショートコードを退避してから消去
$orig_shortcode_tags = $shortcode_tags;
remove_all_shortcodes();
// wpautop関数実行前に処理したいショートコードをここで登録
add_shortcode('prism', 'shortcode_prism_js');
// [prism]ショートコードを実行
$content = do_shortcode($content);
// 退避したショートコードを元に戻す
$shortcode_tags = $orig_shortcode_tags;
// 実行済みのショートコードを削除
remove_shortcode('prism');
return $content;
}, 9, 1);
以上で意図した動作と表示になりました。
エディタのクイックボタンにprismを追加する
さて、ショートコード化したことでタグ入力よりも簡素になったとは言え、長いショートコードを自分で打つのも同じように面倒です。そこで、prism ショートコードの挿入をエディタのクイックボタンに追加します。
function add_my_quick_btn()
if ( !wp_script_is( 'quicktags' ) ) {
return;
}
?>
<script type="text/javascript">
// QTags.addButton('ID', 'ボタンのラベル', '開始タグ', '終了タグ');
QTags.addButton('prism', 'prism', '[prism language="" data_language="" data_line=""]', '[/prism]');
</script>
<?php
}
add_action('admin_print_footer_scripts', 'add_my_quick_btn');
prismボタンが追加されました。クイックボタンをクリックすると…
[prism language="" data_language="" data_line=""]
[/prism]
が挿入されます。以上で完成です。
追記: ショートコードが展開されない時がある
ショートコードがうまく展開されないときがあり、閉じタグが文字列のまま出力されてしまうときがありましたが、ショートコードの展開よりも先にエスケープ処理をすることで対処できました。
function shortcode_prism_js($atts, $content = null)
{
// ここまで省略
$format = '<pre class="line-numbers"%s%s><code class="language-%s">%s</code></pre>';
return sprintf(
$format,
$data_language,
$data_line,
esc_attr($language),
// htmlspecialchars(trim($content), ENT_QUOTES, 'UTF-8') 消去
$content
);
}
add_filter('the_content', function ($content) {
// ここまで省略
add_shortcode('prism', 'shortcode_prism_js');
$content = preg_replace_callback(
'/\[prism(.+?)\](.+?)\[\/prism\]/su',
function ($matches) {
return '[prism'. $matches[1]. ']'. htmlspecialchars(trim($matches[2]), ENT_QUOTES, 'UTF-8'). '[/prism]';
},
$content
);
$content = do_shortcode($content);
// ここから省略
}, 9, 1);