カスタム/セカンダリクエリをテンプレートファイル/カスタムページテンプレートに追加しました。メインクエリループのページネーションを使用する代わりに、WordPressでページネーションにカスタムクエリを使用するにはどうすればよいですか?
補遺
を介してメインループクエリを変更しましたquery_posts()
。ページネーションが機能しないのはなぜですか?どうすれば修正できますか?
カスタム/セカンダリクエリをテンプレートファイル/カスタムページテンプレートに追加しました。メインクエリループのページネーションを使用する代わりに、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
、paged
URLクエリ変数。クエリがフェッチされると、そのpaged
パラメーターを使用して、どのページ分割された投稿のセットを返すかが決定されます。表示されたページネーションリンクをクリックして、次のページがロードされると、カスタムクエリにはページネーションが変更されたことを知る方法がありません。
カスタムクエリがargs配列を使用すると仮定します。
$custom_query_args = array(
// Custom query parameters go here
);
正しいpaged
パラメーターを配列に渡す必要があります。これを行うには、現在のページを特定するために使用されるURLクエリ変数を取得しますget_query_var()
:
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()
、と(いないいくつかの問題に実行されます少なくともページネーションの問題になりますています)。これらの問題を解決するための最初のステップは、不適切な使用をquery_posts()
適切なWP_Query()
呼び出しに変換することです。
query_posts()
メインループの変更に使用ページごとの投稿の変更やカテゴリの除外など、メインループクエリのパラメーターを変更するだけの場合は、を使用したくなるかもしれませんquery_posts()
。しかし、まだすべきではありません。を使用するとquery_posts()
、WordPressがメインのクエリオブジェクトを強制的に置き換えます。(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()
。
paged
が更新されていないことがわかりました(管理者と関係あります- ajax.php環境)ので、私はこれを追加しました: global $paged; $paged = $custom_query_args['paged'];
そしてそれは働いた:)
次のコードをページネーション付きのカスタムループに使用します。
<?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;
?>
ソース:
いつものように素晴らしいチップ。これに対する補足として、「イントロテキスト」のページにアタッチされたグローバルページテンプレートを使用し、その後にページングするサブクエリが続くという状況を考慮してください。
上記のようにpaginate_links()を使用すると、ほとんどがデフォルトで(そして、かなりパーマリンクがオンになっていると仮定すると)、ページネーションリンクはデフォルトmysite.ca/page-slug/page/#
で美しいですが404
、WordPressはその特定のURL構造を知らず、実際にエラーをスローします「page-slug」の子である「page」の子ページを探します。
ここでの秘trickは、/page/#/
構造を受け入れ、WordPress CANが理解できるクエリ文字列、つまりに書き換える特定の「疑似アーカイブページ」ページナメクジにのみ適用される気の利いた書き換えルールを挿入すること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" );
いつものように、書き換えルールを変更するときは、管理バックエンドで[設定]> [パーマリンク]にアクセスしてパーマリンクをフラッシュすることを忘れないでください。
このように動作する複数のページがある場合(たとえば、複数のカスタム投稿タイプを処理する場合)、各ページスラッグの新しい書き換えルールの作成を避けることができます。特定したページスラッグに対して機能する、より一般的な正規表現を作成できます。
1つのアプローチは次のとおりです。
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を受け取ります。
この方法の回避策が考えられるかどうかはわかりませんが、それが何らかの理由で書き換えルールをトリガーしたグローバルページテンプレートであるとよいでしょう。他の誰もその特定のナッツを割ったことがなければ、いつかこの答えを再訪するかもしれません。
_wp_page_template
別の書き換えルールとフラッシュルールを追加します。
を介してメインループクエリを変更しました
query_posts()
。ページネーションが機能しないのはなぜですか?どうすれば修正できますか?
作成された素晴らしい答えチップは今日修正する必要があります。
しばらくの間、メインクエリの実行直後にグローバルに$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
グローバルに依存します。
ページネーションの仕組みをさらに改善し、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;
?>