Pregunta interesante! Lo resolví expandiendo la consulta WHERE
con un grupo de cláusulas post_title LIKE 'A%' OR post_title LIKE 'B%' ...
. También puede usar una expresión regular para realizar 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 cláusula WHERE
:
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 entradas externas aleatorias en su consulta. Es por eso que tengo un paso de desinfección de entrada en pre_get_posts
, que convierte dos variables de consulta en un rango válido. (Si encuentra una manera de romper esto, por favor 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 puedas ir a example.com/posts/a-g/
o example.com/posts/a
para ver todas las publicaciones que comiencen con esta (gama 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;
}
Puedes cambiar el patrón de regla de reescritura para comenzar con otra cosa. Si esto es para un tipo de publicación personalizada, asegúrate de agregar &post_type=your_custom_post_type
a la sustitución (la segunda cadena, que comienza con index.php
).
La adición de enlaces de paginación se deja como un ejercicio para el lector :-)