Question interessante! Je l'ai résolu en développant la WHERE
requête avec un tas de post_title LIKE 'A%' OR post_title LIKE 'B%' ...
clauses. Vous pouvez également utiliser une expression régulière pour effectuer une recherche par plage, mais je pense que la base de données ne pourra alors pas utiliser d'index.
C'est le cœur de la solution: un filtre sur la WHERE
clause:
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;
}
Bien sûr, vous ne voulez pas autoriser une entrée externe aléatoire dans votre requête. C'est pourquoi j'ai une étape de nettoyage d'entrée pre_get_posts
, qui convertit deux variables de requête en une plage valide. (Si vous trouvez un moyen de briser cela, veuillez laisser un commentaire afin que je puisse le corriger)
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 ) );
}
}
La dernière étape consiste à créer une jolie règle de réécriture afin que vous puissiez accéder à example.com/posts/a-g/
ou example.com/posts/a
voir tous les messages commençant par cette (plage de) lettre (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;
}
Vous pouvez modifier le modèle de règle de réécriture pour commencer par autre chose. S'il s'agit d'un type de publication personnalisé, assurez-vous d'ajouter &post_type=your_custom_post_type
à la substitution (la deuxième chaîne, qui commence par index.php
).
L'ajout de liens de pagination est laissé comme exercice au lecteur :-)