Os links Next / Prev Post podem ser ordenados por ordem de menu ou por uma meta key?

30

Eu tenho uma série de postagens ordenadas por um valor meta_key. Eles também podem ser organizados por ordem de menu, se necessário.

Os links de postagem próximos / anteriores (gerados por next_post_link , previous_post_link ou posts_nav_link navegam por cronologia. Embora eu entenda esse comportamento padrão, não entendo como alterá-lo. Descobri que mapeia até o adjacente_post_link no link-template.php, mas depois ele começa a parecer bastante codificado. É recomendável reescrevê-lo do zero para substituí-lo ou há uma solução melhor.

    
por Jodi Warren 19.11.2012 / 18:23
fonte

7 respostas

27

Entendendo os internos

A ordem de "classificação" de posts adjacentes (next / prev) não é realmente uma espécie de "ordem". É uma consulta separada em cada solicitação / página, mas classifica a consulta pelo post_date - ou pelo pai do post se você tiver uma postagem hierárquica como o objeto atualmente exibido.

Quando você dá uma olhada nos componentes internos de next_post_link() , você vê que é basicamente um wrapper de API para < href="http://queryposts.com/function/adjacent_post_link/"> adjacent_post_link() . A função posterior chama get_adjacent_post() internamente com o argumento $previous / flag definido como bool(true|false) para capturar o próximo ou o anterior postar link.

O que filtrar?

Depois de aprofundar, você verá que get_adjacent_post() Link de origem tem alguns bons filtros para sua saída (também conhecido como resultado da consulta): (Nome do filtro / Argumentos)

  • "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"'
    

Então você pode fazer muito com ele. Isso começa com a filtragem da cláusula WHERE , assim como a tabela JOIN ed e a declaração ORDER BY .

O resultado é armazenado em cache na memória para a solicitação atual, portanto, não adiciona consultas adicionais se você chamar essa função várias vezes em uma única página.

Criação automática de consultas

Como @StephenHarris apontou nos comentários, há uma função central que pode ser útil quando construindo a Consulta SQL: get_meta_sql() - Exemplos no Codex . Basicamente, essa função é usada apenas para construir a instrução meta SQL que é usada em WP_Query , mas você pode usá-la nesse caso (ou em outros) também. O argumento que você joga nele é uma matriz, exatamente a mesma que seria adicionada a um WP_Query .

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

O valor de retorno é uma matriz:

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

Você pode usar $sql['join'] e $sql['where'] no seu retorno de chamada.

Dependências a serem lembradas

No seu caso, o mais fácil seria interceptá-lo em um pequeno plugin (mu) ou no arquivo functions.php de seus temas e alterá-lo dependendo da variável $adjacent = $previous ? 'previous' : 'next'; e da variável $order = $previous ? 'DESC' : 'ASC'; :

Os nomes dos filtros reais

Assim, os nomes dos filtros são:

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

Enrolado como um plugin

... e o retorno de chamada do filtro seria (por exemplo) algo como o seguinte:

<?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' );
    
por kaiser 19.11.2012 / 18:40
fonte
18

A resposta do Kaiser é impressionante e completa, no entanto, apenas alterar a cláusula ORDER BY não é suficiente, a menos que o seu menu_order corresponde a sua ordem cronológica.

Não posso receber crédito por isso, mas encontrei o seguinte código em esta essência :

<?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' );

Eu modifiquei os nomes das funções para o WP.SE.

Se você alterar apenas a cláusula ORDER BY, a consulta ainda procurará postagens maiores ou menores que a data da postagem atual. Se suas postagens não estiverem em ordem cronológica, você não receberá a postagem correta.

Isto muda a cláusula where para procurar posts onde o menu_order é maior ou menor que o menu_order do post atual, além de modificar a cláusula orderby.

A cláusula orderby também não deve ser codificada para usar o DESC, pois será necessário alternar se você está obtendo o próximo ou o anterior link de postagem.

    
por jjeaton 16.04.2013 / 05:18
fonte
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' );
    
por Micheal Jess 20.06.2013 / 07:00
fonte
2

Tentei entrar sem sucesso. Pode ser apenas um problema da minha configuração, mas para aqueles que não podem fazer o gancho funcionar, aqui está a solução mais simples:

<?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; ?>
    
por Szabolcs Páll 26.10.2017 / 12:38
fonte
0

Eu acho este pequeno plugin muito útil: enlace

  

WP_Query Powered Adjacente O Post Link é um plug-in para desenvolvedores. Ele adiciona a função wpqpapl(); ao WordPress, que pode retornar informações sobre o post anterior e o próximo para o atual. Aceita argumentos para uso na classe WP_Query .

    
por any_h 26.11.2013 / 19:17
fonte
0

Isso funcionou para mim:

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 )";
}

Extraído de: enlace

    
por Philip 12.03.2015 / 15:22
fonte
-1

Eu encontrei uma maneira muito mais fácil de conseguir uma navegação de postagem baseada em meta-teclas, sem a necessidade de modificar functions.php.

Meu exemplo: você tem um products.php e deseja alternar entre produtos. O produto anterior é o próximo mais barato, o próximo produto o próximo mais caro.

Aí vem a minha solução 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 } ?>
    
por Kent Miller 21.05.2014 / 10:25
fonte