Arialize配列としてメタ値を持つMeta_Query
-
22-10-2019 - |
質問
カスタムポストタイプとカスタムポストタイプに関連付けられたメタボックスを介して入力されたカスタムポストタイプとカスタムデータを作成するプロジェクトに取り組んでいます。何らかの理由で、各メタボックスの入力が配列の一部であるようにメタボックスをコーディングすることにしました。たとえば、私は経度と緯度を保存しています:
<p>
<label for="latitude">Latitude:</label><br />
<input type="text" id="latitude" name="coordinates[latitude]" class="full-width" value="" />
</p>
<p>
<label for="longitude">Longitude:</label><br />
<input type="text" id="longitude" name="coordinates[longitude]" class="full-width" value="" />
</p>
何らかの理由で、私は各メタボックスに特異なポストメタエントリを持っているというアイデアが好きでした。に save_post
フック、私はそうするようなデータを保存します:
update_post_meta($post_id, '_coordinates', $_POST['coordinates']);
私は3つのメタボックスを持っているのでこれをしました、そして、私は各投稿に3つのポストメタ値を持っているのが好きです。しかし、私はこれに関する潜在的な問題に気付いた。これらのメタ値に基づいて特定の投稿のみを引き出すために、wp_queryを使用してください。たとえば、50を超える緯度値を持つすべての投稿を取得したい場合があります。データベースに個別にこのデータがある場合は、おそらくキーを使用しています。 latitude
, 、私は次のようなことをします:
$args = array(
'post_type' => 'my-post-type',
'meta_query' => array(
array(
'key' => 'latitude',
'value' => '50',
'compare' => '>'
)
)
);
$query = new WP_Query( $args );
私はその一部として緯度を持っているので _coordinates
Postmeta、これはうまくいきません。
だから、私の質問は、利用する方法があるということです meta_query
このシナリオのようにシリアル化された配列を照会しますか?
解決
いいえ、それは不可能であり、危険でさえあります。
データを確認して、保存ルーチンを変更することを強くお勧めします。これに似たものは、データを新しい形式に変換する必要があります。
$args = array(
'post_type' => 'my-post-type',
'meta_key' => '_coordinates',
'posts_per_page' => -1
);
$query = new WP_Query( $args );
if($query->have_posts()){
while($query->have_posts()){
$query->the_post();
$c = get_post_meta($post->id,'_coordinates',true);
add_post_meta($post->ID,'_longitude',$c['longitude']);
add_post_meta($post->ID,'_latitude',$c['latitude']);
delete_post_meta($post->ID,'_coordinates',$c);
}
}
その後、個々のキーで必要に応じてクエリができるようになります
複数の長期と複数の緯度を保存する必要がある場合は、同じ名前の複数のポストメタを保存できます。の3番目のパラメーターを使用するだけです get_post_meta
, 、そしてそれはそれらすべてを配列として返します
シリアル化されたデータ内で照会できないのはなぜですか?
MySQLはそれを単なる文字列と見なし、構造化されたデータに分解することはできません。構造化されたデータに分解することは、上記のコードが正確に行うことです
日付の部分的なチャンクをクエリすることができるかもしれませんが、これは非常に信頼性が高く、高価で、遅く、非常に脆弱で、多くのエッジケースがあります。シリアル化されたデータは、SQLクエリを対象としたものではなく、定期的かつ一定の方法でフォーマットされていません。
部分的な文字列検索のコストは別として、メタのポストクエリは遅くなり、シリアル化されたデータは、内容の長さなどに応じて変更され、検索が非常に高価になります。
メタのシリアル化されたオブジェクトとしてレコード/エンティティ/オブジェクトを保存することに関するメモ
ポストメタにトランザクションレコードを保存したり、ユーザーメタに他の種類のデータ構造を保存してから、上記の問題に遭遇することもできます。
ここでの解決策は、それを個々のポストメタに分割することではなく、それが最初からメタであったはずであることを認識することではなく、カスタムポストタイプです。たとえば、ログまたはレコードはカスタム投稿タイプであり、元の投稿は親として、または分類学的用語で結合されます
セキュリティおよびシリアル化されたオブジェクト
シリアル化されたPHPオブジェクトを介して保存します serialize
機能は危険です, 、WordPressにオブジェクトを渡すことがシリアル化されることを意味するため、残念です。これは、オブジェクトがシリアル化されると、オブジェクトが作成され、すべてのウェイクアップメソッドとコンストラクターが実行されるためです。これは、ユーザーが慎重に作成された入力をスニークすることができ、データベースからデータが読み取られ、WordPressによってシリアル化されたときにリモートコード実行につながるまで、これは大したことではないように思えないかもしれません。
これは、代わりにJSONを使用することで回避できます。これにより、クエリが簡単になりますが、データを正しく保存し、構造化されたシリアル化されたデータを最初から避ける方がはるかに簡単/高速です。
他のヒント
私もこの状況に遭遇します。ここで私がしたこと:
$args = array(
'post_type' => 'my-post-type',
'meta_query' => array(
array(
'key' => 'latitude',
'value' => sprintf(':"%s";', $value),
'compare' => 'LIKE'
)
)
);
この助けを願っています
WPデータベースへのエントリをシリアル化する際に、効率的な方法でデータを照会する機能を本当に失うことになります。
全体的なパフォーマンスを節約し、あなたがシリアル化によって達成していると思う利益は、どんな範囲でも目立たないでしょう。データベースサイズがわずかに小さくなる可能性がありますが、SQLトランザクションのコストは、これらのフィールドを照会し、有用で意味のある方法でそれらを比較しようとすると重くなります。
代わりに、あなたがその性質で照会するつもりはないデータのシリアル化を保存しますが、代わりに直接WP API呼び出しによってパッシブファッションでのみアクセスするでしょう get_post_meta()
- その関数から、シリアル化されたエントリを開梱して、配列プロパティにもアクセスできます。
実際、の値を割り当てました 本当です のように;
$meta = get_post_meta( $post->ID, 'key', true );
データを配列として返し、通常に応じて繰り返してアクセスできます。
必要に応じて、キャッシュ、CSS、JSの模擬などの他のデータベース/サイトの最適化やCDNとしてのサービスを使用するなど、他のデータベース/サイトの最適化に焦点を当てることができます。名前をいくつか挙げてください.... WordPress Codexは、そのトピックについてさらに明らかにするための良い出発点です。 ここ
シリアル化されたフィールドを扱ったばかりで、それらを照会することができました。 Meta_Queryを使用するのではなく、SQLクエリを使用します。
global $wpdb;
$search = serialize('latitude').serialize(50);
$query = $wpdb->prepare("SELECT `post_id`
FROM `wp_postmeta`
WHERE `post_id` IN (SELECT `ID` FROM `wp_posts` WHERE `post_type` = 'my-post-type')
AND `meta_key` = '_coordinates'
AND `meta_value` LIKE '%s'",'%'.$search.'%');
$ids = $wpdb->get_col($query);
$args = array(
'post__in' => $ids
'post_type' => 'team' //add the type because the default will be 'post'
);
$posts = get_posts($args);
クエリは最初にPOST_TYPEを使用して投稿を検索するため、WP_POSTMETAレコードの量がフィルタリングするのが少なくなります。次に、フィルタリングすることにより、行をさらに減らすためのWhere Statementを追加しました meta_key
IDは、get_postsに必要に応じて配列でうまく終了します。
詩良好なサブクエリパフォーマンスには、mysql v5.6以上が必要です
この例は本当に私を助けてくれました。特にS2Membersプラグイン(ユーザーメタデータをシリアル化)専用です。ただし、Meta_Key内のシリアル化された配列の一部を照会することができます。
MySQL regexp関数を使用して機能します。
ここ ソースです
これは、米国に住んでいるすべてのユーザーを照会するコードです。カスタム登録フィールドの1つを照会するように簡単に変更しましたが、すぐに機能しました。
<?php
global $wpdb;
$users = $wpdb->get_results ("SELECT `user_id` as `ID` FROM `" . $wpdb->usermeta .
"` WHERE `meta_key` = '" . $wpdb->prefix . "s2member_custom_fields' AND
`meta_value` REGEXP '.*\"country_code\";s:[0-9]+:\"US\".*'");
if (is_array ($users) && count ($users) > 0)
{
foreach ($users as $user)
{
$user = /* Get full User object now. */ new WP_User ($user->ID);
print_r($user); /* Get a full list of properties when/if debugging. */
}
}
?>
弦と整数の両方として保存されている結果の問題を解決しようとする2つのソリューションがあると思います。ただし、他の人が指摘したように、整数として保存された結果の整合性を保証することは不可能であると言うことが重要です。なぜなら、これらの値はシリアル化されたアレイとして保存されているため、インデックスと値は同じパターンで正確に保存されるからです。例:
array(37,87);
このようなシリアル化された配列として保存されます
a:2:{i:0;i:37;i:1;i:87;}
注意してください i:0
配列の最初の位置として i:37
最初の値として。パターンは同じです。しかし、ソリューションに行きましょう
1)regexpソリューション
このソリューションは、文字列または番号 / IDとして保存されているメタ値に関係なく、私にとっては機能します。ただし、使用します REGEXP
, 、使用ほど速くありません LIKE
$args = array(
'post_type' => 'my-post-type',
'meta_query' => array(
array(
'key' => 'latitude',
'value' => '\;i\:' . $value . '\;|\"' . $value . '\";',
'compare' => 'REGEXP'
)
)
);
2)ソリューションのような
パフォーマンスの違いについてはわかりませんが、これは使用するソリューションです LIKE
また、数字と文字列の両方で機能します
$args = array(
'post_type' => 'my-post-type',
'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'latitude',
'value' => sprintf(':"%s";', $value),
'compare' => 'LIKE'
),
array(
'key' => 'latitude',
'value' => sprintf(';i:%d;', $value),
'compare' => 'LIKE'
)
)
);
実行するためのヒントの束を読んだ後 WP_Query
シリアル化されたアレイによるフィルタリング、最終的にそれを行う方法は次のとおりです。 $wpdb
カスタムSQLクエリを使用します FIND_IN_SET
要求された値のコンマ分離リストを検索します。
(これはTomasの答えに似ていますが、SQLクエリのパフォーマンスが少し少ない)
1. functions.php:
functions.phpファイル(またはメタボックスをセットアップする場所)で yourname_save_post()
関数の使用
update_post_meta($post->ID, 'checkboxArray', implode(",", $checkboxArray)); //adding the implode
コンマ分離値を含む配列を作成します。
また、出力変数を yourname_post_meta()
管理メタボックス構造機能
$checkboxArray = explode(",", get_post_custom($post->ID)["checkboxArray"][0]); //adding the explode
2.テンプレートPHPファイル:
テスト:実行する場合 get_post_meta( $id );
君は見るべきだ checkboxArray
シリアル化された配列の代わりにコンマ分離値を含む配列として。
次に、カスタムSQLクエリを使用して作成します $wpdb
.
global $wpdb;
$search = $post->ID;
$query = "SELECT * FROM wp_posts
WHERE FIND_IN_SET( $search, (
SELECT wp_postmeta.meta_value FROM wp_postmeta
WHERE wp_postmeta.meta_key = 'blogLocations'
AND wp_postmeta.post_id = wp_posts.ID )
)
AND ( wp_posts.post_type = 'post' )
AND ( wp_posts.post_status = 'publish' );";
$posts = $wpdb->get_results($query);
foreach ($posts as $post) {
//your post content here
}
に注意してください FIND_IN_SET
, 、それが魔法が起こる場所です。
今...私は使用しているので SELECT *
これは戻ります すべての投稿データ そして、 foreach
あなたはそれからあなたが望むものをエコーすることができます( print_r($posts);
何が含まれているのかわからない場合。それはあなたのために「ループ」をセットアップしません(私はこの方法でそれを好みます)が、あなたが望むならば、それは簡単にループをセットアップするように簡単に変更できます(を見てください setup_postdata($post);
コーデックスでは、おそらく変更する必要があります SELECT *
IDのみを選択するには $wpdb->get_results
正しい $wpdb
タイプ - コーデックスを参照してください $wpdb
詳細についても それ 主題)。
whelp、それは少し努力しましたが、それ以来 wp_query
行うことをサポートしていません 'compare' => 'IN'
シリアル化またはコンマ分離値このシムがあなたの最良の選択肢です!
これが誰かを助けることを願っています。
使用する場合 like
メタクエリの比較演算子は、シリアル化された配列内を見るには正常に動作するはずです。
$wp_user_search = new WP_User_Query(array(
'meta_query' => array(
array(
'key' => 'wp_capabilities',
'value' => 'subscriber',
'compare' => 'not like'
)
)
)
);
結果:
[query_where] => WHERE 1=1 AND (
( wp_usermeta.meta_key = 'wp_capabilities'
AND CAST(wp_usermeta.meta_value AS CHAR) NOT LIKE '%subscriber%' )
私のメタデータが配列タイプの場合、私はこの方法をメタによるクエリに使用しています:
$args = array(
'post_type' => 'fotobank',
'posts_per_page' => -1,
'meta_query' => array(
array(
'key' => 'collections',
'value' => ':"'.$post->ID.'";',
'compare' => 'LIKE'
)
)
);
$fotos = new WP_Query($args);
上記の答えに興味があります。 meta_query
キーをターゲットにしました latitude
それ以外の _coordinates
. 。メタクエリで実際に可能であるかどうかをテストして、シリアル化された配列内の特定のキーをターゲットにしていたかどうかをテストする必要がありました。 :)
明らかにそうではありませんでした。
したがって、ターゲットの正しいキーは _coordinates
それ以外の latitude
.
$args = array( 'post_type' => 'my-post-type', 'meta_query' => array( array( 'key' => '_coordinates', 'value' => sprintf(':"%s";', $value), 'compare' => 'LIKE' ) ) );
ノート:
このアプローチにより、正確な一致をターゲットにすることのみが可能になります。だから 50を超えるすべての緯度 不可能です。
サブストリングマッチを含めるには、使用できます
'value' => sprintf(':"%%%s%%";', $value),
. 。 (テストしていません)
同じ質問があります。 「タイプ」パラメーターが必要ですか?この関連する質問をご覧ください。カスタムフィールドクエリ - メタ値は配列です
おそらく試してみてください:
$args = array( 'post_type' => 'my-post-type', 'meta_query' => array( array( 'key' => 'latitude', 'value' => '50', 'compare' => '>', 'type' => 'numeric' ) ) );
Magic Fieldsプラグインを使用している間、私は同様の何かに出くわしました。これはトリックをするかもしれません
$values_serialized = serialize(array('50'));
$args = array(
'post_type' => 'my-post-type',
'meta_query' => array(
array(
'key' => 'latitude',
'value' => $values_serialized,
'compare' => '>'
)
)
);