Как создать структуру постоянных ссылок для произвольных типов записей и таксономий (вложенные термы)?
Я больше не могу. Перерыл весь интернет и перепробывал разные фрагменты кода, но так и не нашёл того что мне нужно. Надеюсь на помощь сообщества: https://qna.habr.com/q/826639
Что я сделал:
Создал произвольный тип записи и зарегистрировал
px_product - тип записи - товары.
px_product_cat - таксономия - категории товаров (термы таксономии имеют иерархическую структуру, вложенность).
Мне нужно, чтобы ссылки имели следующий вид:
mysite.com/products/category1/child-category-1/grandchild-category-1/product-name mysite.com/Товары/Мебель/Мягкая мебель/Диваны/Диван mysite.com/products/category-1/category-1.1/category-1.1.1/product-name
Вот часть моего functions.php файла
/**
* CPT - Создание произвольного типа записи.
*/
add_action( 'init', 'cpt_product', 0 );
function cpt_product() {
// Тип записи
register_post_type( 'px_product', array(
'labels' => array( 'name' => __( 'Товары' ) ),
'public' => true,
'show_ui' => true,
'capability_type' => 'post',
'publicly_queryable' => true,
'exclude_from_search' => false,
'hierarchical' => true,
'_builtin' => false,
'query_var' => true,
'rewrite' => array( 'slug' => 'products/%px_product_cat%', 'with_front' => true ),
'supports' => array( 'title', 'editor', 'author', 'excerpt', 'trackbacks', 'custom-fields' )
) );
// Таксономия
register_taxonomy( 'px_product_cat', array( 'px_product' ), array(
'labels' => array( 'name' => __( 'Категории' ) ),
'hierarchical' => true,
'show_ui' => true,
'query_var' => true,
'rewrite' => array( 'slug' => 'products', 'with_front' => true )
) );
}
/**
* PermaLink - Внедрение терма таксономии в структуру постоянных ссылок для произвольного типа записи.
*/
add_filter( 'post_type_link', 'permalink_cpt_product', 10, 2 );
function permalink_cpt_product( $link, $post ) {
if ( $post->post_type === 'px_product' ) {
if ( $terms = get_the_terms( $post->ID, 'px_product_cat' ) )
$link = str_replace( '%px_product_cat%', current( $terms )->slug, $link );
}
return $link;
}
Далее, я создаю в админ панели WordPress три терма (категории), которые имею вложенность:
- Мебель
- Мягкая
- Диваны
Далее создаю новый товар - Диван, и присваиваю ему категорию Диваны.
В теме Astra путь хлебных крошек такой:
Главная/Мебель/Мягкая/Диваны/Диван
Ссылка выглядит так:
http://a.ru/products/диваны/диван/
Помогите, что мне сделать, чтобы моя ссылка выводила полный путь, как в крошках
http://a.ru/products/мебель/мягкая/диваны/диван
В поиске решения:
Нашёл похожий вопрос тут
Код работает, но есть 2 проблемы:
- В ссылке появляется двойной слешь
http://b.ru/products/Мебель/Мягкая/Диваны//Диван - Если перейти по пути выше, Диваны или Мягкая, то структура рушиться:
http://b.ru/products/Диваны/
http://b.ru/products/Мягкая/
// 1
add_filter( 'rewrite_rules_array', 'mmp_rewrite_rules' );
function mmp_rewrite_rules( $rules ) {
$newRules = array();
$newRules['products/(.+)/(.+)/(.+)/(.+)/?$'] = 'index.php?px_product=$matches[4]'; // my custom structure will always have the post name as the 5th uri segment
$newRules['products/(.+)/?$'] = 'index.php?px_product_cat=$matches[1]';
return array_merge( $newRules, $rules );
}
// 2
add_filter( 'post_type_link', 'filter_post_type_link', 10, 2 );
function filter_post_type_link( $link, $post ) {
if ($post->post_type != 'px_product')
return $link;
if ( $cats = get_the_terms( $post->ID, 'px_product_cat' ) ) {
$link = str_replace( '%px_product_cat%', get_taxonomy_parents( array_pop( $cats )->term_id, 'px_product_cat', false, '/', true ), $link ); // see 3 custom function defined below
}
return $link;
}
// 3 - my own function to do what get_category_parents does for other taxonomies
function get_taxonomy_parents( $id, $taxonomy, $link = false, $separator = '/', $nicename = false, $visited = array() ) {
$chain = '';
$parent = &get_term( $id, $taxonomy );
if ( is_wp_error( $parent ) ) {
return $parent;
}
if ( $nicename )
$name = $parent -> slug;
else
$name = $parent -> name;
if ( $parent -> parent && ( $parent -> parent != $parent -> term_id ) && !in_array( $parent -> parent, $visited ) ) {
$visited[] = $parent -> parent;
$chain .= get_taxonomy_parents( $parent -> parent, $taxonomy, $link, $separator, $nicename, $visited );
}
if ( $link ) {
// nothing, can't get this working :(
} else
$chain .= $name . $separator;
return $chain;
}
В сети есть готовое решение.
В functions:
add_filter('post_link', 'post_type_url_link', 20, 3); add_filter('post_type_link', 'post_type_url_link', 20, 3); function post_type_url_link( $permalink, $post_id, $leavename ) { $post_type_name = 'px_product'; $post_type_slug = 'products'; $tax_name = 'px_product_cat'; $post = get_post( $post_id ); if ( strpos( $permalink, $post_type_slug ) === FALSE || $post->post_type != $post_type_name ) return $permalink; $termini = wp_get_object_terms( $post->ID, $tax_name ); if ( !is_wp_error( $termini ) && !empty( $termini ) && is_object( $termini[0] ) ) $permalink = str_replace( $post_type_slug, $termini[0]->slug, $permalink ); return $permalink; } add_filter('request', 'post_type_url_request', 1, 1 ); function post_type_url_request( $query ){ global $wpdb; $post_type_name = 'px_product'; $tax_name = 'px_product_cat'; $yarlik = $query['attachment']; $post_id = $wpdb->get_var( " SELECT ID FROM $wpdb->posts WHERE post_name = '$yarlik' AND post_type = '$post_type_name' " ); $termini = wp_get_object_terms( $post_id, $tax_name ); if( isset( $yarlik ) && $post_id && !is_wp_error( $termini ) && !empty( $termini ) ) : unset( $query['attachment'] ); $query[$post_type_name] = $yarlik; $query['post_type'] = $post_type_name; $query['name'] = $yarlik; endif; return $query; } add_action('template_redirect', 'old_url_redirect'); function old_url_redirect() { $post_type_name = 'px_product'; $post_type_slug = 'products'; $tax_name = 'px_product_cat'; if( strpos( $_SERVER['REQUEST_URI'], $post_type_slug ) === FALSE) return; if( is_singular( $post_type_name ) ) : global $post, $wp_rewrite; $termini = wp_get_object_terms( $post->ID, $tax_name ); if ( !is_wp_error( $termini ) && !empty( $termini ) && is_object( $termini[0] ) ) : wp_redirect( site_url() . '/' . $wp_rewrite->front . '/' . $termini[0]->slug . '/' . $post->post_name, 301 ); exit(); endif; endif;В админке нужно будет зайти в Настройки -> Постоянные ссылки -> Общие настройки, выставить на "Произвольно"и в поле после домена указать /%postname%/.
т.е http://домен.com
/%postname%/