Швидкий WordPress: 20 директив замість теорії

7 хв читанняWordPressшвидкістьCore Web Vitals

Що робити, чого не робити і в якому порядку. З кодом, який можна скопіювати, і з поясненням, чому аналітика майже ніколи не валить LCP, а плагіни - не винні.

Під одним із наших постів розробник попросив розписати досвід і додав умову, яку ми вважаємо найрозумнішою з можливих: хочеться набір директив, а не кілометри відео з теорією. Ось він - двадцять пунктів, кожен з яких ми робимо руками на реальних проєктах.

Прожерливий не WordPress. Голе ядро віддає сторінку швидко. Повільним сайт роблять тема з конструктора і сторонні скрипти, на які ніхто не дивиться.

Спочатку домовимось, що ви міряєте

1. Lighthouse - це лабораторія, а в ранжуванні Google дивиться на польові дані. Мобільний тест емулює повільний процесор і стрибає на кілька пунктів від запуску до запуску без жодних змін у коді. Значення мають реальні LCP, INP і CLS у браузерах ваших відвідувачів. Бал у звіті на позиції не впливає взагалі.

2. Міряйте всі типи шаблонів, а не головну. Головна завжди вилизана. Біда живе на сторінці запису, у лістингах з пагінацією, у пошуку і в кошику. Проженіть по одному URL кожного типу, інакше ви оптимізуєте вітрину, а люди ходять по складу.

3. Розділяйте метрики за природою. LCP - це критичний шлях рендерингу: що заважає намалювати найбільший елемент. INP - головний потік: скільки JavaScript виконується між кліком і реакцією. CLS - зарезервоване місце. Три різні хвороби, три різні лікування. Найчастіша помилка - побачити червоне і почати «оптимізувати все».

Тема і плагіни

4. Конструктор сторінок - це податок, який ви платите на кожному запиті. Elementor, WPBakery і подібні тягнуть власний CSS, власний JS і власний шар рендерингу поверх WordPress. Викинути конструктор - найбільший одиничний виграш, який взагалі можливий. Але сам по собі він сотку не дає, це половина шляху.

5. Плагіни - не вороги, і рахувати їх немає сенсу. Хороший плагін кращий за криву саморобку в темі, і більша частина корисного на сайті приїжджає саме плагінами. Якщо річ нормально в темі не робиться - беріть плагін і не соромтесь.

6. Питання не «скільки плагінів», а що конкретний плагін друкує у фронт там, де він не потрібен. Плагін форми, який вантажить свій CSS і JS на всіх сторінках, поки форма стоїть на одній, - це не поганий плагін, це погано налаштований плагін. Знімається одним хуком.

add_action( 'wp_enqueue_scripts', function () {
    if ( is_page( 'contact' ) ) {
        return;
    }
    wp_dequeue_style( 'some-forms-plugin' );
    wp_dequeue_script( 'some-forms-plugin' );
}, 100 );
Пріоритет 100 - щоб спрацювати після того, як плагін поставив свої асети в чергу.

7. Приберіть те, що ядро друкує саме і що вам не потрібно: скрипт емодзі, генератор версії, RSD і WLW посилання, XML-RPC. Десяток рядків у темі і мінус кілька запитів на кожній сторінці.

remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
remove_action( 'wp_print_styles', 'print_emoji_styles' );
remove_action( 'wp_head', 'wp_generator' );
remove_action( 'wp_head', 'rsd_link' );
remove_action( 'wp_head', 'wlwmanifest_link' );
add_filter( 'xmlrpc_enabled', '__return_false' );

Кеш: плагін береться за стеком

8. Сторінковий кеш обов'язковий, і який саме - каже сервер, а не ваші вподобання.

  • LiteSpeed або OpenLiteSpeed - LiteSpeed Cache. Кеш живе в самому сервері: запит до закешованої сторінки взагалі не доходить до PHP. Найдешевший виграш, який є, і безкоштовний.
  • nginx або Apache - WP Rocket. Тут кеш неминуче PHP-рівня: плагін пише статичний HTML і віддає його раніше, ніж стартує ядро.
  • Пастка: якщо хостер продає «LiteSpeed», а насправді там Apache з lsapi, LSCache відкотиться на PHP-рівень і головна перевага зникне. Перевіряйте заголовки відповіді, а не сторінку тарифів.

9. Скидайте кеш за подіями, а не за таймером. Кеш на тиждень з інвалідацією при публікації, коментарі чи зміні даних працює краще, ніж кеш на годину, який гасне сам. Правило: кожна дія, що змінює контент, має явно скинути те, що вона змінила.

10. «Магічні» опції поверх кешу - об'єднання і мінімізація CSS та JS, видалення невикористаних стилів, відкладання всього JavaScript - працюють рівно тоді, коли ви не контролюєте код. На успадкованому сайті з конструктором і двома десятками плагінів, який ніхто не сяде переписувати руками, це найкращий інструмент, який у вас взагалі є, і він дає реальний результат. На сайті з власною темою і нормальною збіркою вони не дають майже нічого: код уже мінімізований, об'єднувати нема чого, а зламати є що. Вмикайте по одній і перевіряйте сайт після кожної - так ви знайдете ту, яка ламає, замість відкочувати всі разом. Без «залежить» тут одне: ніколи не вмикайте мінімізацію HTML у плагіні разом із власним стисненням на рівні теми чи сервера - відповідь приходить побитою, і ви шукатимете причину тиждень.

CSS, JavaScript, шрифти

11. Усі власні скрипти вантажте з defer. Це штатний параметр при реєстрації скрипта, милиці з фільтром script_loader_tag більше не потрібні. Жодного скрипта, який блокує парсинг, у вас бути не повинно.

wp_enqueue_script(
    'theme-main',
    get_theme_file_uri( '/assets/main.js' ),
    array(),
    filemtime( get_theme_file_path( '/assets/main.js' ) ),
    array( 'strategy' => 'defer', 'in_footer' => true )
);
filemtime як версія - кеш браузера скидається сам, щойно файл змінився.

12. Вмикайте окремі стилі для блоків і розбивайте код по типах сторінок. За замовчуванням ядро віддає один великий файл для всіх блоків; один фільтр - і воно віддає стилі лише тих, які реально є на сторінці. Те саме стосується вашого коду: потрібний на одній сторінці має вантажитись лише на ній. Саме тут ховається половина зайвої ваги в типовому проєкті.

add_filter( 'should_load_separate_core_block_assets', '__return_true' );

13. Шрифти тільки локально, тільки woff2, font-display: swap, дві родини максимум. Зовнішній шрифтовий сервіс - це сторонній домен у критичному шляху, який коштує вам DNS, TCP і TLS перед першим малюванням. Preload робіть лише для того накреслення, яким написаний заголовок: preload усього підряд - це не оптимізація, а конкуренція за той самий канал.

Картинки. Тут лежить найбільший виграш

14. Готуйте всі розміри заздалегідь у WebP, а не конвертуйте в рантаймі. Конвертація на льоту силами плагіна - це навантаження на хостинг і затримка на першому відвідувачі.

15. Один герой eager, решта lazy. У ядрі це керується порогом, після якого проставляється відкладене завантаження. Стандартне значення - 3. Для макетів з великим банером його треба знижувати до одиниці.

add_filter( 'wp_omit_loading_attr_threshold', function () {
    return 1;
} );

16. Перевірте, що саме ядро вважає LCP-картинкою, і зробіть їй preload. Ядро само проставляє високий пріоритет першому великому зображенню - і коли макет починається з декоративної плашки або логотипа, воно помиляється. Дивіться в готовий HTML, а не в наміри, і підстрахуйте preload з тим самим набором розмірів, який віддаєте в розмітці. Найдешевший спосіб зняти пів секунди з найповільнішої метрики.

add_filter( 'wp_preload_resources', function ( $resources ) {
    if ( ! is_front_page() ) {
        return $resources;
    }
    $resources[] = array(
        'href'          => get_theme_file_uri( '/assets/hero-1280.webp' ),
        'as'            => 'image',
        'fetchpriority' => 'high',
    );
    return $resources;
} );

17. Ширина і висота обов'язкові завжди. Без них браузер не знає, скільки місця резервувати, і сторінка стрибає. Це прямий шлях до поганого CLS, який відчуває читач, а не лише тест.

Сторонні скрипти

18. Аналітика майже ніколи не валить LCP. Це головне непорозуміння в темі. GA4 вантажиться асинхронно і б'є по INP та по часу в головному потоці, а не по найбільшому елементу. LCP валить те, що стоїть у критичному шляху, і за частотою це: шрифти з чужого домену, банер згоди, реклама над згином, менеджер тегів, а далі чати підтримки, карти й вбудовані відео. Останні - тільки через фасад: картинка з кнопкою, плеєр після кліку.

19. Не відкладайте аналітику до першої взаємодії, якщо вам потрібні чесні дані. Порада вантажити її після скролу чи кліку справді додає пунктів, але ви втрачаєте всіх, хто пішов одразу - тобто саме тих, заради кого ви в статистику й дивитесь. Це обмін, а не оптимізація, і рішення тут приймає власник, а не розробник.

Як закрити суперечку з клієнтом

20. Міряйте двічі: зі сторонніми скриптами і без них. Заблокуйте їхні домени в DevTools і прожніть тест ще раз. Різниця між двома прогонами - це і є ціна, яку клієнт платить за аналітику й рекламу.

Поки клієнт не побачив цю різницю цифрою, повільний сайт - ваша провина. Після того, як побачив, це його рішення і його компроміс.

Це найважливіший пункт усього списку, і він не технічний. Іншого способу закрити цю розмову остаточно ми не знаємо. А через тиждень подивіться польові дані в Search Console - це єдина оцінка, яка щось означає для пошуку.

Порядок дій

  • Викинути конструктор і те, що ядро друкує саме.
  • Налаштувати плагіни так, щоб вони не друкували себе там, де не потрібні.
  • Правильно віддати картинки і шрифти.
  • Поставити кеш під свій сервер, а «магічні» опції вмикати там, де код не ваш.
  • І лише в кінці торгуватись зі сторонніми скриптами.

Якщо почати з кінця, ви поставите плагін кешування поверх конструктора сторінок і будете здивовані, чому нічого не змінилось.

І пам'ятайте головне: сотка на мобільному з рекламою - це або тест без реклами, або вдалий збіг. Ставте собі чесний бюджет і оптимізуйте те, що справді у вашій владі.