はじめに
現在、当ブログは WordPress ではなく、Gatsby.js で構築されています 🙇♂️
ブログのテーマ上、ソースコードを貼付することが多いのですが、WordPress で用意されている Syntax 系のプラグインではコードの表示がイマイチ。開発当初はとりあえずプラグインで間に合わせていたのですが、安定運用に入ってからブログを書いてると、痒いところに手が届かないというか、スタイルを頻繁に調整したくなったり、対応している言語が少なかったりと、とにかく何か物足りない感じでした。
しばらく、Enlighter というプラグインを使っていたのですが、良いプラグインではあるのですが、大変感謝しているのですが、どうしても物足りなかったので HTML/CSS/JavaScript での自前実装に切り変えました。
- 行数表示
- コードを折り返し表示ではなく、スクロール表示
- より多くの言語を Syntax Highlight
WordPress ならプラグインを使えば良いのですが、何か満足できない人もいるかと思い、今回はこの実装内容を共有します。
使用経験のある Syntax Highlight プラグイン
ちなみに今まで使用したことのある Syntax Highlight 系プラグインが下記になります。
個人的には Enlighter がそこそこ良いかなと思います。
Enlighter (Version 4.1 CE)
- 開発活発、保守性良好
- 古い言語や Apache などのミドルウェア周りの構文は未サポート
- 評価 4/5 以上
- テーマ15個
Crayon Syntax Highlighter (Version 2.8.4)
- 4年以上アップデートされていない
- 評価 4/5 以上
- 古い言語までサポートしており歴史を感じる
- 根強い人気を誇るが最近は見なくなった?
Highlighting Code Block (Version 1.1.0)
- 日本人が開発(LOOS WEB STUDIO)
- 評価 5/5
- 比較的新しいプラグイン
- 非常にシンプルな設定・構成
tl; dl
実装後
実装前
環境
- PHP 7.3
- WordPress 5.3
実装サンプル
あくまでサンプルで、お使いの WordPress 環境に添うかは分かりません。また、網羅的な OS・ブラウザの表示テストは行っていません、Ubuntu の Chrome では横のスクロールバーが二重表示されるなどの表示崩れを確認しています。
この実装はこちらの Qiita の記事を大いに参考にしています。
HTML
Syntax Highlight を実装するのは難しいので highlight.js と呼ばれる JavaScript のライブラリを使用しました。npm で管理できるのですが、今回は簡単に利用するため CDN を利用しています。
head タグ内に下記を追加してください。
テーマは複数用意されており、公式ページにてテーマの見た目を試すことができます。私は atom-one-dark を選んでいます。
1<!-- highlight.js -->
2<link
3 rel="stylesheet"
4 href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.0.0/styles/atom-one-dark.min.css"
5/>
6<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.0.0/highlight.min.js"></script>
7<script>
8 hljs.initHighlightingOnLoad("");
9</script>
JavaScript
JavaScript ではソースコードの行数を表示するために、行数分だけ空の span タグを追加する関数を実装しています。後述の CSS では span ダグをカウントして行番号を表示するスタイルを適用します。
1window.onload = () => {
2 addNumLinesCode();
3};
4
5/**
6 * Add number of lines for source code
7 */
8const addNumLinesCode = () => {
9 let wp_block_code_elems = document.getElementsByClassName("wp-block-code");
10 if (wp_block_code_elems.length === 0) return null;
11
12 Array.prototype.forEach.call(wp_block_code_elems, (wp_block_code_elem) => {
13 // get code text
14 var code_elem = wp_block_code_elem.getElementsByTagName("code");
15 var code_text = code_elem[0].textContent;
16 var code_lines = code_text.match(/\r\n|\n/g);
17
18 // get code number of lines
19 var code_line_count = 0;
20 if (code_lines !== null) {
21 code_line_count = code_lines.length + 1;
22 } else {
23 code_line_count = 1;
24 }
25
26 // append span-tag to line_numbers_elem for the number of code rows
27 // ex.) <div class="line_number"><span></span><span></span>....</class>
28 var line_numbers_elem = document.createElement("div");
29 for (var i = 0; i < code_line_count; i++) {
30 var span_elem = document.createElement("span");
31 line_numbers_elem.appendChild(span_elem);
32 }
33
34 // insert line-numbers to the first element
35 wp_block_code_elem.insertBefore(line_numbers_elem, code_elem[0]);
36
37 // add line-numbers class
38 line_numbers_elem.classList.add("line-numbers");
39 });
40};
CSS
counter-increment: linenumber で span タグをカウントして、span の擬似要素 after にて counter(linenumber) でカウント数値を表示します。おそらくお使いの環境に応じてその他のスタイルが微調整必要かと思われますので、その際は対応願います。
1.wp-block-code {
2 width: 100%;
3 height: auto;
4 padding: 3.5rem 2rem 2rem 2rem;
5 display: flex;
6 flex-flow: row nowrap;
7 overflow-y: hidden;
8 overflow-x: scroll;
9 background-color: #222222;
10 border: none;
11 border-radius: 1rem;
12 font-size: 1.3rem;
13}
14.wp-block-code code {
15 width: 100%;
16 margin: 0;
17 padding: 0 0 1.5rem 1rem;
18 line-height: 2rem;
19 white-space: pre;
20}
21
22.hljs {
23 background-color: transparent !important;
24}
25.hljs span {
26 line-height: 2rem;
27}
28
29.line-numbers {
30 width: 4rem;
31 height: 100%;
32 margin: 0;
33 padding: 0 1rem 0 0;
34 -webkit-user-select: none;
35 -moz-user-select: none;
36 -ms-user-select: none;
37 user-select: none;
38 border-right: solid 0.1rem rgba(255, 255, 255, 0.4);
39 color: rgba(255, 255, 255, 0.4);
40}
41.line-numbers > span {
42 width: 100%;
43 margin: 0;
44 display: block;
45 counter-increment: linenumber;
46 text-align: right;
47 line-height: 2rem;
48}
49.line-numbers > span::after {
50 content: counter(linenumber);
51}
おわりに
車輪の再発明は良くないと言いますが、脳筋で全てそのロジックで考えるのは良くないですね。十分にテストできていないですが、満足度は結構高いです。何だかんだこの程度の実装なら下手にケチらなければ良かったです。
WordPress はプラグインの数に比例してわかり易く重くなるので、個人開発レベルなら積極的に自前実装した方が良いのかなと感じました。