Carbon Fields — бесплатный аналог ACF

  1. Главная
  2. Блог
  3. WordPress
  4. 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 я вижу ряд минусов:

  1. Нельзя править «на горячую». Это значит, что если мы увидим проблему в процессе работы, то чтобы исправить недочёт, после правок в коде, блок нужно заново добавить и наполнить. А если этот блок использован по всему сайту — значит надо менять блоки по всему проекту? Если вы знаете, как решить эту проблему — пишите мне на почту (info@feodoraxis.ru) или в комментариях, если они открыты 🙂
  2. Сложно. Нужно потратить немало времени, чтобы создать такой блок. Для проектов с ограниченным бюджетом это проблема.

Возможно, проблемы описанные мной, связаны с моей некомпетентностью. Для серьезных проектов можно выделить время, а проблема «горячих» правок наверняка как-то решается.

У блоков, созданных через CF тоже есть свои минусы:

  1. Названия блоков поддерживают только латинские буквы. По-русски назвать блок не получится, но можно использовать ключевые слова на русском (метод set_keywords()), чтобы находить нужный блок используя русские названия
  2. Мы ограничены типами полей, хотя свои типы полей можно создать на React.js
  3. Мы ограничены способом конструировать блоки, который дает CF
  4. Вероятно, страницы с такими блоками (и сайт в целом) будут работать немного медленней, чем как если-бы мы создавали их как положено, через 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 максимально подробно со всеми важными деталями. Конечно, в статье могут быть косяки, ошибки или недочёты. О них я прошу писать в комментариях в группе ВК. Да и вообще пишите, что думаете там. Так вы поможете моему продвижению 🙂