it-swarm.com.ru

Пользовательский запрос - альтернативные сообщения по категориям

У меня есть пользовательский тип записи под названием "services" с пользовательской таксономией под названием "location". Каждое сообщение относится к категории "Местоположение A" или "Местоположение B".

Мне нужно запросить все сообщения из типа "услуги" и упорядочить их по дате. Однако вместо того, чтобы просто перечислять по дате, я хочу чередовать сообщения по каждой категории, например так:

  1. Новейший пост от "Местоположение А"
  2. Новейший пост от "Местоположение Б"
  3. 2-й новейший пост от "Местоположение А"
  4. 2-й новейший пост от "Местоположение B"
  5. 3-й новейший пост от "Местоположение А"
  6. 3-й новейший пост от "Местоположение B"

так далее...

Можно ли изменить следующий запрос для достижения этой цели? Или мне нужно проделать какое-то сложное объединение/объединение баз данных и т.д. (Как вы можете догадаться, я не знаком с этими запросами).

<?php $args = array(
        'post_type' => 'services', 
        'posts_per_page' => '-1',
        'order_by' => 'date',
        'order' => 'DESC',
            'tax_query' => array(
                array(
                    'taxonomy' => 'location',
                    'field' => 'slug',
                    'terms' => array ('location-a', 'location-b')
                )
            )
        );
        $query = new WP_Query( $args );

        if (have_posts()) : while( $query->have_posts() ) : $query->the_post(); ?>

Дополнительные примечания:

  • В каждой категории не будет четного количества сообщений, поэтому мне нужен запрос, чтобы продолжить вывод сообщений из местоположения A, как только у вас закончатся сообщения из местоположения B, и наоборот.
  • Что произойдет, если сообщение будет разделено на две категории? Я не хочу, чтобы это показывалось дважды.
  • Пользовательская таксономия "местоположение" используется несколькими различными типами записей. Но я хочу запросить только один тип сообщения за раз.
  • Мне нужно сохранить способность делать некоторые сообщения липкими.

Это возможно? Спасибо.

3
LBF

Правка

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

Если у меня есть 3 прикрепленных сообщения, не должны ли они быть первыми 3 сообщениями на первой странице, независимо от их даты публикации? Происходит то, что только липкие посты, которые попадают в этот первый набор из 10 постов в зависимости от их даты, рассматриваются как липкие. Остальные прикрепленные посты отображаются вверху любой страницы, на которую они попадают, в зависимости от их даты. Как заставить их отображаться в верхней части первой страницы, независимо от даты?

Я проверил то, что вы сказали, и поведение липких сообщений не такое, как я ожидал, при использовании налогового запроса с новым экземпляром WP_Query.

Возможные решения

  • Вы можете просто выполнить два запроса, один для липких постов и один, как описано в моем исходном ответе, и просто исключить липкие посты из второго запроса. Вам просто нужно немного переделать оригинальный ответ. Недостатком этого является то, что если вам нужно ровно 10 сообщений на страницу, то это не сработает. Чтобы это работало, вам нужно использовать смещения

  • Решение, которое я выбрал, рассматривает все условия отдельно, а затем объединяет их в одно

РЕШЕНИЕ

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

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

Хорошо, давайте код: ( я не буду вдаваться в детали по определенным пунктам, как это было обработано в исходном ответе )

Как вы увидите, я решил опубликовать два возможных используемых для липких сообщений. Вам нужно будет решить, как вы хотите обрабатывать стикеры, а затем раскомментировать и закомментировать код в соответствии с вашими потребностями. Вот два метода, которые я использовал

  • Если все ваши стикеры будут в пределах двух установленных терминов, вы можете просто использовать код как есть

  • Если ваши стикеры будут включать посты вне двух установленных терминов, и вам нужно исключить те, которые не принадлежат двум заданным терминам, вам нужно будет раскомментировать код, который не был закомментирован, а затем удалить эту строку

    $q = array_merge( $sticky_post, $new_posts_array );
    

ОСНОВНЫЕ ВНУТРЕННИЕ РАБОТЫ КОДЕКСА

Посты (мы извлекаем только идентификаторы постов для ускорения запросов) из определенного термина извлекаются отдельно, причина в том, что это быстрее, чем извлечение всех постов одновременно, а затем сортировка их по термину. Чтобы убедиться, что вы не получаете дубликаты, я установил второй запрос, чтобы исключить все сообщения, относящиеся к обоим терминам. Эти сообщения получаются только по первому запросу

Каждому из двух возвращаемых массивов затем назначаются новые ключи, один массив будет иметь четные ключи, а другой массив - неравные ключи. Эти массивы затем объединяются и сортируются. Новый массив теперь будет содержать сообщения из обоих массивов, отсортированных поочередно

Последний шаг - добавить к этому заметки. Теперь у вас есть массив, в котором хранятся идентификаторы постов, первые липкие посты, а затем посты сортируются попеременно по термину. Этот массив идентификаторов сохраняется во временном режиме, который будет обновляться каждые 7 дней (вы можете установить это соответствующим образом) или когда обновляется, удаляется или публикуется любое сообщение.

Этот массив идентификаторов сообщений теперь используется в обычном режиме для отображения сообщений в new WP_Query, а последовательность, в которой используются идентификаторы сообщений, будет использоваться для сортировки сообщений. Вот полный код

if ( false === ( $q = get_transient( 'ordered_posts' ) ) ) {

    $sticky_post = get_option( 'sticky_posts' );
    /* 
     * Only do this if sticky posts can belong to terms outside the given two terms
     * and you only need to include sticky posts that belongs to the given two terms
     * Uncomment this part if needed
    */
    /* 
    if( $sticky_post ) {
        $sticky_args = array(
            'post_type'         => 'services', 
            'posts_per_page'    => -1,
            'post__in'          => $sticky_post,
            'fields'            => 'ids',
            'tax_query'         => array(
                array(
                    'taxonomy'  => 'location',
                    'field'     => 'slug',
                    'terms'     => array ('location-a', 'location-b' )
                )
            )
        );
        $sticky_query = get_posts( $sticky_args );
    }
    */

    $args1 = array(
        'post_type'         => 'services', 
        'posts_per_page'    => -1,
        'post__not_in'      => $sticky_post,
        'fields'            => 'ids',
        'tax_query'         => array(
            array(
                'taxonomy'  => 'location',
                'field'     => 'slug',
                'terms'     => array ('location-a')
            )
        )
    );
    $query1 = get_posts( $args1 );

    $new_posts_array1 = [];

    if( $query1 ) {
        $counter1 = 0;

        foreach ( $query1 as $post ) {
            $new_posts_array1[$counter1++ * 2] = $post;
        }
        unset( $post );
    }

    $args2 = array(
        'post_type'         => 'services', 
        'posts_per_page'    => -1,
        'post__not_in'      => $sticky_post,
        'fields'            => 'ids',
        'tax_query'         => array(
                array(
                    'taxonomy'  => 'location',
                    'field'     => 'slug',
                    'terms'     => array ('location-b')
                ),
                array(
                    'taxonomy'  => 'location',
                    'field'     => 'slug',
                    'terms'     => array ('location-a'),
                    'operator'  => 'NOT IN',
                )
            )
    );
    $query2 = get_posts( $args2 );

    $new_posts_array2 = [];

    if( $query2 ) {
        $counter2 = 0;

        foreach ( $query2 as $post ) {
            $new_posts_array2[($counter2++ * 2) + 1] = $post;
        }
        unset( $post );
    }


    $new_posts_array = $new_posts_array1 + $new_posts_array2;
    ksort( $new_posts_array );

    // Comment this line out if you uncommented the other block of code
    $q = array_merge( $sticky_post, $new_posts_array );

    /* 
     * If you going to use the first block of commented-out code
     * then you will need to uncomment this piece of code. Just remember
     * to comment the piece of code above out as stated. You cannot have both
     * pieces of code going at once
    */
    /*
    if( isset( $sticky_query ) ) {
        $q = array_merge( $sticky_query, $new_posts_array );
    }else{
        $q = $new_posts_array;
    }   
    */

    set_transient( 'ordered_posts', $q, 7 * DAY_IN_SECONDS );
}

$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
$args = array(
 'post_type' => 'services',
    'paged'                 => $paged,
    'posts_per_page'        => 5,
    'post__in'              => $q,
    'ignore_sticky_posts'   => 1,
    'orderby'               => 'post__in',
);
$query = new WP_Query( $args );

if ( $query->have_posts() ) {
    while ( $query->have_posts() ) {
        $query->the_post();

        get_template_part( 'content', get_post_format() );

    }

    next_posts_link( 'Older Entries', $query->max_num_pages ); //Remember the $max_pages parameter with custom queries
    previous_posts_link( 'Newer Entries' );

    wp_reset_postdata();
}

Затем в вашем functions.php добавьте следующий код. Это приведет к удалению переходного процесса, если будет опубликовано новое сообщение, обновлено сообщение или изменен статус сообщения.

add_action( 'transition_post_status', function ( $new_status, $old_status, $post )
{
        delete_transient( 'ordered_posts' );

}, 10, 3 );

Отладка вышеуказанного кода

Как только переходный процесс установлен, вы не можете изменить код внутри него. Эти изменения появятся только после истечения переходного периода или после его удаления. Если код не работает, сделайте следующее

  • Сначала обновите любой пост, чтобы удалить переходный процесс, или удалите его вручную из БД.

  • Затем удалите две следующие строки

    if ( false === ( $q = get_transient( 'ordered_posts' ) ) ) {
    
  • а также

    set_transient( 'ordered_posts', $q, 7 * DAY_IN_SECONDS );
        }
    
  • Это удалит переходный процесс из установленного.

  • После удаления переходного процесса выполните var_dump( $var ) всех переменных и проверьте, получите ли вы желаемый результат. Специально проверяйте запросы и что возвращается

    • Пример: выгрузить то, что возвращается запросом $query1

      var_dump( $query1 );
      

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

ОРИГИНАЛЬНЫЙ ОТВЕТ

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

Вы сможете сделать это только с одним запросом. Первое, что нужно сделать, это получить все ваши сообщения из двух терминов за один раз, как вы уже сделали. Примечание: вам не нужно устанавливать порядок сортировки, так как date и DESC являются значениями по умолчанию.

Пользовательская таксономия "местоположение" используется несколькими различными типами записей. Но я хочу запросить только один тип сообщения за раз.

Просто добавьте параметр post_type к аргументам запроса, чтобы указать целевой тип сообщения

<?php 
$args = array(
    'post_type' => 'services', 
    'posts_per_page' => '-1',
    'tax_query' => array(
            array(
                'taxonomy' => 'location',
                'field' => 'slug',
                'terms' => array ('location-a', 'location-b')
            )
        )
);
$query = new WP_Query( $args );

if( $query->have_posts() ) {

Теперь вам нужно будет разбить массив возвращаемых постов на два отдельных массива: один массив для терминов location-a и location-b и один для липких постов. Массив возвращаемых сообщений хранится в $query->posts

Что произойдет, если сообщение будет разделено на две категории? Я не хочу, чтобы это показывалось дважды.

Вам нужно будет заранее решить, как вы хотите обработать это, либо как location-a, либо location-b, иначе вы можете получить дублирование. Допустим, мы относимся к ним как location-a

Мне нужно сохранить способность делать некоторые сообщения липкими.

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

Итак, вы можете сделать что-то вроде этого

$counter1 = 0;
$counter2 = 0;

$new_posts_array = [];
$sticky = [];
foreach ( $query->posts as $post ) {
    if( is_sticky() ) {
       $sticky[] = $post;
    }elseif( has_term( 'location-a', 'location' ) && has_term( 'location-b', 'location' ) || has_term( 'location-a', 'location' ) ) {
       $new_posts_array[$counter1++ * 2] = $post;
    }else{
       $new_posts_array[($counter2++ * 2) + 1] = $post;
    }
}

Все вопросы уже решены. Теперь у нас есть два массива: один содержит массив прикрепленных сообщений, а другой - переупорядоченные ключи с массивом сообщений.

Теперь нам нужно отсортировать массив сообщений естественным образом, чтобы ключи были в обычном порядке сортировки, начиная с 0. ( Мы также можем "сбросить" все клавиши, хотя в этом нет необходимости )

ksort($new_posts_array);

Теперь мы можем объединить наши два массива, чтобы у нас снова был один массив. Этот массив будет отображать наши сообщения

$q = array_merge( $sticky, $new_posts_array );

Теперь осталось только удалить исходный массив записей, сбросить исходный массив записей с помощью нашего переупорядоченного массива, перемотать цикл и повторно запустить его для вывода нашего списка.

unset( $query->posts );
$query->posts = $q;

$query->rewind_posts();

while( $query->have_posts() ) { 
   $query->the_post();

  //Display loop elements

}
wp_reset_postdata();

}

ВСЕ ВМЕСТЕ СЕЙЧАС!!!

<?php 
$args = array(
    'post_type' => 'services', 
    'posts_per_page' => '-1',
    'tax_query' => array(
            array(
                'taxonomy' => 'location',
                'field' => 'slug',
                'terms' => array ('location-a', 'location-b')
            )
        )
);
$query = new WP_Query( $args );

if( $query->have_posts() ) {

    $counter1 = 0;
    $counter2 = 0;

    $new_posts_array = [];
    $sticky = [];
    foreach ( $query->posts as $post ) {
        if( is_sticky() ) {
           $sticky[] = $post;
        }elseif( has_term( 'location-a', 'location' ) && has_term( 'location-b', 'location' ) || has_term( 'location-a', 'location' ) ) {
           $new_posts_array[$counter1++ * 2] = $post;
        }else{
           $new_posts_array[($counter2++ * 2) + 1] = $post;
        }
    }

    ksort($new_posts_array);

    $q = array_merge( $sticky, $new_posts_array );

    unset( $query->posts );
    $query->posts = $q;

    $query->rewind_posts();

    while( $query->have_posts() ) { 
       $query->the_post();

      //Display loop elements like
      echo get_the_term_list( $post->ID, 'location');
      the_title(); 

    }
    wp_reset_postdata();

}

ЗАПРОС С СТРАНИЦЕЙ

// set the "paged" parameter (use 'page' if the query is on a static front page)
$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
$args = array(
    'post_type'         => 'services', 
    'paged'             => $paged,
    'posts_per_page'    => '5',
    'tax_query'         => array(
            array(
                'taxonomy'  => 'location',
                'field'     => 'slug',
                'terms'     => array ('location-a', 'location-b')
            )
        )
);
$query = new WP_Query( $args );

if( $query->have_posts() ) {

    $counter1 = 0;
    $counter2 = 0;

    $new_posts_array = [];
    $sticky = [];
    foreach ( $query->posts as $post ) {
        if( is_sticky() ) {
           $sticky[] = $post;
        }elseif( has_term( 'location-a', 'location' ) && has_term( 'location-b', 'location' ) || has_term( 'location-a', 'location' ) ) {
           $new_posts_array[$counter1++ * 2] = $post;
        }else{
           $new_posts_array[($counter2++ * 2) + 1] = $post;
        }
    }

    ksort($new_posts_array);

    $q = array_merge( $sticky, $new_posts_array );

    unset( $query->posts );
    $query->posts = $q;

    $query->rewind_posts();

    while( $query->have_posts() ) { 
       $query->the_post();

      //Display loop elements like
      echo get_the_term_list( $post->ID, 'location');
      the_title(); 

    }

    next_posts_link( 'Older Entries', $query->max_num_pages ); //Remember the $max_pages parameter with custom queries
    previous_posts_link( 'Newer Entries' );


    wp_reset_postdata();

}
6
Pieter Goosen