` (меняет вызовы, Text Domain, пересобирает .pot). * Шаблон после правки строк — `php tools/perevod.php pot`. * * @package finalwork-accessibility */ defined( 'ABSPATH' ) || exit; /* * Файлов перевода в плагине нет, и грузить их кодом не нужно. Каталог просит не класть * .po/.mo/.json в архив (письмо 17.09): переводы приходят языковыми пакетами * translate.wordpress.org в wp-content/languages/plugins, и ядро (4.6+) берёт их само * при первом __() — just-in-time. Поэтому нет ни load_plugin_textdomain(), ни Domain Path. * JS — так же: wp_set_script_translations без третьего аргумента (admin.php). * Исходники немецкого для заливки в translate.wordpress.org — razvedka/perevod, сборка — tools/perevody. */ /** * Версия плагина. Хранится ещё и в базе (опция ниже), чтобы будущее обновление * видело, с какой версии идёт, и знало, что чинить в данных. */ define( 'ONSITE_A11Y_VERSIYA', '1.0.0' ); /** Опция с версией. Вторая опция плагина — ONSITE_A11Y_OPCIYA_OBHODA (obhod.php); обе сносит uninstall.php по имени. */ define( 'ONSITE_A11Y_OPCIYA_VERSII', 'onsite_a11y_version' ); /** Путь и адрес папки плагина — понадобятся, когда появятся свои css и js. */ define( 'ONSITE_A11Y_FAYL', __FILE__ ); define( 'ONSITE_A11Y_PUT', plugin_dir_path( __FILE__ ) ); define( 'ONSITE_A11Y_ADRES', plugin_dir_url( __FILE__ ) ); /* * Раздел в панели — только для админки. На чужом сайте посетитель не должен * тянуть ни байта нашего кода ради страницы, которую он никогда не увидит. */ if ( is_admin() ) { require_once ONSITE_A11Y_PUT . 'admin.php'; require_once ONSITE_A11Y_PUT . 'obhod.php'; } /** Метка в адресе: «отдай страницу так, как её видит посетитель». */ define( 'ONSITE_A11Y_METKA_GOSTYA', 'onsite_a11y_kak_gost' ); /** * Стоит ли в адресе метка гостя. * * Это флаг только на чтение: он не меняет ничего в базе и не запускает действий — * страница лишь собирается без виджета и (для администратора) как для гостя. * Поэтому nonce ему не нужен, а гостю — эталонной проверке, которая по той же метке * убирает виджет, — его и не выдать. Значение нам не важно, только наличие; читаем * через filter_input, а не из $_GET напрямую, — данные запроса не трогаем вовсе. */ function onsite_a11y_est_metka_gostya() { return null !== filter_input( INPUT_GET, ONSITE_A11Y_METKA_GOSTYA, FILTER_DEFAULT ); } /* Виджет посетителя живёт на фронте, поэтому подключается всегда. */ require_once ONSITE_A11Y_PUT . 'vidzhet.php'; /** * Проверяемую страницу отдаём глазами ГОСТЯ, а не администратора. * * Сканер грузит страницу в рамке внутри панели, то есть с нашей же сессией — * и WordPress подрисовывает сверху админ-панель, которой у посетителя нет. * Мы находили нарушения в ней и показывали владельцу сайта проблемы, которых * его читатели не видят. Цех поймал это на правиле region: находка родилась * на служебной ссылке админ-панели. * * Почему именно так, а не иначе: * - прятать панель стилями бессмысленно: она осталась бы в разметке, и * правила, которые смотрят на структуру, всё равно за неё цепляются; * - вырезать её узел из проверки — лечение симптома: панель тянет свои * скрипты и стили, и они меняют страницу вокруг себя; * - грузить без нашей сессии нельзя технически: рамка шлёт куки сайта сама. * * Сначала мы только гасили панель — и этого оказалось мало. Панель лишь самое * заметное из того, что WordPress и темы рисуют вошедшему: в форме комментария * стояла строка «Angemeldet als admin» с двумя ссылками, и цех поймал на ней две * ложные находки link-in-text-block. Туда же ссылки «Изменить», черновики и всё, * что прячется за is_user_logged_in. Гасить их по одной — бесконечная охота. * Поэтому для такого запроса WordPress вообще не узнаёт администратора: текущий * пользователь — гость, и страница собирается ровно как для гостя. * * Фильтр determine_current_user, а не wp_set_current_user на init: до init тема * и плагины уже могли спросить, кто вошёл, и собрать своё под администратора. * * @param int|false $id Пользователь, которого WordPress узнал по кукам. * @return int|false */ function onsite_a11y_rezhim_gostya( $id ) { if ( ! $id || is_admin() || ! onsite_a11y_est_metka_gostya() ) { return $id; } // Метку принимаем только у того, кто и так может запускать проверку: // иначе это просто лишний способ дёргать сайт чужими руками. user_can по id, // а не current_user_can: текущего пользователя мы сейчас и определяем. if ( ! user_can( $id, 'manage_options' ) ) { return $id; } return 0; } add_filter( 'determine_current_user', 'onsite_a11y_rezhim_gostya', PHP_INT_MAX ); /** * Включение плагина. * * Заводим ровно одну строку в базе — записанную версию. Больше пока нечего: * ни таблиц, ни расписаний, ни настроек. Каждая новая строка обязана быть * добавлена и сюда, и в uninstall.php одним движением. */ function onsite_a11y_vklyuchenie() { update_option( ONSITE_A11Y_OPCIYA_VERSII, ONSITE_A11Y_VERSIYA ); } register_activation_hook( __FILE__, 'onsite_a11y_vklyuchenie' ); /** * Выключение плагина. * * Выключение — это НЕ удаление: данные владельца сайта здесь не трогаем, иначе * человек, выключивший плагин на минуту, потеряет результаты своих проверок. * Сюда идёт только то, что не должно жить без плагина: задания расписания, * правила перезаписи. Сейчас нет ни того, ни другого. */ function onsite_a11y_vyklyuchenie() { // Пусто намеренно. Появится расписание — снимать его здесь. } register_deactivation_hook( __FILE__, 'onsite_a11y_vyklyuchenie' );