Верх страницы
Обложка к записи Оптимизация плагина ACF
Время для прочтения: 1 мин. 9 сек.

Оптимизация плагина ACF

Безусловно, плагин Advanced Custom Fields (ACF) является лидером среди плагинов для добавления произвольных полей в WordPress.

У него тысячи контрибьюторов, которые находят и фиксят ошибки, занимаются оптимизацией производительности, но всегда есть, что подкрутить.

Суть данной оптимизации заключается в переносе инициализации полей из базы данных в РНР, скрытии GUI плагина, удалению ненужных записей в базе данных и отключении плагина во фронтенде.

Экспорт полей в РНР

Для начала экспортируем имеющиеся поля в виде PHP кода. Для чего переходим по пути Группы полей → Инструменты, отмечаем чекбокс Выбрать все и нажимаем кнопку Генерировать РНР.

Копируем полученный код и вставляем его в файл functions.php вашей активной темы, используя рекомендуемый хук acf/init:

add_action( 'acf/init', function() {
    acf_add_local_field_group( array( ... ) );
} );

Отключение GUI в ACF

Так как все поля у нас теперь инициализируются через РНР, то управлять ими через админку нам более не требуется, поэтому отключим данный интерфейс при помощи хука acf/settings/show_admin внутри файла functions.php вашей активной темы:

add_filter( 'acf/settings/show_admin', '__return_false' );

Теперь и админка WordPress и сам сайт будут делать ровно в два раза меньше запросов в базу данных для получения полей.

ACF Builder

После экспорта полей в PHP и отключения ненужного нам более GUI можно подтянуть к себе в проект удобную обёртку ACF Builder, которая использует текучий интферфейс (fluent interface) для создания конфигурации полей прямо из кода.

Устанавливается она либо через composer:

composer require stoutlogic/acf-builder

Либо простым подключением файла autoload.php в ваш проект. Сначала нужно склонировать себе проект:

git clone git@github.com:StoutLogic/acf-builder.git

И после этого подключать:

require_once __DIR__ . '/acf-builder/autoload.php';

Использовать билдер достаточно просто:

use StoutLogic\AcfBuilder\FieldsBuilder;

$banner = new StoutLogic\AcfBuilder\FieldsBuilder('banner');
$banner
    ->addText('title')
    ->addWysiwyg('content')
    ->addImage('background_image')
    ->setLocation('post_type', '==', 'page')
        ->or('post_type', '==', 'post');

add_action('acf/init', function() use ($banner) {
   acf_add_local_field_group($banner->build());
});

Более подробно смотрите в документации к ACF Builder.

Удаление лишних записей в базе данных

Внутренняя архитектура плагина ACF такова, что для хранения одного поля у одного поста используется две метазаписи в базе данных. Одна содержит информацию о самом поле, вторая — значение этого поля.

После переноса всех полей в само приложение информация о поле в базе данных нам больше не нужна, поэтому мы может ее удалить.

Перед началом работы с базой данных — сделайте её полный бекап.

Бекап делаем при помощи WP-CLI:

wp db export

После создания бекапа, открываем консоль MySQL, куда будем вводить SQL запросы:

wp db cli

Удаление полей у записей

Ищем поля, которые начинаяются на _field_ и удаляем их:

DELETE FROM wp_postmeta WHERE meta_key like '\_field\_%' LIMIT 100000;

Удаление полей у пользователей

Ищем поля, которые начинаяются на _field_ и удаляем их:

DELETE FROM wp_usermeta WHERE meta_key like '\_field\_%' LIMIT 100000;

Отключение плагина ACF во фронтенде

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

Копируем следующий код и вставляем его в файл _disable-acf-on-frontend.php (подчеркивание в начале нужно, чтобы файл подключился в самом начале загрузки плагинов WordPress) в папке wp-content/mu-plugins:

/**
* Удаляем плагин ACF во фронтенде
*
* @param array $plugins Массив всех плагинов
* @return array
*/
function mihdan_disable_acf_on_frontend( $plugins ) {
    if ( is_admin() || wp_is_json_request() || wp_is_jsonp_request() ) {
        return $plugins;
    }
 
    foreach( $plugins as $key => $plugin ) {
        if ( 'advanced-custom-fields-pro/acf.php' === $plugin ) {
            unset( $plugins[ $key ] );
        }
    }
 
    return $plugins;
}
add_filter( 'option_active_plugins', 'mihdan_disable_acf_on_frontend' );

Теперь, чтобы вывести поля нужно использовать стандартные функции ядра get_post_meta, get_term_meta, get_user_meta вместо функции get_filed из набора ACF.

Чтиво

Комментарии приветствуются.

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

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

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

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

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

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

28 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии
Игорь Тронь
5 лет назад

Отключение на фронте что конкретно дает в плане производительности?

anton
anton
5 лет назад
Ответить на  Кобзарёв Михаил

Спасибо! Ваша статья по поводу «попрофилировать через xdebug и сразу увидишь сколько памяти и на что тратит плагин на фронте.» была бы очень всем полезна.

anton
anton
5 лет назад

В коде ошибки

wp_is_json_request наверное wp_is_json_request()?

$i навероное $key?

Или это защита от копипасты? ))

Руслан
Руслан
5 лет назад

Вариант с отключением плагина во фронте не срабатывает. Функция плагина остаются доступными и возвращают значения при обращении.

Руслан
Руслан
5 лет назад
Ответить на  Кобзарёв Михаил

Да, я это заметил. Но моя ошибка была в другом. Я вставил фильтр в functions.php темы, но не как mu plugins. Значение active_plugins менялось после того, как плагины уже были прогружены. Спасибо!

Dominik
Dominik
3 лет назад

В первом пункте вы написали:

используя рекомендуемый хук acf/init:

add_action(
    'acf/init',
    function() {
        acf_add_local_field_group( array( ... ) );
    }
);

объясните пожалуйста что это значит??? Если вы имели ввиду то, что нужно поставить сгенеррированный из ACF PHP код заместо «…» то происходит крах сайта.

Почему нельзя просто скопировать то, что сгенеррируется из ACF сразу в functions.php?

Dominik
Dominik
3 лет назад
Ответить на  Кобзарёв Михаил

Спасибо за ответ!

Это действительно классно, когда разработчик отвечает, особенно если ответ в адекватный срок (не через год).

Приведите пожалуйста пример того, как нужно поставить PHP код из ACF используя хук acf/init — я не совсем понимаю то, как это нужно сделать.

Заранее спасибо. Добавил ваш сайт в закладки — отличная инфа!

Dominik
Dominik
3 лет назад

Ещё пару вопросов:

1) А для чего удалять в базе — они же не будут использоваться. Просто что бы уменьшить размер базы?

2) «add_filter( ‘acf/settings/show_admin’, ‘__return_false’ );» вставляем после php кода от ACF или без разницы? Просто не происходит отключение интерфейса. Как слева стоит плагин, так всё и осталось.

3) Отключение плагина ACF во фронтенде — правильно ли я понимаю, что после отключения придётся дописывать код, что бы вывести поля? Т.е. Уже ранее работающие поля перестанут работать? Что даёт данный шаг и на сколько высока его необходимость?

Иван
Иван
3 лет назад
Ответить на  Кобзарёв Михаил

Можно пример вывода поля через get_post_meta() и get_term_meta()?

Вот допустим этих полей

<?php if($artikyl=get_field(«artikyl» )){echo $artikyl;} ?>

<?php if($foto_6=get_field(«foto_6»)){echo ‘<img src=»‘.$foto_6.'»/>’;}?>

Michael F.
Michael F.
3 лет назад

имеет ли смысл проводить данную оптимизацию для сайтов с количеством полей ~20 и посещением ~1000 в сутки?

Michael F.
Michael F.
3 лет назад
Ответить на  Кобзарёв Михаил

хорошо. вот еще один вопрос, очень хотелось бы узнать, какой вариант делает меньше всего запросов к базе данных в цикле WP_Query
1 вариант:

<?php if( empty( get_post_meta( $post->ID, 'name', true ) ) ) : 
	echo get_post_meta( $post->ID, 'name', true );
endif; ?>

2 вариант:

<?php if ( $price = get_field( 'name' ) ) : ?>
	<?php echo $price; ?>
<?php endif; ?>
Последний раз редактировалось 3 лет назад Michael F. ем
Бойчук Иван
Бойчук Иван
3 лет назад

Привет, отличная статья. А что вы посоветуете делать с полями типа Репитер? как это обойти грамотно?

Бойчук Иван
Бойчук Иван
2 лет назад

в MU плагине еще можно добавить проверку на крон wp_doing_cron()

Александр
Александр
1 год назад

Не понял зачем переносить поля в php если можно скинуть их в json, бред же, тем более через пару обновлений структура может поменяться и фиг потом что сделаешь с этими полями

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

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

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