В этой статье расскажу, как без кучи кода сделать подстраницы у произвольного типа записей с сохранением структуры url.
Как делал раньше
Я пользовался костылём — разрывом страницы.
Недостатки такого решения:
- Url будут нечитабельными. Каждый разрыв страницы в url будет идти цифрой: /1, /2, /3. А я хочу, чтобы это были нормальные url: /logo, /process, /mobile
- Всё в одной странице. Если вы создадите таких 5−6 разрывов с кучей контента, ваша админка начнёт загибаться.
- Если же вы начнёте создавать страницы отдельно и связывать их допустим ACF — в списке страниц они могут быть далеко друг от друга.
Задача
У меня появилась задача делать подстраницы для моих кейсов на сайте. Чтобы можно было создать страницу под разный аспект проекта: дизайн сайта, дизайн приложения, логотип. Но чтобы всё было привязано к одному проекту и пользователь мог переключаться.
Выглядеть должно примерно так:
Сделать так, чтобы можно было делать подстраницы, в решении этого мне нужно:
- нормальные url, которыми я могу управлять
- разделить страницы на разные, чтобы избежать нагрузки на админку
- чтобы подстраницы были связаны с родительскими страницами в списке
Решение
Наше решение состоит из нескольких шагов
- Поменять параметры в создании произвольного типа записи
- Обновить постоянные ссылки
- Выбрать родительскую страницу у нескольких страниц
- Вывести подстраницы на родительской страницы
- Вывести подстраницы на каждой подстранице
Поменять параметры в создании произвольного типа записи
Вот так выглядит мой код создания произвольного типа записи.
register_post_type('projects', array(
'label' => null,
'labels' => array(
'name' => 'Проекты', // основное название для типа записи
'singular_name' => 'Проект', // название для одной записи этого типа
'add_new' => 'Добавить проект', // для добавления новой записи
'add_new_item' => 'Добавление проекта', // заголовка у вновь создаваемой записи в админ-панели.
'edit_item' => 'Редактирование проекта', // для редактирования типа записи
'new_item' => 'Новый проект', // текст новой записи
'view_item' => 'Смотреть проект', // для просмотра записи этого типа.
'search_items' => 'Искать проект', // для поиска по этим типам записи
'not_found' => 'Не найдено', // если в результате поиска ничего не было найдено
'not_found_in_trash' => 'Не найдено в корзине', // если не было найдено в корзине
// 'parent_item_colon' => '', // для родителей (у древовидных типов)
'menu_name' => 'Проекты', // название меню
),
'description' => '',
'public' => true,
'publicly_queryable' => true, // зависит от public
'exclude_from_search' => false, // зависит от public
'show_ui' => true, // зависит от public
'show_in_menu' => true, // показывать ли в меню адмнки
'show_in_admin_bar' => true, // по умолчанию значение show_in_menu
'show_in_nav_menus' => true, // зависит от public
'show_in_rest' => true, // добавить в REST API. C WP 4.7
'rest_base' => null, // $post_type. C WP 4.7
'menu_position' => 4,
'menu_icon' => 'dashicons-format-gallery',
'capability_type' => 'page',
//'capabilities' => 'post', // массив дополнительных прав для этого типа записи
//'map_meta_cap' => null, // Ставим true чтобы включить дефолтный обработчик специальных прав
'hierarchical' => true,
'supports' => array('title', 'thumbnail','comments', 'editor', 'page-attributes','post-formats', 'excerpt', 'revisions', 'custom-fields'),
'has_archive' => false,
'taxonomies' => array('projectcategory'),
'rewrite' => true,
'query_var' => true
) );
Для нас важны параметры:
- parent_item_colon
- show_in_rest
- rewrite
- capability_type
- hierarchical
Если у вас таких нет, скопируйте их из моего кода.
Что менять в коде:
- parent_item_colon — он должен быть либо закомментирован, либо там должно быть что-то написано. Если будет просто пустое — он не покажет блок выбора родительской страницы
- show_in_rest => true
- rewrite => true
- capability_type => true
- hierarchical => true
Обновить постоянные ссылки
В админке переходим в: «Настройки → Постоянные ссылки». И нажать кнопку «Сохранить изменения».
Выбрать родительскую страницу у нескольких страниц
Я создал тестовый проект и несколько подстраниц. У подстраниц выбрал родительскую страницу.
Вывести подстраницы на родительской странице
Теперь нам надо вывести их на родительской странице.
Будем использовать функцию get_childen
, подробнее о ней можно почитать на WP Kama.
Иду в код single-project.php
, у вас может быть свой шаблон детальной страницы.
У меня уже тут стоит костыль от прошлого решения. Его мы и перепишем.
Вот такой код я скопировал с WP Kama, надо в post_parent
поставить айди поста и вывести ссылки в цикле.
$childrens = get_children( [
'post_parent' => 0, // попеняем на $post->ID
'post_type' => 'any',
'numberposts' => -1,
'post_status' => 'any'
] );
if( $childrens ){
foreach( $childrens as $children ){
// вывыдем ссылки
}
}
Вот, что у меня получилось, пришлось попотеть, чтобы учесть всё. Не забудьте заменить projects
на свою таксономи.
<?
$parents = get_post_ancestors($post->ID); // выводим родителей страницы
$parentPost = get_post($parents[0]); // выводим пост в отдельную странцу
$childrens = get_children( [
'post_parent' => (!empty($parents)? $parents[0] : $post->ID), // если массив родителей не пустой —
'post_type' => 'projects', // здесь вставьте свою таксономию
'numberposts' => -1,
'post_status' => 'any'
] );
?>
<!-- Выводим заголовок родительского поста, если он есть -->
<h1 class="case-title">
<?if(!empty($parents)):?>
<? echo $parentPost->post_title;?> <!-- Заголовок родителя -->
<?else:?>
<?the_title();?> <!-- Заголовок поста -->
<?endif;?>
</h1>
<!-- Если нет родителей и детей, не выодим блок с ссылками -->
<?if (!empty($chilrens) & !empty($parents)):?>
<!-- Контейнер с ссылками подстраниц -->
<div>
<!-- Выводим ссылку описание:
если у проекта есть родитель — выводим его ссылку.
если у проекта есть дети — выводим его собственную ссылку -->
<?if (!empty($parents)):?>
<a href="<?=get_permalink($parents[0]);?>" class="project-page-tab js-tab-description">Описание</a>
<?elseif (!empty($childrens)):?>
<a href="<?=get_permalink($post->ID);?>" class="project-page-tab js-tab-description">Описание</a>
<?endif;?>
<!-- Выводим ссылки подстраниц, если есть -->
<?if( $childrens ): ?>
<? foreach( $childrens as $children ): ?>
<!-- Выводим ссылку -->
<a href="<?=get_permalink($children->ID);?>"><?=$children->post_title;?></a>
<?endforeach;
endif;?>
</div><!-- end контейнер с ссылками -->
<?endif;?>
Что получилось в итоге
Обратите внимание на url.
Решение подсказал Дмитрий Воробьев.
Канал о фрилансе
Там я делюсь фишками о фрилансе: деньги, клиенты, автоматизация, фриланс. Раньше это был закрытый материал с платным доступом. Сейчас он открыт. Иногда подписчикам будет открываться платные материалы.
Подписаться