Câu hỏi thú vị! Tôi đã giải quyết nó bằng cách mở rộng WHERE
truy vấn bằng một loạt các post_title LIKE 'A%' OR post_title LIKE 'B%' ...
mệnh đề. Bạn cũng có thể sử dụng biểu thức chính quy để thực hiện tìm kiếm phạm vi, nhưng tôi tin rằng cơ sở dữ liệu sẽ không thể sử dụng một chỉ mục sau đó.
Đây là cốt lõi của giải pháp: một bộ lọc về WHERE
mệnh đề:
add_filter( 'posts_where', 'wpse18703_posts_where', 10, 2 );
function wpse18703_posts_where( $where, &$wp_query )
{
if ( $letter_range = $wp_query->get( 'wpse18703_range' ) ) {
global $wpdb;
$letter_clauses = array();
foreach ( $letter_range as $letter ) {
$letter_clauses[] = $wpdb->posts. '.post_title LIKE \'' . $letter . '%\'';
}
$where .= ' AND (' . implode( ' OR ', $letter_clauses ) . ') ';
}
return $where;
}
Tất nhiên bạn không muốn cho phép đầu vào bên ngoài ngẫu nhiên trong truy vấn của mình. Đó là lý do tại sao tôi có một bước khử trùng đầu vào pre_get_posts
, trong đó chuyển đổi hai biến truy vấn thành một phạm vi hợp lệ. (Nếu bạn tìm được cách phá vỡ điều này, vui lòng để lại nhận xét để tôi có thể sửa nó)
add_action( 'pre_get_posts', 'wpse18703_pre_get_posts' );
function wpse18703_pre_get_posts( &$wp_query )
{
// Sanitize input
$first_letter = $wp_query->get( 'wpse18725_first_letter' );
$last_letter = $wp_query->get( 'wpse18725_last_letter' );
if ( $first_letter || $last_letter ) {
$first_letter = substr( strtoupper( $first_letter ), 0, 1 );
$last_letter = substr( strtoupper( $last_letter ), 0, 1 );
// Make sure the letters are valid
// If only one letter is valid use only that letter, not a range
if ( ! ( 'A' <= $first_letter && $first_letter <= 'Z' ) ) {
$first_letter = $last_letter;
}
if ( ! ( 'A' <= $last_letter && $last_letter <= 'Z' ) ) {
if ( $first_letter == $last_letter ) {
// None of the letters are valid, don't do a range query
return;
}
$last_letter = $first_letter;
}
$wp_query->set( 'posts_per_page', -1 );
$wp_query->set( 'wpse18703_range', range( $first_letter, $last_letter ) );
}
}
Bước cuối cùng là tạo một quy tắc viết lại khá đẹp để bạn có thể đi đến example.com/posts/a-g/
hoặc example.com/posts/a
xem tất cả các bài đăng bắt đầu bằng (phạm vi) chữ cái này.
add_action( 'init', 'wpse18725_init' );
function wpse18725_init()
{
add_rewrite_rule( 'posts/(\w)(-(\w))?/?', 'index.php?wpse18725_first_letter=$matches[1]&wpse18725_last_letter=$matches[3]', 'top' );
}
add_filter( 'query_vars', 'wpse18725_query_vars' );
function wpse18725_query_vars( $query_vars )
{
$query_vars[] = 'wpse18725_first_letter';
$query_vars[] = 'wpse18725_last_letter';
return $query_vars;
}
Bạn có thể thay đổi mẫu quy tắc viết lại để bắt đầu với một cái gì đó khác. Nếu đây là loại bài đăng tùy chỉnh, hãy chắc chắn để thêm &post_type=your_custom_post_type
vào thay thế (chuỗi thứ hai, bắt đầu bằng index.php
).
Thêm liên kết phân trang được để lại như một bài tập cho người đọc :-)