Display posts by month

时间:2015-01-27 作者:wpuser

我想实现这样的目标,我不知道这是否可能,最好的方法是什么:

enter image description here

我查询帖子的方式如下:

<div class="post">
    <?php global $wp_query;
    query_posts( array(\'post_type\' => array( \'lecturas-post\' ),\'showposts\' => 15, \'paged\'=>$paged, \'order\' => \'DESC\' ));?>
    <?php while ( $wp_query->have_posts() ) : $wp_query->the_post(); ?>
        <div><?php the_title() ?></a>
    <?php endwhile; // end of the loop. ?>
</div>
任何人都可以给我一个如何或最好的方式做这件事的提示吗?

3 个回复
最合适的回答,由SO网友:Pieter Goosen 整理而成

正如在评论中所说,您可以在一个查询中完成此操作。这里的原则是,仅当前一篇文章的发布日期月份与前一篇文章的月份不匹配时,才显示日期标题

几句话开始之前,几句话:

  • Never 使用query_posts, 除非你真的需要打破页面上的所有内容。它不仅会重新运行主查询并将其中断,还会弄乱分页和全局查询,还会弄乱查询到的对象函数。如果确实需要运行自定义查询,请使用WP_Queryget_posts

  • showposts 几年前就放弃了posts_per_page

    无需使用全球$wp_query. query_posts 不管怎样,把事情搞砸了

    计划的帖子是按时间顺序排列的,最新的帖子排在第一位,最老的帖子排在最后,所以它们已经按照正确的顺序排列好了。这只是在适当的地方显示日期的问题。

    要做到这一点,您只需从当前帖子的发布日期获取当前月份和年份,然后将其与前一篇帖子的发布日期月份进行比较,如果月份不匹配,则显示日期,如果月份匹配,则不显示日期

    作为说明,我将使用主循环和主查询。

    要做到这一点,您需要:

    获取当前帖子发布日期后的月份。为此,请使用get_the_date( \'F\' )

    使用获取循环中的上一篇文章$wp_query->posts[\'this will be current post -1 \']->post.

    获取并比较两个职位的月份

    根据比较显示或不显示日期

    该代码进入循环,就在while() 陈述

    $current_month = get_the_date(\'F\');
    
    if( $wp_query->current_post === 0 ) { 
    
       the_date( \'F Y\' );
    
    }else{ 
    
        $f = $wp_query->current_post - 1;       
        $old_date =   mysql2date( \'F\', $wp_query->posts[$f]->post_date ); 
    
        if($current_month != $old_date) {
    
            the_date( \'F Y\' );;
    
        }
    
    }
    
    如果需要运行自定义查询,请尝试以下操作

    $q = new WP_Query( array(\'post_type\' => array( \'lecturas-post\' ),\'posts_per_page\' => 15, \'paged\'=>$paged, \'order\' => \'DESC\' ));
    
    if( $q->have_posts() ) {
        while( $q->have_posts() ) {
    
            $q->the_post();
    
            $current_month = get_the_date(\'F\');
    
            if( $q->current_post === 0 ) { 
    
               the_date( \'F Y\' );
    
            }else{ 
    
                $f = $q->current_post - 1;       
                $old_date =   mysql2date( \'F\', $q->posts[$f]->post_date ); 
    
                if($current_month != $old_date) {
    
                    the_date( \'F Y\' );;
    
                }
    
            }
    
            the_title();
    
        }
    
    }
    

SO网友:David Gard

在考虑了下面@PieterGoosen的评论后,我添加了一种通过使用单个查询实现您目标的方法。

我对这些方法进行了基准测试,单个查询速度更快multiple query method being about 15% slower. 不是很高的边际,但每一点都有帮助,老实说,这种方法可能会进一步完善。

我在Response中保留了multiple query方法,但我建议使用single query方法。

Single Query Method

$time_start = microtime(true);

/** Set up a date interval object for 6 monts ago (you can change as required) */
$interval = new DateInterval(\'P6M\');
$interval->invert = 1;

/** Grab the date as it was 6 months ago */
$date = new DateTime(date(\'Y-m-d\'));
$date->add($interval);

/** Query the database for all posts newer than the the given date interval */
$args = array(
    \'nopaging\'          => true,
    \'posts_per_page\'    => -1,
    \'post_type\'         => \'post\',
    \'post_status\'       => \'publish\',
    \'order_by\'          => \'date\',
    \'date_query\'        => array(
        \'after\' => $date->format(\'Y-m-d\')
    )
);
$month_query = new WP_Query($args);

/** Check to ensure that there are articles for this month... */
if($month_query->have_posts()) :

    $month_titles = array();
    $close_ul = false;
    
    
    //echo \'<ul style="padding-left: 250px;" id="monthly-posts">\';
    
    /** Set the attributes for displaying the title as an attribute */
    $title_attribute_args = array(
        \'before\'    => \'Visit article \\\'\',
        \'after\'     => \'\\\' \',
        \'echo\'      => false
    );      
    
    /** Loop through each post for this month... */
    while($month_query->have_posts()) : $month_query->the_post();
    
        /** Check the month/year of the current post */
        $month_title = date(\'F Y\', strtotime(get_the_date(\'Y-m-d H:i:s\')));
        
        /** Maybe output a human friendly date, if it\'s not already been output */
        if(!in_array($month_title, $month_titles)) :
        
            if($close_ul) echo \'</ul>\';                                                             // Check if the unordered list of posts should be closed (it shouldn\'t for the first \'$monthe_title\')
            echo \'<h1 style="padding-left: 250px;" id="monthly-title">\' . $month_title . \'</h1>\';   // Output the \'$month_title\'
            echo \'<ul style="padding-left: 250px;" id="monthly-posts">\';                            // Open an unordered lists for the posts that are to come
            $month_titles[] = $month_title;                                                         // Add this `$month_title\' to the array of `$month_titles` so that it is not repeated
            $close_ul = true;                                                                       // Indicate that the unordered list should be closed at the next oppurtunity
            
        endif;
        
        /** Output each article for this month */
        printf(
            \'<li id="monthly-post-%1$s">%2$s <a href="%3$s" title="%4$s">%3$s</a></li>\',
            get_the_ID(),                               /** %1$s - The ID of the post */
            get_the_title(),                            /** %2$s - The article title */
            get_permalink(get_the_ID()),                /** %3$s - The article link */
            the_title_attribute($title_attribute_args)  /** %4$s - The title for use as an attribute */
        );
        
    endwhile;
    
    if($close_ul) echo \'</ul>\'; // Close the last unordered list of posts (if there are any shown)
    
endif;

/** Reset the query so that WP doesn\'t do funky stuff */
wp_reset_query();
原始答案试试看。我把它设置为只选择最后6个月的帖子,每个月只选择最后5个帖子,但你可以随意修改。

基本上,代码将首先检查哪些月份有帖子,然后输出该月份的最后五篇帖子以及一个链接。

Multiple Query Method

global $wpdb, $wp_locale;
    
/** Query the individual months to display (I\'ve chosen the last 6 months) */
$query = $wpdb->prepare(\'
    SELECT DISTINCT YEAR(`%1$s`.`post_date`) AS year, MONTH(`%1$s`.`post_date`) AS month
    FROM `%1$s`
    WHERE `%1$s`.`post_type` = "post"
    ORDER BY `%1$s`.`post_date` DESC
    LIMIT 6\',
    $wpdb->posts
);
$months = $wpdb->get_results($query);

/** Count the number of months */
$month_count = count($months);

/** Ensure that there are months to display... */
if($month_count || ($month_count === 1 && $months[0]->month > 0)) :

    /** Loop through each month... */
    foreach($months as $month) :

        if($month->year === 0) :
            continue;
        endif;
        
        /** Grab the individual month and year, and construct a human friendly date (for the title) */
        $m = zeroise($month->month, 2);
        $y = $month->year;
        $human_date = sprintf(__(\'%1$s %2$d\'), $wp_locale->get_month($m), $y);
        
        /** Grab any posts for this month (I\'ve chosedn only the last 5 posts) */
        $args = array(
            \'nopaging\'          => true,
            \'posts_per_page\'    => 5,
            \'post_type\'         => \'post\',
            \'post_status\'       => \'publish\',
            \'order_by\'          => \'date\',
            \'year\'              => $y,
            \'monthnum\'          => $m
        );
        $month_query = new WP_Query($args);
        
        /** Check to ensure that there are articles for this month... */
        if($month_query->have_posts()) :

            /** Output a human friendly date */
            echo \'<h1 id="monthly-title">\' . $human_date . \'</h1>\';
            echo \'<ul id="monthly-posts">\';
            
            /** Set the attributes for displaying the title as an attribute */
            $title_attribute_args = array(
                \'before\'    => \'Visit article \\\'\',
                \'after\'     => \'\\\' \',
                \'echo\'      => false
            );      
            
            /** Loop through each post for this month... */
            while($month_query->have_posts()) : $month_query->the_post();
            
                /** Output each article for this month */
                printf(
                    \'<li id="monthly-post-%1$s">%2$s <a href="%3$s" title="%4$s">%3$s</a></li>\',
                    get_the_ID(),                               /** %1$s - The ID of the post */
                    get_the_title(),                            /** %2$s - The article title */
                    get_permalink(get_the_ID()),                /** %3$s - The article link */
                    the_title_attribute($title_attribute_args)  /** %4$s - The title for use as an attribute */
                );
                
            endwhile;
            
            echo \'</ul>\';
            
        endif;
        
        /** Reset the query so that WP doesn\'t do funky stuff */
        wp_reset_query();
        
    endforeach;

endif;

SO网友:Luca Reghellin

这是我为满足一般需要而开发的一个函数,用于检索特定年/月或当前年份之前或之后的post或自定义post类型数据,以您需要的顺序为准:

// you could change the name in case it collides with some other plugin
function get_posts_by_date($user_options = array()){

  $options = array(
    \'year_limit\' => \'1980\'
    ,\'month_limit\' => \'01\'
    ,\'operator\' => \'>=\' // date comparison operator
    ,\'current_year\' => true // limit data to current year
    ,\'post_type\' => \'post\'
    ,\'year_order\' => \'DESC\'
    ,\'month_order\' => \'DESC\'
    ,\'post_ids_order\' => \'DESC\'
    ,\'raw_output\' => false
  );

  extract(array_merge($options, $user_options));

  global $wpdb;

  if($operator == \'>=\' || $operator == \'==\'){
    $day = "01";
  } elseif($mode == \'<=\'){
    $day = "31";
  }

  if($current_year){ // will be after [previous year]/12/31
    $year_limit = date(\'Y\', strtotime(\'-1 year\'));
    $month_limit = \'12\';
    $day = "31";
    $operator == \'>=\';
  }

  // warning: if your parameters come from user input/forms, 
  // pass them using $wpdb::prepare()
  // https://developer.wordpress.org/reference/classes/wpdb/prepare/
  $results = $wpdb->get_results("
    SELECT tbl.y year, group_concat(month_posts ORDER BY tbl.m " . $month_order . " SEPARATOR \'-\') months
      FROM (
        SELECT YEAR(p.post_date) y, MONTH(p.post_date) m, concat(MONTH(p.post_date), \':\', group_concat(p.id ORDER BY p.post_date " . $post_ids_order . " )) month_posts
        FROM $wpdb->posts p
        WHERE (p.post_status = \'publish\' OR p.post_status = \'future\')
          AND p.post_type = \'" . $post_type . "\'
          AND p.post_date " . $operator . " DATE(\'" . $year_limit . "-" . $month_limit . "-" . $day . " 00:00:00\')
        GROUP BY y, m
      ) tbl
    GROUP BY tbl.y
    ORDER BY tbl.y " . $year_order
  );

  if($raw_output) return $results;

  global $wp_locale;

  foreach ($results as $data){
    $months_data = explode(\'-\',$data->months);
    $months = array();
    $data->count = 0; // year count

    foreach ($months_data as $month_data){
      $month_obj = new stdClass;

      $splitted = explode(\':\',$month_data);
      $raw_month = $splitted[0];
      $month_obj->number = $raw_month;
      $month_obj->name = $wp_locale->get_month($raw_month);
      $month_obj->posts = array();
      $post_ids = explode(\',\',$splitted[1]);
      $data->count += count($post_ids);

      foreach($post_ids as $post_id){
        $month_obj->posts[] = get_post($post_id);
        $months[$raw_month] = $month_obj;
      }// foreach
    }// foreach

    $data->months = $months;
  }// foreach

  return $results;
}// get_posts_by_date
用法示例:

$posts_by_date = get_posts_by_date(array(
  \'year_limit\' => \'2016\'
  ,\'operator\' => \'<=\'
  ,\'current_year\' => false
  ,\'post_type\' => \'product\'
  ,\'month_order\' => \'ASC\'
  ,\'raw_output\' => true
));
如果raw_output 选项为true时,默认输出如下:

array(2) {
  [0]=>
  object(stdClass)#6645 (2) {
    ["year"]=>
    string(4) "2017"
    ["months"]=>
    string(65) "8:386,401-7:406,373,380,377,408,399,362-6:1,391,404-5:367,397,394"
  }
  [1]=>
  object(stdClass)#6644 (2) {
    ["year"]=>
    string(4) "2016"
    ["months"]=>
    string(5) "6:429"
  }
}
“months”字符串包含以下格式的值:

month:[post ids]-month:[post ids]-ecc
如果raw_output 选项为false时,您会得到如下帖子列表:

array (array of objects)
  object
    -> year (ex. \'2017\')
    -> count (total year\'s posts)
    -> months (array of objects)
        month
          -> number (of month)
          -> name (localized)
          -> posts (array of post objects)
快乐编码…:)

结束