Bagaimana saya bisa membuat halaman pendaratan kategori diikuti oleh halaman posting?

9

Saya mencoba membuat templat kategori di tema saya yang akan menampilkan konten statis jika pengguna ada di halaman pertama arsip, dan kemudian menampilkan tulisan dalam kategori di halaman berikut. Saya pada dasarnya mencoba untuk meniru perilaku kategori di Wired.com di mana http://www.wired.com/category/design adalah halaman arahan sementara / kategori / desain / halaman / 1 menunjukkan daftar kronologis terbalik dari posting seperti Anda harapkan pada arsip kategori.

Kuncinya di sini adalah bahwa saya tidak menampilkan posting apa pun dari arsip kategori pada halaman pertama, jadi saya perlu halaman berikutnya untuk memulai dengan posting pertama. Saya pertama kali mencoba melakukan ini menggunakan offset dan pagination manual dengan mengatur offset query ke 0 jika 'paged' query var adalah 2. Tetapi offset diabaikan ketika diatur ke nol, jadi yang terbaik yang bisa saya lakukan adalah mengatur offset ke 1 dan mulai dengan posting kedua dalam kategori.

Inilah yang saya tambahkan ke 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 );
  }
}

Apa yang akan lebih baik, dan apa yang tampaknya dilakukan Wired , adalah dengan menggunakan pagination default sehingga posting dimulai pada halaman 1, tetapi masukkan halaman 0 untuk konten statis. Hipotetis, ini sepertinya akan mungkin dengan menampilkan konten statis jika 'paged' adalah 0, dan menampilkan halaman pertama posting jika 'paged' adalah 1. Masalahnya adalah 'paged' tidak pernah 1 karena Wordpress menetapkan 'paged 'ke nol ketika pengguna meminta halaman pertama. Itu berarti 'halaman' adalah 0 untuk / kategori / berita / halaman / 1 dan / kategori / berita.

Apakah ada cara untuk memeriksa apakah pengguna meminta / kategori / berita / halaman / 1 yang bertentangan dengan / kategori / berita? Gagal itu, apakah ada cara untuk menampilkan semua posting dalam kategori mulai dari halaman 2?

willcwelch
sumber

Jawaban:

7

Ini adalah pertanyaan yang cukup menarik ( yang telah saya angkat, khususnya untuk pendekatan dan penelitian Anda ). Curveball besar di sini adalah halaman pertama dari kueri:

  • Anda tidak dapat mengatur kueri untuk mengembalikan 0posting di halaman pertama

  • Dengan memindahkan konten halaman dari setiap halaman ke atas oleh satu halaman, Anda akan kehilangan halaman terakhir karena kueri masih akan memiliki jumlah posting yang sama sehingga $max_num_pagesproperti akan tetap sama.

Kita perlu "menipu" WP_Querykelas untuk mengembalikan postingan kita dengan benar dengan offset satu halaman, dan juga mendapatkan jumlah halaman yang benar agar tidak kehilangan halaman terakhir dalam kueri

Mari kita lihat ide berikut dan mencoba untuk memasukkan semuanya ke dalam kode. Sebelum kita melakukannya, saya ingin membuat beberapa catatan di sini

CATATAN PENTING:

  • Semuanya belum teruji, jadi mungkin buggy. Pastikan untuk menguji ini secara lokal dengan debug dihidupkan

  • Kode membutuhkan setidaknya PHP 5.3, versi di bawah 5.3 akan menyebabkan kesalahan fatal. Catatan, jika masih menggunakan versi apa pun di bawah PHP 5.5, Anda seharusnya sudah meningkatkan versi lama

  • Ubah dan penyalahgunaan kode sesuai keinginan Anda

IDE LIGHTBULB:

APA YANG KAMI BUTUHKAN

Untuk membuat semuanya berfungsi, kita perlu yang berikut:

  • Nomor halaman saat ini sedang dilihat

  • The posts_per_pageset pilihan dalam pengaturan membaca

  • Adat offset

  • Ubah $found_postsproperti kueri untuk memperbaiki $max_num_pagesproperti

Pagination WP_Queryditurunkan beberapa baris kode yang sangat sederhana

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'];
}

Apa yang pada dasarnya terjadi, setelah offset diatur secara eksplisit, pagedparameter diabaikan. Parameter pertama LIMITklausa SQL dihitung ulang dari offset dan akan menjadi jumlah posting yang dilewati dalam query SQL yang dihasilkan.

Dari pertanyaan Anda, tampaknya saat menyetel offsetke 0, kueri offset gagal, yang aneh, karena pemeriksaan berikut akan mengembalikan true

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

0adalah angka yang valid dan harus mengembalikan true. Jika ini tidak pada instalasi Anda, Anda harus men-debug masalah tersebut

Untuk kembali ke masalah yang ada, kami akan menggunakan jenis logika yang sama untuk menghitung dan mengatur offset kami untuk mendapatkan pos 1 di halaman 2 dan dari sana paginate permintaan. Untuk halaman pertama, kami tidak akan mengubah apa pun, sehingga postingan yang seharusnya berada di halaman 1 masih akan di halaman seperti biasa, kami hanya perlu "menyembunyikan" mereka nanti sehingga kami tidak menampilkannya di halaman 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 );
        }
    }
});

Anda harus melihat posting yang sama dari halaman 1 di halaman 2. Seperti yang saya katakan sebelumnya, jika ini tidak terjadi, salah satu is_numeric( 0 )akan kembali salah ( yang seharusnya tidak ) atau Anda memiliki pre_get_poststindakan lain yang juga mencoba untuk mengatur offset atau Anda menggunakan penggunaan posts_*filter klausa ( lebih khusus, post_limitsfilter ). Ini akan menjadi sesuatu yang perlu Anda debug sendiri.

Masalah berikutnya adalah memperbaiki pagination, karena seperti yang saya katakan sebelumnya, Anda akan kekurangan halaman. Untuk ini, kita perlu menambahkan nilai get_option( 'posts_per_page' )ke jumlah posting yang ditemukan dalam permintaan karena kita mengimbangi permintaan dengan jumlah itu. dengan melakukan hal ini, kita secara efektif menambahkan 1ke $max_num_pagesproperti.

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 );

Ini harus mengurutkan semuanya, kecuali halaman pertama.

SEMUA BERSAMA SEKARANG ( dan khusus untuk @ialocin - Kapal Selam Kuning )

Ini semua harus masuk 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 );

OPSI HALAMAN PERTAMA

Ada beberapa opsi di sini:

PILIHAN 1

Saya kemungkinan besar akan memilih opsi ini. Apa yang ingin Anda lakukan di sini adalah membuat category-news.php( jika Anda belum melakukan ini ). Ini akan menjadi templat yang akan digunakan setiap kali newskategori dilihat. Template ini akan sangat sederhana

Contoh

<?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();

Seperti yang Anda lihat, saya telah menyertakan dua bagian templat, news-special.phpdan news-loop.php. Sekarang, dasar-dasar kedua templat khusus adalah:

  • news-special.php-> Bagian templat ini akan menjadi apa pun yang ingin Anda tampilkan di halaman pertama. Tambahkan semua info statis khusus Anda di sini. Berhati-hatilah untuk tidak memanggil loop dalam template ini karena ini akan menampilkan posting dari halaman pertama.

  • news-loop.php-> Ini adalah templat di mana kita akan mengaktifkan perulangan. Bagian ini akan terlihat seperti ini:

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

PILIHAN 2

Buat templat terpisah dengan konten statis Anda dan cukup gunakan category_templatefilter untuk menggunakan templat ini ketika kami melihat halaman pertama dari newskategori tersebut. Juga, pastikan untuk tidak mengaktifkan loop default di template ini. Juga, pastikan bahwa konvensi penamaan Anda di sini tidak bertabrakan dengan nama templat di dalam hierarki templat

Saya harap ini bermanfaat. Jangan ragu untuk meninggalkan komentar dengan keprihatinan

EDIT

Berkat OP, ada bug yang pasti di WP_Querykelas, periksa tiket trac # 34060 . Kode yang saya posting adalah dari Wordpress v4.4, dan bug diperbaiki pada versi ini.

Saya kembali ke kode sumber v4.3, di mana bug itu berada, dan saya dapat mengonfirmasi bahwa 0diabaikan ketika ditetapkan sebagai nilai offsetkarena kode hanya memeriksa apakah offsetparameternya empty. 0diambil sebagai kosong di PHP. Saya tidak yakin apakah perilaku ini (bug) hanya ditemukan di v4.3 saja atau di semua versi sebelumnya (sesuai tiket, bug ini ada di v4.3), tetapi ada tambalan untuk bug ini yang dapat Anda periksa di tiket trac. Seperti yang saya katakan, bug ini sudah pasti diperbaiki di v4.4

Pieter Goosen
sumber
2
Terima kasih atas jawaban terinci Anda. Ini sebenarnya cukup banyak apa yang saya terapkan dalam upaya pertama saya. Masalahnya adalah pengaturan 'offset' ke 0 tidak berfungsi. Ternyata itu sebenarnya bug di WordPress Core core.trac.wordpress.org/ticket/34060 . Menambal itu membuat semuanya berfungsi. Satu-satunya kode Anda yang hilang adalah return $found_posts;setelah pernyataan if dalam tindakan found_posts. Terima kasih!
willcwelch
Terima kasih atas umpan balik positif Anda. Saya kembali ke kode sumber versi 4.3 query.php, dan ya, 0akan diabaikan karena cek di sini kosong, dan 0dianggap kosong. Kode dalam jawaban saya adalah kode pembaruan yang dikirimkan bersama v4.4, jadi saya dapat mengonfirmasi bahwa bug diperbaiki pada 4.4. Saya akan memperbarui jawaban saya sesuai. Pada found_postsmasalah ini, tangkapan yang baik, itu sebenarnya adalah filter dan harus dikembalikan. Selamat Menikmati
Pieter Goosen
haha, terima kasih :) dan untuk semua yang bertanya-tanya mengapa ... satu, dua, tiga, empat, dapatkah saya memiliki sedikit lagi ... tautan sebenarnya ke lagu semuanya sekarang
Nicolai
@ialocin hahaha, saya akan ingat yang ini ;-)
Pieter Goosen
1
itu sangat menarik :) tapi tidak heran, karena itu cukup banyak ditulis seperti lagu anak-anak
Nicolai
0

Memperbarui:

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);
}

Coba beberapa hal seperti

$paged = ( get_query_var('paged') ) ? get_query_var('paged')-1 : 1;
$args = array (
    'paged' => $paged,
);
Kika
sumber
Saya telah mengoreksi penjelasan saya untuk cara kerja variabel 'paged'. Sepertinya apa yang Anda coba lakukan adalah menurunkan setiap nomor halaman dengan 1, jadi permintaan untuk halaman 2 memberi Anda halaman 1. Masalahnya adalah ketika halaman 1 dipertanyakan, 'paged' diatur ke 0. Juga, get_query_var () harus digunakan sebagai ganti get_option untuk 'halaman'. Dengan perbaikan itu, saat ini berjalan, setiap kali kueri diubah, loop lagi sampai 'halaman' adalah 0 untuk permintaan halaman apa pun.
willcwelch