WordPressのブロックテーマで各投稿のカスタムフィールドを表示する（2024年8月時点）

## はじめに

WordPressはサイト全体を投稿本文のように編集できる「ブロックテーマ」に本格的に移行しています。
多くの資料がありますが、カスタムフィールド（投稿メタ）の表示に関する情報が少ないです。

現実には、画像のようなゴリッゴリのカスタムフィールドを多用したサイトを運用していて、頭を抱えている人も多いのではないかと思います。そのような人の一助となれば幸いです。

![blocktheme_binding_02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21117/3220bb6d-f5c7-d2e9-f62e-5a17509b5d2e.jpeg)

カスタムフィールドを表示することは、できます。
が、この記事を書いている時点では難易度が高めです。また、仕様が変わる可能性も高いです。

読んでいるあなたがWordPressについて常時学習する時間が取れない、納品後の改修ができない状況であれば、他のCMSへの乗り換えを強く勧めます。

## 暫定措置

### ノーコードで表示する

「Snow Monkey Blocks」プラグインには、カスタムフィールドの内容を表示できるブロックがあります。

https://ja.wordpress.org/plugins/snow-monkey-blocks/

ただし表示できるのは文字列だけで、画像カスタムフィールドは画像IDが表示されてしまうため使用できません。出力されるコードはdiv要素となります。

```html
<div class="smb-custom-field wp-block-snow-monkey-blocks-custom-field">
	カスタムフィールドに入力した情報
</div>
```

### 旧来のコードのまま表示する

「Custom Blocks Constructor – Lazy Blocks」は、旧来のWordPressのテーマのコードからブロックを作成できます。

https://ja.wordpress.org/plugins/lazy-blocks/

## Block Bindings APIを使用する

ここからは今後のWordPressの推薦、「ブロックバインディングAPI」を使用する方法の解説です。バージョン6.6を使用している前提です。
お急ぎの方は4.まで飛ばすことができますが、おそらく後悔します。

### 1. Block Bindings APIとは

テンプレートに書いてあるブロックに外部情報を関連付けて、置き換えられる機能です。例として以下のようなことができます。

- クエリループ内の投稿テンプレートや、各記事に配置したブロックの…
    - 段落を、投稿内のカスタムフィールドに登録した文字で置き換える
    - 画像のURLを、投稿内のカスタムフィールドにアップロードした画像のURLで置き換える
    - ボタンのリンク先を、投稿内のカスタムフィールドに登録したURLで置き換える

### 2. 置き換えられる値の制限

記事を書いている時点で、置き換えができるブロックは画像、段落、見出し、ボタンに制限されています。また、見出しと段落以外は**全体のHTMLを置き換えることはできません**。つまり、投稿ループ全体をa要素で囲むなど、大幅な加工はできません。

詳細は以下を参照ください。

https://make.wordpress.org/core/2024/03/06/new-feature-the-block-bindings-api/

例えば画像は、以下の3つの属性値のみ可能です。

- 画像のURL `url`
- 画像の代替テキスト `alt`
- 画像のタイトル `title`

このため、SEOやスライドショーで表示するために、altやtitleも書き換えたい場合は、関連付けをこれらにも行わなくてはなりません。この記事ではURLの差し替えのみ解説します。

### 3. ACFに関する注意

[Advanced Custom Fields](https://ja.wordpress.org/plugins/advanced-custom-fields/)（以降、ACF）プラグインはWordPress公式のカスタムフィールドとは規格が異なるので、後述の `core/post-meta` では表示できません。また、ブロックエディタ内では表示を確認できません。

「6. 画像ブロックを置き換える関数を追加する」の解説は、WordPress公式のカスタムフィールド前提で解説しています。もしかするとACFの画像ブロックだともっと簡単に表示できるかもしれません。この記事を書いている時点で未検証です。すみません。

----

以降、文字、画像のバインディングを解説していきます。

### 4. カスタムフィールドをブロックが参照できるようにする

ACFでカスタムフィールドを作成している場合は、この作業は不要なので飛ばしてください。

現在使用しているテーマの `functions.php` にコードを追記して、ブロックに関連付けたいカスタムフィールドを登録してください。
以下のサンプルコードでは投稿タイプ `sightseeing` に、カスタムフィールド `sightseeing_catch, sightseeing_thumbnail` を関連付けています。

```php
add_action( 'init', 'mysite_register_post_meta' );
if ( ! function_exists( 'mysite_register_post_meta' ) ) {
	function mysite_register_post_meta() {
		register_post_meta(
			'sightseeing',
			'sightseeing_catch',
			array(
				'show_in_rest' => true,
				'sanitize_callback' => 'sanitize_text_field',
				'single' => true
			)
		);
		register_post_meta(
			'sightseeing',
			'sightseeing_thumbnail',
			array(
				'show_in_rest' => true,
				'sanitize_callback' => 'sanitize_text_field',
				'single' => false
			)
		);
	}
}
```

- 以降、 `mysite` はテーマ名などに置き換えてください
- この作業は、将来のバージョンアップで不要になってくれればいいなあと期待しています

入力データの無害化　`sanitize_callback` はこちらの記事が詳しいです。

https://www.mirucon.com/2017/06/21/wordpress-cutomizer-sanitize/

### 5. 文字列フィールドを表示する

画像を置き換えたい場合は、この項は飛ばしてください。

表示したいテンプレートの編集画面へ移動し、右側の詳細メニューから「コードエディター」に切り替えます。
（実はテーマのテンプレートHTMLを直接編集する手もありますが、ここでは割愛します）

![スクリーンショット 2024-08-04 12.08.49.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21117/0ac49202-722d-6090-c213-0e1172c4549a.jpeg)

カスタムフィールドを表示したい段落ブロックを探します。
以下のようになっているはずなので

```html
<!-- wp:paragraph -->
<p>これはキャッチコピー</p>
<!-- /wp:paragraph -->
```

開始タグを以下の通り書き換えてください。 サンプルコードでは `key` にさっき関連付けたカスタムフィールド名 `sightseeing_catch` を指定しています。

```json
<!-- wp:paragraph {
  "metadata":{
    "bindings":{
      "content":{
        "source":"core/post-meta",
        "args":{
          "key":"sightseeing_catch"
        }
      }
    }
  }
} -->
```

ACFの場合は `source` の値を以下の通り `acf/field` としてください。

```json
<!-- wp:paragraph {
  "metadata":{
    "bindings":{
      "content":{
        "source":"acf/field",
        "args":{
          "key":"sightseeing_catch"
        }
      }
    }
  }
} -->
```

編集後、コードエディタを閉じると、段落ブロックが編集できなくなり、文字列がカスタムフィールドに置き換わっているはずです。

### 6. 画像ブロックを置き換える関数を追加する（前半）

現在使用しているテーマの `functions.php` に以下のコードを追記してください。

`register_block_bindings_source` の第一引数 `mysite/image` は控えておいてください。

```php
add_action( 'init', 'mysite_register_block_bindings' );
function mysite_register_block_bindings() {

	register_block_bindings_source( 'mysite/image', array(
		'label' => 'mysite_image',
		'get_value_callback' => 'mysite_image_binding',
		'uses_context' => [ 'postId' ]
	) );

}
```

### `register_block_bindings_source` 関数

ブロックの `source` に第一引数の文字列が指定されていたときだけ、第二引数の `get_value_callback` の値の名前の関数を実行します。 `uses_context` で、その関数に投稿のIDを渡しています。

実行関数 `mysite_image_binding` が必要になることがわかります。

### 7. 画像ブロックを置き換える関数を追加する（後半）

続けて以下のコードを追記してください。 `$image_src` には画像がなかったときのノーイメージのURLを記述してください。

```php
function mysite_image_binding( $source_args, $block_instance ) {
	$image_src = 'https://mydomain/path-to-theme/noimage.png';
	if($block_instance->context['postId'] && $source_args['key']) {
		$image_src = wp_get_attachment_image_url( get_post_meta( $block_instance->context['postId'], $source_args['key'], true ), 'large' );
	}
	return esc_url($image_src);
}
```

ここでは、カスタムフィールドの画像URLを取得しています。最終行の `return` の値がブロックに置き換える内容となります。

### 8. 画像ブロックを表示する

表示したいテンプレートの編集画面へ移動し、右側の詳細メニューから「コードエディター」に切り替えます。

カスタムフィールドを表示したい画像ブロックを探します。
開始タグが以下のようになっているはずなので

```html
<!-- wp:image {（ブロックの設定値が書かれている）} -->
```

以下の通り書き換えてください。 サンプルコードでは `source` に控えておいた`register_block_bindings_source` の第一引数 `mysite/image` 、 `key` にさっき関連付けたカスタムフィールド名 `sightseeing_thumbnail` を指定しています。

```json
<!-- wp:image {
  "metadata":{
    "bindings":{
      "url":{
        "source":"mysite/image",
        "args":{
          "key":"sightseeing_thumbnail"
        }
      }
    }
  },
  （ブロックの設定値が書かれている）
} -->
```

編集後、コードエディタを閉じると、画像ブロックが編集できなくなり、公開画面の画像がカスタムフィールドに置き換わっているはずです。

「7. 画像ブロックを置き換える関数を追加する（後半）」で、 `$source_args['key']` という変数が出てきました。実はここには、ブロックの `key` で指定したカスタムフィールド名が渡されています。
投稿IDとカスタムフィールド名を参照して、画像のURLを取得して置き換える、という仕組みです。

## おわりに

WordPressのブロックテーマで、各投稿のカスタムフィールドを表示する手順は以上です。繰り返しますが、この記事の内容も古い or 間違いがあるかもしれません。コメントでご指摘いただけますと幸いです。

他にもよくあるカスタマイズとして、「カスタムフィールドに入力したURLをボタンのリンク先にする」がありますが、画像フィールドと同じ手順で実装できるので割愛しました。

なお、本文の特定のブロックのHTMLを、一覧ページにそのまま表示することも可能です。記事を書いている時点では、やや魔改造じみたカスタマイズになりますが、今後のバージョンアップによっては、クエリループの検索条件に使用しないカスタムフィールドは不要となるかもしれません。

#### 謝辞

この記事は下記を始めとした、多数のドキュメントを参考にさせていただきました。

- [コアブロックリファレンス – Japanese Team – WordPress.org 日本語](https://ja.wordpress.org/team/handbook/block-editor/reference-guides/core-blocks/#button--%E3%83%9C%E3%82%BF%E3%83%B3)
- [New Feature: The Block Bindings API – Make WordPress Core](https://make.wordpress.org/core/2024/03/06/new-feature-the-block-bindings-api/)
- [クエリ－ループブロックのフィルターフックを使ってみた – ゼロイチプログラミング塾](https://zero1-pg.com/2024/03/18/38367/)
- [Block Bindings API についてしらべる](https://zenn.dev/chiilog/scraps/e6449f644d2ccd)
- [register\_block\_bindings\_source\(\) – Function \| Developer\.WordPress\.org](https://developer.wordpress.org/reference/functions/register_block_bindings_source/)
- [ACF \| ACF 6\.2\.8](https://www.advancedcustomfields.com/blog/acf-6-2-8/)