2025/10/03

MovableTypeで「『中に任意の種類・数のブロックを追加可能なブロック』を複数抱えたカスタムブロック」を作る

ひさびさにこのトピック。
何を言ってるかまったくわからんタイトルだけどこれ以上簡単に表現できない。

このたび以下のような要望に直面した。

  • MTブロックエディタに標準で備わっている「マルチカラム」は、中(子階層)に任意数の枠を追加することができ、そのまた中(孫階層)で自由にブロックが追加可能になっている。
  • ただし縛りとして、常に等分割のレイアウトとなる。(flex:1;な子要素を抱えるflex要素として作られているため)
  • これを任意の比率、例えば左:右=2:1なんかにして、その中に自由に画像とキャプションなどを置いたりできないか。

というもの。
解決までの道筋を、順を追って書き記しておきたい。

比率指定の2分割レイアウトまでならシンプルにできた

先述の「マルチカラム」ブロックは、ブロック内のカラムごとに「ブロック追加」ボタンがあり、そこでさらに画像ブロックやテキストブロックなどを任意に追加できるという形をしている。
これは他のどのブロックとも違っていて、他はたとえばテキストならテキスト、画像なら画像の入力欄が現れるのみ。

今回の要望は、画像にキャプションがあったりなかったりというブレを許容する必要があり、ある程度任意に編集できるようにしておきたい。
MT標準の「テキストブロック」は、TinyMCE(リッチテキストエディタ)の各種ツールボタンが使えるから、画像挿入もテキスト自由入力の一環としてやってもらえばよいのではないかといったん判断。

ということで、下記の3要素からなるカスタムブロックを作ってみる。
先に書いておくけどこれは不完全なやつです。

  • 「分割比率」(=ドロップダウンブロック)
    →レイアウト(分割比率)指定用に使用。これによって左:右のサイズ比率を可変にする。
    クラス名:horizontalDivision_ratio
    ブロック要素:p(※選択値がいったん書き出されるHTML要素を指定。「なし」にするとJSで整形できないので注意)
    オプション:分割比率の指定用として、作りたい選択肢を任意に用意(今回は1:2, 2:1, 1:3, 3:1を作った)
  • 「左ブロック」(=テキストブロック)
    →横分割される表示コンテンツの左側。
    クラス名:horizontalDivision_left
  • 「右ブロック」(=テキストブロック)
    →横分割される表示コンテンツの右側。
    クラス名:horizontalDivision_right

さらに作成画面を下に進み、やり方を調べて「カスタムスクリプト」欄で出力を整形。
~CompiledHtmlを含む最初と最後の2行はそう書くと決まってるものらしく、おもにlet ratioの行からconst outputの中身までをカスタマイズした。

<script>
document.addEventListener("DOMContentLoaded",()=>{
  if (document.body.dataset.hasCompiledHtml){return;}
  let ratio = document.querySelector('.horizontalDivision_ratio').textContent;
  const cnt_left = document.querySelector('.horizontalDivision_left').innerHTML;
  const cnt_right = document.querySelector('.horizontalDivision_right').innerHTML;
  ratio = ratio.replace(":","fr ") + "fr";
  const output=`
    <div style="display:grid; grid-template-columns:${ratio}; gap:20px;">
      <div>${cnt_left}</div>
      <div>${cnt_right}</div>
    </div>
  `;
  MTBlockEditorSetCompiledHtml(output, true);
});
</script>

ひとまずこれで完成。(表示比率の適用のさせかたが非常に行儀悪いのは何卒スルーの方向で)
さっそくテストしてみたところ、「テキストブロック」のエディタには画像追加のツールボタンがない。事前確認不足!
画像は別途アセットからアップして、imgタグを直書きすれば挿入できないこともないが、それでは不親切にもほどがある。
期待が持てそうな名前をしている「テキスト(複数行)」ブロックや「HTML」ブロックなどを確認するも、逆にツールボタンすらなくて、より悪い。

リッチテキストエディタがだめなら、やはり標準の「マルチカラム」ブロックと同様、あらかじめ設けた分割枠の下層に、画像ブロックやテキストブロックを任意に追加できるようにする方向で解決を図れないかと、ここで路線変更。
それをやるにはすなわち、「ブロックエディタのカスタムブロックの中に『ブロックエディタ』が欲しい」ということになり、そんな不思議なものは当然用意されていない。

「ブロックを追加できるブロックを持つブロック」どう作る

Geminiに尋ねたらプラグインを使ったウソの解決策を教えられ、ChatGPTに尋ねたらWordPressを参考にした話にならん大ウソを教えられてしまった。諦めず再度Geminiを違う角度から問い詰めたところ、現実的なヒントが示された。(無料版ChatGPTは最近のことを何も知らない)
すなわち、「ブロックを自由に追加できる以外に何の機能もないカスタムブロック」をまず自作し、それを今回最終的に作りたいカスタムブロックの中に持たせる という二段階戦略。

カスタムブロックの作成・編集ページの下のほうには、「ブロックの追加・削除を許可する」というチェックボックスがあり、onにすると「追加可能なブロック」欄で追加候補のブロックの種類を選択できるようになっている。
これは通常、カスタムブロック直下(=子階層)に要素を増減させるためのものだが、この操作ができるカスタムブロックを別のカスタムブロックの中に入れ子状態で持たせることで、孫階層の要素もブロックエディタで編集することができるようになるという話。

名前は「内部ブロック追加用」とでもして、ブロック追加用ブロックを作成。(もうゲシュタルト)
プリセットみたいな部分は真っさらにしておく。
追加・削除可能なブロックの指定部分は、明らかにレイアウト崩れを起こしそうなもの以外全種類にチェックが入った状態に。
この「内部ブロック追加用」を、さっき失敗に終わったやつのテキストブロックと入れ替える。全然シンプルな話だった。

結果こうなる。

  • 1つ目:「分割比率」(=ドロップダウン)
    クラス名:horizontalDivision_ratio(オプション等はさっきと同じ)
  • 2つ目:「左ブロック」(=カスタムブロック「内部ブロック追加用」)
    クラス名:horizontalDivision_left
  • 3つ目:「右ブロック」(=カスタムブロック「内部ブロック追加用」)
    クラス名:horizontalDivision_right

クラス名は変えていないので、カスタムスクリプトはさっきのがそのまま使える。
これでめでたく意図通りのものを作ることができた。

blockeditor01.png

出力結果のデモ。(横スクロールが出てるけど左:右=1:2)

blockeditor02.png

自由度の高いカスタムブロックを自作するうえで肝要になりそうな「ブロックエディタの中に置くためのブロックエディタ」が標準では存在せず、しかもあっさり自作できるというのが盲点だった。
この問題でお困りの方、これで早く帰れますように。