У меня есть два запроса, которые мне нужно попытаться объединить, чтобы моя разбивка на страницы работала правильно, а сообщения отображаются в правильном порядке.
У меня есть один запрос:
$today = date('m/d/Y', strtotime('today')); $args = array( 'post_type' => 'workshops', "posts_per_page" => 5, "paged" => $paged, 'meta_key' => 'select_dates_0_workshop_date', 'orderby' => 'meta_value', 'order' => 'ASC', 'meta_query' => array( array( 'key' => 'select_dates_0_workshop_date', 'meta-value' => "meta_value", 'value' => $today, 'compare' => '>=', 'type' => 'CHAR' ) ) );
Результаты этого запроса должны появиться после запроса выше:
$args = array( 'post_type' => 'workshops', "posts_per_page" => 5, "paged" => $paged, 'meta_key' => 'select_dates_0_workshop_date', 'orderby' => 'meta_value', 'order' => 'DESC', 'meta_query' => array( array( 'key' => 'select_dates_0_workshop_date', 'meta-value' => "meta_value", 'value' => $today, 'compare' => '<', 'type' => 'CHAR' ) ) );
Разница между двумя запросами заключается в следующем: 'order'
и 'compare'
.
Я сделал это в чистых запросах MYSQL, но я не уверен, как это сделать на WordPress
Это обновленная версия ответа, более гибкая, чем предыдущая.
Вот одна идея с использованием SQL UNION
:
Мы можем использовать данные из фильтра posts_clauses
для перезаписи SQL-запроса из фильтра posts_request
.
Мы расширяем класс WP_Query
для достижения нашей цели. Мы на самом деле делаем это дважды:
WP_Query_Empty
: получить сгенерированный SQL-запрос для каждого подзапроса, но без запроса базы данных. WP_Query_Combine
: для получения сообщений. Следующая реализация поддерживает объединение N
подзапросов.
Вот две демонстрации:
Предположим, у вас есть шесть должностей, упорядоченных по дате (DESC):
CCC AAA BBB CCC YYY ZZZ XXX
где XXX
, YYY
и ZZZ
старше DT=2013-12-14 13:03:40
.
Давайте закажем наши сообщения, чтобы сообщения, опубликованные после DT
, упорядочивались по заголовку (ASC) и сообщения publisehd перед тем, как DT
упорядочены по названию (DESC):
AAA BBB CCC ZZZ YYY XXX
Затем мы можем использовать следующее:
/** * Demo #1 - Combine two sub queries: */ $args1 = array( 'post_type' => 'post', 'orderby' => 'title', 'order' => 'ASC', 'date_query' => array( array( 'after' => '2013-12-14 13:03:40' ), ), ); $args2 = array( 'post_type' => 'post', 'orderby' => 'title', 'order' => 'DESC', 'date_query' => array( array( 'before' => '2013-12-14 13:03:40', 'inclusive' => TRUE ), ), ); $args = array( 'posts_per_page' => 1, 'paged' => 1, 'sublimit' => 1000, 'args' => array( $args1, $args2 ), ); $results = new WP_Combine_Queries( $args );
Это генерирует следующий SQL-запрос:
SELECT SQL_CALC_FOUND_ROWS * FROM ( ( SELECT wp_posts.* FROM wp_posts WHERE 1=1 AND ( ( post_date > '2013-12-14 13:03:40' ) ) AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') ORDER BY wp_posts.post_title ASC LIMIT 1000 ) UNION ( SELECT wp_posts.* FROM wp_posts WHERE 1=1 AND ( ( post_date <= '2013-12-14 13:03:40' ) ) AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') ORDER BY wp_posts.post_title DESC LIMIT 1000 ) ) as combined LIMIT 0, 10
Вот ваш пример:
/** * Demo #2 - Combine two sub queries: */ $today = date( 'm/d/Y', strtotime( 'today' ) ); $args1 = array( 'post_type' => 'workshops', 'meta_key' => 'select_dates_0_workshop_date', 'orderby' => 'meta_value', 'order' => 'ASC', 'meta_query' => array( array( 'key' => 'select_dates_0_workshop_date', 'value' => $today, 'compare' => '>=', 'type' => 'CHAR', ), ) ); $args2 = array( 'post_type' => 'workshops', 'meta_key' => 'select_dates_0_workshop_date', 'orderby' => 'meta_value', 'order' => 'DESC', 'meta_query' => array( array( 'key' => 'select_dates_0_workshop_date', 'value' => $today, 'compare' => '<', 'type' => 'CHAR', ), ) ); $args = array( 'posts_per_page' => 5, 'paged' => 4, 'sublimit' => 1000, 'args' => array( $args1, $args2 ), ); $results = new WP_Combine_Queries( $args );
Это должно дать вам запрос, подобный этому:
SELECT SQL_CALC_FOUND_ROWS * FROM ( ( SELECT wp_posts.* FROM wp_posts INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id) INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id) WHERE 1=1 AND wp_posts.post_type = 'workshops' AND (wp_posts.post_status = 'publish' OR wp_posts.post_author = 1 AND wp_posts.post_status = 'private') AND (wp_postmeta.meta_key = 'select_dates_0_workshop_date' AND (mt1.meta_key = 'select_dates_0_workshop_date' AND CAST(mt1.meta_value AS CHAR) >= '05/16/2014') ) GROUP BY wp_posts.ID ORDER BY wp_postmeta.meta_value ASC LIMIT 1000 ) UNION ( SELECT wp_posts.* FROM wp_posts INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id) INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id) WHERE 1=1 AND wp_posts.post_type = 'workshops' AND (wp_posts.post_status = 'publish' OR wp_posts.post_author = 1 AND wp_posts.post_status = 'private') AND (wp_postmeta.meta_key = 'select_dates_0_workshop_date' AND (mt1.meta_key = 'select_dates_0_workshop_date' AND CAST(mt1.meta_value AS CHAR) < '05/16/2014') ) GROUP BY wp_posts.ID ORDER BY wp_postmeta.meta_value DESC LIMIT 1000 ) ) as combined LIMIT 15, 5
Мы могли бы также объединить более двух подзапросов:
/** * Demo #3 - Combine four sub queries: */ $args = array( 'posts_per_page' => 10, 'paged' => 1, 'sublimit' => 1000, 'args' => array( $args1, $args2, $args3, $args4 ), ); $results = new WP_Combine_Queries( $args );
Вот демонстрационные классы:
/** * Class WP_Combine_Queries * * @uses WP_Query_Empty * @link https://stackoverflow.com/a/23704088/2078474 * */ class WP_Combine_Queries extends WP_Query { protected $args = array(); protected $sub_sql = array(); protected $sql = ''; public function __construct( $args = array() ) { $defaults = array( 'sublimit' => 1000, 'posts_per_page' => 10, 'paged' => 1, 'args' => array(), ); $this->args = wp_parse_args( $args, $defaults ); add_filter( 'posts_request', array( $this, 'posts_request' ), PHP_INT_MAX ); parent::__construct( array( 'post_type' => 'post' ) ); } public function posts_request( $request ) { remove_filter( current_filter(), array( $this, __FUNCTION__ ), PHP_INT_MAX ); // Collect the generated SQL for each sub-query: foreach( (array) $this->args['args'] as $a ) { $q = new WP_Query_Empty( $a, $this->args['sublimit'] ); $this->sub_sql[] = $q->get_sql(); unset( $q ); } // Combine all the sub-queries into a single SQL query. // We must have at least two subqueries: if ( count( $this->sub_sql ) > 1 ) { $s = '(' . join( ') UNION (', $this->sub_sql ) . ' ) '; $request = sprintf( "SELECT SQL_CALC_FOUND_ROWS * FROM ( $s ) as combined LIMIT %s,%s", $this->args['posts_per_page'] * ( $this->args['paged']-1 ), $this->args['posts_per_page'] ); } return $request; } } // end class /** * Class WP_Query_Empty * * @link https://stackoverflow.com/a/23704088/2078474 */ class WP_Query_Empty extends WP_Query { protected $args = array(); protected $sql = ''; protected $limits = ''; protected $sublimit = 0; public function __construct( $args = array(), $sublimit = 1000 ) { $this->args = $args; $this->sublimit = $sublimit; add_filter( 'posts_clauses', array( $this, 'posts_clauses' ), PHP_INT_MAX ); add_filter( 'posts_request', array( $this, 'posts_request' ), PHP_INT_MAX ); parent::__construct( $args ); } public function posts_request( $request ) { remove_filter( current_filter(), array( $this, __FUNCTION__ ), PHP_INT_MAX ); $this->sql = $this->modify( $request ); return ''; } public function posts_clauses( $clauses ) { remove_filter( current_filter(), array( $this, __FUNCTION__ ), PHP_INT_MAX ); $this->limits = $clauses['limits']; return $clauses; } protected function modify( $request ) { $request = str_ireplace( 'SQL_CALC_FOUND_ROWS', '', $request ); if( $this->sublimit > 0 ) return str_ireplace( $this->limits, sprintf( 'LIMIT %d', $this->sublimit ), $request ); else return $request; } public function get_sql( ) { return $this->sql; } } // end class
Затем вы можете настроить классы для своих нужд.
Я использую трюк, упомянутый здесь, чтобы сохранить порядок UNION
. Вы можете изменить его соответствующим нашим параметром sublimit
.
Это также должно работать для основных запросов, например , с помощью фильтра posts_request
.
Надеюсь, это поможет.
Проблема заключается в аргументе «порядок»: аргумент «meta_query» принимает массив мета-запросов, а также аргумент «отношение» (в основном, «AND» или «OR»). Это можно использовать для выбора сообщений как меньше, так и большего, чем-или-равно- $today
(хотя в этот момент мета-запрос бесполезен, поскольку он выбирает все семинары («ИЛИ») или «нет» («И») К сожалению, WP_Query не позволяет произвольно сортировать результаты (переход от ближайшего ближайшего к последнему мастерству).
Если вы знаете, как это сделать непосредственно в MySQL, вы можете рассмотреть возможность просмотра фильтров WP_Query , в posts_orderby
фильтра posts_orderby
. Эти фильтры позволяют начать воспроизведение с фактического SQL, сгенерированного классом WP_Query, без необходимости переключения на полностью настраиваемые запросы. Однако следует предупредить, что важно ограничить объем этих фильтров или подвергнуть их риску их применение к каждому запросу вашего сайта (в документации по фильтрам posts_where
есть несколько хороших примеров того, как это сделать).