Paginación personalizada para tipos de publicaciones personalizadas (por nombres)

10

Tengo dos tipos de publicaciones personalizadas que tratan con los nombres de las personas. En este momento, en las vistas de navegación, solo las enumera todas alfabéticamente y la paginación las desglosa por números, lo que no es muy útil cuando intenta encontrar a una persona específica.

Específicamente, me han pedido que cree enlaces de paginación para personas que se ven así:

  • AG
  • HM
  • NQ
  • RQ

Mi problema: no puedo entender cómo puedo consultar los tipos de publicaciones personalizadas por la primera letra de un campo. Entonces, no estoy seguro de cómo puedo crear la paginación de esta manera. ¿Alguien tiene alguna sugerencia? ¡Gracias!

mcleodm3
fuente
Interesante ... Lo intentaré pero no muy pronto. Tengo un espacio libre después de un par de días. Comparta su solución si encuentra algo antes de eso. Solo para comenzar a mirar el filtro posts_where para modificar la búsqueda y hacer la paginación que necesita para jugar con las reglas de reescritura, eche un vistazo a query_vars, query_posts y la clase WP_Rewrite. Estoy seguro de que lo conseguirás con estas cosas.
Hameedullah Khan
@ mckeodm3 ¿Y qué?
Kaiser

Respuestas:

4

¡Interesante pregunta! Lo resolví expandiendo la WHEREconsulta con un montón de post_title LIKE 'A%' OR post_title LIKE 'B%' ...cláusulas. También puede usar una expresión regular para hacer 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 WHEREcláusula:

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 una entrada externa aleatoria en su consulta. Es por eso que tengo un paso de desinfección de entrada pre_get_posts, que convierte dos variables de consulta en un rango válido. (Si encuentra una manera de romper esto, 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 pueda ir example.com/posts/a-g/o example.com/posts/aver todas las publicaciones que comienzan con esta (rango 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;
}

Puede cambiar el patrón de la regla de reescritura para comenzar con otra cosa. Si se trata de un tipo de publicación personalizado, asegúrese de agregar &post_type=your_custom_post_typea la sustitución (la segunda cadena, que comienza con index.php).

Agregar enlaces de paginación se deja como un ejercicio para el lector :-)

Jan Fabry
fuente
Solo una pista: like_escape():)
kaiser
3

Esto te ayudará a comenzar. No sé cómo rompería la consulta en una letra específica y luego le diría a WP que hay otra página con más letras, pero la siguiente toma el 99% del resto.

¡No olvides publicar tu solución!

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;
emperador
fuente
No está probado.
Kaiser
2

Una respuesta usando el ejemplo de @ kaiser, con un tipo de publicación personalizado como una función que acepta los parámetros alfa de inicio y fin. Este ejemplo es obviamente para una lista corta de elementos, ya que no incluye paginación secundaria. Lo estoy publicando para que pueda incorporar el concepto en su functions.phpsi lo desea.

// 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
fuente
1

Aquí hay una manera de hacer esto usando los filtros query_varsy 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
fuente
0

Esto no es tanto una respuesta, sino más bien un puntero a una dirección a seguir. Esto probablemente tendrá que ser 100% personalizado, y estará muy involucrado. Deberá crear una consulta sql personalizada (utilizando las clases wpdb) y luego, para la paginación, pasará estos parámetros a su consulta personalizada. Probablemente también necesite crear nuevas reglas de reescritura para esto. Algunas funciones a considerar:

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