Вступление
Рассмотрим работу с Carbon Fields — аналогом ACF.
Advanced Custom Fields (ACF) очень раскручен и им все пользуются. Но у ACF есть ряд минусов:
- Для создания полей ACF использует визуальный интерфейс. В некоторых версиях интерфейс глючит, некорректно сохраняет данные. А у Carbon Fields (CF) поля создаются прямо в коде. Для разработчика это удобно, а человеку без знаний PHP создание полей в интерфейсе бесполезно, потому что данные из новых полей еще нужно вывести в файлах темы. В итоге не понятно, для кого сделан графический интерфейс создания полей
- Carbon Fields полностью бесплатный (open source), и его возможностей достаточно для большинства задач. Еще по документации там можно создавать свои поля на React.js.
- Если вам нужно перенести какие-то наработки по интерфейсу в другой проект, то у ACF это делается через импорт-экспорт файла с параметрами. У CF можно скопировать и вставить код интерфейса и подправить в нужных местах. Как по-мне — это быстрее и удобней.
Еще CF можно подключить как библиотеку прямо в тему, а не как плагин. Через Composer. Чаще всего это очень удобно. Особенно, когда приходится подключать несколько библиотек, типа PHPWord или DomPDF. В этом случае у нас идет всего одно подключение через functions.php к автолоадеру, который подключает все остальное. В итоге код получается чище и понятней.
Поэтому я предпочитаю Carbon Fields. Рассмотрим следующие вопросы по CF:
- Как установить и начать пользоваться CF
- Как создать настройки темы и кастомные поля для любых типов записей.
Официальный сайт Carbon Fields — carbonfields.net
Чтобы понимать статью, полезно знать основы ООП в PHP, пространства имён и хуков WP. Тему хуков я разобрал в этой статье.
Как установить
Есть 2 основных способа установки: по-проще и по-сложнее 🙂
Способ по-проще: установить как плагин
Сначала идём по ссылке — https://docs.carbonfields.net/plugin-quickstart.html#without-composer
Дальше нажимаем сюда, чтобы скачать плагин:
Скачанный архив устанавливаем как обычный плагин WP.
Дальше открываем functions.php вашей темы и пишем код:
<?php
/**
* Укажем пространства имен. Их лучше прописать в самом верху файла
**/
use Carbon_Fields\Container;
use Carbon_Fields\Field;
/**
* Через хук вызовем функцию для создания настроек темы
**/
add_action( 'carbon_fields_register_fields', 'feodoraxis_attach_theme_options' );
function feodoraxis_attach_theme_options() {
Container::make( 'theme_options', __( 'Theme Options' ) )
->add_fields( array(
Field::make( 'text', 'feodoraxis_text', 'Text Field' ),
) );
}
Вообще, такие вещи лучше делать в отдельном файле. Например, в теме создать файл /inc/template-carbon-fields.php, подключить его в functions.php и работать с CF там.
Отлично! Если вы всё сделали правильно, то увидите в админке такую картину:
Способ по-сложнее: через Composer
Тут вам нужно уметь хоть немного работать с терминалом, а также установить composer на свой компьютер или сервер. Если работаете на сервере — то потребуется доступ по SSH через Terminal.
Если вы еще не разобрались с composer, то предлагаю ознакомиться со статей Composer: что это такое и как им пользоваться. При помощи composer вы сможете легко устанавливать и удалять разные PHP-библиотеки для вашего проекта. При этом не придется каждый раз добавлять/убирать код подключения доп. файлов. Кроме того, ваш проект будет «чище» с точки зрения расположения файлов и директорий, что упростит его разработку и поддержку.
Если не получается установить composer на компьютер — попробуйте его на хостинге beget через ssh прямо в панели управления. Это очень удобно и я сам этим постоянно пользуюсь 🙂
Я предполагаю, что вы работаете на локальной машине, поэтому не учитываю подключение по SSH. Если вы подключились — то дальше действия такие-же.
Для начала перейдем в директорию темы сайта:
cd wp-content/themes/twentytwentytwo/
Важно: вы уже должны находиться в директории сайта
Дальше выполним команду:
composer require htmlburger/carbon-fields
Теперь в functions.php добавляем код:
<?php
/**
* Укажем пространства имен. Их лучше прописать в самом верху файла
**/
use Carbon_Fields\Container;
use Carbon_Fields\Field;
/**
* Сначала подключим loader композера (composer)
*
* Подключив loader один раз, мы автоматически подключаем остальные решения,
* которые в будущем захотим установить через composer.
**/
add_action( 'after_setup_theme', 'feodoraxis_load' );
function feodoraxis_load() {
require_once( __DIR__ . '/vendor/autoload.php' );
\Carbon_Fields\Carbon_Fields::boot();
}
/**
* Через хук вызовем функцию для создания настроек темы
**/
add_action( 'carbon_fields_register_fields', 'feodoraxis_attach_theme_options' );
function feodoraxis_attach_theme_options() {
Container::make( 'theme_options', __( 'Theme Options' ) )
->add_fields( array(
Field::make( 'text', 'crb_text', 'Text Field' ),
) );
}
Если вы всё сделали правильно, то увидите в админке такую картину:
Основы, теория
Здесь я расскажу о принципах работы CF и дам советы из моей практики, которые могут упростить вам работу 🙂
Пространства имён
Классы CF работают в своём пространстве имён. Поэтому, в каком-бы файле вы не создавали кастомные поля CF, вы всегда должны указать пространства имён тех классов, с которыми работаете.
Например: если вы создаёте только кастомные поля, то вам нужны класс Container и Field. Их можно подключить так:
<?php
use Carbon_Fields\Container;
use Carbon_Fields\Field;
Если создаёте блок Gutenberg — то нужно подключить классы Field и Block:
<?php
use Carbon_Fields\Field;
use Carbon_Fields\Block;
Где указывать кастомные поля
Абсолютно все действия (создание настроек тем, кастомных полей и т.д.) выполняются в функции, которая должна вызываться через хук carbon_fields_register_fields.
На один хук можно «повесить» хоть сотню функций, поэтому для каждой задачи лучше подключать свою.
Например: для настроек темы одна функция; для записей — другая; для товаров — третья; для блока Gutenberg — четвёртая. Выглядеть это может примерно так:
<?php
use Carbon_Fields\Container;
use Carbon_Fields\Field;
/**
* Настройки темы.
*
* Последний параметр у add_action() - приоритет выполнения функции.
* Это значит, что если у хука carbon_fields_register_fields
* будет еще 9 функций с приоритетом ниже 10 - то сначала будут
* выполнены они, и только потом - наша
**/
add_action( 'carbon_fields_register_fields', 'feodoraxis_attach_theme_options', 10 );
function feodoraxis_attach_theme_options() {
Container::make( 'theme_options', __( 'Theme Options' ) )
->add_fields( array(
Field::make( 'text', 'feodoraxis_text', 'Text Field' ),
) );
}
/**
* Кастомные поля для записей
**/
add_action( 'carbon_fields_register_fields', 'feodoraxis_posts_fields', 20 );
function feodoraxis_posts_fields() {
Container::make( 'post_meta', 'Мои кастомные поля' )
->where( 'post_type', '=', 'post' ) // укажем условие, чтобы поля выводились только у записей
->add_fields([
Field::make( 'text', 'feodoraxis-subtitle', 'Подзаголовок' )
->set_width(70),
Field::make( 'media_gallery', 'feodoraxis-gallery', 'Галерея изображений' )
->set_width(30),
])
}
/**
* Кастомные поля для товаров WooCommerce
*
* Конечно, у WC характеристики лучше делать через Атрибуты
**/
add_action( 'carbon_fields_register_fields', 'feodoraxis_products_fields', 30 );
function feodoraxis_products_fields() {
Container::make( 'post_meta', 'Дополнительные данные' )
->where( 'post_type', '=', 'product' ) // укажем условие, чтобы поля выводились только у товаров WooCommerce
->add_fields([
Field::make( 'select', 'feodoraxis-paper-type', 'Тип бумаги' )
->set_options([
'gloss' => 'Глянец',
'mate' => 'Матовый'
])
])
}
Вообще, я предпочитаю раскидывать код по файлам и подключать их автолоадером. Дело в том, что когда у вас появляется много настроек, то работать с «колбасой» кода становится неудобно. А когда все раскидано по файлам с логичным названием — то и работать проще.
Помните, с помощью CF вы можете создать кастомные поля почти для любого типа записей: любые записи (posts), комментарии, категории, метки (таксономии) и прочее. Это открывает большие возможности при работе.
Условия (conditions)
У CF можно настроить отображение полей ввода при определенных условиях.
Например: показывать поле ввода только тогда, когда отмечен какой-то чекбокс:
Field::make( 'checkbox' 'feodoraxis-condition', 'Показать поле ввода?' ),
Field::make( 'text', 'feodoraxis-text', 'Поле ввода' )
->set_conditional_logic( array(
'relation' => 'AND', // Опционально, стандартно "AND"
array(
'field' => 'feodoraxis-condition', //Укажем имя поля, значение которого определяет условие
'value' => true, // какое значение должно принять поле. true - если чекбокс отмечен
'compare' => '=', // Способ сравнения. Опционально, стандартно "=". Доступные операторы: =, <, >, <=, >=, IN, NOT IN
)
) ),
Теперь текстовое поле будет доступно только тогда, когда чекбокс отмечен.
Контейнеры (Containers)
Создание настроек темы, кастомных полей записей, таксономий, комментариев — это всё создаётся через контейнеры (containers).
Контейнер — это группа кастомных полей и настроек отображения. Контейнеры отображаются в разных частях бекенда, в зависимости от их типа настроек отображения.
Это перевод определения с официального сайта. Мне оно не нравится. Поэтому скажу по-своему:
В контейнерах мы создаем все кастомные поля и блоки Gutenberg. Это основа всех кастомных полей в CF. Сам контейнер может отображаться в разных разделах админки: при добавлении/редактировании записи, таксономии, комментария, или, например, создать страницу настроек темы (theme_options).
Доступны следующие типы контейнеров:
- Comment Meta — Комментарии
- Gutenberg Blocks — Создание блоков Gutenberg
- Nav Menu Item — Настройки для пунктов меню
- Network — Поля для страниц в Мультсайтах
- Post Meta — Записи, страницы, товары WooCommerce, любые записи типа post
- Term Meta — Рубрики, метки, любые таксономии
- Theme Options — Настройки темы
- User Meta — Пользователи
- Widgets — Виджеты. Т.е. можно создавать свои виджеты, не придумывая новый плагин.
При этом отображение контейнера, как мы видели выше, можно настроить, чтобы он выводился только в нужных типах записей. Например, не во всех записях типа post, а только у страниц:
Container::make( 'post_meta', 'Дополнительные данные' )
->where( 'post_type', '=', 'page' )
Настройки темы
Конечно, настройки темы правильно создавать при помощи нативного кастомизатора WP. Но работать с CF гораздо проще, при этом возможности из коробки — шире.
У CF можно создать не только блок с кастомными полями, но и разбить их на табы. Часто мой код выглядит так:
<?php
use Carbon_Fields\Container;
use Carbon_Fields\Field;
add_action( 'carbon_fields_register_fields', 'feodoraxis_attach_theme_options', 10 );
function feodoraxis_attach_theme_options() {
Container::make( 'theme_options', __( 'Theme Options' ) )
/**
* Вкладка с общими настройками
**/
->add_tab( 'Общие настройки', [
Field::make( 'image', 'feodoraxis-logo', 'Логотип сайта' ),
Field::make( 'text', 'feodoraxis-sn-vk', 'Ссылка на VK' )
->set_width(33),
Field::make( 'text', 'feodoraxis-sn-telegram', 'Ссылка на Telegram' )
->set_width(33),
Field::make( 'text', 'feodoraxis-sn-youtube', 'Ссылка на YouTube' )
->set_width(33),
Field::make( 'text', 'feodoraxis-email', 'Email' )
->set_width(50),
Field::make( 'text', 'feodoraxis-phone', 'Номер телефона' )
->set_width(50),
])
/**
* Если FAQ выводится на нескольких страницах
* и текст везде одинаковый - лучше указать его в одном месте
**/
->add_tab( 'Часто задаваемые вопросы', array(
Field::make( 'complex', 'feodoraxis-faq-list', 'FAQ' )
->setup_labels([
'plural_name' => 'вопрос', //Как-то странно множественное число тут работает. Вообще не берется во внимание
'singular_name' => 'вопрос',
])
->set_collapsed( true ) // Чтобы при открытии в админке все вопросы были свёрнуты
->add_fields([
Field::make( 'text', 'feodoraxis-faq-item-question', 'Вопрос' ),
Field::make( 'textarea', 'feodoraxis-faq-item-answer', 'Ответ' ),
])
) );
}
Результат:
Чтобы получить нужные нам данные в публичной части сайта, воспользуемся функцией carbon_get_theme_option():
$faq = carbon_get_theme_option( 'feodoraxis-faq-list' ); //Так получим все вопросы и ответы
$vk = carbon_get_theme_option( 'feodoraxis-sn-vk' ); //Получим ссылку на VK
$telegram = carbon_get_theme_option( 'feodoraxis-sn-telegram' ); //Получим ссылку на Telegram
$youtube = carbon_get_theme_option( 'feodoraxis-sn-youtube' ); //Получим ссылку на YouTube
Создание кастомных полей
Если вы читали статью полностью — этого вопроса уже быть не должно. Но если нет, то вот наглядный пример, как создать кастомные поля для товаров WooCommerce. Создадим поле feodoraxis-paper-type для товаров WooCommerce:
<?php
use Carbon_Fields\Container;
use Carbon_Fields\Field;
add_action( 'carbon_fields_register_fields', 'feodoraxis_products_fields' );
function feodoraxis_products_fields() {
Container::make( 'post_meta', 'Дополнительные данные' )
->where( 'post_type', '=', 'product' ) // укажем условие, чтобы поля выводились только у товаров WooCommerce
->add_fields([
Field::make( 'select', 'feodoraxis-paper-type', 'Тип бумаги' )
->set_options([
'gloss' => 'Глянец',
'mate' => 'Матовый'
])
])
}
Для других типов записей, в условии отображения контейнера (Container) просто указываем нужный слаг вместо «product».
Как получить кастомные поля
Выше мы создали поле feodoraxis-paper-type для товаров WooCommerce. Чтобы вывести значение для конкретного товара, нужна функция carbon_get_post_meta().
/**
* Вместо $post->ID, можно использовать get_the_ID() или $product->get_id() (только для WooCommerce);
* Или можно ручками указать ID записи, данные которой нужны
**/
$feodoraxis_paper_type = carbon_get_post_meta( $post->ID, 'feodoraxis-paper-type' );
print_r( $feodoraxis_paper_type );
Если ранее мы указали, например, тип бумаги «матовый», то такой скрипт выведет нам следующий результат:
mate
Да, просто текстовое значение выбранного варианта. А в случае с изображением, если не укажем тип получаемых данных, получим массив, состоящий из:
- Его ID в системе (что предпочтительно)
- Прямую ссылку
- Оригинальную запись о нем из БД.
Создание блоков Gutenberg
Есть мнение, что создавать блоки Gutenberg средствами PHP неправильно. Мол, нужно использовать JS.
Отчасти я согласен — для каждой задачи нужно использовать свой инструмент.
Однако, у создания при помощи JS я вижу ряд минусов:
- Нельзя править «на горячую». Это значит, что если мы увидим проблему в процессе работы, то чтобы исправить недочёт, после правок в коде, блок нужно заново добавить и наполнить. А если этот блок использован по всему сайту — значит надо менять блоки по всему проекту? Если вы знаете, как решить эту проблему — пишите мне на почту (info@feodoraxis.ru) или в комментариях, если они открыты 🙂
- Сложно. Нужно потратить немало времени, чтобы создать такой блок. Для проектов с ограниченным бюджетом это проблема.
Возможно, проблемы описанные мной, связаны с моей некомпетентностью. Для серьезных проектов можно выделить время, а проблема «горячих» правок наверняка как-то решается.
У блоков, созданных через CF тоже есть свои минусы:
- Названия блоков поддерживают только латинские буквы. По-русски назвать блок не получится, но можно использовать ключевые слова на русском (метод set_keywords()), чтобы находить нужный блок используя русские названия
- Мы ограничены типами полей, хотя свои типы полей можно создать на React.js
- Мы ограничены способом конструировать блоки, который дает CF
- Вероятно, страницы с такими блоками (и сайт в целом) будут работать немного медленней, чем как если-бы мы создавали их как положено, через JSX. Но это только догадка, я не сравнивал и замеры скорости не делал. Возможно, сделаю в будущем.
Но это всё лирика. Давайте рассмотрим создание блоков Gutenberg на практике!
Создание блоков Gutenberg в CF, на мой взгляд, даже проще, чем создание кастомных полей. Можно всё сделать в одном файле.
<?php
use Carbon_Fields\Field;
use Carbon_Fields\Block;
add_action( 'carbon_fields_register_fields', 'feodoraxis_about_block' );
function feodoraxis_about_block() {
/**
* CF не поддерживает кириллицу в названии блоков, поэтому пишем их на английском
**/
Block::make( 'About' )
->add_fields([
Field::make( 'text', 'feodoraxis-about-title', 'Заголовок' ),
Field::make( 'textarea', 'feodoraxis-about-text', 'Текст' )
->set_rows(2),
Field::make( 'text', 'feodoraxis-about-link-text', "Текст ссылки"),
Field::make( 'text', 'feodoraxis-about-link-uri', "Адрес ссылки"),
])
->set_render_callback( function ( $fields, $attributes, $inner_blocks ) {
?>
<section class="about">
<div class="wrapper">
<h2><?php echo $fields["feodoraxis-about-title"]; ?></h2>
<p><?php echo nl2br($fields['feodoraxis-about-text']); ?></p>
<p><a href="<?php echo $fields['feodoraxis-about-link-uri']; ?>"><?php echo $fields['about-link-text']; ?></a></p>
</div>
</section>
<?php
} );
Как видите, всё предельно просто. В методе add_fields(), как и у контейнеров, мы создаем нужные поля, которые будем заполнять в админке, а в методе set_render_callback() закидываем вёрстку и выводим в ней данные полей нашего блока.
В админке этот блок будет выглядеть так:
А в публичной части примерно так:
Конечно, многое при этом зависит от стилей 🙂
Рекомендации
Здесь я буду дополнять рекомендации по работе с библиотекой. Хотя она мне нравится, но часто в ней возникают проблемы, решение которых найти сложно. О таких решениях я буду писать в этом разделе.
Используйте составные названия полей
Еще лучше — используйте префикс в названии. Например, название «category» лучше не использовать для ассоциативных полей, потому что это может вызвать ошибку «Call to a member function get_thumbnail_by_type() on null«. Но если в название поля добавить, например, «catalogs_category», то ошибка может исчезнуть. Такая беда возникает с кастомными записями и таксономиями. Почему — не знаю.
Заключение
Я постарался рассказать о Carbon Fields максимально подробно со всеми важными деталями. Конечно, в статье могут быть косяки, ошибки или недочёты. О них я прошу писать в комментариях в группе ВК. Да и вообще пишите, что думаете там. Так вы поможете моему продвижению 🙂