Вопрос или проблема
Я работаю над сайтом для вебкомикса, и у меня настроен собственный тип записи для страниц комиксов. У меня на сайте несколько серий, и каждая страница комикса сделана дочерней записью родителя (один родитель для каждой серии), чтобы они были организованы и чтобы 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 и наоборот.
Моя резервная опция для всего этого – просто использовать таксономию серии (которую я настраивал ранее и которая работала), но я пытаюсь устранить как можно больше ненужного кода и необходимых вещей для проверки на каждой странице комикса. Я могу сделать буквально все остальное, что мне нужно, без таксономии только для этого, так что если это вообще возможно сделать с помощью отношений родитель/дочерний, пожалуйста, помогите мне!
Так что я не могу предложить вам полное решение, но вот некоторые моменты, которые, как я думаю, могут помочь:
-
Получение ID родительской записи:
wp_get_post_parent_id()
– https://developer.wordpress.org/reference/functions/wp_get_post_parent_id/ -
Получение всех записей с определенным ID родителя. Вот аргументы WP_Query для получения всех записей по ID родителя:
$args = array(
'post_parent' => $parentID,
'posts_per_page' => -1,
'orderby' => '???' // вам нужно выбрать, как должны быть упорядочены ваши дочерние записи
);
Таким образом, вы могли бы использовать приведенный выше код, чтобы найти ID родителя текущей записи, а затем получить всех детей этого родителя – это будут ‘братья и сестры’ текущей записи.
- Используйте приведенный выше код, чтобы найти 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 следующей/предыдущей записи, пока находитесь в цикле, а не искать их позже, но я оставлю это на ваше усмотрение.
Ответ или решение
Навигация между постами одного родителя в WordPress: Решения для комиксов
В процессе разработки веб-сайта для веб-комиксов возникла необходимость внедрения функции навигации «Предыдущий» и «Следующий» между страницами комиксов. Это особенно важно, когда у вас есть несколько серий комиксов, и каждая страница является дочерним постом к соответствующему родительскому посту. В данной статье мы рассмотрим, как можно решить эту задачу, учитывая два ключевых аспекта.
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>';
}
Заключение
С помощью предложенных выше решений вы сможете создать функционал для навигации между страницами комиксов, который будет работать независимо от идентификаторов постов и обеспечит плавный переход между страницами одной серии. Это не только улучшит удобство навигации на вашем сайте, но и повысит общее качество пользовательского опыта.
Возможно, в будущем вам также следует рассмотреть использование таксономий для группировки таких постов. Однако на текущий момент предложенное решение с использованием родительских и дочерних постов является эффективным и минимизирует лишнюю сложность в коде.