Метаданные в таксономиях без использования плагинов

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

Шаг 1. Создание таблицы в базе данных

Всё дело в том, что, в отличии от метабоксов для постов, которые можно прикрутить на основе значений произвольных полей постов, то для таксономий WordPress тупо не предусматривает никаких метаданных, места в базе данных для них не предназначено.

Ну что же, похоже, что единственный выход — это создание собственной таблицы в БД, наподобие wp_postmeta.

Вообще назвать нужно её wp_termmeta (естественно префикс может быть другим), иначе стандартные вордпрессовские функции по работе с метаданными у нас просто не будут работать.

Есть два способа создания таблицы:

  1. Лезем в phpMyAdmin и создаем там.
  2. Через SQL-запрос, который можно задействовать прямо в коде.

Способ 1. Создание таблицы в базе данных через phpMyAdmin

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

создание новой таблицы через phpMyAdmin

Способ 2. Использование SQL-запроса для создания таблицы

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

if ( is_admin() && isset($_GET['activated'] ) && $pagenow == "themes.php" ) { // вешаем запрос создания таблицы на активацию темы
    global $wpdb; // глобальный класс $wpdb необходим при работе с базой данных в WordPress
    $collate = '';
 
    if($wpdb->has_cap('collation')) { 
        if(!empty($wpdb->charset)) $collate = "DEFAULT CHARACTER SET $wpdb->charset";
        if(!empty($wpdb->collate)) $collate .= " COLLATE $wpdb->collate";
    }
 
    // дальше идет сам SQL запрос
    $wpdb->query("CREATE TABLE IF NOT EXISTS ". $wpdb->prefix . "termmeta (
        `meta_id` bigint(20) NOT NULL AUTO_INCREMENT,
        `term_id` bigint(20) NOT NULL,
        `meta_key` varchar(255) NOT NULL,
        `meta_value` longtext DEFAULT '' NOT NULL,
        PRIMARY KEY id (`meta_id`)) $collate;"
    );
}

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

Шаг 2. Универсальное решение по добавлению настроек — использование PHP класса

Реально — использование готового класса это круто и легко. Вы на лету сможете создавать столько настроек в таксономиях, сколько захотите.

И я дам вам готовый класс с некоторыми базовыми полями: <input> (текстовый и чекбокс), <select>, <textarea>. Также вы можете прикрутить поле с загрузкой изображения, используя код из этого поста.

Я решил не добавлять в код вообще ничего лишнего (я не хочу сказать, что nonce-проверки и проверки на права пользователей — лишнее, просто в этом примере я от них отказался для простоты восприятия кода).

<?php
class trueTaxonomyMetaBox {
    /*
     * Функция-конструктор, в ней мы активируем хуки
     */
    function __construct( $options ) {
        $this->options = $options;
        $this->prefix = $this->options['id'] .'_'; // префикс настроек
        foreach ( $this->options['taxonomy'] as $taxonomy ) { // для каждой таксономии, которая указана в параметрах
            add_action($taxonomy . '_edit_form_fields', array(&$this, 'fill'), 10, 2 ); // хук добавления полей
        }
        add_action('edit_term', array(&$this, 'save'), 10,1); // хук сохранения значений полей
    }
    /*
     * Функция, создающая поля, я описал в ней текстовые поля (input type=text и textarea), чекбокс и выпадающий список
     */
    function fill( $term, $taxonomy ){
 
        foreach ( $this->options['args'] as $param ) { // для каждого описанного параметра...
 
            ?><tr class="form-field"><?php
                // определяем значение произвольного поля таксономии
                if(!$value = get_metadata('term', $term->term_id, $this->prefix .$param['id'], true)) $value = $param['std'];
                switch ( $param['type'] ) {
                    // input[type="text"]
                    case 'text':{ ?>
                        <th scope="row"><label for="<?php echo $this->prefix .$param['id'] ?>"><?php echo $param['title'] ?></label></th>
                        <td>
                            <input name="<?php echo $this->prefix .$param['id'] ?>" type="<?php echo $param['type'] ?>" id="<?php echo $this->prefix .$param['id'] ?>" value="<?php echo $value ?>" class="regular-text" />
                            <?php if(isset( $param['desc'] ) ) echo '<p class="description">' . $param['desc'] . '</p>'  ?>
                        </td>
                        <?php
                        break;                          
                    }
                    // textarea
                    case 'textarea':{ ?>
                        <th scope="row"><label for="<?php echo $this->prefix .$param['id'] ?>"><?php echo $param['title'] ?></label></th>
                        <td>
                            <textarea name="<?php echo $this->prefix .$param['id'] ?>" type="<?php echo $param['type'] ?>" id="<?php echo $this->prefix .$param['id'] ?>" value="<?php echo $value ?>" class="large-text" /><?php echo $value ?></textarea>
                            <?php if(isset( $param['desc'] ) ) echo '<p class="description">' . $param['desc'] . '</p>'  ?>
                        </td>
                        <?php
                        break;                          
                    }
                    // input[type="checkbox"]
                    case 'checkbox':{ ?>
                        <th scope="row"><label for="<?php echo $this->prefix .$param['id'] ?>"><?php echo $param['title'] ?></label></th>
                        <td>
                            <label for="<?php echo $this->prefix .$param['id'] ?>"><input name="<?php echo $this->prefix .$param['id'] ?>" type="<?php echo $param['type'] ?>" id="<?php echo $this->prefix .$param['id'] ?>"<?php echo ($value=='on') ? ' checked="checked"' : '' ?> />
                            <?php if(isset( $param['desc'] ) ) echo $param['desc']  ?></label>
                        </td>
                        <?php
                        break;                          
                    }
                    // select
                    case 'select':{ ?>
                        <th scope="row"><label for="<?php echo $this->prefix .$param['id'] ?>"><?php echo $param['title'] ?></label></th>
                        <td>
                            <label for="<?php echo $this->prefix .$param['id'] ?>">
                            <select name="<?php echo $this->prefix .$param['id'] ?>" id="<?php echo $this->prefix .$param['id'] ?>"><option>...</option><?php
                                foreach($param['args'] as $val=>$name){
                                    ?><option value="<?php echo $val ?>"<?php echo ( $value == $val ) ? ' selected="selected"' : '' ?>><?php echo $name ?></option><?php
                                }
                            ?></select></label>
                            <?php if(isset( $param['desc'] ) ) echo '<p class="description">' . $param['desc'] . '</p>'  ?>
                        </td>
                        <?php
                        break;                          
                    }
                } 
            ?></tr><?php
 
        }
 
    }
    /*
     * Функция сохранения значений полей
     */
    function save( $term_id ){
        foreach ( $this->options['args'] as $param ) {
            if ( isset( $_POST[ $this->prefix . $param['id'] ] ) && trim( $_POST[ $this->prefix . $param['id'] ] ) ) {
                update_metadata('term', $term_id, $this->prefix . $param['id'], trim($_POST[ $this->prefix . $param['id'] ], '') );
            } else {
                delete_metadata('term', $term_id, $this->prefix . $param['id'], '', false);
            }
        }
    }
}

Добавив этот класс в свой плагин или тему, можно приступить к заданию параметров класса, или иначе говоря к созданию настроек.

Вот пример:

$options = array(
    array(
        'id'    =>   'metatax', // айдишник играет роль префикса названий полей
        'taxonomy'  =>   array('category', 'game'), // укажите таксономии, для которых нужно добавить ниже перечисленные поля
        'args'  =>   array(
            array(
                'id'            =>   'order', // атрибуты name и id без префикса, например с префиксом будет meta1_field_1
                'title'         =>   'Порядок', // лейбл поля
                'type'          =>   'text', // тип, в данном случае обычное текстовое поле
                'desc'          =>   'Укажите порядок сортировки.', // описание
                'std'           =>   '0' // значение поля по умолчанию
            ),
            array(
                'id'            =>   'homepage',
                'title'         =>   'Главная',
                'type'          =>   'checkbox', // чекбокс
                'desc'          =>   'Отображать на главной странице в списке рубрик',
                'std'           =>   ''
            )
        )
    ),
    array(
        'id'    =>   'metagame',
        'taxonomy'  =>   array('game'),
        'args'  =>   array(
            array(
                'id'            =>   'genre',
                'title'         =>   'Жанр игры',
                'type'          =>   'select', // выпадающий список
                'desc'          =>   'Выберите жанр из выпадающего списка.',
                'std'           =>   '',
                'args'          =>   array('mmorpg' => 'MMORPG', 'strategy' => 'Стратегия', 'racing' => 'Гонки' ) // элементы задаются через массив, по типу атрибут value=>лейбл
            ),
            array(
                'id'            =>   'reqs',
                'title'         =>   'Системные требования',
                'type'          =>   'textarea',
                'std'           =>   ''
            )
        )
    )
);
 
foreach ($options as $option) {
    $truetaxmetabox = new trueTaxonomyMetaBox($option);
}

Вот результат:

добавленные поля

Вот в принципе и всё. Я написал только про самое основное.

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

Источник: misha.blog

Миша Рудрастых

Путешествует по миру и рассказывает всем о WordPress лично, у себя в блогах и на курсах в Санкт-Петербурге. Умеет просто объяснять сложные вещи, делает это красиво. Организовывает неплохие WordCamp's, но совсем не умеет слушать чужие доклады.

Добавить комментарий

%d такие блоггеры, как: