Masalah
Secara default, dalam konteks apa pun yang diberikan, WordPress menggunakan kueri utama untuk menentukan pagination. Objek kueri utama disimpan di $wp_query
global, yang juga digunakan untuk menampilkan loop kueri utama:
if ( have_posts() ) : while ( have_posts() ) : the_post();
Saat Anda menggunakan kueri khusus , Anda membuat objek kueri yang sepenuhnya terpisah:
$custom_query = new WP_Query( $custom_query_args );
Dan permintaan itu adalah output melalui loop yang sepenuhnya terpisah:
if ( $custom_query->have_posts() ) :
while ( $custom_query->have_posts() ) :
$custom_query->the_post();
Tapi tag pagination Template, termasuk previous_posts_link()
, next_posts_link()
, posts_nav_link()
, dan paginate_links()
, mendasarkan output mereka pada objek query utama , $wp_query
. Kueri utama itu mungkin atau mungkin tidak paginasi. Jika konteks saat ini adalah templat halaman kustom, misalnya, $wp_query
objek utama hanya akan terdiri dari satu posting - ID dari halaman di mana templat halaman kustom ditugaskan.
Jika konteks saat ini adalah semacam indeks arsip, utama $wp_query
mungkin terdiri dari cukup banyak posting yang menyebabkan pagination, yang mengarah ke bagian selanjutnya dari masalah: untuk $wp_query
objek utama , WordPress akan mengirimkan paged
parameter ke kueri, berdasarkan pada paged
Variabel kueri URL. Ketika kueri diambil, paged
parameter itu akan digunakan untuk menentukan set posting paginasi mana yang akan dikembalikan. Jika tautan pagination yang ditampilkan diklik, dan halaman berikutnya dimuat, permintaan khusus Anda tidak akan mengetahui bahwa pagination telah berubah .
Solusinya
Melewati Parameter Paged yang Benar ke Permintaan Kustom
Dengan asumsi bahwa kueri khusus menggunakan array args:
$custom_query_args = array(
// Custom query parameters go here
);
Anda harus meneruskan paged
parameter yang benar ke array. Anda dapat melakukannya dengan mengambil variabel kueri URL yang digunakan untuk menentukan halaman saat ini, melalui get_query_var()
:
get_query_var( 'paged' );
Anda kemudian dapat menambahkan parameter itu ke array args kueri khusus:
$custom_query_args['paged'] = get_query_var( 'paged' )
? get_query_var( 'paged' )
: 1;
Catatan: Jika halaman Anda adalah halaman depan statis , pastikan untuk menggunakan page
bukan paged
sebagai halaman depan statis gunakan page
dan tidak paged
. Inilah yang harus Anda miliki untuk halaman depan statis
$custom_query_args['paged'] = get_query_var( 'page' )
? get_query_var( 'page' )
: 1;
Sekarang, ketika kueri khusus diambil, kumpulan kiriman paginasi yang benar akan dikembalikan.
Menggunakan Objek Kueri Kustom untuk Fungsi Pagination
Agar fungsi pagination dapat menghasilkan output yang benar - yaitu tautan sebelumnya / berikutnya / halaman relatif terhadap permintaan khusus - WordPress harus dipaksa untuk mengenali permintaan khusus. Hal ini memerlukan sedikit "hack": mengganti utama $wp_query
objek dengan objek query kustom, $custom_query
:
Meretas objek permintaan utama
- Cadangkan objek permintaan utama:
$temp_query = $wp_query
- Null objek permintaan utama:
$wp_query = NULL;
Tukar kueri khusus ke objek kueri utama: $wp_query = $custom_query;
$temp_query = $wp_query;
$wp_query = NULL;
$wp_query = $custom_query;
"Retasan" ini harus dilakukan sebelum memanggil fungsi pagination
Setel ulang objek kueri utama
Setelah fungsi pagination telah di-output, reset objek query utama:
$wp_query = NULL;
$wp_query = $temp_query;
Perbaikan Fungsi Pagination
The previous_posts_link()
fungsi akan bekerja secara normal, terlepas dari pagination. Ini hanya menentukan halaman saat ini, dan kemudian menampilkan tautan untuk page - 1
. Namun, perbaikan diperlukan untuk next_posts_link()
menghasilkan dengan benar. Ini karena next_posts_link()
menggunakan max_num_pages
parameter:
<?php next_posts_link( $label , $max_pages ); ?>
Seperti parameter kueri lainnya, secara default fungsi akan digunakan max_num_pages
untuk $wp_query
objek utama . Untuk memaksa next_posts_link()
untuk memperhitungkan $custom_query
objek, Anda harus meneruskan max_num_pages
ke fungsi. Anda dapat mengambil nilai ini dari $custom_query
objek $custom_query->max_num_pages
::
<?php next_posts_link( 'Older Posts' , $custom_query->max_num_pages ); ?>
Menyatukan semuanya
Berikut ini adalah konstruksi dasar dari loop kueri khusus dengan fungsi pagination yang berfungsi dengan baik:
// 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;
Tambahan: Bagaimana query_posts()
?
query_posts()
untuk Loop Sekunder
Jika Anda menggunakan query_posts()
untuk menghasilkan loop kustom, alih-alih instantiating objek terpisah untuk permintaan kustom melalui WP_Query()
, maka Anda _doing_it_wrong()
, dan akan mengalami beberapa masalah (tidak sedikit yang akan menjadi masalah pagination). Langkah pertama untuk menyelesaikan masalah-masalah tersebut adalah mengonversi penggunaan yang tidak query_posts()
tepat menjadi WP_Query()
panggilan yang tepat .
Menggunakan query_posts()
untuk Memodifikasi Loop Utama
Jika Anda hanya ingin mengubah parameter untuk kueri loop utama - seperti mengubah posting per halaman, atau mengecualikan kategori - Anda mungkin tergoda untuk menggunakannya query_posts()
. Tapi kamu tetap tidak seharusnya. Saat Anda menggunakan query_posts()
, Anda memaksa WordPress untuk mengganti objek permintaan utama. (WordPress benar-benar membuat kueri kedua, dan menimpa $wp_query
.) Masalahnya, meskipun, ia melakukan penggantian ini terlambat dalam proses untuk memperbarui pagination.
Solusinya adalah dengan memfilter permintaan utama sebelum posting diambil , melalui pre_get_posts
hook.
Alih-alih menambahkan ini ke file templat kategori ( category.php
):
query_posts( array(
'posts_per_page' => 5
) );
Tambahkan yang berikut ke 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' );
Alih-alih menambahkan ini ke file template indeks posting blog ( home.php
):
query_posts( array(
'cat' => '-5'
) );
Tambahkan yang berikut ke 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' );
Dengan begitu, WordPress akan menggunakan objek yang sudah dimodifikasi $wp_query
saat menentukan pagination, tanpa perlu modifikasi templat.
Kapan harus menggunakan fungsi apa
Penelitian pertanyaan ini dan jawaban dan pertanyaan dan jawaban untuk memahami bagaimana dan kapan menggunakan WP_Query
, pre_get_posts
dan query_posts()
.
paged
tidak diperbarui (obv ada hubungannya dengan admin lingkungan ajax.php) jadi saya menambahkan ini:global $paged; $paged = $custom_query_args['paged'];
dan itu berhasil :)Saya menggunakan kode ini untuk loop kustom dengan pagination:
Sumber:
sumber
Luar biasa seperti biasa. Sebagai tambahan untuk ini, pertimbangkan situasi di mana Anda menggunakan templat halaman global yang dilampirkan ke Halaman untuk beberapa "teks intro" dan diikuti oleh subquery yang ingin Anda paging.
Menggunakan paginate_links () seperti yang Anda sebutkan di atas, dengan sebagian besar default, (dan dengan asumsi Anda telah mengaktifkan permalink cukup) tautan pagination Anda akan default ke
mysite.ca/page-slug/page/#
yang indah tetapi akan menimbulkan404
kesalahan karena WordPress tidak tahu tentang struktur URL tertentu dan akan benar-benar akan cari halaman anak dari "halaman" itu adalah anak dari "page-slug".Triknya di sini adalah menyisipkan aturan penulisan ulang yang bagus yang hanya berlaku untuk siput halaman "pseudo archive page" tertentu yang menerima
/page/#/
struktur dan menulis ulangnya ke string kueri yang dapat dipahami oleh WordPress, yaitumysite.ca/?pagename=page-slug&paged=#
. Perhatikanpagename
danpaged
tidakname
danpage
(yang menyebabkan saya benar-benar JAM kesedihan, memotivasi jawaban ini di sini!).Berikut aturan pengalihan:
Seperti biasa, ketika mengubah aturan penulisan ulang, jangan lupa untuk membilas permalink Anda dengan mengunjungi Pengaturan> Permalinks di Admin.
Jika Anda memiliki beberapa halaman yang akan berperilaku seperti ini (misalnya, ketika berhadapan dengan beberapa jenis posting kustom), Anda mungkin ingin menghindari membuat aturan penulisan ulang baru untuk setiap halaman slug. Kami dapat menulis ekspresi reguler yang lebih umum yang berfungsi untuk setiap halaman siput yang Anda identifikasi.
Satu pendekatan di bawah ini:
Kekurangan / Peringatan
Salah satu kelemahan dari pendekatan ini yang membuat saya muntah sedikit di mulut saya adalah hard-coding dari Page slug. Jika admin pernah mengubah halaman slug dari halaman pseudo-arsip itu, Anda bersulang - aturan penulisan ulang tidak akan lagi cocok dan Anda akan mendapatkan 404 yang ditakuti.
Saya tidak yakin bisa memikirkan solusi untuk metode ini, tetapi alangkah baiknya jika itu adalah templat halaman global yang entah bagaimana memicu aturan penulisan ulang. Suatu hari saya dapat meninjau kembali jawaban ini jika tidak ada orang lain yang memecahkan kacang itu.
sumber
_wp_page_template
, lalu tambahkan aturan penulisan ulang dan flush lainnya.Jawaban hebat Chip yang dibuat perlu dimodifikasi hari ini.
Untuk beberapa waktu kami memiliki
$wp_the_query
variabel yang harus sama dengan$wp_query
global setelah permintaan utama dijalankan.Inilah sebabnya mengapa ini bagian dari jawaban Chip:
sudah tidak dibutuhkan lagi. Kita bisa melupakan bagian ini dengan membuat variabel sementara.
Jadi sekarang kita bisa menelepon:
atau bahkan lebih baik kita dapat memanggil:
Segala yang lainnya yang diuraikan Chip tetap. Setelah permintaan-reset-bagian Anda dapat memanggil fungsi pagination yang
f($wp_query)
- tergantung pada$wp_query
global.Untuk lebih meningkatkan mekanika pagination dan memberikan lebih banyak kebebasan untuk
query_posts
fungsi, saya membuat peningkatan yang mungkin:https://core.trac.wordpress.org/ticket/39483
sumber
sumber