カスタム・メタボックス

メタボックスとは ?

ユーザーが投稿を編集する際、編集画面はいくつかのデフォルトボックスで構成されます: エディター、投稿、カテゴリー、タグ等です。これらのボックスはメタボックスです。プラグインは、任意の投稿タイプの編集画面にカスタムメタボックスを追加できます。

カスタム・メタボックスの内容は、通常、プラグインの目的に関連したデータをユーザーが入力する HTML フォーム要素ですが、実質的にはどんな HTML でもかまいません。

なぜメタボックスを使うのですか ?

メタボックスは、編集中の投稿に関連する情報を収集するために使用できる、便利で柔軟なモジュール式の編集画面要素です。カスタム・メタボックスは、他のすべての投稿関連情報と同じ画面に表示されるため、明確な関係が確立されます。

メタボックスは、見る必要のないユーザーには簡単に非表示にでき、見る必要のあるユーザーには表示されます。メタボックスは編集画面上でユーザーが配置できます。ユーザーは自分に合った方法で編集画面を自由に配置でき、編集環境をコントロールできます。

このページに掲載されている例はすべて、説明のためのものです。コードは本番環境には適していません。

入力の安全確保ユーザー権限nonce国際化などの操作は、意図的に省略されています。これらの重要な操作には必ず対処してください。

メタボックスの追加

メタボックスを作成するには、add_meta_box() 関数を使用し、その実行を add_meta_boxes アクションフックに接続します。

次の例は、post 編集画面と wporg_cpt 編集画面にメタボックスを追加するものです。

function wporg_add_custom_box() {
  $screens = [ 'post', 'wporg_cpt' ];
  foreach ( $screens as $screen ) {
    add_meta_box(
      'wporg_box_id',                 // Unique ID
      'Custom Meta Box Title',      // Box title
      'wporg_custom_box_html',  // Content callback, must be of type callable
      $screen                            // Post type
    );
  }
}
add_action( 'add_meta_boxes', 'wporg_add_custom_box' );

wporg_custom_box_html 関数は、メタボックス用の HTML を保持します。

次の例では、フォーム要素、ラベル、その他の HTML 要素を追加しています。

function wporg_custom_box_html( $post ) {
  ?>
  <label for="wporg_field">Description for this field</label>
  <select name="wporg_field" id="wporg_field" class="postbox">
    <option value="">Select something...</option>
    <option value="something">Something</option>
    <option value="else">Else</option>
  </select>
  <?php
}
メタボックスには、送信ボタンがないことに注意してください。 メタボックスの HTML は編集画面のフォームタグの中に含まれ、ユーザーが公開または更新ボタンをクリックすると、メタボックスの値を含むすべての投稿データが POST 経由で転送されます。

ここに示した例には、1つのフォームフィールド、1つのドロップダウンリストしかありません。メタボックスには必要な数だけフィールドを作成できます。大量の表示フィールドがある場合は、複数のメタボックスを使用し、各メタボックスで類似のフィールドをグループ化することを検討してください。ページはより整理され、より視覚的にアピールできます。

値の取得

保存したユーザーデータを取得して利用するには、最初に保存した場所から取得する必要があります。postmeta テーブルに保存されている場合は、get_post_meta() でデータを取得できます。

次の例では、保存されたメタ・ボックスの値にもとづいてあらかじめ入力されたデータで、以前のフォーム要素を拡張しています。メタボックスの値を保存する方法については、次のセクションで説明します。

function wporg_custom_box_html( $post ) {
  $value = get_post_meta( $post->ID, '_wporg_meta_key', true );
  ?>
  <label for="wporg_field">Description for this field</label>
    <select name="wporg_field" id="wporg_field" class="postbox">
      <option value="">Select something...</option>
      <option value="something" <?php selected( $value, 'something' ); ?>>Something</option>
      <option value="else" <?php selected( $value, 'else' ); ?>>Else</option>
    </select>
    <?php
}

selected() 関数について。

値の保存

投稿タイプが保存または更新されると、いくつかのアクションが発生します。入力された値を保存するには、そのどれかにフックするのが適切でしょう。この例では save_post アクションフックを使用していますが、状況によっては他のフックの方が適切かもしれません。一つの更新イベントに対して複数回 save_post が発生する可能性があることに注意してください。こうした条件を念頭に、データを保存する方法を構築してください。

入力されたデータは、WordPress の外であっても、好きな場所に保存できます。おそらく投稿に関連するデータを扱うので、postmeta テーブルはデータを格納するのに都合の良い場所になることが多いです。

次の例は、非表示の _wporg_meta_key メタキーの wporg_field フィールドの値を保存します。

function wporg_save_postdata( $post_id ) {
  if ( array_key_exists( 'wporg_field', $_POST ) ) {
    update_post_meta(
      $post_id,
      '_wporg_meta_key',
      $_POST['wporg_field']
    );
  }
}
add_action( 'save_post', 'wporg_save_postdata' );

実運用コードでは、情報ボックスに概説されているセキュリティ対策に従うことを忘れないでください !

舞台裏

通常、舞台裏で何が起こっているのかを気にする必要はありません。このセクションは完全を期すために追加されました。

投稿編集画面が、追加されたすべてのメタボックスを表示したい場合、do_meta_boxes() 関数を呼び出します。この関数はすべてのメタボックスをループし、それぞれに関連付けられた callback を呼び出します。

それぞれの呼び出しの間に、(div やタイトルなどの) 付随するマークアップが追加されます。

メタボックスの削除

編集画面から既存のメタボックスを削除するには、remove_meta_box() 関数を使用します。渡されるパラメータは、add_meta_box() でメタボックスを追加する際に使用したパラメータと完全に一致しなければなりません。

デフォルトのメタボックスを削除するには、使用されているパラメータのソースコードを確認してください。デフォルトの add_meta_box() 呼び出しは、wp-includes/edit-form-advanced.php から行われます。

実装のバリエーション

これまで、メタボックスの実装には手続き的なテクニックを使ってきました。多くのプラグイン開発者は、他のさまざまなテクニックを使ってメタボックスを実装する必要性を感じています。

OOP (オブジェクト指向プログラミング)

OOP (オブジェクト指向プログラミング) を使ったメタボックスの追加は簡単で、グローバル名前空間での名前の衝突を心配する必要もありません。

メモリを節約し、実装を容易にするために、以下の例では静的メソッドを持つ抽象クラスを使用しています。

abstract class WPOrg_Meta_Box {

  /**
   * Set up and add the meta box.
   */
  public static function add() {
    $screens = [ 'post', 'wporg_cpt' ];
    foreach ( $screens as $screen ) {
      add_meta_box(
        'wporg_box_id',          // Unique ID
        'Custom Meta Box Title', // Box title
        [ self::class, 'html' ],   // Content callback, must be of type callable
        $screen                  // Post type
      );
    }
  }

  /**
   * Save the meta box selections.
   *
   * @param int $post_id  The post ID.
   */
  public static function save( int $post_id ) {
    if ( array_key_exists( 'wporg_field', $_POST ) ) {
      update_post_meta(
        $post_id,
        '_wporg_meta_key',
        $_POST['wporg_field']
      );
    }
  }

  /**
   * Display the meta box HTML to the user.
   *
   * @param WP_Post $post   Post object.
   */
  public static function html( $post ) {
    $value = get_post_meta( $post->ID, '_wporg_meta_key', true );
    ?>
    <label for="wporg_field">Description for this field</label>
    <select name="wporg_field" id="wporg_field" class="postbox">
      <option value="">Select something...</option>
      <option value="something" <?php selected( $value, 'something' ); ?>>Something</option>
      <option value="else" <?php selected( $value, 'else' ); ?>>Else</option>
    </select>
    <?php
  }
}

add_action( 'add_meta_boxes', [ 'WPOrg_Meta_Box', 'add' ] );
add_action( 'save_post', [ 'WPOrg_Meta_Box', 'save' ] );

AJAX (非同期の JavaScript と XML)

メタボックスの HTML 要素は編集画面の form タグの中にあるので、デフォルトの挙動としては、ユーザーがページを投稿した後 に、$_POST スーパーグローバルからメタボックスの値をパース (解析) します。

AJAX を使ってデフォルトの体験を向上させることができます。これにより、(ユーザーがページを送信したかどうかに関係なく) ユーザーの入力と行動にもとづいてアクションを起こすことができます。

トリガーの定義

まず、トリガーを定義する必要があります。これは、リンクのクリック、値の変更、または他の JavaScript イベントでもかまいません。

以下の例では、AJAX リクエストを実行するトリガーとして change を定義します。

/*jslint browser: true, plusplus: true */
(function ($, window, document) {
  'use strict';
  // execute when the DOM is ready
  $(document).ready(function () {
    // js 'change' event triggered on the wporg_field form field
    $('#wporg_field').on('change', function () {
      // our code
    });
  });
}(jQuery, window, document));

クライアントサイドのコード

次に、トリガーに何をさせたいかを定義する必要があります。つまり、クライアントサイドのコードを書く必要があります。

以下の例では POST リクエストを行い、レスポンスは成功か失敗のどちらかで、wporg_field の値が有効か否かを示します。

/*jslint browser: true, plusplus: true */
(function ($, window, document) {
  'use strict';
  // execute when the DOM is ready
  $(document).ready(function () {
    // js 'change' event triggered on the wporg_field form field
    $('#wporg_field').on('change', function () {
      // jQuery post method, a shorthand for $.ajax with POST
      $.post(wporg_meta_box_obj.url,                        // or ajaxurl
        {
          action: 'wporg_ajax_change',                // POST data, action
          wporg_field_value: $('#wporg_field').val(), // POST data, wporg_field_value
          post_ID: jQuery('#post_ID').val()           // The ID of the post currently being edited
        }, function (data) {
          // handle response data
          if (data === 'success') {
            // perform our success logic
          } else if (data === 'failure') {
            // perform our failure logic
          } else {
            // do nothing
          }
        }
      );
    });
  });
}(jQuery, window, document));

WordPress の AJAX ファイルの URL は、次のステップで作成する JavaScript カスタムオブジェクト wporg_meta_box_obj から動的に取得します。

メタボックスが WordPress の AJAX ファイル URL のみを必要とする場合、新しいカスタム JavaScript オブジェクトを作成する代わりに、定義済みの JavaScript 変数 ajaxurl を使用できます。

WordPress の管理画面でのみ利用可能です。 ロジックを実行する前に、空でないことを確認してください。

クライアントサイドのコードをエンキューする

次のステップは、コードをスクリプト・ファイルに入れ、編集画面でそれをエンキューすることです。

以下の例では、右記の投稿タイプの編集画面に AJAX 機能を追加します: post、wporg_cpt

スクリプトファイルは /plugin-name/admin/meta-boxes/js/admin.js に置かれ、plugin-name はメインのプラグインフォルダー、/plugin-name/plugin.php は関数を呼び出すファイルです。

function wporg_meta_box_scripts() {
  // get current admin screen, or null
  $screen = get_current_screen();
  // verify admin screen object
  if (is_object($screen)) {
    // enqueue only for specific post types
    if (in_array($screen->post_type, ['post', 'wporg_cpt'])) {
      // enqueue script
      wp_enqueue_script('wporg_meta_box_script', plugin_dir_url(__FILE__) . 'admin/meta-boxes/js/admin.js', ['jquery']);
      // localize script, create a custom js object
      wp_localize_script(
        'wporg_meta_box_script',
        'wporg_meta_box_obj',
        [
          'url' => admin_url('admin-ajax.php'),
        ]
      );
    }
  }
}
add_action('admin_enqueue_scripts', 'wporg_meta_box_scripts');

サーバーサイドのコード

最後のステップは、リクエストを処理するサーバーサイドのコードを書くことです。

// The piece after `wp_ajax_`  matches the action argument being sent in the POST request.
add_action( 'wp_ajax_wporg_ajax_change', 'my_ajax_handler' );

/**
 * Handles my AJAX request.
 */
function my_ajax_handler() {
  // Handle the ajax request here
  if ( array_key_exists( 'wporg_field_value', $_POST ) ) {
    $post_id = (int) $_POST['post_ID'];
    if ( current_user_can( 'edit_post', $post_id ) ) {
      update_post_meta(
        $post_id,
        '_wporg_meta_key',
        $_POST['wporg_field_value']
      );
    }
  }

  wp_die(); // All ajax handlers die when finished
}

最後の注意点として、このページで説明されているコードには、セキュリティに配慮した重要な操作が欠けています。本番のコードには、そのような操作が含まれていることを確認してください。

AJAX については、ハンドブックの AJAX の章と Codex を参照してください。

詳細情報

原文 / 日本語訳

s
検索
c
新規投稿を作成する
r
返信
e
編集
t
ページのトップへ
j
次の投稿やコメントに移動
k
前の投稿やコメントに移動
o
コメントの表示を切替
esc
投稿やコメントの編集をキャンセル