Web production note

 【更新日 :

【WordPress】ACF 6.2.7以降でthe_field()やthe_sub_field()がHTMLエスケープされる仕様変更への対応方法

記事執筆次点ではACF 6.2.5です。
※本記事は以下のACF 6.2.5 セキュリティリリース記事を元に執筆しているため、今後のアップデート状況によっては適宜加筆修正する可能性があります。

ACF 6.2.7以降 the_field() と the_sub_field() で出力する場合にWordPressのHTMLエスケープ関数 wp_kses() を経由するようになる

ACF 6.2.5では、ショートコード [ acf field="field_name"] に対してWordPressのHTMLエスケープ関数wp_kses()がデフォルトで働くようになりましたが、2024年2月以降に予定されているACF 6.2.7以降には、the_field() と the_sub_field()にもHTMLエスケープ処理がデフォルトで働くようになるそうです。

単純に文字を出力するような想定であれば特に問題ないはずですが、カスタムフィールド内にHTMLタグを登録する想定で実装している場合は、styleタグやscriptタグなどが出力されなくなるはずなので対策が必要です。

From ACF 6.2.5, use of the ACF Shortcode to output an ACF field will be escaped by the WordPress HTML escaping function wp_kses.

This has potential to be a breaking change if you’re using the shortcode ([ acf field=”field_name”]) to output potentially unsafe HTML such as scripts or iframes for textarea or WYSIWYG fields.

【ブラウザ翻訳】
ACF 6.2.5から、ACFフィールドを出力するためにACFショートコードを使用すると、WordPressのHTMLエスケープ関数wp_ksesによってエスケープされます。

ショートコード([ acf field=”field_name”])を使って、textareaやWYSIWYGフィールドにスクリプトやiframeのような潜在的に安全でないHTMLを出力している場合、これは破壊的な変更になる可能性があります。

〜中略〜

From ACF 6.2.7, expected in February 2024, escaping unsafe HTML will also apply to other functions where ACF handles outputting the value of a field, namely the the_field() and the_sub_field() functions. To help get ahead of the impact of this future change, we’ve also added a notice in ACF 6.2.5 alerting you that your site is outputting HTML that will be altered by the escaping coming in 6.2.7.

【ブラウザ翻訳】
2024年2月に予定されているACF 6.2.7からは、安全でないHTMLのエスケープは、ACFがフィールドの値の出力を処理する他の関数、すなわちthe_field()関数とthe_sub_field()関数にも適用されます。この将来的な変更の影響を先取りするために、ACF 6.2.5では、6.2.7で導入されるエスケーピングによって変更されるHTMLを出力しているサイトがあることを警告する通知も追加しました。

https://www.advancedcustomfields.com/blog/acf-6-2-5-security-release/

HTMLが削除された場合はWordPressの管理画面にエラーメッセージが表示される

ACF 6.2.5 からはショートコードで出力された値から安全でない HTML が削除された場合はエラーメッセージを出すようになりました。エラーを検出するたびに、ACF は影響を受けた関数呼び出しに関するデータをログに記録するそうです。

メッセージを完全無効化できるショートコードも用意されました。

add_filter( 'acf/admin/prevent_escaped_html_notice', '__return_true' );

Whenever we detect that escaping the field value has modified the output value, ACF will log data about the affected function call.

Any detected modification will trigger the log, but it may not necessarily be a breaking change. For example, & become & when escaped. This would be detected as a modification, but is unlikely to be a problem as it will still be rendered normally in the browser. In these cases you do not need to make any code changes, instead you can leave the upcoming automatic escaping to work correctly.

This log is stored as an option in the wp_options table. Whenever this log contains entries, the notices in WordPress admin will be shown for all users with the “Editor” role and higher by default. Users with the ability to manage ACF will have the option to view the full details. Users without the ability to manage ACF will be asked to contact their site admin about the error.

Admin users have the ability to dismiss the message, which will also clear the log. Dismissing the notice after you’ve made fixes will allow you to verify you’ve fixed every instance, as the message will not return after the affected pages have been loaded.

【ブラウザ翻訳】
フィールド値のエスケープによって出力値が変更されたことが検出されるたびに、ACF は影響を受けた関数呼び出しに関するデータをログに記録します。

検出された変更はログをトリガーしますが、必ずしも重大な変更であるとは限りません。例えば逃走し&た&場合など。これは変更として検出されますが、ブラウザでは通常どおりレンダリングされるため、問題になる可能性は低いです。このような場合、コードを変更する必要はなく、今後の自動エスケープが正しく機能するようにしておいても問題ありません。

このログはオプションとしてwp_optionsテーブルに保存されます。このログにエントリが含まれる場合は常に、デフォルトで「編集者」以上の役割を持つすべてのユーザーに対して WordPress 管理者の通知が表示されます。ACF を管理できるユーザーには、完全な詳細を表示するオプションがあります。ACF を管理できないユーザーは、エラーについてサイト管理者に問い合わせるよう求められます。

管理者ユーザーはメッセージを閉じることができ、ログも消去されます。影響を受けるページがロードされた後はメッセージが返されないため、修正を行った後で通知を閉じると、すべてのインスタンスが修正されたことを確認できます。

https://www.advancedcustomfields.com/blog/acf-6-2-5-security-release/#detection-and-notice-information

以前の仕様のまま値を出力するには、echo get_field()を利用する

HTMLエスケープさせたくない値に関しては、the_field()を利用せず echo get_field() で値を出力するとエスケープなしで返り値をそのまま出力することができます。

<?php 
  //ACF 6.2.7以降 the_field()はHTMLエスケープされる
  the_field('field_name');

  //HTMLエスケープなしで値をそのまま出力
  echo get_field('field_name');
?>

if you’re confident you can trust every user registered on your site with contributor or higher access—we recommend you use echo get_field() to output this unsafe HTML to ensure it’s not filtered.

【ブラウザ翻訳】
contributor以上のアクセス権を持つサイトに登録されているすべてのユーザーを信頼できると確信している場合は、この安全でないHTMLがフィルタリングされないように、echo get_field()を使用して出力することをお勧めします。

https://www.advancedcustomfields.com/blog/acf-6-2-5-security-release/#how-to-use-acf-securely

apply_filters()でHTMLエスケープを条件付きで無効にする

functions.phpでコントロールしたい場合、以下のフィルターが追加されています。

  • acf/shortcode/allow_unsafe_htmlショートコードのエスケープを無効
  • acf/the_field/allow_unsafe_htmlthe_field()のエスケープを無効

ショートコードのエスケープを無効

apply_filters( 'acf/shortcode/allow_unsafe_html', false, $attributes, $field_type, $field_object );

//利用例
//iframeを出力するために[acf field="podcast_iframe"]を使っている場合
add_filter( 'acf/shortcode/allow_unsafe_html', function ( $allowed, $atts ) {
  if ( $atts['field'] === 'podcast_iframe' ) {
    return true;
  }
  return $allowed;
}, 10, 2 );

the_field()のエスケープを無効

apply_filters( 'acf/the_field/allow_unsafe_html', false, $selector, $post_id, $field_type, $field_object );

//利用例
//google_maps_iframeというフィールドがあり、そこにグーグルマップのiframeが含まれている場合
add_filter( 'acf/the_field/allow_unsafe_html', function( $allowed, $selector ) {
  if ( $selector === "google_maps_iframe" ) {
      return true;
  }
  return $allowed;
}, 10, 2);

フィルターを使ってACF 6.2.5からHTMLエスケープを早期に有効化する

動作検証など今から実施したい場合は、以下のフィルターをfunctions.phpに追加することでthe_field() と the_sub_field() のHTMLエスケープ処理を有効化できます

add_filter( 'acf/the_field/escape_html_optin', '__return_true' );

参考リンク