web-dev-qa-db-ja.com

月ごとに投稿を表示する

私はこのようなことを達成したいのですが、それが可能であるかどうか、そしてそれを実行するための最良の方法が何であるかわかりません。

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
wpuser

コメントで述べたように、1回のクエリでこれを実行できます。ここでの原則は、前の投稿の投稿日の月が前の投稿の月と一致しない場合にのみ日付の見出しを表示することです。

いくつかの注意

始める前に、いくつか注意してください。

  • 絶対に query_postsを使用しないでください。ただし、実際にページ上のすべての情報を分割する必要がある場合は除きます。それは単にメインクエリを再実行してそれを壊すだけでなく、ページネーションとあなたのグローバルをめちゃくちゃにし、そしてまたあなたの問い合わせられたオブジェクト関数とめちゃくちゃにします。本当にカスタムクエリを実行する必要がある場合は、WP_Queryまたはget_postsを使用してください。

  • showpostsposts_per_pageのために数年前にドロップされました

  • グローバルな$wp_queryを利用する必要はありません。 query_postsはとにかくそれをめちゃくちゃにします

計画

投稿は、最新の投稿が最初に、最も古い投稿が最後に時系列順に配信されるため、すでに正しい順番になっています。適切な場所に日付を表​​示するだけです。

これを行うには、現在の投稿の投稿日から現在の月と年を取得し、それを前の投稿の投稿日の月と比較して、月が一致しない場合は日付を表示するだけです。一致すれば表示する

説明として、メインクエリでメインループを使用します。

これを達成するために、あなたはする必要があります:

  • 現在の投稿の投稿日から月を取得します。これを実現するには、get_the_date( 'F' )を使います

  • ループ内の前の投稿を$wp_query->posts['this will be current post -1 ']->postで取得します。

  • 2つの投稿の間の月を取得および比較する

  • 比較に従って日付を表示または非表示

コード

このコードは、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();

    }

}
9
Pieter Goosen

更新された回答

以下の@PieterGoosenからのコメントを検討した後、単一のクエリを使用してあなたの目的を達成する方法を追加しました。

私はメソッドをベンチマークしました、そして 複数のクエリメソッドはおよそ15%遅くなりました 。余計な余裕はありませんが、少しでも役立つので、正直に言うとメソッドはさらに洗練されたものになるでしょう。

私は繁栄のために答えの中に複数の問い合わせ方法を残しました、しかし私は単一の問い合わせ方法が使われることを勧めます。

シングルクエリ方式

$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つの投稿のみが選択されるように設定しましたが、あなたは好きなようにそれを変更することができます。

基本的に、コードは最初にどの月に投稿があるのか​​を確認してから、その月の最後の5つの投稿をリンクと共に出力します。

複数クエリ方式

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;
4
David Gard

これは、特定の年/月、または当年の前後に、投稿またはカスタム投稿の種類のデータを取得するために、一般的なニーズに合わせて使用​​した関数です。

// 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"
  }
}

「月」文字列には、次の形式の値が含まれています。

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)

ハッピーコーディング... :)

1
Luca Reghellin