Пользовательские типы записей, таксономии и постоянные ссылки

14 дек. 2010 г., 01:56:21
Просмотры: 22.3K
Голосов: 66

Это сводит меня с ума, и я уверен, что решение простое, но ничего из того, что я ищу, не дает простой структуры (все очень сложно).

У меня есть пользовательский тип записи product_listing и пользовательская таксономия product_cat (которая является иерархической и должна вести себя как категории).

Я просто хочу, чтобы мои URL выглядели так:

mysite.com/products/category1/product-name1 
mysite.com/products/category2/product-name2

Но как бы я ни старался, я получаю пресловутую ошибку 404. Страницы работают нормально, и Записи работают нормально, но мои пользовательские записи не работают корректно. Они отображаются как:

mysite.com/products/product-name1
mysite.com/products/product-name2

Что на самом деле работает! Просто я хочу видеть свою пользовательскую таксономию в URL, плюс я хочу иметь возможность обращаться к шаблону taxonomy.php, который я настроил, переходя по:

mysite.com/products/category1/
mysite.com/products/category2/

Ни один из моих ярлыков не совпадает, и я этого не хочу. Вот часть файла functions.php с типом записи и таксономией:

///// ПОЛЬЗОВАТЕЛЬСКИЕ ТИПЫ ЗАПИСЕЙ /////

// регистрируем новый тип записи
register_post_type( 'product_listing', 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'             => __( 'Родительский товар' ),
    ),
    'description'           => __( 'Здесь вы можете создавать новые товары на вашем сайте.' ),
    'public'                => true,
    'show_ui'               => true,
    'capability_type'       => 'post',
    'publicly_queryable'    => true,
    'exclude_from_search'   => false,
    'menu_position'         => 2,
    'menu_icon'             => get_stylesheet_directory_uri() . '/images/tag_orange.png',
    'hierarchical'          => true,
    '_builtin'              => false, // Это пользовательский тип записи, не встроенный!
    'rewrite'               => array( 'slug' => 'products', 'with_front' => true ),
    'query_var'             => true,
    'supports'              => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'trackbacks', 'custom-fields', 'comments', 'revisions' ),
) );


//подключаемся к действию init и вызываем create_book_taxonomies при его срабатывании
add_action( 'init', 'create_product_taxonomies', 0 );
//add_action('admin_init', 'flush_rewrite_rules');

//создаем две таксономии, жанры и писатели для типа записи "книга"
function create_product_taxonomies() {
    // Добавляем новую таксономию, делаем её иерархической (как категории)
    $labels = array(
        'name'              => _x( 'Категории', 'общее название таксономии' ),
        'singular_name'     => _x( 'Категория', 'единственное название таксономии' ),
        'search_items'      =>  __( 'Поиск категорий' ),
        'all_items'         => __( 'Все категории' ),
        'parent_item'       => __( 'Родительские категории' ),
        'parent_item_colon' => __( 'Родительские категории:' ),
        'edit_item'         => __( 'Редактировать категорию' ), 
        'update_item'       => __( 'Обновить категорию' ),
        'add_new_item'      => __( 'Добавить новую категорию' ),
        'new_item_name'     => __( 'Название новой категории' ),
        'menu_name'         => __( 'Категория' ),
    );  

    register_taxonomy( 'product_cat', array( 'product_listing' ), array(
        'hierarchical'  => true,
        'labels'        => $labels,
        'show_ui'       => true,
        'query_var'     => true,
        //'rewrite'     => true,
        'rewrite'       => array( 'slug' => '%category%', 'with_front' => true ),
    ) );

    // Добавляем новую таксономию, НЕ иерархическую (как метки)
    $labels = array(
        'name'                       => _x( 'Ароматы', 'общее название таксономии' ),
        'singular_name'              => _x( 'Аромат', 'единственное название таксономии' ),
        'search_items'               =>  __( 'Поиск ароматов' ),
        'popular_items'              => __( 'Популярные ароматы' ),
        'all_items'                  => __( 'Все ароматы' ),
        'parent_item'                => null,
        'parent_item_colon'          => null,
        'edit_item'                  => __( 'Редактировать аромат' ), 
        'update_item'                => __( 'Обновить аромат' ),
        'add_new_item'               => __( 'Добавить новый аромат' ),
        'new_item_name'              => __( 'Название нового аромата' ),
        'separate_items_with_commas' => __( 'Разделяйте ароматы запятыми' ),
        'add_or_remove_items'        => __( 'Добавить или удалить ароматы' ),
        'choose_from_most_used'      => __( 'Выбрать из наиболее используемых ароматов' ),
        'menu_name'                  => __( 'Ароматы' ),
    ); 

    register_taxonomy( 'scent', 'product_listing', array(
        'hierarchical'  => false,
        'labels'        => $labels,
        'show_ui'       => true,
        'query_var'     => true,
        //'rewrite'     => array( 'slug' => 'scents' ),
    ) );
}

У меня также есть другая пользовательская таксономия scents, для которой я бы хотел иметь какой-то дружественный URL, но тут я более гибок. Я бы хотел, возможно, получить доступ к списку всех ароматов, перейдя по mysite.com/products/scents, но они не обязательно должны быть привязаны к конкретной категории.

Кто-нибудь может помочь?

0
Все ответы на вопрос 5
9
67

Измените slug в аргументах вашего типа записи на products/%product_cat%, а slug в аргументах таксономии просто на products, затем сбросьте правила перезаписи. Теперь WordPress должен обрабатывать URL вида /products/my-product-cat/post-name/!

Теперь, наконец, нам нужно немного помочь WordPress с генерацией постоянных ссылок (из коробки он не распознает тег %product_cat% в структуре постоянных ссылок):

/**
 * Вставляет slug термина в структуру постоянных ссылок пользовательского типа записи.
 * 
 * @link   http://wordpress.stackexchange.com/a/5313/1685
 * 
 * @param  string  $link
 * @param  WP_Post $post 
 * @return array
 */
function wpse_5308_post_type_link( $link, $post ) {
    if ( $post->post_type === 'product_listing' ) {
        if ( $terms = get_the_terms( $post->ID, 'product_cat' ) )
            $link = str_replace( '%product_cat%', current( $terms )->slug, $link );
    }

    return $link;
}

add_filter( 'post_type_link', 'wpse_5308_post_type_link', 10, 2 );

Один важный момент: этот код просто берет первую категорию товара для записи отсортированную по имени. Если вы назначаете несколько категорий одному товару, я могу легко изменить логику выбора категории для постоянной ссылки.

Дайте мне знать, как у вас получилось, и мы сможем разобраться с остальными вопросами!

14 дек. 2010 г. 03:50:16
Комментарии

Ого, я в восторге! Это СРАБОТАЛО! Наконец-то! Я уже думал, что ничего не поможет!!! Огромное спасибо!!! ............ Теперь, как мне сгенерировать ссылку (что-то вроде the_permalink), чтобы получить URL таксономии отдельно? /products/my-product-cat/

RodeoRamsey RodeoRamsey
14 дек. 2010 г. 05:21:13

Кажется, я разобрался с этим^^^ ............ но теперь застрял на пагинации. Кажется, она ломается при использовании любой пагинации (кастомной или встроенной) — /products/my-product-cat/ выглядит нормально, но /products/my-product-cat/page/2/ возвращает 404 и переключается с taxonomy.php на index.php. Перепробовал все, что нашел, но безрезультатно.

RodeoRamsey RodeoRamsey
14 дек. 2010 г. 08:45:48

Рассмотрите возможность изменения перезаписи одиночных товаров на product/cat-name/product-name? (обратите внимание на единственное число) Проблема в том, что правило перезаписи для пагинации таксономии не срабатывает, потому что его перехватывает более раннее правило для одиночных товаров!

TheDeadMedic TheDeadMedic
14 дек. 2010 г. 12:52:16

Я открыт к этому. Но чтобы разобраться, это означает, что у товаров будет разный URL-путь при просмотре страницы отдельного товара и страницы категории? То есть для товара будет product/cat-name/prod-name, а для категорий — products/cat-name/? Не будет ли это противоречить идее "человеко-понятных" URL? Моим клиентам и так сложно разобраться в админке WordPress, а тут ещё такие нюансы... Если я что-то не так понял, поправьте меня! Может, можно вообще обойтись без префикса, например product-cat/product-name и просто product-cat/. Такое возможно?

RodeoRamsey RodeoRamsey
14 дек. 2010 г. 16:44:44

Вы правильно поняли — но я бы сказал, что это всё же "человеко-понятно", так как есть чёткое различие между архивами (products/) и отдельными элементами (product/). И нет, я бы оставил 'префикс' — он помогает чётко отделить товары от записей и страниц, плюс без него могут возникнуть проблемы с производительностью (например, избыточные правила перезаписи).

TheDeadMedic TheDeadMedic
14 дек. 2010 г. 17:31:53

Хорошо, а если использовать менее похожие термины? Например, product/cat-name/product-name/ для страниц товаров и что-то вроде categories/cat-name/ для архивов категорий? Что нужно изменить в коде выше, чтобы это заработало?

RodeoRamsey RodeoRamsey
14 дек. 2010 г. 19:18:59

Я протестировал плагин, который предложил другой ответ, и он, кажется, работает нормально для /products/cat-name/prod-name/ И /products/cat-name/ ... это жизнеспособный вариант?

RodeoRamsey RodeoRamsey
14 дек. 2010 г. 19:58:26

Возможно, плагин вручную генерирует правила перезаписи в порядке, который работает — единственное, что я бы сделал, это следил за производительностью — используйте <?php timer_stop(true); ?> и <?php echo get_num_queries(); ?> где-нибудь в вашем footer.php и посмотрите, какие средние значения вы получаете при запросе архивов таксономий и отдельных товаров.

TheDeadMedic TheDeadMedic
15 дек. 2010 г. 00:21:48

Ребята, вы нашли способ это исправить? Я попробовал код, который предложил @TheDeadMedic, и плагин, но ни то, ни другое не сработало. Если да, пожалуйста, взгляните на мой вопрос. Спасибо! - http://wordpress.stackexchange.com/questions/40587/shouldnt-this-be-easy-custom-post-type-custom-taxonomy-permalink

fxfuture fxfuture
30 янв. 2012 г. 04:43:40
Показать остальные 4 комментариев
0

Спасибо @TheDeadMechanic, ваш ответ мне помог, но только частично. Я хотел сделать то же самое, о чём спрашивал @RodeoRamsey, но с вложенными категориями (например: mysite.com/products/category1/child-category-1/grandchild-category-1/product-name), и ваше решение для этого не сработало.

В итоге я нашёл расширенное решение для своего вопроса, которое работает, поэтому если кому-то ещё нужны вложенные категории/подкатегории, вы можете посмотреть подробное решение в моём собственном вопросе. Надеюсь, это поможет другим, и спасибо за первоначальные шаги.

23 янв. 2012 г. 20:39:23
1

Не уверен, что WordPress поддерживает такую структуру URL "из коробки" — но вы можете легко создать собственные правила перезаписи для этого.

Посмотрите предыдущий ответ здесь: Перезапись URL автора.

Вы можете изменить строку

$newrules['author/([^/]+)/songs/?$'] = 'index.php?post_type=songs&author=$matches[1]';

на что-то вроде

$newrules['products/([^/]+)/([^/]+)/?$'] = 'index.php?post_type=product_listing&product_cat=$matches[1]&name=$matches[2]';

Часть с product_cat здесь может быть избыточной — я не уверен, нужна ли она.

Вы можете добавить любые правила, и они будут иметь приоритет над встроенными.

14 дек. 2010 г. 02:07:03
Комментарии

Ну разве это не интересно. Ох, кажется, пользовательские правила перезаписи мне не по зубам. Я попробовал приведённый выше код (и остальной из другого поста), но ничего не изменилось. Я сбросил всё и попробовал снова, но изменений так и не было, поэтому я закомментировал все правила перезаписи, установленные в пользовательских типах записей и таксономиях, сбросил кеш, но ВСЁ РАВНО ничего.

RodeoRamsey RodeoRamsey
14 дек. 2010 г. 03:09:48
1

Это сводило меня с ума, пока я не настроил постоянные ссылки для пользовательского типа записей. Я нашел плагин для управления постоянными ссылками пользовательских типов записей. Он очень прост в использовании. http://wordpress.org/extend/plugins/custom-post-permalinks/ WP стоит добавить это в базовый функционал! Лео

14 дек. 2010 г. 12:13:59
Комментарии

Я видел это решение раньше и не использовал его, потому что там было указано "для неиерархических" таксономий. У меня была иерархическая таксономия, поэтому я думал, что это не сработает, но пока что, кажется, помогло! Кроме того, похоже, что это позволяет добиться структуры /products/название-категории/название-продукта/, которую я пытался реализовать (см. комментарий к другому ответу). @TheDeadMedic, это жизнеспособный вариант? Или мне лучше придерживаться перезаписей в файле functions.php?

RodeoRamsey RodeoRamsey
14 дек. 2010 г. 19:57:35
0

На самом деле это довольно просто. Вам понадобится всего одна строка. Вот мой код:


function create_product_taxonomies()
{
// Добавляем новую таксономию, делаем её иерархической (как категории)
    $labels = array(
        'name' => _x('Категории', 'taxonomy general name'),
        'singular_name' => _x('Категория', 'taxonomy singular name'),
        'search_items' => __('Искать категории'),
        'all_items' => __('Все категории'),
        'parent_item' => __('Родительские категории'),
        'parent_item_colon' => __('Родительские категории:'),
        'edit_item' => __('Редактировать категорию'),
        'update_item' => __('Обновить категорию'),
        'add_new_item' => __('Добавить новую категорию'),
        'new_item_name' => __('Название новой категории'),
        'menu_name' => __('Категория'),
    );

    register_taxonomy('product_cat', array('product_listing'), array(
        'hierarchical' => true,
        'labels' => $labels,
        'show_ui' => true,
        'query_var' => true,
        'rewrite' => array('hierarchical' => true),
    ));

И применил к сгенерированной таксономии для моего CPT "Отзывы" с GenerateWP.com. Я использую это на своем собственном WordPress сайте, https://www.wpstarters.com


function reviews_category_taxonomy() {

    $labels = array(
        'name'                       => _x( 'Категории отзывов', 'Taxonomy General Name', 'reviews_category' ),
        'singular_name'              => _x( 'Категория отзывов', 'Taxonomy Singular Name', 'reviews_category' ),
        'menu_name'                  => __( 'Категории отзывов', 'reviews_category' ),
        'all_items'                  => __( 'Все категории отзывов', 'reviews_category' ),
        'parent_item'                => __( 'Родительская категория отзывов', 'reviews_category' ),
        'parent_item_colon'          => __( 'Родительская категория отзывов:', 'reviews_category' ),
        'new_item_name'              => __( 'Название новой категории отзывов', 'reviews_category' ),
        'add_new_item'               => __( 'Добавить новую категорию отзывов', 'reviews_category' ),
        'edit_item'                  => __( 'Редактировать категорию отзывов', 'reviews_category' ),
        'update_item'                => __( 'Обновить категорию отзывов', 'reviews_category' ),
        'view_item'                  => __( 'Просмотреть категорию отзывов', 'reviews_category' ),
        'separate_items_with_commas' => __( 'Разделять элементы запятыми', 'reviews_category' ),
        'add_or_remove_items'        => __( 'Добавить или удалить элементы', 'reviews_category' ),
        'choose_from_most_used'      => __( 'Выбрать из наиболее часто используемых', 'reviews_category' ),
        'popular_items'              => __( 'Популярные категории отзывов', 'reviews_category' ),
        'search_items'               => __( 'Поиск элементов', 'reviews_category' ),
        'not_found'                  => __( 'Не найдено', 'reviews_category' ),
        'no_terms'                   => __( 'Нет категорий отзывов', 'reviews_category' ),
        'items_list'                 => __( 'Список категорий отзывов', 'reviews_category' ),
        'items_list_navigation'      => __( 'Навигация по списку категорий отзывов', 'reviews_category' ),
    );
    $args = array(
        'labels'                     => $labels,
        'hierarchical'               => true,
        'public'                     => true,
        'show_ui'                    => true,
        'show_admin_column'          => true,
        'show_in_nav_menus'          => true,
        'show_tagcloud'              => false,
        'show_in_rest'               => true,
        'rewrite' => array( 'hierarchical' => true ),
    );
    register_taxonomy( 'reviews_category', array( 'wps_reviews' ), $args );

}
add_action( 'init', 'reviews_category_taxonomy', 0 );

Все, что вам нужно - это добавить 'rewrite' => array('hierarchical' => true),

6 дек. 2017 г. 21:15:00