Как лучше всего обрабатывать действия на страницах пользовательского плагина?
Я постоянно сталкиваюсь с одной и той же проблемой, поэтому хотел бы узнать, есть ли какие-то идеи или опыт решения...
Я создал плагин, который использует свою собственную страницу администратора. Это необходимо. Теперь, когда я разобрался с WP_List_Table(), должен сказать, что это здорово... но...
Пользовательские страницы плагина всегда загружаются как admin.php?page=...
, если только я не хочу загружать их напрямую из директории плагина, чего я не хочу. Теперь, если я выполняю 'action' с этой страницы, мне нужно как-то обработать это и затем перенаправить обратно на страницу без параметра action. Неважно, использую ли я GET или POST.
На всех своих внутренних страницах WP делает это на той же странице - проверяет, есть ли действие, если да, обрабатывает его и затем перенаправляет на себя без действия. Это возможно, потому что на этих страницах admin-header
еще не загружен.
Если же вы попытаетесь сделать это на своей странице, половина интерфейса администратора уже отправлена в браузер, поэтому перенаправление уже невозможно. Очевидно, решение заключается в том, чтобы отправлять POST/GET напрямую на другую страницу, загрузить фреймворк WP там, выполнить обработку и затем перенаправить обратно на исходную страницу... но... это немного раздражает, потому что... моя исходная страница загружается через callback, поэтому она выполняется внутри метода моего класса. Это прекрасно.
Если я загружаю отдельную страницу, мне нужно вручную подключать wp-load.php
и находиться вне моего класса, что раздражает, и в моем конкретном случае особенно беспокоит, потому что я создаю экземпляр моего класса плагина анонимно, чтобы никто не мог получить к нему доступ извне.
Итак, после этой длинной истории... кто-нибудь нашел хорошее решение для загрузки другой страницы через callback без предварительной настройки всего интерфейса администратора вокруг неё?
(Я знаю об обходном пути... я могу подключить функцию к load-....
, которая проверяет параметр action и выполняет обработку и перенаправление. Но мне интересно, есть ли способ лучше.)
Спасибо.

Как правило, следует использовать POST-запрос для большинства действий, чтобы убедиться, что они не выполняются случайно. Также хорошей практикой является перенаправление на обычную страницу после POST-запроса, чтобы предотвратить повторное выполнение при обновлении страницы пользователем.
Таким образом, процесс выглядит следующим образом:
- Страница вашего плагина с POST-формой, которая отправляет данные на
- Страницу, обрабатывающую запрос, которая перенаправляет на
- Страницу вашего плагина, которая отображает результат выполнения действия
Промежуточная страница не обязательно должна быть страницей вашего плагина. Это означает, что вы можете использовать "универсальный обработчик POST-запросов", который был добавлен три года назад, хук 'admin_action_' . $_REQUEST['action']
в admin.php
.
Примером использования является плагин Akismet. Если вы хотите использовать его надежно, необходимо отправлять данные напрямую в admin.php
, а не на другую страницу, которая включает в себя admin.php
.
Вот очень простой пример того, как это можно использовать:
add_action( 'admin_action_wpse10500', 'wpse10500_admin_action' );
function wpse10500_admin_action()
{
// Здесь выполняются необходимые действия
wp_redirect( $_SERVER['HTTP_REFERER'] );
exit();
}
add_action( 'admin_menu', 'wpse10500_admin_menu' );
function wpse10500_admin_menu()
{
add_management_page( 'WPSE 10500 Test page', 'WPSE 10500 Test page', 'administrator', 'wpse10500', 'wpse10500_do_page' );
}
function wpse10500_do_page()
{
?>
<form method="POST" action="<?php echo admin_url( 'admin.php' ); ?>">
<input type="hidden" name="action" value="wpse10500" />
<input type="submit" value="Сделать это!" />
</form>
<?php
}

Привет, я еще раз взгляну на код, я явно этого не заметил, но просто для подтверждения... ты говоришь, что если вызвать admin.php напрямую без параметра page, он пропускает загрузку всех страниц и просто выполняет некоторую инициализацию и запускает хук? Это было бы круто... вроде как (я все еще не понимаю, почему они не поместили хук перед загрузкой страницы).

@wyrfel: Да, вызов admin.php
напрямую — это "трюк", которому меня научил исходный код Akismet. Ты прав, когда отображаешь форму и хочешь показать ее снова в случае ошибок: тогда было бы удобно, если целью является страница твоего плагина, но хук находится где-то в начале (так ты мог бы перенаправить при успехе или снова отобразить форму с сообщениями об ошибках, если что-то пошло не так). Может, предложить это в тикете Trac?

Я создам тикет. В качестве временного решения я обнаружил, что работает хук 'load-<pagehook>'
... он вызывается перед загрузкой страницы... но концепция admin_action_...
кажется гораздо приятнее и конкретнее. Также, замечу, что сообщения об ошибках все еще проблематичны, если делаешь POST-запросы и не хочешь повторной отправки при перезагрузке, но это уже другая тема.

@wyrfel: Почему сообщения об ошибках всё ещё могут быть проблемой? Если есть сообщение об ошибке, оставайтесь на странице и снова отобразите форму с сообщениями (конечно, обновление страницы здесь не имеет особого смысла — но это и не навредит, так как ошибки всё равно останутся, и никакое действие не будет выполнено). Если ошибок нет, выполните действие и перенаправьте на "безопасную" страницу обзора. Это сработает — если хук admin_action_
будет перемещён перед загрузчиком страницы плагина.

Я расширил эту публикацию и включил возможность вызова этих же методов 'admin-action' из URL 'post-row-action'. Решение использует Jquery для сопоставления GET URL с POST запросом FORM, который рассматривается в этом ответе. http://wordpress.stackexchange.com/questions/82761/how-can-i-link-post-row-actions-with-a-custom-action-function

Я подошел к этому немного иначе, просто добавив noheader=true к URL действия на странице, где пользователь отправляет форму.
Мой обработчик затем выполняет действие (например, добавление, обновление или удаление) и завершается вызовом wp_redirect() для перехода к следующему действию (например, страница добавления -> страница редактирования, страница удаления -> страница списка, страница редактирования -> страница редактирования). Я также передаю сообщение в URL, чтобы можно было отобразить статус, например "успешно обновлено" или "ошибка".
Такой подход позволяет сохранить все действия: список, добавление, редактирование, удаление, массовое удаление и т.д. в одном классе и с одним административным slug'ом, что делает код простым в поддержке и понимании.
