投稿のページが続くカテゴリランディングページを作成するにはどうすればよいですか?


9

ユーザーがアーカイブの最初のページにいる場合に静的コンテンツを表示し、次のページのカテゴリに投稿を表示するテーマテンプレートを作成しようとしています。私は基本的にWired.comでカテゴリの動作を再現しようとしています。http: //www.wired.com/category/design はランディングページであり、/ category / design / page / 1はあなたのような投稿の新しい日付順のリストを表示しますカテゴリーアーカイブに期待します。

ここで重要なのは、カテゴリアーカイブの投稿を最初のページに表示しないことです。そのため、次のページから最初の投稿を開始する必要があります。「ページングされた」クエリ変数が2の場合、クエリのオフセットを0に設定することにより、オフセットと手動ページネーションを使用してこれを最初に試しましたが、ゼロに設定されている場合、オフセットは無視されるため、オフセットを次のように設定することが最善です。 1、カテゴリの2番目の投稿から開始します。

これは私がfunctions.phpに追加したものです:

add_action('pre_get_posts', 'category_query_offset', 1 );
function category_query_offset(&$query) {
  // Before anything else, make sure this is the right query
  if (!$query->is_category('news')) {
    return;
  }

  // Next, determine how many posts per page
  $ppp = get_option('posts_per_page');

  //Next, detect and handle pagination
  if ($query->is_paged) {
    // Manually determine page query offset
    $page_offset = (($query->query_vars['paged']-1) * $ppp) - $ppp;
    // Apply adjust page offset
    $query->set('offset', $page_offset );
  }
}

より良い方法と、Wiredが行うように見えるのは、デフォルトのページ付けを使用して、投稿が1ページ目から始まるが、静的コンテンツにはページ0を挿入することです。仮に、これは、「ページ」が0の場合は静的コンテンツを表示し、「ページ」が1の場合は投稿の最初のページを表示することで可能になるようです。 'ユーザーが最初のページを要求するとゼロになります。これは、/ pagegory / news / page / 1と/ category / newsの両方で「paged」が0であることを意味します。

ユーザーが/ category / newsではなく/ category / news / page / 1をリクエストしたかどうかを確認する方法はありますか?それが失敗した場合、2ページ目から始まるカテゴリのすべての投稿を表示する方法はありますか?

回答:


7

これは非常に興味深い質問です(私は特にあなたのアプローチと研究のために賛成しています)。ここでの大きな曲線は、クエリの最初のページです。

  • 0最初のページで投稿を返すようにクエリを設定することはできません

  • すべてのページのページコンテンツを1ページ上に移動すると、最後のページが失われます。クエリの投稿数は同じであるため、$max_num_pagesプロパティは同じままです。

WP_Query1ページのオフセットを使用して投稿を正しく返すようにクラスを「だます」必要があります。また、クエリの最後のページが失われないように、正しいページ数を取得する必要があります。

次のアイデアを見て、すべてをコードに入れてみましょう。ただしその前に、ここでいくつか注意点を挙げておきます。

重要な注意:

  • すべてがテストされていないため、バグがある可能性があります。デバッグをオンにしてこれをローカルでテストしてください

  • コードには少なくともPHP 5.3が必要です。5.3より前のバージョンでは致命的なエラーが発生します。PHP 5.5より前のバージョンをまだ使用している場合は、すでにかなり前にアップグレードしているはずです。

  • 正確なニーズに合うようにコードを変更して悪用する

電球のアイデア:

何が必要か

すべてを機能させるには、次のものが必要です。

  • 表示されている現在のページ番号

  • posts_per_page読み取り設定のオプションを設定

  • カスタム offset

  • $found_postsクエリのプロパティを変更してプロパティを修正し$max_num_pagesます

改ページはWP_Query非常に単純な数行のコードで行われます

if ( empty($q['nopaging']) && !$this->is_singular ) {
    $page = absint($q['paged']);
    if ( !$page )
        $page = 1;
    // If 'offset' is provided, it takes precedence over 'paged'.
    if ( isset( $q['offset'] ) && is_numeric( $q['offset'] ) ) {
        $q['offset'] = absint( $q['offset'] );
        $pgstrt = $q['offset'] . ', ';
    } else {
        $pgstrt = absint( ( $page - 1 ) * $q['posts_per_page'] ) . ', ';
    }
    $limits = 'LIMIT ' . $pgstrt . $q['posts_per_page'];
}

基本的に何が起こるか、オフセットが明示的に設定されると、pagedパラメーターは無視されます。SQL LIMIT句の最初のパラメーターはオフセットから再計算され、生成されたSQLクエリでスキップされる投稿の数になります。

あなたの質問から、明らかにに設定offsetする0と、次のチェックがtrueを返すはずなので、オフセットクエリは失敗します。これは奇妙です

if ( isset( $q['offset'] ) && is_numeric( $q['offset'] ) )

0は有効な数値であり、trueを返す必要があります。これがインストールにない場合は、問題をデバッグする必要があります

目の前の問題に戻るために、同じ種類のロジックを使用してオフセットを計算および設定し、ページ2の投稿1を取得し、そこからクエリをページ分割します。最初のページについては何も変更しないので、ページ1にあると想定される投稿は通常どおりページ上にあります。ページに表示しないように、後で「非表示」にするだけで済みます。 1

add_action( 'pre_get_posts', function ( $q )
{
    if (    !is_admin() // Only target the front end, VERY VERY IMPORTANT
         && $q->is_main_query() // Only target the main query, VERY VERY IMPORTANT
         && $q->is_cateory( 'news' ) // Only target the news category
    ) {
        $current_page = $q->get( 'paged' ); // Get the current page number
        // We will only need to run this from page 2 onwards
        if ( $current_page != 0 ) { // You can also use if ( is_paged() ) {
            // Get the amount of posts per page
            $posts_per_page = get_option( 'posts_per_page' );
            // Recalculate our offset
            $offset = ( ( $current_page - 1) * $posts_per_page ) - $posts_per_page; // This should work on page 2 where it returns 0

            // Set our offset
            $q->set( 'offset', $offset );
        }
    }
});

2ページの1ページから同じ投稿が表示されるはずです。前に述べたように、これが発生しない場合は、is_numeric( 0 )falseが返される(そうではないはずです)かpre_get_posts、オフセットを設定しようとしている別のアクションがあるか、活かし使用しているposts_*句フィルタ(具体的には、post_limitsフィルタを)。これは、自分でデバッグする必要があるものです。

次の問題は、前に述べたようにページ付けを修正することです。ページが短くなります。このためget_option( 'posts_per_page' )、クエリをその量でオフセットしているので、クエリで見つかった投稿の量にの値を追加する必要があります。これにより1$max_num_pagesプロパティに効果的に追加されます。

add_action( 'found_posts', function ( $found_posts, $q )
{
    if (    !is_admin() // Only target the front end, VERY VERY IMPORTANT
         && $q->is_main_query() // Only target the main query, VERY VERY IMPORTANT
         && $q->is_cateory( 'news' ) // Only target the news category
    ) {
        $found_posts = $found_posts + get_option( 'posts_per_page');
    }
}, 10, 2 );

これにより、最初のページを除くすべてがソートされます。

ALL TOGETHER NOW(特に@ialocin- Yellow Submarineの場合

これはすべて入ります functions.php

add_action( 'pre_get_posts', function ( $q )
{
    if (    !is_admin() // Only target the front end, VERY VERY IMPORTANT
         && $q->is_main_query() // Only target the main query, VERY VERY IMPORTANT
         && $q->is_cateory( 'news' ) // Only target the news category
    ) {
        $current_page = $q->get( 'paged' ); // Get the current page number
        // We will only need to run this from page 2 onwards
        if ( $current_page != 0 ) { // You can also use if ( is_paged() ) {
            // Get the amount of posts per page
            $posts_per_page = get_option( 'posts_per_page' );
            // Recalculate our offset
            $offset = ( ( $current_page - 1) * $posts_per_page ) - $posts_per_page; // This should work on page 2 where it returns 0

            // Set our offset
            $q->set( 'offset', $offset );
        }
    }
});

add_filter( 'found_posts', function ( $found_posts, $q )
{
    if (    !is_admin() // Only target the front end, VERY VERY IMPORTANT
         && $q->is_main_query() // Only target the main query, VERY VERY IMPORTANT
         && $q->is_cateory( 'news' ) // Only target the news category
    ) {
        $found_posts = $found_posts + get_option( 'posts_per_page');
    }
    return $found_posts;
}, 10, 2 );

最初のページのオプション

ここにはいくつかのオプションがあります:

オプション1

私はおそらくこのオプションを選びます。ここでしたいことは、category-news.phpこれをまだ行っていない場合)を作成することです。これは、newsカテゴリが表示されるときに常に使用されるテンプレートになります。このテンプレートは非常に単純になります

<?php
get_header()

if ( !is_paged() ) { // This is the first page
    get_template_part( 'news', 'special' );
} else { // This is not the first page
    get_template_part( 'news', 'loop' );
}

get_sidebar();
get_footer();

あなたが見ることができるように、私は2つのテンプレートパーツを含め、しているnews-special.phpnews-loop.php。2つのカスタムテンプレートの基本は次のとおりです。

  • news-special.php->このテンプレートパーツは、最初のページに表示したいものです。ここにすべてのカスタム静的情報を追加します。最初のページの投稿が表示されるため、このテンプレートでループを呼び出さないように注意してください。

  • news-loop.php->これは、ループを呼び出すテンプレートです。このセクションは次のようになります。

    global $wp_query;
    while ( have_posts() ) {
    the_post();
    
        // Your template tags and markup
    
    }
    

オプション2

静的コンテンツを含む別のテンプレートを作成し、category_templateフィルターを使用して、newsカテゴリーの最初のページを表示するときにこのテンプレートを使用します。また、このテンプレートではデフォルトのループを呼び出さないでください。また、ここでの命名規則がテンプレート階層内のテンプレート名と衝突しないことを確認してください

これがお役に立てば幸いです。気になるコメントはお気軽にどうぞ

編集

OPのおかげで、WP_Queryクラスに明確なバグがあります。tracチケット#34060を確認してください。私が投稿したコードはWordpress v4.4からのもので、このバージョンではバグが修正されています。

バグがあるv4.3のソースコードに戻りました。コードがパラメーターがであるかどうかを確認するだけなので、0値としてに設定すると無視されることを確認できます。PHPでは空と見なされます。この動作(バグ)がv4.3のみで見つかるか、以前のすべてのバージョンで見つかるかはわかりませんが(チケットによれば、このバグはv4.3にあります)、このバグのパッチを確認できます。トラックチケットで出ます。私が言ったように、このバグは間違いなくv4.4で修正されていますoffsetoffsetempty0


2
詳しい回答ありがとうございます。これは実際、私が最初の試みで実装したものとほぼ同じです。問題は、「オフセット」を0に設定しても機能しないことでした。実際には、WordPress Core core.trac.wordpress.org/ticket/34060のバグでした。パッチを当てることですべてがうまくいきました。コードが欠けているのはreturn $found_posts;、found_postsアクションのifステートメントの後だけです。ありがとう!
willcwelch

あなたの肯定的なフィードバックをありがとう。私は、バージョン4.3のソースコードに戻ってquery.php、はい、0ここでチェックが空のためであるため、無視され、0空としています。私の回答のコードはv4.4に同梱されている更新コードです。そのため、4.4でバグが修正されたことを確認できます。それに応じて回答を更新します。上のfound_posts問題、良いキャッチは、それが実際にフィルタであり、返されるべきです。楽しむ
Pieter Goosen

はは、ありがとう:)そして、なぜ不思議に思っているすべての人のために... 1、2、3、4、もう少し...私は
Nicolai

@ialocin haha​​ha、これは覚えておきます;-)
Pieter Goosen

1
それはかなりキャッチーです:)しかし、それは子供の歌のようにほとんど書かれているので不思議ではありません
ニコライ

0

更新:

add_action('pre_get_posts', 'category_query_offset', 1 );
function category_query_offset($query) {
 // Before anything else, make sure this is the right query
 if (!$query->is_category('news')) {
    return;
 }

 // Next, determine paged
 $ppp = get_option('paged');
}
// Next, handle paged
if($ppp > 1){
    $query->set('paged', $ppp-1);
}

次のようなことを試してください

$paged = ( get_query_var('paged') ) ? get_query_var('paged')-1 : 1;
$args = array (
    'paged' => $paged,
);

'paged'変数がどのように機能するかについての説明を修正しました。あなたがやろうとしていることは、各ページ番号を1だけ下げることです。そのため、ページ2のリクエストによってページ1が返されます。問題は、ページ1が照会されると、「paged」が0に設定されることです。また、get_query_var ()は、 'paged'のget_optionの代わりに使用する必要があります。この修正により、これが実行されると、クエリが変更されるたびに、ページリクエストの「paged」が0になるまでループが繰り返されます。
willcwelch
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.