2013-08-13 6 views
4

В WordPress, как вы уже должны были знать, при использовании get_posts() или query_posts() или даже WP_Query, вы не можете заказать возвращенные сообщения, указав список идентификаторов сообщений в том порядке, в котором мы хотим.Как избежать влияния на другие запросы при использовании posts_orderby?

Вместо этого мы должны просмотреть результаты и переупорядочить их на стороне PHP. Это хиты производительности и плохая практика. Вместо этого мы должны использовать встроенные функции MySQL для извлечения сообщений в нужном порядке.

К счастью, есть posts_orderby, который может быть использован для определения пользовательского договора OrderBy, как это:

// My list of post IDs in my custom order 
$my_post_ids = array(1,3,2); 

// Apply filter to the ORDERBY SQL statement 
add_filter('posts_orderby', 'my_custom_orderby'); 
function my_custom_orderby($orderby_statement) { 
    global $my_post_ids; 
    $orderby_statement = 'FIELD(ID, '.implode(',',$my_post_ids).')';  
    return $orderby_statement; 
} 

// My custom query 
$my_custom_query = new WP_Query(array('post_type' => 'post', 'post__in' => $my_post_ids); 

Однако есть проблема с вышеуказанным кодом, является то, что это будет влиять на порядок всех запросов на странице! Включая запросы, сделанные плагинами, шорткодами и т. Д.

Простая установка!

Простой способ исправить это, чтобы применить фильтр только один раз, и удалить его, как только он называется, поставив remove_filter() внутри самого фильтра, поэтому он выполняется только один раз:

// My list of post IDs in my custom order 
$my_post_ids = array(1,3,2); 

// Apply filter to the ORDERBY SQL statement 
add_filter('posts_orderby', 'my_custom_orderby'); 
function my_custom_orderby($orderby_statement) { 

    // Disable this filter for future queries! 
    remove_filter(current_filter(), __FUNCTION__); 

    global $my_post_ids; 
    $orderby_statement = 'FIELD(ID, '.implode(',',$my_post_ids).')';  
    return $orderby_statement; 
} 

// My custom query 
$my_custom_query = new WP_Query(array('post_type' => 'post', 'post__in' => $my_post_ids); 

Поскольку я устанавливаю этот фильтр непосредственно перед моим пользовательским запросом, после выполнения моего пользовательского запроса его следует фильтровать с помощью установленного выше фильтра posts_orderby, который сразу же отключается, поэтому он не повлияет на будущие запросы.

Теоретически это здорово, и в большинстве случаев он отлично работает!

Проблема с WPML

Однако я столкнулся случай, когда с помощью WPML plugin, где этот фильтр влияет на другие запросы, чем у меня и вызывает ошибки. Я считаю, что плагин WPML создает собственный запрос, который выполняется непосредственно перед моим собственным пользовательским запросом, что делает мой фильтр применимым к запросу WPML вместо моего!

Есть ли способ добавить проверку в фильтр, чтобы убедиться, что он влияет на правильный запрос?

Большое спасибо


Edit:

Исправление WPML

Для получения дополнительной информации, а принятый ответ на этот вопрос правильно, это не решило проблему Я работал с WPML. Вот как я установил WPML конфликт:

// My list of post IDs in my custom order 
$my_post_ids = array(1,3,2); 

// Apply filter to the ORDERBY SQL statement 
add_filter('posts_orderby', 'my_custom_orderby'); 
function my_custom_orderby($orderby_statement) { 

    // Disable this filter for future queries! 
    remove_filter(current_filter(), __FUNCTION__); 

    global $my_post_ids, $wpdb; 
    $orderby_statement = 'FIELD('.$wpdb->base_prefix.'posts.ID, '.implode(',',$my_post_ids).')';  
    return $orderby_statement; 
} 

// My custom query 
$my_custom_query = new WP_Query(array('post_type' => 'post', 'post__in' => $my_post_ids); 

ответ

4

Этот фильтр takes two parameters, $orderby и &$this. «this» является объектом WP_Query. Я не уверен, как определить, что WPML делает звонок, но мы можем проверить, что ваш звонок является тем, который был сделан .

$my_post_ids = array(1,3,2); 

add_filter('posts_orderby', 'my_custom_orderby', 10, 2); 

function my_custom_orderby($orderby_statement, $object) 
{ 
    global $my_post_ids; 
    if($my_post_ids != $object->query['post__in']) 
     return $orderby_statement; 

    // Disable this filter for future queries! 
    remove_filter(current_filter(), __FUNCTION__); 

    $orderby_statement = 'FIELD(ID, ' . implode(',', $my_post_ids) . ')';  
    return $orderby_statement; 
} 
+0

Спасибо за ваш ответ.Я принял ваш ответ и предоставил вам репутацию +50 баунти, как только это позволит мне. Для информации ** это не решило мою проблему с WPML **, но по-прежнему является правильным ответом на мой вопрос. Я смог решить свою проблему, заменив 'ID' на' '. $ Wpdb-> base_prefix.'posts.ID' в инструкции. Поскольку WPML делает JOIN для каждого запроса (для получения перевода из другой таблицы, я думаю), имеющий сам идентификатор, вызвал ошибку MySQL, поскольку он не знал, к какой таблице относится поле идентификатора, поэтому добавление таблицы починил это! – Community

+0

Приятно было знать, что мой вклад помог решить проблему;) Возможно, вы можете написать ответ своим решением и пометить его как правильный, или отредактировать его и отредактировать. – brasofilo