クラシックブロック(core/freeform)に入力されたHTMLがブロックエディタ上でパースされるときに、JavaScript側の処理でautop(pタグ自動挿入)が起こるのをできるだけ止めたいときがあったので、それを調べたメモ。
★2024年4月9日に完全にやり方を変更しました★
この方法ではTinyMCEによるHTMLの成形を完全に止めることはできないが、多少ましにする。
目次
やりたいこと
入力
<div>
<a class="c-card">
<div class="c-card__image">
<img src="https://placehold.jp/150x150.png" alt="">
</div>
<h3>Title</h3>
</a>
<a class="c-card">
<div class="c-card__image">
<img src="https://placehold.jp/150x150.png" alt="">
</div>
<h3>Title</h3>
</a>
</div>
そのままだとこうなる
<div><a class="c-card">
<div class="c-card__image"><img src="https://placehold.jp/150x150.png" alt="" /></div>
<h3>Title</h3>
<p></p>
</a><br /><a class="c-card">
<div class="c-card__image"><img src="https://placehold.jp/150x150.png" alt="" /></div>
<h3>Title</h3>
<p></p>
</a></div>
求める結果
<div><a class="c-card">
<div class="c-card__image"><img src="https://placehold.jp/150x150.png" alt="" /></div>
<h3>Title</h3>
</a> <a class="c-card">
<div class="c-card__image"><img src="https://placehold.jp/150x150.png" alt="" /></div>
<h3>Title</h3>
</a></div>
コード
★2024年4月9日に完全にやり方を変更しました★
functions.php
// TinyMCE側の自動整形を止める
function tiny_mce_options( $init_array ) {
global $allowedposttags;
$init_array['valid_elements'] = '*[*]';//すべてのHTML要素の許可
$init_array['extended_valid_elements'] = '*[*]';//すべての属性値の許可
$init_array['valid_children'] = '+a[' . implode( '|', array_keys( $allowedposttags ) ) . '|link|meta|style|script]';//aタグの子要素の許可指定。
$init_array['forced_root_block'] = '';//直下に<a>を置いたときの破壊防止
return $init_array;
}
add_filter( 'tiny_mce_before_init', 'tiny_mce_options' );
// クラシックブロックをパースし直すJSを読み込む
function my_theme_enqueue_block_editor_assets() {
// 現在の投稿タイプを取得
$post_type = get_post_type();
// 固定ページである場合のみ
if ('page' === $post_type) {
wp_enqueue_script(
'my-theme-block-editor-script',
get_template_directory_uri() . '/admin.js',
array( 'wp-blocks', 'wp-editor', 'wp-data' )
);
}
}
add_action( 'enqueue_block_editor_assets', 'my_theme_enqueue_block_editor_assets' );
admin.js(ファイル名は何でもOK)
document.addEventListener( 'DOMContentLoaded', function(){
waitForEditorToLoad();
}, false);
//実行が早すぎるとうまく動かないのでエディタの準備完了を待つ
const waitForEditorToLoad = () => {
// wp.data.select メソッドを使用してエディタの読み込み完了を判断します
if ( wp.data.select("core/editor").getCurrentPost().content ) {
swapNoAutopContents();
} else {
// エディタがまだ読み込まれていない場合、ウェイト関数を再度呼び出します
setTimeout( waitForEditorToLoad, 100 );
}
}
//パース前のコンテンツデータをとってきて__unstableSkipAutop: trueの状態でパースし直してエディタに入れなおす
const swapNoAutopContents = ()=>{
let content = wp.data.select("core/editor").getCurrentPost().content;
let blocks = wp.blocks.parse(content, {__unstableSkipAutop: true});
wp.data.dispatch("core/block-editor").resetBlocks(blocks);
}
2024年2月時点の内容
wp.domReady(function () {
// core/freeform のブロックの設定を取得
var coreFreeform = wp.blocks.getBlockType("core/freeform");
// 取得した設定を使ってブロックを再登録し、__unstableSkipAutopを適用
wp.blocks.unregisterBlockType("core/freeform");
wp.blocks.registerBlockType("core/freeform", {
...coreFreeform,
__unstableSkipAutop: true, // オプションを追加…これが効いてるのかどうかは微妙
});
});
function my_theme_enqueue_scripts() {
// 現在の投稿タイプを取得
$post_type = get_post_type();
// 固定ページである場合のみ
if ('page' === $post_type) {
wp_enqueue_script(
'my-block-overrides',
get_stylesheet_directory_uri() . '/blocks/classic.js',
array( 'wp-blocks', 'wp-dom-ready', 'wp-edit-post' )
);
}
}
add_action( 'enqueue_block_editor_assets', 'my_theme_enqueue_scripts' );
このままだとdivを囲んでいるaタグが消滅するので、TinyMCEの方を調整。
やりたいことによってきちんと調整したほうがよさそうだが、いったん暫定で以下。
function tiny_mce_options( $init_array ) {
global $allowedposttags;
$init_array['valid_elements'] = '*[*]';//すべてのHTML要素の許可
$init_array['extended_valid_elements'] = '*[*]';//すべての属性値の許可
$init_array['valid_children'] = '+a[' . implode( '|', array_keys( $allowedposttags ) ) . '|link|meta|style|script]';//aタグの子要素の許可指定。
$init_array['forced_root_block'] = '';//直下に<a>を置いたときの破壊防止
return $init_array;
}
add_filter( 'tiny_mce_before_init', 'tiny_mce_options' );
メモ
この方法を使うと、この実装を行う前に存在したクラシックブロックが、undefinedになり、カスタムHTMLブロックに変換せざるを得なくなる場合がある気がしますが、詳細は未検証です。
また、追加したオプションのskipAutop
自体は意味がなく、単にunregisterBlockTypeしてからregisterBlockTypeしていることに意味があるかも。
参考
Widgets: HTML block is formatted using autop and has its attributes removed
コメント