Чем больше узнаю Wordpress, тем еще больше мне нравится эта система управления контентом. Рано или поздно любой создатель сайтов, кто действительно осваивает это ремесло, приходит к коду. Первоначальное решение любой задачи через поиск плагина постепенно сменяется более правильными, лаконичными решениями через functions.php. Достаточно лирики, к сути.

Вы наверняка знаете, что Wordpress позволяет использовать иерархическую структуру для записей. То есть, может быть родительская запись и несколько дочерних, свойство которых устанавливается через «Атрибуты страницы». Не получилось найти? Да, по-умолчанию эта фишка работает только для типов записей Страницы, для типов записей Записи эту функцию необходимо активировать. Это касается и пользовательских типов записей, которые вы создаете сами. Как это сделать расскажу чуть ниже.

Имея иерархическую структуру записей можно сделать офигительную по мощности и функциональности штуковину: подменю из дочерних страниц, при этом адрес этих страниц будет правильно отображать логическую структуру (site.ru/pearent/child-1, site.ru/pearent/child-2). Смотрите пример тут.

Реализовать скрипт можно двумя вариантами: изменив непосредственно файлы шаблона (идеально, если у вас дочерняя тема или делаете собственную тему), через шорт код (пригодится, если вы пользуетесь билдерами, например Elementor). Я постараюсь рассказать вам логику, тогда вы сможете изменить код самостоятельно как вам будет нужно. И я не буду касаться оформления, всякие css правила вы придумаете и напишите самостоятельно.

Я рекомендую писать код последовательно, как это рассказываю я, тогда вы будете понимать логику скрипта и сможете самостоятельно его откорректировать. Если это не требуется: готовый скрипт, готовый шорткод.

Редактирую шаблон

Отредактировать нужно страницу отображения поста. Способ выбирайте любой, как вам будет удобно, можно из самого Wordpress’a Внешний вид -> Редактор тем. Будьте внимательны, для какого типа записей вы хотите добавить эту функцию. Если для Страниц, то редактировать нужно page.php, если для записей, то single.php (и помним про активацию иерархической структуры для типа записей). В этом примере я редактирую page.php, меню будет работать на страницах.

У меня тема Astra, перехожу в Редактор тем Wordpress, ищу page.php, открываю для редактирования, выбираю место для размещения нового меню. Мне кажется тут будет идеально.

Добавляю вывод дочерних объектов, используя функцию wp_list_pages().

<?php wp_list_pages(); ?> //Функция выводит список всех записей сайта заданного типа записей (страницы)

Теперь над заголовком страницы появился длинный список всех страниц сайта. Задача оставить только дочерние к этой странице. Сделать это можно добавив аргументы в функцию. Добавляю массив $args и описываю его значения.

<?php

$args = array(         //Добавляет массив с аргументами для функции

'child_of' => $post->ID//Значение для фильтрации и отображения только дочерних элементов 

);

wp_list_pages($args);  //Функция выводит список всех записей сайта заданного типа записей (страницы)

?>

Теперь немного причешем. Первым пунктом нового меню остался заголовок, в котором нет необходимости. Прячу его, добавляю в массив с аргументами пустое значение.

<?php

$args = array(          //Добавляет массив с аргументами для функции

'child_of' => $post->ID,//Аргумент для фильтрации и отображения только дочерних элементов
'title_li' => ''        //Значение для скрытие заголовка дочерних элементов

);

wp_list_pages($args);   //Функция выводит список всех записей сайта заданного типа записей (страницы)

?>

Меню из дочерних записей собрано. Теперь не важно какая страница и сколько дочерних записей, меню будет формироваться на всех страницах, у которых есть дочерние записи. К стати, этот параметр можно отрегулировать. Будет полезно поизучать вот эту страницу. Среди аргументов массива есть child_of, exclude, include — параметры, которые позволяют указывать ID записей или получать их динамически.

Единственный недостаток нового меню — оно не отображается на дочерних страницах, а очень хотелось бы. Открываю functions.php, пишу функцию.

//Функция для определения родительской страницы для вывода меню на дочерних страницах
function get_top_ancestor_id() {//Объявление функции

global $post;//Получаем доступ к записи

if ($post->post_parent) {      //Проверка на наличе родительской записи

$ancestors = array_reverse(get_post_ancestors($post->ID));//Массив с иерархическим построением записей (Родитель-Дочерний/Родитель-       Дочерниий/Родитель и тд, с обратным построением массива, поскольку массив строится от младшего к старшему)

return $ancestors[0];//Вывод первого значения массива

}
return $post->ID;//Вывод ID записи

}

Остался последний шаг. Добавить родительскую запись в меню, чтобы можно было вернуться к ней из дочерних записей. Делаю следующее.

//Этот код добавляю в page.php перед добавленным ранее кодом

<span><a href="<?php echo get_the_permalink(get_top_ancestor_id()); ?>"><?php echo get_the_title(get_top_ancestor_id()); ?></a></span>

//Получаю заголовок с помощью функции get_the_title(), используя как аргумент функцию get_top_ancestor_id(), поскольку с помощью нее был получен ID родительской записи
//То же самое со ссылкой - get_the_permalink()

Вот и все. Получилось действительно круто — автоматическое меню из дочерних страниц. Далее украшаем на свой вкус и под свою тему.

Итоговый код

В файл page.php или single.php необходимо добавить следующий код:

<!-- Начало меню -->
<span><a href="<?php echo get_the_permalink(get_top_ancestor_id()); ?>"><?php echo get_the_title(get_top_ancestor_id()); ?></a></span>

<?php 
		
$args = array (
		
'child_of' => get_top_ancestor_id(),
'title_li' => ''
			
);
		
wp_list_pages($args); 
		
?>
<!-- Конец меню -->

В файл functions.php необходимо добавить следующий код:

//Функция получения родителя для подменю из дочерних записей
function get_top_ancestor_id() {
	
global $post;
	
if ($post->post_parent) {

$ancestors = array_reverse(get_post_ancestors($post->ID));
return $ancestors[0];
	
}
return $post->ID;
	
}

Добавляем шорткод

С шорткодом все тоже самое. Я не буду объяснять что значит каждая строчка кода, если захотите, разберетесь. Только отмечу, что объявлено два шорткода: один для вывода дочерних записей, один для вывода родительской. Я так делал под себя, вы можете объединить все в один шорткод. Ну и демонстрация возможностей.

Весь код добавляется в файл function.php.

function get_top_ancestor_id() {
	
	global $post;
		
	if ($post->post_parent) {
			
		$ancestors = array_reverse(get_post_ancestors($post->ID));
		return $ancestors[0];
			
	}
		
	return $post->ID;
}

function show_subpost_child() {
	
	global $post;
	
 
 $args = array(
	'child_of' => get_top_ancestor_id(),
	'title_li' => '',
 );
 
 $out = wp_list_pages($args);
 return $out;
  
}
add_shortcode( 'subposts_child', 'show_subpost_child');

function show_subpost_pearent() {
	
	$title = get_the_title( get_top_ancestor_id() );
	$link = get_the_permalink( get_top_ancestor_id() );
	
	return '<div><a href="' . $link . '">Описание</a></div>';
	
}
add_shortcode( 'subposts_pearent', 'show_subpost_pearent');

Пользовательский тип записей

Наверняка будут вопросы как прикрутить это меню к пользовательским типам записей. Во-первых, я обещал рассказать как активировать иерархическую структуру для типов записей. Очень просто с помощью плагинов создания пользовательских типов записей. Например, это позволяет сделать JetEngine в один клик.

Причем. с помощью JetEngine это возможно сделать не только для пользовательских типов, но и для типа Записи.

Возвращаюсь к коду. Чтобы меню работало с пользовательским типом записей в массив фильтрации нужно добавить аргумент, указывающий на соответствующий тип.

'post_type' => 'breeds_posts'

На выходе получается вот что.

$args = array(
	'child_of' => get_top_ancestor_id(),
	'title_li' => '',
	'post_type' => 'breeds_posts'
 );

Для тех, кто не внимательно читал в начале. Еще раз обращаю ваше внимание на эту страницу. Она поможет подобрать нужные аргументы и значения.

На этом все. Удачи!