【WordPress】シンタックスハイライター「Prism.js」を導入する方法

シンタックスハイライター「Prism.js」

Web 上でソースコードを見やすく表示するためのライブラリです。
プラグインで実装されている方も多いようですが、一度入れてみたら重くてもっさりしていたので、私は数年前からずっとこちらを使用しています。

導入すると↓こんな感じにソースコードを表示できます。

test.html

<div class="prism">
<p class="prism_title">test.html</p>
<pre class="line-numbers">
<code class="language-markup">
ここにソースコードを記述
</code></pre></div>

Prism.js の特徴

デザインの細かい変更が可能

JS と CSS がセットになっていて、8種類のテンプレートの中から好きなデザインを選ぶことができます。ダウンロードした CSS ファイルを編集することで自分でデザインを変更することも可能。

必要な機能だけを選んで使える

たくさんの言語とプラグインが用意されており、その中から自分の使いたい機能だけを選んでダウンロードできます。 私が使用しているのは以下のものだけです。

  • デフォルトでチェックされている言語+PHP
  • ワンクリックでソースコードをコピーできるボタン(ツールバーとセット)
  • 指定した行だけハイライト表示する機能
  • 行番号を表示させる機能

ファイルサイズが小さい

機能や言語を増やせば増やしただけファイルサイズが大きくなるので必要なものだけを入れていますが、これで大体 26KB と超軽量です。

導入する方法

Prism.jsにアクセスします。
私が選んだものと同じで良い場合はこちらからアクセスすれば、言語(PHP)と各種プラグインを選んだ状態のダウンロードページに飛べます。テンプレートはデフォルトのままなので、好みのものを選択してください。

デザインのサンプルをチェック

右側の丸が連なっている部分をクリックすると、デザインのテンプレートが適用されたページが表示されます。
好みのデザインをチェックしたら「Download」ボタンを押して選択・ダウンロードページに進んでください。
Prism.js TOP

テンプレートと言語を選ぶ

テンプレートと追加したい言語にチェックを入れます。
デフォルトで選択されている言語は、HTML・CSS・Javascript(C-like とセット)です。

Prism.js CHOSE

プラグインを選びダウンロード

追加したい機能を選んでチェックを入れてダウンロードします。
JS ファイルと CSS ファイル、それぞれをダウンロードする必要がありますのでご注意ください。

Prism.js DOWNLOAD

サーバーにアップロードする

自分のサーバーの適当な場所にアップロードします。
テーマの「library」フォルダーにアップロードすると不具合が出ることがあるそうなので、別の場所にアップロードしてください。私は「wp-content」直下に「library」というフォルダーを作ってそこに入れています。

サイトに適用する

テーマファイルの「header.php」や「footer.php」などに以下のように記述してください。テーマの機能で<head>内に追記できる場合はそこでも大丈夫です。
私は Prism.js を使用する記事でだけ読み込むようにしています。(「記事ごとにCSSなどを記述できるカスタムフィールドを追加」で実装したカスタムフィールドの一番上に CSS を、一番下に JS を入れています)

header.php

<link rel="stylesheet" href="アップロードしたフォルダまでのパス/prism.css">
<script src="アップロードしたフォルダまでのパス/prism.js"></script>
注意
テーマによっては行番号がズレて下に落ちている場合があります(最新バージョンでは SANGO・THE THOR で確認)
直し方は環境によって違うと思うので割愛しますが、当サイトで使用している CSS のサンプルを最下部に置いておきます。SANGO(とPORIPU)ユーザーの方は該当部分を同じように書き換えれば対応できると思います。

記事内での記述の仕方

<code class=language-〇〇"> でマークアップする言語を指定します。
css・javascript・php はそのままですが、HTML の場合は「language-markup」になりますのでご注意ください。

<code>タグの後に改行を入れると1行目に空行が入ります。空行を入れたくない場合は、<code>の後に改行を入れず、続けてソースコードを記述してください。

行番号のプラグインを使用しない場合

html

<pre>
<code class="language-言語名">
ここに表示したいソースコード
</code>
</pre>

行番号や使用言語名を表示させる場合

下記ではコードサンプルと同じようにハイライトする行を指定しています。
使用言語の方は私はプラグインを入れていないので表示されていませんが、プラグインを入れている場合は、下記のように記述すればソースの右上に「Markup」と表示されると思います。

html

<pre class="line-numbers" data-line="2,4-5"> /*行番号の表示とハイライトする行*/
<code class="language-markup" data-language="markup"> /*使用言語の指定と使用言語の表示*/
ここに表示したいソースコード
</code>
</pre>

基本的には「class」で使用する機能を指定して、「data-〇〇」で機能を使用します。
「data-line」ではハイライトする行を指定していて、複数指定する場合は「,」で区切り、「-」で連続する複数行を指定できます。

ソースコードのエスケープ処理

そのままソースコードを記述するとブラウザにコードとして認識されてしまうので、エスケープ処理(実態参照に変換する処理)を行う必要があります。

AddQuictag を使用する場合

プラグイン「AddQuictag」には特殊文字をエスケープするための拡張機能があるので、私は主にこれを使用しています。
設定画面でここにチェックを入れて変更を保存します。

AddQuicktag 設定画面

テキストエディタではこんなボタンが出現します。変換したい文字列を選択してこの「HTML Entities」というボタンを押すだけです。
(もう1つの「Decode HTML」で、エスケープ処理された文字列をHTMLに戻すこともできます)

投稿画面

各種ツールを使用する場合

アプリやテキストエディタのエスケープ処理機能でも変換できますが、お手軽なのは上記の「AddQuicktag」の拡張機能か、下記のようなオンラインツールだと思います。

htmlやスクリプトのコードをpreタグで表示するためメタ文字をエスケープ
HTML特殊文字変換ツール

このサイトの Prism.js のデザイン

ここで使用しているものは「COY」のテンプレートの CSS を編集して、ツールバーのようなものを実装し、左に言語 or 編集するファイル名、右に COPY ボタンを置いています。
あとは、デフォルトの CSS を適用した場合、私の環境だと行番号がコードのエリアの下に表示されていたためそこを直し、モバイル・タブレットからの表示で背景色がズレていたので指定部分の CSS を削除しました。

参考までに、当サイトで使用している html と CSS を置いておきます。
そのままコピペして使用されても構いませんが、一部テーマや子テーマの CSS が適用されている部分があると思うので、お使いのテーマによっては当サイトと同じ表示にはならないかもしれません。

HTML

html

<div class="prism">
<p class="prism_title">ここに左上に表示する文字</p>
<pre class="line-numbers" data-line="ハイライトする行">
<code class="language-マークアップする言語名">
ここにソースコードを記述
</code></pre></div>

<div class="prism> の部分を <div class="prism_min> に変更すると、下記の Prism.css のように画面サイズの60%の大きさでスクロールするようになります。

Prism.css

Prism.css

/* PrismJS 1.15.0
https://prismjs.com/download.html#themes=prism-coy&languages=markup+css+clike+javascript+markup-templating+php+php-extras&plugins=line-highlight+line-numbers+toolbar+copy-to-clipboard */
/**
 * prism.js Coy theme for JavaScript, CoffeeScript, CSS and HTML
 * Based on https://github.com/tshedor/workshop-wp-theme (Example: http://workshop.kansan.com/category/sessions/basics or http://workshop.timshedor.com/category/sessions/basics);
 * @author Tim  Shedor
 */
code[class*="language-"],
pre[class*="language-"] {
	color: black;
	background: none;
	font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
	text-align: left;
	white-space: pre-wrap;
	word-spacing: normal;
	word-break: break-all;
	word-wrap: normal;
	line-height: 2;
	font-family: Arial, sans-serif;
	font-size:.9em!important;
	-moz-tab-size: 4;
	-o-tab-size: 4;
	tab-size: 4;
	-webkit-hyphens: none;
	-moz-hyphens: none;
	-ms-hyphens: none;
	hyphens: none;
}
/* Code blocks */
pre[class*="language-"] {
	position: relative;
	margin:0;
	overflow: visible;
	padding: 0;
	border:none;
}
pre[class*="language-"]>code {
    position: relative;
    box-shadow: 0px -2px 0px 2px #8491c3, 0px 0px 0px 2px #8491c3;
}
code[class*="language"] {
	height: inherit;
	padding: .5em 1em .5em 3.3em!important;
	display: block;
	border-radius:0;
	overflow:visible;
	background: #fcfcfc!important;
}
/* Margin bottom to accommodate shadow */
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
	background-color: transparent;
	-webkit-box-sizing: border-box;
	-moz-box-sizing: border-box;
	box-sizing: border-box;
	margin-bottom: 1em;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
	position: relative;
	padding: .2em;
	border-radius: 0.3em;
	color: #c92c2c;
	border: 1px solid rgba(0, 0, 0, 0.1);
	display: inline;
	white-space: normal;
}
pre[class*="language-"]:before,
pre[class*="language-"]:after {
display:none;
}
:not(pre) > code[class*="language-"]:after,
pre[class*="language-"]:after {
display:none;
}
.token.comment,
.token.block-comment,
.token.prolog,
.token.doctype,
.token.cdata {
	color: #7D8B99;
}
.token.punctuation {
	color: #5F6364;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.function-name,
.token.constant,
.token.symbol,
.token.deleted {
	color: #c92c2c;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.function,
.token.builtin,
.token.inserted {
	color: #2f9c0a;
}
.token.operator,
.token.entity,
.token.url,
.token.variable {
	color: #a67f59;
	background: rgba(255, 255, 255, 0.5);
}
.token.atrule,
.token.attr-value,
.token.keyword,
.token.class-name {
	color: #1990b8;
}
.token.regex,
.token.important {
	color: #e90;
}
.language-css .token.string,
.style .token.string {
	color: #a67f59;
	background: rgba(255, 255, 255, 0.5);
}
.token.important {
	font-weight: normal;
}
.token.bold {
	font-weight: bold;
}
.token.italic {
	font-style: italic;
}
.token.entity {
	cursor: help;
}
.namespace {
	opacity: .7;
}
@media screen and (max-width: 767px) {
	pre[class*="language-"]:before,
	pre[class*="language-"]:after {
		bottom: 14px;
		box-shadow: none;
	}
}
/* Plugin styles */
.token.tab:not(:empty):before,
.token.cr:before,
.token.lf:before {
	color: #e0d7d1;
}
/* Plugin styles: Line Numbers */
pre[class*="language-"].line-numbers.line-numbers {
	padding-left: 0;
}
pre[class*="language-"].line-numbers.line-numbers code {
	padding-left: 3.8em;
}
pre[class*="language-"].line-numbers.line-numbers .line-numbers-rows {
	left: 0;
}
/* Plugin styles: Line Highlight */
pre[class*="language-"][data-line] {
	padding-top: 0;
	padding-bottom: 0;
	padding-left: 0;
}
pre[data-line] code {
	position: relative;
	padding-left: 4em;
}
pre .line-highlight {
	margin-top: 0;
}
pre[data-line] {
	position: relative;
	padding: 1em 0 1em 3em;
}
.line-highlight {
	position: absolute;
	left: 0;
	right: 0;
	padding: inherit 0;
	margin-top: 1em; /* Same as .prism’s padding-top */
	background: hsla(232, 56%, 69%,.08);
	background: linear-gradient(to right, hsla(232, 56%, 69%,.1) 70%, hsla(232, 56%, 69%,0));
	pointer-events: none;
	line-height: inherit;
	white-space: pre;
}
	.line-highlight:before,
	.line-highlight[data-end]:after {
		content: attr(data-start);
		position: absolute;
		top: .4em;
		left: .6em;
		min-width: 1em;
		padding: 0 .5em;
		background-color: hsla(24, 20%, 50%,.4);
		color: hsl(24, 20%, 95%);
		font: bold 65%/1.5 sans-serif;
		text-align: center;
		vertical-align: .3em;
		border-radius: 999px;
		text-shadow: none;
		box-shadow: 0 1px white;
	}
	.line-highlight[data-end]:after {
		content: attr(data-end);
		top: auto;
		bottom: .4em;
	}
.line-numbers .line-highlight:before,
.line-numbers .line-highlight:after {
	content: none;
}
pre[class*="language-"].line-numbers {
	position: relative;
	padding-left: 3.8em;
	counter-reset: linenumber;
}
pre[class*="language-"].line-numbers > code {
	position: relative;
	white-space: inherit;
}
span.line-numbers-rows {
	position: absolute;
	pointer-events: none;
	top: 0;
	font-size: 100%;
	left: -0.2em;
	width: auto; /* works for line-numbers below 1000 lines */
	min-width:2.1em;
	letter-spacing: 0;
	padding-left:.4em;
	padding-top:.5em;
	padding-bottom:.5em;
	background:#eaedf7;
	opacity:.8;
	-webkit-user-select: none;
	-moz-user-select: none;
	-ms-user-select: none;
	user-select: none;
}
	.line-numbers-rows > span {
		pointer-events: none;
		display: block;
		counter-increment: linenumber;
	}
		.line-numbers-rows > span:before {
			content: counter(linenumber);
			color: #999;
			display: block;
			padding-right: 0.5em;
			text-align: center;
		}
div.code-toolbar {
	position: relative;
}
div.code-toolbar > .toolbar {
	position: absolute;
	top: -1.5em;
	right: 0;
    line-height: normal;
}
div.code-toolbar:hover > .toolbar {
	opacity: 1;
}
div.code-toolbar > .toolbar .toolbar-item {
	display: inline-block;
}
div.code-toolbar > .toolbar a {
	cursor: pointer;
}
div.code-toolbar > .toolbar button {
	background: none;
	border: 0;
	color: inherit;
	font: inherit;
	line-height: normal;
	overflow: visible;
	padding: 0;
	-webkit-user-select: none; /* for button */
	-moz-user-select: none;
	-ms-user-select: none;
}
div.code-toolbar > .toolbar a,
div.code-toolbar > .toolbar button,
div.code-toolbar > .toolbar span {
	color: #fcfcfc;
    font-size: .8em;
    line-height: normal;
    padding: .3em 1em;
    background: transparent;
    border-radius: 0;
}
div.code-toolbar > .toolbar a:hover,
div.code-toolbar > .toolbar a:focus,
div.code-toolbar > .toolbar button:hover,
div.code-toolbar > .toolbar button:focus,
div.code-toolbar > .toolbar span:hover,
div.code-toolbar > .toolbar span:focus {
	color: #fcfcfc;
	opacity:.5;
	text-decoration: none;
}
#entry .entry-content p.prism_title {
    margin: 0;
    background:#8491c3;
    color:#fcfcfc;
    font-size:.8em;
    padding:0 1em;
    box-shadow:0px 0px 0px 2.3px #8491c3;
    border-radius:2px;
}
div.prism_min code[class*="language"] {
	max-height: 60vh;
	overflow:auto;
}
div.prism_min code[class*="language"]::-webkit-scrollbar{width: 12px;}
div.prism_min code[class*="language"]::-webkit-scrollbar-track{background: #fbfbfb;}
div.prism_min code[class*="language"]::-webkit-scrollbar-thumb{border-radius:6px;background:#eaedf7;}