Перепишите вложенные URL для пользовательского типа записи

Вопрос или проблема

У меня проблема с вложенной постоянной ссылкой. У меня есть структура 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. Если у вас останутся вопросы или возникнут другие трудности, не стесняйтесь задавать их!

Оцените материал
Добавить комментарий

Капча загружается...