Interessante Frage! Ich habe es gelöst, indem ich die WHERE
Abfrage um eine Reihe von post_title LIKE 'A%' OR post_title LIKE 'B%' ...
Klauseln erweitert habe. Sie können auch einen regulären Ausdruck verwenden, um eine Bereichssuche durchzuführen, aber ich glaube, dass die Datenbank dann keinen Index verwenden kann.
Dies ist der Kern der Lösung: ein Filter für die WHERE
Klausel:
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;
}
Natürlich möchten Sie keine zufälligen externen Eingaben in Ihre Abfrage zulassen. Aus diesem Grund habe ich einen Schritt zur Bereinigung der Eingabe pre_get_posts
, der zwei Abfragevariablen in einen gültigen Bereich konvertiert. (Wenn Sie einen Weg finden, dies zu brechen, hinterlassen Sie bitte einen Kommentar, damit ich ihn korrigieren kann.)
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 ) );
}
}
Der letzte Schritt besteht darin, eine hübsche Umschreiberegel zu erstellen, damit Sie zu allen Posts gehen example.com/posts/a-g/
oder example.com/posts/a
sie sehen können, die mit diesem (Bereich von) Buchstaben beginnen.
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;
}
Sie können das Muster für das Umschreiben von Regeln ändern, um mit etwas anderem zu beginnen. Wenn dies für einen benutzerdefinierten Beitragstyp gilt, müssen Sie &post_type=your_custom_post_type
die Ersetzung hinzufügen (die zweite Zeichenfolge, die mit beginnt index.php
).
Das Hinzufügen von Paginierungslinks bleibt dem Leser als Übung :-)