2017-08-28 73 views
8

背景复杂custom_field搜索与meta_query

我公司采用先进的自定义字段临来管理我的自定义字段和他们有一个包含存储为repeatername_X_fieldname子场一个“转发”字段,其中X是行数的中继器。

我有一个自定义后类型student具有中继attendance包含dateclass

所以,当学生参加一类,它将存储他们的出席如下

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

In或DER寻找谁一直到某一类或某一日期范围内参加任何学生,我要钩住get_meta_sql和转换我meta_query使用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'); 

这让我做这样的事情

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

为了寻找人谁参加历史101或

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

寻找今年参加的人。

问题部分1

我需要能够搜索到的人谁也参加了今年的“历史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' 
     ) 
    ) 
); 

然而,因为通配符没有联系,这样做可能会返回一个人谁出席“历史101”去年,但今年的课程不同。

问题部分2

实际上需要能够得到谁出席“历史101”这一年,但并没有表现出向上的类都在过去一周我们每个人的列表。这进一步使问题更加复杂,因为我需要将meta_query的EXISTSNOT EXISTS与其他条件结合起来。再次,从表面上看,这听起来相当简单使用嵌套meta_queries:

$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' 
      ) 
     ) 
    ) 
); 

显然,这是造成与逻辑问题,但令人印象深刻的WordPress由postmeta表中一次每次使用在元查询加盟解决了大部分。不幸的是,这意味着>日期部分不在NOT EXISTSON中使用,因此不能使用IS NULL来测试它不存在。

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

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

帮助!

回答

3

我一直在那里...试图把所有的一个复杂的元查询。最后,您需要手动处理生成的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 ...我希望你能理解这个想法。

+0

乍一看,这似乎是一个很好的解决方案。只要我有机会,我会测试它,让你知道。 – trex005

+0

好的。这对第2部分非常有用。但第1部分仍然存在相同的问题。例如,如果“学生1”去年参加了“历史101”,他将会出现在第一个“get_posts”结果中。那么,如果他今年参加了“历史102”,他将会在第二个'get_posts'中。 – trex005

+0

在第二个循环中尝试Wp_query post__not_in(https://codex.wordpress.org/Class_Reference/WP_Query) – GNANA