Вопрос или проблема
У меня есть проект, в котором есть два типа записей: “Адвокат” и “Запись” (Запись – это тип записи по умолчанию, который идет с WordPress). “Адвокат” предназначен для нашей рассылки, а “Запись” – для наших новостных бюллетеней.
Я пытаюсь сделать так, чтобы работали ссылки на следующие/предыдущие записи.
Обычно они работают только с типом записи “запись”, но я хочу, чтобы они работали с обоими типами записей “Адвокат” и “Запись”.
Я слышал, что для этого нужно переопределить часть запроса с помощью фильтра:
add_filter( "get_next_post_where", function($where, $in_same_term, $excluded_terms, $taxonomy, $post){
//echo "<br />Старый запрос (следующий): " . $where . "<br />";
$newWhere = str_replace(
array( "p.post_type="advocate"", "p.post_type="post"" ),
"(p.post_type="advocate" OR p.post_type="post")",
$where
);
echo "SQLNext: " . $newWhere;
echo "<br />";
return $newWhere;
}, 10, 5);
add_filter( "get_previous_post_where", function($where, $in_same_term, $excluded_terms, $taxonomy, $post){
//echo "<br />Старый запрос (предыдущий): " . $where . "<br />";
$newWhere = str_replace(
array( "p.post_type="advocate"", "p.post_type="post"" ),
"(p.post_type="advocate" OR p.post_type="post")",
$where
);
echo "SQLPrevious: " . $newWhere;
echo "<br />";
return $newWhere;
}, 10, 5);
Я добавил вывод информации, чтобы проверить, что изменяется, и убедиться, что это выглядит правильно.
Вот пример вывода для двух зарегистрированных фильтров:
SQLPrevious: WHERE p.post_date < '2024-04-14 11:00:00' AND (p.post_type="advocate" OR (p.post_type="advocate" OR p.post_type="post")) AND ( p.post_status="publish" OR p.post_status="private" )
SQLNext: WHERE p.post_date > '2024-04-14 11:00:00' AND (p.post_type="advocate" OR (p.post_type="advocate" OR p.post_type="post")) AND ( p.post_status="publish" OR p.post_status="private" )
Изображение выше взято со страницы facetWP, которая возвращает как адвокатов, так и записи. Второй элемент – это Адвокат, а остальные – это обычные записи (бюллетени).
Если вы посмотрите на адвоката внизу, он показывает следующие и предыдущие бюллетени (тип записи “запись”), как и должно быть, но если вы перейдете к статье “Сообщество Ла Орожи выигрывает выдающееся судебное решение”, следующей статьей должна быть “Тестовый адвокат”, но она пропускается и идет сразу к “Местные голоса на Всемирном конгрессе рыбного хозяйства”.
Кажется, что если смотреть на бюллетень, система просто не видит адвокатов.
Чтобы получить навигацию по предыдущим/следующим записям в файле single-advocate.php, я вывожу эту функцию внизу страницы:
echo blocksy_post_navigation();
blocksy_post_navigation – это функция, которая идет с темой Blocksy, и вместо того, чтобы просто создавать ссылки на предыдущие/следующие записи, она создает симпатичные ссылки с изображениями.
/**
* Вывод навигации по записям.
*/
if (! function_exists('blocksy_post_navigation')) {
function blocksy_post_navigation() {
$prefix = blocksy_manager()->screen->get_prefix();
$next_post = apply_filters(
'blocksy:post-navigation:next-post',
get_adjacent_post(false, '', true)
);
$previous_post = apply_filters(
'blocksy:post-navigation:previous-post',
get_adjacent_post(false, '', false)
);
$post_nav_criteria = blocksy_get_theme_mod($prefix . '_post_nav_criteria', 'default');
if ($post_nav_criteria !== 'default') {
$post_type = get_post_type();
$post_nav_taxonomy_default = array_keys(blocksy_get_taxonomies_for_cpt(
$post_type
))[0];
$post_nav_taxonomy = blocksy_get_theme_mod(
$prefix . '_post_nav_taxonomy',
$post_nav_taxonomy_default
);
$next_post = apply_filters(
'blocksy:post-navigation:next-post',
get_adjacent_post(true, '', true, $post_nav_taxonomy)
);
$previous_post = apply_filters(
'blocksy:post-navigation:previous-post',
get_adjacent_post(true, '', false, $post_nav_taxonomy)
);
}
if (! $next_post && ! $previous_post) {
return '';
}
$title_class="item-title";
$title_class .= ' ' . blocksy_visibility_classes(blocksy_get_theme_mod(
$prefix . '_post_nav_title_visibility',
[
'desktop' => true,
'tablet' => true,
'mobile' => false,
]
));
$thumb_size = blocksy_get_theme_mod($prefix . '_post_nav_thumb_size', 'medium');
$thumb_class="";
$thumb_class .= ' ' . blocksy_visibility_classes(blocksy_get_theme_mod(
$prefix . '_post_nav_thumb_visibility',
[
'desktop' => true,
'tablet' => true,
'mobile' => true,
]
));
$container_class="post-navigation ct-constrained-width";
$container_class .= ' ' . blocksy_visibility_classes(blocksy_get_theme_mod(
$prefix . '_post_nav_visibility',
[
'desktop' => true,
'tablet' => true,
'mobile' => true,
]
));
$home_page_url = get_home_url();
$post_slug = get_post_type_object(get_post_type())->labels->singular_name;
$post_slug = '<span>' . $post_slug . '</span>';
$next_post_image_output="";
$previous_post_image_output="";
if ($next_post) {
$next_title="";
$next_title = $next_post->post_title;
if (get_post_thumbnail_id($next_post)) {
$next_post_image_output = blocksy_media(
[
'attachment_id' => get_post_thumbnail_id($next_post),
'post_id' => $next_post->ID,
'ratio' => '1/1',
'size' => $thumb_size,
'class' => $thumb_class,
'inner_content' => '<svg width="20px" height="15px" viewBox="0 0 20 15" fill="#ffffff"><polygon points="0,7.5 5.5,13 6.4,12.1 2.4,8.1 20,8.1 20,6.9 2.4,6.9 6.4,2.9 5.5,2 "/></svg>',
'tag_name' => 'figure'
]
);
}
}
if ($previous_post) {
$previous_title="";
$previous_title = $previous_post->post_title;
if (get_post_thumbnail_id($previous_post)) {
$previous_post_image_output = blocksy_media(
[
'attachment_id' => get_post_thumbnail_id($previous_post),
'post_id' => $previous_post->ID,
'ratio' => '1/1',
'size' => $thumb_size,
'class' => $thumb_class,
'inner_content' => '<svg width="20px" height="15px" viewBox="0 0 20 15" fill="#ffffff"><polygon points="14.5,2 13.6,2.9 17.6,6.9 0,6.9 0,8.1 17.6,8.1 13.6,12.1 14.5,13 20,7.5 "/></svg>',
'tag_name' => 'figure'
]
);
}
}
$prefix = blocksy_manager()->screen->get_prefix();
$deep_link_args = [
'prefix' => $prefix,
'suffix' => $prefix . '_has_post_nav'
];
ob_start();
?>
<nav class="<?php echo esc_attr( $container_class ); ?>" <?php echo blocksy_generic_get_deep_link($deep_link_args); ?>>
<?php if ($next_post) { ?>
<a href="<?php echo esc_url(get_permalink($next_post)); ?>" class="nav-item-prev">
<?php
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo $next_post_image_output;
?>
<div class="item-content">
<span class="item-label">
<?php
echo wp_kses_post(blocksy_safe_sprintf(
apply_filters(
'blocksy:post-navigation:previous-post:label',
// translators: post title
//__('Предыдущий %s', 'blocksy')
__('Предыдущая запись', 'blocksy')
),
$post_slug
));
?>
</span>
<?php if ( ! empty( $next_title ) ) { ?>
<span class="<?php echo esc_attr( $title_class ); ?>">
<?php echo wp_kses_post($next_title); ?>
</span>
<?php } ?>
</div>
</a>
<?php } else { ?>
<div class="nav-item-prev"></div>
<?php } ?>
<?php if ($previous_post) { ?>
<a href="<?php echo esc_url(get_permalink($previous_post)); ?>" class="nav-item-next">
<div class="item-content">
<span class="item-label">
<?php
echo wp_kses_post(blocksy_safe_sprintf(
apply_filters(
'blocksy:post-navigation:next-post:label',
// translators: post title
//__('Следующий %s', 'blocksy')
__('Следующая запись', 'blocksy')
),
$post_slug
));
?>
</span>
<?php if ( ! empty( $previous_title ) ) { ?>
<span class="<?php echo esc_attr( $title_class ); ?>">
<?php echo wp_kses_post($previous_title); ?>
</span>
<?php } ?>
</div>
<?php
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo $previous_post_image_output;
?>
</a>
<?php } else { ?>
<div class="nav-item-next"></div>
<?php } ?>
</nav>
<?php
return ob_get_clean();
}
}
Также, если я создаю нового Адвоката и ставлю его хронологически рядом с другим Адвокатом, то его навигация показывает только бюллетени. Кажется, что навигация по предыдущим/следующим записям игнорирует мой фильтр, чтобы также включать тип записи адвокат.
Любая помощь в том, как включить моего адвоката, когда система создает ссылки на предыдущие/следующие записи, будет очень ценна.
Ответ или решение
Проблема, с которой вы столкнулись при настройке навигации между записями в WordPress для нескольких типов записей, таких как "Advocate" и "Post", часто возникает из-за особенности работы функции get_adjacent_post()
. Эта функция по умолчанию фильтрует записи только по одному типу, что может привести к нежелательным результатам в вашей навигации.
Анализ проблемы
На основании описанного вами кода, необходимость кастомизации фильтра get_next_post_where
и get_previous_post_where
очевидна. Вы уже правильно используете str_replace
для модификации SQL-запроса, однако есть несколько моментов, которые стоит проверить и улучшить.
Пример исправленного кода
Обратите внимание, что дублирование условий, как, например в вашем случае с p.post_type="advocate"
в строке условия, может создавать неэффективные запросы. Вместо этого можно использовать конструкцию, которая более четко формулирует запрос:
add_filter("get_next_post_where", function($where, $in_same_term, $excluded_terms, $taxonomy, $post){
$newWhere = str_replace(
array('p.post_type="advocate"', 'p.post_type="post"'),
'(p.post_type="advocate" OR p.post_type="post")',
$where
);
return $newWhere;
}, 10, 5);
add_filter("get_previous_post_where", function($where, $in_same_term, $excluded_terms, $taxonomy, $post){
$newWhere = str_replace(
array('p.post_type="advocate"', 'p.post_type="post"'),
'(p.post_type="advocate" OR p.post_type="post")',
$where
);
return $newWhere;
}, 10, 5);
Рекомендации по отладке
-
Логи SQL-запросов: Поскольку вы уже добавили вывод SQL-запросов, убедитесь, что они корректны и что измененное условие действительно включается в запрос. Особенно внимательно следите за тем, как формируется финальное SQL-выражение.
-
Проверка наличия постов: Убедитесь, что у вас действительно есть записи обоих типов, находящихся рядом друг с другом по времени публикации. Если записи создаются в неправильной последовательности или с неправильными датами, это также может привести к трудностям в навигации.
-
Использование функции
get_adjacent_post
: Убедитесь, что параметры этой функции вызываются правильно вblocksy_post_navigation()
. Вы можете попробовать передатьfalse
в качестве третьего аргумента, чтобы убрать фильтрацию по терминам таксономии, что может улучшить ситуацию.
Заключение
Если после внесённых изменений проблема остается актуальной, стоит рассмотреть возможность использования функции wp_get_recent_posts()
для получения списка записей обоих типов и реализации навигации на основе этого списка. Такой подход позволит избежать потенциальных проблем с запросами SQL и наладить работу навигации.
Также рекомендуется протестировать обновленные функции в локальной среде или на тестовом сервере, прежде чем применять изменения на рабочем сайте. Это даст вам возможность удостовериться в правильности работы всех компонентов.
Если потребуется дополнительная помощь, не стесняйтесь задавать вопросы. Удачи в доработке вашей функциональности WordPress!