- 24.05.16
- 20:50
- 2453
- 0
За один запуск WordPress активирует не более одного хука wp_ajax_*
— в случае, когда обрабатывается AJAX-запрос. При обработке не-AJAX-запросов эти хуки не активируются. Поэтому, когда количество обработчиков AJAX велико, регистрировать их все сразу нет смысла.
В самом начале обработки запроса скрипт /wp-admin/admin-ajax.php
задаёт константу DOING_AJAX
как true
, а действие, которое должно быть обработано, находится в $_REQUEST['action']
. Этого достаточно, чтобы определить обработчик, который должен быть запущен. Если имена функций-обработчиков построены в виде "myplugin_ajax_{$action}"
, то регистрация нужного хука может выглядеть так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
if (defined('DOING_AJAX') && DOING_AJAX && !empty($_REQUEST['action'])) // выполняется AJAX-запрос add_action('plugins_loaded', 'myplugin_init_ajax'); function myplugin_init_ajax () { // определить обработчик по идентификатору действия // если подходящего обработчика нет, значит запрос принадлежит другому плагину // и его следует игнорировать; $action = $_REQUEST['action']; $fn = 'myplugin_ajax_' . $action; // определить имя функции if (!is_callable($fn)) // и проверить её существование return; // нет такого обработчика - проигнорировать запрос // зарегистрировать хук в соответствии с авторизованностью посетителя: $hook = is_user_logged_in() ? 'wp_ajax_' : 'wp_ajax_nopriv_'; add_action($hook . $action, $fn); } |
После этого для добавления нового обработчика AJAX потребуется просто определить функцию с соответствующим именем.
Замечание 1: код из myplugin_init_ajax
можно поместить в тело if
‘а в строке 1, если этот if
расположен после определения всех функций 'myplugin_ajax_*'
.
Замечание 2: этот фрагмент может создать впечатление, что регистрация хука 'wp_ajax_*'
в данном случае только усложняет дело и что будет гораздо проще сразу же запустить найденный обработчик $fn
и завершить выполнение WordPress. Но поступать так не следует по ряду причин:
- в момент
'plugins_loaded'
WordPress ещё не загружен и не готов к полноценному использованию (т.е. к выполнению функцииmyplugin_ajax_*
); - в процессе загрузки WordPress выполняет ряд важных задач, не связанных непосредственно с обработкой запроса (напр., инициация действий
wp_cron
происходит по хуку'init'
); - сторонние плагины могут устанавливать собственные обработчики AJAX’ов, вешая их на те же хуки, но с меньшим приоритетом.
Замечание 3: подобно остальным глобальным именам, идентификатор действия (параметр запроса action
) всегда должен иметь префикс, гарантирующий его уникальность — 'myplugin_action'
, например. Поэтому для плагинов или тем, написанных в функциональном стиле, имена функций-обработчиков имеют вид 'myplugin_ajax_myplugin_action'
. В случае ООП-подхода роль префикса функций играет $this
или имя класса плагина/темы, а префикс действия входит в название метода — array($this, '_ajax_myplugin_action')
или array(__CLASS__, '_ajax_myplugin_action')
, если метод статический.
Пренебрегать префиксами нельзя: не должно возникать возможности сформировать запрос, запускающий произвольную или не предназначенную для этого функцию в качестве своего обработчика.
Замечание 4: приведённый вариант применим только для запросов, допускающих работу с неавторизованными пользователями. Если же часть запросов требует авторизации, следует предусмотреть их разделение — чтобы в принципе исключить возможность неавторизованным посетителям совершать привилегированные действия.
Если, например, давать обработчикам привилегированных действий имена вида 'myplugin_ajax_priv_*'
, то предыдущий фрагмент изменится так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
if (defined('DOING_AJAX') && DOING_AJAX && !empty($_REQUEST['action'])) add_action('plugins_loaded', 'myplugin_init_ajax'); function myplugin_init_ajax () { $action = $_REQUEST['action']; $fn = 'myplugin_ajax_' . $action; if (is_callable($fn)) { // обычное действие - обработать для любого посетителя $hook = is_user_logged_in() ? 'wp_ajax_' : 'wp_ajax_nopriv_'; add_action($hook . $action, $fn); return; } // возможно, это привилегированное действие if (!is_user_logged_in()) return; // пользователь не авторизован $fn = 'myplugin_ajax_priv_' . $action; if (!is_callable($fn)) return; // обработчик не найден add_action('wp_ajax_' . $action, $fn); } |