О произвольных типах записей в Вордпрессе (CPT, Custom Post Types in WordPress), как создать и настроить, добавить категории и теги, как сделать вложенные URL /тип записи/рубрика/запись
или https://example.com/post_type/category/post/
.
Тут также описывается, как расширить стандартный функционал WordPress, создав новые типы записей, которые можно использовать в различных целях: добавить собственное порфтолио, картотеку фильмов и музыки, каталог продукции, календарь событий, даже сделать свой небольшой интернет-магазин (потому что для большого лучше пользоваться готовыми решениями навроде WooCommerce) или социальную сеть, и много чего ещё в этом духе.
Вначале общая информация, дальше — частности.
- О записях в WordPress: где хранятся в базе данных, и как их получить
- Предустановленные типы записей в WordPress: post, page, attachment, revision, nav_menu_item
- Записи или посты (post)
- Страницы (page)
- Создаём специальный шаблон страницы (page)
- Прикрепления, вложения или аттачменты (attachment)
- Редакции, черновики или ревизии (revision)
- Элементы навигационного меню (nav_menu_item)
- Пользовательский Произвольный тип записи (Custom Post Type, CPT WordPress)
- Как правильно подобрать название нового типа записи
- Как сделать произвольную таксономию
- Шаблоны для произвольных типов постов
- Шаблон страницы записи
- Шаблон архива записей
- Шаблон произвольной таксономии
- Как получить данные произвольного типа записей (Custom Post Type WordPress) и отобразить на сайте
- Готовый класс для создания произвольного типа записей с произвольной таксономией
- Создание произвольного типа записей с помощью плагина Custom Post Type UI
- Иерархия шаблонов темы в WordPress
- В заключение
О записях в WordPress: где хранятся в базе данных, и как их получить
Абсолютно все записи в WordPress, про которые чуть ниже, хранятся в одной таблице: wp_posts
. Метаданные постов, например, данные из метабоксов Yoast SEO, хранятся в таблице wp_postmeta
.
Приведу пример, как получить 10 записей типа post
(стандартные Записи в панели администратора).
В общих чертах, данные особо запрашивать не надо. В шаблонах они уже предустановлены, например, в single.php
данные по записи уже доступны для обработки в цикле
if ( have_posts() ) { while ( have_posts() ) { the_post(); // Тут используем данные из цикла, такие как the_title() и т.п. } }
Если данные нужно получить где-то вне цикла или шаблона, используется запрос WP_Query
$args = array( 'post_type' => 'post', // Тип поста: page, attachment, ... 'posts_per_page' => 10, // 10 записей за раз ); $p = get_posts( $args ); // Данные можно раскрыть в цикле if ( !empty( $p ) ) { foreach ( $p as $post ) { setup_postdata( $post ); ?> <a href="<?= the_permalink() ?>"><?= the_title() ?></a> <?php } wp_reset_postdata(); }
Данные можно получить посредством SQL запроса:
global $wpdb; $query = "SELECT * FROM {$wpdb -> posts} WHERE post_type = 'post' LIMIT 10"; $p = $wpdb -> get_results( $query ); exit( print_r( $p ) ); // в $p теперь массив с данными о постах
Все три способа выше дадут одинаковый результат на выходе.
Предустановленные типы записей в WordPress: post, page, attachment, revision, nav_menu_item
Как вы, наверное, знаете, Worpdress имеет предустановленные типы контента: записи (post
) и страницы (page
). Есть ещё несколько предустановленных типов (attachment
— аттачменты: изображения, аудио, видео; revision
— ревизии записей, по сути, черновики; nav_menu_item
— элементы меню), но они больше служебные и вспомогательные. Далее речь о них.
Записи или посты (post)
Самая используемая единица из всех типов, что есть в WordPress — Записи
(они же посты, post
). Используется в роли постов блога и тому подобного. Имеет 2 предустановленных таксономии: рубрики, они же категории (category
) и метки, они же теги (post_tag
).
Таксономии
служат для сортировки и упорядочивания записей.
Рубрики
отличаются от меток тем, что имеют древовидную структуру (могут быть вложенными друг в друга).
Метки
являются независимыми друг от друга единицами и этим чем-то похожи на Записи
.
Также, по умолчанию, из записей формируется RSS лента сайта на Вордпрессе.
Для Записей
используются следующие файлы шаблонов (в порядке приоритета):
single-post.php
single.php
singular.php
index.php
Файлы шаблонов ищутся сверху вниз по списку в порядке приоритета. Если файл шаблона найден в теме, используется он, а поиск прекращается.
Страницы (page)
Страницы используются, в основном, в роли служебных страниц, посадочных страниц — лендингов, сборника энциклопедии и тому подобного. Имеют древовидную иерархию, то есть могут быть вложенными друг в друга, что отразится в адресе конечной страницы (ярлыки родительских будут присутствовать в цепочке URL), и в этой роли имеется возможность выставить им приоритет в сортировке.
Чтобы сделать лендинг, вы можете пойти двумя путями:
Создаём специальный шаблон страницы (page)
Где-нибудь внутри темы в корне или её поддиректории создать файл с произвольным названием и расширением php
, например, landing.php
. Внутри вы можете разместить совершенно любой шаблон, который может быть абсолютно не похож на другие страницы сайта. Но главное, это поместить вот такой код в начало файла:
<?php /* Template Name: Наш уникальный лендинг */
Template Name
— это специальная метка, которая говорит WordPress о том, что этот файл — специальный шаблон.
Теперь при создании и редактировании любой страницы (page) посмотрите в блоке справа с названием Атрибуты страницы
, в нём в разделе Шаблон
вы можете выбрать наш уникальный лендинг.
Для Страниц (Page
) используется следующая иерархия шаблонов. Как и с Записями
, указываю в порядке приоритета:
{шаблон}.php
page-{ярлык_страницы}.php
page-{ID_страницы}
page.php
singular.php
index.php
Прикрепления, вложения или аттачменты (attachment)
Служебный тип, предназначенный для хранения информации о файлах (изображениях, аудио, видео и тому подобных), которые загружались через загрузчик в стандартном редакторе WordPress при редактировании Записи, Страницы или подобного: размер, вес, описание, к какому посту или странице прикреплены, и тому подобное.
Получить вложения для последующей манипуляции над ними можно с помощью следующего кода:
$args = array( 'post_type' => 'attachment', // Тип поста: attachment 'post_status' => 'inherit', // По умолчанию "publish", а с ним вложения не получить, поэтому указываем специальный статус вложения "inherit" ); $p = get_posts( $args ); exit( print_r( $p ) ); // На выходе будем иметь массив с вложениями
Иерархия шаблонов для аттачментов:
{mime-тип}.php
{mime-подтип}.php
{mime-тип-подтип}.php
attachment.php
single.php
singular.php
index.php
Редакции, черновики или ревизии (revision)
Редакции
, они же Ревизии
— это версии черновиков записей, которые создаются автоматически, пока вы пишете статью в административной панели Вордпресса или сохраняете статью без фактической её публикации.
В процессе написания, для каждой статьи по умолчанию сохраняется каждая версия черновика. Можно сравнить две разные версии, и к нужной можно откатиться назад.
Хранить помногу версий одной и той же статьи — довольно накладно и часто бессмысленно (хотя, наверное, правильнее было бы оставлять всё по умолчанию, регулярно подчищая старые редакции с помощью плагина, например WP Optimize), поэтому число сохраняемых версий Ревизий
можно изменить с помощью 2 вариантов:
- Использовать фильтр wp_revisions_to_keep
- Прописать в wp-config.php
//Отключаем ревизии до минимально возможного значения define( 'WP_POST_REVISIONS', 0 );
Возможные значения:
true
или-1
: сохраняет каждую версию черновика. Вариант по умолчаниюfalse
или0
: отключает сохранение черновиков, кроме 1 автосохранения- Целое число больше нуля: сохраняется указанное число версий черновиков + 1 автосохранение. Старые версии, не укладывающиеся в указанное число, автоматически удаляются
Элементы навигационного меню (nav_menu_item)
Навигационное меню (nav_menu_item
) — это тип записей, который хранит информацию об единице навигации в WordPress. Первый, и пока единственный тип записи, который используется не как остальные типы записей, данные для работы и отображения на сайте получают свои отдельные функции.
Также, навигационные меню по умолчанию не включены. Чтобы их включить, нужно объявить об их поддержке в functions.php:
- Прописать
add_theme_support( 'menus' );
- Или зарегистрировать место под меню с помощью register_nav_menu(), тогда поддержка меню включится автоматически
Для получения данных пользуйтесь wp_nav_menu(), потому что WP_Query
не будет работать, и это отличительная особенность типа постов nav_menu_item
// Этот код сработает wp_nav_menu(); // Выведет первое зарегистрированное непустое меню // А код ниже работать не будет $args = array( 'post_type' => 'nav_menu_item', // Тип поста: page, attachment, ... ); $p = get_posts( $args ); exit( print_r( $p ) ); // На выходе будем иметь пустой массив
Пользовательский Произвольный тип записи (Custom Post Type, CPT WordPress)
Вот мы и подошли к главному — тому инструменту, который позволяет расширить стандартный блоговый функционал WordPress до бесконечных возможностей: пользовательский произвольный тип записи.
Самый простой пример, как можно зарегистрировать наш новый тип записи sheensay_product
add_action( 'init', 'sheensay_post_type' ); function sheensay_post_type() { register_post_type( 'sheensay_product', array( 'labels' => array( 'name' => 'Продукция', 'singular_name' => 'Продукцию', ), 'public' => true, // тип записи открыт для поиска и тому подобного 'has_archive' => true, // Включаем страницы архивов 'supports' => array( 'title', 'editor', 'thumbnail', 'comments' ), // Включаем поддержку заголовка, редактора, миниатюры, комментариев ) ); }
Здесь sheensay_product
— это название нового типа записей. Оно не должно конфликтовать с другими в системе, об этом подробнее ниже.
Также, в этом варианте оно служит ярлыком этого типа записей, то есть присутствует в URL. Если же хотите указать другой ярлык, например продукция, делайте как на примере ниже
add_action( 'init', 'sheensay_post_type' ); function sheensay_post_type() { register_post_type( 'sheensay_product', array( 'labels' => array( 'name' => 'Продукция', 'singular_name' => 'Продукцию', ), 'public' => true, 'rewrite' => array( 'slug' => 'продукция' ), // Тут определяется ярлык Custom Post Type 'has_archive' => true, 'supports' => array( 'title', 'editor', 'thumbnail' ), ) ); }
Как правильно подобрать название нового типа записи
В WordPress зарезервированы следующие названия, которые нельзя использовать в качестве имени нового типа записи:
post
page
attachment
revision
nav_menu_item
action
theme
order
Также, стоит воздержаться от использования префикса
wp_
в начале названия, так как, возможно, это вызовет конфликты с будущими версиями ядра WordPress.
Лучше всего, если вы будете предварять названия произвольными префиксами, связанными с названием вашего сайта, продукта или бренда, напримерsheensay_product
, тогда гарантированно избежите потенциальных конфликтов
Как сделать произвольную таксономию
Произвольные типы записей могут использовать таксономии из записей, например, рубрики (категории) или метки (теги), но можно, чтобы таксономии были свои.
add_action( 'init', 'sheensay_post_type' ); function sheensay_post_type() { // Регистрируем таксономию register_taxonomy( 'sheensay_product_type', 'sheensay_product', array( 'label' => 'Типы', 'hierarchical' => true, // Если TRUE, таксономия будет аналогом рубрик (категорий). Если FALSE (по умолчанию), то таксономия станет аналогом меток (тегов). 'rewrite' => array( 'slug' => 'тип-продукции' ), ) ); // Регистрируем произвольный тип записи (Custom Post Type) register_post_type( 'sheensay_product', array( 'labels' => array( 'name' => 'Продукция', 'singular_name' => 'Продукцию', ), 'public' => true, 'rewrite' => array( 'slug' => 'продукция' ), // Тут определяется ярлык CPT 'has_archive' => true, 'supports' => array( 'title', 'editor', 'thumbnail' ), // Включаем поддержку заголовка, редактора, миниатюры ) ); }
Шаблоны для произвольных типов постов
Всё зависит от того, какого рода информация отображается. Вариантов может быть 3: шаблон конкретной записи, шаблон архивов записей и шаблон таксономий
Шаблон страницы записи
Перечисляются в порядке приоритета
single-{тип_поста}.php
single.php
index.php
{тип_поста}
в нашем случае, здесь и далее — это sheensay_product
Шаблон архива записей
archive-{тип_поста}.php
archive.php
index.php
Шаблон произвольной таксономии
taxonomy-{имя_таксономии}-{имя_термина}.php
taxonomy-{имя_таксономии}.php
taxonomy.php
archive.php
index.php
Здесь имя_таксономии
— это sheensay_product_type
, а имя_термина
— это ярлык той таксономии, что вы создадите в админке.
Как получить данные произвольного типа записей (Custom Post Type WordPress) и отобразить на сайте
Получить данные произвольного типа записей (Custom Post Type) в WordPress для отображения на сайте можно теми же способами, что и обычные Записи
и Страницы
$args = array( 'post_type' => 'sheensay_product', // Указываем наш новый тип записи 'posts_per_page' => 10, ); $p = get_posts( $args ); foreach ( $p as $post ) { setup_postdata( $post ); ?> <a href="<?= the_permalink() ?>"><?= the_title() ?></a><br /> <?php } wp_reset_postdata(); ?>
Если же говорить про главный запрос, по которому данные, например, предзагружаются для вывода на главной странице или стандартных страницах архивов, то произвольные типы записей там отключены.
Поэтому, если вы хотите, чтобы какой-либо созданный тип записей отображался, скажем, на страницах архивов наряду с обычными записями, вам нужно изменить фильтр предзагрузки постов
// Подключаем к стандартным 'post' и 'page' наш 'sheensay_product' add_action( 'pre_get_posts', 'add_sheensay_product_in_main_query' ); function add_sheensay_product_in_main_query( $query ) { if ( is_archive() && $query -> is_main_query() ) $query -> set( 'post_type', array( 'post', 'page', 'sheensay_product' ) ); return $query; }
Готовый класс для создания произвольного типа записей с произвольной таксономией
Ниже представлен класс, с помощью которого вы сможете зарегистрировать любой произвольный тип записей с собственной таксономией, а URL будет иметь вид
http://example.com/продукция/тип/продукт
Чтобы URL формировался, вы должны перейти в настройки постоянных ссылок
/wp-admin/options-permalink.php
и установить любой отличный от простого вид общих настроек
Ниже сам код класса. Вы можете не вносить в него никаких изменений, а поменять ярлык типа записи можно в самом конце в строке new Sheensay_Product( 'продукция' );
Сам код пишется в MU Plugin или в functions.php. Первый вариант предпочтительнее, так как в этом случае, вы не потеряете доступа к контенту нового типа записей при смене активной темы.
<?php /** * Новости. Объявления * * https://example.com/тип записи/рубрика/запись * https://example.com/post_type/category/post/ * * @link https://sheensay.ru/?p=1713 * */ final class CPT { // Ярлык произвольного типа записи по умолчанию private $post_type = ''; function __construct( $post_type, $post_slug, $labels ) { // Переопределяем значение ярлыка по умолчанию $this -> post_type = $post_type; $this -> post_slug = $post_slug; $this -> labels = $labels; /* * Регистрируем Custom Post Type */ add_action( 'init', array( $this, 'cpt' ) ); // Yoast SEO Breadcrumbs add_filter( 'wpseo_breadcrumb_links', [ $this, 'seo' ], 10, 2 ); /* * Фильтруем URL */ add_filter( 'post_type_link', array( $this, 'product_permalink_structure' ), 10, 2 ); /* * Чтобы работала пагинация */ add_action( 'generate_rewrite_rules', array( $this, 'fix_product_category_pagination' ) ); } // Yoast SEO Breadcrumbs function seo( $links ) { if ( is_singular( [ $this -> post_type ] ) ) { global $post; $term = get_the_terms( $post, "{$this -> post_type}_cat" )[0]; $text = $term -> name; $href = get_term_link( $term, "{$this -> post_type}_cat" ); // Добавляем элемент в ассоциативный массив ссылок array_splice( $links, $offset = 2, $length = 1, [ [ 'text' => $text, 'url' => $href, 'allow_html' => '1', ] ] ); } // Страница таксономий if ( is_tax( "{$this -> post_type}_cat" ) ) { $text = $this -> labels['name']; $href = site_url( $this -> post_slug ); // Добавляем элемент в ассоциативный массив ссылок array_splice( $links, $offset = 1, $length = 0, [ [ 'text' => $text, 'url' => $href, 'allow_html' => '1', ] ] ); } return $links; } function cpt() { /* * Регистрируем произвольную таксономию к новому типу записей */ register_taxonomy( "{$this -> post_type}_cat", $this -> post_type, array( 'label' => 'Рубрики', 'hierarchical' => true, 'query_var' => true, 'show_admin_column' => true, 'show_in_rest' => true, 'rewrite' => array( 'slug' => $this -> post_slug ), ) ); /* * Регистрируем новый тип записи */ $args = array( 'labels' => $this -> labels, 'public' => true, 'publicly_queryable' => true, 'show_ui' => true, 'query_var' => true, 'capability_type' => 'post', 'hierarchical' => false, 'menu_position' => 4, 'menu_icon' => 'dashicons-welcome-write-blog', 'supports' => [ 'title', 'editor', 'thumbnail' ], 'rewrite' => [ 'slug' => "{$this -> post_slug}/%{$this -> post_type}_cat%", ], 'has_archive' => $this -> post_slug, 'taxonomies' => [ "{$this -> post_type}_cat" ], ); register_post_type( $this -> post_type, $args ); if ( current_user_can( 'manage_options' ) ) // Вот с этой функцией осторожней. Она сбрасывает все правила определения URL. Лучше её закомментировать после завершения всех работ flush_rewrite_rules(); } function product_permalink_structure( $post_link, $post ) { // Если находиммся на странице нашего CPT if ( FALSE !== strpos( $post_link, "%{$this -> post_type}_cat%" ) ) { $product_type_term = get_the_terms( $post -> ID, "{$this -> post_type}_cat" ); if ( !empty( $product_type_term ) ) $post_link = str_replace( "%{$this -> post_type}_cat%", $product_type_term[0] -> slug, $post_link ); } return $post_link; } function fix_product_category_pagination( $wp_rewrite ) { unset( $wp_rewrite -> rules[$this -> post_type . '/([^/]+)/page/?([0-9]{1,})/?$'] ); $wp_rewrite -> rules = array( $this -> post_type . '/?$' => $wp_rewrite -> index . "?post_type={$this -> post_type}", $this -> post_type . '/page/?([0-9]{1,})/?$' => $wp_rewrite -> index . "?post_type={$this -> post_type}&paged=" . $wp_rewrite -> preg_index( 1 ), $this -> post_type . '/([^/]+)/page/?([0-9]{1,})/?$' => $wp_rewrite -> index . "?{$this -> post_type}_cat=" . $wp_rewrite -> preg_index( 1 ) . '&paged=' . $wp_rewrite -> preg_index( 2 ), ) + $wp_rewrite -> rules; } } /* * Запускаем класс * В скобках нужно определить $post_type, название ярлыка типа записи и $labels */ new CPT( 'note', 'objavlenija', $labels = array( 'name' => 'Объявления', // Основное название 'singular_name' => 'Объявление', // Добавить 'add_new' => 'Добавить новое', // Имя ссылки на новую запись в сайдбаре 'add_new_item' => 'Добавить новое Объявление', // Заголовок в редакторе при добавлении новой записи ) ); new CPT( 'help', 'spravochnaya', $labels = array( 'name' => 'Справочная', // Основное название 'singular_name' => 'Справка', // Добавить 'add_new' => 'Добавить новую', // Имя ссылки на новую запись в сайдбаре 'add_new_item' => 'Добавить новую Справку', // Заголовок в редакторе при добавлении новой записи ) );
Теперь в админке вы можете зарегистрировать новую продукцию и их типы
Создание произвольного типа записей с помощью плагина Custom Post Type UI
Чтобы не писать код вручную, вы можете воспользоваться готовым плагином. Он довольно популярен, и на момент написания статьи имеет 500 тысяч скачиваний из официального репозитория WordPress.org
Скачать плагин Custom Post Type UI из официального репозитория WordPress.org
Иерархия шаблонов темы в WordPress
Ниже иллюстрация иерархии шаблонов, то есть как ищутся и подбираются подходящие шаблоны (template) внутри темы (кликабельно):
В заключение
Я постарался сжато пройтись по всем пунктам этой важной темы. Если что-то осталось непонятным, задавайте вопросы, статья будет дополняться новыми примерами.
Свежие комментарии