WPのsetMeta()で複数のキーと値を保存する

ちょっと微妙なところはあるのですが、動くところまではできたのでメモとして。
方向性が分かってからは比較的スムーズに進められましたが、必要な情報が出てこない段階では試行錯誤を繰り返していまして、記録用にその段階のコードも記載しています。

前提と問題

  • WordPressでmetaを扱う独自ブロックを開発
  • metaには複数のキーと値を設定したい

上記の前提で以下の問題(といいますかどうすればいいのかわからない部分)が発生します。

  • ハンドブックにあるsetMeta(..meta,{キー:値})の書き方では、複数のキーと値がセットできない

サンプルコード

上記ページで書かれているように、stringではなくobjectを値として渡すことで複数のキーと値を設定できます。
1つ目のページのコードの記述方法を少し変えていますが、以下のようになります。


register_post_meta('post', 'release', [
 'single'       => true,
 'type'         => 'object',
 'show_in_rest' => [
    'schema' => [
     'type'       => 'object',
     'properties' => [
       'version' => [
         'type' => 'string',
       ],
       'artist' => [
         'type' => 'string',
       ],
      ],
    ],
  ],
]);

schema内のpropertiesに必要なキーと型を設定することで複数のキーと値を扱えます。

上記の例であれば、releaseというキーの値として、versionartistという2つのキーを扱う指定になっています。

edit.js内での扱い方

あまり良い例ではないと思いますが、edit.js内での記述は以下のようにして扱えました。


// 以下は必須
const [ meta, setMeta ] = useEntityProp( 'postType', postType, 'meta' );

// 呼び出し
const version = meta.release.version;
const artist = meta.release.artist;

// 保存
const metaProperties = {
  version: "hoge",
  artist: "fuga",
}
setMeta( { ...meta, release: metaProperties } );

onChange内での問題と対応


<TextControl
  label="Version"
  value={ meta.release.version }
  onChange={ ( value ) => {
    setMeta( { ...meta, release: { version: value } );
  } }
/>
<TextControl
  label="Artist Name"
  value={ meta.release.artist }
  onChange={ ( value ) => {
    setMeta( { ...meta, release: { artist: value } );
  } }
/>

サイドバー用のInspectorControls内に上記のようなTextControlをつけ、その入力内容をmetaに取り込む場合に以下のような問題が起こりました。

  • 入力後に一旦「更新」すると、入力値が変更できなくなる(正確には「更新」後に1文字分だけ追加や削除が反映される)
  • 2つ並べると、どちらかが保存されない

記述方法に問題があるとは思いますが、いくつか試したもののsetMeta()を実行すると発生が抑えられなかったため、個人的にはattributesを用いて対応しました。


// 事前にatrributesでversionを用意し、edit.js上で使えるようにしている前提
<TextControl
  label="Version"
  value={ version }
  onChange={ ( value ) => {
    setAttributes( { version: value } );
  } }
/>

meta用ブロックなのでsave.jsにはreturn null;しか書いていないため、「更新」を押してもattributesに値は保存されませんが、一時的な入れ物としては使えます。

あくまで私の場合はですが、元々入力値を保存するボタンを別に設置する設計だったので、このボタン押下時に以下のようにしてsetMeta()を動作させて対応できました。


// onClick時に以下のsaveMetaProperties()を実行させる
const saveMetaProperties = () => {
  const metaProperties = {
    version: attributes.version,
    artist: attributes.artist,
  }
  setMeta( { ...meta, release: metaProperties } );
}

初期値が設定できない

'type'=>'object'にすると、stringの時には使用できていたdefaultが使えなくなります。

解決策を模索しましたが、設定や書き方でどうにかなるものではなさそうなので、edit.js内で初期値を設定する形で解決しました。

サンプルコード(独自版)

前項の方法を試す前に独自で試行錯誤していた際に動いたのが以下に記載する方法です。
バッドノウハウ濃厚なのですが、個人的な記録としては書いておきたいので記載します。

前提として、用いたいキーの数だけregister_post_meta()type:string(object以外)で設定している必要があります。

ちなみにsetMeta()を複数個記載し実行すると、最後に記載したsetMeta()の値だけが保存される模様です。
つまり単に複数個setMeta()を記述しても意図通りに動作しません。

サンプル1


const [ meta, setMeta ] = useEntityProp( 'postType', postType, 'meta' );
const saveMetaProperties = () => {
  meta.hoge1 = value1;
  meta.hoge2 = value2;
  setMeta( { ...meta, 'hoge3': value3 } );
}

meta.hoge1=value1;だけでは値が保存されませんが、最後に一度だけsetMeta()を用いることで、そこまでmetaに入れていたキーと値が保存されることを確認しました。

サンプル2


const [ meta, setMeta ] = useEntityProp( 'postType', postType, 'meta' );
const saveMetaProperties = () => {
  setMeta( {
    meta,
    hoge1: value1,
    hoge2: value2,
    hoge3: value3,
  });
}

第1引数をmetaにして、第2引数以降にキーと値をセットすると保存されました。

GitHubでsetMeta()のコードを確認していた際になんとなく思いついたので試したら動いたという程度で、詳細な検討はしていません。

サンプルコード(詳細未確認)

上記一つ目のスレッドの回答にあるコードを引用します。


var post = new wp.api.models.Post( { id: 1 } );
post.fetch();
post.setMeta('metaKey', 'metaValue');
// Or multiple metas at one time:
post.setMetas({metaKeyOne: 'metaValueOne', metaKeyTwo: 'metaValueTwo'});
post.save()

add_action(
    'init',
    function() {
        register_post_meta('my_post_type', 'my_meta_key', ['show_in_rest' => true, 'single' => true]);
    }
);

使ったことがないので推測になりますが、REST APIを使って直接metaにキーと値を入れる感じでしょうか。

この場合であればpost.setMetasという複数の値に対応する方法が使えるようなので、これを使えば解決できそうです。

結び

今回の用途は、ページのコンテンツ領域外にメインビジュアルを設定したいがためのものでした。

ブロックエディタの範囲外なのでmetaに画像に関する指定を保存するしかなく、最低限画像名とaltの2つは投稿画面から設定できる必要があり、ここをどうにかしたいだけだったのですが、実現までにかなりの時間を使いました。

なお、今後フルサイト編集になった場合にはmetaを使わずとも値の受け渡しができるようになると思いますので、当記事の情報も不要になるような気はします。

1人がこの記事を評価

役に立ったよという方は上の「記事を評価する」ボタンをクリックしてもらえると嬉しいです。

連投防止のためにCookie使用。SNSへの投稿など他サービスとの連動は一切ありません。

コメント欄