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 ) で使えます。

基本の流れ

  1. HTML 文字列を渡してインスタンスを作る
  2. next_tag() で目的のタグまで進める
  3. get_attribute()・set_attribute() などで操作する
  4. 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() は、&amp; などの文字参照をデコードした値を返します。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 の役割で、このクラスでは行えない。

関連記事:

お気軽にご相談ください

お見積りへ お問い合わせへ
▲