it-swarm.com.de

Können die Next/Prev Post-Links nach Menüreihenfolge oder nach einem Metaschlüssel sortiert werden?

Ich habe eine Reihe von Posts, die nach einem meta_key-Wert sortiert sind. Sie können bei Bedarf auch nach Menüreihenfolge arrangiert werden.

Die Links für den nächsten/vorherigen Beitrag (generiert von next_post_link, previous_post_link oder posts_nav_link) navigieren alle nach Chronologie. Obwohl ich dieses Standardverhalten verstehe, verstehe ich nicht, wie ich es ändern kann. php, aber dann scheint es ziemlich hart zu sein. Es wird empfohlen, dies von Grund auf neu zu schreiben, um es zu ersetzen, oder gibt es eine bessere Lösung.

31
Jodi Warren

Interna verstehen

Die "Sortierreihenfolge" benachbarter (nächster/vorheriger) Beiträge ist eigentlich keine "Sortierreihenfolge". Es ist eine separate Abfrage auf jeder Anfrage/Seite, aber es sortiert die Abfrage nach dem post_date - oder dem übergeordneten Post, wenn Sie einen hierarchischen Post als aktuell angezeigtes Objekt haben.

Wenn Sie sich die Interna von next_post_link() ansehen, stellen Sie fest, dass es sich im Grunde um einen API-Wrapper für adjacent_post_link() handelt. Die spätere Funktion ruft get_adjacent_post() intern mit dem Argument/Flag $previous auf, das auf bool(true|false) gesetzt ist, um den nächsten oder vorherigen Beitragslink abzurufen.

Was filtern?

Nachdem Sie sich näher damit befasst haben, werden Sie feststellen, dass get_adjacent_post() Quelllink  hat einige nette Filter für seine Ausgabe (a.k.a. Abfrageergebnis): (Filtername/Argumente)

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

Also kannst du (viel damit machen. Das beginnt mit dem Filtern der WHERE-Klausel sowie der JOINed-Tabelle und der ORDER BY-Anweisung.

Das Ergebnis wird für die aktuelle Anforderung im Arbeitsspeicher zwischengespeichert, sodass keine zusätzlichen Abfragen hinzugefügt werden, wenn Sie diese Funktion mehrmals auf einer einzelnen Seite aufrufen.

Automatische Abfrageerstellung

Wie @StephenHarris in den Kommentaren ausgeführt hat, gibt es eine Kernfunktion, die sich beim Erstellen der SQL-Abfrage als nützlich erweisen könnte: get_meta_sql() - Beispiele im Codex . Grundsätzlich wird diese Funktion nur zum Erstellen der Meta-SQL-Anweisung verwendet, die in WP_Query verwendet wird. Sie können sie jedoch auch in diesem Fall (oder in anderen Fällen) verwenden. Das Argument, das Sie hineinwerfen, ist ein Array, genau dasselbe, das einem WP_Query hinzugefügt würde.

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

Der Rückgabewert ist ein Array:

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

Sie können also $sql['join'] und $sql['where'] in Ihrem Rückruf verwenden.

Abhängigkeiten im Hinterkopf behalten

In Ihrem Fall ist es am einfachsten, es in einem kleinen (mu) Plugin oder in der Datei functions.php Ihres Themes abzufangen und abhängig von der Variablen $adjacent = $previous ? 'previous' : 'next'; und der Variablen $order = $previous ? 'DESC' : 'ASC'; zu ändern:

Die tatsächlichen Filternamen

Die Filternamen lauten also:

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

Als Plugin eingepackt

... und der Filter-Callback würde (zum Beispiel) ungefähr so ​​lauten:

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

Kaisers Antwort ist großartig und gründlich, aber nur die ORDER BY-Klausel zu ändern reicht nicht aus, es sei denn, Ihr menu_order stimmt mit Ihrer chronologischen Reihenfolge überein.

Ich kann das nicht gutschreiben, aber ich habe den folgenden Code in this Gist gefunden:

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

Ich habe die Funktionsnamen für WP.SE geändert.

Wenn Sie nur die ORDER BY-Klausel ändern, sucht die Abfrage weiterhin nach Beiträgen, die größer oder kleiner als das aktuelle Beitragsdatum sind. Wenn Ihre Beiträge nicht chronologisch geordnet sind, erhalten Sie nicht den richtigen Beitrag.

Dies ändert die where-Klausel, um nach Beiträgen zu suchen, bei denen menu_order größer oder kleiner als menu_order des aktuellen Beitrags ist. Außerdem wird die orderby-Klausel geändert.

Die orderby-Klausel sollte auch nicht hartcodiert sein, um DESC zu verwenden, da sie abhängig davon wechseln muss, ob Sie den nächsten oder den vorherigen Beitragslink erhalten.

21
jjeaton
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' );
4
Micheal Jess

Versuchte, ohne Erfolg einzuhaken. Könnte nur ein Problem meiner Konfiguration sein, aber für diejenigen, die den Hook nicht zum Laufen bringen können, ist hier die einfachste Lösung:

<?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; ?>
4
Szabolcs Páll

Basierend auf @Szabolcs Pálls Antwort habe ich diese Utility-Klasse mit Hilfsmethoden erstellt, um Beiträge nach Menüreihenfolge und den nächsten und vorherigen Beitrag auch nach Menüreihenfolge abrufen zu können. Ich habe außerdem Bedingungen hinzugefügt, um zu überprüfen, ob der aktuelle Beitrag der erste oder der letzte ist, um den letzten bzw. den ersten Beitrag zu erhalten.

Zum Beispiel:

// $currentPost is first by menu order
getPreviousPostByMenuOrder($postType, $$currentPost->ID)
// returns => last post by menu order

// $currentPost is last by menu order
getPreviousPostByMenuOrder($postType, $$currentPost->ID)
// returns => first post by menu order

Die volle Klasse:

class PostMenuOrderUtils {

    public static function getPostsByMenuOrder($postType){
        $args =[
            'post_type' => $postType,
            'orderby' => 'menu_order',
            'order' => 'ASC',
            'posts_per_page' => -1
        ];

        $posts = get_posts($args);

        return $posts;
    }

    public static function getNextPostByMenuOrder($postType, $postID){
        $posts = self::getPostsByMenuOrder($postType);

        $nextPost = null;

        foreach($posts as $key => $value) {
            if($value->ID == $postID){
                $nextPost = $posts[$key] !== end($posts) ? $posts[$key + 1] : $posts[0];

                break;
            }
        }

        return $nextPost;
    }

    public static function getPreviousPostByMenuOrder($postType, $postID){
        $posts = self::getPostsByMenuOrder($postType);


        $prevPost = null;

        foreach($posts as $key => $value) {
            if($value->ID == $postID){
                $prevPost = $key !== 0 ? $posts[$key - 1] : end($posts);
                break;
            }
        }

        return $prevPost;
    }

}
0
Eli Jayson

Ich finde dieses kleine Plugin sehr praktisch: http://wordpress.org/plugins/wp-query-powered-adjacent-post-link/

WP_Query Powered Adjacent Post Link ist ein Plugin für Entwickler. Es fügt die Funktion wpqpapl(); zu WordPress hinzu, mit der Informationen zum vorherigen und nächsten Beitrag an den aktuellen zurückgegeben werden können. Es akzeptiert Argumente zur Verwendung in der Klasse WP_Query.

0
any_h

Das hat bei mir funktioniert:

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

Entnommen: https://stackoverflow.com/questions/16495117/how-to-skip-certain-links-on-adjacent-posts-in-wordpress

0
Philip