web-dev-qa-db-ja.com

2つのカスタムループ、ページ付け、オフセット

WP_Queryを使用しているループが2つあります。

最初のループはX件の投稿を示しています。改ページなし。
ループA

2番目のループはYの投稿を示しています。カスタムページネーション付き。
ループB

ちょっとうまくいく。しかし、2番目のループが最初のループからX個のポストを繰り返すのを見ることができます。最初に頭に浮かぶのはオフセットを設定することです(Xに等しい)、しかしそれはページネーションを壊し、この問題に専用のCodexに関する全ページがあります。回避策もありますが、問題はループが2つあるため、この回避策は両方のループに適用されます。

だから問題は
意図したとおりにこれを機能させる方法
可能な解決策は、Codexからのコードを2番目のループを「ターゲット」にすることですが、私はプログラマーではないので、これを行う方法がわかりません。私がやろうとしていることを達成するためのさらに良い方法があるかもしれませんが、私は他の選択肢を考えることができません。

追加情報
1)マークアップが非常に複雑なため、1つのループしか使用できません。
2)すべてのコードがネット上で見つかった
3)どちらのループも、作者やカテゴリなどに制限されません。単一の「フィード」のように見えるように「組み合わされた」2つの異なるレイアウトを持つ同じコンテンツです。

そして私は3つ以上のリンクを投稿することができないので、ここにページ付けコードがあります

function custom_pagination($numpages = '', $pagerange = '', $paged='') {
    if (empty($pagerange)) {
        $pagerange = 2;
    }

/**
    This first part of our function is a fallback
    for custom pagination inside a regular loop that
    uses the global $paged and global $wp_query variables.

    It's good because we can now override default pagination
    in our theme, and use this function in default quries
    and custom queries.
**/

global $paged;
if (empty($paged)) {
    $paged = 1;
}
if ($numpages == '') {
    global $wp_query;
    $numpages = $wp_query->max_num_pages;
    if(!$numpages) {
        $numpages = 1;
    }
}

/** 
    We construct the pagination arguments to enter into our paginate_links
    function. 
**/

$pagination_args = array(
    'base'            => get_pagenum_link(1) . '%_%',
    'format'          => 'page/%#%',
    'total'           => $numpages,
    'current'         => $paged,
    'show_all'        => False,
    'end_size'        => 1,
    'mid_size'        => $pagerange,
    'prev_next'       => True,
    'prev_text'       => __('«'),
    'next_text'       => __('»'),
    'type'            => 'plain',
    'add_args'        => false,
    'add_fragment'    => ''
);

$paginate_links = paginate_links($pagination_args);

if ($paginate_links) {
    echo "<nav class='custom-pagination'>";
        echo "<span class='page-numbers page-num'>Page " . $paged . " of " . $numpages . "</span> ";
        echo $paginate_links;
    echo "</nav>";
}
}

Codexからの解決策

add_action('pre_get_posts', 'myprefix_query_offset', 1 );
function myprefix_query_offset(&$query) {

//Before anything else, make sure this is the right query...
if ( ! $query->is_home() ) {
    return;
}

//First, define your desired offset...
$offset = 1;

//Next, determine how many posts per page you want (we'll use WordPress's settings)
$ppp = get_option('posts_per_page');

//Next, detect and handle pagination...
if ( $query->is_paged ) {

    //Manually determine page query offset (offset + current page (minus one) x posts per page)
    $page_offset = $offset + ( ($query->query_vars['paged']-1) * $ppp );

    //Apply adjust page offset
    $query->set('offset', $page_offset );

}
else {

    //This is the first page. Just use the offset...
    $query->set('offset',$offset);

}
}


add_filter('found_posts', 'myprefix_adjust_offset_pagination', 1, 2 );
function myprefix_adjust_offset_pagination($found_posts, $query) {

//Define our offset again...
$offset = 1;

//Ensure we're modifying the right query object...
if ( $query->is_home() ) {
    //Reduce WordPress's found_posts count by the offset... 
    return $found_posts - $offset;
}
return $found_posts;
}
1
Colton

マークアップが非常に複雑なため、1つのループしか使用できません。

マークアップは、どんなに複雑であっても、複数のループを実行することにしたときに有効な根拠になることは決してありません。複数のループは、特定の結果を得るための手段が他にまったくない場合にのみ使用してください。ほとんどの場合、投稿タイプごとのページごとの投稿数が異なるなど、クエリ引数ごとに異なる結果が必要です。

両方のループは、作者やカテゴリなどに制限されない

上記のステートメントも2番目のループの使用を検証しません。このステートメントに基づいて、マークアップがどれほど複雑かにかかわらず、ループが1つだけ必要になります。

特定のクエリからの結果の表示方法は、次のようにして常に操作できます。

  • rewind_posts()はあなたのニーズに応じて2、3、100回ループを再実行させます。

  • カスタムカウンタ、または投稿をカウントし、ループカウンタ/カスタムカウンタが特定の数に当たった場合に別のことをさせるビルドインループカウンタ

  • 特定の条件に従って特定の投稿をターゲットにできる条件付きタグ/ステートメント(投稿タイプやカテゴリなど)

  • 投稿の追加/削除や並べ替えなど、返される投稿の配列を変更できるthe_postsのようなフィルタ

  • normal PHP usort()のような関数で、スクリーンに出力する前に返された投稿の配列をソートするのに使用できます。

  • 必要なものを表示するために、pre_get_postsを使用してメインクエリをいつでも操作できます。

これらは、複数のループを実行する代わりに使用できるほんの少しのオプションです。複数のループに関する問題は

  • ページネーションに関しては問題があります

  • 不要なデータベースクエリが発生し、ページの読み込み時間が遅くなり、リソースが無駄になる

常に覚えておくべき重要なことの1つは、メインクエリの結果を表示するメインループをカスタムクエリに置き換えてはいけないということです。彼らは常にそれらを解決するよりも多くの問題につながります。時間をかけて次の記事を読んでください。

問題を解決するには、オフセットを設定したりページ付けを再計算したりする必要がないので、pre_get_postsアクションとfound_postsフィルタを削除します。

あなたはあなたの必要性に従って望ましいページのあなたのループを調整する必要があるでしょう

実施例1

最初の投稿のスタイルを変更して他の投稿より詳細な情報を表示する

if ( have_posts() ) {
    while ( have_posts() ) {
        the_post();

            if ( 0 === $wp_query->current_post ) { // Target the first post only
                // Do what you need to do for the first post only
            } else {
                // Display all the other posts as needed   
            }
    }
}

または

if ( have_posts() ) {
    // Start our custom counter
    $counter = 0;
    while ( have_posts() ) {
        the_post();

            if ( 0 === $counter ) { // Target the first post only
                // Do what you need to do for the first post only
            } else {
                // Display all the other posts as needed   
            }
        // Update the counter 
       $counter++;
    }
}

この方法は複雑なマークアップにも適用できます。カスタムカウンタを設定してカスタムdivを開閉したり、投稿位置に異なるスタイルを適用したり、投稿グリッドを作成したりすることもできます。私はこれについてかなりの数の投稿をしました、それで私の答えを通して検索することを忘れないでください

実施例2

投稿タイプ別に分類された投稿を投稿タイプpostpageで表示する必要がある場合。ここではループを実行してpost投稿タイプの投稿を表示し、ループを巻き戻して再実行しますが、今回はpage投稿タイプの投稿のみを表示します

if ( have_posts() ) {
    while ( have_posts() ) {
        the_post();

            if ( 'post' === get_post_type() ) { // Only display posts from post post type
                // Do what you need to do post post type posts
            } 
    }

    rewind_posts(); // Rewind the loop so we can run it again

    while ( have_posts() ) {
        the_post();

            if ( 'page' === get_post_type() ) { // Only display posts from page post type
                // Do what you need to do page post type posts
            } 
    }
}

結論

マークアップがどれほど複雑に感じられるとしても、見てのとおり、それは常に複数のループの必要性を検証するものではなく、常に1つのループで十分です。PHPそして私達の利点に賢くろ過する

2
Pieter Goosen