2026年8月31日
2026年8月31日
WP_HTML_Tag_Processorの使い方:HTMLのタグ属性やクラスを安全に書き換える
WP_HTML_Tag_Processor は、WordPress 6.2 で追加された HTML API のクラスです。HTML の文字列を先頭から読み進めて目的のタグを見つけ、そのタグの属性やクラスを追加・変更・削除できます。正規表現で <a ...> を置き換える方法と違い、属性値の中の > やコメント、<script> の中身などで誤動作しにくいのが利点です。
この記事では、基本の使い方、the_content やブロック出力での実例、そしてよく誤解される「サニタイズ(危険なタグの除去)には使えない」点を説明します。動作は WordPress 6.9 で確認しています(2026年10月時点)。
できることとできないこと
| できること | できないこと |
|---|---|
タグを名前やクラスで探す(next_tag()) |
タグそのものの削除や追加、入れ子構造の組み替え |
| 属性の取得・追加・変更・削除 | 危険なタグやイベント属性の除去(サニタイズ) |
| クラスの追加・削除・有無の確認 | 親子関係(どの要素の中にあるか)の判定 |
クラスの読み込みや use 文は不要です。WordPress の中で動くコード(テーマ、プラグイン)であれば、そのまま new WP_HTML_Tag_Processor( $html ) で使えます。
基本の流れ
- HTML 文字列を渡してインスタンスを作る
next_tag()で目的のタグまで進めるget_attribute()・set_attribute()などで操作するget_updated_html()で変更後の HTML を受け取る
<?php
$html = '<div class="card"><img src="photo.jpg" alt=""></div>';
$p = new WP_HTML_Tag_Processor( $html );
if ( $p->next_tag( 'img' ) ) {
$p->set_attribute( 'loading', 'lazy' );
$p->set_attribute( 'alt', '商品の写真' );
}
echo $p->get_updated_html();
// <div class="card"><img loading="lazy" src="photo.jpg" alt="商品の写真"></div>
元の文字列は変わらないため、get_updated_html() の戻り値を使うことを忘れないでください。
タグの探し方(next_tag)
next_tag() は、条件に合う次のタグへ進み、見つかれば true を返します。引数は文字列(タグ名)か配列です。
$p->next_tag(); // 次のタグ(種類を問わない)
$p->next_tag( 'a' ); // 次の a タグ
$p->next_tag( array( 'class_name' => 'note' ) ); // class="note" を含むタグ
$p->next_tag( array( 'tag_name' => 'p', 'match_offset' => 2 ) ); // 2番目の p タグ
class_name はクラス名の完全一致で、class="note big" のように複数のクラスがあっても一致します。すべての該当タグを処理するときは while で回します。
$p = new WP_HTML_Tag_Processor( '<p class="note">1</p><p>2</p><p class="note big">3</p>' );
while ( $p->next_tag( array( 'class_name' => 'note' ) ) ) {
$p->remove_class( 'note' );
$p->add_class( 'memo' );
}
echo $p->get_updated_html();
// <p class="memo">1</p><p>2</p><p class="big memo">3</p>
処理は前から後ろへの一方向です。戻って処理し直したいときは、set_bookmark() で位置を記録して seek() で戻るか、インスタンスを作り直します。
主なメソッド
| メソッド | 内容 |
|---|---|
get_tag() |
現在のタグ名を大文字で返す(例: DIV) |
get_attribute( $name ) |
属性値を返す。値の無い属性(hidden など)は true、属性が無ければ null |
set_attribute( $name, $value ) |
属性を追加・変更する。true で値なしの属性、false で削除 |
remove_attribute( $name ) |
属性を削除する |
add_class( $name ) / remove_class( $name ) |
クラスを追加・削除する |
has_class( $name ) |
クラスを持っているかを返す |
class_list() |
クラス名を1つずつ返す(WordPress 6.4 以降) |
get_updated_html() |
変更を反映した HTML を返す |
get_attribute() は、& などの文字参照をデコードした値を返します。set_attribute() には、エスケープしていない普通の文字列を渡します。必要なエスケープは自動で行われ、href や src などの URL 系の属性には esc_url() が適用されます。たとえば javascript: で始まる値を href に設定しようとしても、その値は設定されません。
実例1:本文中の外部リンクに属性を付ける
投稿本文の外部リンクにだけ target="_blank" と rel="noopener noreferrer" を付け、見た目用のクラスを足す例です。子テーマの functions.php か自作プラグインに置きます。
<?php
function my_external_links( $content ) {
if ( false === strpos( $content, '<a' ) ) {
return $content;
}
$home = wp_parse_url( home_url(), PHP_URL_HOST );
$processor = new WP_HTML_Tag_Processor( $content );
while ( $processor->next_tag( 'a' ) ) {
$href = $processor->get_attribute( 'href' );
if ( ! is_string( $href ) ) {
continue; // href が無い、または値の無い属性
}
$host = wp_parse_url( $href, PHP_URL_HOST );
if ( ! $host || $host === $home ) {
continue; // 相対URLや自サイトへのリンクはそのまま
}
$processor->set_attribute( 'target', '_blank' );
$processor->set_attribute( 'rel', 'noopener noreferrer' );
$processor->add_class( 'is-external' );
}
return $processor->get_updated_html();
}
add_filter( 'the_content', 'my_external_links', 20 );
get_attribute() が null(属性なし)や true(<a href> のような値なし)を返す場合があるため、文字列かどうかを確かめてから使っています。既存の rel に値を追加したい場合は、get_attribute( 'rel' ) で今の値を読み、足してから set_attribute() してください。
実例2:先頭の画像だけ優先読み込みにする
最初の画像に fetchpriority="high" を付けて loading を外し、2枚目以降で loading が無いものに loading="lazy" を付ける例です。
function my_lazy_images( $html ) {
$p = new WP_HTML_Tag_Processor( $html );
$count = 0;
while ( $p->next_tag( 'img' ) ) {
++$count;
if ( 1 === $count ) {
$p->set_attribute( 'fetchpriority', 'high' );
$p->remove_attribute( 'loading' );
continue;
}
if ( null === $p->get_attribute( 'loading' ) ) {
$p->set_attribute( 'loading', 'lazy' );
}
}
return $p->get_updated_html();
}
WordPress 本体も画像に loading や fetchpriority を自動で付けています。本体の処理と重ならないか、表示を確かめてから使ってください。
実例3:ブロックの出力に属性を足す
render_block_{ブロック名} フィルターと組み合わせると、特定のブロックの出力だけを書き換えられます。ボタンブロックのリンクに data-track 属性を足す例です。
add_filter(
'render_block_core/button',
function ( $block_content, $block ) {
$p = new WP_HTML_Tag_Processor( $block_content );
if ( $p->next_tag( array( 'tag_name' => 'a', 'class_name' => 'wp-block-button__link' ) ) ) {
$p->set_attribute( 'data-track', 'cta' );
}
return $p->get_updated_html();
},
10,
2
);
ブロックの HTML 構造は WordPress の版で変わることがあるため、クラス名で探す処理は更新後に動作を確認してください。
サニタイズには使わない
このクラスは「指定したタグの属性を書き換える」道具で、危険な HTML を取り除く機能はありません。たとえば set_attribute( 'onclick', ... ) もそのまま設定されますし、<script> タグを削除するメソッドもありません。
利用者が入力した HTML を安全にするには、WordPress の KSES を使います。
- 投稿本文と同じ基準で許可する:
wp_kses_post( $html ) - 許可するタグと属性を自分で決める:
wp_kses( $html, $allowed_html ) - HTML を一切許可しない:
esc_html()(表示時)やsanitize_text_field()(保存時)
KSES で不要なタグを取り除いたあとに、WP_HTML_Tag_Processor で属性を整える、という順番で組み合わせると役割がはっきりします。
入れ子の構造を扱いたいとき
WP_HTML_Tag_Processor は、タグがどの要素の中にあるかを判定しません。「figure の中の img だけ」のように構造を条件にしたい場合は、WordPress 6.4 で追加された WP_HTML_Processor を検討します。WP_HTML_Processor::create_fragment( $html ) で作成し、get_breadcrumbs() で現在のタグまでの要素の並びを取得できます。対応している HTML の範囲は版ごとに広がっているため、使う前に利用中の版で動作を確認してください。
まとめ
WP_HTML_Tag_Processorは、HTML の中のタグを探して属性やクラスを書き換えるクラス(WordPress 6.2 以降)。next_tag()で進め、set_attribute()・add_class()などで変更し、get_updated_html()で結果を受け取る。set_attribute()は値を自動でエスケープし、URL 系の属性にはesc_url()をかける。- 危険な HTML の除去は
wp_kses_post()などの KSES の役割で、このクラスでは行えない。
関連記事: