Wordpress

PrismJSでシンタックスハイライトブロック

以前作ったBlog Cardをパワーアップしようという記事でコードを貼り付けるときにLuxeritasのシンタックスハイライトブロックでHandlebarsのコードがうまくハイライトされなかったのにゃー

人物のアイコン素材 その5

Luxeritasは対応していないので当然では!?

まあそうなんだけど過去の記事を見直したら
以前はハイライト出来ていたはずのものもハイライト出来てない場合があったりして
公式サイトのサンプルもハイライトされてないままになっているので
WordPressのバージョンアップとかでちゃんと動いてないのかも

人物のアイコン素材 その5

そうなんですね
まあこのサイトはソースコードを載せることは稀なので影響は少ないと思いますけど

将来的に独自テーマに移行しようとしているので
プラグインでシンタックスハイライトするようにしようと思ったけど
なんかうまく動かなかったりしたのでLazy Blockでシンタックスハイライトのカスタムブロックを作ってみようと思うの

人物のアイコン素材 その5

Lazy BlockにCode Editorというのがあるけどソレを使うのですか?

なんかそれはProバージョンじゃあないと使えないぽいので独自開発にゃー
といっても一からハイライトする仕組みを一から作るとしんどいので有名どころのPrismを使う実装にしたにゃー

人物のアイコン素材 その5

なるほど

その他の有名どころはhighlight.jsとかReact Syntax Highlighterかな
あとShikiというヤツもあってこれは別記事で書く予定にゃー

人物のアイコン素材 その5

たしかWordPressはReact系なのでReact Syntax Highlighterがいいのでしょうか?

今回は使っていないからわからんがもしかしたらあっさりと導入できるのかも
既に入っていたりして
Prismに先に出会ってしまったのでな
それにVue派だったのでReactとか知らんし

人物のアイコン素材 その5

独自テーマを作ろうとしているのにそんなことで良いのでしょうか?

DenoとかWeb Componentとかもう最新トレンドには疎いにゃー
CSSすらまともに把握できてないのにどんどん機能追加されるからついていけなくなっているにゃー
そこでAIですよ
もうコーディングはAIに任せる!
こちらは指示を与えて動作確認するのが2026年の開発スタイルよ

人物のアイコン素材 その5

単にスキルが追いついてないだけじゃあないのか!?

まあ最初はサンプルとか見ながら作っていたのだけど
調べながらGoogle検索のAIモード使ったらコードを書いてくれるし
こちらの懸念点をカバーする変更も簡単に入れられたからAIにお任せしよう!ということにゃー
まあ完全にお任せできないのでこちらで修正を入れてチェックはAIにしてもらうとかもやったけど

人物のアイコン素材 その5

ヴァイブコーディングというやつか

コードを理解するためにこちらも勉強になるのでAIも使いよう、という感じにゃー

コードのポイント解説

<?php
/**
 * Lazy Blocks: Highlight Code Block (Self-contained)
 *
 * 設計方針(重要):
 * - このコードは「Lazy Blocks 内で完全に自己完結」することを最優先とする
 * - functions.php / enqueue_* は一切使用しない
 * - Lazy Blocks が削除された場合、このコードも完全に消える(副作用ゼロ)
 *
 * 注意:
 * - WordPress / Gutenberg には「Editorかどうか」を PHP 側で正確に判定する手段がない
 * - そのため Editor 専用の見た目変更は CSS セレクタで吸収する
 * - is_admin() は JS の実行制御にのみ使用する(CSS分岐には使わない)
 */


// CDN から読み込む Web Components のバージョン固定
// ※ 将来アップデート時は互換性を必ず確認すること
$SYNTAX_HIGHLIGHT_ELEMENT_VER = '1.2.0';
$LINE_NUMBERS_VER = '1.0.3';

// Lazy Blocks attributes
// ユーザー入力は必ず esc_* して出力する(XSS対策)
$code       = isset( $attributes['code'] ) ? $attributes['code'] : '';
$language   = isset( $attributes['language'] ) ? $attributes['language'] : 'html';
$show_lines = isset( $attributes['show_lines'] ) ? $attributes['show_lines'] : false;
?>

<?php if ( $show_lines ) : ?>
  <pre useBlockProps>
    <code>
      <line-numbers obtrusive>
        <syntax-highlight language="<?php echo esc_attr( $language ); ?>"><?php echo esc_html( $code ); ?>
        </syntax-highlight>
      </line-numbers>
    </code>
  </pre>
<?php else : ?>
<pre useBlockProps>
    <code>
  <syntax-highlight language="<?php echo esc_attr( $language ); ?>"><?php echo esc_html( $code ); ?>
  </syntax-highlight>
    </code>
</pre>
<?php endif; ?>


<?php
/**
 * 二重ロード防止フラグ
 *
 * - 同一ページ内にこのブロックが複数配置された場合でも
 *   JS / CSS を一度だけ出力するための仕組み
 * - enqueue_* と同等の役割だが、Lazy Blocks 内完結を優先している
 */
echo '<script type="module">
  if (!window.__ptSyntaxHighlightLoaded) {
    window.__ptSyntaxHighlightLoaded = true;

  /**
   * シンタックスハイライト用テーマCSS
   * - CDN 配信
   * - Lazy Blocks 削除時に完全に消える
   */
    const link = document.createElement("link");
    link.rel = "stylesheet";
    link.href = "https://cdn.jsdelivr.net/npm/syntax-highlight-element@'
      . esc_attr($SYNTAX_HIGHLIGHT_ELEMENT_VER) . '/dist/themes/prettylights.min.css";
    document.head.appendChild(link);

   /**
   * Web Components(Frontend / Editor 共通)
   *
   * - type="module" を使用(ESM)
   */
    import("https://cdn.jsdelivr.net/npm/syntax-highlight-element@'
      . esc_attr($SYNTAX_HIGHLIGHT_ELEMENT_VER) . '/+esm");

    import("https://cdn.jsdelivr.net/npm/@zachleat/line-numbers@'
      . esc_attr($LINE_NUMBERS_VER) . '/+esm");
  }
</script>';
?>


<?php
/**
 * 共通スタイル(Frontend / Editor 両対応)
 *
 * 注意:
 * - Editor 専用スタイルも「常に出力」される
 * - 実際の適用可否は CSS セレクタで制御する
 */
echo '<style>
.wp-block-lazyblock-highlight-code {
  --prettylights-bg: light-dark(#f6f8fa, #151b23);
  --prettylights-comment: light-dark(#59636e, #9198a1);
  color-scheme: light dark;

  /* 行高・フォントサイズは変数で一元管理 */
  --pt_syntax_highlight_code-line-height: 1.6;
  --pt_syntax_highlight_code-font-size: 16px;

}

.wp-block-lazyblock-highlight-code code {
  display: block;
  color: var(--prettylights-comment, #9198a1);
  background-color: var(--prettylights-bg, #151b23);

  border-radius: 0.5rem;
  padding: 1rem;

  line-height: var(--pt_syntax_highlight_code-line-height);
  font-size: var(--pt_syntax_highlight_code-font-size);

  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco,
    Consolas, "Liberation Mono", "Courier New", monospace;
}

/* line-numbers Web Component */
line-numbers:not(:defined),
line-numbers {
  display: flex;
  white-space: pre;
  user-select: none;
}

line-numbers {
  content-visibility: visible;
}

/* Web Component 初期化前の CLS / FOUC 対策 */
line-numbers:not(:defined) {
  content-visibility: auto;
  contain-intrinsic-size: 1px 200px;
}

/* syntax-highlight Web Component */
syntax-highlight:not(:defined),
syntax-highlight {
  display: block;
  min-height: calc(1em * var(--pt_syntax_highlight_code-line-height));
  padding-inline-start: 1rem;
  user-select: text;
}

/* =========================
  Editor preview only
  =========================
  - Frontend には .editor-styles-wrapper が存在しないため影響しない
  - Lazy Blocks の preview DOM (.lzb-preview-server) を前提にしている
*/
.editor-styles-wrapper
.wp-block-lazyblock-highlight-code
.lzb-preview-server
pre code {
  max-height: 10em;
  overflow-y: auto;
}
</style>';
?>
人物のアイコン素材 その5

これが実際のコードですね

うむ、方針として
Lazy Blocks内だけで完結する
CDN経由でPrism読み込み
パフォーマンス、セキュリティ、SEO観点も重視
EditorとFrontendは同じコードで統一
という基本指示を与えたにゃー

人物のアイコン素材 その5

コメントがあるのでわかりやすいですね

仕上げにコメント入れて!と指示を出したので良い感じに仕上がっているにゃー
さすがはAI様にゃー

人物のアイコン素材 その5

本当に何もしてないな

ちゃんとデバッグしてAIにフィードバックしているにゃー
重要なコアの部分はこちらで書いてAIにリライトしてもらったけど

人物のアイコン素材 その5

そうなんですね

まあもはや最終コードにはその断片しか残ってないのだけど
で、Prismと書いてたけど実際はもう少し高機能な<syntax-highlight> elementというやつを使っているにゃー
これはPrismとブラウザ側のHighlight APIを組み合わせてDOMが少なくなるようになっているみたいにゃー
コード量が多いときもハイライトが重くならないらしいにゃー

人物のアイコン素材 その5

最近はカスタムエレメントとかあるのですね
ちょっとよくわかりませんが

あとこのREADMEから辿ったサンプルに<line-numbers> Web Componentっていうヤツもあったので行番号の処理はコイツに任すことに決めたにゃー

人物のアイコン素材 その5

これもカスタムエレメントですね

コイツをCDN経由で読み込みのだけどブロックごとに読み込みと無駄だから重複ローディング防止を入れたのがポイントの一つにゃー

人物のアイコン素材 その5

テーマ用のCSSもCDN経由で読み込みですね
重複ローディング防止になってますね
ブロック用のCSSはベタ書きですね

うむ
CSSはCSSで面倒くさい部分ではあった
light-dark()関数がいまいちサポート状況が87%と良くなかったのでフォールバックとしてデフォルト値を埋め込むことにしたにゃー
content-visibilityがCLSとかFOUC対策になっているらしいけど本当かどうかよくわからんにゃー

人物のアイコン素材 その5

そこは検索エンジン対策なので本質ではないですね

Lazy Blocks向けのポイントとしては.lzb-preview-serverのCSSでEditorモードだけCSSが適用されるようにした点にゃー
これでProバージョンでなくてもCSSをEditorとFrontendで使い分けできるにゃー

人物のアイコン素材 その5

:not(:defined)のありとなしのものがありますけどこれは何でしょうか?

カスタムエレメントの処理実行前と実行後のセレクターにゃー
JSが実行されるとカスタムエレメントの中身がハイライトされた結果になるのだけど
前後でコンテンツの大きさが変わらないように同じにしているにゃー

人物のアイコン素材 その5

なるほど

最終コードは比較的シンプルなので満足にゃー
でも問題点として対応している言語がHTMLとCSSとJavaScriptだけなのにゃー

人物のアイコン素材 その5

なんだよソレ
じゃあどうやってこのソースコードをハイライトしているのでしょうか?

別記事で書くと言っていたShikiを使ったヤツにゃー
テストのとき、JavaScriptだけで確認していたから気付くのが遅れたにゃー
AIさんも後出しで対応してないとかやるなら設定を追加しないとダメとか言ってきたから限定的なヤツとして断念したにゃー

人物のアイコン素材 その5

確かに指示には書いてなかったですね

PrismJS本体がPHPはデフォルトで組み込まれてなくAutoLoaderとかで別口で読み込む設計になってるぽい
あとHightlight APIでキーワード入れないとPHP対応してくれなさそうにゃー

人物のアイコン素材 その5

それが設定追加というやつですね

デフォルトですべての言語に対応していると思っていたから指示してなかったにゃー
というか後出しで教えるのやめろ!

人物のアイコン素材 その5

指示しか出してないくせに何言ってるのでしょうか!?

まあ別の方法で解決したしLazy BlocksとAI開発の知見も得られたことだし良しとするにゃー
ということで別記事を待て!

人物のアイコン素材 その5

次はちゃんとやれよ

,