WordPress. Произвольные типы записей
06.09.2019
Теги: CMS • Web-разработка • WordPress • Виджет • Иерархия • Навигация • Плагин • Таксономия
В WordPress по умолчанию уже есть несколько типов записей: посты (тип post
), страницы (тип page
), вложения (тип attachment
), редакции (тип revision
) и элементы меню (тип nav_menu_item
). Посты предназначены для публикации статей блога и имеют две таксономии: рубрики и метки. Страницы в целом похожи на посты, но имеют несколько уникальных особенностей — например, поддерживают иерархию.
Произвольный тип записи может описывать любую сущность. Например, работы в портфолио, книги, фильмы, товары в интернет-магазине. После регистрации нового типа записи, в панели управления будет доступна отдельная страница для работы записями этого типа. Для произвольного типа записи могут быть зарегистрированы таксономии — как плоские (по типу стандартных меток), так и иерархические (по типу стандартных рубрик).
Давайте напишем плагин, который зарегистрирует новый тип записи book
(книга) и добавит для него иерархическую таксономию genre
(жанр). Еще напишем класс виджета для навигации по книгам и зарегистрируем его в коде плагина.
Плагин «Каталог книг»
Итак, создаем директорию tokmakov-book
и внутри нее — файл tokmakov-book.php
:
<?php /* Plugin Name: Каталог книг Plugin URI: https://tokmakov.msk.ru Description: Позволяет создать на сайте простой каталог книг с таксономией по жанрам. Version: 1.0 Author: Евгений Токмаков Author URI: https://tokmakov.msk.ru */ register_activation_hook(__FILE__, function() { // проверяем права пользователя на установку плагинов if (!current_user_can('activate_plugins')) { return; } }); register_deactivation_hook(__FILE__, function() { // проверяем права пользователя на деактивацию плагинов if (!current_user_can('deactivate_plugins')) { return; } });
Регистрируем пользовательский тип записи book
:
/* * Регистрируем пользовательский тип записи book */ add_action('init', function () { $labels = [ 'name' => 'Книги', 'menu_name' => 'Книги', 'singular_name' => 'Книга', 'add_new' => 'Добавить книгу', 'add_new_item' => 'Добавить новую книгу', 'edit_item' => 'Редактировать книгу', 'new_item' => 'Новая книга', 'all_items' => 'Все книги', 'view_item' => 'Посмотреть книгу', 'search_items' => 'Найти книги', 'not_found' => 'Ничего не найдено', 'not_found_in_trash' => 'В корзине не найдено' ]; $args = [ 'labels' => $labels, 'public' => true, 'publicly_queryable' => true, 'show_ui' => true, 'show_in_menu' => true, 'query_var' => true, 'rewrite' => true, 'capability_type' => 'post', 'has_archive' => true, 'hierarchical' => false, 'menu_position' => null, 'supports' => [ 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'custom-fields' ], 'taxonomies' => ['genre'], ]; register_post_type('book', $args); });
Регистрируем иерархическую таксономию — жанры книг:
/* * Регистрируем иерархическую таксономию по жанрам */ add_action('init', function () { $labels = array( 'name' => 'Жанры', 'singular_name' => 'Жанр', 'menu_name' => 'Жанры' , 'all_items' => 'Все жанры', 'edit_item' => 'Редактировать жанр', 'view_item' => 'Посмотреть жанр', 'update_item' => 'Сохранить жанр', 'add_new_item' => 'Добавить новый жанр', 'parent_item' => 'Родительский жанр', 'search_items' => 'Поиск по жанрам', 'back_to_items' => 'Назад на страницу жанров', 'most_used' => 'Популярные жанры', ); $args = array( 'labels' => $labels, 'show_admin_column' => true, 'hierarchical' => true, ); register_taxonomy('genre', ['book'], $args); });
Создаем виджет для навигации
Нам потребуется файл класса виджета Book_Genres_Widget.php
, в который мы добавим следующий код:
<?php /** * Класс виджета, который позволяет вывести все жанры книг * в виде многоуровневого списка */ class Book_Genres_Widget extends WP_Widget { /** * Cоздание виджета */ function __construct() { parent::__construct( 'book_genres_widget', 'Жанры книг', // заголовок виджета ['description' => 'Все жанры книг в виде дерева'] // описание ); } /** * Метод выводит жанры книг в общедоступной части сайта */ public function widget($args, $instance) { // к заголовку применяем фильтр $title = apply_filters('widget_title', $instance['title']); echo $args['before_widget']; // выводим заголовок виджета if ( ! empty($title)) { echo $args['before_title'] . $title . $args['after_title']; } // выводим жанры книг в иерархическом виде $this->tree(0); echo $args['after_widget']; } private function tree($parent) { $terms = get_terms([ 'taxonomy' => 'genre', 'hide_empty' => false, 'parent' => $parent ]); if (!empty($terms)) { ?> <ul<?= $parent ? '' : ' id="book-genres-widget"'; ?>> <?php foreach ($terms as $term): ?> <?php $link = get_term_link($term->term_id, 'genre'); ?> <li><a href="<?= $link; ?>"><?= $term->name; ?></a> <?php $this->tree($term->term_id); ?> </li> <?php endforeach; ?> </ul> <?php } } /* * Форма настроек виджета в панели управления */ public function form($instance) { $title = ''; if (isset($instance['title'])) { $title = $instance['title']; } ?> <p> <label for="<?= $this->get_field_id('title'); ?>">Заголовок</label> <input type="text" class="widefat" id="<?= $this->get_field_id('title'); ?>" name="<?= $this->get_field_name('title'); ?>'" value="<?= esc_attr($title); ?>" /> </p> <?php } /* * Сохранение настроек виджета в панели управления */ public function update($new_instance, $old_instance) { $instance = array(); $instance['title'] = ! empty($new_instance['title']) ? strip_tags($new_instance['title']) : ''; return $instance; } }
Теперь подключим файл класса в коде плагина и зарегистрируем виджет:
require 'Book_Genres_Widget.php'; /* * Регистрируем виджет «Жанры книг» */ add_action( 'widgets_init', function () { register_widget('Book_Genres_Widget'); } );
Далее, переходим в панель управления, активируем плагин, добавляем несколько жанров и несколько книг:
Классика Русская классика Зарубежная классика Детективы Исторические детективы Современные детективы Фантастика Научная фантастика Космическая фантастика
Размещаем наш виджет в сайдбаре, для возможности навигации по каталогу книг:
Все, наш каталог книг и навигация для него уже работают:
Шаблоны для показа книг
В нашем случае запись типа book
мало чем отличается от записи типа post
. Так что для показа записей типа book
вполне подходят шаблоны для записей типа post
. Но в общем случае это может быть не так, и для книг могут потребоваться отдельные шаблоны. Так что давайте создадим шаблоны: single-book.php
— для показа отдельной книги и taxonomy-genre.php
— для показа списка книг выбанного жанра:
<?php /** * Шаблон для показа отдельной записи типа book, файл single-book.php */ /* * Подключаем шапку сайта */ get_header(); ?> <div id="content"> <div class="container"> <div class="row"> <main class="col-md-9"> <?php get_template_part('parts/single-book'); ?> </main> <aside class="col-md-3"> <?php get_sidebar(); ?> </aside> </div> </div> </div> <?php /* * Подключаем подвал сайта */ get_footer(); ?>
<?php /** * Шаблон для показа отдельной записи типа book, файл parts/single-book.php */ ?> <?php if (have_posts()): ?> <div id="clean-single"> <?php the_post(); ?> <h1><?php the_title(); ?></h1> <div class="row"> <div class="col-md-5"> <?= get_the_post_thumbnail(null, 'full'); ?> </div> <div class="col-md-7"> <?php the_content(); ?> </div> </div> <div class="well well-sm" style="margin-top: 1em"> Категории: <?= get_the_term_list( get_the_ID(), 'genre', '', ', ', '' ); ?> </div> <ul class="pager"> <li class="previous"> <?php previous_post_link( '%link', __('Предыдущая', 'clean') ); ?> </li> <li class="next"> <?php next_post_link( '%link', __('Следующая', 'clean') ); ?> </li> </ul> </div> <?php endif; ?>
<?php /** * Шаблон для показа списка записей с таксономией genre, файл taxonomy-genre.php */ /* * Подключаем шапку сайта */ get_header(); ?> <div id="content"> <div class="container"> <div class="row"> <main class="col-md-9"> <h1><?php the_archive_title(); ?></h1> <p><?php the_archive_description(); ?></p> <?php get_template_part('parts/list-book'); ?> </main> <aside class="col-md-3"> <?php get_sidebar(); ?> </aside> </div> </div> </div> <?php /* * Подключаем подвал сайта */ get_footer(); ?>
<?php /** * Список записей типа book с постраничной навигацией, файл parts/list-book.php */ ?> <?php if (have_posts()): ?> <ul class="media-list"> <?php while (have_posts()): ?> <?php the_post(); ?> <li class="media well"> <div class="media-left"> <?php $default = get_template_directory_uri().'/assets/img/default-background.jpg'; $thumbnail = get_the_post_thumbnail_url(null, 'thumbnail') ?: $default; ?> <img class="media-object" src="<?= $thumbnail; ?>" alt=""> </div> <div class="media-body"> <h4 class="media-heading"><?php the_title(); ?></h4> <p><?php the_excerpt(); ?></p> <p> <a href="<?php the_permalink(); ?>" class="btn btn-default"> <?php _e('Читать дальше', 'clean'); ?> </a> </p> </div> </li> <?php endwhile; ?> </ul> <?php the_posts_pagination(); ?> <?php else: ?> <p><?php _e('Ничего не найдено', 'clean'); ?></p> <?php endif; ?>
Добавляем каталог в меню
Записи типа post
могут быть показаны на главной странице сайта, либо на статической странице сайта. Это задается в настройках в панели управления:
Вместе с записями типа post
мы можем вывести и записи типа book
. Для этого достаточно добавить в наш плагин следующий код:
/* * Показываем книги на главной странице вместе с постами блога */ add_action('pre_get_posts', function ($query) { if (is_home() && $query->is_main_query()) { $query->set('post_type', ['post', 'book']); } return $query; });
Но мы можем показать на главной странице только книги, для этого нужно лишь немного изменить код:
/* * Показываем на главной странице только книги */ add_action('pre_get_posts', function ($query) { if (is_home() && $query->is_main_query()) { $query->set('post_type', ['book']); } return $query; });
А теперь представим такую ситуацию. Есть сайт, на главной странице показывается статическая страница. Записи типа post
показываются на статической странице «Блог», эта страница есть в главном меню. И мы хотим добавить в главное меню еще один пункт «Книги». Для этого создаем статическую страницу со слагом books
. И создадим для этой страницы шаблон page-books.php
в директории темы:
<?php /** * Шаблон для показа списка записей типа book с * постраничной навигацией, файл page-books.php */ /* * Подключаем шапку сайта */ get_header(); ?> <div id="content"> <div class="container"> <div class="row"> <main class="col-md-9"> <?php the_post(); ?> <h1><?php the_title(); ?></h1> <?php the_content(); ?> <?php // изменяем основной запрос, теперь он будет содержать не данные // о статической странице books, а данные о записях типа book query_posts([ 'post_type' => 'book', 'publish' => true, 'paged' => get_query_var('paged'), ]); get_template_part('parts/list-book'); ?> </main> <aside class="col-md-3"> <?php get_sidebar(); ?> </aside> </div> </div> </div> <?php /* * Подключаем подвал сайта */ get_footer(); ?>
Создаем статическую страницу:
Добавляем эту страницу в меню:
И вот что получилось в итоге:
book
, в публичной части сайта доступна страница /book/
. Если она все-таки недоступна — надо в панели управления перейти на страницу настроек постоянных ссылок и нажать кнопку «Сохранить изменения». В качестве шаблона эта страница использует файл archive.php
темы, но лучше создать отдельный шаблон archive-book.php
.
books
и шаблон page-books.php
, как мы это делали выше. Достаточно просто добавить в меню произвольную ссылку http://server.com/book/
. Иначе, мы получим две абсолютно одинаковые страницы со списком всех книг, но доступные по разным адресам /book/
и /books/
.
- WordPress. Пользовательские таксономии
- WordPress. Виджет «Дерево категорий»
- WordPress. Фильтр записей по произвольным полям. Часть 1 из 3
- WordPress. Что такое сайдбар
- WordPress. Фильтр записей по произвольным полям. Часть 3 из 3
- WordPress. Фильтр записей по произвольным полям. Часть 2 из 3
- WordPress. Добавляем мета-теги. Часть 3 из 3
Поиск: CMS • Web-разработка • WordPress • Виджет • Иерархия • Навигация • Плагин • Таксономия • register_taxonomy • register_post_type