Должен ли я использовать Pre Get Posts или WP_Query

29

У меня есть следующий запрос, который я вызываю в моем шаблоне taxonomy.php через query_brands_geo('dealers', 'publish', '1', $taxtype, $geo, $brands);

Эта функция работает отлично. Однако после прочтения кодекса для постов запросов он упомянул pre_get_posts как предпочтительный способ изменить запрос по умолчанию. Будут ли pre_get_posts более эффективными, чем моя функция wp_query ниже?

Если так, то как мне построить pre_get_posts и передать свою переменную и запрос ниже?

function my_custom_query($posttype, $poststatus, $paidvalue, $taxtype, $geo, $brands) {
   global $wp_query; 
   $wp_query = new WP_Query();
   $args = array( 
      'post_type' => $posttype, 
      'post_status' => array($poststatus), 
      'orderby' => 'rand', 
      'posts_per_page' => 30, 
      'meta_query' => array( 
         array( 
            'key' => 'wpcf-paid', 
            'value' => array($paidvalue), 
            'compare' => 'IN', 
            ) 
      ), 
      'tax_query' => array( 
         'relation' => 'AND', 
         array( 
            'taxonomy' => $taxtype, 
            'field' => 'slug', 
            'terms' => $geo 
         ), 
         array( 
            'taxonomy' => 'brands', 
            'field' => 'slug', 
            'terms' => $brands 
         ) 
      ) 
   ); 

   return $wp_query->query($args); 
} 
user1609391
источник

Ответы:

14

pre_get_postsбудет выполнять один и тот же запрос, так что оба будут занимать одинаковое время Но, если вы используете pre_get_postsдействие, вы сохраните один или несколько SQL-запросов. В данный момент WordPress выполняет запрос по умолчанию, а затем вы запускаете запрос с помощью этой функции, которая заменяет результаты запроса по умолчанию (в результате запрос по умолчанию бесполезен). Ниже , как вы можете переместить $argsTo

function custom_pre_get_posts($query, $posttype='dealers', $poststatus='publish', $paidvalue='1', $taxtype='any_default_value', $geo='any_default_value', $brands='any_default_value') {

    // filter your request here.
    if($query->is_category) {

        $args = array(
            'post_type' => $posttype,
            'post_status' => array($poststatus),
            'orderby' => 'rand',
            'posts_per_page' => 30,
            'meta_query' => array(
                array(
                    'key' => 'wpcf-paid',
                    'value' => array($paidvalue),
                    'compare' => 'IN',
                )
            ),
            'tax_query' => array(
                'relation' => 'AND',
                array(
                    'taxonomy' => $taxtype,
                    'field' => 'slug',
                    'terms' => $geo
                ),
                array(
                    'taxonomy' => 'brands',
                    'field' => 'slug',
                    'terms' => $brands
                )
            )
        );
        $query->query_vars = $args;
    }
}
add_action('pre_get_posts', 'custom_pre_get_posts');
МИСТЕР
источник
Большое спасибо за ответ. Это очень полезно. Один быстрый вопрос. Я поместил функцию в мой файл function.php темы. Я запускаю эту функцию custom_pre_get_posts ($ query) из моего таксономического .php. В файле taxonomy.php я устанавливаю переменные $ posttype, $ post_status, $ geo, $ бренды, $ taxtype и запускаю два цикла, изменяя эти переменные. Есть ли способ передать переменную в вышеуказанную функцию из taxonomy.php? Когда я пробую custom_pre_get_posts ($ query, 'дилеры', 'publish', '1', $ taxtype, $ geo, $ бренды); Я получаю пропущенный аргумент 2-7 для custom_pre_get_posts (). Я предполагаю из-за add_action ???
user1609391
1
Я предполагаю, что вы изменили custom_pre_get_posts, чтобы принять оставшиеся аргументы. Да, вы получаете ошибку из-за add_action. add_action вызывает эту функцию с одним аргументом (т. е. $ query), вы должны задать значения по умолчанию для других аргументов, чтобы избежать ошибок пропущенных аргументов. например ($ posttype = null, $ poststatus = null ...), чтобы он мог правильно вызываться с помощью add_action.
MR
М.Р. Спасибо за ответ. Я прочитал об операции добавления и вижу, что должен назначить приоритет и номер аргумента. Поэтому я изменил действие добавления на <code> add_action ('pre_get_posts', 'custom_pre_get_posts', 10,7); </ code> Затем на своей странице taxonomy.php я <code> do_action ('pre_get_post', $ query, ' дилеры ',' публиковать ',' 1 ', $ taxtype, $ geo, $ бренды); </ code>. Но я все еще получаю ту же ошибку. Я не был уверен, где поставить значения по умолчанию. Я попробовал Google, но не смог найти ссылку. Можете ли вы дать мне немного больше информации о том, как с этим справиться?
user1609391
Спасибо за ответ и пример. Но я думаю, что, возможно, я пытаюсь использовать pre_get_posts, когда мне просто нужно сделать новый запрос WordPress. Я пытался сохранить запрос, но в моем случае это могло быть невозможно. Причина в том, что все аргументы, которые вы устанавливаете в параметре, я хотел передать функции из моего файла taxonomy.php. Поэтому $ paidvalue = ”1” может быть 1 или 0, в зависимости от того, какое условие я выполняю в taxonomy.php. Кажется, pre_get_posts выше срабатывает, когда страница загружается, даже если я не вызываю функцию в моем файле taxonomy.php. Я вижу это правильно?
user1609391
3
Этот ответ не имеет смысла, поскольку он в настоящее время написан. Вы будете эффективно перезаписывать любое значение внутри $wp_queryобъекта, и все закончится неудачей. Кроме того, это просто неправда, что pre_get_postsбудет запущен дополнительный запрос ...
kaiser
10

Поздний ответ, так как ответ с наибольшим количеством голосов сломает ваш запрос и просто не соответствует действительности в некоторых важных моментах.

Основной WP_Query и это фильтры

Во-первых, WordPress внутренне использует query_posts()(тонкая обертка вокруг, WP_Queryкоторая не должна использоваться в темах или плагинах), чтобы сделать WP_Query. Это WP_Queryдействует как основной цикл / запрос. Этот запрос будет проходить через множество фильтров и действий, пока не будет построена фактическая строка запроса SQL. Одним из них является pre_get_posts. Другие posts_clauses, posts_whereи т.д. , которые также позволяют перехватывать процесс создания строки запроса.

Подробно рассмотрим, что происходит внутри ядра

WordPress запускает wp()функцию (in wp-includes/functions.php), которая вызывает $wp->main()( $wpявляется объектом класса WP, который определен в wp-includes/class-wp.php). Это говорит WordPress:

  1. Разобрать URL в спецификации запроса, используя WP->parse_request()- подробнее об этом ниже.
  2. Установите все переменные is_, которые используются условными тегами, используя $wp_query->parse_query()( $wp_queryявляется объектом class WP_Query, который определен в wp-includes/query.php). Обратите внимание, что, несмотря на название этой функции, в этом случае мы WP_Query->parse_queryфактически не выполняем синтаксический анализ для нас, поскольку это делается заранее WP->parse_request().
  3. Преобразуйте спецификацию запроса в запрос базы данных MySQL и выполните запрос базы данных, чтобы получить список сообщений, в функции WP_Query-> get_posts (). Сохраните записи в объекте $ wp_query для использования в цикле WordPress.

Исходный кодекс

Вывод

Если вы действительно хотите изменить основной запрос, то вы можете использовать широкий спектр фильтров. Просто используйте $query->set( 'some_key', 'some_value' );для изменения данных или используйте $query->get( 'some_key' );для извлечения данных для выполнения условных проверок. Это избавит вас от выполнения второго запроса, так как вы изменяете только SQL-запрос.

Если вам нужно сделать дополнительный запрос, тогда идите с WP_Queryобъектом. Это добавит еще один запрос к БД.

пример

Поскольку ответы всегда лучше работают с примером, у вас здесь есть один действительно хороший (подпорки для Брэда Туеснарда), который просто расширяет основной объект и, следовательно, довольно многократно используется (сделайте из него плагин):

class My_Book_Query extends WP_Query
{
    function __construct( $args = array() )
    {
        // Forced/default args
        $args = array_merge( $args, array(
            'posts_per_page' => -1
        ) );

        add_filter( 'posts_fields', array( $this, 'posts_fields' ) );

        parent::__construct( $args );
    }

    public function posts_fields( $sql )
    {
        return "{$sql}, {$GLOBALS['wpdb']->terms}.name AS 'book_category'";
    }
}

Затем вы можете запустить второй / дополнительный запрос, как показано в следующем примере. Не забудьте сбросить ваш запрос впоследствии.

$book_query = new My_Book_Query();
if ( $book_query->have_posts() )
{
    while ( $book_query->have_posts() )
    {
        $book_query->the_post();
        # ...do stuff...
    } // endwhile;
    wp_reset_postdata();
} // endif;
кайзер
источник