Регистрация пользовательского типа поста
Конечно же, самое интересное начинается, когда мы создаем собственный тип записей. Это может быть абсолютно, что угодно: работы в портфолио, опросы, товары в интернет-магазине.
Никогда! Не используйте плагины для регистрации типов записей.
Момент, о котором я решил сразу упомянуть. Знаю, что не так давно я высказывал недовольство от того, что для работы с произвольными полями люди используют плагин ACF и рекомендовал всем перейти на Carbon Fields. Так вот, с типами записей всё ещё гораздо гораздо печальнее. Ведь вся суть в том, что такие плагины, как acf или carbon fields хотя бы помогают вам сэкономить время на разработку метабоксов (про acf кстати не уверен, по факту гораздо больше времени потратил, тыкаясь в его интерфейсе). Если кодить метабоксы с нуля, то там действительно немало кода. Так вот, а в случае с произвольными типами постов мне вообще неясен смысл использования плагинов. Самый популярный вроде CPT UI.
Чуть ниже в первом шаге мы уже зарегистрируем тип записи и вы убедитесь в том, насколько это легко. Во втором-третьем шагах мы уже поговорим о дополнительной кастомизации.
register_post_type()
Всё начинается с функции register_post_type(). Пока что вы можете использовать код, который найдёте ниже, подставив свои собственные значения параметров в массивы.
add_action( 'init', 'true_register_post_type_init' ); function true_register_post_type_init() { $labels = array( 'name' => 'Лиды', 'singular_name' => 'Лид', 'add_new' => 'Добавить лид', 'add_new_item' => 'Добавить лид', 'edit_item' => 'Редактировать лид', 'new_item' => 'Новый лид', 'all_items' => 'Все лиды', 'search_items' => 'Искать лиды', 'not_found' => 'Лидов по заданным критериям не найдено.', 'not_found_in_trash' => 'В корзине нет лидов.', 'menu_name' => 'Лиды' ); $args = array( 'labels' => $labels, 'public' => true, 'publicly_queryable' => false, 'has_archive' => false, 'menu_icon' => 'dashicons-email-alt2', 'menu_position' => 2, 'supports' => array( 'title', 'editor' ) ); register_post_type( 'lead', $args ); }
Важно: в качестве имени типа поста (первый аргумент функции) нельзя использовать следующие слова: post
, page
, attachment
, revision
, nav_menu_item
, action
, order
, theme
. Помню случай, когда я пытался зарегистрировать тип поста order
и не мог понять, почему ничего не работает.
Ещё более супер важно – если ваш тип записи будет просматриваемым на сайте и использовать ЧПУ, то обязательно после его создания зайдите в Настройки > Постоянные ссылки и, не меняя даже ничего, нажмите кнопку сохранения изменений.
Этот пример очень упрощён. На моем блоге вы также найдете полную документацию функции register_post_type() с подробным описанием её параметров и их значений.
В рамках работы с нашей темой вставляйте код в functions.php
, а вообще читайте это.
В результате получаем:

Круто, да? Дальше вы уже можете приступать к работе с этим типом записей, а я ещё покажу несколько моментов его настройки.
Тексты уведомлений для типа постов
В принципе обычно бывает достаточно первого шага, однако, если вы всерьез занялись настройкой админки, то остальные шаги тоже важны.
Наверное вы понимаете, о каких уведомлениях идет речь. Это сообщения, которые появляются в верхней части экрана при например сохранении или обновлении поста.

Если вы пропустите этот шаг, то по умолчанию будут использоваться уведомления из записей типа post
.
add_filter( 'post_updated_messages', 'true_post_type_messages' ); function true_post_type_messages( $messages ) { global $post, $post_ID; $messages[ 'lead' ] = array( // lead - название созданного нами типа записей 0 => '', // Данный индекс не используется. 1 => 'Лид обновлён.', 2 => 'Поле изменено.', 3 => 'Поле удалено.', 4 => 'Лид обновлён.', 5 => isset( $_GET[ 'revision' ] ) ? sprintf( 'Лид восстановлен из редакции из редакции: %s', wp_post_revision_title( (int) $_GET[ 'revision' ], false ) ) : false, 6 => 'Лид добавлен.', 7 => 'Лид сохранён.', 8 => 'Отправлено на проверку.', 9 => sprintf( 'Лид запланирован на публикацию на <strong>%1$s</strong>.', date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ) ), 10 => 'Черновик лида сохранён', ); return $messages; }
Кроме того, есть ещё сообщения быстрого редактирования постов. Вот о чём я говорю:

Их тоже можно подкорректировать при помощи хуков, а конкретнее – при помощи bulk_post_updated_messages
.
add_filter( 'bulk_post_updated_messages', 'true_bulk_post_updated_messages', 25, 2 ); function true_bulk_post_updated_messages( $messages, $counts ) { $bulk_messages[ 'lead' ] = array( // не совсем правильный способ, но уже полностью рабочий прямо сейчас 'updated' => $counts[ 'updated' ] . ' ' . true_wordform( $counts[ 'updated' ], 'лид', 'лида', 'лидов') . ' обновлено.', 'locked' => $counts[ 'locked' ] . ' ' . true_wordform( $counts[ 'locked' ], 'лид', 'лида', 'лидов') . ' не обновлено, потому что кто-то редактирует их.', 'deleted' => $counts[ 'deleted' ] . ' ' . true_wordform( $counts[ 'deleted' ], 'лид', 'лида', 'лидов') . ' удалено безвозвратно.', 'trashed' => $counts[ 'deleted' ] . ' ' . true_wordform( $counts[ 'deleted' ], 'лид', 'лида', 'лидов') . ' перемещено в корзину.', // правильный способ, это когда наш код поддерживает локализацию // но при написание чего-либо для себя, возможно в этом и нет большого смысла 'untrashed' => _n( '%s lead restored from the Trash.', '%s leads restored from the Trash.', $bulk_counts[ 'untrashed' ] ), ); return $bulk_messages; }
Несколько важных моментов по коду сразу:
- Функция
true_wordform()
вряд ли у вас определена, её вы можете найти тут и нужна она для склонения слов. - Однако это не совсем правильный способ, особенно, если вы пишете плагин или тему не для какого-то определённого клиента или для себя, а для людей. В таком случае ваш код должен поддерживать локализацию этих строк и использовать функцию _n().
$bulk_messages[ 'lead' ]
– в качестве ключа этого массива указываем свой тип записи.
Вкладка «Помощь»
Вкладка «Помощь» находится в правой верхней части экрана. Для нашего типа поста её ещё пока что нет, но вы сможете найти её на странице записей в админке например.

Да, содержимое этой вкладки мы тоже можем настроить. Это обычно бывает полезно при работе с клиентами, для которых админка WordPress нелегка в освоении. Туда можно добавить какую-нибудь справочную информацию и не только.
Что мы и сделаем:

Следующий код будет работать в версиях WordPress 3.3 и выше.
add_action( 'admin_head', 'true_post_type_help_tab', 25 ); function true_post_type_help_tab() { $screen = get_current_screen(); // Прекращаем выполнение функции, если находимся на страницах других типов постов if ( 'lead' !== $screen->post_type ) { return; } // Добавляем первую вкладку $screen->add_help_tab( array( 'id' => 'tab_1', 'title' => 'Общая информация', 'content' => '<h3>Общая информация</h3><p>На этой странице вы сможете найти все заявки, отправленные через формы обрутной связи на странице контактов.</p>' ) ); // Добавляем вторую вкладку $screen->add_help_tab( array( 'id' => 'tab_2', 'title' => 'Вторая вкладка', 'content' => '<h3>Вторая вкладка</h3><p>Содержимое второй вкладки</p>' ) ); }
Колонки в таблице со списком постов произвольного типа
Про работу с колонками в админке у меня есть отдельный исчерпывающий урок. Сейчас же, в качестве примера, добавим ещё одну колонку, в которой будет выводиться текст сообщения лида.
Получится что-то в этом роде:

Код:
add_filter( 'manage_edit-lead_columns', 'true_add_lead_columns', 25 ); function true_add_lead_columns( $columns ){ $message = array( 'message' => 'Сообщение' ); $columns = array_slice( $columns, 0, 2, true ) + $message + array_slice( $columns, 2, NULL, true ); return $columns; } add_action( 'manage_posts_custom_column', 'true_fill_lead_columns', 25 ); function true_fill_lead_columns( $column ) { switch ( $column ) { case 'message': { global $post; echo wpautop( esc_html( $post->post_content ) ); break; } } }
На этом с регистрацией и настройкой типа записи – всё! Дальше уже работаем с ним в рамках нашей задачи, например в этом видео – автоматически будем создавать посты при отправке формы пользователями.
источник: учебник Михаила Радрастых
Пример плагина сотрудников.
добавляем тип записи и таксономия для него.
add_action( 'init', 'main' );
function main() {
$taxLabels = [
'name' => 'Отделы',
'singular_name' => 'Отдел',
'search_items' => 'Поиск отделов',
'all_items' => 'Все отделы',
'view_item ' => 'Просмотреть отдел',
'parent_item' => 'Родительский отдел',
'parent_item_colon' => 'Родительский отдел:',
'edit_item' => 'Редактировать отдел',
'update_item' => 'Обновить отдел',
'add_new_item' => 'Добавить отдел',
'new_item_name' => 'Новый отдел',
'menu_name' => 'Отдел',
'back_to_items' => '← Вернуться к отделам',
];
$taxArgs = [
'public' => true,
'labels' => $taxLabels,
'hierarchical' => true,
];
register_taxonomy('department', ['staff'], $taxArgs);
$labels = array(
'name' => 'Сотрудники',
'singular_name' => 'Сотрудник',
'add_new' => 'Добавить сотрудника',
'add_new_item' => 'Добавить сотрудника',
'edit_item' => 'Редактировать сотрудника',
'new_item' => 'Новый сотрудник',
'all_items' => 'Все Сотрудники',
'search_items' => 'Искать Сотрудников',
'not_found' => 'Сотрудников по заданным критериям не найдено.',
'not_found_in_trash' => 'В корзине нет сотрудников.',
'menu_name' => 'Компания'
);
$args = array(
'labels' => $labels,
'public' => true,
'has_archive' => true,
'menu_icon' => 'dashicons-email-alt2',
'menu_position' => 3,
'supports' => array('title','editor','author','thumbnail','trackbacks','custom-fields','comments','revisions')
);
register_post_type('staff', $args);
}
Добавляем метаданные и метабокс для их редактирования
add_action( 'add_meta_boxes', 'staff_add_custom_box' );
function staff_add_custom_box() {
$screens = [ 'staff' ];
foreach ( $screens as $screen ) {
add_meta_box(
'staff_metabox', // Unique ID
'Карточка сотрудника', // Box title
'staff_custom_box_html', // Content callback, must be of type callable
$screen, // типы постов, для которых его подключим
'normal', // расположение (normal, side, advanced)
'high' // приоритет (default, low, high, core)
);
}
}
function staff_custom_box_html( $post ) {
// сначала получаем значения этих полей
$staff_phone = get_post_meta( $post->ID, 'phone', true );
$staff_age = get_post_meta( $post->ID, 'age', true );
wp_nonce_field( 'seopostsettingsupdate-' . $post->ID, '_truenonce' );
?>
<label for="phone_box">Телефон сотрудника</label>
<input type="text" value="<?=esc_attr($staff_phone);?>" id="phone" name="phone" class="regular-text">
<label for="age_box">Возраст сотрудника</label>
<input type="number" value="<?=esc_attr($staff_age);?>" id="age" name="age" class="regular-text">
<?php
}
пишем функцию для сохранения метаданных нового типа записи.
function true_save_meta_staff( $post_id, $post ) {
// проверка одноразовых полей
if ( ! isset( $_POST[ '_truenonce' ] ) || ! wp_verify_nonce( $_POST[ '_truenonce' ], 'seopostsettingsupdate-' . $post->ID ) ) {
return $post_id;
}
// проверяем, может ли текущий юзер редактировать пост
$post_type = get_post_type_object( $post->post_type );
if ( ! current_user_can( $post_type->cap->edit_post, $post_id ) ) {
return $post_id;
}
// ничего не делаем для автосохранений
if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) {
return $post_id;
}
// проверяем тип записи
if( !in_array($post->post_type, array('staff')) ) {
return $post_id;
}
if( isset( $_POST[ 'phone' ] ) ) {
update_post_meta( $post_id, 'phone', sanitize_text_field( $_POST[ 'phone' ] ) );
} else {
delete_post_meta( $post_id, 'phone' );
}
if( isset( $_POST[ 'age' ] ) ) {
update_post_meta( $post_id, 'age', sanitize_text_field( $_POST[ 'age' ] ) );
} else {
delete_post_meta( $post_id, 'age' );
}
return $post_id;
}
Остаётся разработать шаблон для вывода этого типа постов. Либо написать в плагине шорткод выводящий эти записи и использовать его.