Всем привет!
Начиная с версии 16.22.0 под капотом плагина WP-Recall загудело новое мощное API произвольных полей.
Произвольные поля WP-Recall - одна из основных частей ядра плагина. Именно на основе этого функционала создаются все формы плагина: административные настройки, формы входа и регистрации, профиль, различные менеджеры в административной части, форма публикации, формы форума и многие другие примеры из многочисленных дополнений плагина. Я уже рассказывал как работать с произвольными полями и как строить различные формы на основе произвольных полей, прошу ознакомиться с материалом, если еще не успели сделать это ранее.
Последнее обновление плагина значительно расширило гибкость и возможности этого API и что самое главное - позволило добавлять свои типы полей, что ранее было просто невозможно!
Сначала давайте рассмотрим пример инициализации и работы с отдельным произвольным полем.
Сначала формируем массив с данными произвольного поля. Я не буду подробно останавливаться на структуре массива, его содержимое массива и порядок формирования не претерпели изменений, с этим вопросом можно подробно ознакомиться в моих предыдущих статьях ссылки на которые я оставил выше.
$field = array( 'type' => 'text', 'slug' => 'field_one', 'title' => __('Текстовое поле'), 'placeholder' => __('Заполните это поле'), 'required' => 1, 'notice' => __('тут какое то примечание к полю') )<br>
Далее инициализируем произвольное поле
$fieldObject = Rcl_Field::setup( $field );
В результате мы получим объект с данными произвольного поля в свойствах и полезными методами, которые понадобятся для дальнейшей работы.
Полный перечень всех методов и свойств можно посмотреть в файле
/classes/fields/class-rcl-field-abstract.php
Класс содержит абстрактное поле с общими методами, а уже каждый конкретный тип поля формируется соответствующими классами, которые находятся в папке
/classes/fields/types/
Специальные классы из этой папки передают нюансы определенного типа поля: формируют отдельные свойства, его отображение, настройки, порядок вывода значения и тд.
Итак, для построения формы из полученного объекта поля нам могут понадобиться следующие основные методы:
->get_value() - получает значение поля для вывода, в зависимости от типа может быть обернуто html-разметкой ->get_notice() - получает указанную заметку к полю, результат обернут html-разметкой ->get_title() - наименование поля, обернут html-разметкой ->get_field_value('title' = false) - значение поля, обернут html-разметкой ->get_field_input() - основное html-представление поля, без заголовка ->get_field_html() - полное html-представление поля
Используя эти методы можно быстро сформировать html-представление поля для использования в своем коде или форме.
Я все же предполагаю, что для создания форм вы будете использовать функцию rcl_get_form(), которую я описывал в статье о создании форм, она позволяет быстро и без заморочек создавать формы на основе текущего API произвольных полей.
Давайте рассмотрим пример создания и добавления поля своего типа.
Для начала нам потребуется создать класс-потомок от класса Rcl_Abstract_Field с основными методами:
class Rcl_MY_Field extends Rcl_Field_Abstract { //специальные свойства поля function __construct( $args ) { parent::__construct( $args ); } //метод, где указывается массив опций поля, //которые будут доступны в административном менеджере полей function get_options() { } //возвращаем минимальное html-представление поля function get_input() { } //возвращает значение поля (если возвращается только $this->value, //то можно не определять метод, он уже есть в родителе) function get_value(){ } }
Мы получили класс с типичным содержимым для произвольного поля, осталось только заполнить предлагаемые методы, а этот вопрос напрямую зависит от того, какое именно поле мы хотим создать.
Давайте допустим, что в нашем проекте нам необходимо использовать некое поле, которое будет состоять из нескольких числовых или текстовых input'ов, число которых может изменяться в зависимости от переданных данных при формировании поля. Соответственно, данные, указанные в этих input'ах должны сохраняться в массив. Мы предполагаем использовать данное поле в нашей форме. Поехали.
Укажем специальные свойства класса и возможные настройки поля в методе get_options(). У нас будет два специальных свойства: одно для указания количества input'ов, второе - для указания типа этих inpit'ов. Массив настроек формируется точно также как и любое произвольное поле плагина, настройки формируем с оглядкой на то, что нужные нам свойства должны изменяться через них:
class Rcl_MY_Field extends Rcl_Field_Abstract { //специальные свойства поля public $number_fields; public $type_fields; function __construct( $args ) { parent::__construct( $args ); } function get_options() { return array( array( 'slug' => 'number_fields', 'default' => $this->number_fields, 'type' => 'number', 'title' => __( 'количество полей' ) ), array( 'slug' => 'type_fields', 'default' => $this->type_fields, 'type' => 'radio', 'title' => __( 'тип полей' ), 'values' => [ 'text' => __('Текстовое поле'), 'number' => __('Числовое поле') ] ) ); } function get_input() {} function get_value(){} }
Следует отдельно сообщить, что наш класс также унаследовал много свойств от родителя, которые мы при желании можем сразу же использовать без объявления, например:
- title
- slug (id)
- value
- placeholder
- maxlenght
- required
- notice
- input_id
- input_name
Теперь формируем минимальное html-представление нашего поля. Мы помним, что это несколько input'ов типа text или number, количество зависит от свойства type_fields:
class Rcl_MY_Field extends Rcl_Field_Abstract { /******/ function get_input() { $fields = array(); for($a = 0; $a < $this->number_fields; $a++){ $fields[] = '<input type="'.$this->type_fields.'" name="' . $this->input_name . '[]" value="' . $this->value[$a] . '">'; } return implode(' ', $fields); } /******/ }
Мы прогнали простой цикл с количеством итераций равным type_fields и в каждой сформировали свой input сразу позаботившись о выводе значения, если такое уже будет присутствовать на тот момент.
Осталось описать вывод значения поля:
class Rcl_MY_Field extends Rcl_Field_Abstract { /******/ function get_value(){ return implode(', ', $this->value); } }
Так как в значении у нас массив значений, значит мы разворачиваем его в строку с запятой в разделителе.
Полный класс нашего поля
class Rcl_MY_Field extends Rcl_Field_Abstract { public $number_fields; public $type_fields; function __construct( $args ) { parent::__construct( $args ); } function get_options() { return array( array( 'slug' => 'number_fields', 'default' => $this->number_fields, 'type' => 'number', 'title' => __( 'количество полей' ) ), array( 'slug' => 'type_fields', 'default' => $this->type_fields, 'type' => 'radio', 'title' => __( 'тип полей' ), 'values' => [ 'text' => __('Текстовое поле'), 'number' => __('Числовое поле') ] ) ); } function get_input() { $fields = array(); for($a = 0; $a < $this->number_fields; $a++){ $fields[] = '<input type="'.$this->type_fields.'" name="' . $this->input_name . '[]" value="' . $this->value[$a] . '">'; } return implode(' ', $fields); } function get_value(){ return implode(', ', $this->value); } }
Вроде класс готов, но я присмотрелся к строчке
$fields[] = '<input type="'.$this->type_fields.'" name="' . $this->input_name . '[]" value="' . $this->value[$a] . '">';
и подумал, что использовать в данном случае html для формирования поля input определенного типа некомильфо и решил сделать его на основе ... уже имеющихся типов произвольных полей: text и number. После соответствующей замены получилось совсем хорошо:
class Rcl_MY_Field extends Rcl_Field_Abstract { public $number_fields; public $type_fields; function __construct( $args ) { parent::__construct( $args ); } function get_options() { return array( array( 'slug' => 'number_fields', 'default' => $this->number_fields, 'type' => 'number', 'title' => __( 'количество полей' ) ), array( 'slug' => 'type_fields', 'default' => $this->type_fields, 'type' => 'radio', 'title' => __( 'тип полей' ), 'values' => [ 'text' => __('Текстовое поле'), 'number' => __('Числовое поле') ] ) ); } function get_input() { $fields = array(); for($a = 0; $a < $this->number_fields; $a++){ $fields[] = Rcl_Field::setup([ 'type' => $this->type_fields, 'slug' => $this->slug, 'input_name' => $this->input_name . '[]', 'value' => $this->value[$a] ]) ->get_input(); } return implode(' ', $fields); } function get_value(){ return implode(', ', $this->value); } }
Без html стало куда лучше)
Теперь осталось зарегистрировать наше произвольного поля нового типа, пусть будет тип 'mytype'. Делается это так:
add_filter( 'rcl_fields', 'add_my_new_field_type' ); function add_my_new_field_type( $fields ) { $fields['mytype'] = array( 'label' => __( 'Мой тип поля' ), 'class' => 'Rcl_MY_Field' ); return $fields; }
После этого, мы можем использовать новый тип произвольного поля в нашей форме, например так:
$form = rcl_get_form([ 'submit' => __('Сохранить'), 'fields' => [ [ 'type' => 'mytype', 'slug' => 'myfield', 'title' => __('Название поля'), 'number_fields' => 3, 'type_fields' => 'number', 'value' => [ //тут укажем дефолтные значения для каждого input 1,2,3 ] ] ] ]);
Не забываем указать 'slug' - он будет определять тег name для input и основные свойства поля, необходимые для его формирования. Также можем указать дефолтные значения в свойстве 'value'.
В результате мы создали форму с нашим типом поля, которое мы можем использовать там где потребует долг разработчика.
Наш класс будет формировать примерно такое ядро поля:
<div class="rcl-field-core"> <input type="number" name="myfield[]" value="1"> <input type="number" name="myfield[]" value="2"> <input type="number" name="myfield[]" value="3"> </div>
Данные с нашего поля будут сохраняться в массив, затем их надо будет отдать в массив поля также как и дефолтные значения.
Вот такая революционная возможность появилась. Я уверен, что в дальнейшем мы увидим появление новых типов полей, которые будут предлагаться общественности для использования в виде дополнения или отдельных сниппетов, ну а в ядре плагина, уже очень скоро, появится новое поле реализующее продвинутый загрузчик файлов. Все интересное впереди!
А тут для тех, кто дочитал до конца, я делюсь типом поля 'rangedate' - диапазон дат https://pastebin.com/7kmYjyWy, возможно вам это пригодится.
Пока на этом все.
Если вы были внимательны, то обратили внимание, что мы никак не задействовали сформированные опции нашего поля, но мы обязательно рассмотрим этот момент чуть позже, в следующей статье.
Надеюсь Вам было не только интересно, но и понятно)
Всем удачи!
Что если я сделаю свое произвольное поле, которое будет состоять, например, из 3ех текстовых полей. А затем, когда оно будет выводиться, у него будет кнопка клонирования, как у динамического поля.
Такие данные сохранятся и потом при выводе можно будет восстановить структуру?
т.е. будет что то типо такого:
input type="text" name="city[]"
input type="text" name="street[]"
input type="text" name="city[]"
input type="text" name="street[]"
input type="text" name="city[]"
input type="text" name="street[]"
И тут кнопка "Добавить еще блок с полями"
Данные с одного поля должны формировать один массив, в твоем примере, массива получается два, лучше тогда назначить для тега name значения
$this->input_name.'[city][]'
$this->input_name.'[street][]'
тогда данные будут сохранены одним массивом, который можно будет получить по $this->input_name или $this->slug и далее разложить его так как надо.
Логику обработки полученного массива с сохраненными значениями тебе придется описать самому в методе get_input(). Смотри примеры существующих полей, которые работают с массивами, например, select или checkbox.
Скрипт обработки нажатия по кнопке добавления новых полей тебе также придется написать самому, как это сделано в поле dynamic.
Вроде понял, я искал как в этом классе получается дефолтное значение, но потом дошло что дефолтное значение я сам буду передавать в момент создания поля, так что должно получиться.
А что с авто выводом таких сложных полей, например когда включен авто вывод произвольных полей в теле публикации? Тогда это значение recall будет брать по методу get_value и я сам смогу вернуть нужную структуру?
При автовыводе полей, будут получены все произвольные поля прикрепленные к форме публикации, а далее по их slug будут получены все их значения из post_meta публикации, далее они будут передаваться в поле в качестве value и обрабатываться уже твоим классом в методе get_value(), поэтому все должно отработать хорошо.
Важно убедиться, что при сохранении публикации данные твоего поля также сохраняются в post_meta, если нет, то сохранять его самому в хуке 'update_post_rcl'
Пожалуйста, очень вас прошу, расскажите пошагово как вы реализовали данный репитер, с учетом что мне нужно еще 4 чекбокса в него вставить. Буду очень признателен.
Thanks codeseller, I your code is very important. I like it.
I glad my code was helpful.
Так то все вроде бы и понятно, но хочется одновременно плакать и материться. Читаю значит. "Формируем массив с данными и т.д." Вроде все понятно. Сформировал. Читаю дальше. "Далее инициализируем произвольное поле". В общем то понятно что такое инициализация, но где ее проводить мне конкретно непонятно. Я открыл статью про формирование своей формы, там тоже этого не нашел, так же перелопатил десяток ваших форумов, ноль. Увадаемые разработчики и создатели данного плагина, я конечно может и не супер специалист, и много чего не понимаю, но мне очень хотелось бы чтоб документация была написано не для людей которые и так шарят что где и к чему, а для таких как я. Неужели так сложно описать этот гребанный процесс инициализации, или если он где то есть, кинуть на эту статью ссылку. Или в идеале, вместо постоянно повторяющихся в статьях фраз "Это описывалось там-то", "Это мы обсуждали в другом месте", просто сделать над собой усилие и откопипастить и вставить цитатой в данную статью, чтоб не пришлось шариться открывая миллиард вкладок в поисках нужной информации. Спасибо большое за внимание.
Как много хотелок от вас к бесплатному плагину. Повышайте свой уровень и вернитесь чтоб привести документацию к пониманию таким как вы. Много кто хочет взять нахаляву и мало кто вносит вклад. Так что будьте одним из первых.
А этот ресурс и не основан чтобы учить азам программирования. Для этого в сети есть платные курсы.
p.s. Минусанул за "гребаный".
Внимательно в прочтении, плюсонуло бы вам к пониманию того что я изложил. Мне в общем то все равно на рейтинг это во первых, а во вторых, к самому плагину у меня претензий нет вообще, будь вы хоть на грамм учтивее, вы бы вычленили из всего моего текста не одно слово, на котором сконцентрировались, а суть моего комментария. В котором говориться что документация убогая, чтоб решить какую то задачу, нужно очень долго пользоваться поиском и тратить уйму времени которого зачастую и так не хватает. Но ваш неискушенный взгляд падает лишь на неугодные вам словечки, которые в контексте в целом звучат как крик отчаяния человека, которому нужно сделать работу, а толковой информации нет. И вместо того чтоб высказывать свое никому не нужное мнение, могли бы просто помочь.
В частности это руководство полное и линейное.
Вам, новичку, от php которому плохо становится (а именно так кажется от вашего вступления) - всё кругом гребаное и плохое. Как говорится "плохому танцору..."
Вы сами пришли с наездами и ожидаете что вот с такого наезда ринутся вам помогать. Начните следующий раз не с хамства и романтических вступлений.
Думаете воду, что вы излили, читать кто-то будет и пытаться вникнуть? Больше конкретики - что делал и где и что не получилось. Но лучше не через каменты - а через форум с ссылкой на это руководство.