Полное руководство по настройке WordPress API, часть 4: опции темы

Содержание цикла статей «Полное руководство по настройке WordPress API»:

  1. Полное руководство по настройке WordPress API, часть 1: введение
  2. Полное руководство по настройке WordPress API, часть 2: секции, поля и настройки
  3. Полное руководство по настройке WordPress API, часть 3: все о создании меню
  4. Полное руководство по настройке WordPress API, часть 4: опции темы
  5. Полное руководство по настройке WordPress API, часть 5: закладочная навигация
  6. Полное руководство по настройке WordPress API, часть 6: страницы меню
  7. Полное руководство по настройке WordPress API, часть 7: валидация, очистка и элементы ввода
  8. Полное руководство по настройке WordPress API, часть 8: валидация, очистка и элементы ввода

В прошлой статье мы углубились в изучение различных типов меню, которые поддерживает WordPress API. Хотя материал, рассмотренный в предыдущей статье, и не является частью Settings API, но очень важен в разработке, особенно при работе над сложными плагинами и темами.

В этой статье рассматривается практическое использование меню, так как теперь мы серьезно начинаем работать над нашей темой Sandbox путем оптимизации существующих настроек и добавления нескольких новых страниц.

Если вы только что присоединились к нам, то, пожалуйста, ознакомьтесь с предыдущими статьями и убедитесь, что у вас установлена последняя версия темы Sandbox доступной в репозитарии на GitHub.

В этой статье очень много кода. В её первой половине, мы будем совершенствовать существующий код. А во второй половине – писать новый функционал с нуля.

Очень важно тщательно читать весь представленный код с комментариями и полностью в нем разбираться, чтобы понимать происходящие процессы. Избегайте простого копирования и вставки кода.

«Уборка» кода

Если вы работали с предыдущими примерами, то у вас в файле functions.php имеется множество функций для создания различных пунктов меню. Так как в этой статье у нас более практический подход, то часть существующего кода, созданного в предыдущих статьях цикла, нужно удалить.

Я знаю, вам кажется нецелесообразным писать столько кода только для того, чтобы его потом удалить, но предыдущие примеры служили базой для понимания основ написания кода для WordPress.

Для начала нам нужно найти две функции из предыдущих статей, создававшие подпункт в меню «Плагины»:

/** 
 * Добавление одиночного подпункта в пункт меню «Плагины»
 */

function sandbox_example_plugin_menu() {  
  
    add_plugins_page(  
        'Плагин Sandbox',           // Текст, отображаемый в заголовке окна браузера.  
        'Плагин Sandbox',           // Текст, отображаемый в пункте меню  
        'administrator',            // Группа пользователей, имеющих доступ к данному пункту меню  
        'sandbox_plugin_options',   // Уникальный ID - псевдоним – для данного пункта  
        'sandbox_plugin_display'    // Имя callback-функции   
    );  
  
} // Конец функции sandbox_example_plugin_menu

add_action('admin_menu', 'sandbox_example_plugin_menu');  
  
/** 
 * Отображение простой страницы настроек. 
 */

function sandbox_plugin_display() {  
  
    // Создаем заголовок в стандартном контейнере «wrap»  
    $html = '<div class="wrap">';
        $html .= '<h2>Опции плагина Sandbox</h2>';  
        $html .= '<p class="description">Пока тут нет опций. Это просто демонстрация.</p>';  
    $html .= '</div>';  
      
    // Посылаем html-разметку браузеру  
    echo $html;  
      
} // Конец функции sandbox_plugin_display

Удалите этот код из файла functions.php.

Далее, нам нужно удалить функции, ответственные за добавление меню верхнего уровня. Мы перепишем этот кусок кода позже, но он будет сильно отличаться от первоначального варианта.

/** 
 * Добавляем новое меню верхнего уровня в нижнюю часть административного меню WordPress. 
 */

function sandbox_create_menu_page() {  
  
    add_menu_page(  
        'Опции Sandbox',              // Отображаемый в браузере заголовок для данного меню  
        'Sandbox',                    // Текст пункта меню  
        'administrator',              // Пользователи, которые могут видеть этот пункт меню  
        'sandbox',                    // Уникальный идентификатор для данного пункта меню  
        'sandbox_menu_page_display'   // Имя функции, вызываемой при отображении меню 
    );

    add_submenu_page(  
        'sandbox',                  // Регистрация подпункта под определенным выше пунктом меню  
        'Опции Sandbox',            // Текст заголовка браузера при активированном пункте меню  
        'Опции',                    // Текст для этого подпункта  
        'administrator',            // Группа пользователей, которой доступен этот подпункт  
        'sandbox_options',          // Уникальный ID - псевдоним – для данного подпункта меню  
        'sandbox_options_display'   // Функция, используемая для вывода содержимого этого пункта меню  
    );
  
} // Конец функции sandbox_create_menu_page  

add_action('admin_menu', 'sandbox_create_menu_page');  
  
function sandbox_menu_page_display() {  
      
    // Создание тега заголовка в стандартном контейнере «wrap»  
    $html = '<div class="wrap">';  
        $html .= '<h2>Sandbox</h2>';  
    $html .= '</div>';  
      
    // Посылаем разметку на вывод в браузер  
    echo $html;  
      
} // Конец функции sandbox_menu_page_display

function sandbox_options_display() {  
  
    // Создаем заголовок в стандартном контейнере «wrap»  
    $html = '<div class="wrap">';
        $html .= '<h2>Опции Sandbox</h2>';  
    $html .= '</div>';
      
    // Посылаем созданную разметку браузеру  
    echo $html;  
      
} // конец функции sandbox_options_display

На данный момент, в административной панели WordPress, относительно оригинала, имеются следующие модификации:

Подпункт «Тема Sandbox» находится в меню «Внешний вид» (Appearance);
Набор трех опций для управления видимостью контейнеров располагается на вкладке «Общие настройки» (General) в меню «Настройки» (Settings).

Если у вас имеются перечисленные модификации, то можете смело двигаться дальше. В противном случае, проверьте ваш файл functions.php и сверьте его с кодом ниже:

function sandbox_example_theme_menu() {  
  
    add_theme_page(  
        'Тема Sandbox',             // Текст в заголовке браузера  
        'Тема Sandbox',             // Текст самого пункта меню в боковом меню WordPress  
        'administrator',            // Группы пользователей, имеющих доступ к данному меню  
        'sandbox_theme_options',    // Уникальный ID - псевдоним – для данного пункта меню  
        'sandbox_theme_display'     // Имя функции, используемой для вывода страницы пункта меню на экран 
    );  
  
}  // Конец функции sandbox_example_theme_menu

add_action('admin_menu', 'sandbox_example_theme_menu');

function sandbox_theme_display() {  
  
    // Создадим тег заголовка в контейнере «wrap» в WordPress
    $html = '<div class="wrap">';  
        $html .= '<h2>Опции темы Sandbox</h2>';  
        $html .= '<p class="description">Пока тут нет опций. Это просто демонстрация.</p>';  
    $html .= '</div>';  
      
    // Посылаем разметку браузеру  
    echo $html;  

} // Конец функции sandbox_theme_display 

/* ---------------------------------------------------------------- 
 * Регистрация настроек 
 * ----------------------------------------------------------------
*/  
  
/* Инициализация страницы опций темы, регистрация секций, полей и настроек.
 * Эта функция регистрируется с помощью хука  admin_init. 
*/
function sandbox_initialize_theme_options() {  
    //Сначала мы регистрируем секцию. Это необходимо, так как объявляемые далее опции будут принадлежать именно к этой секции.
    add_settings_section(  
        'general_settings_section',           // ID, который будет использоваться для идентификации этой секции и по которому мы будем регистрировать опции
        'Опции Sandbox',                      // Заголовок, который будет отображаться на странице административной панели
        'sandbox_general_options_callback',   // Вызов, который используется для отображения описания секции  
        'general'                             // Страница, на которую будет добавлена секция  
    );

    // Далее, мы создадим поле для переключения видимости контейнеров в шаблоне  
    add_settings_field(   
        'show_header',                      // Идентификатор, используемый для идентификации поля внутри темы  
        'Контейнер header',                 // Метка слева от элемента интерфейса
        'sandbox_toggle_header_callback',   // Имя функции, ответственной за вывод элемента интерфейса  
        'general',                          // Страница, на которую будет выведена опция  
        'general_settings_section',         // Имя секции, которой принадлежит поле
        array(                              // Массив-аргументов, передаваемый callback-функции. В нашем случае просто описание.  
            'Активируйте эту опцию, чтобы отобразить контейнер header.'  
        )  
    );

    add_settings_field(  
        'show_content',  
        'Контейнер content',  
        'sandbox_toggle_content_callback',  
        'general',  
        'general_settings_section',  
        array(  
            'Активируйте эту опцию, чтобы отобразить контейнер content.'  
        )  
    );

    add_settings_field(   
        'show_footer',                        
        'Контейнер Footer',                 
        'sandbox_toggle_footer_callback',     
        'general',                            
        'general_settings_section',           
        array(                                
            'Активируйте эту опцию, чтобы отобразить контейнер footer.'  
        )  
    );

    // Регистрируем поля в WordPress  
    register_setting(  
        'general',  
        'show_header'  
    );

    register_setting(  
        'general',  
        'show_content'  
    );  
  
    register_setting(  
        'general',  
        'show_footer'  
    );  

} // Конец функции sandbox_initialize_theme_options

add_action('admin_init', 'sandbox_initialize_theme_options');  
  
/* ----------------------------------------------------------------
 * Callback-функции для секций
 * ----------------------------------------------------------------
*/   
  
/* 
 * Эта функция предоставляет простое описание страницы «Общие настройки».  
 * Она вызывается из функции «sandbox_initialize_theme_options» и передается в нее как параметр
*/
function sandbox_general_options_callback() {  
    echo '<p>Выберите, какие секции вы хотите показывать на странице.</p>';  
} // Конец функции sandbox_general_options_callback  

/* ------------------------------------------------------------------------ * 
 * Callback-функции для полей
 * ------------------------------------------------------------------------
*/

/* 
 * Эта функция выводит элемент интерфейса для изменения видимости контейнера header.
 * Она получает массив аргументов, в котором первым идет описание, которое будет отображено после чекбокса. 
*/
function sandbox_toggle_header_callback($args) {  
      
    //Идентификатор и имя атрибута элемента должны совпадать с указанными в функции add_settings_field  
    $html = '<input type="checkbox" id="show_header" name="show_header" value="1" ' . checked(1, get_option('show_header'), false) . '/>';  
      
    // Берем первый элемент массива и добавляем его к метке чекбокса
    $html .= '<label for="show_header"> ' . $args[0] . '</label>';  
      
    echo $html;  
      
} // Конец функции sandbox_toggle_header_callback

function sandbox_toggle_content_callback($args) {  
  
    $html = '<input type="checkbox" id="show_content" name="show_content" value="1" ' . checked(1, get_option('show_content'), false) . '/>';   
    $html .= '<label for="show_content"> '  . $args[0] . '</label>';   
      
    echo $html;  
      
} // Конец функции sandbox_toggle_content_callback  

function sandbox_toggle_footer_callback($args) {  
      
    $html = '<input type="checkbox" id="show_footer" name="show_footer" value="1" ' . checked(1, get_option('show_footer'), false) . '/>';   
    $html .= '<label for="show_footer"> '  . $args[0] . '</label>';   
      
    echo $html;  
      
} // Конец функции sandbox_toggle_footer_callback

А теперь, пора начать по-настоящему!

Эскизы наших будущих опций

До написания кода, нам следует спланировать наши действия. На данный момент у нас уже написана базовая функциональность – мы дали пользователям возможность переключать видимость контейнеров header, content и footer. Группа этих опций находится на вкладке «Общие» (General) на странице «Настройки» (Settings).

Однако, трех этих опций недостаточно для полноценной темы. В наши дни практически все пользуются социальными сетями в своих блогах, так что давайте дадим возможность пользователям показывать ссылки на их аккаунты в Twitter, Facebook и Google+.

Для себя, в уме, мы можем составить вид страницы с настройками из двух секций:

  1. Отображение:
    • Контейнер Header;
    • Контейнер Content;
    • Контейнер Footer;
  2. Социальные сети:
    • Twitter;
    • Facebook;
    • Google+

На следующем шаге, мы создадим эти опции на странице настроек нашей темы Sandbox, к которой можно получить доступ из меню «Внешний вид» (Appearance). В дополнение ко всему прочему, каждая секция будет доступна на отдельной вкладке навигационной панели.

Создание опций

Переработка страницы опций

Наша страница настроек станет более функциональной за время прохождения данного цикла статей, поэтому полезно будет подготовиться. Сейчас наша callback-функция выглядит так:

function sandbox_theme_display() {  
  
    // Создадим тег заголовка в контейнере «wrap» в WordPress
    $html = '<div class="wrap">';  
        $html .= '<h2>Опции темы Sandbox</h2>';  
        $html .= '<p class="description">Пока тут нет опций. Это просто демонстрация.</p>';  
    $html .= '</div>';  
      
    // Посылаем разметку браузеру  
    echo $html;  

} // Конец функции sandbox_theme_display

Вот список усовершенствований, которые нам нужно сделать:

  • Указать иконку для страницы опций, чтобы она выглядела более органично и вписывалась в общий вид WordPress;
  • Удалить описание страницы;
  • Переделать PHP-строки с HTML-кодом в блоки, чтобы с ними было проще работать;
  • Написать функцию для отображения ошибок;
  • Создать форму, которая будет использована для размещения наших опций.

Перечисленное реализовать не так уж и сложно. В данном случае, прокомментированным кодом будет проще показать, каков смысл действий, чем описывать это текстом.

Изучите листинг, расположенный ниже, уделяя особое внимание комментариям, а затем добавьте измененную callback-функцию в ваш проект:

function sandbox_theme_display() {  
?>  
    <!-- Создаем заголовок в стандартном контейнере «wrap» -->  
    <div class="wrap">  
  
        <!-- Добавляем иконку к странице -->  
        <div id="icon-themes" class="icon32"></div>  
        <h2>Опции темы Sandbox</h2>  
  
        <!-- Делаем вызов функции WordPress для вывода ошибок, возникающих при сохранении настроек. -->  
        <?php settings_errors(); ?>  
  
        <!-- Создаем форму, которая будет использоваться для вывода наших опций -->  
        <form method="post" action="options.php">  
            <?php settings_fields( 'general' ); ?>  
            <?php do_settings_sections( 'general' ); ?>             
            <?php submit_button(); ?>  
        </form>  
  
    </div> <!-- Конец контейнера «wrap» -->  
<?php  
} // Конец функции sandbox_theme_display

Если вы не сделали ошибку в коде, то ваша страница настроек должна выглядеть следующим образом:

страница настроек

Перемещение настроек

Теперь, когда страница приобрела задуманный нами вид, самое время переместить настройки на страницу опций темы. В прошлой статье, мы добавили каждую опцию по отдельности на вкладку «Общие» (General) и они были сгруппированы под меткой «Опции Sandbox».

Теперь, чтобы переместить их на страницу настроек нашей темы, нужно сделать несколько модификаций. Мы детально рассмотрим каждый шаг, чтобы понимать, что происходит.

Шаг 1. Проверка опций на существование

После того, как мы стали добавлять наши опции в созданные группы, а не в существующие, возникла необходимость проверки на существование полей в базе данных.

Чтобы это сделать, мы вызовем функцию get_option. Если она возвращает значение false, то добавляем наш новый набор опций с помощью функции add_option.

Для этого, добавим следующий блок кода в начало функции sandbox_initialize_theme_options:

if( false == get_option( 'sandbox_theme_display_options' ) ) {    
    add_option( 'sandbox_theme_display_options' );  
} // Конец конструкции if

Шаг 2. Перестройка секций

Найдите вызов функции add_settings_section, а в ней — аргумент title. Сейчас эта функция выглядит так:

add_settings_section(  
        'general_settings_section',           // ID, который будет использоваться для идентификации этой секции и по которому мы будем регистрировать опции
        'Опции Sandbox',                      // Заголовок, который будет отображаться на странице административной панели
        'sandbox_general_options_callback',   // Вызов, который используется для отображения описания секции  
        'general'                             // Страница, на которую будет добавлена секция  
    );

Так как наши опции теперь находятся на странице «Опции Sandbox», нам нужно изменить название секции. Вместо этого текста, давайте введем «Опции отображения».

add_settings_section(  
        'general_settings_section',           // ID, который будет использоваться для идентификации этой секции и по которому мы будем регистрировать опции
        'Опции отображения',                  // Заголовок, который будет отображаться на странице административной панели
        'sandbox_general_options_callback',   // Вызов, который используется для отображения описания секции  
        'general'                             // Страница, на которую будет добавлена секция  
    );

Нам больше не нужно отображать опции на странице «Общие настройки» (General Settings), поэтому изменим последний аргумент в функции выше на идентификатор страницы настроек нашей темы. Я выбрал для этого имя sandbox_theme_display_options:

add_settings_section(
        'general_settings_section',           // ID, который будет использоваться для идентификации этой секции и по которому мы будем регистрировать опции
        'Опции отображения',                  // Заголовок, который будет отображаться на странице административной панели
        'sandbox_general_options_callback',   // Вызов, который используется для отображения описания секции  
        'sandbox_theme_display_options'       // Страница, на которую будет добавлена секция  
    );

Шаг 3. Обновление полей

После задания уникального идентификатора для страницы, нужно убедиться, что настройки имеют правильные ссылки на страницы. Сейчас, все наши вызовы функций add_settings_field ссылаются на страницу «Общие настройки» (General Settings):

add_settings_field(   
        'show_header',                      // Идентификатор, используемый для идентификации поля внутри темы  
        'Контейнер header',                 // Метка слева от элемента интерфейса
        'sandbox_toggle_header_callback',   // Имя функции, ответственной за вывод элемента интерфейса  
        'general',                          // Страница, на которую будет выведена опция  
        'general_settings_section',         // Имя секции, которой принадлежит поле
        array(                              // Массив-аргументов, передаваемый callback-функции. В нашем случае просто описание.  
            'Активируйте эту опцию, чтобы отобразить контейнер header.'  
        )  
    );

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

Это делается простым изменением строки на значение sandbox_theme_display_options. Теперь, три подкорректированные опции должны выглядеть так:

add_settings_field(   
        'show_header',                      // Идентификатор, используемый для идентификации поля внутри темы  
        'Контейнер header',                 // Метка слева от элемента интерфейса
        'sandbox_toggle_header_callback',   // Имя функции, ответственной за вывод элемента интерфейса  
        'sandbox_theme_display_options',    // Страница, на которую будет выведена опция  
        'general_settings_section',         // Имя секции, которой принадлежит поле
        array(                              // Массив-аргументов, передаваемый callback-функции. В нашем случае просто описание.  
            'Активируйте эту опцию, чтобы отобразить контейнер header.'  
        )  
    );

    add_settings_field(  
        'show_content',  
        'Контейнер content',  
        'sandbox_toggle_content_callback',  
        'sandbox_theme_display_options',  
        'general_settings_section',  
        array(  
            'Активируйте эту опцию, чтобы отобразить контейнер content.'  
        )  
    );

    add_settings_field(   
        'show_footer',                        
        'Контейнер Footer',                 
        'sandbox_toggle_footer_callback',     
        'sandbox_theme_display_options',                            
        'general_settings_section',           
        array(                                
            'Активируйте эту опцию, чтобы отобразить контейнер footer.'  
        )  
    );

Шаг 4. Регистрация новых настроек

До этого момента, мы регистрировали каждую опцию отдельно, на странице общих настроек, следующим образом:

register_setting(  
        'general',  
        'show_header'  
    );

    register_setting(  
        'general',  
        'show_content'  
    );  
  
    register_setting(  
        'general',  
        'show_footer'  
    );

С созданием отдельного меню темы Sandbox, мы можем объединить три этих вызова в один, который зарегистрирует все поля в нашей новой секции опций:

register_setting(  
    'sandbox_theme_display_options',  
    'sandbox_theme_display_options'  
);

Обратившись ко второй статье, мы вспомним, что настройка это комбинация полей и секций, которым они принадлежат. А так как все наши поля теперь принадлежат одной и той же секции «Опции отображения», то мы можем одной командой зарегистрировать их в WordPress.

Шаг 5. Обновление элементов опций

Раньше наши опции сохранялись как отдельные настройки в базе данных. Это значит, что мы могли найти их по уникальному ID (например, «get_option(‘show_header’)»).

Но так как теперь у нас своя собственная секция, они являются частью набора опций. Чтобы прочитать опции, мы должны сначала получить доступ к набору, а затем найти в нем интересующее нас поле.

Сейчас нам нужно обновить все элементы ввода. Найдите секцию callback-функций в файле functions.php. Функция для первой опции, переключающей видимость контейнера header, на данный момент должна выглядеть так:

function sandbox_toggle_header_callback($args) {  
      
    //Идентификатор и имя атрибута элемента должны совпадать с указанными в функции add_settings_field  
    $html = '<input type="checkbox" id="show_header" name="show_header" value="1" ' . checked(1, get_option('show_header'), false) . '/>';  
      
    // Берем первый элемент массива и добавляем его к метке чекбокса
    $html .= '<label for="show_header"> ' . $args[0] . '</label>';  
      
    echo $html;  
      
}  // Конец функции sandbox_toggle_header_callback

Как было замечено выше, каждая опция является частью набора опций, поэтому нам необходимо изменить метод доступа к ним. Мы должны:

  • Прочитать набор опций;
  • Получить доступ к отдельной опции из набора;
  • Обновить атрибуты элементов ввода, чтобы ссылки верно ссылались на элементы из набора.

Несмотря на кажущую сложность, это достаточно простая процедура. Ознакомьтесь с нижеследующим кодом, обращая внимание на комментарии:

function sandbox_toggle_header_callback($args) {  
      
    // Считываем опции из группы 
    $options = get_option('sandbox_theme_display_options');  
      
    // Обновляем имена атрибутов для доступа к ID элементов в контексте массива отображаемых опций  
    // Получаем доступ к элементу show_header из группы опций, вызывая вспомогательную функцию checked()
    $html = '<input type="checkbox" id="show_header" name="sandbox_theme_display_options[show_header]" value="1" ' . checked(1, $options['show_header'], false) . '/>';  
     
    // Берем первый элемент массива и добавляем его в содержимое метки чекбокса  
    $html .= '<label for="show_header"> '  . $args[0] . '</label>';   
      
    echo $html;  
      
} // Конец функции sandbox_toggle_header_callback

Просто, не правда ли? После того, как у нас есть три наших опции, нужно внести соответствующие изменения в каждую из них. Все функции будут выглядеть похоже, за исключением имен опций. Вместо show_header, будет show_content или show_footer.

Итак, финальная версия для реализации всех трех опций выглядит так:

function sandbox_toggle_header_callback($args) {  
  
    $options = get_option('sandbox_theme_display_options');  
  
    $html = '<input type="checkbox" id="show_header" name="sandbox_theme_display_options[show_header]" value="1" ' . checked(1, $options['show_header'], false) . '/>';   
    $html .= '<label for="show_header"> '  . $args[0] . '</label>';   
  
    echo $html;  
  
} // Конец функции sandbox_toggle_header_callback  
  
function sandbox_toggle_content_callback($args) {  
  
    $options = get_option('sandbox_theme_display_options');  
  
    $html = '<input type="checkbox" id="show_content" name="sandbox_theme_display_options[show_content]" value="1" ' . checked(1, $options['show_content'], false) . '/>';   
    $html .= '<label for="show_content"> '  . $args[0] . '</label>';   
  
    echo $html;  
  
} // Конец функции sandbox_toggle_content_callback  
  
function sandbox_toggle_footer_callback($args) {  
  
    $options = get_option('sandbox_theme_display_options');  
  
    $html = '<input type="checkbox" id="show_footer" name="sandbox_theme_display_options[show_footer]" value="1" ' . checked(1, $options['show_footer'], false) . '/>';   
    $html .= '<label for="show_footer"> '  . $args[0] . '</label>';   
  
    echo $html;  
  
} // Конец функции sandbox_toggle_footer_callback

Шаг 6. Вывод опций

Наконец, мы готовы отобразить наши опции на странице нашей темы. Это делается простым вызовом двух функций Settings API:

  • settings_fields отвечает за безопасность при работе с опциями на форме;
  • do_settings_sections выводит опции на страницу.

Каждая функция принимает ID страницы, на которой должен быть произведен вывод. В нашем случае, это sandbox_theme_display_options. Чтобы отобразить наши опции, обновим содержимое формы:

<form method="post" action="options.php">  
    <?php settings_fields( 'sandbox_theme_display_options' ); ?>  
    <?php do_settings_sections( 'sandbox_theme_display_options' ); ?>           
    <?php submit_button(); ?>  
</form>

Обновите страницу опций вашей темы и увидите три опции, как показано на изображении ниже:

три опции

Итоговая версия файла functions.php представлена ниже:

<?php 

function sandbox_theme_display() {  
?>  
    <!-- Создаем заголовок в стандартном контейнере «wrap» -->  
    <div class="wrap">  
  
        <!-- Добавляем иконку к странице -->  
        <div id="icon-themes" class="icon32"></div>  
        <h2>Опции темы Sandbox</h2>  
  
        <!-- Делаем вызов функции WordPress для вывода ошибок, возникающих при сохранении настроек. -->  
        <?php settings_errors(); ?>  
  
        <!-- Создаем форму, которая будет использоваться для вывода наших опций -->  
        <form method="post" action="options.php">
            <?php settings_fields( 'sandbox_theme_display_options' ); ?>
            <?php do_settings_sections( 'sandbox_theme_display_options' ); ?>
            <?php submit_button(); ?>
        </form>
  
    </div> <!-- Конец контейнера «wrap» -->  
<?php  
} // Конец функции sandbox_theme_display

?>

Создание настроек социальных сетей

В предыдущем разделе было много кода, и мы почти полностью переделали наш изначальный вариант проекта. Настало время пустить в ход Settings API на полную катушку!

Недостаточно просто сделать отдельную страницу с настройками. Чтобы создать полноценную страницу настроек с новыми полезными опциями, мы создадим еще один набор настроек.

По традиции, составим план наших дальнейших действий:

  • Сначала создадим новую секцию;
  • Затем, добавим в нее три поля настроек: одно для Facebook, одно для Twitter и одно для Google+;
  • Наконец, обновим страницу наших опций, чтобы появились новые настройки.

Создание секций, полей и настроек

Секция с настройками социальных сетей

Для начала, давайте создадим новую функцию и добавим ее к хуку admin_init. Эта функция будет предназначена специально для настройки опций социальных сетей.

По аналогии с настройками отображения, необходимо выполнить проверку, чтобы убедиться, что опции созданы. Если нет, то следует их создать.

Вот функция инициализации. Следите за комментариями!

/* 
 * Инициализация настроек социальных сетей — регистрация секций, полей и настроек.
 * Эта функция регистрируется с помощью хука 'admin_init'. 
*/

function sandbox_theme_intialize_social_options() {  
  
    // Если опции социальных сетей не созданы, то создаем их.  
    if( false == get_option( 'sandbox_theme_social_options' ) ) {     
        add_option( 'sandbox_theme_social_options' );  
    } // Конец конструкции if  
  
} // Конец функции sandbox_theme_intialize_social_options

add_action( 'admin_init', 'sandbox_theme_intialize_social_options' );

Далее, нам нужно добавить новую секцию для настроек. Это делается сразу после вышеприведенного кода:

add_settings_section(  
    'social_settings_section',          // ID, который будет использоваться для идентификации этой секции и по которому мы будем регистрировать опции  
    'Опции социальных сетей',           // Заголовок, который будет отображаться на странице административной панели  
    'sandbox_social_options_callback',  // Вызов, который используется для отображения описания секции  
    'sandbox_theme_social_options'      // Страница, на которую будет добавлена секция  
);

Но это еще не все! В третьем аргументе функции add_settings_section передается имя callback-функция. Не забудьте её определить:

function sandbox_social_options_callback() {  
    echo '<p>Заполните URL-адреса на социальные сети, которые вы хотите отобразить.</p>';  
} // конец функции sandbox_general_options_callback

Сейчас мы можем сделать проверку, чтобы убедиться, что секция действительно была зарегистрирована Settings API. Вернитесь к функции sandbox_theme_display и добавьте следующие две строки к форме.

Они должны располагаться сразу после функции sandbox_theme_display_options:

<?php settings_fields( 'sandbox_theme_social_options' ); ?>
            <?php do_settings_sections( 'sandbox_theme_social_options' ); ?>

Если вы все сделали правильно, то увидите то, что изображено ниже:

Settings API
<?php settings_fields( 'sandbox_theme_social_options' ); ?>
            <?php do_settings_sections( 'sandbox_theme_social_options' ); ?>

Поля настроек социальных сетей

Теперь, мы готовы добавить поля настроек социальных сетей на нашу страницу. Начнем с поля для Twitter. Ниже приведен вызов функции add_settings_section:

add_settings_field(   
    'twitter',                        
    'Twitter',                            
    'sandbox_twitter_callback',   
    'sandbox_theme_social_options',   
    'social_settings_section'
);

Заметьте, мы определили callback-функцию, как sandbox_twitter_callback, поэтому нам также нужно не забыть её реализовать. По аналогии с предыдущими опциями, нам нужно получить доступ к набору настроек, создать HTML-элемент для визуализации и правильно задать все атрибуты.

Особое внимание обратите на условную конструкцию в коде ниже – для ясности она прокомментирована. Условие нужно для того, чтобы убедиться, что мы не пытаемся читать пустые опции:

function sandbox_twitter_callback() {  
      
    // Сначала, читаем весь набор настроек  
    $options = get_option( 'sandbox_theme_social_options' );  
      
    // Далее проверяем, определен ли элемент в наборе. Если нет, то  определяем его.  
    $url = ''; 
    if( isset( $options['twitter'] ) ) { 
        $url = $options['twitter']; 
    } // Конец конструкции if 
     
    // Вывод на экран 
    echo '<input type="text" id="twitter" name="sandbox_theme_social_options[twitter]" value="' . $options['twitter'] . '" />';  
      
} // Конец функции sandbox_twitter_callback

Наконец, возвратимся к функции sandbox_theme_intialize_social_options и зарегистрируем новую настройку в WordPress:

register_setting(  
    'sandbox_theme_social_options',  
    'sandbox_theme_social_options',  
    'sandbox_theme_sanitize_social_options'  
);

Важное отличие: до этого момента, функции register_setting мы передавали два аргумента – группу опций и имя опции. Но сейчас, мы используем третий аргумент: имя callback-функции.

Эта функция вызывается ДО сохранения в базу данных, что позволяет проверить их на соответствие. Иначе говоря, мы можем проверить данные на их безопасность и правильность, перед их сохранением.

Давайте создадим заготовку функции:

function sandbox_theme_sanitize_social_options( $input ) {  
} // Конец функции sandbox_theme_sanitize_social_options

Callback-функция принимает единственный аргумент, который мы назвали $input. Это набор опций, который был создан для секции настроек социальных сетей.

Так как мы позволяем пользователю ввести любой текст в поле ввода, необходимо предотвратить запись любого вредоносного кода (такого, как JavaScript или SQL) .

Вот наш план действий для реализации механизмов защиты:

  • Создание массива, в который мы сможем записывать обработанные данные;
  • Проверка каждой опции и очистка данных;
  • Возврат обработанного набора данных.

Давайте напишем код, реализующий это. Вставьте данный код в свой файл functions.php:

/* ------------------------------------------------------------------------
 * Callback-функции для настроек
 * ------------------------------------------------------------------------
*/

function sandbox_theme_sanitize_social_options( $input ) {  
      
    // Объявление массива для обработанных опций  
    $output = array();  
  
    // Проверка каждой опции и очистка данных
    foreach( $input as $key => $val ) {  
      
        if( isset ( $input[$key] ) ) {  
            $output[$key] = esc_url_raw( strip_tags( stripslashes( $input[$key] ) ) );  
        } // Конец конструкции if   
      
    } // Конец конструкции foreach  
      
    // Возвращение обработанного набора 
    return apply_filters( 'sandbox_theme_sanitize_social_options', $output, $input );  
  
} // Конец функции sandbox_theme_sanitize_social_options

Выше, мы использовали три функции, каждая из которых послужила для реализации механизмов очистки данных:

  • stripslashes родная функция PHP для удаления экранирующих символов из строк;
  • strip_tags еще одна родная функция PHP, которая удаляет HTML- и PHP-теги из строк;
  • esc_url_raw функция WordPress, которая сохраняет чистый URL-адрес без кодировки.

Приведенный выше код очень строг по отношению к содержимому, но если нужно разрешить сохранять в базу данных исключительно URL-адреса, то он очень эффективен.

Последняя строка возвращает результат работы функции apply_filters, а не сам массив. Это действенный способ, чтобы убедиться в том, что другие функции, прикрепленные к этому же хуку, также будут вызваны.

В нашей простой теме, конечно, нет других функций, однако этот совет актуален при разработке сложных профессиональных тем.

А сейчас, сохраните ваш проект и обновите окно браузера. Ваша страница опций теперь отображает не только секцию «Настройки отображения», но также и первую опцию социальных сетей. Более того, вы можете ввести URL-адрес своего профиля на Twitter и сохранить его в базе данных.

«Настройки отображения»

Создание оставшихся опций

Вставка опций для Facebook и Google+ потребует выполнения точно таких же шагов, как и для Twitter. Основные шаги:

  • Определение поля для настройки;
  • Вызов callback-функции.

Обо всем остальном заботится Settings API. Конечно, нам нужно доделать опции для оставшихся двух социальных сетей.

Определим два поля настроек:

add_settings_field(   
        'facebook',                       
        'Facebook',                           
        'sandbox_facebook_callback',      
        'sandbox_theme_social_options',   
        'social_settings_section'             
    );  
      
    add_settings_field(   
        'googleplus',                         
        'Google+',                            
        'sandbox_googleplus_callback',    
        'sandbox_theme_social_options',   
        'social_settings_section'             
    );

Далее, определим для них две callback-функции:

function sandbox_facebook_callback() {  
      
    $options = get_option( 'sandbox_theme_social_options' );  
      
    $url = '';  
    if( isset( $options['facebook'] ) ) {  
        $url = $options['facebook'];  
    } // Конец конструкции if  
      
    // Вывод на экран  
    echo '<input type="text" id="facebook" name="sandbox_theme_social_options[facebook]" value="' . $options['facebook'] . '" />';  
      
} // Конец функции sandbox_facebook_callback  
  
function sandbox_googleplus_callback() {  
      
    $options = get_option( 'sandbox_theme_social_options' );  
      
    $url = '';  
    if( isset( $options['googleplus'] ) ) {  
        $url = $options['googleplus'];  
    } // Конец конструкции if  
      
    // Вывод на экран  
    echo '<input type="text" id="googleplus" name="sandbox_theme_social_options[googleplus]" value="' . $options['googleplus'] . '" />';  
      
} // Конец функции sandbox_googleplus_callback

Сохраните вашу работу и снова обновите вашу страницу опций. Должно появиться два дополнительных поля – одно для Facebook и одно для Google+. Попробуйте их в действии.

Замечание по безопасности: Хотя этот пример достаточно хорошо работает, есть еще несколько мер безопасности, которые следует предпринять перед сохранением опций в базу данных.

Позже, в данном цикле статей, мы их рассмотрим, когда будем подробно заниматься полями ввода. Там будет показан наиболее безопасный способ очистки данных перед их сохранением.

Вывод полей

Зачем нужны опции, если к ним нет доступа с сайта? Перед тем, как закончить эту статью, давайте сделаем маленькую модификацию в файле index.php нашей темы. А точнее, нам нужно проверить включение наших опций, и показать информацию об указанных социальных сетях:

<!DOCTYPE html>  
<html>
 
    <head>      
        <title>Полноценный гид по Settings API | Тема Sandbox</title>  
    </head>
  
    <body>
        <?php $display_options = get_option( 'sandbox_theme_display_options' ); ?>  
        <?php $social_options = get_option ( 'sandbox_theme_social_options' ); ?>  
      
        <?php if( $display_options[ 'show_header' ] ) { ?>  
            <div id="header">  
                <h1>Заголовок Sandbox</h1>  
            </div><!-- /#header -->  
        <?php } // Конец конструкции if ?>  
          
        <?php if( $display_options[ 'show_content' ] ) { ?>  
            <div id="content">  
                <?php echo $social_options['twitter'] ? '<a href="' . $social_options['twitter'] . '">Twitter</a>' : ''; ?>  
                <?php echo $social_options['facebook'] ? '<a href="' . $social_options['facebook'] . '">Facebook</a>' : ''; ?>  
                <?php echo $social_options['googleplus'] ? '<a href="' . $social_options['googleplus'] . '">Google+</a>' : ''; ?>  
            </div><!-- /#content -->  
        <?php } // Конец конструкции if ?>  
          
        <?php if( $display_options[ 'show_footer' ] ) { ?>  
            <div id="footer">  
                <p>© <?php echo date('Y'); ?> Все права защищены.</p>  
            </div><!-- /#footer -->  
        <?php } // Конец конструкции if ?>
    </body>  

</html>

Заключение

Это была самая, без сомнения, самая объёмная статья в данном цикле. Если вы с ней справились, то готовьтесь к плотной работе с Settings API. В двух следующих статьях, мы займемся нашими навигационными меню – закладочной навигацией и меню верхнего уровня.

Они будут короче и менее наполнены кодом. После этого, мы подробно займемся элементами ввода.

Пока у вас есть время, поэкспериментируйте с тем, что у нас получилось на данный момент!

Перевод статьи «The Complete Guide To The WordPress Settings API, Part 4: On Theme Options» был подготовлен дружной командой проекта Сайтостроение от А до Я.