amit
  • 0
Учитель

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

  • 0

У меня есть 3 категории с 15 сообщениями в каждой, я хочу сделать ОДИН запрос к базе данных, выводя только 5 первых сообщений для каждой категории, как я могу это сделать?

$q = new WP_Query(array( 'post__in' => array(2,4,8), 'posts_per_page' => **FIRST_5_OF_EACH_CAT** ));

Если это невозможно, что эффективнее: получить все сообщения для родительской категории и просмотреть их в цикле или создать 3 разных запроса?

Share
  1. Как вы хотите, чтобы они были заказаны?

    • 0
  2. То, что вы хотите, возможно, но потребует от вас углубиться в SQL, которого я стараюсь избегать, когда это возможно (не потому, что я этого не знаю, я продвинутый разработчик SQL, а потому, что в WordPress вы хотите использовать API, когда это возможно чтобы свести к минимуму будущие проблемы совместимости, связанные с будущими потенциальными изменениями структуры базы данных.)

    SQL с UNION оператором — это возможность

    Чтобы использовать SQL, вам нужен UNION оператор в вашем запросе, что-то вроде этого, если ваши слаги категории "category-1", "category-1" и "category-3" :

    SELECT * FROM wp_posts WHERE ID IN (
      SELECT tr.object_id
      FROM wp_terms t 
      INNER JOIN wp_term_taxonomy tt ON t.term_id = tt.term_id
      INNER JOIN wp_term_relationships tr ON tt.term_taxonomy_id = tr.term_taxonomy_id
      WHERE tt.taxonomy='category' AND t.slug='category-1'
      LIMIT 5
    
      UNION
    
      SELECT tr.object_id
      FROM wp_terms t 
      INNER JOIN wp_term_taxonomy tt ON t.term_id = tt.term_id
      INNER JOIN wp_term_relationships tr ON tt.term_taxonomy_id = tr.term_taxonomy_id
      WHERE tt.taxonomy='category' AND t.slug='category-2'
      LIMIT 5
    
      UNION
    
      SELECT tr.object_id
      FROM wp_terms t 
      INNER JOIN wp_term_taxonomy tt ON t.term_id = tt.term_id
      INNER JOIN wp_term_relationships tr ON tt.term_taxonomy_id = tr.term_taxonomy_id
      WHERE tt.taxonomy='category' AND t.slug='category-3'
      LIMIT 5
    )
    

    Вы можете использовать SQL UNION с posts_join фильтром

    Используя вышеизложенное, вы можете либо просто сделать вызов напрямую, либо использовать posts_join хук-фильтр, как показано ниже; обратите внимание, что я использую PHP heredoc, поэтому убедитесь, что SQL; он выровнен по левому краю. Также обратите внимание, что я использовал глобальную переменную, чтобы вы могли определять категории вне хука, перечисляя ярлыки категорий в массиве. Вы можете поместить этот код в плагин или в functions.php файл вашей темы:

    <?php
    global $top_5_for_each_category_join;
    $top_5_for_each_category_join = array('category-1','category-2','category-3');
    add_filter('posts_join','top_5_for_each_category_join',10,2);
    function top_5_for_each_category_join($join,$query) {
      global $top_5_for_each_category_join;
      $unioned_selects = array();
      foreach($top_5_for_each_category_join as $category) {
        $unioned_selects[] =<<<SQL
    SELECT object_id
    FROM wp_terms t
    INNER JOIN wp_term_taxonomy tt ON t.term_id = tt.term_id
    INNER JOIN wp_term_relationships tr ON tt.term_taxonomy_id = tr.term_taxonomy_id
    WHERE tt.taxonomy='category' AND t.slug='{$category}'
    LIMIT 5
    SQL;
      }
      $unioned_selects = implode("\n\nUNION\n\n",$unioned_selects);
      return $join . " INNER JOIN ($unioned_selects) categories ON wp_posts.ID=categories.object_id " ;
    }
    

    Но могут быть побочные эффекты

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

    Вместо этого сосредоточиться на оптимизации?

    Тем не менее, я предполагаю, что ваш вопрос больше касается оптимизации, чем возможности выполнить 5 лучших запросов по времени 3, верно? Если это так, то, возможно, есть другие варианты, использующие WordPress API?

    Лучше использовать Transients API для кэширования?

    Я полагаю, ваши сообщения не будут меняться так часто, верно? Что, если вы периодически принимаете три (3) запроса, а затем кэшируете результаты с помощью Transients API ? Вы получите удобный для сопровождения код и отличную производительность; немного лучше, чем UNION запрос выше, потому что WordPress будет хранить списки сообщений в виде сериализованного массива в одной записи wp_options таблицы.

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

    <?php
    
    $timeout = 4; // 4 hours
    $categories = array('category-1','category-2','category-3');
    
    include "wp-load.php";
    $category_posts = get_transient('top5_posts_per_category');
    if (!is_array($category_posts) || count($category_posts)==0) {
      echo "Hello Every {$timeout} hours!";
      $category_posts = array();
      foreach($categories as $category) {
        $posts = get_posts("post_type=post&numberposts=5&taxonomy=category&term={$category}");
        foreach($posts as $post) {
          $category_posts[$post->ID] = $post;
        }
      }
      set_transient('top5_posts_per_category',$category_posts,60*60*$timeout);
    }
    header('Content-Type:text/plain');
    print_r($category_posts);
    

    Резюме

    Хотя да, вы можете делать то, о чем просили, используя SQL UNION -запрос и posts_join ловушку фильтра, которую вам, вероятно, лучше предложить, используя вместо этого кэширование с API Transients.

    Надеюсь это поможет?

    • 0
  3. WP_Query() не поддерживает что-то вроде First X For Each Cat. Вместо этого WP_Query() вы можете использовать get_posts() на каждой из ваших категорий, так сказать, три раза:

    <?php
    $posts      = array():
    $categories = array(2,4,8);
    foreach($categories as $cat) {
      $posts[] = get_posts('numberposts=5&offset=1&category='.$cat);
    }
    ?>
    

    $posts теперь содержит первые пять сообщений для каждой категории.

    • 0
  4. Я не знаю, как получить первые пять сообщений для каждой из категорий в одном запросе. Если у вас когда-либо будет только 45 сообщений, то один раз попасть в базу данных и получить пять сообщений для каждой категории, вероятно, будет наиболее эффективным подходом. Однако трижды попасть в базу данных и объединить результаты — это неплохо.

    • 0

Оставить ответ

You must login to add an answer.