Как создать структуру постоянных ссылок для произвольных типов записей и таксономий (вложенные термы)?

Я больше не могу. Перерыл весь интернет и перепробывал разные фрагменты кода, но так и не нашёл того что мне нужно. Надеюсь на помощь сообщества: 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 три терма (категории), которые имею вложенность:

  1. Мебель
  2. Мягкая
  3. Диваны

Далее создаю новый товар - Диван, и присваиваю ему категорию Диваны.

В теме Astra путь хлебных крошек такой:
Главная/Мебель/Мягкая/Диваны/Диван

Ссылка выглядит так:
http://a.ru/products/диваны/диван/

Помогите, что мне сделать, чтобы моя ссылка выводила полный путь, как в крошках
http://a.ru/products/мебель/мягкая/диваны/диван

В поиске решения:

Нашёл похожий вопрос тут

Код работает, но есть 2 проблемы:

  1. В ссылке появляется двойной слешь
    http://b.ru/products/Мебель/Мягкая/Диваны//Диван
  2. Если перейти по пути выше, Диваны или Мягкая, то структура рушиться:
    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;    
}
0
7GIT
4.2 года назад 30
  • 0

    В сети есть готовое решение.

    В 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%/

    Комментировать
На вопросы могут отвечать только зарегистрированные пользователи. Вход . Регистрация