使用meta_query进行复杂的custom_field搜索

时间:2017-08-28 23:21:09

标签: wordpress advanced-custom-fields custom-fields

背景

我使用高级自定义字段专业版来管理我的自定义字段,他们有一个"转发器"包含存储为repeatername_X_fieldname的子字段的字段,其中X是转发器的行号。

我有一个自定义帖子类型student,其中包含转发符attendance,其中包含dateclass

因此,当一名学生上课时,会按如下方式存储他们的出勤情况

  • meta_key :' attendance_X_date'的 meta_value :' 20170701'
  • meta_key :' attendance_X_class' meta_value :'历史101'

为了搜索已经去过某个班级或在特定日期范围内就读的学生,我必须挂钩get_meta_sql并将我的meta_query转换为使用{{1}当值包含LIKE

时,而不是=
%

这允许我做类似

的事情
function key_rewrite($parts){
    foreach($parts as &$part){
        $part = preg_replace("/(meta_key = )(\'[^']*[%][^']*\')/", "meta_key LIKE $2", $part);
    }
    return $parts;
}
add_action( 'get_meta_sql', 'key_rewrite');

为了搜索参加历史101或

的任何人
$args = array(
    'post_type' => 'student',
    'meta_query' => array(
        array(
            'key'=>'attendance_%_class',
            'compare'=>'=',
            'value'=>'History 101'
        )
    )
);
$my_query = new WP_Query($args);

搜索今年参加过的人。

问题第1部分

我需要能够搜索参加过历史记录101'今年。

最初,似乎meta_query上的一个简单的AND可以解决这个问题:

$args = array(
    'post_type' => 'student',
    'meta_query' => array(
        array(
            'key'=>'attendance_%_date',
            'compare'=>'>=',
            'value'=>'20170101'
        )
    )
);

但是,由于通配符没有链接,这实际上可能会让那些参加历史记录101'去年,但今年是另一个班级。

问题第2部分

实际上需要能够获得所有参加过历史记录101'今年,但过去一周没有出现在课堂上。这使问题进一步复杂化,因为我需要将meta_query的$args = array( 'post_type' => 'student', 'meta_query' => array( 'relation' => 'AND', array( 'key'=>'attendance_%_class', 'compare'=>'=', 'value'=>'History 101' ), array( 'key'=>'attendance_%_date', 'compare'=>'>=', 'value'=>'20170101' ) ) ); EXISTS与其他条件相结合。同样,从表面上看,使用嵌套的meta_queries听起来相当简单:

NOT EXISTS

显然,这是由逻辑问题造成的,但令人印象深刻的是,WordPress通过在元查询中每次使用一次加入postmeta表来解决大部分问题。不幸的是,这意味着>日期部分未在$args = array( 'post_type' => 'student', 'meta_query' => array( 'relation' => 'AND', array( 'relation' => 'AND', array( //Just assume by some magic we resolved Problem part 1 'key'=>'attendance_%_class', 'compare'=>'=', 'value'=>'History 101' ), array( 'key'=>'attendance_%_date', 'compare'=>'>=', 'value'=>'20170101' ) ), array( 'relation' => 'AND', array( //again... magic! 'key'=>'attendance_%_class', 'compare'=>'=', 'value'=>'History 101' ), array( 'key'=>'attendance_%_date', 'compare'=>'>', 'value'=>'20170821' ), array( 'key'=>'attendance_%_date', 'compare'=>'NOT EXISTS' ) ) ) ); NOT EXISTS中使用,因此无法使用ON来测试它是否存在。

我知道这非常复杂,如果你跟着我,我会留下深刻的印象。如果没有,请提出问题,以便我帮忙澄清。

是的,我知道我可以完全编写自己的查询,但我想坚持使用内置的WordPress工具。

HELP!

1 个答案:

答案 0 :(得分:2)

我去过那里......试图将所有内容放在一个复杂的元查询中。最后,您需要手动处理生成的SQL - 移动括号,替换运算符,引号等。

最后,查询非常复杂,并且对postmeta表有多个JOINS,它变得过于昂贵和缓慢。

我选择通过选择略有不同的方法来实现这一目标。 因此,您可以做的是将查询分成几个子查询,稍后将其与post__inpost__not_in合并,

例如问题第1部分

/* Filter by class */
$history_students_ids = get_posts(array(
    'post_type'      => 'student',
    'fields'         => 'ids',
    'posts_per_page' => -1,
    'meta_query'     => array(
        array(
            'key'=>'attendance_%_class',
            'compare'=>'=',
            'value'=>'History 101'
        ),
    )
));

/* Filter by date */
$students = get_posts(array(
    'post_type' => 'student',
    'post__in' => $history_students_ids,
    'meta_query' => array(
        array(
            'key'=>'attendance_%_date',
            'compare'=>'>=',
            'value'=>'20170101'
        )
    )
));

问题第2部分

也是如此
$not_attended_history_students_ids = get_posts(array(
    'post_type' => 'student',
    'post__in' => $history_students_ids,
    'fields'         => 'ids',
    'posts_per_page' => -1,
    'meta_query' => array(
        array(
            'key'=>'attendance_%_date',
            'compare'=>'NOT EXISTS'
        )
    )
));

$students = get_posts(array(
    'post_type' => 'student',
    'post__in' => $not_attended_history_students_ids,
    'meta_query' => array(
        array(
            'key'=>'attendance_%_date',
            'compare'=>'>=',
            'value'=>'20170101'
        )
    )
)); 

您可以将出勤状况反转为EXISTS并使用post__not_in ...我希望您能够理解这个想法。