post_type_link
Позволяет изменить ссылку на кастомный пост.
Callback должен вернуть URL.
Фильтр вызывается в конце get_post_permalink(), в файле wp-includes/link-template.php. get_permalink() также использует эту функцию для произвольных типов записей.
При получении ссылок через get_permalink() используется:
- для обычных записей - post_link.
- для страниц - page_link.
- для вложений - attachment_link.
Использование
add_filter( 'post_type_link', 'wp_kama_post_type_link_filter', 10, 4 );
/**
* Function for `post_type_link` filter-hook.
*
* @param string $post_link The post's permalink.
* @param WP_Post $post The post in question.
* @param bool $leavename Whether to keep the post name.
* @param bool $sample Is it a sample permalink.
*
* @return string
*/
function wp_kama_post_type_link_filter( $post_link, $post, $leavename, $sample ){
// filter...
return $post_link;
}
- $post_link(строка)
- Постоянная ссылка записи.
Может быть ЧПУ или URL с GET-параметрами: фильтр применяется в обоих случаях. - $post(WP_Post)
- Объект записи, для которой формируется ссылка.
Проверяйте$post->post_type, чтобы ограничить действие нужным типом. - $leavename(логический)
- Сохранять ли в ЧПУ плейсхолдер
%имя_типа%вместо подстановки слага записи.
Например, приtrueссылка может содержать/books/%book%/.
ПриfalseWordPress подставляет слаг, а для иерархического типа - путь с родительскими записями.
При формировании обычной ссылки с GET-параметрами этот флаг не влияет на результат. - $sample(логический)
- Формируется ли образец постоянной ссылки, например для редактора. Это не проверка режима предпросмотра
is_preview().
ПриtrueWordPress может использовать ЧПУ даже для записи, которой обычно нужна простая ссылка.
get_sample_permalink() временно меняет статус и слаг объекта записи. Поэтому для исключения образцов ссылок проверяйте$sample, а не только$post->post_status.
Примеры
#1 Внешняя ссылка из метаполя
Для опубликованных записей типа resource заменим ссылку значением метаполя external_url.
add_filter( 'post_type_link', 'my_resource_external_link', 10, 4 );
function my_resource_external_link( $post_link, $post, $leavename, $sample ) {
if (
'resource' !== $post->post_type
|| 'publish' !== $post->post_status
|| $leavename
|| $sample
|| 'link' !== get_post_format( $post )
) {
return $post_link;
}
$url = get_post_meta( $post->ID, 'external_url', true );
$url = is_string( $url ) ? esc_url_raw( $url, [ 'http', 'https' ] ) : '';
return $url ?: $post_link;
}
Замена работает только для формата записи link. Тип записи должен поддерживать post-formats, а тема - формат link, если он выбирается в редакторе.
Редирект со старого формата нужно выполнять отдельно на template_redirect. Проверяйте тот же тип, статус, формат и метаполе; предпросмотр исключайте через is_preview().
Для перехода на внешний сайт используется wp_redirect(), после успешного вызова нужен exit.
#2 Перенос GET-параметра в ссылку
Добавим текущий utm_source в ссылки записей типа book. Переносим только выбранный параметр, чтобы случайно не добавить служебные параметры запроса.
add_filter( 'post_type_link', 'my_book_tracking_link', 10, 4 );
function my_book_tracking_link( $post_link, $post, $leavename, $sample ) {
if ( 'book' !== $post->post_type || $leavename || $sample ) {
return $post_link;
}
if ( ! ( $_GET['utm_source'] ?? '' ) ) {
return $post_link;
}
$source = sanitize_text_field( wp_unslash( $_GET['utm_source'] ) );
return add_query_arg( 'utm_source', rawurlencode( $source ), $post_link );
}
add_query_arg() не экранирует результат для HTML. При самостоятельном выводе ссылки в href используйте esc_url().
Учтите, что фильтр действует на все соответствующие вызовы получения ссылки, включая вызовы вне шаблона. Если параметр нужен только конкретной кнопке, добавляйте его при формировании этой кнопки.
#3 Удаление префикса типа записи
Например, можно изменить /team-member/jack/ на /jack/. Однако одной замены строки в post_type_link недостаточно.
Нужно также научить WordPress искать запись нужного типа по новому адресу. Если правила перезаписи уже разобрали адрес в переменную name, основной запрос можно уточнить через pre_get_posts: найти запись с помощью get_page_by_path() и установить её post_type.
Такую обработку ограничивают основным запросом на фронтенде, без явно заданного post_type. Если адрес разобран иначе, например в pagename, потребуется отдельная обработка. Также нужно разрешить конфликты одинаковых слагов со страницами и обычными записями. Универсально удалять префикс без учёта структуры сайта нельзя.
Список изменений
| С версии 3.0.0 | Введена. |
Где вызывается хук
return apply_filters( 'post_type_link', $post_link, $post, $leavename, $sample );