コンテンツにスキップ

WordPress でプラグインを使わず繰り返しカスタムフィールドを自作する方法

メインイメージ

WordPress でプラグインを使わずに繰り返しカスタムフィールド(ポストメタ)を自作する方法を紹介します。

Note

ここではすべての値を wp_postmeta テーブルの 1 つのレコードに格納するパターンをご紹介します。 この方法で追加したカスタムフィールドは投稿の検索には使えないのでご注意ください。

繰り返しカスタムフィールド追加後のイメージは次のとおりです。

WordPress 繰り返しカスタムフィールド

今回はデモとして「ラベル」「 URL 」という 2 つのフィールドを持つカスタムフィールドを繰り返せる形を作ります。

やるべきことは大きく 3 つあります。

  1. カスタムフィールドを定義する: init アクション
  2. 投稿編集ページに入力フィールドを追加する: add_meta_boxes アクション
  3. 投稿の保存時にカスタムフィールドの値を更新する: save_post アクション

確認時のバージョン

  • WordPress 6.6.1

WordPress で繰り返しカスタムフィールドを作成する方法

カスタムフィールドの作成はプラグインとテーマのどちらでもできますが、今回はプラグインを使って行います。

wp-content/plugins 以下に custom-field-related-pages というディレクトリを作成してその中にファイルを作成します。

wp-content/plugins
┗ custom-field-related-pages
  ┣ custom-field-related-pages.php
  ┗ custom-field-related-pages.js

まずプラグインのメインファイルを作成します。

custom-field-related-pages.php:

<?php

/**
 * Plugin Name: 繰り返しカスタムフィールド「関連ページ」を「投稿」に追加する
 */

defined( 'ABSPATH' ) || exit;

1. カスタムフィールドを定義する

init アクションと関数 register_post_meta() を使ってカスタムフィールドを定義します。

custom-field-related-pages.php:

add_action ( 'init', function () {
  // カスタムフィールド `related_pages` を登録する:
  register_post_meta( 'post', 'related_pages', [
    'type' => 'array',
    'single' => true,
    'default' => [],
  ] );
} );

2. 投稿編集ページに入力フィールドを追加する

次に add_meta_boxes アクションを使って投稿編集ページに入力フィールドを追加します。

custom-field-related-pages.php:

add_action( 'add_meta_boxes', function () {
  // 「関連ページ」のメタボックスを追加する:
  add_meta_box(
    'related_pages', // ID
    '関連ページ', // 表示タイトル
    'slug_display_meta_box', // コールバック
    'post', // 対象スクリーン
    'normal', // コンテキスト(表示位置)
  );
} );

/**
 * メタボックス related_pages の表示用コールバック
 */
function slug_display_meta_box($post) {
  $related_pages = get_post_meta( $post->ID, 'related_pages', true );
  wp_nonce_field( basename(__FILE__), 'related_pages' );

  // テーブルヘッダー:
  ?>
<div id="custom-field-related-pages">
  <table class="table" width="100%">
    <thead>
      <tr>
        <th width="40%">ラベル</th>
        <th width="40%">URL</th>
        <th width="20%"></th>
      </tr>
    </thead>
    <tbody>
  <?php
  // テーブルボディ:
  // 保存された値がある場合
  if ( ! empty($related_pages) ) {
    foreach ($related_pages as $field) {
  ?>
      <tr>
        <td><input type="text" name="label[]" value="<?php echo esc_attr($field['label']); ?>" /></td>
        <td><input type="text" name="url[]" value="<?php echo esc_attr($field['url']); ?>" /></td>
        <td><a class="button remove-row" href="#">削除</a></td>
      </tr>
  <?php 
    }   
  } else {
  // 保存された値が無い場合
  ?>
      <tr>
        <td><input type="text" name="label[]" /></td>
        <td><input type="text" name="url[]" /></td>
        <td><a class="button remove-row" href="#">削除</a></td>
      </tr>
  <?php 
  } 
  // 追加用の非表示行:
  ?>
      <tr class="empty-row screen-reader-text">
        <td><input type="text" name="label[]" /></td>
        <td><input type="text" name="url[]" /></td>
        <td><a class="button remove-row" href="#">削除</a></td>
      </tr>
    </tbody>
  </table>
  <?php // 追加用ボタン: ?>
  <p><a id="add-row" class="button" href="#">行を追加</a></p>
</div>
  <?php
  // 「削除」と「行を追加」ボタンを機能させる JavaScript コードを追加:
  wp_enqueue_script(
    'custom-field-related-pages',
    plugin_dir_url( __FILE__ ) . '/custom-field-related-pages.js',
    ['jquery'],
    '0.1.0',
    true
  );
}

ページに追加する JavaScript のスクリプトを作成します。

custom-field-related-pages.js:

jQuery(document).ready(($) => {
  const $parent =$('#custom-field-related-pages');
  const $table = $parent.find('table');

  // 「行を追加」ボタンがクリックされたら新たな行を追加する:
  $parent.find('#add-row').on('click', () => {
    const $row = $('.empty-row').clone(true);
    $row.removeClass('empty-row screen-reader-text');
    $row.insertBefore($table.find('tbody>tr:last'));
    return false;
  });

  // 「削除」ボタンがクリックされたら行を削除する:
  $table.on('click', '.remove-row', (event) => {
    $(event.target).parents('tr').remove();
    return false;
  });
});

3. 投稿の保存時にカスタムフィールドの値を更新する

最後に、 save_post アクションを使って投稿の保存時にカスタムフィールドの値を更新する処理を追加します。

add_action( 'save_post', function ($post_id) {
  // nonce チェックを行う:
  $nonce_key = 'related_pages';
  if ( ! isset($_POST[$nonce_key]) || 
    ! wp_verify_nonce($_POST[$nonce_key], basename( __FILE__ ) )) {
    return;
  }

  // 自動保存では処理を行わない:
  if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
    return;
  }

  // ユーザーが編集権限を持たない場合は処理を行わない:
  $post_type = $_POST['post_type'];
  if (!current_user_can('edit_' . $post_type, $post_id)) {
    return;
  }

  // 保存処理を行う:
  $labels = $_POST['label'];
  $urls = $_POST['url'];
  $count = count($labels);

  $new = [];
  foreach (range(0, count($labels) - 1) as $i) {
    if ($labels[$i] != '') {
      $new[$i] = [
      'label' => stripslashes(strip_tags($labels[$i])),
      'url' => stripslashes(strip_tags($urls[$i])),
      ];
    }
  }

  $old = get_post_meta($post_id, 'related_pages', true);
  if (!empty($new) && $new != $old) {
    update_post_meta($post_id, 'related_pages', $new);
  } else if (empty($new) && $old) {
    delete_post_meta($post_id, 'related_pages', $old);
  }
} );

ここまでできたら完了です。

プラグインを有効化して投稿編集ページを開いてください。 投稿編集ページを開くとカスタムフィールドが追加できることが確認できるはずです。

新規作成時は次のように表示されます。

WordPress 繰り返しカスタムフィールド: 初期表示

要素を追加します。

WordPress 繰り返しカスタムフィールド:

さらに追加して投稿を保存します。

WordPress 繰り返しカスタムフィールド:

編集ページを開き直すと、保存した値が格納されて表示され、値が正しく保存されていることが確認できます。

WordPress 繰り返しカスタムフィールド:

以上です。

まとめ

繰り返しカスタムフィールドを追加するには次の 3 つのことをする必要があります。 それぞれ init アクション、 add_meta_boxes アクション、 save_post アクションを使用します。

  1. カスタムフィールドを定義する: init アクション
  2. 投稿編集ページに入力フィールドを追加する: add_meta_boxes アクション
  3. 投稿の保存時にカスタムフィールドの値を更新する: save_post アクション

繰り返しのカスタムフィールドは実装が複雑になりがちですが、今回のようにシンプルな形であればプラグインなしでも比較的シンプルなコードで実装ができます。 ぜひ参考にしてみてください。

サンプルコード

GitHub に置きました。 試したい方は使ってみてください。