Добавление категорий в пользовательский тип записи в постоянной ссылке
Я знаю, что люди уже задавали этот вопрос и дошли до добавления пользовательского типа записи и перезаписи для постоянной ссылки.
Проблема в том, что у меня есть 340 существующих категорий, которые я хотел бы продолжать использовать. Раньше я мог видеть /category/subcategory/postname
Теперь у меня есть слаг customposttype/postname. Выбранная категория больше не отображается в постоянной ссылке... Я не менял настройки постоянных ссылок в админке.
Может быть, я что-то упускаю или нужно что-то добавить в этот код?
function jcj_club_post_types() {
register_post_type( 'jcj_club', array(
'labels' => array(
'name' => __( 'Джаз-клубы' ),
'singular_name' => __( 'Джаз-клуб' ),
'add_new' => __( 'Добавить новый' ),
'add_new_item' => __( 'Добавить новый джаз-клуб' ),
'edit' => __( 'Редактировать' ),
'edit_item' => __( 'Редактировать джаз-клубы' ),
'new_item' => __( 'Новый джаз-клуб' ),
'view' => __( 'Просмотреть джаз-клуб' ),
'view_item' => __( 'Просмотреть джаз-клуб' ),
'search_items' => __( 'Поиск джаз-клубов' ),
'not_found' => __( 'Джаз-клубы не найдены' ),
'not_found_in_trash' => __( 'В корзине джаз-клубы не найдены' ),
'parent' => __( 'Родительский джаз-клуб' ),
),
'public' => true,
'show_ui' => true,
'publicly_queryable' => true,
'exclude_from_search' => false,
'menu_position' => 5,
'query_var' => true,
'supports' => array(
'title',
'editor',
'comments',
'revisions',
'trackbacks',
'author',
'excerpt',
'thumbnail',
'custom-fields',
),
'rewrite' => array( 'slug' => 'jazz-clubs-in', 'with_front' => true ),
'taxonomies' => array( 'category','post_tag'),
'can_export' => true,
)
);
При добавлении пользовательских правил перезаписи (rewrite rules) для типов записей необходимо учитывать два ключевых момента:
Правила перезаписи
Это происходит при генерации правил перезаписи в файле wp-includes/rewrite.php
, в методе WP_Rewrite::rewrite_rules()
. WordPress позволяет фильтровать правила перезаписи для отдельных элементов, таких как записи, страницы и различные типы архивов. Там, где вы видите posttype_rewrite_rules
, часть posttype
должна быть заменена на имя вашего пользовательского типа записи. Альтернативно можно использовать фильтр post_rewrite_rules
, главное не перезаписать стандартные правила для обычных записей.
Далее нам понадобится функция для генерации правил перезаписи:
// добавляем новую структуру постоянных ссылок к правилам перезаписи
add_filter( 'posttype_rewrite_rules', 'add_permastruct' );
function add_permastruct( $rules ) {
global $wp_rewrite;
// задаем желаемую структуру постоянных ссылок
$struct = '/%category%/%year%/%monthnum%/%postname%/';
// используем функцию WordPress для генерации правил перезаписи
$rules = $wp_rewrite->generate_rewrite_rules(
$struct, // структура постоянных ссылок
EP_PERMALINK, // Маска конечной точки: добавляет правила для конечных точек отдельных записей (страницы комментариев и т.д.)
false, // Пагинация: добавлять ли правила для разбивки на страницы (например, для архивов) - здесь не нужно
true, // Ленты: добавлять ли правила для RSS-лент
true, // Для комментариев: должны ли правила лент относиться к комментариям записи
false, // Обход директорий: генерировать ли правила для каждого сегмента структуры, разделенного '/'. Всегда false, иначе правила будут слишком жадными
true // Добавлять пользовательские конечные точки
);
return $rules;
}
Основной момент, на который стоит обратить внимание при настройке - это параметр 'Walk directories' (Обход директорий). Он генерирует правила перезаписи для каждого сегмента структуры и может вызвать несоответствия. Когда WordPress обрабатывает URL, правила проверяются сверху вниз, и первое совпадение определяет дальнейшую обработку. Например, для структуры /%category%/%postname%/
с включенным обходом будут созданы правила как для /%category%/%postname%/
, так и для /%category%/
, что приведет к избыточным совпадениям. Если это произойдет слишком рано, возникнут проблемы.
Постоянные ссылки
Эта функция преобразует структуру постоянных ссылок (например, '/%year%/%monthnum%/%postname%/') в реальный URL.
Следующий код представляет упрощенный вариант функции get_permalink()
из файла wp-includes/link-template.php
. Постоянные ссылки для пользовательских типов записей генерируются функцией get_post_permalink()
, которая является упрощенной версией get_permalink()
. get_post_permalink()
фильтруется через post_type_link
, что позволяет нам создать собственную структуру.
// обрабатываем сгенерированные ссылки
add_filter( 'post_type_link', 'custom_post_permalink', 10, 4 );
function custom_post_permalink( $permalink, $post, $leavename, $sample ) {
// выполняем наши действия только для pretty permalinks
// и только для нужного типа записи
if ( $post->post_type == 'posttype' && get_option( 'permalink_structure' ) ) {
// задаем желаемую структуру постоянных ссылок
// и заменяем плейсхолдеры реальными данными
$struct = '/%category%/%year%/%monthnum%/%postname%/';
$rewritecodes = array(
'%category%',
'%year%',
'%monthnum%',
'%postname%'
);
// получаем данные
$terms = get_the_terms($post->ID, 'category');
$unixtime = strtotime( $post->post_date );
// код из get_permalink()
$category = '';
if ( strpos($permalink, '%category%') !== false ) {
$cats = get_the_category($post->ID);
if ( $cats ) {
usort($cats, '_usort_terms_by_ID'); // сортировка по ID
$category = $cats[0]->slug;
if ( $parent = $cats[0]->parent )
$category = get_category_parents($parent, false, '/', true) . $category;
}
// используем рубрику по умолчанию, если не задана явно
if ( empty($category) ) {
$default_category = get_category( get_option( 'default_category' ) );
$category = is_wp_error( $default_category ) ? '' : $default_category->slug;
}
}
$replacements = array(
$category,
date( 'Y', $unixtime ),
date( 'm', $unixtime ),
$post->post_name
);
// формируем окончательную ссылку
$permalink = home_url( str_replace( $rewritecodes, $replacements, $struct ) );
$permalink = user_trailingslashit($permalink, 'single');
}
return $permalink;
}
Это упрощенный пример для создания пользовательских правил перезаписи и постоянных ссылок. Он не отличается гибкостью, но дает основу для дальнейшей работы.
Обходной путь
Я создал плагин, который позволяет определять структуру постоянных ссылок для любых пользовательских типов записей. Подобно тому, как %category%
работает для обычных записей, мой плагин поддерживает %название_таксономии%
для любых пользовательских таксономий, например %club%
.
Плагин работает как с иерархическими, так и с неиерархическими таксономиями.

плагин отличный, но не могли бы вы объяснить, как исправить проблему в вопросе без вашего плагина?

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

@EugeneManuilov Хорошо, извините за длинный ответ. И это после того, как я сократил его до основного!

Похоже, что первый $permalink = home_url(...
перезаписывается $permalink = user_trailingslashit(...
и никогда не используется. Или я что-то упускаю? $post_link
даже не определен. Возможно, должно было быть $permalink = user_trailingslashit( $permalink, 'single' );
?

Хорошее замечание, должно быть $permalink
, а не $post_link
. Спасибо :)

Я НАШЕЛ РЕШЕНИЕ!!!
(После бесконечных поисков... Я могу получить ЧПУ для ПРОИЗВОЛЬНОГО ТИПА ЗАПИСЕЙ в таком виде:
example.com/category/sub_category/my-post-name
Вот код (в functions.php или плагине):
//===ШАГ 1 (затронет только эти ПРОИЗВОЛЬНЫЕ ТИПЫ ЗАПИСЕЙ)
$GLOBALS['my_post_typesss__MLSS'] = array('my_product1','....');
//===ШАГ 2 (создаем желаемые ЧПУ)
add_filter('post_type_link', 'my_func88888', 6, 4 );
function my_func88888( $post_link, $post, $sdsd){
if (!empty($post->post_type) && in_array($post->post_type, $GLOBALS['my_post_typesss']) ) {
$SLUGG = $post->post_name;
$post_cats = get_the_category($id);
if (!empty($post_cats[0])){ $target_CAT= $post_cats[0];
while(!empty($target_CAT->slug)){
$SLUGG = $target_CAT->slug .'/'.$SLUGG;
if (!empty($target_CAT->parent)) {$target_CAT = get_term( $target_CAT->parent, 'category');} else {break;}
}
$post_link= get_option('home').'/'. urldecode($SLUGG);
}
}
return $post_link;
}
// ШАГ 3 (по умолчанию, при обращении к "EXAMPLE.COM/category/postname"
// WP считает, что запрашивается стандартная запись. Поэтому мы добавляем ПРОИЗВОЛЬНЫЙ ТИП ЗАПИСИ
// в этот запрос.
add_action('pre_get_posts', 'my_func4444', 12);
function my_func4444($q){
if ($q->is_main_query() && !is_admin() && $q->is_single){
$q->set( 'post_type', array_merge(array('post'), $GLOBALS['my_post_typesss'] ) );
}
return $q;
}

Решение найдено!
Для создания иерархических постоянных ссылок для произвольного типа записей установите плагин Custom Post Type Permalinks(https://wordpress.org/plugins/custom-post-type-permalinks/).
Обновите регистрацию типа записи. У меня тип записи называется Help Center
function help_centre_post_type(){
register_post_type('helpcentre', array(
'labels' => array(
'name' => __('Центр помощи'),
'singular_name' => __('Центр помощи'),
'all_items' => __('Просмотреть записи'),
'add_new' => __('Новая запись'),
'add_new_item' => __('Новый центр помощи'),
'edit_item' => __('Редактировать центр помощи'),
'view_item' => __('Просмотреть центр помощи'),
'search_items' => __('Искать в центре помощи'),
'no_found' => __('Записи центра помощи не найдены'),
'not_found_in_trash' => __('В корзине нет записей центра помощи')
),
'public' => true,
'publicly_queryable'=> true,
'show_ui' => true,
'query_var' => true,
'show_in_nav_menus' => false,
'capability_type' => 'page',
'hierarchical' => true,
'rewrite'=> [
'slug' => 'help-center',
"with_front" => false
],
"cptp_permalink_structure" => "/%help_centre_category%/%post_id%-%postname%/",
'menu_position' => 21,
'supports' => array('title','editor', 'thumbnail'),
'has_archive' => true
));
flush_rewrite_rules();
}
add_action('init', 'help_centre_post_type');
А вот регистрация таксономии
function themes_taxonomy() {
register_taxonomy(
'help_centre_category',
'helpcentre',
array(
'label' => __( 'Категории' ),
'rewrite'=> [
'slug' => 'help-center',
"with_front" => false
],
"cptp_permalink_structure" => "/%help_centre_category%/",
'hierarchical' => true,
'public' => true,
'show_ui' => true,
'show_admin_column' => true,
'show_in_nav_menus' => true,
'query_var' => true
)
);
}
add_action( 'init', 'themes_taxonomy');
Эта строка делает ваши постоянные ссылки рабочими
"cptp_permalink_structure" => "/%help_centre_category%/%post_id%-%postname%/",
Вы можете удалить %post_id%
и оставить /%help_centre_category%/%postname%/"
Не забудьте сбросить постоянные ссылки в админ-панели.

+1 самое простое решение — просто использовать этот плагин: https://wordpress.org/plugins/custom-post-type-permalinks/ работает идеально

У вас есть несколько ошибок в коде. Я исправил ваш существующий код:
<?php
function jcj_club_post_types() {
$labels = array(
'name' => __( 'Джаз-клубы' ),
'singular_name' => __( 'Джаз-клуб' ),
'add_new' => __( 'Добавить новый' ),
'add_new_item' => __( 'Добавить новый джаз-клуб' ),
'edit' => __( 'Редактировать' ),
'edit_item' => __( 'Редактировать джаз-клубы' ),
'new_item' => __( 'Новый джаз-клуб' ),
'view' => __( 'Просмотреть джаз-клуб' ),
'view_item' => __( 'Просмотреть джаз-клуб' ),
'search_items' => __( 'Искать джаз-клубы' ),
'not_found' => __( 'Джаз-клубы не найдены' ),
'not_found_in_trash' => __( 'В корзине нет джаз-клубов' ),
'parent' => __( 'Родительский джаз-клуб' ),
);
$args = array(
'public' => true,
'show_ui' => true,
'publicly_queryable' => true,
'exclude_from_search' => false,
'menu_position' => 5,
'query_var' => true,
'supports' => array( 'title','editor','comments','revisions','trackbacks','author','excerpt','thumbnail','custom-fields' ),
'rewrite' => array( 'slug' => 'jazz-clubs-in', 'with_front' => true ),
'has_archive' => true
);
register_post_type( 'jcj_club', $args );
}
add_action( 'init','jcj_club_post_types' );
?>
Замените ваш код на код выше и проверьте, работает ли он. Если у вас остались вопросы, ответьте мне, и я постараюсь помочь.
РЕДАКТИРОВАНО:
Я заметил, что забыл добавить 'has_archive' => true
.
