WordPress 7.0でadd_meta_boxを廃止してGutenberg APIへ完全移行する方法

Cocoonカスタマイズ集
この記事は約9分で読めます。
記事内に広告が含まれています。

はじめに

WordPress 7.0にて、エディター回りは非常に大きな進化を遂げました。
特に目玉機能である「ビジュアルリビジョン」や「リアルタイム共同編集機能(コラボレーション機能)」は、制作・運用の現場を大きく変える革新的なアップデートです。

しかし、画面内に従来のadd_meta_boxが残っていると、これらの先進的な新機能は動作しません。
そのため、旧来のメタボックスを廃止し、「React + REST API」をベースとしたモダンな設計への移行が不可欠です。

この記事では、この方法について説明します。

完成イメージ

実装手順

以下をadd_meta_boxを廃止し新しい設計へと変更します。


以下のコードをfunctions.phpに追加します。

// メタデータを登録
add_action('init', function () {
  $post_types = ['post', 'page'];

  foreach ($post_types as $post_type) {
    // 投稿日・更新日の非表示フラグ
    register_post_meta($post_type, '_my_date', [
      'show_in_rest'      => true,
      'single'            => true,
      'type'              => 'string',
      'sanitize_callback' => 'sanitize_text_field',
      'auth_callback'     => function () {
        return current_user_can('edit_posts');
      },
    ]);

    // アイキャッチの非表示フラグ
    register_post_meta($post_type, '_my_thumb', [
      'show_in_rest'      => true,
      'single'            => true,
      'type'              => 'string',
      'sanitize_callback' => 'sanitize_text_field',
      'auth_callback'     => function () {
        return current_user_can('edit_posts');
      },
    ]);
  }
});


// エディター用パネルを追加
add_action('enqueue_block_editor_assets', function () {
  wp_enqueue_script('wp-edit-post');

  ob_start();
  ?>
  (function(plugins, editPost, data, components, element) {
    var el = element.createElement;
    var registerPlugin = plugins.registerPlugin;
    var PluginDocumentSettingPanel = editPost.PluginDocumentSettingPanel;
    var useSelect = data.useSelect;
    var CheckboxControl = components.CheckboxControl;

    // メタを取得・マージ・保存
    function updateMetaField(key, value) {
      var currentMeta = wp.data.select('core/editor').getEditedPostAttribute('meta');
      var updatedMeta = Object.assign({}, currentMeta, {
        [key]: value
      });

      wp.data.dispatch('core/editor').editPost({
        meta: updatedMeta
      });
    }

    var PageSettingsPanel = function () {
      var postType = useSelect(function(select) {
        return select('core/editor').getCurrentPostType();
      }, []);

      // メタを取得
      var meta = useSelect(function(select) {
        return select('core/editor').getEditedPostAttribute('meta');
      }, []);

      if (postType !== 'post' && postType !== 'page') {
        return null;
      }

      var isDateChecked  = meta && meta['_my_date'] === '1';
      var isThumbChecked = meta && meta['_my_thumb'] === '1';

      var wrapperStyle = {
        margin: '10px 0'
      };

      return el(
        PluginDocumentSettingPanel,
        {
          name: 'singular-page-settings',
          title: 'ページ設定'
        },

        el(
          'div',
          { style: wrapperStyle },
          el(CheckboxControl, {
            label: '投稿日・更新日を表示しない',
            checked: isDateChecked,
            onChange: function(nextValue) {
              updateMetaField('_my_date', nextValue ? '1' : '');
            }
          })
        ),

        el(
          'div',
          { style: wrapperStyle },
          el(CheckboxControl, {
            label: 'アイキャッチを表示しない',
            checked: isThumbChecked,
            onChange: function(nextValue) {
              updateMetaField('_my_thumb', nextValue ? '1' : '');
            }
          })
        )
      );
    };

    registerPlugin('singular-page-settings', {
      render: PageSettingsPanel
    });
  })(
    window.wp.plugins,
    window.wp.editPost,
    window.wp.data,
    window.wp.components,
    window.wp.element
  );
  <?php
  wp_add_inline_script('wp-edit-post', ob_get_clean());
});


/**
 * 投稿日・更新日の表示設定を変更
 *
 * @param mixed $current_mod 元の表示設定値
 * @return mixed '0' 非表示または元の設定値
 */
if (!function_exists('get_date_visible')):
function get_date_visible($current_mod) {
  if (is_singular()) {
    $date = get_post_meta(get_the_ID(), '_my_date', true);

    if ($date === '1') {
      $mod = 0;
    }
  }

  return $current_mod;
}
endif;


// アイキャッチの表示を変更
add_filter('theme_mod_eyecatch_visible', function ($current_mod) {
  if (is_singular()) {
    $thumb = get_post_meta(get_the_ID(), '_my_thumb', true);

    if ($thumb === '1') {
      $current_mod = 0;
    }
  }

  return $current_mod;
});


// 投稿日の表示を変更
add_filter('theme_mod_post_date_visible', 'get_date_visible');


// 更新日の表示を変更
add_filter('theme_mod_post_update_visible', 'get_date_visible');

注意点

データの先祖返りや消失といった致命的な競合(データ衝突)を防ぐため、カスタムフィールド名には必ずアンダーバーを付与し、_my_dateのような隠しメタキーとして定義します。

標準カスタムフィールド欄からの保存は「ページ全体のクラシックなPOST送信」、サイドバーパネルからの保存は「REST APIによる非同期送信」で行われます。

同じキーを両方から同時に書き換えることができる状態は、データの先祖返りや消失といった致命的な競合(データ衝突)を引き起こす引き金になります。

Reactベース移行への懸念とデメリット

現実の運用において「複数人が同時に一つの投稿をリアルタイム編集するケース」は、大規模なニュースメディアなどを除けばそれほど多くないかもしれません。

そのため、従来のPHPだけで完結していたシンプルな開発環境から、わざわざReactベースの設計へと切り替えることに対して、学習コストや実装の手間という面でデメリットに思えるのも事実です。

さいごに

今回紹介した方法を使えば、Gutenbergエディターの進化を妨げることなく、安全かつ堅牢なカスタム設定パネルを追加することができます。

WordPress 7.0がもたらす「リアルタイム共同編集」や「ビジュアルリビジョン」を活用するために旧来のadd_meta_boxから「React + REST API」への移行を進めてみてください。

タイトルとURLをコピーしました