Верх страницы
Обложка к записи Создание ACF блоков при помощи block.json
Время для прочтения: 3 мин. 53 сек.

Создание ACF блоков при помощи block.json

Версия ACF 6.0 включает в себя значительное улучшение способа создания блоков.

Теперь он поддерживает использование block.json, что соответствует предпочтительному методу регистрации блоков в ядре WordPress.

Почему это важно? Как только WordPress представит новые возможности для блоков, вы сразу же сможете начать их использовать. Блоки регистрируются «WordPress way», поэтому поддерживают все функции ядра WP. Вам не нужно ждать, пока ACF добавит поддержку новой функции.

Что по поводу моих старых блоков? Блоки, созданные с помощью acf_register_block_type(), будут продолжать работать точно так же, как ожидалось, и нет необходимости возвращаться и обновлять старый код. Однако я рекомендую использовать новый метод для всех будущих блоков.

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

Если у вас возникли проблемы с тем, что ваши блоки не отображаются, сначала убедитесь, что у вас ACF 6.0 или выше, затем пропустите ваш файл block.json через валидатор JSON, чтобы проверить, есть ли какие-либо проблемы. К сожалению, из коробки нет никаких сообщений об ошибках, если в вашем JSON-файле есть опечатки.

Создание файла block.json

Каждый блок должен иметь файл block.json, поэтому лучше всего создать каталог для каждого блока. Я рекомендую создать папку /blocks/ в вашей теме или плагине для их хранения.

Создайте файл block.json в папке с конкретным блоком. Пример: /blocks/tip/block.json

{
    "name": "cwp/tip",
    "title": "Recipe Tip",
    "description": "",
    "style": "file:./style.css",
    "script": "",
    "category": "cultivatewp",
    "icon": "carrot",
    "apiVersion": 2,
    "keywords": [],
    "acf": {
        "mode": "preview",
	"renderTemplate": "render.php"
    },
    "styles": [],
    "supports": {
        "align": false,
        "anchor": false,
        "alignContent": false,
        "color": {
            "text": false,
            "background": true,
            "link": false
        },
        "alignText": false,
        "fullHeight": false
    },
    "attributes": {
    }
}

Большинство из этого будет соответствовать настройкам для acf_register_block_type(), но есть несколько важных моментов, которые следует отметить.

Произвольные префиксы в имени блока

Для имени (name) теперь можно указать свой собственный префикс, вместо автоматического префикса acf. Если вы не добавите префикс, будет использоваться префикс ACF.

Script (скрипты)

Если вам нужно загрузить файл JavaScript вместе с блоком, используйте параметр script для передачи обработчика: "script": "block-tip".

Убедитесь, что вы также зарегистрировали этот скрипт и указали все зависимости.

/**
 * Register block script
 */
function cwp_register_block_script() {
    wp_register_script( 'block-tip', get_template_directory_uri() . '/blocks/tip/block-tip.js', [ 'jquery', 'acf' ] );
}
add_action( 'init', 'cwp_register_block_script' );

Если вы используете ACF JS API (например, window.acf.addAction), вам нужно включить acf в качестве зависимости.

Если вы используете пространство имен, отличное от acf/, вам нужно использовать полное имя блока в функции обратного вызова, например: render_block_preview/type=cwp/tip.

Style (стили)

Параметр style позволяет указать таблицу стилей для подключения в этот блок. Здесь есть пара вариантов использования.

"style": "file:./style.css"

При этом фактический CSS будет загружен непосредственно в шапку документа. Это означает, что файл CSS не загружается отдельным запросом, что уменьшает время начальной загрузки страницы (плюс), но также файл CSS не кэшируется браузером, что немного увеличивает время последующей загрузки страницы (минус).

Поместите файл style.css в директорию блока (например: /wp-content/themes/my-theme/blocks/tip/style.css).

"style": "block-tip"

Это позволит запустить wp_enqueue_style( 'block-tip' ) для нормальной загрузки CSS файла. В любом месте вашей темы/плагина вы должны зарегистрировать данный файл стилей:

wp_register_style( 'block-tip', get_template_directory_uri() . '/blocks/tip/style.css' )

Небольшое замечание по поводу стилей:

Если вы используете тему FSE (блочную тему), то загрузка стилей будет работать именно так, как вы ожидаете. Файлы CSS и встроенные стили будут загружаться только в том случае, если страница содержит блок.

Если вы похожи на меня и создаете «классические» темы на основе PHP, WordPress загружает каждый зарегистрированный стиль блока в заголовке, независимо от того, существует ли этот блок на странице. Вы можете использовать фильтр should_load_separate_core_block_assets, чтобы сказать WP загружать только те файлы, которые необходимы, но этот фильтр ждёт события wp_footer, чтобы загрузить CSS, вызывая большие проблемы CLS, что делает эту функцию бесполезной.

Аргументы ядра WordPress (как я их понимаю) заключаются в том, что мы не знаем точно, какие блоки находятся на странице в данный момент. Они могут быть в содержимом поста, или в переиспользуемых блоках, или в виджетах, или в других блочных функциях. Хотя все это верно, я бы предпочел загружать CSS-файлы, которые находятся в содержимом записи, в шапку и загружать недостающие — в подвал.

Я создал свой собственный CSS-загрузчик, который определял, какие блоки появляются на странице, но теперь я предпочитаю использовать WP Rocket для удаления неиспользуемых CSS со страницы.

Icon (иконка)

Вы можете указать иконку из набора Dashicons, которую следует использовать, или включить прям SVG:

"icon": "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22.5 22.5'><defs><style>.a{fill:#222;}.b{fill:#1fa8af;}</style></defs><path class='a' d='M20.17,4a10.17,10.17,0,0,0-7-3.5L11.91.38h-.18a.64.64,0,0,0-.47.13A.68.68,0,0,0,11,.93L10.6,3.79a.48.48,0,0,0,.12.43.54.54,0,0,0,.44.18h.11l1.44.17c3.94.45,6.12,2.69,5.84,6a8.37,8.37,0,0,1-2.49,5.12A8.14,8.14,0,0,1,10,18.06l-.65,0H9.15a.8.8,0,0,0-.5.17.68.68,0,0,0-.25.44L8,21.5a.49.49,0,0,0,.12.42.57.57,0,0,0,.45.18h.17l1,0h.34a11.61,11.61,0,0,0,8.21-3.39,12.76,12.76,0,0,0,3.77-7.92A9.49,9.49,0,0,0,20.17,4Z'/><path class='b' d='M9.2,17h.15L10,17a7.61,7.61,0,0,0,3.64-.77L15,6.15a8.65,8.65,0,0,0-2.33-.57l-1-.12-1,7.35L9.23,7c-.11-.45-.33-.67-.65-.67H7.16c-.29,0-.5.22-.65.67L5.1,12.81,3.82,3a.55.55,0,0,0-.61-.55H.78a.36.36,0,0,0-.29.16A.6.6,0,0,0,.37,3a.5.5,0,0,0,0,.18L2.53,19.22a1.07,1.07,0,0,0,.23.6.64.64,0,0,0,.53.23H5.16c.37,0,.61-.21.73-.65l2-7.19Z'/></svg>",

ACF

В этот массив помещаются настройки, специфичные для ACF.

Используйте mode, чтобы указать, как блок будет отображаться в редакторе блоков. По умолчанию используется режим auto, который показывает блок в соответствии с фронтендом, пока вы не выберете его, тогда он становится редактором группы полей ACF. Если установить значение preview, то блок всегда будет выглядеть как фронтенд, и вы сможете редактировать группу полей ACF в боковой панели.

Используйте renderTemplate, чтобы указать, какой PHP файл будет рендерить этот блок. Я обычно располагаю файл render.php в каждой директории блока для единообразия.

Также вы можете использовать renderCallback, чтобы указать PHP-функцию, которая будет выводить содержимое блока.

Styles (стили)

Используйте styles для указания массива стилей типов блока.

"styles": [
        { "name": "default", "label": "Default", "isDefault": true },
        { "name": "red", "label": "Red" },
        { "name": "green", "label": "Green" },
        { "name": "blue", "label": "Blue" }
    ],

Supports (возможности)

Используйте supports, чтобы указать, какие функции Gutenberg поддерживает этот блок. По умолчанию для всех элементов используется значение false, поэтому вам не нужно указывать все элементы, которые он не поддерживает, но я обычно оставляю их все с пометкой false, чтобы можно было легко переключить нужные мне элементы на true.

В данном примере единственная функция, которую поддерживает этот блок, — это цвет фона:

"supports": {
        "align": false,
        "anchor": false,
        "alignContent": false,
        "color": {
            "text": false,
            "background": true,
            "link": false
        },
        "alignText": false,
        "fullHeight": false
    },

Attributes (атрибуты)

Вы можете установить атрибуты по умолчанию для возможностей блока. Например, если блок поддерживает цвет фона, можно сделать так, чтобы этот блок по умолчанию использовал третичный цвет (tertiary):

"attributes": {
	"backgroundColor": {
		"type": "string",
		"default": "tertiary"
	}
}

Для более детальной информации смотрите статью Metadata in block.json.

Регистрация вашего блока

После того, как вы создали папку tip в вашей теме или плагине и положили туда файлы block.json, style.css и render.php, то самое время сообщить WordPress о вашем блоке с помощью функции register_block_type().

В файле functions.php вашего плагина или темы добавьте:

/**
 * Load Blocks
 */
function cwp_load_blocks() {
    register_block_type( get_template_directory() . '/blocks/tip/block.json' );

    // Optional - register stylesheet if using Style Method 2 from above
    wp_register_style( 'block-tip', get_template_directory_uri() . '/blocks/tip/style.css' );
}
add_action( 'init', 'cwp_load_blocks' );

Вот и все! Теперь ваш пользовательский блок должен Recipe Tip быть доступен в редакторе блоков.

Расширенное использование

Хотя приведенный выше простой пример работает идеально, есть несколько способов его улучшить:

  • Зарегистрировать каждый блок, существующий в каталоге /blocks
  • Закэшировать список блоков, чтобы не обращаться к файловой системе при каждой загрузке страницы.
  • Зарегистрировать таблицу стилей для каждого блока
  • Включить все группы полей ACF, связанные с этим блоком
  • Включить любые дополнительные PHP-файлы, необходимые для блока.

Вот код, который я использую в своих темах, с последующим описанием того, что он делает.

<?php
/**
 * Blocks
 *
 * @package      CultivateClient
 * @author       CultivateWP
 * @since        1.0.0
 * @license      GPL-2.0+
 **/

namespace Cultivate\Blocks;

/**
 * Load Blocks
 */
function load_blocks() {
	$theme  = wp_get_theme();
	$blocks = get_blocks();
	foreach ( $blocks as $block ) {
		if ( file_exists( get_template_directory() . '/blocks/' . $block . '/block.json' ) ) {
			register_block_type( get_template_directory() . '/blocks/' . $block . '/block.json' );
			wp_register_style( 'block-' . $block, get_template_directory_uri() . '/blocks/' . $block . '/style.css', null, $theme->get( 'Version' ) );

			if ( file_exists( get_template_directory() . '/blocks/' . $block . '/init.php' ) ) {
				include_once get_template_directory() . '/blocks/' . $block . '/init.php';
			}
		}
	}
}

add_action( 'init', __NAMESPACE__ . '\load_blocks', 5 );

/**
 * Load ACF field groups for blocks
 */
function load_acf_field_group( $paths ) {
	$blocks = get_blocks();
	foreach ( $blocks as $block ) {
		$paths[] = get_template_directory() . '/blocks/' . $block;
	}

	return $paths;
}

add_filter( 'acf/settings/load_json', __NAMESPACE__ . '\load_acf_field_group' );

/**
 * Get Blocks
 */
function get_blocks() {
	$theme   = wp_get_theme();
	$blocks  = get_option( 'cwp_blocks' );
	$version = get_option( 'cwp_blocks_version' );
	if ( empty( $blocks ) || version_compare( $theme->get( 'Version' ), $version ) || ( function_exists( 'wp_get_environment_type' ) && 'production' !== wp_get_environment_type() ) ) {
		$blocks = scandir( get_template_directory() . '/blocks/' );
		$blocks = array_values( array_diff( $blocks, array( '..', '.', '.DS_Store', '_base-block' ) ) );

		update_option( 'cwp_blocks', $blocks );
		update_option( 'cwp_blocks_version', $theme->get( 'Version' ) );
	}

	return $blocks;
}

/**
 * Block categories
 *
 * @since 1.0.0
 */
function block_categories( $categories ) {

	// Check to see if we already have a CultivateWP category
	$include = true;
	foreach ( $categories as $category ) {
		if ( 'cultivatewp' === $category['slug'] ) {
			$include = false;
		}
	}

	if ( $include ) {
		$categories = array_merge(
			$categories,
			[
				[
					'slug'  => 'cultivatewp',
					'title' => __( 'CultivateWP', 'cultivate_textdomain' ),
					'icon'  => \cwp_icon( [ 'icon' => 'cultivatewp', 'group' => 'color', 'force' => true ] ),
				],
			]
		);
	}

	return $categories;
}

add_filter( 'block_categories_all', __NAMESPACE__ . '\block_categories' );

Моя функция get_blocks() сканирует каталог /blocks и создает массив всех блоков. Я сохраняю его как опцию, поэтому нам нужно сделать это только один раз, и использую текущую версию темы для сброса кэша. Поэтому, когда я добавляю новый блок, я также изменяю номер версии в style.css.

Код делает следующее для каждого блока:

  • Вызывает register_block_type(), используя файл block.json
  • Вызывает wp_register_style() для регистрации таблицы стилей блока. Эта функция будет загружена только в том случае, если в файле block.json указан стиль (style).
  • Если в каталоге блока есть файл init.php, загружает и его. Это то, что я использую для любого дополнительного PHP-кода, который я хочу запустить независимо от рендеринга блока.
  • Я делаю все это на хуке init с приоритетом 5, чтобы я мог использовать обычный init (с приоритетом 10) внутри моего файла init.php.
  • Фильтр acf/settings/load_json указывает ACF искать в каталогах моих блоков файлы групп полей ACF JSON.

Дополнительная информация

Автор: Кобзарёв Михаил

Русский разработчик с 20-ти летним стажем. Работаю с PHP, ООП, JavaScript, Git, WordPress, Битрикс, Joomla, Drupal, Opencart, DLE, Laravel, Moonshine, SuiteCRM.

Оптимизирую сайты под Google Page Speed, настраиваю импорты для больших магазинов на WooCommerce + WP All Import. Пишу плагины на заказ. Все мои услуги.

Веду блог о разработке, дайджест в телеграмме и в ВК.

Вы всегда можете нанять меня.

Комментарии
Подписаться
Уведомить о
guest

2 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии
Dan Zakirov
Dan Zakirov
8 месяцев назад

Напишите в целом про block.json

Предыдущая запись
Следующая запись

Давайте дружить
в Телеграме

Авторский блог вашего покорного слуги в Telegram про web, программирование, алгоритмы, инструменты разработчика, WordPress, Joomla, Opencart, Laravel, Moonshine, фильмы и сериалы