株式会社オルタ

[解決] get_field() が使えなくなったAdvanced Custom Fields (ACF)の対策

こんばんわ、しのはらです。
寝る前に見つけてしまったので、やっつけな感じですが残しておきます。

【追記】5.11.4 が出た件

2021/12/2 また元に戻ったようです。
元に戻ったとは、5.11.1 のときのようにエラーが出るようになったのです。

更新履歴を見ても特に書かれてません。

さすがにこれでは困るのでACFのソースを追いかけていきました。

で、気が付いたのは新しいフィルターが追加されてました。サイレントに。

以前の動作をサポートしたいならこのフィルターでどうにかしろってことのようです。サイレントに。

ということで完全なる解決策は次のとおりです。

解決策

functions.php に追記します。

// ACF 5.11.4 対策
add_filter('acf/slugify', function($slug, $raw, $glue){
    return str_replace( array( '_', '-', '/', ' ' ), $glue, sanitize_title( strtolower( $raw ) ) );
}, 10, 3);

こちらを追記する場合には注意があります。

自力で acf_add_local_field_group() で登録している場合は、こちらが呼び出される前にフィルターのセットを行う必要があります。

【追記】5.11.3 (5.11.2) が出た件

2021/11/26 get_field() が元に戻ったようです。

私が保守しているWordpressサイトがあって、そこは自動更新を止めています。自動更新を停めて、月に一度手動でアップデートする日を設けています。

それが今日( 2021/11/26 )でした。

ACF で問題が発生することは分かっていたので、まずはローカル環境でアップデートです。

get_field() を使っているページを開き、問題が発生していることを確認・・・し・・・ま・・・

・・・あれ?

同様にget_field() を使っているいくつかのページを確認したのですが、問題なさそう。

ふと、管理画面からプラグインのページを見てみるとバージョン「5.11.3」

いつの間にか、5.11.3 になっていたようです。
これは私の知らない仕様が追加されたのでは?
と、公式のブログをチェックしてみます。

https://www.advancedcustomfields.com/blog/acf-5-11-1-release/

5.11.2、5.11.3 のページが単独であるかな?と思ったのですが無いようで、上記 5.11.1 のページに追記されていました。

Update
ACF 5.11.2 is now available and makes some changes to the details in the original post below.

Now, only the ACF shortcode implements the previously implemented data access changes detailed below, whilst get_field() and the_field() will prevent access to non-ACF options only.

You can read more about this on the acf field functions documentation.

https://www.advancedcustomfields.com/blog/acf-5-11-1-release/

意訳すると、5.11.2 でまた get_field() の仕様を変えて、以前のバージョンに近い形になったようです。
※正確には、get_field() で ACF管理外の値は取れないようになったようですが、普通に使ってる分には意識しなくて良いはずです。

ということで、ACF 5.11 ~ 5.11.1 を使っている方はさっさとバージョンアップしましょう。
下記の、5.11.1 までの対策は必要なくなりました。

ってことで解決っぽいです。

【ACF Changelog】

https://www.advancedcustomfields.com/changelog/

【追記】5.11.1 が出た件

https://www.advancedcustomfields.com/blog/acf-5-11-1-release/

2021/11/20 に5.11.1 がリリースされました。
詳しくはリンク先ですが、ここで初めて get_field() が正式に使えなくなったとアナウンスがありました。

もしかしたら5.11の時点で発表されていて見落としていたのかもしれませんが、本ページに対策をするときに「もしかして?」とその辺りについて入念に調査したときには見つけることができませんでした。

ということで、公式に get_field() が使えなくなったことが分かったので、違う方法で考えます。

ということで、割り切ったバージョンとしては▼のような感じになります。

<?php
namespace aulta;

function get_field( $selector, $post_id = false) {

    global $wpdb;

    $post_id = acf_get_valid_post_id( $post_id );

    $sql = 'SELECT meta_value FROM ' . $wpdb->prefix . 'postmeta WHERE post_id = %d AND meta_key = %s';
    $sql = $wpdb->prepare($sql, $post_id, $selector);
    $rows = $wpdb->get_results($sql, ARRAY_A);
    if ( ! empty($rows)) {
        $row = reset($rows);
        return $row['meta_value'];
    }
    return null;
}
?>

名前空間付きにしても良いですが、get_field という関数名が衝突しなければ関数名はなんでもOKです。

<?php echo \aulta\get_field('キー'); ?>

自分の独自ルールとして「ACFは生データしか扱わない」と決めています。

登録データを取得するとき、自動整形させたりできますが、そういうのは最初から使わないことにしています。整形するなら自前でします。

ってことで、そういうルールを設けている場合は上記で対策完了です。
そうでない場合は、もう少しコードが必要になります。

※追記はここまでです。

get_field() が使えなくなった状況

2021年11月11日に発生
自分のWordpressサイトで一部のページが崩れていることで発見

原因と思われるもの

Advanced Custom Fields (ACF)のバージョンアップが怪しいです。
本現象と同様のツイートをされている方もいらっしゃいました。

解決するための方針

割と深刻な不具合だと思うので、割と早い段階で公式から修正バージョンがリリースされると予想。
そのため、間に合わせ程度のやっつけ対応を方針とします。

Advanced Custom Fields (ACF)内に直接書くことで、バージョンアップで解消されたとき、不要になる本対策も一緒に消えてなくなる作戦です。

対応内容

編集対象のファイル

/wp-content/plugins/advanced-custom-fields/includes/api/api-template.php

23行目の「 $post_id = ・・・」を超えた24行目あたりから、下記の内容を加えます。

// 2021-11-12 ---------------------------------------
global $wpdb;
$sql = 'SELECT meta_value FROM ' . $wpdb->prefix . 'postmeta WHERE post_id = %d AND meta_key = %s';
$sql = $wpdb->prepare($sql, $post_id, $selector);
$rows = $wpdb->get_results($sql, ARRAY_A);
if ( ! empty($rows)) {
    $row = reset($rows);
    return $row['meta_value'];
}
// 2021-11-12 ---------------------------------------

周辺の前後を加えた完成形は次のようになります。
6 ~ 15 行目が追加個所です。

function get_field( $selector, $post_id = false, $format_value = true ) {

	// filter post_id
	$post_id = acf_get_valid_post_id( $post_id );

	// 2021-11-12 ---------------------------------------
	global $wpdb;
	$sql = 'SELECT meta_value FROM ' . $wpdb->prefix . 'postmeta WHERE post_id = %d AND meta_key = %s';
	$sql = $wpdb->prepare($sql, $post_id, $selector);
	$rows = $wpdb->get_results($sql, ARRAY_A);
	if ( ! empty($rows)) {
	    $row = reset($rows);
	    return $row['meta_value'];
	}
	// 2021-11-12 ---------------------------------------

	// get field
	$field = acf_maybe_get_field( $selector, $post_id );

	// create dummy field
	if ( ! $field ) {

		$field = acf_get_valid_field(
			array(
				'name' => $selector,
				'key'  => '',
				'type' => '',
			)
		);

		// prevent formatting
		$format_value = false;

	}

	// get value for field
	$value = acf_get_value( $post_id, $field );

	// format value
	if ( $format_value ) {

		// get value for field
		$value = acf_format_value( $value, $post_id, $field );

	}

	// return
	return $value;

}

あとがき

こちらのファイルは、 Advanced Custom Fields (ACF) がバージョンアップされたときに最新版に置き換わります。

言い換えると、ここで書き換えた内容は消えてなくなります。

次期バージョンでは本不具合が解消されていると信じてこれでOKとします。
次期でもダメだったらそのときに考えます。

ちなみにこれは、私が所有し私が個人的に運営するブログにて行う対策です。

仕事として行う場合は、これ以外に色々考えることが出てきます。

真似するのは自由ですが、自己責任でお願いします。
本記事は知識の共有を目的とし、一切の責任を負うものではありません。