Можно ли упорядочить ссылки на следующий/предыдущий пост по порядку меню или по мета-ключу?

19 нояб. 2012 г., 19:23:48
Просмотры: 28.3K
Голосов: 40

У меня есть серия постов, которые упорядочены по значению meta_key. При необходимости их также можно расположить по порядку меню.

Ссылки на следующий/предыдущий пост (генерируемые с помощью next_post_link, previous_post_link или posts_nav_link) все навигируют по хронологии. Хотя я понимаю это поведение по умолчанию, я не понимаю, как его изменить. Я обнаружил, что это связано с adjacent_post_link в link-template.php, но затем это начинает казаться довольно жестко закодированным. Рекомендуется ли переписать это с нуля для замены, или есть лучшее решение.

2
Комментарии

Вот идеальный плагин для вашей проблемы: http://wordpress.org/support/topic/plugin-ambrosite-nextprevious-post-link-plus-custom-meta-key-value?replies=6 http://wordpress.org/extend/plugins/ambrosite-nextprevious-post-link-plus/ Спасибо Ambrosite! :)

miguelb miguelb
16 мар. 2013 г. 14:33:11

Обратите внимание, что второй ответ, кажется, дает правильный результат.

Thomas Thomas
11 мар. 2016 г. 14:34:10
Все ответы на вопрос 13
7
36

Понимание внутренней работы

"Сортировка" соседних (следующих/предыдущих) записей на самом деле не является порядком сортировки. Это отдельный запрос для каждой страницы, но он сортирует результаты по post_date — или по родительской записи, если у вас иерархический тип записи и он отображается в текущий момент.

Если заглянуть внутрь функции next_post_link(), то можно увидеть, что это по сути обёртка API для adjacent_post_link(). Последняя функция вызывает get_adjacent_post() с аргументом $previous, установленным в bool(true|false), чтобы получить ссылку на следующую или предыдущую запись.

Что можно фильтровать?

При более глубоком изучении становится видно, что get_adjacent_post() Источник содержит несколько полезных фильтров для результата запроса: (Название фильтра/Аргументы)

  • "get_{$adjacent}_post_join"

    $join
    // Только если `$in_same_cat`
    // или: ! empty( $excluded_categories` 
    // и тогда: 
    // " 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"; 
    // а если $in_same_cat, то добавляется: 
    // " 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, ',') . ')'; 
          // ИЛИ пустая строка, если $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.

Результат кэшируется в памяти на время текущего запроса, поэтому повторные вызовы функции не приводят к дополнительным SQL-запросам.

Автоматическое построение запроса

Как отметил @StephenHarris в комментариях, в ядре WordPress есть полезная функция для построения SQL-запросов: get_meta_sql()примеры в Codex. Эта функция обычно используется для формирования 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'].

Важные зависимости

В вашем случае проще всего перехватить запрос через небольшой (mu)плагин или в файле functions.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) Изменение порядка сортировки соседних записей */
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' );
19 нояб. 2012 г. 19:40:07
Комментарии

+1. Просто для информации, (@magnakai), если нужно сделать что-то подобное для мета-запросов, посмотрите get_meta_sql()

Stephen Harris Stephen Harris
19 нояб. 2012 г. 20:30:12

+1 тебе, @StephenHarris! Раньше не видел эту функцию. Короткий вопрос: как я понял из исходного кода, нужно передавать полностью сформированный объект запроса, как это сделать с упомянутыми выше фильтрами? Насколько я вижу, там передаются только строки запросов, так как сам запрос выполняется после фильтров.

kaiser kaiser
19 нояб. 2012 г. 20:58:39

нет, $meta_query - это просто массив, который ты передаешь в WP_Query для аргумента meta_query: В этом примере: $meta_sql = get_meta_sql( $meta_query, 'post', $wpdb->posts, 'ID'); - это генерирует части запроса JOIN и WHERE, которые нужно добавить.

Stephen Harris Stephen Harris
19 нояб. 2012 г. 21:41:06

@StephenHarris Идеальный момент, чтобы отредактировать один (мой) ответ.

kaiser kaiser
20 нояб. 2012 г. 02:28:57

@StephenHarris, у меня не получается применить результат get_meta_sql() - поможешь соединить точки?

Jodi Warren Jodi Warren
20 нояб. 2012 г. 13:27:27

@Magnakai это массив $sql => (array) 'join' => array(), 'where' => array(). Так что просто возьми $sql['join']; или $sql['where'].

kaiser kaiser
26 нояб. 2013 г. 19:13:39

Это сработало, за исключением того, что ссылки идут в обратном порядке. Функция previous_post_link генерирует ссылку, которую должна создавать next_post_link, и наоборот. Я пробовал изменить порядок с DESC на ASC, но это не помогло.

Dan Dan
10 мая 2019 г. 16:53:23
Показать остальные 2 комментариев
2
27

Ответ Kaiser'а великолепен и детален, однако просто изменить предложение ORDER BY недостаточно, если ваш menu_order не соответствует хронологическому порядку.

Я не могу приписать себе заслугу этого решения, но я нашел следующий код в этом gist'е:

<?php
/**
 * Настройка порядка соседних ссылок на записи
 */
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, запрос всё равно будет искать записи с датой больше или меньше текущей. Если ваши записи не в хронологическом порядке, вы не получите правильную запись.

Этот код изменяет условие WHERE для поиска записей, где menu_order больше или меньше menu_order текущей записи, в дополнение к изменению порядка сортировки.

Также предложение orderby не должно быть жестко закодировано с использованием DESC, так как оно должно меняться в зависимости от того, получаете ли вы следующую или предыдущую ссылку.

16 апр. 2013 г. 06:18:47
Комментарии

Одно замечание: Условие WHERE ожидает формат 'YYYY-mm-dd HH:mm:ss'. Если этот формат не соблюдён, условие не сработает. Поскольку значение устанавливается не базой данных, а приложением, вам нужно сначала проверить соответствие этому формату при построении регулярного выражения.

kaiser kaiser
6 апр. 2014 г. 15:11:15

Если вам нужно сортировать по post_title, вы можете заменить все вхождения menu_order в приведённом выше коде, и всё должно работать. Обратите внимание на второй элемент массива $replacements — мне пришлось заключить его в одинарные кавычки, чтобы он работал: $replacements[] = '\'' . $the_post->post_title . '\'';

Ben Stevens Ben Stevens
1 июл. 2021 г. 22:26:28
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; ?>
26 окт. 2017 г. 13:38:52
Комментарии

после нескольких часов попыток заставить get_previous_post_where, get_previous_post_join и get_previous_post_sort корректно работать с пользовательскими типами записей и сложной сортировкой, включающей мета-поля, я сдался и использовал это. Спасибо!

squarecandy squarecandy
13 июл. 2018 г. 01:52:16

То же самое, мне нужно было сортировать не только по Menu Order, но и искать записи с определёнными meta_key и meta_value, поэтому этот метод оказался лучшим. Единственное изменение, которое я сделал - обернул это в функцию.

MrCarrot MrCarrot
10 февр. 2019 г. 10:35:30

этот код подвержен ошибкам выхода за границы диапазона

eballeste eballeste
2 апр. 2020 г. 04:35:51

@eballeste, если ты имеешь в виду получение первого поста при нахождении на последнем и последнего при нахождении на первом, смотри мой ответ ниже

Eli Jayson Eli Jayson
3 апр. 2020 г. 22:10:50

ага, увидел позже и проголосовал, спасибо

eballeste eballeste
9 апр. 2020 г. 02:38:44
0
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' );
20 июн. 2013 г. 08:00:36
0

Кстати, вот как можно отсортировать по menu_order для определенного типа записи:

/**
 * Настройка порядка соседних записей
 */
add_filter('get_next_post_sort', function($order) {
    if (is_singular('my_custom_post_type')) {
        return 'ORDER BY p.menu_order ASC LIMIT 1';
    }

    return $order;
}, 10);

add_filter('get_previous_post_sort', function($order) {
    if (is_singular('my_custom_post_type')) {
        return 'ORDER BY p.menu_order DESC LIMIT 1';
    }

    return $order;
}, 10);

add_filter('get_next_post_where', function() {
    if (is_singular('my_custom_post_type')) {
        global $post, $wpdb;
        return $wpdb->prepare("WHERE p.menu_order > %s AND p.post_type = %s AND p.post_status = 'publish'", $post->menu_order, $post->post_type);
    }
}, 10);

add_filter('get_previous_post_where', function() {
    if (is_singular('my_custom_post_type')) {
        global $post, $wpdb;
        return $wpdb->prepare("WHERE p.menu_order < %s AND p.post_type = %s AND p.post_status = 'publish'", $post->menu_order, $post->post_type);
    }
}, 10);

Надеюсь, это поможет кому-то еще!

4 авг. 2021 г. 21:00:58
0

На основе ответа @Szabolcs Páll я создал этот вспомогательный класс с методами для получения записей типа по порядку меню, а также для получения следующей и предыдущей записи по порядку меню. Дополнительно я добавил проверки, является ли текущая запись первой или последней, чтобы в таком случае возвращать последнюю или первую запись соответственно.

Например:

// $currentPost является первой по порядку меню
getPreviousPostByMenuOrder($postType, $$currentPost->ID)
// возвращает => последнюю запись по порядку меню

// $currentPost является последней по порядку меню
getPreviousPostByMenuOrder($postType, $$currentPost->ID)
// возвращает => первую запись по порядку меню

Полный класс:

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

}
16 мая 2019 г. 23:04:20
1

На основе ответа от @Szabolcs Páll и статьи bbloomer о добавлении кнопок "следующий/предыдущий" на странице товара WooCommerce, я создал этот код.

Он сортирует все товары по мета-ключу и добавляет кнопки "предыдущий/следующий" сверху и снизу товара.

(Мета-ключом может быть и поле ACF!)

/**
 * @snippet       Добавление кнопок "следующий/предыдущий" с сортировкой по мета-ключу или полю ACF @ WooCommerce Single Product Page
 * @testedwith    WooCommerce 4.8.0
 * @source        Elron : https://wordpress.stackexchange.com/a/365334/98773
 * @thanks        bbloomer : https://businessbloomer.com/?p=20567
 * @thanks        Szabolcs Páll : https://wordpress.stackexchange.com/a/284045/98773
 */

add_action('woocommerce_before_single_product', 'elron_prev_next_product');

// а если хотите их и внизу...
add_action('woocommerce_after_single_product', 'elron_prev_next_product');

function elron_prev_next_product()
{
   global $post;

   echo '<div class="prev-next-buttons">';

   $all_posts = new WP_Query(
      array(
         'post_type' => 'product',
         'meta_key' => 'the_meta_key_or_acf_field', // <-- ИЗМЕНИТЕ ЭТО
         'orderby' => 'meta_value',
         'order' => 'DESC',
         '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;
      }
   }

   if ($prevID) : ?>
      <a href="<?= get_the_permalink($prevID) ?>" rel="prev" class="prev" title="<?= get_the_title($prevID) ?>"><?= esc_attr__('Предыдущий товар') ?></a>
   <?php endif; ?>
   <?php if ($nextID) : ?>
      <a href="<?= get_the_permalink($nextID) ?>" rel="next" class="next" title="<?= get_the_title($nextID) ?>"><?= esc_attr__('Следующий товар') ?></a>
   <?php endif; ?>
<?php

   echo '</div>';
}

Если вам нужен дополнительный scss-файл, который я использовал: _prev-next-buttons.scss

.prev-next-buttons {
    background: $lightpurple;
    padding: 2em;
    text-align: center;

    a {
        opacity: 0.7;
        border-radius: 0.5em;
        border: $white 1px solid;
        color: $white;
        display: inline-block;
        padding: 0.5em 0.8em;
        text-decoration: none;
        margin: 0 0.1em;
        &:hover, &:focus {
            opacity: 1;
        }
    }

    .prev {
        &:before {
            content: "  ";
        }
    }
    .next {
        &:after {
            content: "  ";
        }
    }
}

.rtl {
    .prev-next-buttons {
        .prev {
            &:before {
                content: "  ";
            }
        }
        .next {
            &:after {
                content: "  ";
            }
        }
    }
}

28 апр. 2020 г. 21:51:17
Комментарии

Спасибо за ценную информацию. Я использовал её с моим пользовательским типом записи, у которого также есть пользовательское поле даты. Работает отлично на WordPress 5.9.3. Также могу подтвердить, что это работает с пользовательскими типами записей и полями, созданными с помощью сторонних плагинов, таких как ACF.

Mycodingproject Mycodingproject
10 мая 2022 г. 14:44:00
2

Ни один из ответов, представленных здесь или в интернете в целом, которые я смог найти на момент написания этого текста, не предлагал достаточно простого/элегантного решения для вывода ссылок на Следующую/Предыдущую запись, отсортированных по мета-ключу. Этот вариант отлично работает для меня и легко адаптируется. Наслаждайтесь!

add_filter( 'get_previous_post_where', function( $where ) {
    return get_adjacent_post_where( $where, false) ;
});
add_filter( 'get_next_post_where', function ( $where ) {
    return get_adjacent_post_where( $where, true );
}); 

function get_adjacent_post_where( $where, $is_next ) {  

    global $post;

    /* Укажите ваш тип записи -> */
    $post_type = "_my_post_type_";

    if ($post_type == $post->post_type){

        global $wpdb;

        $show_private = current_user_can( 'read_private_pages', $post->ID );
        /* Укажите название вашего мета-ключа -> */
        $meta_key = '_my_meta_key_name_'; 
        $meta_value = get_post_meta($post->ID,$meta_key,true);
        $operand = $is_next?">":"<";
        $direction = $is_next?"ASC":"DESC";

        $sub_query = "(SELECT m.post_id FROM `" . $wpdb->postmeta . "` AS m JOIN `" . $wpdb->posts . "` as p1 ON m.post_id = p1.ID "
        . "WHERE m.meta_key = '$meta_key' AND m.meta_value $operand '$meta_value' "
        . "AND (p1.post_status = 'publish'" . ($show_private?" OR p1.post_status = 'private') ":") ")
        . "ORDER BY m.meta_value $direction LIMIT 1)";
         
        /* Вложенный подзапрос обходит текущие ограничения mysql/mariadb */
        $where = "WHERE p.post_type = '$post_type'  AND p.ID IN (SELECT * FROM $sub_query as sq)";  
    }

    return $where;

}
28 янв. 2024 г. 20:24:54
Комментарии

В вашем коде есть ссылки на таблицы с префиксами, например kc_wppostmeta и kc_wpposts. Лучшей практикой является использование глобального объекта $wpdb для указания этих таблиц, например $wpdb->posts вместо kc_wpposts.

Также стоит отметить, что это предполагает получение публично или приватно опубликованного контента в вашем подзапросе. В основном коде есть целый раздел условий, который обрабатывает это: https://github.com/WordPress/wordpress-develop/blob/8338c630284124bbe79dc871822d6767e3b45f0b/src/wp-includes/link-template.php#L1893

MikeNGarrett MikeNGarrett
2 февр. 2024 г. 22:17:57

Спасибо @MikeNGarrett. Внес изменения. Пожалуйста, дайте знать, если я что-то упустил.

Collie Collie
5 февр. 2024 г. 02:55:03
0

Я нахожу этот небольшой плагин действительно удобным: http://wordpress.org/plugins/wp-query-powered-adjacent-post-link/

WP_Query Powered Adjacent Post Link — это плагин для разработчиков. Он добавляет в WordPress функцию wpqpapl();, которая может возвращать информацию о предыдущей и следующей записях относительно текущей. Функция принимает аргументы для использования в классе WP_Query.

26 нояб. 2013 г. 20:17:59
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-certain-links-on-adjacent-posts-in-wordpress

12 мар. 2015 г. 16:22:08
0

У меня тоже были с этим проблемы. Волшебным образом всё заработало вот так:

  • Убедитесь, что ваш тип записи поддерживает иерархические записи.
  • Затем используйте простой плагин для сортировки произвольных типов записей. https://wordpress.org/plugins/simple-custom-post-order/
    Помимо простой сортировки перетаскиванием, этот плагин гарантирует правильную работу ссылок "предыдущая" и "следующая" через порядок меню. К сожалению, он может работать в обратном порядке (DSC вместо ASC). Чтобы это исправить, мы можем создать функцию обратной навигации по записям.
  • Используйте функцию обратной навигации. Я нашёл одну на gist. (добавьте в файл functions.php вашей темы) https://gist.github.com/jaredchu/3e3bcb866240d1d32a3b4ae55905b135#file-the_reverse_post_navigation

И мне не пришлось писать ни строчки кода самому :)

4 февр. 2020 г. 18:03:26
0

Я отредактировал код Szabolcs Páll выше, чтобы сортировать по пользовательскому meta_key и в рамках определенной категории, а также попытался добавить условия для первого и последнего постов.

В оригинальном коде для первого и последнего поста не отображались правильные ссылки next/prev, показывалась только ссылка на текущий ID поста, на котором я находился.

Ниже приведенный код сработал для меня, но я не уверен, есть ли в нем потенциальные проблемы. (Я не самый продвинутый кодер)

<?php
$all_posts = new WP_Query(array(
    'taxonomy' => 'category',
    'category_name' => 'projects',
    'meta_key' => 'grid_number_projects',
    'orderby' => 'meta_value',
    'order' => 'ASC',
    'posts_per_page' => -1
));
foreach($all_posts->posts as $key => $value) {
    if($value->ID == $post->ID){
        $nextID = isset($all_posts->posts[$key + 1]) ? $all_posts->posts[$key + 1]->ID : null;
        $prevID = isset($all_posts->posts[$key - 1]) ? $all_posts->posts[$key - 1]->ID : null;
        break;
    }
}

?>

<div class="project-nav-prev">
    <?php if($prevID): ?>
        <a href="<?= get_the_permalink($prevID) ?>" rel="prev"><span class="arrow">←</span> ПРЕДЫДУЩИЙ ПРОЕКТ </br><?= get_the_title($prevID) ?></a>
    <?php endif; ?>
</div>
<div class="project-nav-next">
    <?php if($nextID): ?>
        <a href="<?= get_the_permalink($nextID) ?>" rel="next">СЛЕДУЮЩИЙ ПРОЕКТ <span class="arrow">→</span> </br><?= get_the_title($nextID) ?></a>
    <?php endif; ?>
</div>
23 мар. 2023 г. 14:18:59
4
-2

Я нашел гораздо более простой способ реализации навигации по записям на основе мета-ключа, без необходимости изменять functions.php.

Мой пример: У вас есть products.php и вы хотите переключаться между товарами. Предыдущий товар - следующий по дешевизне, следующий товар - следующий по дороговизне.

Вот мое решение для single.php:

<div class="post_navigation">

<?php

// Подготавливаем цикл
$args = array(
'post_type' => 'products',
'post_status' => 'publish',
'meta_key' => 'price',
'orderby' => 'meta_value_num',
'order' => 'ASC',
'posts_per_page' => -1
);
query_posts($args);

// Инициализируем массив, в котором будут храниться ID всех товаров
$posts = array();

// ... и запускаем цикл
while ( have_posts() ) : the_post();
$posts[] += $post->ID;
endwhile;

// Сбрасываем запрос
wp_reset_query();

// Определяем позицию текущего товара в массиве $posts
$current = array_search(get_the_ID(), $posts);

// Получаем ID предыдущего товара
$prevID = $posts[$current-1];

// Получаем ID следующего товара
$nextID = $posts[$current+1];

// Ссылка "предыдущий товар"
if (!empty($prevID)) { ?>
<a href="/?p=<?php echo $prevID; ?>">предыдущий товар</a>
<?php }
// Ссылка "следующий товар"
if (!empty($nextID)) { ?>
<a href="/?p=<?php echo $nextID; ?>">следующий товар</a>

<?php } ?>
21 мая 2014 г. 11:25:46
Комментарии

-10 за этот ответ. Как это может быть лучшим решением, если вы используете query_posts, когда в кодексе указано, что его не следует применять.

Pieter Goosen Pieter Goosen
21 мая 2014 г. 11:31:30

но это работает. значит альтернатива — WP_Query или что?

Kent Miller Kent Miller
21 мая 2014 г. 12:22:49

Да, следует использовать WP_Query, как в предыдущих ответах.

Pieter Goosen Pieter Goosen
21 мая 2014 г. 12:27:09

@KentMiller, на странице кодекса есть информативная диаграмма, а также вам может быть полезен этот вопрос. Определенно стоит ознакомиться с этими соглашениями.

Jodi Warren Jodi Warren
21 мая 2014 г. 13:56:19