Pagination personnalisée pour les types de publication personnalisés (par noms)

10

J'ai deux types de messages personnalisés qui traitent des noms de personnes. À l'heure actuelle, 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:

  • AG
  • HM
  • NQ
  • RQ

Mon problème - je ne peux pas comprendre comment je peux interroger les types de messages 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!

mcleodm3
la source
Intéressant .. Je vais lui donner un coup mais pas très bientôt. J'ai une place libre après quelques jours. Partagez votre solution si vous trouvez quelque chose avant cela. Juste pour commencer à regarder le filtre posts_where pour modifier la recherche et pour faire la pagination dont vous avez besoin pour jouer avec les règles de réécriture, jetez un œil à query_vars, query_posts et WP_Rewrite class. Je suis sûr que vous le clouerez avec ces choses.
Hameedullah Khan
@ mckeodm3 Alors quoi ??
kaiser

Réponses:

4

Question interessante! Je l'ai résolu en développant la WHERErequê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 WHEREclause:

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/avoir 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 :-)

Jan Fabry
la source
Juste un indice: like_escape():)
kaiser
3

Cela vous aidera à démarrer. Je ne sais pas comment vous briseriez la requête à une lettre spécifique, puis diriez à WP qu'il y a une autre page avec plus de lettres, mais ce qui suit 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;
kaiser
la source
Ce n'est pas testé.
kaiser
2

Une réponse en utilisant l'exemple de @ kaiser, avec un type de message personnalisé en tant que fonction acceptant les paramètres alpha de début et de fin. Cet exemple concerne évidemment une courte liste d'éléments, car il n'inclut pas la pagination secondaire. Je le poste pour que vous puissiez intégrer le concept dans votre functions.phpsi 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;
    }
}
Tyrus
la source
1

Voici une façon de le faire en utilisant les filtres query_varset 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') );

Souce: https://gist.github.com/3904986

Styledev
la source
0

Ce n'est pas tant une réponse, mais plutôt un pointeur vers une direction à prendre. Cela devra probablement être 100% personnalisé - et sera très impliqué. Vous devrez créer une requête SQL personnalisée (à l'aide des classes wpdb), puis pour la pagination, vous passerez ces paramètres à votre requête personnalisée. Vous devrez probablement également créer de nouvelles règles de réécriture pour cela. Quelques fonctions à étudier:

add_rewrite_tag( '%byletter%', '([^/]+)');
add_permastruct( 'byletter', 'byletter' . '/%byletter%' );
$wp_rewrite->flush_rules();
paginate_links()
dwenaus
la source