テンプレートファイル/カスタムページテンプレートにカスタム/セカンダリクエリを追加しました。メインクエリループのページ区切りを使用するのではなく、WordPressでページ区切りにカスタムクエリを使用する方法
query_posts()
でメインループクエリを修正しました。ページネーションが機能しないのはなぜですか。また、どうすれば修正できますか?
デフォルトでは、特定のコンテキストで、WordPressはメインクエリを使用してページネーションを決定します。メインクエリオブジェクトは$wp_query
グローバルに保存され、メインクエリループの出力にも使用されます。
if ( have_posts() ) : while ( have_posts() ) : the_post();
カスタムクエリを使用 の場合、完全に別個のクエリオブジェクトを作成します。
$custom_query = new WP_Query( $custom_query_args );
そして、そのクエリは完全に独立したループを介して出力されます:
if ( $custom_query->have_posts() ) :
while ( $custom_query->have_posts() ) :
$custom_query->the_post();
しかし、 previous_posts_link()
、 next_posts_link()
、 posts_nav_link()
、および paginate_links()
を含むページネーションテンプレートタグは、メインクエリオブジェクト、$wp_query
。そのメインクエリはページ分割される場合とされない場合があります。たとえば、現在のコンテキストがカスタムページテンプレートである場合、メインの$wp_query
オブジェクトは、単一のポスト-カスタムページテンプレートが属するページのIDのみで構成されます。割り当てられています。
現在のコンテキストが何らかのアーカイブインデックスである場合、メインの$wp_query
はページネーションを引き起こすのに十分な投稿で構成され、次の問題の部分につながります。メインの$wp_query
オブジェクトの場合、WordPressはpaged
URLクエリ変数に基づく、クエリのpaged
パラメーター。クエリが取得されると、そのpaged
パラメータを使用して、どのページ分割された投稿のセットを返すかが決定されます。表示されたページネーションリンクをクリックして、次のページがロードされると、カスタムクエリにはページネーションが変更されたことを知る方法がありません。
カスタムクエリがargs配列を使用すると仮定します。
$custom_query_args = array(
// Custom query parameters go here
);
正しいpaged
パラメーターを配列に渡す必要があります。 get_query_var()
を使用して、現在のページを決定するために使用されるURLクエリ変数を取得することにより、これを行うことができます。
get_query_var( 'paged' );
その後、カスタムクエリの引数配列にそのパラメーターを追加できます。
$custom_query_args['paged'] = get_query_var( 'paged' )
? get_query_var( 'paged' )
: 1;
注:ページが静的フロントページの場合、必ず静的フロントページはpage
ではなくpaged
を使用するため、page
の代わりにpaged
を使用します。これは、静的なフロントページに必要なものです。
$custom_query_args['paged'] = get_query_var( 'page' )
? get_query_var( 'page' )
: 1;
これで、カスタムクエリが取得されると、ページ分割された投稿の正しいセットが返されます。
ページネーション関数が正しい出力を生成するために-すなわち、カスタムクエリに関連する前/次/ページリンク-WordPressは、カスタムクエリを強制的に認識する必要があります。これにはちょっとした「ハック」が必要です。メインの$wp_query
オブジェクトをカスタムクエリオブジェクト$custom_query
に置き換えるには:
$temp_query = $wp_query
$wp_query = NULL;
カスタムクエリをメインクエリオブジェクトにスワップします:$wp_query = $custom_query;
$temp_query = $wp_query;
$wp_query = NULL;
$wp_query = $custom_query;
この「ハック」は、ページネーション関数を呼び出す前に実行する必要があります
ページネーション関数が出力されたら、メインクエリオブジェクトをリセットします:
$wp_query = NULL;
$wp_query = $temp_query;
previous_posts_link()
関数は、ページネーションに関係なく正常に機能します。現在のページを特定し、page - 1
のリンクを出力するだけです。ただし、 next_posts_link()
を適切に出力するには修正が必要です。これは、 next_posts_link()
がmax_num_pages
パラメーターを使用するためです。
<?php next_posts_link( $label , $max_pages ); ?>
他のクエリパラメータと同様に、デフォルトでは、関数はメインのmax_num_pages
オブジェクトに$wp_query
を使用します。 next_posts_link()
に$custom_query
オブジェクトを考慮させるには、max_num_pages
を関数に渡す必要があります。この値を$custom_query
オブジェクトから取得できます:$custom_query->max_num_pages
:
<?php next_posts_link( 'Older Posts' , $custom_query->max_num_pages ); ?>
以下は、ページネーション関数が適切に機能するカスタムクエリループの基本的な構成です。
// Define custom query parameters
$custom_query_args = array( /* Parameters go here */ );
// Get current page and append to custom query parameters array
$custom_query_args['paged'] = get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1;
// Instantiate custom query
$custom_query = new WP_Query( $custom_query_args );
// Pagination fix
$temp_query = $wp_query;
$wp_query = NULL;
$wp_query = $custom_query;
// Output custom query loop
if ( $custom_query->have_posts() ) :
while ( $custom_query->have_posts() ) :
$custom_query->the_post();
// Loop output goes here
endwhile;
endif;
// Reset postdata
wp_reset_postdata();
// Custom query loop pagination
previous_posts_link( 'Older Posts' );
next_posts_link( 'Newer Posts', $custom_query->max_num_pages );
// Reset main query object
$wp_query = NULL;
$wp_query = $temp_query;
query_posts()
についてはどうですか?query_posts()
query_posts()
を使用してカスタムループを出力する場合、 WP_Query()
を使用してカスタムクエリの個別のオブジェクトをインスタンス化すると、 _doing_it_wrong()
=、およびいくつかの問題に遭遇します(leastではなく、ページネーションの問題です)。これらの問題を解決する最初のステップは、 query_posts()
の不適切な使用を適切な WP_Query()
呼び出しに変換することです。
query_posts()
を使用してメインループを変更するメインループクエリのパラメーターを変更するだけの場合(ページごとの投稿の変更やカテゴリの除外など)、 query_posts()
を使用したくなるかもしれません 。しかし、まだすべきではありません。 query_posts()
を使用する場合、WordPressを強制してreplaceメインクエリオブジェクトにします。 (WordPressは実際に2番目のクエリを作成し、$wp_query
を上書きします。)ただし、問題は、ページ付けを更新するにはこの置換をプロセスの後半で行うことです。
解決策は、pre_get_posts
フックを介して、投稿を取得する前にメインクエリをフィルタリングすることです。
これをカテゴリテンプレートファイル(category.php
)に追加する代わりに:
query_posts( array(
'posts_per_page' => 5
) );
以下をfunctions.php
に追加します。
function wpse120407_pre_get_posts( $query ) {
// Test for category archive index
// and ensure that the query is the main query
// and not a secondary query (such as a nav menu
// or recent posts widget output, etc.
if ( is_category() && $query->is_main_query() ) {
// Modify posts per page
$query->set( 'posts_per_page', 5 );
}
}
add_action( 'pre_get_posts', 'wpse120407_pre_get_posts' );
これをブログ投稿インデックステンプレートファイル(home.php
)に追加する代わりに:
query_posts( array(
'cat' => '-5'
) );
以下をfunctions.php
に追加します。
function wpse120407_pre_get_posts( $query ) {
// Test for main blog posts index
// and ensure that the query is the main query
// and not a secondary query (such as a nav menu
// or recent posts widget output, etc.
if ( is_home() && $query->is_main_query() ) {
// Exclude category ID 5
$query->set( 'category__not_in', array( 5 ) );
}
}
add_action( 'pre_get_posts', 'wpse120407_pre_get_posts' );
そうすれば、WordPressは、改ページを決定するときに、テンプレートを変更することなく、すでに変更された$wp_query
オブジェクトを使用します。
調査 この質問と回答 および この質問と回答 使用方法とタイミングを理解する WP_Query
、 pre_get_posts
、および query_posts()
。
このコードは、ページ区切り付きのカスタムループに使用します。
<?php
if ( get_query_var('paged') ) {
$paged = get_query_var('paged');
} elseif ( get_query_var('page') ) { // 'page' is used instead of 'paged' on Static Front Page
$paged = get_query_var('page');
} else {
$paged = 1;
}
$custom_query_args = array(
'post_type' => 'post',
'posts_per_page' => get_option('posts_per_page'),
'paged' => $paged,
'post_status' => 'publish',
'ignore_sticky_posts' => true,
//'category_name' => 'custom-cat',
'order' => 'DESC', // 'ASC'
'orderby' => 'date' // modified | title | name | ID | Rand
);
$custom_query = new WP_Query( $custom_query_args );
if ( $custom_query->have_posts() ) :
while( $custom_query->have_posts() ) : $custom_query->the_post(); ?>
<article <?php post_class(); ?>>
<h3><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h3>
<small><?php the_time('F jS, Y') ?> by <?php the_author_posts_link() ?></small>
<div><?php the_excerpt(); ?></div>
</article>
<?php
endwhile;
?>
<?php if ($custom_query->max_num_pages > 1) : // custom pagination ?>
<?php
$orig_query = $wp_query; // fix for pagination to work
$wp_query = $custom_query;
?>
<nav class="prev-next-posts">
<div class="prev-posts-link">
<?php echo get_next_posts_link( 'Older Entries', $custom_query->max_num_pages ); ?>
</div>
<div class="next-posts-link">
<?php echo get_previous_posts_link( 'Newer Entries' ); ?>
</div>
</nav>
<?php
$wp_query = $orig_query; // fix for pagination to work
?>
<?php endif; ?>
<?php
wp_reset_postdata(); // reset the query
else:
echo '<p>'.__('Sorry, no posts matched your criteria.').'</p>';
endif;
?>
ソース:
いつものように素晴らしいチップ。これに対する補足として、ある「イントロテキスト」のためにPageにアタッチされたグローバルページテンプレートを使用していて、その後にページングしたいサブクエリが続くという状況を考えてみましょう。
上記のように paginate_links() を使用すると、ほとんどデフォルトで、(そしてかなりパーマリンクがオンになっていると仮定して)ページネーションリンクはデフォルトでmysite.ca/page-slug/page/#
になりますが、404
エラーが発生します。特定のURL構造で、実際には "page"の子ページが "page-slug"の子になります。
ここでのトリックは、/page/#/
構造を受け入れ、それをWordPressが理解できるクエリ文字列、すなわちmysite.ca/?pagename=page-slug&paged=#
に書き換える、その特定の "疑似アーカイブページ"ページスラッグにのみ適用される気の利いた書き換えルールを挿入することです。 pagename
とpaged
はname
とpage
ではないことに注意してください(これが文字通り私の悲しみの原因となっていました。
これがリダイレクトのルールです。
add_rewrite_rule( "page-slug/page/([0-9]{1,})/?$", 'index.php?pagename=page-slug&paged=$matches[1]', "top" );
いつものように、書き換えルールを変更するときは、管理者バックエンドの設定>パーマリンクを訪問してパーマリンクのフラッシュを忘れないでください。
このように動作するページが複数ある場合(たとえば、複数のカスタム投稿タイプを扱う場合)、各ページスラッグに対して新しい書き換え規則を作成しないようにすることをお勧めします。私たちはあなたが識別したどのページスラッグにも使えるより一般的な正規表現を書くことができます。
一つのアプローチは以下の通りです:
function wpse_120407_pseudo_archive_rewrite(){
// Add the slugs of the pages that are using a Global Template to simulate being an "archive" page
$pseudo_archive_pages = array(
"all-movies",
"all-actors"
);
$slug_clause = implode( "|", $pseudo_archive_pages );
add_rewrite_rule( "($slug_clause)/page/([0-9]{1,})/?$", 'index.php?pagename=$matches[1]&paged=$matches[2]', "top" );
}
add_action( 'init', 'wpse_120407_pseudo_archive_rewrite' );
私が私の口の中で少し戸惑うのは、このアプローチの1つの欠点は、ページスラッグのハードコーディングです。管理者がその疑似アーカイブページのページスラッグを変更したことがある場合は乾杯です - 書き換え規則が一致しなくなり、恐ろしい404が表示されます。
私はこの方法のための回避策を考えることができるかどうかわからないが、それがどういうわけか書き換え規則を引き起こしたのがグローバルページテンプレートであるならば、それはいいだろう。他の誰もその特定のナッツを割っていないならばいつか私はこの答えを再検討するかもしれません。
私は
query_posts()
を介してメインループクエリを修正しました。ページネーションが機能しないのはなぜですか。また、どうすれば修正できますか?
素晴らしい答えChipが作成したものは今日修正する必要があります。
しばらくの間、メインクエリが実行された直後の$wp_the_query
グローバル変数と等しいはずの$wp_query
変数がありました。
これが、チップの答えの一部である理由です。
メインのクエリオブジェクトをハックする
もう必要ありません。一時変数を作成することでこの部分を忘れることができます。
// Pagination fix
$temp_query = $wp_query;
$wp_query = NULL;
$wp_query = $custom_query;
だから今我々は呼び出すことができます:
$wp_query = $wp_the_query;
あるいはもっと良いことが言えます。
wp_reset_query();
他のチップが概説したものはすべてそのままです。そのquery-reset-partの後、あなたはf($wp_query)
であるページ付け関数を呼び出すことができます - それらは$wp_query
globalに依存します。
ページネーションのメカニズムをさらに改善し、query_posts
関数により多くの自由を与えるために、私はこの可能な改善を作成しました:
global $wp_query;
$paged = get_query_var('paged', 1);
$args = array(
'post_type' => '{your_post_type_name}',
'meta_query' => array('{add your meta query argument if need}'),
'orderby' => 'modified',
'order' => 'DESC',
'posts_per_page' => 20,
'paged' => $paged
);
$query = new WP_Query($args);
if($query->have_posts()):
while ($query->have_posts()) : $query->the_post();
//add your code here
endwhile;
wp_reset_query();
//manage pagination based on custom Query.
$GLOBALS['wp_query']->max_num_pages = $query->max_num_pages;
the_posts_pagination(array(
'mid_size' => 1,
'prev_text' => __('Previous page', 'patelextensions'),
'next_text' => __('Next page', 'patelextensions'),
'before_page_number' => '<span class="meta-nav screen-reader-text">' . __('Page', 'patelextensions') . ' </span>',
));
else:
?>
<div class="container text-center"><?php echo _d('Result not found','30'); ?></div>
<?php
endif;
?>