WordPress как на ладони

ЧПУ для 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
}
2 комментария
    Войти