Таблица с опциями в WordPress содержит все настройки вашего сайта, тем и плагинов. В ней могут храниться как простые флажки (да/нет), так и данные более крупных размеров, иногда даже логи. API для работы с опциями в WordPress очень простой, его можно резюмировать в две строки:
update_option( 'foo', 'bar' ); // сохранить опцию с названием foo $foo = get_option( 'foo' ); // получить опцию foo
Но это лишь поверхность, так как внутренний механизм работы с опциями намного сложнее, и именно из-за этого многие даже опытные разработчики совершают ряд критических ошибок, которые могут привести к замедлению WordPress сайтов и чрезмерному потреблению памяти.
Fatal error: Allowed memory size of 134217728 bytes exhausted
Конечно можно обратиться к хостинг-провайдеру, попросить поднять лимит памяти до 256 мегабайт, затем еще больше, еще и еще. Но таким образом вы временно скрываете проблему, а не решаете ее.
Как работают опции в WordPress
В WordPress есть таблица wp_options
, ее структура достаточно простая:
+-----------+-------------+-------------------+----------+ | option_id | option_name | option_value | autoload | +-----------+-------------+-------------------+----------+ | 1 | siteurl | http://develop.lo | yes | +-----------+-------------+-------------------+----------+
При обращении к функции get_option()
в WordPress, мы получаем значение опции по ключу из базы данных, но здесь стоит помнить одну очень важную вещь: опции с флажком autoload
подгружаются в память автоматически при загрузке ядра WordPress, за это отвечает внутренняя функция wp_load_alloptions().
Это значит, что при обращении к опции siteurl
в нашей теме или в плагине WordPress, результат будет выдан сразу из кэша объектов, а не из базы данных MySQL.
Такой подход является безусловным плюсом для тех опций, которые мы (ядро, наша тема, наши плагины) намерены использовать для отображения текущей страницы в WordPress. Это предотвращает лишние походы в базу данных MySQL за каждой требуемой опцией.
Но что насчет тех опций, которые мы загрузили в память, но так ими и не воспользовались? Они ведь просто потребляют наши ресурсы.
Что с этим делать?
Вряд ли найдется такая страница, для отображения которой потребовались бы абсолютно все опции с флагом autoload
, и наверняка большинство страниц на вашем WordPress сайте используют намного меньше половины всех авто-подгружаемых опций, и это нормальная практика.
Проблемы с производительностью возникают далеко не из-за их количества. Вернемся к нашему API для работы с опциями WordPress, возьмем простой плагин, который решил записать в опцию foo
значение bar
:
update_option( 'foo', 'bar' );
Многие разработчики даже не задумываются над тем, станет ли такая опция подгружаться автоматически. Требуется ли эта опция для отображения большинства страниц на сайте, и сколько «лишней» памяти будет потреблять эта опция.
Запомните, при использовании функций update_option()
или add_option()
, флаг autoload
ставится по умолчанию для новых опций. А при деактивации или удалении темы или плагина, опция (как правило) никуда не исчезает. Если вам потребовалось создать опцию без autoload
, то воспользуйтесь четвертым аргументом функции add_option().
Конечно для опции foo-bar это всего порядка 6 байт памяти (три байта для ключа и три для значения), и даже тысяча таких опций (~ 6 килобайт) практически никак не скажутся на скорость работы сайта и потребление памяти, но давайте рассмотрим более интересный пример.
Пример
Не так давно мы помогали разобраться с производительностью одного небольшого проекта, обнаружили следующий код, написанный на заказ небольшой студией. Им поставили простую задачу — записывать IP адреса всех, кто посещает страницу оплаты в их интернет-магазине:
add_action( 'wp_footer', function() { if ( ! is_page( 'payment' ) ) return; $log = get_option( 'payment-ip-log' ); $log .= $_SERVER['REMOTE_ADDR'] . PHP_EOL; update_option( 'payment-ip-log', $log ); } );
Конечно все работало хорошо, посетители заходили на страницу оплаты, этот плагин записывал их адреса, заказчик был довольным. Но спустя несколько месяцев каждая страница сайта стала вылетать за рамки выделяемой памяти.
К сожалению их хостинг-провайдер перевел их на более дорогой тарифный план, затем еще дороже и еще, ссылаясь на то, что WordPress «прожорлив к серверным ресурсам». Они деактивировали все плагины, поставили тему по умолчанию, но это не помогло.
Проблема здесь в том, что опция payment-ip-log
была установлена с флагом autoload
по умолчанию. Таким образом, при загрузке любой страницы сайта, WordPress загружал весь этот лог IP-адресов в память:
mysql> SELECT option_name, LENGTH(option_value), autoload FROM wp_options WHERE option_name = 'payment-ip-log'; +----------------+----------------------+----------+ | option_name | LENGTH(option_value) | autoload | +----------------+----------------------+----------+ | payment-ip-log | 131329015 | yes | +----------------+----------------------+----------+
Если бы разработчик здесь поставил no
для флага autoload
, это решило бы проблему для всех страниц, кроме страницы оплаты, так как на ней мы все равно пытались бы загрузить большой объем в память.
Удалив эту опцию целиком из базы данных, и удалив плагин, который ее генерировал, нам удалось решить проблему с потреблением памяти, и вернуть лимит до стандартных 32 мегабайт. Если же говорить о самой задаче, то намного логичнее было бы решить ее с помощью произвольной таблицы в MySQL, или с помощью записи значений в файл на диске.
Как найти подобные опции?
С помощью запроса в базу данных MySQL можно получить список самых крупных по объему опций с флагом autoload
:
mysql> SELECT option_name, LENGTH(option_value) AS length FROM wp_options WHERE autoload = 'yes' ORDER BY length DESC LIMIT 10; +--------------------------------+--------+ | option_name | length | +--------------------------------+--------+ | jetpack_file_data | 23046 | | rewrite_rules | 22430 | | weaverii_settings | 17952 | | _site_transient_update_plugins | 11697 | | columbus | 7836 | | useradminsimplifier_options | 6308 | | theme_mods_semicolon | 4787 | | wp_user_roles | 4188 | | _site_transient_update_themes | 2817 | | wpseo_titles | 2633 | +--------------------------------+--------+
Все эти опции будут загружаться при каждом запросе на ваш WordPress сайт. В данном примере все вполне прилично, 23кб не такой существенный объем, хотя если вы например не используете плагин Jetpack, то опцию jetpack_file_data
можно смело удалить. Если у вас не активирована тема Weaver II, то опцию weaverii_settings
можно удалить.
К сожалению не всегда из названий опций можно понять к какой теме или плагину она относится, и тогда приходится выполнять поиск по исходному коду.
Также не следует удалять опции ядра WordPress, а если вы заметили что некоторые из них стали потреблять слишком много памяти, то вероятно проблема в стороннем плагине, теме или в конфигурации сервера.
Например, недавно мы столкнулись с опцией ядра cron
(планировщик задач в WordPress) которая потребляла более 8 мегабайт памяти. Выяснилось, что хостинг-провайдер отключил клиенту исполнение cron-задач, а новые задачи продолжали добавляться в эту опцию каждый день. Решить проблему удалось просто включив планировщик задач WordPress.
Заключение
Если вы заметили, что ваш сайт на WordPress со временем стал медленным и использует чрезмерное количество памяти, то не спешите бросаться деньгами в вашего хостинг-провайдера. Возможно проблему можно решить более дешевым и надежным способом.
Если у вас возникли вопросы по работе опций в ядре WordPress — оставьте комментарий.