Как сделать так, чтобы на странице медиа/загрузки работали настраиваемые массовые действия?

Вопрос или проблема

Я адаптирую сценарий, который нашел в интернете, чтобы добавить пользовательские действия массового воздействия на экран со списком записей. В нем есть такая строка:

add_action('load-edit.php', 'custom_bulk_action');

Я пытаюсь адаптировать это для медиатеки. Я вижу, что вместо edit.php я должен использовать upload.php, что наводит меня на мысль, что нужно найти медианный аналог для load-edit.php. Звучит просто, но я даже не могу найти load-edit.php в своей установке WP, чтобы посмотреть, не является ли она тем, что я ищу. Я нашел несколько упоминаний в интернете о load-*.php (например, Custom bulk_action), но ничего, что могло бы сказать мне, какие значения может принимать *.

(Я пробовал load-upload.php, но это не сработало — хотя это всегда может быть что-то другое в моем коде, что мешает работе.)

Итак, мои вопросы два:

  1. Какой медианный аналог load-edit.php?
  2. Где находится load-edit.php (и другие файлы load-*.php), или какой код обрабатывает эти запросы файлов?

Первый вопрос — это мой настоящий вопрос, но второй уже стал раздражать меня.

Могут ли какие-нибудь из вас, эксперты, дать мне какую-нибудь подсказку? Я был бы очень признателен.

ИЗМЕНЕНИЕ

Под “не работает” я подразумевал не то, что он выдает ошибку, а что он не выполнял то, что должен был (изменение атрибута медиа).

Код, который я адаптирую, можно скачать внизу поста “Добавить пользовательское массовое действие WordPress” Джастина Стерна из Fox Run Software. Вернувшись к проверке каждого шага кода, я заставил адаптированную версию работать, но только если я закомментировал условие и проверку безопасности (оба помечены звездочкой ниже). Какие медианные аналоги я должен использовать, чтобы заменить их?

 add_action('load-upload.php', array(&$this, 'custom_bulk_action'));

function custom_bulk_action() {

//  ***if($post_type == 'attachment') {  ЗАМЕНИТЕ НА:
    if ( !isset( $_REQUEST['detached'] ) ) {

    // получить действие
    $wp_list_table = _get_list_table('WP_Media_List_Table');  
    $action = $wp_list_table->current_action();

    echo "\naction = $action\n</pre>";

    $allowed_actions = array("export");
    if(!in_array($action, $allowed_actions)) return;

    // проверка безопасности
//  ***check_admin_referer('bulk-posts'); ЗАМЕНИТЕ НА:
    check_admin_referer('bulk-media'); 

    // убедитесь, что id переданы. В зависимости от типа ресурса это может быть 'media' или 'ids'
    if(isset($_REQUEST['media'])) {
      $post_ids = array_map('intval', $_REQUEST['media']);
    }

    if(empty($post_ids)) return;

    // это основано на wp-admin/edit.php
    $sendback = remove_query_arg( array('exported', 'untrashed', 'deleted', 'ids'), wp_get_referer() );
    if ( ! $sendback )
      $sendback = admin_url( "upload.php?post_type=$post_type" );

    $pagenum = $wp_list_table->get_pagenum();
    $sendback = add_query_arg( 'paged', $pagenum, $sendback );

    switch($action) {
      case 'export':

        // если мы настроили разрешения/возможности пользователя, код мог бы выглядеть так:
        //if ( !current_user_can($post_type_object->cap->export_post, $post_id) )
        //  wp_die( __('Вы не имеете права экспортировать этот пост.') );

        $exported = 0;
        foreach( $post_ids as $post_id ) {

          if ( !$this->perform_export($post_id) )
            wp_die( __('Ошибка при экспорте поста.') );
          $exported++;
        }

        $sendback = add_query_arg( array('exported' => $exported, 'ids' => join(',', $post_ids) ), $sendback );
      break;

      default: return;
    }

    $sendback = remove_query_arg( array('action', 'action2', 'tags_input', 'post_author', 'comment_status', 'ping_status', '_status',  'post', 'bulk_edit', 'post_view'), $sendback );

    wp_redirect($sendback);
    exit();
  }
}

Я ценю вашу помощь.

ИЗМЕНЕНИЕ 2

Я изменил код выше, чтобы отразить информацию из принятого ответа. Большое спасибо Ralf912!

Если хотите использовать свой код, попробуйте это:

Если вы хотите проверить, являются ли медиа вложениями, вы можете попробовать использовать $_REQUEST['detached']

add_action( 'load-upload.php', 'export_media_test' );

function export_media_test() {

    if ( ! isset( $_REQUEST['action'] ) )
        return;

    echo 'Экспорт медиа';

    if ( isset( $_REQUEST['detached'] ) ) {
        die( 'Нет вложений' );
    } else {
        die( 'Вложения' );
    }

    exit();
}

Вы не можете проверить nonce, который не был установлен. Nonce bulk-posts установлен в edit.php, и это список постов. В upload.php установлен nonce bulk-media. Так что используйте check_admin_referer('bulk-media');

В WordPress отсутствуют некоторые apply_filters и do_action в upload.php. Поэтому вам придется сделать некоторые хитрости.

Сначала нам нужно добавить экспортное действие в массовые действия. WP_Media_List_Table — это объект, и эта задача очень проста. Мы можем просто расширить класс и переопределить/расширить необходимые методы:

require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
require_once( ABSPATH . 'wp-admin/includes/class-wp-media-list-table.php' );

class Extended_Media_List_Table extends WP_Media_List_Table
{

    /**
     * Добавить экспортное массовое действие
     * @return array
     */
    public function get_bulk_actions() {

        // получить оригинальные массовые действия    
        $actions = parent::get_bulk_actions();

        // добавить наши собственные действия
        $actions['export'] = __( 'Экспорт' );

        // вернуть действия    
        return $actions;
    }

    /**
     * Возвращает текущее действие
     * @return string
     */
    public function current_action() {

        // проверить, установлены ли наши действия и обработать их
        if ( isset( $_REQUEST['action'] ) && 'export' === $_REQUEST['action'] ) {
            return 'export_media';
        }

        // позволить родительскому классу обрабатывать все другие действия
        parent::current_action();

    }

}

Первый метод просто добавляет действие экспорта. Второй метод возвращает export_media, если выбрано действие экспорта.

Теперь становится сложно. В upload.php нет apply_filter, и мы не можем изменить класс, который upload.php использует для отображения медиа. Второй момент — нет add_action, чтобы подключиться, чтобы добавить другое действие, если массовое действие выбрано.

Скопируйте upload.php и переименуйте его (например, extended_upload.php). Отредактируйте свой новый файл и удалите require_once( './admin.php' );. Позже мы подключим load-upload.php, этот хук вызывается в admin.php. Если оставить эту строку, это приведет к бесконечному циклу.

Следующий шаг — вставить обработчик для вашего действия экспорта. Как вы можете видеть в вышеуказанном расширенном классе, ::current_action() возвращает строку, которая будет скопирована в $doaction. В extended_upload.php вы найдете оператор switch, который обрабатывает действие. Добавьте случай, чтобы обработать действие экспорта:

case 'export_media':
    // обрабатывать только вложения
    // $wp_list_table->detached = false ==> вложения
    // $wp_list_table->detached = true ==> не связанные файлы
    if ( true == $wp_list_table->detached )
        return;

    // $_REQUEST['media'] содержит массив с post_ids
    if ( ! empty( $_REQUEST['media'] ) ) {
        foreach ( $_REQUEST['media'] as $postID ) {
            export_image( $postID );
        }
    }
    break;

Помните! Все действия будут обрабатываться внутри AJAX-запроса. Поэтому никакой вывод (echo, print, printf и т. д.) не будет отображаться!!

Последний шаг — подключиться к load-upload.php и сказать WordPress использовать наш новый extended_upload.php вместо оригинального upload.php:

add_action( 'load-upload.php', 'add_bulk_action_export_to_list_media' );
function add_bulk_action_export_to_list_media() {
    require_once 'extended_upload.php';
    // НЕ ВОЗВРАЩАЙТЕ ЗДЕСЬ, ИНАЧЕ ОРИГИНАЛ upload.php ТАКЖЕ БУДЕТ ЗАГРУЖЕН!
}

Это очень сложное и хитроумное решение. Каждое обновление WordPress может это разрушить, и вам придется отслеживать все изменения в upload.php. Но это единственный способ получить некоторые значения (например, $wp_list_table->detached, который скажет вам, является ли это вложением или нет).

Возможно, неплохая идея написать тикет для фильтра $wp_list_table и добавить действие в оператор switch.

$wp_list_table = apply_filters( 'upload_list_table', _get_list_table('WP_Media_List_Table') );

switch ( $doaction ) {
[...]

default:
  global $doaction;
  do_action( 'upload_list_table_actions' );
  break;
}

Эти два изменения значительно упростили бы добавление массовых действий и их обработку.

Для тех, кто наткнется на это (через 10 лет) … пожалуйста, сделайте это вместо:

add_filter('bulk_actions-upload', 'filter_bulk_actions_upload', 10, 1);
add_filter('handle_bulk_actions-upload', 'filter_handle_bulk_actions_upload', 10, 3);

/**
 * Добавить массовое действие в upload.php (Медиатека)
 *
 * @param array $actions
 * @return array
 */
function filter_bulk_actions_upload($actions): array
{
    $actions['my-bulk-action'] = __('Мое массовое действие', 'text-domain');
    return $actions;
}

/**
 * Обработать массовое действие в upload.php (Медиатека)
 *
 * @param string $location
 * @param string $doaction
 * @param array $post_ids
 * @return string
 */
function filter_handle_bulk_actions_upload($location, $doaction, $post_ids): string
{
    // ничего не обрабатывать - это не наше действие
    if ($doaction !== 'my-bulk-action') {
        return $location;
    }

    // обрабатывать массовое действие для post_ids
    foreach ($post_ids as $post_id) {
        do_something($post_id);
    }

    return $location;
}

Конец связи 🙂

Ответ или решение

Для реализации пользовательских массовых действий на странице медиафайлов в WordPress вам будет нужно внести некоторые изменения в код. Вы можете использовать хуки и фильтры, которые уже содержатся в WordPress, для добавления и обработки этих действий.

1. Что такое аналог load-edit.php для медиафайлов?

Для страницы загрузки (медиафайлов) в WordPress, вам не нужно искать load-upload.php. Вместо этого, вы можете использовать фильтры для добавления действий и их обработки. Основные хуки, которые вам понадобятся, это bulk_actions-upload для добавления ваших действий и handle_bulk_actions-upload для обработки этих действий.

2. Как добавлять и обрабатывать пользовательские массовые действия?

Вот пошаговое руководство, как это сделать:

  1. Добавьте ваши действия в выпадающий список массовых действий:
add_filter('bulk_actions-upload', 'filter_bulk_actions_upload', 10, 1);
function filter_bulk_actions_upload($actions) {
    $actions['my-bulk-action'] = __('Мое массовое действие', 'text-domain');
    return $actions;
}
  1. Обработайте ваше массовое действие:
add_filter('handle_bulk_actions-upload', 'filter_handle_bulk_actions_upload', 10, 3);
function filter_handle_bulk_actions_upload($location, $doaction, $post_ids) {
    // Проверяем, нужно ли обрабатывать это действие
    if ($doaction !== 'my-bulk-action') {
        return $location;
    }

    // Обработка массового действия для каждого идентификатора медиафайла
    foreach ($post_ids as $post_id) {
        // Замените этот вызов на ваши действия с медиафайлом
        do_something($post_id);
    }

    // Возвращаем пользователя на ту же страницу
    $location = add_query_arg('bulk_action_completed', 1, $location);
    return $location;
}

Примечания

  • Не забудьте заменить do_something($post_id); на фактическую логику, которую вы хотите реализовать для каждого медиафайла.
  • Вы можете создать уведомление об успешном выполнении действия, добавив соответствующие параметры в URL.

Вместо load-edit.php и upload.php

Вы не сможете найти load-upload.php в документации WordPress, так как это не файл, доступный для редактирования. Вместо этого эта функция вызывается динамически в зависимости от состояния контекста админки.

Заключение

Такой подход позволит вам добавлять пользовательские массовые действия на страницу медиафайлов, не изменяя ядро WordPress и сохраняя возможность обновления. Это также обеспечивает простую и понятную реализацию, используя стандартные хуки и фильтры WordPress. Если вы хотите добавить пользовательские действия в будущем, вы сможете легко расширить данный код, следуя описанным выше шагам.

Оцените материал
Добавить комментарий

Капча загружается...