क्या मेन्यू ऑर्डर या किसी मेटा कुंजी के द्वारा नेक्स्ट / प्रीव पोस्ट लिंक आर्डर किए जा सकते हैं?


32

मेरे पास पोस्ट की एक श्रृंखला है जो एक मेटा_की मान द्वारा आदेशित है। यदि आवश्यक हो, तो उन्हें मेनू ऑर्डर द्वारा भी व्यवस्थित किया जा सकता है।

अगले / पिछला पोस्ट लिंक (द्वारा उत्पन्न next_post_link, previous_post_linkया posts_nav_linkकालक्रम द्वारा सभी नेविगेट। जब मैं इस डिफ़ॉल्ट व्यवहार को समझते हैं, मैं समझता हूँ कि नहीं यह कैसे बदलने के लिए। मैंने पाया कि यह लिंक-template.php में adjacent_post_link के माध्यम से नक्शे, लेकिन तब यह काफी कठोर-कोडित लगने लगता है। क्या इसे बदलने के लिए इसे फिर से लिखने की सिफारिश की गई है, या कोई बेहतर उपाय है।


2
यहाँ आपकी समस्या के लिए एकदम सही प्लगइन है: wordpress.org/support/topic/… wordpress.org/extend/plugins/… धन्यवाद Ambrosite! :)
मिगुएलब

1
ध्यान दें कि दूसरा उत्तर सही परिणाम देता है।
थॉमस

जवाबों:


29

इंटर्नल को समझना

आसन्न (अगले / मौजूदा) पदों का "क्रमबद्ध" क्रम वास्तव में "क्रम" नहीं है। यह प्रत्येक अनुरोध / पृष्ठ पर एक अलग क्वेरी है, लेकिनpost_date यदि आपके पास वर्तमान में प्रदर्शित ऑब्जेक्ट के रूप में एक पदानुक्रमित पोस्ट है - तो यह - या पोस्ट अभिभावक द्वारा क्वेरी को सॉर्ट करता है ।

जब आप के आंतरिक पर एक नज़र डालते हैं next_post_link(), तो आप देखते हैं कि यह मूल रूप से एक एपीआई आवरण है adjacent_post_link()। बाद के फ़ंक्शन अगले या पिछले पोस्ट लिंक को हथियाने के लिए तर्क / ध्वज सेट के get_adjacent_post()साथ आंतरिक रूप से कॉल करते हैं ।$previousbool(true|false)

क्या फ़िल्टर करें?

इसमें गहराई से खुदाई करने के बाद, आप देखेंगे कि get_adjacent_post() स्रोत लिंक में इसके आउटपुट (उर्फ क्वेरी परिणाम) के लिए कुछ अच्छे फ़िल्टर हैं: (फ़िल्टर नाम / छंद)

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

तो आप इसके साथ बहुत कुछ कर सकते हैं । यह WHEREक्लॉज़ को फ़िल्टर करने के साथ-साथ JOINएड टेबल और ORDER BYस्टेटमेंट के साथ शुरू होता है ।

परिणाम वर्तमान अनुरोध के लिए मेमोरी में कैश हो जाता है, इसलिए यदि आप एक ही पृष्ठ पर कई बार उस फ़ंक्शन को कॉल करते हैं तो यह अतिरिक्त प्रश्न नहीं जोड़ता है।

स्वचालित क्वेरी बिल्डिंग

जैसा कि @StephenHarris ने टिप्पणियों में बताया, एक मुख्य कार्य है जो SQL क्वेरी बनाते समय काम में आ सकता है: get_meta_sql()- उदाहरण कोडेक्स में । मूल रूप से इस फ़ंक्शन का उपयोग केवल मेटा SQL स्टेटमेंट के निर्माण के लिए किया जाता है जो इसमें उपयोग किया जाता है WP_Query, लेकिन आप इसे इस मामले में (या अन्य) भी उपयोग कर सकते हैं। जो तर्क आप इसमें फेंकते हैं वह एक सरणी है, ठीक वही जो एक में जोड़ा जाएगा WP_Query

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

वापसी मान एक सरणी है:

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

तो आप उपयोग कर सकते हैं $sql['join']और $sql['where']अपने कॉलबैक में।

ध्यान में रखने के लिए निर्भरताएँ

आपके मामले में सबसे आसान काम यह होगा कि आप इसे एक छोटे (म्यू) प्लग इन या अपने थीम फंक्शन्स.php फाइल में इंटरप्ट करें और इसे $adjacent = $previous ? 'previous' : 'next';वेरिएबल और वेरिएबल के आधार पर बदल दें $order = $previous ? 'DESC' : 'ASC';:

वास्तविक फ़िल्टर नाम

तो फिल्टर नाम हैं:

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

एक प्लगइन के रूप में लिपटे

... और फ़िल्टर कॉलबैक निम्नानुसार होगा (उदाहरण के लिए):

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

2
+1। बस जानकारी के लिए, (@magnakai) अगर मेटा प्रश्नों के लिए ऐसा कुछ किया जाए, तो देखेंget_meta_sql()
स्टीफन हैरिस

+1 करने के लिए @StephenHarris! इससे पहले यह नहीं देखा गया। लघु प्रश्न: जैसा कि मैंने उस स्रोत से पढ़ा है कि आपको पूरी तरह से योग्य क्वेरी ऑब्जेक्ट पास करना है, तो आप उपर्युक्त फ़िल्टर के साथ यह कैसे करेंगे? जहाँ तक मैं देख सकता हूँ कि केवल क्वेरी स्ट्रिंग्स पास हुए हैं, क्योंकि फ़िल्टर के बाद क्वेरी निष्पादित होती है।
kaiser

2
नहीं, $meta_queryकेवल वह सरणी है जिसे आप तर्क के WP_Queryलिए पास करेंगे meta_query: इस उदाहरण में: $meta_sql = get_meta_sql( $meta_query, 'post', $wpdb->posts, 'ID');- यह JOINऔर WHEREउस क्वेरी के भाग को उत्पन्न करता है जिसे जोड़ने की आवश्यकता होगी।
स्टीफन हैरिस

@StephenHarris एक (मेरे) उत्तर को संपादित करने के लिए सही समय है।
०२:२२

@StephenHarris, मुझे get_meta_sql () के आउटपुट को लागू करने में परेशानी हो रही है - क्या आप डॉट्स से जुड़ने में मदद कर सकते हैं?
जोड़ी वॉरेन

21

कैसर का जवाब बहुत बढ़िया और पूरी तरह से है, लेकिन जब तक menu_orderआपके कालानुक्रमिक क्रम से मेल नहीं खाता तब तक ORDER BY क्लॉज को बदलना पर्याप्त नहीं है ।

मैं इसका श्रेय नहीं ले सकता, लेकिन मुझे इस जिस्ट में निम्नलिखित कोड मिला :

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

मैंने WP.SE के लिए फ़ंक्शन नाम संशोधित किए हैं

यदि आप केवल ORDER BY खंड को बदलते हैं, तो क्वेरी अभी भी वर्तमान पोस्ट दिनांक से अधिक या उससे कम के पोस्ट की तलाश करती है। यदि आपकी पोस्ट कालानुक्रमिक क्रम में नहीं हैं, तो आपको सही पोस्ट नहीं मिलेगी।

यह उन स्थानों को बदलता है जहां उन पोस्टों की तलाश की जाती है जहां मेनू_ऑर्डर वर्तमान पोस्ट के मेनू_ऑर्डर की तुलना में अधिक या उससे कम होता है, इसके अलावा ऑर्डरबी क्लॉज को संशोधित भी करता है।

ऑर्डरबी क्लॉज को भी DESC का उपयोग करने के लिए हार्डकोड नहीं किया जाना चाहिए, क्योंकि इसके आधार पर स्विच करने की आवश्यकता होगी, चाहे आपको अगला या बाद का लिंक मिल रहा हो।


3
एक नोट: WHEREखंड के लिए लग रहा है 'YYYY-mm-dd HH:mm:ss'। अगर यह पूरा नहीं हुआ है, यह काम नहीं करेगा। जैसा कि मान डीबी द्वारा निर्धारित नहीं किया गया है, लेकिन एप्लिकेशन द्वारा, आपको रेगुलर एक्सप्रेशन बनाते समय पहले उस प्रारूप की जांच करनी होगी।
केसर

5

सफलता के बिना हुक करने की कोशिश की। मेरे विन्यास की समस्या हो सकती है, लेकिन जो लोग हुक काम नहीं कर सकते हैं, उनके लिए यहां सबसे सरल उपाय है:

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

कुछ घंटों की कोशिश के बाद get_previous_post_where, get_previous_post_joinऔर get_previous_post_sortकस्टम पोस्ट प्रकार और जटिल ऑर्डरिंग के साथ अच्छा खेलने के लिए जिसमें मेटा कीज़ शामिल हैं, मैंने इसे छोड़ दिया और इसका इस्तेमाल किया। धन्यवाद!
चौकोर कैंडी

यहाँ भी, न केवल मुझे मेनू ऑर्डर द्वारा ऑर्डर करना था, बल्कि एक विशिष्ट मेटा_की और मेटा_वल्यू के साथ पोस्ट की भी तलाश थी, इसलिए यह सबसे अच्छा तरीका था। केवल एक ही बदलाव मैंने इसे एक फ़ंक्शन में लपेटने के लिए किया था।
मिकारोट

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

1

@Szabolcs Páll के उत्तर के आधार पर मैंने इस उपयोगिता वर्ग को सहायक बनाया है जिसमें मेनू क्रम द्वारा प्रकार के पद प्राप्त करने में सक्षम हो और मेनू क्रम द्वारा अगला और पिछला पद भी प्राप्त कर सके। मैंने यह जांचने के लिए अतिरिक्त शर्तें जोड़ी हैं कि क्या वर्तमान पद क्रमशः अंतिम या पहला पद है।

उदाहरण के लिए:

// $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

पूरी कक्षा:

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

मुझे यह छोटा सा प्लगइन वास्तव में आसान लगता है: http://wordpress.org/plugins/wp-query-powered-adjacent-post-link/

WP_Query संचालित आसन्न पोस्ट लिंक डेवलपर्स के लिए एक प्लगइन है। यह wpqpapl();वर्डप्रेस में फ़ंक्शन जोड़ता है जो पिछली और अगली पोस्ट पर वर्तमान में जानकारी वापस कर सकता है। यह WP_Queryकक्षा में उपयोग के लिए तर्क स्वीकार करता है ।


0

यह मेरे लिए काम किया:

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

से लिया गया: https://stackoverflow.com/questions/16495117/how-to-skip-earch-links-on-adjacent-posts-in-wordpress


-1

मैंने फ़ंक्शन को संशोधित करने की आवश्यकता के बिना मेटा-कुंजी आधारित पोस्ट नेविगेशन को प्राप्त करने का एक बहुत आसान तरीका पाया है।

मेरा उदाहरण: आपके पास एक products.php है और आप उत्पादों के बीच स्विच करना चाहते हैं। पिछला उत्पाद अगला सस्ता है, अगला उत्पाद अगला अधिक महंगा है।

यहाँ 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 } ?>

-10 इस उत्तर के लिए। यह एक बेहतर समाधान कैसे हो सकता है यदि आप उपयोग कर रहे हैं query_postsजब कोडेक्स बताता है कि इसका उपयोग नहीं किया जाना चाहिए।
पीटर गोयन ने

लेकिन यह काम करता है। तो विकल्प WP_Query या क्या है?
कैंट मिलर

हां, WP_Queryपिछले उत्तरों की तरह इस्तेमाल किया जाना चाहिए।
पीटर गोयन ने

1
@KentMiller, कोडेक्स पेज पर एक जानकारीपूर्ण आरेख है , और आपको यह प्रश्न भी आसान लग सकता है। यह इन सम्मेलनों के साथ खुद को परिचित करने लायक है।
जोडी वारेन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.