Добавление настроек к пользовательскому типу записей
У меня есть пользовательский тип записей Portfolio. Он связан с тремя пользовательскими таксономиями. Всё работает нормально.
Однако для архивной страницы мне нужно добавить несколько пользовательских настроек. Из-за ограничений проекта я не могу создать плагин — все изменения должны быть сделаны в теме.
Мне удалось добавить страницу настроек в подменю (это было несложно), следуя этому руководству, и настройки отображаются на странице без проблем. Проблема в том, что они не сохраняются.
Пока я добавил только одну настройку (header_text
), пока не решу проблему с сохранением.
Думаю, что проблема, вероятно, в $option_group
.
Если сделать var_dump($_POST)
, я получаю:
array (size=6)
'option_page' => string 'edit.php?post_type=rushhour_projects&page=projects_archive' (length=58)
'action' => string 'update' (length=6)
'_wpnonce' => string '23c70a3029' (length=10)
'_wp_http_referer' => string '/wp-admin/edit.php?post_type=rushhour_projects&page=projects_archive' (length=68)
'rushhour_projects_archive' =>
array (size=1)
'header_text' => string 'asdf' (length=4)
'submit' => string 'Save Changes' (length=12)
Вот регистрация пользовательского типа записей:
if ( ! function_exists('rushhour_post_type_projects') ) :
// Добавляем Portfolio Projects в WordPress
add_action( 'init', 'rushhour_post_type_projects', 0 );
// Регистрируем пользовательский тип записей Portfolio Projects
function rushhour_post_type_projects()
{
$labels = array(
'name' => _x( 'Портфолио', 'Общее название типа записи', 'rushhour' ),
'singular_name' => _x( 'Проект', 'Название одного элемента этого типа', 'rushhour' ),
'menu_name' => __( 'Проекты портфолио', 'rushhour' ),
'name_admin_bar' => __( 'Проект портфолио', 'rushhour' ),
'archives' => __( 'Архивы портфолио', 'rushhour' ),
'parent_item_colon' => __( 'Родительский проект:', 'rushhour' ),
'all_items' => __( 'Все проекты', 'rushhour' ),
'add_new_item' => __( 'Добавить новый проект', 'rushhour' ),
'add_new' => __( 'Добавить новый', 'rushhour' ),
'new_item' => __( 'Новый проект', 'rushhour' ),
'edit_item' => __( 'Редактировать проект', 'rushhour' ),
'update_item' => __( 'Обновить проект', 'rushhour' ),
'view_item' => __( 'Просмотреть проект', 'rushhour' ),
'search_items' => __( 'Искать проекты', 'rushhour' ),
'not_found' => __( 'Не найдено', 'rushhour' ),
'not_found_in_trash' => __( 'Не найдено в корзине', 'rushhour' ),
'featured_image' => __( 'Изображение записи', 'rushhour' ),
'set_featured_image' => __( 'Установить изображение записи', 'rushhour' ),
'remove_featured_image' => __( 'Удалить изображение записи', 'rushhour' ),
'use_featured_image' => __( 'Использовать как изображение записи', 'rushhour' ),
'insert_into_item' => __( 'Вставить в проект', 'rushhour' ),
'uploaded_to_this_item' => __( 'Загружено для этого проекта', 'rushhour' ),
'items_list' => __( 'Список проектов', 'rushhour' ),
'items_list_navigation' => __( 'Навигация по списку проектов', 'rushhour' ),
'filter_items_list' => __( 'Фильтровать список проектов', 'rushhour' ),
);
$rewrite = array(
'slug' => 'portfolio',
'with_front' => true,
'pages' => true,
'feeds' => true,
);
$args = array(
'label' => __( 'Проект', 'rushhour' ),
'description' => __( 'Проекты портфолио для Global VDC.', 'rushhour' ),
'labels' => $labels,
'supports' => array( 'title', 'editor', 'excerpt', 'thumbnail', 'revisions', ),
'taxonomies' => array( 'rushhour_clients', 'rushhour_locations', 'rushhour_project_type' ),
'hierarchical' => false,
'public' => true,
'show_ui' => true,
'show_in_menu' => true,
'menu_position' => 5,
'menu_icon' => 'dashicons-portfolio',
'show_in_admin_bar' => true,
'show_in_nav_menus' => true,
'can_export' => true,
'has_archive' => 'portfolio',
'exclude_from_search' => false,
'publicly_queryable' => true,
'rewrite' => $rewrite,
'capability_type' => 'page',
);
register_post_type( 'rushhour_projects', $args );
}
endif;
Затем у меня есть функция для настройки страницы подменю в админке:
if ( ! function_exists('rushhour_projects_admin_page') ) :
add_action( 'admin_menu' , 'rushhour_projects_admin_page' );
/**
* Создаем страницу подменю для настроек
*
* @uses rushhour_projects_options_display()
*/
function rushhour_projects_admin_page()
{
add_submenu_page(
'edit.php?post_type=rushhour_projects',
__('Настройки проектов портфолио', 'rushhour'),
__('Настройки портфолио', 'rushhour'),
'manage_options',
'projects_archive',
'rushhour_projects_options_display');
}
endif;
Эти две части работают без проблем.
Проблема, как я думаю, где-то в функциях ниже для регистрации и сохранения настроек:
if ( ! function_exists('rushhour_projects_options_display') ) :
/**
* Отображаем форму на странице настроек Rush Hour Projects.
*
* Используется в 'rushhour_projects_admin_page'.
*/
function rushhour_projects_options_display()
{
// Создаем заголовок в стандартном контейнере WordPress 'wrap'
echo '<div class="wrap">';
settings_errors();
echo '<form method="post" action="">';
var_dump( get_option('rushhour_projects_archive') );
settings_fields( 'edit.php?post_type=rushhour_projects&page=projects_archive' );
do_settings_sections( 'edit.php?post_type=rushhour_projects&page=projects_archive' );
submit_button();
echo '</form></div><!-- .wrap -->';
}
endif;
add_action( 'admin_init', 'rushhour_projects_settings' );
/**
* Регистрируем настройки и добавляем секции и поля настроек на страницу админки.
*/
function rushhour_projects_settings()
{
if ( false == get_option( 'rushhour_projects_archive' ) )
add_option( 'rushhour_projects_archive' );
add_settings_section(
'projects_archive_header', // ID секции
__('Настройки архивной страницы проектов портфолио', 'rushhour'),
'rushhour_project_settings_section_title', // Функция обратного вызова
'edit.php?post_type=rushhour_projects&page=projects_archive' // Ярлык страницы настроек
);
add_settings_field(
'header_text', // ID поля
__('Текст заголовка', 'rushhour'), // Название настройки
'projects_archive_header_text_callback',
'edit.php?post_type=rushhour_projects&page=projects_archive', // Ярлык страницы настроек
'projects_archive_header', // ID секции
array('Текст для отображения в заголовке архива.')
);
register_setting(
'edit.php?post_type=rushhour_projects&page=projects_archive', // Группа опций
'rushhour_projects_archive', // Имя опции
'rushhour_projects_archive_save_options'
);
}
/**
* Функция обратного вызова для секции настроек.
*
* Закомментировано, пока настройки не работают.
*
* @param array $args Получает $id, $title и $callback.
*/
function rushhour_project_settings_section_title( $args ) {
// printf( '<h2>%s</h2>', apply_filters( 'the_title', $args['title'] ) );
}
/**
* Функции обратного вызова для полей настроек.
*/
function projects_archive_header_text_callback($args)
{
$options = get_option('rushhour_projects_archive');
printf( '<input class="widefat" id="header_text" name="rushhour_projects_archive[header_text]" type="textarea" value="%1$s" />',
$options );
}
/**
* Сохраняем настройки.
*/
function rushhour_projects_archive_save_options()
{
if ( isset( $_POST['rushhour_projects_archive[header_text]'] ) )
{
update_option( 'rushhour_projects_archive', $_POST['rushhour_projects_archive[header_text]'] );
}
}
Хорошо, меня раздражало, что это не работает, и я решил просто переписать код. Я не уверен, в чём именно было решение, но подозреваю две вещи: неправильный endpoint для формы (должен быть options.php) и неверные значения $option_group
и $option_name
(скорее всего, они не совпадали).
Для потомков оставлю здесь свою переработанную версию, надеюсь, она поможет другим. Несколько отличий между этой и предыдущей версией:
- Теперь это отдельный файл, поэтому регистрация пользовательского типа записи здесь не видна.
- Я использовал объект для страницы, как показано в примере 2 из кодекса WordPress.
- Добавил вторую опцию для загрузчика медиафайлов, используя этот туториал, который я обновил, применив
wp_localize_script()
для инъекции JSON-объекта с данными из PHP.
<?php
class RushHourProjectArchivesAdminPage
{
/**
* Содержит значения, используемые в колбэках полей
*/
private $options;
public function __construct()
{
add_action( 'admin_menu', array( $this, 'add_submenu_page_to_post_type' ) );
add_action( 'admin_init', array( $this, 'sub_menu_page_init' ) );
add_action( 'admin_init', array( $this, 'media_selector_scripts' ) );
}
/**
* Добавляет страницу подменю к пользовательскому типу записи
*/
public function add_submenu_page_to_post_type()
{
add_submenu_page(
'edit.php?post_type=rushhour_projects',
__('Настройки портфолио проектов', 'rushhour'),
__('Настройки портфолио', 'rushhour'),
'manage_options',
'projects_archive',
array($this, 'rushhour_projects_options_display'));
}
/**
* Колбэк страницы настроек
*/
public function rushhour_projects_options_display()
{
$this->options = get_option( 'rushhour_projects_archive' );
wp_enqueue_media();
echo '<div class="wrap">';
printf( '<h1>%s</h1>', __('Настройки портфолио', 'rushhour' ) );
echo '<form method="post" action="options.php">';
settings_fields( 'projects_archive' );
do_settings_sections( 'projects-archive-page' );
submit_button();
echo '</form></div>';
}
/**
* Регистрирует и добавляет настройки
*/
public function sub_menu_page_init()
{
register_setting(
'projects_archive', // Группа опций
'rushhour_projects_archive', // Имя опции
array( $this, 'sanitize' ) // Функция очистки
);
add_settings_section(
'header_settings_section', // ID
__('Настройки заголовка', 'rushhour'), // Заголовок
array( $this, 'print_section_info' ), // Колбэк
'projects-archive-page' // Страница
);
add_settings_field(
'archive_description', // ID
__('Описание архива', 'rushhour'), // Заголовок
array( $this, 'archive_description_callback' ), // Колбэк
'projects-archive-page', // Страница
'header_settings_section' // Секция
);
add_settings_field(
'image_attachment_id',
__('Фоновое изображение заголовка', 'rushhour'),
array( $this, 'header_bg_image_callback' ),
'projects-archive-page',
'header_settings_section'
);
}
/**
* Очищает каждое поле настроек по мере необходимости
*
* @param array $input Содержит все поля настроек в виде ключей массива
*/
public function sanitize( $input )
{
$new_input = array();
if( isset( $input['archive_description'] )
$new_input['archive_description'] = sanitize_text_field( $input['archive_description'] );
if( isset( $input['image_attachment_id'] ) )
$new_input['image_attachment_id'] = absint( $input['image_attachment_id'] );
return $new_input;
}
/**
* Выводит текст секции
*/
public function print_section_info()
{
print 'Выберите настройки для заголовка страницы архива.';
}
/**
* Получает массив опций настроек и выводит одно из его значений
*/
public function archive_description_callback()
{
printf(
'<input type="text" id="archive_description" name="rushhour_projects_archive[archive_description]" value="%s" />',
isset( $this->options['archive_description'] ) ? esc_attr( $this->options['archive_description']) : ''
);
}
/**
* Получает массив опций настроек и выводит одно из его значений
*/
public function header_bg_image_callback()
{
$attachment_id = $this->options['image_attachment_id'];
// Превью изображения
printf('<div class="image-preview-wrapper"><img id="image-preview" src="%s" ></div>', wp_get_attachment_url( $attachment_id ) );
// Кнопка загрузки изображения
printf( '<input id="upload_image_button" type="button" class="button" value="%s" />',
__( 'Загрузить изображение', 'rushhour' ) );
// Скрытое поле с ID вложения изображения
printf( '<input type="hidden" name="rushhour_projects_archive[image_attachment_id]" id="image_attachment_id" value="%s">',
$attachment_id );
}
public function media_selector_scripts()
{
$my_saved_attachment_post_id = get_option( 'media_selector_attachment_id', 0 );
wp_register_script( 'sub_menu_media_selector_scripts', get_template_directory_uri() . '/admin/js/media-selector.js', array('jquery'), false, true );
$selector_data = array(
'attachment_id' => get_option( 'media_selector_attachment_id', 0 )
);
wp_localize_script( 'sub_menu_media_selector_scripts', 'selector_data', $selector_data );
wp_enqueue_script( 'sub_menu_media_selector_scripts' );
}
}
Затем просто вызываем объект, если is_admin()
возвращает true:
if ( is_admin() )
$my_settings_page = new RushHourProjectArchivesAdminPage();

Это должно сработать. Измените
function rushhour_projects_archive_save_options()
{
if ( isset( $_POST['rushhour_projects_archive[header_text]'] ) )
{
update_option( 'rushhour_projects_archive', $_POST['rushhour_projects_archive[header_text]'] );
}
}
на
function rushhour_projects_archive_save_options()
{
if ( isset( $_POST['rushhour_projects_archive']['header_text'] ) )
{
update_option( 'rushhour_projects_archive', $_POST['rushhour_projects_archive']['header_text'] );
}
}
