WordPress ACF PROのチェックボックスの検索
またWordPressネタ。
ACF PROを購入した。
理由は繰り返しフィールドを使いたかったからだ。
買わないと普通のACFでは繰り返しフィールドは使えない。
でも仕事で使うのに、10000円ぐらい?でこの機能と入力のインターフェイスで用意してくれてるなら安いもんだ。
使い方は色んなサイトで解説されてるから、すぐにわかる。
先日、早速仕事で使用してみた。
何の問題もなく仕様どおりにたくさんのカスタムフィールドを登録し設定をしていく。
絞り込み検索もカスタムフィールドにあわせて作っていく。
楽過ぎる。
動作チェック
問題はそこで起こった。
絞り込み検索ですべてのカスタムフィールドの値で絞り込み検索をかけたとき、サイトが止まった。
SQLのANDの数は感覚だが20くらいだろうか?まったく動かなくなった。
これはマズイと検索
調べていくと、ACFのカスタムフィールドのチェックボックスの値はPHPのシリアライズされている値でDBに保存される仕様。
a:4:{
i:0;
s:3:"値1";
i:1;
s:3:"値2";
i:2;
s:3:"値3";
i:3;
s:3:"値4";
}
こんな感じで、この値に対してLIKE検索をかけるということになる。
そして自己リレーション?していたテーブルに検索をかけていたはず。
// meta_queryのcompare
$option = [
'key' => $key,
'value' => '"' . $value . '"',
'compare' => 'LIKE'
]
そりゃ遅いわ。。。
なんらかの解決方法はあるだろうと検索。
するとこちらのページがヒット
3年前の記事だが、試してみる。
動いた!が、、、チェックボックスだけ動かない。
DBを見るとシリアライズされたデータが入ることを期待していたのだが、NULLだった(←これは記憶)
ACFで保存したデータが保存されないのである。
もちろんこの状況を想定したプラグインではないだろうから、仕方ない。
でも検索用のテーブルを利用して、検索を速くするというものなので、シリアライズされたデータが入りさえすれば確実に動くはず。
カスタマイズ
ACF用にシリアライズされた値が入るようにプラグインを触らせていただいた。
今回のケースではカスタムフィールドはすべてACFで作成されているので問題ない。
// /wp-content/plugins/meta-accelerator/class/posttype.php
/**
* メタデータ保存
* プラグイン外からも呼ばれるため、throwしない
*
* @param $val
* @param $key
* @param bool $append
* @param string $post_type
*/
function update_meta_table_data($key, $val, $post_type, $post_id = "") {
//meta_accelerator_log("update_meta_table_data $post_id $key " . print_r($val, true));
//meta_accelerator_log("update_meta_table_data: " . $key . ":" . print_r($val, true) . " : post_type: " . $post_type);
try {
global $wpdb;
if(Posttype::is_accelerated($post_type) == false) {
// 対象外
return false;
}
if($post_id == "") {
$post_id = get_the_ID();
if($post_id == "") {
return false;
}
}
if($post_id == "") {
// 対象post_idなし
return false;
}
// フィールドチェック
if($this->has_col($key) === false) {
// フィールド追加
$this->add_cols(array($key => ""));
}
// 値が配列かどうかをチェック 配列の場合、文字列を,でつないでセット
if(is_array($val)) {
$insert_val = "";
if(count($val) == 1) {
// 変更
if(isset($val[0]) && is_array($val[0])){
$insert_val = serialize($val);
}else{
$insert_val = array_pop($val);
}
// 変更
} else {
foreach($val as $val2) {
$insert_val .= "\n\n" . $val2;
}
}
} else {
$insert_val = $val;
}
Posttype::insert_accelerated_table($post_id, $post_type);
if($insert_val == "") {
$sql = $wpdb->prepare("update `" . Posttype::get_tablename($post_type) . "` set " . $this->get_col_name($key) . "='' where post_id = %d", $post_id);
} else {
$sql = $wpdb->prepare("update `" . Posttype::get_tablename($post_type) . "` set " . $this->get_col_name($key) . "=%s where post_id = %d", $insert_val, $post_id);
}
$wpdb->query($sql);
meta_accelerator_log("updated_meta_table_data " . $this->get_col_name($key) . " " . $insert_val);
return true;
} catch(\Exception $e) {
return false;
}
}
update_meta_table_data関数を上記の様に変更したところ、シリアライズされた値が保存されるようになった。
このままでも動いているが、define('WP_DEBUG', true);だと管理画面でエラーが出ている。
Notice: has_cap の使用はバージョン 2.0 から非推奨になりました ! プラグインやテーマでのユーザーレベルの使用は推奨されていません。代わりに権限グループと権限を使ってください。
これは以下のadd_submenu_page関数の第3引数にユーザーレベルを指定することがdeprecatedになっているので起こっている。
管理画面で使用するのでadministratorに変更すれば解決
これで自分の環境ではエラーが出ていないので、とりあえず解決。
// /wp-content/plugins/meta-accelerator/meta-accelerator.php
/*
* 管理画面追加
*/
function admin_menu () {
// RAINS処理関連ページ
require_once "meta_accelerator_admin.php";
add_submenu_page( 'options-general.php', \__('meta speedup'), \__('meta speedup'), 10, 'meta_accelerator_admin.php', array(&$this, 'meta_accelerator_admin'));
}
そして問題の絞り込み検索をテスト。
何の問題もなくあっさりと動いた。
皆様に助けられて生きているなと感じた。
上記2つのプラグインの作者様に感謝します。
データが増えたときにどうなるか?はその時に考えます。。。。