特典機能について

Cocoonのwp_termmeta設計に関する問題 | 開発者向けフォーラム | Cocoon フォーラム

サイト内検索
運営者(わいひら)は、10月25日から手術のため数週間入院します。その際、フォーラム負担軽減のため登録者のみ書き込めるようを制限をさせていただきます。フォーラム未登録の方はこちらの手順で登録を行ってください。準備のため10月18日から12月前半(見込み)まで実施させていただきます。
書き込みの前に以下の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. ブラウザ環境チェックツール

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

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

wpForoの解決済みリンク

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

wpForoのいいねリンク

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

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

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

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

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

スポンサーリンク
共有:
通知
すべてクリア

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


ろこ
(@lococo)
Prominent Memberサイト
結合: 4年前
投稿: 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)
メンバーサイト Admin
結合: 4年前
投稿: 12854
わいひら - Facebookわいひら - Twitter
 

カテゴリーで言えば、この部分ですよね。
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サイト
結合: 4年前
投稿: 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)
メンバーサイト Admin
結合: 4年前
投稿: 12854
わいひら - Facebookわいひら - Twitter
 

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

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

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

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


わいひら
(@yhira)
メンバーサイト Admin
結合: 4年前
投稿: 12854
わいひら - Facebookわいひら - Twitter
 

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


わいひら
(@yhira)
メンバーサイト Admin
結合: 4年前
投稿: 12854
わいひら - Facebookわいひら - Twitter
 

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


わいひら
(@yhira)
メンバーサイト Admin
結合: 4年前
投稿: 12854
わいひら - Facebookわいひら - Twitter
 

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


ろこ
(@lococo)
Prominent Memberサイト
結合: 4年前
投稿: 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] );
    }
  }
}

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


わいひら 件のいいね!
わいひら
(@yhira)
メンバーサイト Admin
結合: 4年前
投稿: 12854
わいひら - Facebookわいひら - Twitter
 

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

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


わいひら
(@yhira)
メンバーサイト Admin
結合: 4年前
投稿: 12854
わいひら - Facebookわいひら - Twitter
 

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


ろこ
(@lococo)
Prominent Memberサイト
結合: 4年前
投稿: 830
Topic starter  

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

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

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


わいひら 件のいいね!
わいひら
(@yhira)
メンバーサイト Admin
結合: 4年前
投稿: 12854
わいひら - Facebookわいひら - Twitter
 

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

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

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

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


わいひら
(@yhira)
メンバーサイト Admin
結合: 4年前
投稿: 12854
わいひら - Facebookわいひら - Twitter
 

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

現在修正中です。


わいひら
(@yhira)
メンバーサイト Admin
結合: 4年前
投稿: 12854
わいひら - Facebookわいひら - Twitter
 

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


わいひら
(@yhira)
メンバーサイト Admin
結合: 4年前
投稿: 12854
わいひら - Facebookわいひら - Twitter
 

よく見たら、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サイト
結合: 4年前
投稿: 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でなくてもよいですが、新旧両方のデータが混在し続ける形で考えるのではなく、何らかの動作を区切りに新データのみを扱う形に切り替える方向で考えた方が各コードの動作を複雑化しなくて済むのではないでしょうか?


わいひら 件のいいね!
ろこ
(@lococo)
Prominent Memberサイト
結合: 4年前
投稿: 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)
メンバーサイト Admin
結合: 4年前
投稿: 12854
わいひら - Facebookわいひら - Twitter
 

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

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

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


わいひら
(@yhira)
メンバーサイト Admin
結合: 4年前
投稿: 12854
わいひら - Facebookわいひら - Twitter
 

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


ろこ
(@lococo)
Prominent Memberサイト
結合: 4年前
投稿: 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によりコンテンツの整形が行われません。


わいひら 件のいいね!
わいひら
(@yhira)
メンバーサイト Admin
結合: 4年前
投稿: 12854
わいひら - Facebookわいひら - Twitter
 

ありがとうございます。

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

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


わいひら
(@yhira)
メンバーサイト Admin
結合: 4年前
投稿: 12854
わいひら - Facebookわいひら - Twitter

ろこ
(@lococo)
Prominent Memberサイト
結合: 4年前
投稿: 830
Topic starter  

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

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


わいひら 件のいいね!
わいひら
(@yhira)
メンバーサイト Admin
結合: 4年前
投稿: 12854
わいひら - Facebookわいひら - Twitter
 

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


共有:
スポンサーリンク
SWELLと業務提携しています
WordPressテーマSWELL
わいひらをフォローする
おすすめサーバー(コスパ・バックアップ重視型)

性能も兼ね備えながら安くブログ運営を開始できる点においてのNo.1。
それでいてブログ成長後は、十分すぎるほどのスペックアップ余力も担保されている。

◎安く始められる
◎LiteSpeedを用いた高速サーバー(完全SSD)
◎http/3(高速化プロトコル)に対応
◎東京・大阪でリージョン選択が可能
◎プランのアップ・ダウングレードが自由自在
◎同サービス内でドメイン管理が可能
◎ディスク容量が多い
◎転送量が多い
◎毎日無料バックアップ(14日分)
◎DBは14日以内なら無料自動復旧可能
◎ファイルも14日以内なら無料自動復旧可能
◎アダルト・出会い系サイト可
◎ドメインとサーバー代のチャージ払いが可能
○サーバ引っ越し依頼が可能(有料)

サービス運営期間:3年

1年以上の契約をする場合は、クーポンコード入力でさらに50%割引キャンペーン中!
※BOX2 ~ BOX8プラン契約の場合

クーポンコード:PK4JK4RJ

クーポンの使用方法はこちら

とにかく速い。サイトに表示スピードを求めるならココ。
管理画面がシンプルで使いやすい。

◎nginxを用いた高速サーバー(完全SSD)
◎プランのアップ・ダウングレードが自由自在
◎同サービス内でドメイン管理が可能
◎ディスク容量が多い
◎転送量が多い
○http/2(高速化プロトコル)に対応
◎毎日無料バックアップ(14日分)
◎DBは14日以内なら無料自動復旧可能
◎ファイルも14日以内なら無料自動復旧可能
◎サーバ引っ越しツールあり(無料)
○サーバ引っ越し依頼が可能(有料)
◎ドメインとサーバー代のチャージ払いが可能

サービス運営期間:3年

安定感抜群のサーバーです。あまり急激なアクセス変動がないアフィリエイトサイトに向いています。

◎nginxを用いた高速サーバー(完全SSD)
◎老舗サーバーなので安定感抜群
◎ディスク容量が多い
◎転送量が多い
◎同サービス内でドメイン管理が可能
○http/2(高速化プロトコル)に対応
○毎日無料バックアップ(14日分)
○DBは7日以内なら無料自動復旧可能
×ファイルは有料かつ手動での復旧
×プラン変更でCPUのスペックアップができない
×プラン変更しても即時反映されない
×アダルト・出会い系サイト不可

サービス運営期間:18年

常に新しいことに挑戦しているフロンティア精神あふるるレンタルサーバーです。
LiteSpeedやHTTP/2を日本で初めて導入したサーバー。

◎LiteSpeedを用いた高速サーバー(完全SSD)
◎http/3(高速化プロトコル)に対応
◎プランのアップ・ダウングレードが自由自在
◎同サービス内でドメイン管理が可能
◎転送量が多い
◎ディスク容量が多い
◎毎日無料バックアップ(14日分)
◎DBは14日以内なら無料自動復旧可能
○ファイルは14日以内なら無料復旧可能(※手動)
◎アダルト・出会い系サイト可
◎ドメインとサーバー代のチャージ払いが可能
○サーバ引っ越し依頼が可能(有料)

サービス運営期間:5年

格安な値段で始められる高機能サーバーです。
性能も備えつつ最安ならここ。
ただし少し機能は弱い。

◎LiteSpeedを用いた高速サーバー(完全SSD)
◎激安プランが用意してある
◎値段あたりのスペックが高い(コスパ良し)
◎サーバ引っ越し依頼が可能(無料)
◎アダルト・出会い系サイト可
○http/2(高速化プロトコル)に対応
△プランのアップは可能だがダウンは不可
△毎日自動バックアップ(1日分)
△前日のバックアップからのみ復元できる(無料)

サービス運営期間:5年

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