ЧПУ для 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
}