J'ai deux types de messages personnalisés qui traitent des noms de personnes. Pour le moment, dans les vues de navigation, il les répertorie simplement par ordre alphabétique et la pagination les décompose en chiffres, ce qui n’est pas très utile lorsque vous essayez de trouver une personne spécifique.
Plus précisément, on m'a demandé de créer des liens de pagination pour les personnes qui ressemblent à ceci:
Mon problème - Je ne vois pas comment interroger les types de publication personnalisés par la première lettre d'un champ. Ensuite, je ne sais pas comment je peux créer la pagination de cette façon. Quelqu'un a-t'il des suggestions? Je vous remercie!
Question interessante! Je l'ai résolu en développant la requête WHERE
avec un tas de clauses post_title LIKE 'A%' OR post_title LIKE 'B%' ...
. 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 clause 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;
}
Bien entendu, vous ne souhaitez pas autoriser la saisie externe aléatoire dans votre requête. C'est pourquoi j'ai une étape de désinfection d'entrée sur pre_get_posts
, qui convertit deux variables de requête en une plage valide. (Si vous trouvez un moyen de résoudre ce problème, laissez un commentaire pour 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 aller à example.com/posts/a-g/
ou example.com/posts/a
pour voir toutes les publications 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é, veillez à ajouter &post_type=your_custom_post_type
à la substitution (la deuxième chaîne, qui commence par index.php
).
Ajouter des liens de pagination reste un exercice pour le lecteur :-)
Cela vous aidera à démarrer. Je ne sais pas comment vous pourriez casser la requête avec une lettre spécifique, puis dire à WP qu'il existe une autre page comportant davantage de lettres, mais la suivante prend 99% du reste.
N'oubliez pas de poster votre solution!
query_posts( array( 'orderby' => 'title' ) );
// Build an alphabet array
foreach( range( 'A', 'G' ) as $letter )
$alphabet[] = $letter;
foreach( range( 'H', 'M' ) as $letter )
$alphabet[] = $letter;
foreach( range( 'N', 'Q' ) as $letter )
$alphabet[] = $letter;
foreach( range( 'R', 'Z' ) as $letter )
$alphabet[] = $letter;
if ( have_posts() )
{
while ( have_posts() )
{
global $wp_query, $post;
$max_paged = $wp_query->query_vars['max_num_pages'];
$paged = $wp_query->query_vars['paged'];
if ( ! $paged )
$paged = (int) 1;
the_post();
$first_title_letter = (string) substr( $post->post_title, 1 );
if ( in_array( $first_title_letter, $alphabet ) )
{
// DO STUFF
}
// Pagination
if ( $paged !== (int) 1 )
{
echo 'First: '._wp_link_page( 1 );
echo 'Prev: '._wp_link_page( $paged - 1 );
}
while ( $i = 1; count($alphabet) < $max_paged; i++; )
{
echo $i._wp_link_page( $i );
}
if ( $paged !== $max_paged )
{
echo 'Next: '._wp_link_page( $paged + 1 );
echo 'Last: '._wp_link_page( $max_paged );
}
} // endwhile;
} // endif;
Une réponse utilisant l'exemple de @ kaiser, avec un type d'article personnalisé en tant que fonction acceptant les paramètres de début et de fin alpha. Cet exemple concerne évidemment une courte liste d'éléments, car il n'inclut pas la pagination secondaire. Je le poste afin que vous puissiez incorporer le concept dans votre functions.php
si vous le souhaitez.
// Dr Alpha Paging
// Tyrus Christiana, Senior Developer, BFGInteractive.com
// Call like alphaPageDr( "A","d" );
function alphaPageDr( $start, $end ) {
echo "Alpha Start";
$loop = new WP_Query( 'post_type=physician&orderby=title&order=asc' );
// Build an alphabet array of capitalized letters from params
foreach ( range( $start, $end ) as $letter )
$alphabet[] = strtoupper( $letter );
if ( $loop->have_posts() ) {
echo "Has Posts";
while ( $loop->have_posts() ) : $loop->the_post();
// Filter by the first letter of the last name
$first_last_name_letter = ( string ) substr( get_field( "last_name" ), 0, 1 );
if ( in_array( $first_last_name_letter, $alphabet ) ) {
//Show things
echo "<img class='sidebar_main_thumb' src= '" .
get_field( "thumbnail" ) . "' />";
echo "<div class='sidesbar_dr_name'>" .
get_field( "salutation" ) . " " .
get_field( 'first_name' ) . " " .
get_field( 'last_name' ) . "</div>";
echo "<div class='sidesbar_primary_specialty ' > Primary Specialty : " .
get_field( "primary_specialty" ) . "</div>";
}
endwhile;
}
}
Voici un moyen de le faire en utilisant les filtres query_vars
et posts_where
:
public function range_add($aVars) {
$aVars[] = "range";
return $aVars;
}
public function range_where( $where, $args ) {
if( !is_admin() ) {
$range = ( isset($args->query_vars['range']) ? $args->query_vars['range'] : false );
if( $range ) {
$range = split(',',$range);
$where .= "AND LEFT(wp_posts.post_title,1) BETWEEN '$range[0]' AND '$range[1]'";
}
}
return $where;
}
add_filter( 'query_vars', array('atk','range_add') );
add_filter( 'posts_where' , array('atk','range_where') );
Source: https://Gist.github.com/3904986
Ce n’est pas vraiment une réponse, mais plutôt un indicateur d’une direction à prendre. Cela devra probablement être 100% personnalisé - et sera très impliqué. Vous devez créer une requête SQL personnalisée (à l'aide des classes wpdb), puis, pour la pagination, transmettre ces paramètres à votre requête personnalisée. Vous devrez probablement également créer de nouvelles règles de réécriture pour cela également. Quelques fonctions à examiner:
add_rewrite_tag( '%byletter%', '([^/]+)');
add_permastruct( 'byletter', 'byletter' . '/%byletter%' );
$wp_rewrite->flush_rules();
paginate_links()