course
というカスタム投稿タイプがあります。コースの投稿の中には、course_or_project
、time_to_complete_project
、time_to_complete_course
、difficulty
というカスタムフィールドがあります。私はcourse_project_category
という分類法もあります。
私の目的は、いくつかのドロップダウン/スライダーを作成し、ドロップダウン/スライダーの値を読んでURLを作成し、検索ボタンをクリックして、私がまとめたクエリ文字列(jQuery)を使ってフィルタリングすることです。正しい投稿この機能はすべて機能しています。うーん...時には結果が少し混乱している、つまり一部のパラメータでフィルタリングされているだけです。
コードについて.
カスタムフィールドを公開するための関数を追加しました。
function my_pre_get_posts( $query ) {
// do not modify queries in the admin
if( is_admin() ) {
return $query;
}
// only modify queries for 'course' post type
if( isset($query->query_vars['post_type']) && $query->query_vars['post_type'] == 'course' ) {
// allow the url to alter the query
if( isset($_GET['course_or_project']) ) {
$query->set('meta_key', 'course_or_project');
$query->set('meta_value', $_GET['course_or_project']);
}
if( isset($_GET['time_to_complete_project']) ) {
$query->set('meta_key', 'time_to_complete_project');
$query->set('meta_value', $_GET['time_to_complete_project']);
}
if( isset($_GET['time_to_complete_course']) ) {
$query->set('meta_key', 'time_to_complete_course');
$query->set('meta_value', $_GET['time_to_complete_course']);
}
if( isset($_GET['difficulty']) ) {
$query->set('meta_key', 'difficulty');
$query->set('meta_value', $_GET['difficulty']);
}
}
// return
return $query;
}
add_action('pre_get_posts', 'my_pre_get_posts');
分類法を照会するのはそのままでうまくいくようです。
だから私の完成したURLの例は次のようになります。
http://localhost:3000/courses/?course_project_category=jokes&course_or_project=project&difficulty=easy&time_to_complete_project=15
私の結果は、この時点では混在しています。
上記のクエリから、私の基準にほぼ一致する2つの投稿が返されましたが、具体的な例として、クエリでtime_to_complete_project
が指定されていても1つの投稿に30
の値が15
として表示されます。
これがわかりません。 Chromeの開発ツールでは、パラメータがすべて期待通りに表示されていることがわかります。
何か案は?!
更新
これが私が持っている新しいアプローチです(しかし検証と衛生が欠けています):
// array of filters (field key => field name)
$GLOBALS['my_query_filters'] = array(
'field_1' => 'course_or_project',
'field_2' => 'difficulty',
'field_3' => 'time_to_complete_project',
'field_4' => 'time_to_complete_course'
);
// action
add_action('pre_get_posts', 'my_pre_get_posts', 10, 1);
function my_pre_get_posts( $query ) {
// bail early if is in admin
if( is_admin() ) {
return;
}
if( isset($query->query_vars['post_type']) && $query->query_vars['post_type'] == 'course' ) {
// get meta query
$meta_query = $query->get('meta_query');
// loop over filters
foreach( $GLOBALS['my_query_filters'] as $key => $name ) {
// continue if not found in url
if( empty($_GET[ $name ]) ) {
continue;
}
// get the value for this filter
// eg: http://www.website.com/events?city=melbourne,sydney
$value = explode(',', $_GET[ $name ]);
// append meta query
$meta_query[] = array(
'key' => $name,
'value' => $value,
'compare' => 'IN',
);
}
// update meta query
$query->set('meta_query', $meta_query);
}
}
さて、これが私が最後に働いたものです。パラメータを正しくサニタイズしたかどうかは、私は正直にわかりません。それ以外は、すべて意図したとおりに動作します。 Pieter Goosenに感謝します。
// action
add_action('pre_get_posts', 'my_pre_get_posts', 10, 1);
function my_pre_get_posts( $query ) {
// bail early if is in admin
if( is_admin() ) {
return;
}
if( isset($query->query_vars['post_type']) && $query->query_vars['post_type'] == 'course' ) {
// array of filters (field key => field name)
$GLOBALS['my_query_filters'] = array(
'field_1' => 'course_or_project',
'field_2' => 'difficulty',
'field_3' => 'time_to_complete_project',
'field_4' => 'time_to_complete_course'
);
// get meta query
$meta_query = $query->get('meta_query');
// loop over filters
foreach( $GLOBALS['my_query_filters'] as $key => $name ) {
// sanitize parameter
$name = filter_input( INPUT_GET, $name, FILTER_SANITIZE_STRING );
// continue if not found in url
if( empty($_GET[ $name ]) ) {
continue;
}
// get the value for this filter
// eg: http://www.website.com/events?city=melbourne,sydney
$value = explode(',', $_GET[ $name ]);
// append meta query
$meta_query[] = array(
'key' => $name,
'value' => $value,
);
}
// update meta query
$query->set('meta_query', $meta_query);
}
}
適切なmeta_query
を構築する必要があります。あなたのコードはあなたが1つのmeta_key
セットを持っているときにのみ機能するでしょう、あなたが1つ以上を持っているならば、すべてが混乱するでしょう。
また、決して$_GET
変数からのサニタイズされていない、検証されていない値を使用してはいけません( そしてそれに関してはどこから来る値でも )。 URLにスクリプトを追加して悪意のあるコードをサイトに挿入するのは非常に簡単です。検証と衛生管理はパフォーマンスに与える影響はごくわずかですが、確かにその間の価値があります。
あなたの問題を解決するために、あなたの行動を書き換えてみましょう。必要に応じてコメントしました。
add_action( 'pre_get_posts', function ( $q )
{
if ( !is_admin() // Do this only on the front end
&& $q->is_main_query() // Targets the main query only
) {
if( isset($query->query_vars['post_type']) && $query->query_vars['post_type'] == 'course' ) { // Not sure about this, can be $q->is_post_type_archive( 'course' )
// Get all our $_GET variables and sanitize and validate them
$course_or_project = filter_input( INPUT_GET, 'course_or_project', FILTER_SANITIZE_STRING );
$time_to_complete_project = filter_input( INPUT_GET, 'time_to_complete_project', FILTER_SANITIZE_STRING );
$time_to_complete_course = filter_input( INPUT_GET, 'time_to_complete_course', FILTER_SANITIZE_STRING );
$difficulty = filter_input( INPUT_GET, 'difficulty', FILTER_VALIDATE_INT );
// Set our variable to hold the meta_query
$meta_query = [];
// Now we build our meta_query
if( $course_or_project ) {
$meta_query[] = [
'key' => 'course_or_project',
'value' => $course_or_project
];
}
if( $time_to_complete_project ) {
$meta_query[] = [
'key' => 'time_to_complete_project',
'value' => $time_to_complete_project
];
}
if( $time_to_complete_course ) {
$meta_query[] = [
'key' => 'time_to_complete_course',
'value' => $time_to_complete_course
];
}
if( $difficulty ) {
$meta_query[] = [
'key' => 'difficulty',
'value' => $difficulty
];
}
// Make sure we have something in $meta_query before setting it
if ( $meta_query )
$q->set( 'meta_query', $meta_query );
}
}
});
必要に応じてクエリを絞り込むことができますが、これは非常に基本的なものです。