Вопрос или проблема
У меня проблема с вложенной постоянной ссылкой. У меня есть структура URL следующего вида:
Каталог -> Категория -> Продукт
Мои URL:
www.domain.com/catalogs
(для архива каталогов)www.domain.com/catalogs/%catalog%
(для страницы отдельного каталога со списком категорий)www.domain.com/catalogs/%catalog%/%category%
(для страницы отдельной категории со списком продуктов)www.domain.com/catalogs/%catalog%/%category%/%product%
(для страницы отдельного продукта)
В админке WP и на сайте все URL корректны, единственная проблема, которая у меня есть, это когда я посещаю страницу продукта, например:
www.domain.com/catalogs/catalog-001/category-001/product-001
Там я получаю ошибку 404. Мой код следующий:
add_action( 'init', 'ab_create_catalog_taxonomy' );
function ab_create_catalog_taxonomy() {
$labels = array(
'name' => _x( 'Каталоги', 'название таксономии', 'autoblok' ),
'singular_name' => _x( 'Каталог', 'единственное название таксономии', 'autoblok' ),
'search_items' => __( 'Поиск каталогов', 'autoblok' ),
'all_items' => __( 'Все каталоги', 'autoblok' ),
'parent_item' => __( 'Родительский каталог', 'autoblok' ),
'parent_item_colon' => __( 'Родительский каталог:', 'autoblok' ),
'edit_item' => __( 'Редактировать каталог', 'autoblok' ),
'update_item' => __( 'Обновить каталог', 'autoblok' ),
'add_new_item' => __( 'Добавить новый каталог', 'autoblok' ),
'new_item_name' => __( 'Новое название каталога', 'autoblok' ),
'menu_name' => __( 'Каталог', 'autoblok' ),
);
$args = array(
'labels' => $labels,
'hierarchical' => false,
'public' => true,
'show_ui' => true,
'show_admin_column' => true,
'show_in_nav_menus' => true,
'show_tagcloud' => false,
'query_var' => true,
'rewrite' => array(
'slug' => 'catalogs',
),
);
register_taxonomy( 'catalog', array( 'category', 'product' ), $args );
}
add_action( 'init', 'ab_create_category_post_type' );
function ab_create_category_post_type() {
$labels = array(
'name' => _x( 'Категории', 'Общее название типа записи', 'autoblok' ),
'singular_name' => _x( 'Категория', 'Единственное название типа записи', 'autoblok' ),
'add_new' => __( 'Добавить новую', 'autoblok' ),
'add_new_item' => __( 'Добавить новую категорию', 'autoblok' ),
'edit_item' => __( 'Редактировать категорию', 'autoblok' ),
'new_item' => __( 'Новая категория', 'autoblok' ),
'view_item' => __( 'Просмотреть категорию', 'autoblok' ),
'view_items' => __( 'Просмотреть категории', 'autoblok' ),
'search_items' => __( 'Поиск категории', 'autoblok' ),
'all_items' => __( 'Все категории', 'autoblok' )
);
$args = array(
'label' => __( 'категории', 'autoblok' ),
'description' => __( 'Список категорий', 'autoblok' ),
'labels' => $labels,
'supports' => array(
'title',
'custom-fields'
),
'hierarchical' => true,
'public' => true,
'can_export' => true,
'has_archive' => true,
'menu_position' => 20,
'exclude_from_search' => false,
'capability_type' => 'page',
'rewrite' => array(
'slug' => __( 'catalogs/%catalog%', 'autoblok' ),
),
);
register_post_type( 'category', $args );
}
add_action( 'init', 'ab_create_product_post_type' );
function ab_create_product_post_type() {
$labels = array(
'name' => _x( 'Продукты', 'Общее название типа записи', 'autoblok' ),
'singular_name' => _x( 'Продукт', 'Единственное название типа записи', 'autoblok' ),
'add_new' => __( 'Добавить новый', 'autoblok' ),
'add_new_item' => __( 'Добавить новый продукт', 'autoblok' ),
'edit_item' => __( 'Редактировать продукт', 'autoblok' ),
'new_item' => __( 'Новый продукт', 'autoblok' ),
'view_item' => __( 'Просмотреть продукт', 'autoblok' ),
'view_items' => __( 'Просмотреть продукты', 'autoblok' ),
'search_items' => __( 'Поиск продукта', 'autoblok' ),
'all_items' => __( 'Все продукты', 'autoblok' )
);
$args = array(
'label' => __( 'продукты', 'autoblok' ),
'description' => __( 'Список продуктов', 'autoblok' ),
'labels' => $labels,
'supports' => array(
'title',
'custom-fields'
),
'hierarchical' => false,
'public' => true,
'can_export' => true,
'has_archive' => true,
'menu_position' => 20,
'exclude_from_search' => false,
'capability_type' => 'page',
'rewrite' => array(
'slug' => __( 'catalogs/%catalog%/%category%', 'autoblok' ),
),
);
register_post_type( 'product', $args );
}
add_filter( 'post_type_link', 'ab_category_post_link', 1, 3 );
// Перезапись URL категории
function ab_category_post_link( $post_link, $post ) {
if ( is_object( $post ) && $post->post_type === 'category' ) {
$terms = wp_get_object_terms( $post->ID, 'catalog' );
if ( $terms ) {
return str_replace( '%catalog%', $terms[0]->slug, $post_link );
}
}
return $post_link;
}
add_action( 'add_meta_boxes', 'ab_product_meta_boxes' );
function ab_product_meta_boxes() {
add_meta_box( 'product-parent', 'Категория', 'ab_product_attributes_meta_box', 'product', 'side', 'high' );
}
function ab_product_attributes_meta_box( $post ) {
$pages = wp_dropdown_pages( array(
'post_type' => 'category',
'selected' => $post->post_parent,
'name' => 'parent_id',
'show_option_none' => __( '(без родителя)' ),
'sort_column' => 'menu_order, post_title',
'echo' => 0
) );
if ( ! empty( $pages ) ) {
echo $pages;
}
}
add_filter( 'post_type_link', 'ab_product_post_link', 10, 3 );
function ab_product_post_link( $post_link, $post ) {
if ( is_object( $post ) && $post->post_type === 'product' ) {
$parent = $post->post_parent;
$parent_post = get_post( $parent );
$terms = wp_get_post_terms( $post->ID, 'catalog' );
if ( $terms ) {
$post_link = str_replace( '%catalog%', $terms[0]->slug, $post_link );
}
$post_link = str_replace( '%category%', $parent_post->post_name, $post_link );
}
return $post_link;
}
Вот мой .htaccess:
# НАЧАЛО WordPress
RewriteEngine On
RewriteBase /wordpress/
RewriteRule ^index\.php$ - [L]
# добавление завершающего слеша для /wp-admin
RewriteRule ^([_0-9a-zA-Z-]+/)?wp-admin$ $1wp-admin/ [R=301,L]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) $2 [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(.*\.php)$ $2 [L]
RewriteRule . index.php [L]
# КОНЕЦ WordPress
ОБНОВЛЕНИЕ
Вот изображение из плагина “Rewrite Analyzer”:
Я нашёл решение, спасибо плагину:
Monkeyman Rewrite Rule
С помощью этого плагина я обнаружил, когда правило не работало, затем я исправил это с помощью следующих строк кода:
add_action( 'init', 'ab_category_rewrite_rules' );
function ab_category_rewrite_rules() {
add_rewrite_tag( '%category%', '([^/]+)', 'category=' );
add_permastruct( 'category', '/catalogs/%catalog%/%category%', false );
add_rewrite_rule( '^category/([^/]+)/([^/]+)/?$', 'index.php?category=$matches[2]', 'top' );
}
add_action( 'init', 'ab_product_rewrite_rules' );
function ab_product_rewrite_rules() {
add_rewrite_tag( '%product%', '([^/]+)', 'product=' );
add_permastruct( 'product', '/catalogs/%catalog%/%category%/%product%', false );
add_rewrite_rule( '^product/([^/]+)/([^/]+)/?$', 'index.php?product=$matches[2]', 'top' );
}
Я также удалил конфигурацию опции rewrite
в функции регистрации моих кастомных типов постов (для категории и продукта).
Ответ или решение
Ваша задача заключается в настройке вложенных URL для пользовательского типа записей в WordPress. Вы уже на правильном пути, но вам нужно внести некоторые коррективы, чтобы избежать ошибок 404 при доступе к страницам продуктов. Давайте разберёмся с вашим кодом и приведём его в порядок.
Шаг 1: Регистрация пользовательских типов записей и таксономий
Вы зарегистрировали пользовательские типы записей для категорий и продуктов, а также таксономию для каталогов. Однако в вашей конфигурации были ошибки в определении rewrite
. Вам следует удалить rewrite
параметр из функции регистрации типов записей и разрешить создание пользовательских ссылок через фильтры.
Шаг 2: Добавление собственных ЧПУ и правил перезаписи
Вам будет полезно использовать функцию add_rewrite_rule
для указания схемы URL. Вот обновленный код:
add_action( 'init', function() {
// Регистрируем таксономию для каталогов
// ...
// Регистрируем пользовательский тип записей для категорий
// ...
// Регистрируем пользовательский тип записей для продуктов
// ...
add_rewrite_tag('%catalog%', '([^/]+)');
add_rewrite_tag('%category%', '([^/]+)');
add_rewrite_tag('%product%', '([^/]+)');
add_permastruct('category', '/catalogs/%catalog%/%category%', false);
add_permastruct('product', '/catalogs/%catalog%/%category%/%product%', false);
// Правила для категорий
add_rewrite_rule('^catalogs/([^/]+)/([^/]+)/?$', 'index.php?category=$matches[2]', 'top');
// Правила для продуктов
add_rewrite_rule('^catalogs/([^/]+)/([^/]+)/([^/]+)/?$', 'index.php?product=$matches[3]', 'top');
});
Шаг 3: Настройка ссылок на записи
После установления правил перезаписи, убедитесь в том, что ссылки на ваши категории и продукты корректно ссылаются на эти идентификаторы. Обновите команды для формирования ссылок для категорий и продуктов:
add_filter('post_type_link', 'ab_category_post_link', 1, 3);
function ab_category_post_link($post_link, $post) {
if (is_object($post) && $post->post_type === 'category') {
$terms = wp_get_object_terms($post->ID, 'catalog');
if ($terms) {
return str_replace('%catalog%', $terms[0]->slug, $post_link);
}
}
return $post_link;
}
add_filter('post_type_link', 'ab_product_post_link', 10, 3);
function ab_product_post_link($post_link, $post) {
if (is_object($post) && $post->post_type === 'product') {
$parent = $post->post_parent;
$parent_post = get_post($parent);
$terms = wp_get_post_terms($post->ID, 'catalog');
if ($terms) {
$post_link = str_replace('%catalog%', $terms[0]->slug, $post_link);
}
if ($parent_post) {
$post_link = str_replace('%category%', $parent_post->post_name, $post_link);
}
}
return $post_link;
}
Шаг 4: Обновление постоянных ссылок
После внесения этих изменений вам необходимо обновить настройки постоянных ссылок. Перейдите в административную панель WordPress в Настройки
-> Постоянные ссылки
и просто нажмите Сохранить изменения
. Это обновит правила перезаписи и устранит возможные проблемы с 404 ошибками.
Заключение
Эти изменения должны помочь устранить ошибки 404 для продуктов на вашем сайте WordPress и обеспечить правильную вложенность URL. Если у вас останутся вопросы или возникнут другие трудности, не стесняйтесь задавать их!