¿Se pueden ordenar los enlaces Siguiente / Anterior Publicación por orden de menú o por una meta clave?

30

Tengo una serie de publicaciones ordenadas por un valor de meta_key. También se pueden organizar por orden de menú, si es necesario.

Los enlaces de publicación anterior / siguiente (generados por next_post_link , previous_post_link o posts_nav_link navegan por cronología. Aunque entiendo este comportamiento predeterminado, no entiendo cómo cambiarlo. se correlaciona con el enlace_post_link adyacente en link-template.php, pero luego comienza a parecer bastante rígido. ¿Se recomienda volver a escribir esto desde cero para reemplazarlo o hay una solución mejor?

    
pregunta Jodi Warren 19.11.2012 - 18:23

7 respuestas

27

Entendiendo los aspectos internos

El orden de "clasificación" de las publicaciones adyacentes (siguiente / anterior) no es realmente un "orden de clasificación". Es una consulta separada en cada solicitud / página, pero ordena la consulta por el post_date , o el padre de la publicación si tiene una publicación jerárquica como objeto actualmente mostrado.

Cuando echa un vistazo a las partes internas de next_post_link() , verá que es básicamente un contenedor de API para < a href="http://queryposts.com/function/adjacent_post_link/"> adjacent_post_link() . La función más reciente llama a get_adjacent_post() internamente con el argumento / flag $previous establecido en bool(true|false) para capturar el siguiente o el anterior publicar enlace.

¿Qué filtrar?

Después de profundizar en él, verás que get_adjacent_post() Enlace de origen tiene algunos filtros agradables para su salida (también conocido como resultado de la consulta): (Nombre / Argumentos del filtro)

  • "get_{$adjacent}_post_join"

    $join
    // Only if '$in_same_cat'
    // or: ! empty( $excluded_categories' 
    // and then: 
    // " INNER JOIN $wpdb->term_relationships AS tr 
    //     ON p.ID = tr.object_id 
    // INNER JOIN $wpdb->term_taxonomy tt 
    //     ON tr.term_taxonomy_id = tt.term_taxonomy_id"; 
    // and if $in_same_cat then it APPENDS: 
    // " AND tt.taxonomy = 'category' 
    // AND tt.term_id IN (" . implode(',', $cat_array) . ")";
    $in_same_cat
    $excluded_categories
    
  • "get_{$adjacent}_post_where"

    $wpdb->prepare(
          // $op = $previous ? '<' : '>'; | $current_post_date
           "WHERE p.post_date $op %s "
          // $post->post_type
          ."AND p.post_type = %s "
          // $posts_in_ex_cats_sql = " AND tt.taxonomy = 'category' 
          // AND tt.term_id NOT IN (" . implode($excluded_categories, ',') . ')'; 
          // OR empty string if $in_same_cat || ! empty( $excluded_categories
          ."AND p.post_status = 'publish' $posts_in_ex_cats_sql "
        ",
        $current_post_date,
        $post->post_type
    )
    $in_same_cat
    $excluded_categories
    
  • "get_{$adjacent}_post_sort"

    "ORDER BY p.post_date $order LIMIT 1"'
    

Así que puedes hacer mucho con él. Esto comienza con el filtrado de la cláusula WHERE , así como la tabla JOIN ed y la declaración ORDER BY .

El resultado se almacena en la memoria caché para la solicitud actual, por lo que no agrega consultas adicionales si llama a esa función varias veces en una sola página.

Creación automática de consultas

Como @StephenHarris en los comentarios, hay una función central que puede ser útil cuando construyendo la consulta SQL: get_meta_sql() - Ejemplos en Codex . Básicamente, esta función solo se usa para generar la sentencia meta SQL que se usa en WP_Query , pero también puede usarla en este caso (u otros). El argumento que le lanzas es una matriz, exactamente la misma que se agregaría a un WP_Query .

$meta_sql = get_meta_sql(
    $meta_query,
    'post',
    $wpdb->posts,
    'ID'
);

El valor de retorno es una matriz:

$sql => (array) 'join' => array(),
        (array) 'where' => array()

Para que pueda usar $sql['join'] y $sql['where'] en su devolución de llamada.

Dependencias a tener en cuenta

En su caso, lo más fácil sería interceptarlo en un pequeño plugin (mu) o en su archivo de funciones functions.php de temas y modificarlo según la variable $adjacent = $previous ? 'previous' : 'next'; y la variable $order = $previous ? 'DESC' : 'ASC'; :

Los nombres de filtro reales

Los nombres de los filtros son:

  • get_previous_post_join , get_next_post_join
  • get_previous_post_where , get_next_post_where
  • get_previous_post_sort , get_next_post_sort

Envuelto como un complemento

... y la devolución de llamada del filtro sería (por ejemplo) algo como lo siguiente:

<?php
/** Plugin Name: (#73190) Alter adjacent post link sort order */
function wpse73190_adjacent_post_sort( $orderby )
{
    return "ORDER BY p.menu_order DESC LIMIT 1";
}
add_filter( 'get_previous_post_sort', 'wpse73190_adjacent_post_sort' );
add_filter( 'get_next_post_sort', 'wpse73190_adjacent_post_sort' );
    
respondido por el kaiser 19.11.2012 - 18:40
18

La respuesta de Kaiser es impresionante y exhaustiva, sin embargo, solo cambiar la cláusula ORDER BY no es suficiente a menos que su menu_order coincide con su orden cronológico.

No puedo tomar crédito por esto, pero encontré el siguiente código en this gist :

<?php
/**
 * Customize Adjacent Post Link Order
 */
function wpse73190_gist_adjacent_post_where($sql) {
  if ( !is_main_query() || !is_singular() )
    return $sql;

  $the_post = get_post( get_the_ID() );
  $patterns = array();
  $patterns[] = '/post_date/';
  $patterns[] = '/\'[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\'/';
  $replacements = array();
  $replacements[] = 'menu_order';
  $replacements[] = $the_post->menu_order;
  return preg_replace( $patterns, $replacements, $sql );
}
add_filter( 'get_next_post_where', 'wpse73190_gist_adjacent_post_where' );
add_filter( 'get_previous_post_where', 'wpse73190_gist_adjacent_post_where' );

function wpse73190_gist_adjacent_post_sort($sql) {
  if ( !is_main_query() || !is_singular() )
    return $sql;

  $pattern = '/post_date/';
  $replacement = 'menu_order';
  return preg_replace( $pattern, $replacement, $sql );
}
add_filter( 'get_next_post_sort', 'wpse73190_gist_adjacent_post_sort' );
add_filter( 'get_previous_post_sort', 'wpse73190_gist_adjacent_post_sort' );

He modificado los nombres de funciones para WP.SE.

Si solo cambia la cláusula ORDER BY, la consulta aún busca publicaciones mayores o menores que la fecha de publicación actual. Si tus publicaciones no están en orden cronológico, no obtendrás la publicación correcta.

Esto cambia la cláusula where para buscar publicaciones donde menu_order sea mayor o menor que menu_order de la publicación actual, además de modificar la cláusula order by.

La cláusula orderby tampoco debe tener un código fijo para usar DESC, ya que tendrá que cambiar en función de si está obteniendo el enlace de la publicación siguiente o anterior.

    
respondido por el jjeaton 16.04.2013 - 05:18
4
function wpse73190_gist_adjacent_post_sort( $sql ) {
    $pattern = '/post_date/';
    $replacement = 'menu_order';

    return preg_replace( $pattern, $replacement, $sql );
}

add_filter( 'get_next_post_sort', 'wpse73190_gist_adjacent_post_sort' );
add_filter( 'get_previous_post_sort', 'wpse73190_gist_adjacent_post_sort' );
    
respondido por el Micheal Jess 20.06.2013 - 07:00
2

Intenté engancharme sin éxito. Podría ser solo un problema de mi configuración, pero para aquellos que no pueden hacer que el enlace funcione, aquí está la solución más simple:

<?php
    $all_posts = new WP_Query(array(
        'orderby' => 'menu_order',
        'order' => 'ASC',
        'posts_per_page' => -1
    ));

    foreach($all_posts->posts as $key => $value) {
        if($value->ID == $post->ID){
            $nextID = $all_posts->posts[$key + 1]->ID;
            $prevID = $all_posts->posts[$key - 1]->ID;
            break;
        }
    }
?>
<?php if($prevID): ?>
    <span class="prev">
        <a href="<?= get_the_permalink($prevID) ?>" rel="prev"><?= get_the_title($prevID) ?></a>
    </span>
<?php endif; ?>
<?php if($nextID): ?>
    <span class="next">
        <a href="<?= get_the_permalink($nextID) ?>" rel="next"><?= get_the_title($nextID) ?></a>
    </span>
<?php endif; ?>
    
respondido por el Szabolcs Páll 26.10.2017 - 12:38
0

Me parece muy útil este pequeño complemento: enlace

  

WP_Query Powered Adjacent Post Link es un complemento para desarrolladores. Agrega la función wpqpapl(); a WordPress, que puede devolver información sobre la publicación anterior y la siguiente a la actual. Acepta argumentos para su uso en la clase WP_Query .

    
respondido por el any_h 26.11.2013 - 19:17
0

Esto me funcionó:

add_filter( 'get_previous_post_where', 'so16495117_mod_adjacent_bis' );
add_filter( 'get_next_post_where', 'so16495117_mod_adjacent_bis' );
function so16495117_mod_adjacent_bis( $where ) {
    global $wpdb;
    return $where . " AND p.ID NOT IN ( SELECT post_id FROM $wpdb->postmeta WHERE ($wpdb->postmeta.post_id = p.ID ) AND $wpdb->postmeta.meta_key = 'archive' AND $wpdb->postmeta.meta_value = 1 )";
}

Tomado de: enlace

    
respondido por el Philip 12.03.2015 - 15:22
-1

He encontrado una forma mucho más fácil de lograr una navegación posterior basada en meta-clave, sin la necesidad de modificar functions.php.

Mi ejemplo: tienes products.php y quieres cambiar entre productos. El producto anterior es el siguiente más barato, el siguiente producto el más caro.

Aquí viene mi solución para single.php :

<div class="post_navigation">

<?php

// Prepare loop
$args = (
'post_type' => 'products',
'post_status' => 'publish',
'meta_key' => 'price',
'orderby' => 'meta_value_num',
'order' => 'ASC',
'posts_per_page' => -1
);
query_posts($args);

// Initialize array in which the IDs of ALL products posts will be stored
$posts = array();

// ... and now let's start the loop
while ( have_posts() ) : the_post();
$posts[] += $post->ID;
endwhile;

// Reset Query
wp_reset_query();

// Identify the position of the current product within the $posts-array 
$current = array_search(get_the_ID(), $posts);

// Identify ID of previous product
$prevID = $posts[$current-1];

// Identify ID of next product
$nextID = $posts[$current+1];

// Link "previous product"
if (!empty($prevID)) { ?>
<a href="/?p=<?php echo $prevID; ?>">previous product</a>
<?php }
// Link "next product"
if (!empty($nextID)) { ?>
<a href="/?p=<?php echo $nextID; ?>">next product</a>

<?php } ?>
    
respondido por el Kent Miller 21.05.2014 - 10:25

Lea otras preguntas en las etiquetas