Cocoonフォーラム

サイト内検索
書き込みの前に以下の3点をご確認ください。
  1. 1つのトピックにつき1つの質問を書き込んでください
  2. 不具合・カスタマイズ対象ページのURLを提示高速化を無効にしてください
  3. 該当部分のキャプチャ・環境情報とともに書き込んでいただけると助かります

何を書き込んだら良いか分からない場合は、以下のテンプレートをコピペしてご利用ください。

不具合・カスタマイズ対象ページのURL:

相談内容:

不具合の発生手順:

解決のために試したこと:

※文字だけでは正しく伝わらない可能性があるため、スクショ画像の添付もお願いします。
※高速化設定をしている場合は無効にしてください。
環境情報:

※↑こちらに「Cocoon設定 → テーマ情報」にある「環境情報」を貼り付けてください。

環境情報の取得方法はこちら。
https://wp-cocoon.com/theme-report/
高速化設定を無効にするにはこちら。
https://wp-cocoon.com/theme-trouble/

フォーラム利用ガイドリンク

  1. フォーラムガイドライン
  2. よくある質問と答え(FAQ)
  3. サポート対象外のケース
  4. 原因不明の不具合用トラブルシューティング
  5. トピックにHTMLを貼り付ける方法(推奨ツール:notepad.pw
  6. 真っ白画面でのエラーメッセージの確認方法
  7. ブラウザ環境チェックツール
  8. Cocoonカスタマイズ依頼

フォーラム質問後、問題等が解決した場合は結果を書き込んでいただけると幸いです。同様の問題で調べている方には、結果が一番気になる部分となります。

共有:
通知
すべてクリア

[解決済] Cocoonのwp_termmeta設計に関する問題

24 投稿
2 ユーザー
5 Reactions
2,771 表示
ろこ
(@lococo)
Prominent Member Registered
結合: 7年前
投稿: 830
Topic starter  

WordPressにDBのテーブルにwp_termmetaが追加され、カテゴリー・タグページのカスタムフィールドが作成しやすくなりました。
Cocoonでも、「カテゴリ色」以下の設定ではこのタームメタが使用されています。

実際に直接問題が生じたわけではないのですが、独自のタームメタカスタマイズ実装中にCocoonでのwp_termmetaの取り扱いについて問題を感じ、今後のために一応問題となり得る点を共有させていただきます。

以下、wp_postmetaと比較してみるのが分かりやすいかもしれません。


Cocoonではmeta_keyが{taxonomy}_meta_{term_id}、そしてCocoonの全カスタムフィールド値をひとつの配列にまとめたものがmeta_valueとなるよう設計されています。

get_term_metaなど、タームのメタ情報を操作する各関数を使用するだけであれば、特に問題となることはないと思います。
しかし、wp_termmetaに合わせて実装されたWP_Term_Query(get_terms)のmeta_queryを含めて考えると、あまり良い設計ではなさそうです。

 

WP_Term_QueryはWP_Queryのターム版とも言えますが、例えば「個別の投稿記事のうち、Cocoonの"インデックスしない"を選択した記事を一覧で取得したい」場合、wp_postmetaのmeta_key'the_page_noindex'から取得することができます。

一方、Cocoonで用意されているterm_metaだとmeta_keyがターム毎に独立してしまっており、またmeta_valueも複雑になっていることから、meta_queryを使用するのが困難になってしまっています。

wp_termmetaにはmeta_key・meta_valueに加え、各term_idも合わせて保存されるため、少なくともmeta_keyにterm_idを含める必要はないかと思います。

 

新たにタームメタを用いた機能を実装する場合は、上記のようなWordPressの仕様を考慮して実装した方がよさそうです。


   
わいひら
(@yhira)
Illustrious Memberサイト Admin
結合: 7年前
投稿: 17179
 

カテゴリーで言えば、この部分ですよね。
https://github.com/yhira/cocoon/blob/24a428b1988a0126f60c3d7b547f3216061bed20/lib/content-category.php#L18
https://github.com/yhira/cocoon/blob/24a428b1988a0126f60c3d7b547f3216061bed20/lib/content-category.php#L31
https://github.com/yhira/cocoon/blob/24a428b1988a0126f60c3d7b547f3216061bed20/lib/content-category.php#L235

wp_postmetaのmeta_key'the_page_noindex'で例えるとすると、キーがthe_page_noindex_{post_id}になっているということですね。
だとしたら、意味のないID指定ですよね。

うーん、どうしよう…。
とりあえず、category_metaをキーにして保存もしておいて、読み込み時category_metaキーで読み込めない場合は、category_meta_{term_id}も取得して値を読み込むようにしたほうが良いのだろうか。
余計な処理は増えるけど、その方が後々分かりやすいような気がする。


   
ろこ
(@lococo)
Prominent Member Registered
結合: 7年前
投稿: 830
Topic starter  

はい、挙げられたコードの部分です。

wp_termmetaには、単体のデータとしてterm_id・meta_key・meta_valueがセットで保存されており、get_term_meta関数はひとつのterm_idとmeta_keyから特定のmeta_valueを取得してくる一方、WP_Term_Queryクラスのmeta_queryは指定したmeta_key(とmeta_value)にマッチするterm群を取得してくるよう実装されています。
meta_keyがterm_id毎に独立してしまっていることにより、共通条件のクエリでは取得できません。

typeパラメータやcompareパラメータでmeta_valueを条件指定できることまで考慮すると、個別のメタ情報におけるmeta_valueはなるべく整理してシンプルにしておくのがよさそうなので、私がカスタマイズで新たに加えた箇所は取得データが1対1となるように切り分けて保存する形にしました。
Cocoonの例で言うと、カテゴリ色でひとつ、タイトルでひとつ…といった感じです。

現在のデータに修正を加えるのであれば、保存する際(save_extra_category_fileds関数)は新たに整理した形のタームメタに保存するようにし、取得する際(get_category_meta関数)は新タームメタ⇒(データがセットされていない場合のみ)旧タームメタになりそうですね。
メタ情報を切り分ける場合は、save_extra_category_fileds関数での保存時に$_POST['cat_meta']を要素ごとに繰り返しupdate_term_metaすることで対応可能です。


   
わいひら
(@yhira)
Illustrious Memberサイト Admin
結合: 7年前
投稿: 17179
 

今回、IDごとにキーを指定しているのと、配列で保存しているという2つの問題点がありますね…。
なんでこんな仕様にしてしまったんだか…。結構昔なので全部覚えてないです。
多分、あまり深く考えないでやってしまったんだと思います。

私がカスタマイズで新たに加えた箇所は取得データが1対1となるように切り分けて保存する形にしました。

よろしければ、content-category.phpコードをnotepad.pw等で、見せていただいて、命名とコードなどを参考にさせていただくことは可能でしょうか。

追記:とりあえずブランチ側で修正しました。


   
わいひら
(@yhira)
Illustrious Memberサイト Admin
結合: 7年前
投稿: 17179
 

wp_postmetaに命名を合わせて、色だったらthe_category_color, the_category_text_colorとかにした方が良いのかもしれませんね。


   
わいひら
(@yhira)
Illustrious Memberサイト Admin
結合: 7年前
投稿: 17179
 

とりあえずは、こちら側でブランチを切って修正してみようと思います。


   
わいひら
(@yhira)
Illustrious Memberサイト Admin
結合: 7年前
投稿: 17179
 

とりあえず、こんな感じで修正してみました。
https://github.com/yhira/cocoon/commits/save_extra_category_fileds
https://github.com/yhira/cocoon/commit/324bda0dec5aff26f986869caf457f064403307c
これで、以前の保存情報取得できつつも、新しいwp_termmetaに保存できるようになったのではないかと思います。
もう少し、動作確認してみてタグの方も修正しようと思います。


   
ろこ
(@lococo)
Prominent Member Registered
結合: 7年前
投稿: 830
Topic starter  

ぱっと見た感じでは問題なさそうなので、とりあえずテストして詳しく確認してみようと思います。

問題が起こらない限りは修正の必要はありませんが、

私がカスタマイズで新たに加えた箇所は取得データが1対1となるように切り分けて保存する形にしました。

について、一応私の命名やコードを書いておきます。

命名については、私は主なカスタマイズはアップデートしやすいようにプラグインにまとめているため、meta_keyは[プラグイン名]_[キー名]といった感じで命名しており、基本的にCocoonの仕様が変更されても問題ありません。

save_extra_category_fileds関数での保存時に$_POST['cat_meta']を要素ごとに繰り返しupdate_term_metaする

コードについては、上記の説明をコードにしておけばよかったのですが、name="example[meta_key]"と配列のままで送信し、$_POST['example']をもとにforeach内で繰り返しupdate_term_metaする形にしました。

以前のCocoonからだと、

function save_extra_category_fileds( $cat_id ) {
  if ( isset( $_POST['cat_meta'] ) ) {
  $keys = array_keys( $_POST['cat_meta'] );
  foreach ( $keys as $key ) {
      update_term_meta( $cat_id, $key, $_POST['cat_meta'][$key] );
    }
  }
}

のような形と言えます。
その他は修正版のコードとおよそ同じ形になっています。


   
わいひら reacted
わいひら
(@yhira)
Illustrious Memberサイト Admin
結合: 7年前
投稿: 17179
 

ご確認と、コードありがとうございます。
今のところ、僕の環境でいろいろ動作確認しても問題ないので、タグ部分も変更してみようと思います。

修正したらまた書き込みます。


   
わいひら
(@yhira)
Illustrious Memberサイト Admin
結合: 7年前
投稿: 17179
 

一応、タグも修正しておきました。
https://github.com/yhira/cocoon/commits/save_extra_category_fileds
https://github.com/yhira/cocoon/commit/a18b4a369ee6f1645b61eb54200390469f51a92d
これも、とりあえず動作確認した限りでは、大丈夫そう。


   
ろこ
(@lococo)
Prominent Member Registered
結合: 7年前
投稿: 830
Topic starter  

カテゴリー・タグそれぞれの動作をざっと確認した限りでは問題なさそうです。

アプデ後の利用者向けに書き加えておくと、各フィールドの値を取得するのにget_term_meta関数から各々のメタ情報を取得する関数に置き換えたことで、タイトルを設定するフィールドの初期値にカテゴリー名が入るようになったのが変更点といったところでしょうか。
実際の動作に影響はありません。

最終的に不要になった旧メタ情報については、delete_term_metaなどで削除処理を加える予定はありますでしょうか?
なさそうであれば、本件の実装に合わせて自分で処理を加えようと思いますが。


   
わいひら reacted
わいひら
(@yhira)
Illustrious Memberサイト Admin
結合: 7年前
投稿: 17179
 

タイトルを設定するフィールドの初期値にカテゴリー名が入るようになったのが変更点といったところでしょうか。

これは、意図しないものでした。未入力の場合はカテゴリー名が入らないように修正しました。
あと、新しい値に空欄を入力したときに、反映されない不具合があったので修正しておきました(今のところカテゴリーのみ)。
https://github.com/yhira/cocoon/commit/85fab2937953591dc68103c921c0fb08ae2aa027
加えて、一応、古い配列の値も設定を保存するようにも変更しました。新しい値と、古い値が別々だと、ややこしいような気もして。

最終的に不要になった旧メタ情報については、delete_term_metaなどで削除処理を加える予定はありますでしょうか?

今のところ新しいキーにデータが保存してない場合は、旧データ(get_the_category_metaで読み込んでいる配列)を読み込む必要があるのと、あっても負荷はそこまで変わらないと思うので、今のところ削除は考えていません。


   
わいひら
(@yhira)
Illustrious Memberサイト Admin
結合: 7年前
投稿: 17179
 

すいません。上記のものは、旧データを読み込まない不具合がありました。

現在修正中です。


   
わいひら
(@yhira)
Illustrious Memberサイト Admin
結合: 7年前
投稿: 17179
 

一応修正はしてみたものの、これだとget_term_metaを読み込んだ後、空欄だったらget_the_category_metaをもう一度読み込む必要があるのが、ちょっと気持ち悪い。
https://github.com/yhira/cocoon/commit/847a5b1db405e12c28f8b00b8770194d529e2830
とりあえずの修正。


   
わいひら
(@yhira)
Illustrious Memberサイト Admin
結合: 7年前
投稿: 17179
 

よく見たら、get_metadata→get_metadataで失敗したときの返り値がflaseに限定されていたわけではないっぽいのが原因だったかも。
https://developer.wordpress.org/reference/functions/get_term_meta/
https://developer.wordpress.org/reference/functions/get_metadata/

これじゃ、このように書くとダメな場合もあるのかも。

function get_the_category_color($cat_id = null){
  $res = get_term_meta( $cat_id, 'the_category_color', true );
  if ($res !== false) {
    return $res;
  } else {//旧バージョン対応 

   
ろこ
(@lococo)
Prominent Member Registered
結合: 7年前
投稿: 830
Topic starter  

get_term_metaは実際にはget_metadataが処理しているので、meta_keyの有無にかかわらずsingleパラメータがtrue→空文字、false→空配列を返す形になっています。
その代わりに、meta_keyの有無を確認する方法としてmetadata_existsが存在します。

最終的に不要になった旧メタ情報については、delete_term_metaなどで削除処理を加える予定はありますでしょうか?

私が上記の確認を行ったのは「不要なデータは削除してデータベースを見やすく整理すべき」との考えもありましたが、term_meta関数の仕様も考えてのことでした。

空欄で更新を行った際の不具合については見落としていましたが、旧データと新データを混在したままで取り扱おうとすると、やはり少し複雑になってしまいます。

 

最初の修正版での動作から、

  1. 既存のカテゴリー編集画面を開く
  2. 旧データから各フィールドの設定が読み込まれる
  3. 適宜編集したあとに更新を行う
  4. 編集内容が新メタデータとして格納される

となっているので、4のedited_term時点で該当するterm_idに紐づく旧データは少なくとも必要なくなります。
よって、更新に合わせてこの旧データのみdelete_term_metaを使用しても問題なさそうと思いました。

旧データから新データに移行するためにupdate_term_metaとdelete_term_metaを使用するタイミングはedited_termでなくてもよいですが、新旧両方のデータが混在し続ける形で考えるのではなく、何らかの動作を区切りに新データのみを扱う形に切り替える方向で考えた方が各コードの動作を複雑化しなくて済むのではないでしょうか?


   
わいひら reacted
ろこ
(@lococo)
Prominent Member Registered
結合: 7年前
投稿: 830
Topic starter  
  1. get_the_category_metaで旧データを取得する
  2. 旧データ配列内の各要素を新データのmeta_keyに対するmeta_valueに入れる
  3. 新データについてupdate_term_metaを行う
  4. 旧データについてdelete_term_metaを行う

この一連が動作するポイントは、各ターム編集画面の更新時に個別だろうとアプデ後のテーマ読み込み時に一括だろうと、動作する箇所であればどこでもOKだと思います。

 

この動作を区切りとして、区切りより前は

  • 旧データのmeta_keyは存在する
  • 新データのmeta_keyは存在しない

区切りより後は

  • 旧データのmeta_keyは存在しない
  • 新データのmeta_keyは存在する

といった感じで判断材料にできます。

すると、旧データに対するコードと新データに対するコードを切り分けることができ、最終的に不要なデータが残ることもありません。


   
わいひら
(@yhira)
Illustrious Memberサイト Admin
結合: 7年前
投稿: 17179
 

metadata_existsの存在を知りませんでした。
それを使用して、判定するように変更しました。
https://github.com/yhira/cocoon/commit/d81bdcb3eb0e8ddcbd487ec1ff12085bb9cf39f2

何らかの動作を区切りに新データのみを扱う形に切り替える方向で考えた方が各コードの動作を複雑化しなくて済むのではないでしょうか?

よくよく考えたら、edited_term時、新しい値を保存したのであれば、古い配列の値をわざわざ新しくして保存する必要もなく、削除してしまえば良いですよね。
削除するように変更しておきました。
https://github.com/yhira/cocoon/commit/39dfea27246419daa1d19ec900d13fe813ceaaa7


   
わいひら
(@yhira)
Illustrious Memberサイト Admin
結合: 7年前
投稿: 17179
 

タブを開いたままだったので上の書き込みは、こちらの書き込みに気づかないまま記入しました。
ただ、おそらく同様のことはできたのではないかと思います。


   
ろこ
(@lococo)
Prominent Member Registered
結合: 7年前
投稿: 830
Topic starter  

改めて修正後のテーマをインストールし、チェックしてみました。

 

function get_the_category_title($cat_id = null, $is_cat_name = true){
if (term_metadata_exists($cat_id, 'the_category_title')) {
return get_term_meta( $cat_id, 'the_category_title', true );
} else {//旧バージョン対応
$meta = get_the_category_meta($cat_id);
if (!empty($meta['title'])){
return $meta['title'];
} else {
//タイトルが存在しない場合はカテゴリ名を利用する
if ($is_cat_name) {
return get_category($cat_id)->name;
}
}
}
}

カテゴリータイトルの取得について、'the_category_title'に移行後のタイトルは無条件でreturnしてしまっているため、空の場合に一部カテゴリー名が表示されません。

 

function get_the_category_content($cat_id = null){
if (term_metadata_exists($cat_id, 'the_category_content')) {
return get_term_meta( $cat_id, 'the_category_content', true );
} else {//旧バージョン対応
if (!$cat_id) {
$cat_id = get_query_var('cat');
}
$meta = get_the_category_meta($cat_id);
if (!empty($meta['content']))
$content = $meta['content'];
else
$content = category_description($cat_id);
}
$content = wpautop($content);
$content = apply_filters( 'the_category_tag_content', $content );//カテゴリー・タグ本文共通
$content = apply_filters( 'the_category_content', $content );
return $content;
}

同様に、カテゴリー本文についても無条件でのreturnによりコンテンツの整形が行われません。


   
わいひら reacted
わいひら
(@yhira)
Illustrious Memberサイト Admin
結合: 7年前
投稿: 17179
 

ありがとうございます。

カテゴリータイトルの取得について、'the_category_title'に移行後のタイトルは無条件でreturnしてしまっているため、空の場合に一部カテゴリー名が表示されません。

タイトルが空欄の場合、公開ページで通常のカテゴリ名が必要な場合に、空文字になる恐れがありますね。
双方とも、修正しておきました。
https://github.com/yhira/cocoon/commit/7fc3a167c8cc6071e83237b098b2ae7c72c94e1d


   
わいひら
(@yhira)
Illustrious Memberサイト Admin
結合: 7年前
投稿: 17179

   
ろこ
(@lococo)
Prominent Member Registered
結合: 7年前
投稿: 830
Topic starter  

確認した限りでは、今のところその他に大きな問題は確認されません。
特に問題なさそうでしたら、アップデート内容に加えても大丈夫なのではないでしょうか。

修正ありがとうございました。


   
わいひら reacted
わいひら
(@yhira)
Illustrious Memberサイト Admin
結合: 7年前
投稿: 17179
 

僕もいろいろ確認してみた限りでは大丈夫そう。
とりあえずmasterにはマージしてプシュしておきました。
ご確認と、ご助言ありがとうございます!


   
共有:

問題の解決に至った場合には、トピック冒頭の「解決済み」をクリックしていただけますと幸いです。

また、有用な回答があった場合は返信右下にある「いいね!」もご活用ください。回答者の励みになります。

「いいね!」機能はフォーラム登録者のみが利用できる機能です。

CC BY-ND 2.1)準じていれば(リンクを貼っていただければ)転載も自由です。カスタマイズ記事を書く際にコード等をコピペ利用していただいて構いません。

フォーラムの使い方がよくわからない場合は、テストトピックで自由にテストしていただいて構いません。

最近の書き込みはこちら。

詳細なカスタマイズ依頼をするならこちら。

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