Поддержка Проблемы и решения ЧПУ для страниц фильтра в архиве записей

  • Помогите решить такую задачу.
    Есть свой тип записей (товары) и к нему привязано несколько таксономий. Упрощенно это выглядит так:

    $args = array( 'rewrite' => array('slug' => 'catalog') );
    register_post_type( 'product', $args );
    
    $args = array( 'labels' => array('name' => 'Производитель') );
    register_taxonomy( 'brand', 'product', $args );
    
    $args = array( 'labels' => array('name' => 'Тип') );
    register_taxonomy( 'type', 'product', $args );

    В результате по ссылкам вида /catalog/ открывается архив этих записей — каталог товаров. а по /catalog/product-slug/ сами товары.
    В каталоге есть разные фильтры, которые генерируют URL с get-параметрами вида /catalog/?brand=brand_id
    Но для SEO просят сделать ЧПУ, чтобы получились ссылки /catalog/brand-slug/ и т.п.

    Есть решение с add_rewrite_rule:
    add_rewrite_rule( '/catalog/([^/]*)/?', 'index.php?post_type=product&filter=$matches[1]', 'top' );
    Дальше через get_query_var получаем переменную, применяем фильтр, выводим нужные записи. В этом плане все работает.
    Но возникают проблемы с выводом страниц самих товаров. Ведь у них ссылки устроены точно по такой же схеме, что и страницы фильтров:
    /catalog/product-slug/
    /catalog/brand-slug/

    Можно было бы решить, например, как-то поменяв URL для фильтров:
    add_rewrite_rule( '/catalog/filter/([^/]*)/?', 'index.php?post_type=product&filter=$matches[1]', 'top' );
    Тогда страницы фильтров будут иметь URL вида /catalog/filter/brand-slug/.
    Или поменять slug для товаров и получить у них URL /products/product-slug/
    Но ничего из этого не хотелось бы. Оставлю это уж на самый крайний случай.

    Пока видится только костыльное решение:
    1. Проверить регуляркой $_SERVER[‘REQUEST_URI’].
    2. Если онo соответствует /catalog/any-slug/, то попробовать найти товар с этим any-slug.
    3. Если такой товар найдется, то дальше ничего не делаем (точнее, дальше функционал WP откроет страницу этого товара).
    4. Если товара не нашлось, то add_rewrite_rule, get_query_var… В общем, как я писал двумя абзацами выше.

    Но оно порождает проблемы:
    Во-первых, потребуется при каждом вызове делать $wp_rewrite->flush_rules() или flush_rewrite_rules() — а это очень ресурсоемко, да и товаров несколько тысяч.
    Во-вторых, даже если опустить проблему с ресурсами, при параллельных запросах явно будет происходить не пойми что (правила же в БД не мгновенно будут обновляться).

    Может быть существует какое-то более правильное решение?

Просмотр 6 ответов — с 1 по 6 (всего 6)
  • А зачем товарам префикс catalog? делайте product

    Бренды почему бы не открывать просто по brand/brand-slug/

    Для категорий сделать префикс catalog

    Если нужен чпу по фильтру категория+бренд то урл будет catalog/catalog-slug/brand-slug/, что легко делается через rewrite rule.

    Пока видится только костыльное решение:

    Но оно порождает проблемы:
    Во-первых, потребуется при каждом вызове делать

    Возможно поможет https://wp-kama.ru/hook/request

    • Ответ изменён 4 года, 2 месяца назад пользователем qwert555.

    А зачем товарам префикс catalog? делайте product
    Бренды почему бы не открывать просто по brand/brand-slug/
    Для категорий сделать префикс catalog

    СЕОшники просят, чтобы логически всё было как бы дочерним к странице /catalog/:
    /catalog/product-name/ — страница конкретного товара
    /catalog/brand/ — все товары определенного бренда
    /catalog/type/ — все товары определенного типа (из одной группы)
    /catalog/brand/type/ — все товары бренда определенного типа (группы)
    и т.д.

    Страниц таксономий вида taxonomy/term-slug/ (ну которые шаблонами taxonomy-*.php формируются) там сейчас нет.
    Весь каталог выводится шаблоном archive-product.php. Просто, в зависимости от установок фильтра, он вызывается с разными get-параметрами, ну и в pre_get_posts модифицируется основной запрос.

    Вся эта конструкция благополучно работает давным-давно. Но вот вместо get-параметров нужно сделать ЧПУ…

    Добрый день!

    Делал подобное пару лет назад. Точное решение навскидку не вспомню, но по ощущению надо копать куда-то в сторону эндпоинтов: add_rewrite_endpoint() и смежных доков. Попробуйте начать отсюда: https://wp-kama.ru/function/add_rewrite_endpoint Типовой механизм преобразования GET-параметров в ЧПУ абсолютно точно существует и я почти уверен, что ответ где-то на расстоянии пары ссылок от эндпоинтов 🙂

    P.S. Если не сложится, напишите, постараюсь на неделе поискать исходники того проекта.

    Я сделал по принципу дочерних термов к родительской (может это не совсем правильно, но мне кажется что не ошибся), и теперь вывод получается:
    /catalog/
    /catalog/brand/
    /catalog/brand/type/
    Кратко:

    
    add_action( 'init', 'true_register_мой_тип_записи' ); 
    function true_register_мой_тип_записи() {
        $labels = array(...
        );
        $args = array(...
    register_post_type('мой_тип_записи',$args);
    }
    
    function create_мой_тип_записи_taxonomy(){
    	register_taxonomy('таксономия', array('мой_тип_записи'), array(
    		'label'                 => '', // определяется параметром $labels->name
    		...
    		),
    		'hierarchical'          => true, //false,
    //              'rewrite'               => array( 'slug' => '' ),
    	) );
    }
    
    if ( ! function_exists( 'мой_тип_записи_таксономия1_custom_taxonomy' ) ) {
    function мой_тип_записи_таксономия1_custom_taxonomy() {
    	$labels = array(...
    	);
    	$args = array(
    		'labels'                     => $labels,
    		'hierarchical'               => true, // как категории
    	);
    	register_taxonomy( 'таксономия1', array( 'мой_тип_записи' ), $args );
    }
    add_action( 'init', 'мой_тип_записи_таксономия1_custom_taxonomy', 0 );
    }

    @legal2019

    Я сделал по принципу дочерних термов к родительской

    Правильнее будет это назвать созданием типа записи и привязкой к ней таксономии. Эти все примеры в том же Кодексе расписаны. С этим-то проблем как раз и нет — я даже в самом начале писал, что это все создано и работает.
    Проблема в том, чтобы ссылки на всё это дело поменять кардинальным образом.

    Раз с префиксом catalog может быть бренд, а может товар, значит нужно слаг проверять, что есть что.

    Я для городов определял, что это страницы или произвольный тип записи site.ru/msk/

    Города были отдельным типом записей.

    Слаг msk проверял на каждом запросе, если есть город с таким слагом, значит это страница города, если нет — значит это обычная страница или 404.

    Вот пример скопипастил с сайта.

    //определение страницы типа site.com/stati/
    
    add_filter( 'request', function( $query_vars ){
    
    $reguest_url = trim(explode('?', $_SERVER['REQUEST_URI'])[0], '/');
       
    /* если это запись или страница с 1 уровнем вложенности. пример site.com/stati/, то необходимо определить, что возможно эта страница является страницей города  */
    	 if((
                 !empty($query_vars['name']) or 
    	     !empty($query_vars['pagename']) or
    	     !empty($query_vars['category_name']) or
    	     !empty($query_vars['author_name'])	
    	 ) &&  !empty($reguest_url) && (count(explode('/', $reguest_url))==1) && !is_numeric($reguest_url)){
    		 
    	 //получаем данные о городе по слагу 
    	 $city_array = get_city_array($reguest_url);
    
    //если такой город в базе есть, значит это страница города
    	   if(!empty($city_array->slug)){
    		$query_vars['city'] = $city_array->slug;
    		unset( 
    		$query_vars['pagename'],
    		$query_vars['name'],
    		$query_vars['category_name'],
    		$query_vars['author_name']
    		);		
    	  }		
    	}  
    
    	return $query_vars;
    	
    	
    } );	

    get_city_array это собственная функция

    • Ответ изменён 4 года, 2 месяца назад пользователем qwert555.
Просмотр 6 ответов — с 1 по 6 (всего 6)
  • Тема «ЧПУ для страниц фильтра в архиве записей» закрыта для новых ответов.