ЧПУ для 3 типов записей и 3 таксономий (сразу для этих трех типов)
ЗАДАЧА
1) Тип записи `rc` (reabilitacionnye-centry) Тип записи Такса многоур Такса плоская 2 элемента post_name `city_location` - Страна/Область/Город `clinic_type` dom/rc /rossiya/lipetskayz-oblast/lipeck /chastnie /reabilitacionnii-centr-piramida dom/rc /rossiya/lipetskayz-oblast/lipeck /chastnie dom/rc /rossiya/lipetskayz-oblast/lipeck 2) Типа записи `clinic` - аналогичный rc Тип записи Такса многоур Такса плоская 2 элемента post_name `city_location` - Страна/Область/Город `clinic_type` dom/clinic /rossiya/lipetskayz-oblast/lipeck /chastnie /reabilitacionnii-centr-piramida dom/clinic /rossiya/lipetskayz-oblast/lipeck /chastnie dom/clinic /rossiya/lipetskayz-oblast/lipeck 3) Типа записи `specialist` Тип записи Такса многоур Такса плоская 50+ элемент post_name `city_location` `specialty` dom/specialist /rossiya/lipetskayz-oblast/lipeck /специальность /имя dom/specialist /rossiya/lipetskayz-oblast/lipeck /специальность dom/specialist /rossiya/lipetskayz-oblast/lipeck
<?php // require_once get_stylesheet_directory() . '/_register_cpt_rerwrite_rules.php'; ## регистрация типов записей и таксономий add_action( 'init', 'register_post_types_2019_02_10', 0 ); function register_post_types_2019_02_10(){ // Такса - Город: страна/регион/город register_taxonomy( 'city_location', ['rc','clinic','specialist'], [ 'labels' => [ 'name' => 'Города', 'singular_name' => 'Город', ], // ВАЖНО! Элемент всегда должен быть 3-м уровенм - Страна/область/город 'rewrite' => [ 'slug' => 'rc', 'hierarchical' => true, 'with_front' => 0, 'feed' => 0, ], 'hierarchical' => true, 'public' => true, 'show_admin_column' => true, 'show_in_nav_menus' => true, //'update_count_callback' => 'city_location_update_count_callback', ] ); // Такса - Тип: Государственная/Частная register_taxonomy( 'clinic_type', ['rc','clinic'], [ 'labels' => [ 'name' => 'Тип (клиники)', 'singular_name' => 'Тип (клиники)', 'menu_name' => 'Тип (клиники)' ], 'hierarchical' => true, 'public' => false, 'rewrite' => false, 'query_var' => true, // query_var, чтобы запрос на термин работал... 'publicly_queryable' => true, // query_var, чтобы запрос на термин работал... 'show_ui' => true, 'show_in_quick_edit' => true, 'show_tagcloud' => false, 'show_admin_column' => true, 'show_in_nav_menus' => false, ] ); // Такса - Специальность: Прогер/Стоматолог/... register_taxonomy( 'specialty', ['specialist'], [ 'labels' => [ 'name' => 'Специальности', 'singular_name' => 'Специальность', 'menu_name' => 'Специальность' ], 'hierarchical' => true, 'public' => false, 'rewrite' => false, 'query_var' => true, // query_var, чтобы запрос на термин работал... 'publicly_queryable' => true, // query_var, чтобы запрос на термин работал... 'show_ui' => true, 'show_in_quick_edit' => true, 'show_tagcloud' => false, 'show_admin_column' => true, 'show_in_nav_menus' => false, ] ); // Тип записи - rc register_post_type( 'rc', [ 'labels' => [ 'name' => 'РЦентры', 'singular_name' => 'РЦентр', ], 'taxonomies' => [ 'city_location', 'clinic_type' ], 'public' => true, 'query_var' => true, 'rewrite' => [ 'slug' => 'rc/%city_location%/%clinic_type%', // + /%post_name% 'with_front' => false, 'feeds' => false, 'pages' => false, 'paged' => false, 'feed' => false, ], 'show_in_menu' => true, 'has_archive' => true, 'supports' => [ 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'custom-fields', 'revisions' ], 'show_ui' => true, 'show_in_nav_menus' => false, 'menu_icon' => 'dashicons-editor-ul', ] ); // Тип записи - clinic register_post_type( 'clinic', [ 'labels' => [ 'name' => 'Клиники', 'singular_name' => 'Клиника', ], 'taxonomies' => [ 'city_location', 'clinic_type' ], 'public' => true, 'query_var' => true, 'rewrite' => [ 'slug' => 'clinic/%city_location%/%clinic_type%', // + /%post_name% 'with_front' => false, 'feeds' => false, 'pages' => false, 'paged' => false, 'feed' => false, ], 'show_in_menu' => true, 'has_archive' => true, 'supports' => [ 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'custom-fields', 'revisions' ], 'show_ui' => true, 'show_in_nav_menus' => false, 'menu_icon' => 'dashicons-editor-ul', ] ); // Тип записи - specialist register_post_type( 'specialist', [ 'labels' => [ 'name' => 'Специалисты', 'singular_name' => 'Специалист', ], 'taxonomies' => [ 'city_location', 'specialty' ], 'public' => true, 'query_var' => true, 'rewrite' => [ 'slug' => 'specialist/%city_location%/%specialty%', // + /%post_name% 'with_front' => false, 'feeds' => false, 'pages' => false, 'paged' => false, 'feed' => false, ], 'show_in_menu' => true, 'has_archive' => true, 'supports' => [ 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'custom-fields', 'revisions' ], 'show_ui' => true, 'show_in_nav_menus' => false, 'menu_icon' => 'dashicons-groups', ] ); if( 'ЧПУ' ){ //add_action('wp', 'xxxxxxx'); // debug function xxxxxxx($wp){ print_r( get_queried_object() ); print_r( $wp ); print_r( $GLOBALS['wp_rewrite'] ); exit; } ## поправим параметры запроса add_action( 'request', function( $vars ){ if( !empty($vars['city_location']) ){ $_city_location = explode( '/', $vars['city_location'] ); $_end = end( $_city_location ); // работает кэширование if( ! $trans_data = chpu_term_names_cache('get') ){ $trans_data = chpu_term_names_cache('set'); } if( in_array( $_end, $trans_data['clinic_types']) ){ $vars['clinic_type'] = array_pop( $_city_location ); $_end = end( $_city_location ); } if( in_array( $_end, $trans_data['specialties']) ){ $vars['specialty'] = array_pop( $_city_location ); $_end = end( $_city_location ); } $vars['city_location'] = $_end; // последний элемент } return $vars; } ); ## Пересоздадим правила перезаписи для типов записей ## '(post_type)_rewrite_rules' foreach( ['rc','clinic','specialist'] as $post_type ){ add_filter( $post_type .'_rewrite_rules', function( $rules ) use ( $post_type ){ $key = '('. $post_type . ')/('. '[^/]+/[^/]+/[^/]+' /*страна/область/город*/ .')/([^/]+)/([^/]+)/?$'; //$key = '('. $post_type . ')/(.+?)/([^/]+)/([^/]+)/?$'; if( 'specialist' === $post_type ) $val = 'index.php?post_type=$matches[1]&city_location=$matches[2]&specialty=$matches[3]&name=$matches[4]'; else $val = 'index.php?post_type=$matches[1]&city_location=$matches[2]&clinic_type=$matches[3]&name=$matches[4]'; return [ $key => $val, "($post_type)/?$" => 'index.php?post_type=$matches[1]', ]; } ); } ## добавим правила перезаписи для 'city_location' ## 'city_location'.'_rewrite_rules' add_filter( 'city_location'.'_rewrite_rules', function( $rules ){ /* [rc/(.+?)/page/?([0-9]{1,})/?$] => index.php?city_location=$matches[1]&paged=$matches[2] [rc/(.+?)/?$] => index.php?city_location=$matches[1] */ // должен быть после правил типа запии 'realty' $_first_part = '(rc|clinic|specialist)/(.+?)'; $_pade_part = 'page/?([0-9]{1,})'; $rules = [ "$_first_part/$_pade_part/?$" => 'index.php?post_type=$matches[1]&city_location=$matches[2]&paged=$matches[3]', "$_first_part/?$" => 'index.php?post_type=$matches[1]&city_location=$matches[2]', ]; return $rules; } ); ## Заполним пермалинк типа записи add_filter( 'post_type_link', 'rc_permalink', 1, 2 ); function rc_permalink( $permalink, $post ){ if( false === strpos($permalink, '%city_location%') ) return $permalink; return strtr( $permalink, [ '%city_location%' => __build_tax_uri( get_the_terms( $post, 'city_location') ), // много уровней - asd/asd '%clinic_type%' => __build_tax_uri( get_the_terms( $post, 'clinic_type') ), // один уровень - asd '%specialty%' => __build_tax_uri( get_the_terms( $post, 'specialty') ), // один уровень - asd ] ); } ## Получает цепочку из ярлыков указанного термина - 'parent/child/child' function __build_tax_uri( $terms ){ if( is_wp_error($terms) || empty($terms) || ! ( is_object(reset($terms)) || is_object($terms) ) ) return 'no_terms'; // элемента таксы нет, а должен быть... $term = is_object(reset($terms)) ? reset($terms) : $terms; $path = array( $term->slug ); while( $term->parent ){ $term = get_term( $term->parent ); $path[] = $term->slug; } return implode( '/', array_reverse($path) ); } ## Сбросим кэш при обновлении термина add_action( 'edited_term', 'update_cache_chpu_term_names_hook', 10, 3 ); add_action( 'created_term', 'update_cache_chpu_term_names_hook', 10, 3 ); add_action( 'delete_term', 'update_cache_chpu_term_names_hook', 10, 3 ); function update_cache_chpu_term_names_hook( $term_id, $tt_id, $taxonomy ){ if( in_array( $taxonomy, ['clinic_type','specialty']) ) chpu_term_names_cache( 'set' ); } function chpu_term_names_cache( $action = 'get' ){ $opt_name = 'chpu_term_names_cache'; if( 'get' === $action ){ return get_option( $opt_name ); } if( 'clear' === $action ){ update_option( $opt_name, '' ); } if( 'set' === $action ){ $clinic_types = get_terms([ 'taxonomy' => 'clinic_type', 'fields' => 'id=>slug', ]); $specialties = get_terms([ 'taxonomy' => 'specialty', 'fields' => 'id=>slug', ]); $data = [ 'clinic_types' => $clinic_types, 'specialties' => $specialties ]; update_option( $opt_name, $data ); return $data; } } } } ## отменим показ выбранного термина наверху в checkbox списке терминов add_filter( 'wp_terms_checklist_args', 'set_checked_ontop_default', 10 ); function set_checked_ontop_default( $args ){ // изменим параметр по умолчанию на false if( ! isset($args['checked_ontop']) ) $args['checked_ontop'] = false; return $args; } ## Удаление табов "Все рубрики" и "Часто используемые" из метабоксов рубрик (таксономий) на странице редактирования записи. add_action( 'admin_print_footer_scripts', 'hide_tax_metabox_tabs_admin_styles', 99 ); function hide_tax_metabox_tabs_admin_styles(){ $cs = get_current_screen(); if( $cs->base !== 'post' || empty($cs->post_type) ) return; // не страница редактирования записи ?> <style> .postbox div.tabs-panel{ max-height:1200px; border:0; } .category-tabs{ display:none; } </style> <?php } ## Переделаем checkbox в radio на страницах записей add_action( 'admin_print_footer_scripts', 'func_hook_admin_footer_scripts', 99 ); function func_hook_admin_footer_scripts(){ if( get_current_screen()->base !== 'post' ) return; ?> <script> [ 'city_location', 'clinic_type' ].forEach(function(taxname){ jQuery( '#' + taxname + 'div input[type="checkbox"]' ).prop( 'type', 'radio' ); }) </script> <?php }