Комплексные поля
Carbon Fields 1.6- Контейнеры
- Произвольные поля
- Комплексные поля
- Расширяемость
Комплексное поле - это поле, состоящие из других полей, используемых в связке друг с другом. Данное поле в ряде случаев можно назвать повторяющимся полем или гибким контентом. Но лучшее представление о чем речь дадут только примеры...
Пример создания комплексного поля
Создание поля
<?php use Carbon_Fields\Container; use Carbon_Fields\Field; Container::make( 'post_meta', 'Заметки автора статьи' ) ->show_on_post_type( 'page' )// отобразим контейнер только на страницах (post_type=page) ->add_fields( array( Field::make( 'complex', 'fio', 'Соавторы статьи' ) ->add_fields( array( Field::make( 'text', 'name', 'ФИО' ) ->set_width( 33 ), Field::make( 'text', 'spec', 'Специальность' ) ->set_width( 33 ), ) ) ->help_text( 'Перечислите всех, кто помогал Вам написать статью.' ) ) );
Соответственно, в комплексном поле можно использовать любое поле из списка доступных полей Carbon Fields.
Вывод значений
Если использовать carbon_get_post_meta()
таким образом:
$data = carbon_get_post_meta( $post->ID, 'fio', 'complex' ); print_r( $data ); /* Array ( [0] => Array ( [_type] => _ [name] => Василий Пупкин [spec] => Айтишник ) [1] => Array ( [_type] => _ [name] => Елена Бессмертная [spec] => Дизайнер ) [2] => Array ( [_type] => _ [name] => Иван Бровин [spec] => Программист ) )
На основе структуры данных пишем код вывода значений:
<?php $table = carbon_get_post_meta( $post->ID, 'fio', 'complex' ); if ( ! empty( $table ) ): ?> <table> <thead> <tr> <th>ФИО</th> <th>Специальность</th> </tr> </thead> <tbody> <?php foreach ( $table as $tr ): ?> <tr> <td><?php echo $tr['name'] ?></td> <td><?php echo $tr['spec'] ?></td> </tr> <?php endforeach; ?> </tbody> </table> <?php endif; ?>
Получаем html код на выходе:
<table> <thead> <tr> <th>ФИО</th> <th>Специальность</th> </tr> </thead> <tbody> <tr> <td>Василий Пупкин</td> <td>Айтишник</td> </tr> <tr> <td>Елена Бессмертная</td> <td>Дизайнер</td> </tr> <tr> <td>Иван Бровин</td> <td>Программист</td> </tr> </tbody> </table>
Single Group (одиночное комплексное поле)
Пример такого поля был приведен выше. Для добавления комплексного поля используется метод
Field::make()->add_fields( $fields )
- $fields
- Массив с произвольными полями. Добавленные строки, состоящие из полей, можно сортировать, перетаскивая мышкой, а также дублировать или удалять. Данное поле ещё называют
repeater
(повторитель).
Пример
Field::make('complex', 'crb_test') ->add_fields(array( Field::make('text', 'name', 'Имя'), Field::make('text', 'job_title', 'Работа'), ))
Multiple groups (множественное комплексное поле)
Это поле позволяет пользователю из выпадающего списка выбрать то или иное одиночное комплексное поле, тем самым пользователь сам решает, в каком виде должен преподноситься контент. Данное поле ещё называют flexible content
(гибкое содержимое).
Параметры
Множественное комплексное поле - это набор одиночных комплексных полей, которые можно назвать слоями. Для создания слоя используется метод
Field::make()->add_fields( $name, $label, $fields )
- $name(строка) (обязательный)
- Название комплексного поля (слоя). Используйте только буквы английского алфавита!
- $label(строка)
- Заголовок комплексного поля (слоя). Разрешается использования любых символов.
По умолчанию: $name - $fields(массив) (обязательный)
- Нумерованный массив полей
Принцип создания множественного комплексного поле такой же, как и одиночного, только метод add_fields()
вызывается несколько раз. Получается эдакая цепочка, где каждый вызываемый метод add_fields()
создаёт новый вариант одиночного комплексного поля (слоя) для выбора.
Создание поля
use Carbon_Fields\Container; use Carbon_Fields\Field; Container::make( 'post_meta', 'Предпочтения автора статьи' ) ->show_on_post_type( 'page' )// отобразим контейнер только на страницах (post_type=page) ->add_fields( array( Field::make('complex', 'sheet-preferences', 'Список') ->add_fields('movie', 'Кино', array( Field::make('text', 'name', 'Название фильма'), Field::make('rich_text', 'description', 'Описание фильма')->set_width(70), Field::make('image', 'poster', 'Постер') ->set_width(30) )) ->add_fields('music', 'Музыка', array( Field::make('text', 'name', 'Название трека') ->set_width(70), Field::make('file', 'music', 'Трек') ->set_type('audio') ->set_width(30) )) ->add_fields('poetry', 'Поэзия', array( Field::make('text', 'writer', 'Писатель'), Field::make('text', 'name', 'Название'), Field::make('textarea', 'short-poem', 'Часть стихотворения'), Field::make('text', 'url', 'Ссылка на полное стихотворение') )) ) );
Запрос в базу данных
Carbon Fields формирует следующий запрос для получения данных поля:
SELECT meta_key AS field_key, meta_value AS field_value FROM wp_postmeta WHERE `meta_key` LIKE "_sheet-preferences_%" AND `post_id`="1086"
На тестовом сайте с 22 000 строк в таблице *_postmeta
такой запрос выполняется мгновенно (php7, HDD).
Хранение данных
Данные хранятся в таблице *_postmeta
, причем каждое произвольное поле в отдельности:
Рассмотрим вариант хранения данных поля, в котором мы выбрали "Музыка" и "Eddy - Need (Remix)".
_sheet-preferences_music-_name_0 - Eddy - Need (Remix)
_sheet-preferences
- имя множественного комплексного поля. Как уже говорилось, Carbon Fields автоматически добавляет знак подчеркивания при сохранении имени большинства полей._music
- имя одиночного комплексного поля (слоя)Дефис
- разделитель, отделяющий цепочку "контейнеров и слоев" от имени самого поля_name
- имя поля (в нашем случае поле "name" для ввода название песни)_0
- позиция слоя в списке выбранных слоев. Как и в нумерованных массивах, 0 - это первый элемент.
Как видим, цепочка идёт от общего к частному. Получить данные можно с помощью функции carbon_get_post_meta()
или другой, в зависимости от места использования множественного поля (посты, таксономии, настройки темы и т.д.) - все эти функции описаны в статье о контейнерах Carbon Fields.
$data_arr = carbon_get_post_meta( $post->ID, 'sheet-preferences', 'complex' ); print_r( $data_arr ); /* Array ( [0] => Array ( [_type] => _music [music] => 976 [name] => Eddy - Need (Remix) ) [1] => Array ( [_type] => _movie [description] => Рокки отошел от дел, занявшись ресторанным бизнесом и все еще тяжело переживает смерть своей жены Эдриан. Пытаясь развеять образовавшуюся пустоту, Бальбоа решает вернуться на ринг для боев местного значения с боксерами в легком весе. Но когда он соглашается выступить против действующего чемпиона-тяжеловеса Мэйсона Диксона, пресса неожиданно проявляет к возвращению Рокки пристальный интерес. [name] => Рокки Бальбоа [poster] => 9670 ) [2] => Array ( [_type] => _poetry [url] => http://www.askbooka.ru/stihi/aleksandr-pushkin/ya-vas-lyubil-lyubov-eshchyo-byt-mozhet.html [name] => Я вас любил: любовь ещё, быть может... [short-poem] => Я вас любил: любовь ещё, быть может, В душе моей угасла не совсем; Но пусть она вас больше не тревожит; Я не хочу печалить вас ничем. [writer] => Александр Пушкин ) [3] => Array ( [_type] => _poetry [url] => http://www.askbooka.ru/stihi/aleksandr-pushkin/pismo-tatyany-k-oneginu.html [name] => Письмо Татьяны к Онегину [short-poem] => Я к вам пишу - чего же боле? Что я могу ещё сказать? Теперь, я знаю, в вашей воле Меня презреньем наказать. [writer] => Александр Пушкин ) ) */
Получили двумерный массив, где первый уровень - простой числовой массив, значения которого хранят ассоциативный массив с информацией о самих полях и их значениях.
Теперь остается перебрать данный массив, а благодаря ключу _type
решить, какой слой какой внешний вид будет иметь. Выводится значения полей будут в том порядке, какой вы определили в админке.
Сгенерированный html код:
Nested Complex Fields (Вложенные комплексные поля)
Сложные (комплексные) поля могут быть вложенными, что даёт практически неограниченные возможности по созданию удобных форм для заполнения информацией. Вложенные комплексные поля - это комплексное поле, которое принимает массив из простых и комплексных полей.
Когда это может пригодится? Вернемся к примеру выше, где мы дали возможность автору статьи добавлять комплексное поле "Музыка". В нем он указывал название песни и прикреплял аудиофайл из медиабиблиотеки. А что если пользователь захочет указать альбом и прикрепить к нему несколько музыкальных произведений? Ему придется несколько раз выбирать слой "Музыка", причем название альбома ему некуда вписать. Затем во фронт-энде с помощью функции wp_playlist_shortcode() мы отображали аудиоплеер с выбранной песней. А если слоев с музыкой будет много? Будет куча аудиоплееров на странице, у которых в плейлисте по 1 песне.
В таких случаях, на помощь приходят вложенные комплексные поля, которые поддерживают любой уровень вложенности.
Порядок действий для создания вложенных комплексных полей
Рассмотрим вариант, когда пользователь можно выбрать - добавить одну песню или альбом.
-
Создадим множественное комплексное поле, которое будет иметь ещё 2 комплексных поля (слоя).
-
Первое комплексное поле будет одиночным и содержать два поля: название песни и аудиофайл.
- Второе поле будет множественным и содержать 3 поля: 1 - текстовое поле для названия альбома, 2 - поле для изображения альбома, 3 - одиночное комплексное поле, состоящее из повторяющегося поля для загрузки файла.
Схема
Создание поля
use Carbon_Fields\Container; use Carbon_Fields\Field; Container::make( 'post_meta', 'Предпочтения автора статьи' ) ->show_on_post_type( 'page' )// отобразим контейнер только на страницах (post_type = page) ->add_fields( array( Field::make( 'complex', 'sheet-preferences', 'Какой музыкой Вы вдохновлялись при написании статьи?' ) ->add_fields( 'single_song', 'Одна песня', array( Field::make( 'text', 'name-song', 'Название песни' ) ->set_width( 70 ), Field::make( 'file', 'file-song', 'Файл' ) ->set_type( 'audio' ) ->set_width( 30 ) ) ) ->add_fields( 'music_albums', 'Музыкальный альбом', array( Field::make( 'image', 'cover', 'Обложка альбома' ) ->set_width( 30 ), Field::make( 'text', 'name-album', 'Название альбома' ) ->set_width( 70 ), Field::make( 'complex', 'list_songs', 'Список песен' ) ->add_fields('item_song','Песня', array( Field::make( 'file', 'file-song', 'Файл' ) ->set_type( 'audio' ) ) ) ) ) ) );
Хранение данных
// Получаем данные $data_arr = carbon_get_post_meta( $post->ID, 'sheet-preferences', 'complex' ); print_r( $data_arr ); // Выведет Array ( [0] => Array ( [_type] => _single_song [file-song] => 976 [name-song] => Eddy - Need (Remix) ) [1] => Array ( [_type] => _single_song [file-song] => 9675 [name-song] => Heavy Love - Andrew Rayel Ft Kye Sones ) [2] => Array ( [_type] => _music_albums [cover] => 9688 [list_songs] => Array ( [0] => Array ( [_type] => _item_song [file-song] => 9673 ) [1] => Array ( [_type] => _item_song [file-song] => 9677 ) [2] => Array ( [_type] => _item_song [file-song] => 9681 ) [3] => Array ( [_type] => _item_song [file-song] => 9680 ) [4] => Array ( [_type] => _item_song [file-song] => 9676 ) [5] => Array ( [_type] => _item_song [file-song] => 9672 ) ) [name-album] => Andrew Rayel - Moments ) )
Вывод значений
В примере, на основе структуры получаемых данных определяем, что относится к одиночной записи, а что к альбому - от этого зависит внешний вид блоков. Предположим, нам надо вывести значения полей в таком виде:
Тогда код в шаблоне будет такой:
А полученный html будет выглядеть так:
Неправильное создание поля
Не используйте тире в методе add_fields() при указании имени и в именах родительских полей, иначе это приводит к неверному парсингу и созданию выходного массива данных с неправильными ключами у вложенных ассоциативных массивов.
Array ( [0] => Array ( [_type] => _single [song-_file-song] => 976 [song-_name-song] => Eddy - Need (Remix) ) [1] => Array ( [_type] => _single [song-_file-song] => 9675 [song-_name-song] => Andrew Rayel Ft Kye Sones - Heavy Love ) [2] => Array ( [_type] => _music [albums-_cover] => 9688 [albums-_list-songs] => Array ( [0] => Array ( [_type] => _item [song-_file-song] => 9681 ) [1] => Array ( [_type] => _item [song-_file-song] => 9680 ) [2] => Array ( [_type] => _item [song-_file-song] => 9676 ) [3] => Array ( [_type] => _item [song-_file-song] => 9678 ) [4] => Array ( [_type] => _item [song-_file-song] => 9673 ) [5] => Array ( [_type] => _item [song-_file-song] => 9672 ) ) [albums-_name-album] => Andrew Rayel - Moments ) )
Обратите внимание на ключи ассоциативных массивов - хоть закономерность составление ключа прослеживается, это всё равно доставит неудобства при обработке данных.
Методы
Отображение и логику работы комплексных полей можно изменить с помощью методов ниже.
add_fields( $fields )
Этот метод идентичен методу add_fields() у класса Container, где $fields - массив полей. То есть мы как бы в родительский контейнер помещаем дочерний контейнер с набором полей. Метод add_fields() можно вызывать по цепочки, тем самым увеличивать количество дочерних контейнеров.
set_layout( $layout )
Метод set_layout определяет макет контейнера, который имеет 3 вида:
grid
(по умолчанию) - список комплексных полей в виде сетки. Каждое поле в группе отображается с новой строки и помечается. Такой вид макета комплексных полей в основном вы ведите в примерах.tabbed-horizontal
- Группы полей отображаются в виде горизонтальных вкладокtabbed-vertical
- Группы полей отображаются в виде вертикальных вкладок
set_min( $min )
Минимальное количество рядов. Должно быть больше 0. По умолчанию -1 (без ограничений). Метод set_min
должен быть вызван после метода add_fields
.
Доверять данному методу не стоит, если вы на этом ограничении строите логику своего web-приложения.
Если указать, к примеру, set_min(2), то первая группа полей сразу будет отображена. Если ничего не заполнить, то запись сохраняется без проблем. Если же заполнить первую группу полей и попробовать сохранить запись, то контейнер с полями будет обведен в красную рамку без каких-либо других намеков на то, что надо добавить вторую группу полей - это сбивает с толку пользователей, потому используйте метод help_text(), чтобы рассказать им о своих ограничениях. Если же заполнить первую группу полей, добавить вторую и ничего в ней не заполнить - запись беспрепятственно сохранится.
set_max( $max )
Максимальное количество рядов. Должно быть больше 0. По умолчанию -1 (без ограничений). Метод set_max
должен быть вызван после метода add_fields().
setup_labels( $labels )
Позволяет клиентскому коду изменять метки для этого сложного поля. Принимаются следующие позиции:
plural_name
— заголовок для множественного числа. По умолчаниюentries
(элементы)singular_name
— заголовок для единственного числа. По умолчаниюentry
(элемент)
use Carbon_Fields\Container; use Carbon_Fields\Field; $assistants_labels = array( 'plural_name' => 'помощников', 'singular_name' => 'помощника', ); Container::make( 'post_meta', 'Дополнительные данные статьи' ) ->show_on_post_type( 'page' )// отобразим контейнер только на страницах (post_type = page) ->add_fields( array( Field::make( 'complex', 'assistants', 'Помощники' ) ->setup_labels( $assistants_labels ) ->help_text( 'Укажите всех, кто помогал Вам написать статью.' ) ->add_fields( array( Field::make( 'text', 'name', 'Как зовут помощника?' ) ->help_text( 'Имя и Фамилия помощника или просто никнейм' ), Field::make( 'textarea', 'contribution', 'Чем помог?' ) ->help_text( 'Какой вклад внес помощник?' ), ) ) ) );
set_header_template( $template )
Метод позволяет применить Underscore шаблон для отображения заголовка группы полей.
use Carbon_Fields\Container; use Carbon_Fields\Field; Container::make( 'post_meta', 'Дополнительные данные статьи' ) ->show_on_post_type( 'page' )// отобразим контейнер только на страницах (post_type = page) ->add_fields( array( Field::make( 'complex', 'donate', 'Пожертвования' ) ->help_text( 'Укажите всех, кто материального помог во время написания статьи.' ) ->add_fields( array( Field::make( 'text', 'name', 'Имя' ), Field::make( 'text', 'money', 'Сколько пожертвовал?' ), Field::make( "radio", "currency", "В какой валюте?" ) ->add_options( array( 'uah' => 'Гривны', 'usd' => 'Доллары', 'byn' => 'Белорусские рубли', 'rub' => 'Российские рубли', ) ) ) ) ->set_header_template(' <# if (name) { #> {{ name }} {{ money ? "пожертвовал " + money : "" }} {{ currency ? " " + currency : "" }} <# } #> ') ) );
Хранилище данных
Комплексные поля хранят данные в таблице *_postmeta
, *_options
и т.д. - это зависит от выбранного контейнера.
Наглядный пример хранения данных комплексного поля приведен в примерах к множественному комплексному полю.
Чтобы иметь возможность отличать значение поля, используется специальный формат ключей: meta_key
или option_name
:
{complex_field_name}_{group_name}-{field_name}_{number}
-
complex_field_name
- Имя комплексного поля, переданного в Field::make(). -
group_name
- Имя группы передается add_fields() или""
, если присутствует только одна группа. -
field_name
- Имя поля в группе, переданное вField::make()
. number
- Определяет номер строки, для которой это значение является частью.
Имена комплексных полей и их подполей именуются, начиная со знака подчеркивания, потому реальный формат получаемого имени поля следующий:
_{complex_field_name}_{group_name}-_{field_name}_{number}