Следующие и предыдущие записи того же родителя

Вопрос или проблема

Я работаю над сайтом для вебкомикса, и у меня настроен собственный тип записи для страниц комиксов. У меня на сайте несколько серий, и каждая страница комикса сделана дочерней записью родителя (один родитель для каждой серии), чтобы они были организованы и чтобы URL имели некоторую структуру. Сейчас я пытаюсь добавить кнопки “Следующий” и “Предыдущий” на каждую страницу комикса, чтобы читатель мог легко перемещаться между ними. В данный момент у меня есть две отдельные, но связанные проблемы.

1. Страницы комиксов используют одинаковое имя и формат URL, только разделенные их родителем. Например, первая страница серии LCC выглядит так:

http://localhost/wordpress/comics/lcc/v01-001/

В то время как первая страница серии HTA выглядит так:

http://localhost/wordpress/comics/hta/v01-001/

WordPress позволяет это на уровне URL/slug, но возникают проблемы при попытке использовать функции следующей и предыдущей записи. Происходит следующее: дети родителя, который был создан первым (в данном случае LCC), имеют приоритет, что работает идеально при перемещении вперед и назад внутри LCC. Однако если я перехожу на страницу из HTA и пытаюсь перемещаться вперед и назад там, меня немедленно выкидывает на страницу с соответствующим slug, но в LCC (то есть, если я нажимаю “следующий” на hta/v01-001, это должно привести к hta/v01-002, но вместо этого ведет к lcc/v01-002 – при этом нажатие “предыдущий” ведет к lcc/v01-001).

Я нашел несколько решений, которые избавляются от функций следующей/предыдущей записи и делают это, увеличивая ID записи, но это не сработает для меня, потому что я настроил пагинацию по порядку в меню, который я изменил на алфавитный (я хочу, чтобы это все работало независимо от номера ID записи). Вот код, который я использовал для этого:

/* === Сортировка пагинации страниц комиксов по алфавиту === */
function filter_next_post_sort($sort) {
    global $post;
    if (get_post_type($post) == 'comic-page') {
        $sort = "ORDER BY p.post_title ASC LIMIT 1";
    }
    else{
        $sort = "ORDER BY p.post_date ASC LIMIT 1";
    }
    return $sort;
}

function filter_next_post_where($where) {
    global $post, $wpdb;
    if (get_post_type($post) == 'comic-page') {
        return $wpdb->prepare("WHERE p.post_title > '%s' AND p.post_type="". get_post_type($post)."" AND p.post_status="publish"",$post->post_title);
    }
    else{
        return $wpdb->prepare( "WHERE p.post_date > '%s' AND p.post_type="". get_post_type($post)."" AND p.post_status="publish"", $post->post_date);
    }
}

function filter_previous_post_sort($sort) {
    global $post;
    if (get_post_type($post) == 'comic-page') {
        $sort = "ORDER BY p.post_title DESC LIMIT 1";
    }
    else{
        $sort = "ORDER BY p.post_date DESC LIMIT 1";
    }
    return $sort;
}

function filter_previous_post_where($where) {
    global $post, $wpdb;
    if (get_post_type($post) == 'comic-page') {
        return $wpdb->prepare("WHERE p.post_title < '%s' AND p.post_type="". get_post_type($post)."" AND p.post_status="publish"",$post->post_title);
    }
    else{
        return $wpdb->prepare( "WHERE p.post_date < '%s' AND p.post_type="". get_post_type($post)."" AND p.post_status="publish"", $post->post_date);
    }
}

add_filter('get_next_post_sort',   'filter_next_post_sort');
add_filter('get_next_post_where',  'filter_next_post_where');
add_filter('get_previous_post_sort',  'filter_previous_post_sort');
add_filter('get_previous_post_where', 'filter_previous_post_where');

А вот мой код для пользовательских записей:

/* === Страница комикса === */
function post_type_comic_page() {

    // Метки
    $labels = array(
        'name' => 'Страницы комиксов',
        'singular_name' => 'Страница комикса',
        'add_new' => 'Добавить новую страницу комикса',
        'add_new_item' => 'Добавить страницу комикса',
        'all_items' => 'Все страницы комиксов',
        'edit_item' => 'Редактировать страницу комикса',
        'not_found' => 'Страницы комиксов не найдены',
        'not_found_in_trash' => 'Страницы комиксов не найдены в корзине',
    );

    // Аргументы
    $args = array(
        'labels' => $labels,
        'public' => true,
        'menu_icon' => 'dashicons-book-alt',
        'hierarchical' => true,
        'exclude_from_search' => false,
        'has_archive' => true,
        'publicly_queryable' => true,
        'rewrite' => array( 'slug' => 'comics', 'with_front' => false ),
        'supports' => array(
            'page-attributes', 'title', 'editor', 'something-else',
        ),
    );

    // Регистрация типа записи "Страницы комиксов"
    register_post_type('comic-page', $args);
}

add_action('init', 'post_type_comic_page');

2. Когда я решу эту проблему, мне также нужно будет ограничить навигацию вперед и назад только для братьев и сестер под одним родителем. То есть после достижения последней страницы LCC, не должно быть перехода на первую страницу HTA и наоборот.

Моя резервная опция для всего этого – просто использовать таксономию серии (которую я настраивал ранее и которая работала), но я пытаюсь устранить как можно больше ненужного кода и необходимых вещей для проверки на каждой странице комикса. Я могу сделать буквально все остальное, что мне нужно, без таксономии только для этого, так что если это вообще возможно сделать с помощью отношений родитель/дочерний, пожалуйста, помогите мне!

Так что я не могу предложить вам полное решение, но вот некоторые моменты, которые, как я думаю, могут помочь:

  1. Получение ID родительской записи: wp_get_post_parent_id()https://developer.wordpress.org/reference/functions/wp_get_post_parent_id/

  2. Получение всех записей с определенным ID родителя. Вот аргументы WP_Query для получения всех записей по ID родителя:

    $args = array(
        'post_parent' => $parentID,
        'posts_per_page' => -1,
        'orderby' => '???'   // вам нужно выбрать, как должны быть упорядочены ваши дочерние записи
    );

Таким образом, вы могли бы использовать приведенный выше код, чтобы найти ID родителя текущей записи, а затем получить всех детей этого родителя – это будут ‘братья и сестры’ текущей записи.

  1. Используйте приведенный выше код, чтобы найти ID следующей/предыдущей записи. Ниже мой совет по коду для чтения всех ‘братских’ записей и определения URL для следующей и предыдущей записи. Что это делает, так это проходит через все братские записи текущей записи, ищет ту, которая перед ней, и ту, которая за ней, чтобы предоставить вам ID записи для предыдущей и следующей записей. Если текущая запись находится в начале, тогда $prevPostID будет false, так что вы можете использовать это, чтобы не отображать ссылку на предыдущую запись. Если текущая запись находится в конце, тогда $nextPostID будет false, так что вы можете предотвратить отображение ссылки на следующую запись.

Это предполагает, что вы создали $args, используя предложение для получения всех детей ID родителя, как указано выше.

$currentID = ?? // предположим, у нас есть текущий ID записи здесь

$wpq = new WP_Query( $args );
if ( $wpg->have_posts() ) {
    $prevPostID = false;
    $nextPostID = false;
    $previousInLoop = false;

    while ( $wpq->have_posts() ) {
        if (get_the_ID() == $currentID) {
            $prevPostID = $previousInLoop;
        }
        if ($previousInLoop == $currentID) {
            $nextPostID = get_the_ID();
            break;
        }
        $previousInLoop = get_the_ID();
    }
}

Это предложение о том, как вы могли бы заставить этот код работать, и это непроверенный код. Я с радостью помогу, если вы его используете и у вас возникнут дальнейшие проблемы.

Обратите внимание, что вы также можете захватить название и URL следующей/предыдущей записи, пока находитесь в цикле, а не искать их позже, но я оставлю это на ваше усмотрение.

Ответ или решение

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

1. Корректное переключение между дочерними страницами

Проблема заключается в том, что перезаписывание слагов страниц комиксов приводит к тому, что WordPress неправильно обрабатывает следующие и предыдущие посты, выталкивая вас из текущей серии в другую. Для решения этого вопроса необходимо модифицировать стандартные функции навигации следующим образом:

Получение ID родителя

Для начала, мы можем использовать функцию wp_get_post_parent_id(), чтобы получить ID родительского поста текущего поста. Это поможет в дальнейшей выборке дочерних постов.

Получение дочерних постов

С помощью WP_Query мы можем получить все дочерние посты конкретного родителя. Вот как это сделать:

$currentID = get_the_ID();
$parentID = wp_get_post_parent_id($currentID);

$args = array(
    'post_parent' => $parentID,
    'posts_per_page' => -1,
    'orderby' => 'menu_order',
    'order' => 'ASC',
);

$siblings_query = new WP_Query($args);

2. Поиск предыдущего и следующего поста

Теперь, зная всех «братьев и сестер» текущего поста, мы можем перебрать их с целью определения предыдущего и следующего поста относительно текущего:

if ($siblings_query->have_posts()) {
    $prevPostID = false;
    $nextPostID = false;
    $previousInLoop = false;

    while ($siblings_query->have_posts()) {
        $siblings_query->the_post();

        if (get_the_ID() == $currentID) {
            $prevPostID = $previousInLoop;
        } elseif ($previousInLoop == $currentID) {
            $nextPostID = get_the_ID();
            break;
        }
        $previousInLoop = get_the_ID();
    }
}

wp_reset_postdata(); // Сброс выборки постов

Визуальная реализация кнопок навигации

Теперь, когда у нас есть IDs предыдущего и следующего постов, мы можем выводить ссылки на них:

if ($prevPostID) {
    echo '<a href="' . get_permalink($prevPostID) . '">Предыдущий</a>';
}

if ($nextPostID) {
    echo '<a href="' . get_permalink($nextPostID) . '">Следующий</a>';
}

Заключение

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

Возможно, в будущем вам также следует рассмотреть использование таксономий для группировки таких постов. Однако на текущий момент предложенное решение с использованием родительских и дочерних постов является эффективным и минимизирует лишнюю сложность в коде.

Оцените материал
Добавить комментарий

Капча загружается...