最合适的回答,由SO网友:J.D. 整理而成
为了实现这一点,无需手工创建自定义SQL查询。自版本4.1以来,WordPress的查询类supported complex/nested meta queries. 因此,您可以创建如下查询:
$args[\'meta_query\'] = array(
// Use an OR relationship between the query in this array and the one in
// the next array. (AND is the default.)
\'relation\' => \'OR\',
// If an end_date exists, check that it is upcoming.
array(
\'key\' => \'end_date\',
\'compare\' => \'>=\',
\'value\' => date( \'Ymd\', $current_date ),
),
// OR!
array(
// A nested set of conditions for when the above condition is false.
array(
// We use another, nested set of conditions, for if the end_date
// value is empty, OR if it is null/not set at all.
\'relation\' => \'OR\',
array(
\'key\' => \'end_date\',
\'compare\' => \'=\',
\'value\' => \'\',
),
array(
\'key\' => \'end_date\',
\'compare\' => \'NOT EXISTS\',
),
),
// AND, if the start date is upcoming.
array(
\'key\' => \'start_date\',
\'compare\' => \'>=\',
\'value\' => date( \'Ymd\', $current_date ),
),
),
);
我已经测试过了,它工作得很好。我的PHPUnit测试用例:
/**
* Tests something.
*/
class My_Plugin_Test extends WP_UnitTestCase {
public function test_wpse() {
$current_time = current_time( \'timestamp\' );
$current_date = date( \'Ymd\', $current_time );
$yesterday_date = date( \'Ymd\', strtotime( \'yesterday\' ) );
$post_ids = $this->factory->post->create_many( 6 );
$post_with_end_past = $post_ids[0];
$post_with_end_now = $post_ids[1];
$post_empty_end_past = $post_ids[2];
$post_empty_end_now = $post_ids[3];
$post_null_end_past = $post_ids[4];
$post_null_end_now = $post_ids[5];
// This post has an end date in the past.
update_post_meta( $post_with_end_past, \'start_date\', $yesterday_date );
update_post_meta( $post_with_end_past, \'end_date\', $yesterday_date );
// This post has an end date in the present.
update_post_meta( $post_with_end_now, \'start_date\', $yesterday_date );
update_post_meta( $post_with_end_now, \'end_date\', $current_date );
// This post has no end date, but a start date in the past.
update_post_meta( $post_empty_end_past, \'start_date\', $yesterday_date );
update_post_meta( $post_empty_end_past, \'end_date\', \'\' );
// This post has an empty end date, but the start date is now.
update_post_meta( $post_empty_end_now, \'start_date\', $current_date );
update_post_meta( $post_empty_end_now, \'end_date\', \'\' );
// This post has no end date set at all, and the start date is past.
update_post_meta( $post_null_end_past, \'start_date\', $yesterday_date );
// This post has no end date set at all, but the start date is now.
update_post_meta( $post_null_end_now, \'start_date\', $current_date );
$args = array();
$args[\'fields\'] = \'ids\';
$args[\'meta_query\'] = array(
// Use an OR relationship between the query in this array and the one in
// the next array. (AND is the default.)
\'relation\' => \'OR\',
// If an end_date exists, check that it is upcoming.
array(
\'key\' => \'end_date\',
\'compare\' => \'>=\',
\'value\' => $current_date,
),
// OR!
array(
// If an end_date does not exist.
array(
// We use another, nested set of conditions, for if the end_date
// value is empty, OR if it is null/not set at all.
\'relation\' => \'OR\',
array(
\'key\' => \'end_date\',
\'compare\' => \'=\',
\'value\' => \'\',
),
array(
\'key\' => \'end_date\',
\'compare\' => \'NOT EXISTS\',
),
),
// AND, if the start date is upcoming.
array(
\'key\' => \'start_date\',
\'compare\' => \'>=\',
\'value\' => $current_date,
),
),
);
$post_query = new WP_Query();
$posts_list = $post_query->query( $args );
// Only the "now" posts should be returned.
$this->assertSame(
array( $post_with_end_now, $post_empty_end_now, $post_null_end_now )
, $posts_list
);
}
}