¡Interesante pregunta! Lo resolví expandiendo la WHERE
consulta con un montón de post_title LIKE 'A%' OR post_title LIKE 'B%' ...
cláusulas. También puede usar una expresión regular para hacer una búsqueda de rango, pero creo que la base de datos no podrá usar un índice en ese momento.
Este es el núcleo de la solución: un filtro en la WHERE
cláusula:
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;
}
Por supuesto, no desea permitir una entrada externa aleatoria en su consulta. Es por eso que tengo un paso de desinfección de entrada pre_get_posts
, que convierte dos variables de consulta en un rango válido. (Si encuentra una manera de romper esto, deje un comentario para que pueda corregirlo)
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 ) );
}
}
El paso final es crear una regla de reescritura bonita para que pueda ir example.com/posts/a-g/
o example.com/posts/a
ver todas las publicaciones que comienzan con esta (rango de) letra (s).
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;
}
Puede cambiar el patrón de la regla de reescritura para comenzar con otra cosa. Si se trata de un tipo de publicación personalizado, asegúrese de agregar &post_type=your_custom_post_type
a la sustitución (la segunda cadena, que comienza con index.php
).
Agregar enlaces de paginación se deja como un ejercicio para el lector :-)