Вопрос или проблема
Мне наконец-то удалось обновить старый сайт WP 3.3.1 до WP 4.1 с небольшими проблемами, но одно неожиданное изменение, похоже, произошло в отношении загрузки файлов.
В версии WP 3.3.1 плагина я включил загрузку для пользовательской роли через ‘read’ и ‘upload_files’.
ПРИМЕЧАНИЕ: Это касается контента, который НЕ основывается на записях. Это просто редактор, который я хочу использовать для каких-то пользовательских таблиц БД. Вызов wp_editor имеет контент, явно установленный в ”. Я использую метод буферизации, чтобы переместить редактор, о чем подробно написано здесь: https://wordpress.stackexchange.com/a/66345
// захватываем редактор для последующего использования...
// ХИТРОСТЬ: https://wordpress.stackexchange.com/a/66345
ob_start();
wp_editor(
'',
'xyz-note-editor',
array(
'textarea_rows' => '10',
)
);
$editor = ob_get_clean();
// ...
$edit_form_template = str_replace('{{NotesEditor}}', $editor, $edit_form_template);
После обновления до WP 4.1 все работает для Редакторов и Администраторов.
Это не работает для Авторов, Участников и моей пользовательской роли, с ошибкой: “У вас нет разрешения прикреплять файлы к этой записи.”
(“Запись” кажется независимым экземпляром пользовательского типа записи, к которому загружаемые медиафайлы присваиваются, когда успешно загружаются как Редактор или Администратор.)
Не зная, как все это решить, или не найдя какой-то плагин (например, Members от Джастина Тадлока, рекомендованный в другом месте на StackExchange), я застрял.
Почему Редакторы могут обойти ограничения на загрузку в этом случае?
Я пытался назначить разрешения редактирования/публикации/чтения для Редакторов (и ниже) для пользовательской роли без успеха – основываясь на http://codex.wordpress.org/Roles_and_Capabilities.
add_role(
XxYyConfig::USER_ROLE(),
'Управляющий пользовательскими данными',
array(
'read' => true,
// ДОБАВЛЕНО: чтобы исправить изменения в том, как работает "Добавить медиа" в WordPress - касательно ошибки "У вас нет разрешения прикреплять файлы к этой записи."
// ПРИМЕЧАНИЕ: Управляющие пользовательскими данными, Участники и Авторы НЕ МОГУТ добавлять медиафайлы -- НО Редакторы/Администраторы могут. Пытается добавить к записи {custom_post_type} (по неизвестным причинам). Контент для редактора установлен в ''...
'edit_files' => true,
'edit_others_pages' => true,
'edit_others_posts' => true,
'edit_pages' => true,
'edit_posts' => true,
'edit_private_pages' => true,
'edit_private_posts' => true,
'edit_published_pages' => true,
'edit_published_posts' => true,
'publish_pages' => true,
'publish_posts' => true,
'read_private_pages' => true,
'read_private_posts' => true,
// ДОБАВЛЕНО: КОНЕЦ
'upload_files' => true,
)
);
Я знаю, что в этом вопросе немного запутался, но это кажется несовместимым (даже если что-то из давно прошедшего времени было “исправлено”).
map_meta_cap похоже, может применяться здесь, но отсутствие пользовательского типа записи заставляет меня думать, что это неправильное решение.
В идеале, я хотел бы знать, почему пользовательский тип записи помечается в этом процессе, но я держусь за то, что необходимо настроить для обработки разрешений/возможностей, чтобы разрешить загрузку через WYSIWYG редактор?
ПРАВКА: Поскольку моя роль устанавливается во время активации плагина, я убедился в том, чтобы отключить и снова активировать плагин, чтобы убедиться, что там не происходит ничего необычного.
Нашел основную проблему! Хотя контекст другой, чем тот, который вы описали, коренная причина, вероятно, та же самая. Я пытался позволить пользователям настроить персональную страницу и загрузить изображение для отображения там. Я продолжал получать досадное сообщение “У вас нет разрешения прикреплять файлы к этой записи”.
Сообщение само по себе приходит из wp_ajax_upload_attachment() в /wp-admin/includes/ajax-actions.php, даже если пользователь работает на главной странице, а не на панели управления, потому что плагин, который я использую (Advanced Custom Fields — рекомендую!) использует библиотечные функции WordPress (к счастью, он ограничивает доступ к библиотеке). Ошибка возникает, если current_user_can() не дает разрешение.
(Вы можете подтвердить, что сообщение находится в этой функции, изменив сообщение на что-то другое.)
В свою очередь, current_user_can() вызывает $current_user->has_cap(), чтобы получить текущие возможности.
has_cap() предлагает хороший фильтр, который мы можем использовать, но он все равно продолжал давать сбой. Причина заключалась в том, что он сначала вызывает map_meta_cap(), которая формирует большой массив возможных возможностей для этого экземпляра. Если хотя бы одна из этих возможных возможностей оставлена ‘пустой’, тогда has_cap возвращает false.
Это означает, что любой пользовательский фильтр, который определен для предоставления разрешения, должен пройти по массиву и установить все на true.
Мне кажется, что лучшее постоянное решение заключалось бы в том, чтобы WordPress игнорировал любые возможности, которые не были явно установлены для разрешения или запрета.
На данный момент вот пример функции фильтра, которая работает для меня:
// разрешить пользователям добавлять изображения на свою домашнюю страницу
function allow_own_attachments( $user_caps, $req_caps, $args, $UserObj ) {
if ( empty($args[2]) ) {
return $user_caps; // нечего проверять
}
$post = get_post( $args[2] ); // post_id был передан здесь
if ( $post->post_author == $UserObj->ID ) { // это моя запись
foreach ( (array) $req_caps as $cap ) {
if ( empty( $user_caps[ $cap ] ) )
$user_caps[ $cap ] = true;
}
}
$user_caps['edit_post'] = true; // протестировано wp_ajax_upload_attachment()
return $user_caps;
}
add_filter( 'user_has_cap', 'allow_own_attachments', 10, 4 );
Код из предыдущего ответа сработал для меня, но я получал это уведомление в режиме отладки: “Попытка получить свойство ‘post_author’ у ненастоящего объекта”. Я добавил проверку, чтобы убедиться, что $post возвращает объект (if (is_object($post))). Это устраняет уведомление.
function allow_own_attachments( $user_caps, $req_caps, $args, $UserObj ) {
if ( empty($args[2]) ) {
return $user_caps; // нечего проверять
}
$post = get_post( $args[2] ); // post_id был передан здесь
if (is_object($post)){ //проверка, является ли $post объектом. Если это не так, код выдает это уведомление: Попытка получить свойство 'post_author' у ненастоящего объекта
if ( $post->post_author == $UserObj->ID ) { // это моя запись
foreach ( (array) $req_caps as $cap ) {
if ( empty( $user_caps[ $cap ] ) )
$user_caps[ $cap ] = true;
}
}
}
$user_caps['edit_post'] = true; // протестировано wp_ajax_upload_attachment()
return $user_caps;
}
add_filter( 'user_has_cap', 'allow_own_attachments', 10, 4 );
Ответ или решение
Добавление возможностей загрузки медиа для настраиваемой роли вне постов в WordPress
Обновление сайта на WordPress с версии 3.3.1 до 4.1 может сопрягаться с рядом особенностей, касающихся управления правами доступа и разрешениями для загрузки медиафайлов различным ролям пользователей. Ваша ситуация характеризуется проблемой доступа с не настраиваемыми ролями (например, Автор, Участник и ваша настраиваемая роль), которые получают сообщение об ошибке: "У вас нет разрешения на прикрепление файлов к этому сообщению". Давайте подробнее рассмотрим, как исправить это и добавить необходимые возможности загрузки.
Анализ проблемы
После обновления возникает проблема с разрешениями на загрузку медиафайлов, которая связана с тем, как WordPress управляет правами доступа. В предыдущих версиях системы доступ к загрузке файлов мог быть более гибким, но с текущими версиями и изменениями в политике безопасности, доступ может быть ограничен, если у пользователя не есть необходимые права.
Причина ограничения
Ваша проблема заключается в том, что функция current_user_can()
не может подтвердить разрешение, так как роль пользователя не имеет соответствующих возможностей. В частности, в случае вашей настраиваемой роли необходимо добавить более специфические права, относящиеся к возможностям управления медиафайлами.
Шаги для решения проблемы
1. Определение необходимых прав
Чтобы разрешить вашей настраиваемой роли загружать медиафайлы, вам необходимо добавить соответствующие возможности через фильтры, как указано ниже:
function custom_role_permissions() {
$role = get_role('custom_role'); // Замените 'custom_role' на ваше название роли
if ($role) {
$role->add_cap('upload_files'); // Позволяет загружать файлы
$role->add_cap('edit_posts'); // Позволяет редактировать посты
$role->add_cap('edit_others_posts'); // Позволяет редактировать посты других пользователей
$role->add_cap('edit_private_posts'); // Позволяет редактировать приватные посты
}
}
add_action('admin_init', 'custom_role_permissions');
2. Использование фильтра user_has_cap
Для более тонкой настройки доступов, вы можете использовать фильтр user_has_cap
. Это позволит вам контролировать и разрешать загрузку медиафайлов на основе определенных условий:
function allow_own_attachments($user_caps, $req_caps, $args, $user_obj) {
if (empty($args[2])) {
return $user_caps; // Нечего проверять
}
$post = get_post($args[2]); // Получаем пост по ID
if (is_object($post) && $post->post_author == $user_obj->ID) {
foreach ((array) $req_caps as $cap) {
// Обеспечиваем доступ к необходимым возможностям, если они не были установлены
if (empty($user_caps[$cap])) {
$user_caps[$cap] = true;
}
}
}
return $user_caps;
}
add_filter('user_has_cap', 'allow_own_attachments', 10, 4);
Заключение
С помощью указанных выше шагов вы можете эффективно разрешить вашей настраиваемой роли загружать медиафайлы в WordPress 4.1 и выше. Обратите внимание, что при использовании среды, где настраиваемые роли и возможности могут изменяться на лету, важно тщательно тестировать все изменения в безопасности и производительности.
Также стоит отметить, что в WordPress политика безопасности может меняться с выходом новых обновлений, поэтому рекомендую всегда следить за официальной документацией и актуальными изменениями в API.
Эти изменения не только обеспечат функциональность, необходимую для вашего сценария, но и проложат основу для более гибкого подхода к управлению правами в будущем.