Разрешение пользователю редактировать только определенные страницы

16 июн. 2015 г., 17:15:25
Просмотры: 26.3K
Голосов: 17

Я хотел бы разрешить определенному пользователю редактировать только одну страницу и её подстраницы. Как это можно реализовать? Я пробовал старый плагин Role Scoper, но похоже, что в нем много проблем и ошибок.

1
Комментарии

Я удалил ваш запрос о рекомендации плагина, так как это делает вопрос не по теме. Да, такое возможно с помощью плагина, но когда я вижу попытки сделать вещи, требующие подобного вмешательства в базовую функциональность, не могу не подумать, что вы идёте неверным путём. Не могли бы вы подробнее описать проект?

s_ha_dum s_ha_dum
16 июн. 2015 г. 17:44:12
Все ответы на вопрос 4
2
17

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

Есть несколько способов сделать это. Это может быть пользовательская метаданная, какое-то значение конфигурации... Для целей данного ответа я предположу, что существует функция вроде этой:

function wpse_user_can_edit( $user_id, $page_id ) {

   $page = get_post( $page_id );

   // найдем самую верхнюю страницу в иерархии
   while( $page && (int) $page->parent ) {
     $page = get_post( $page->parent );
   }

   if ( ! $page ) {
     return false;
   }

   // теперь $page - это верхняя страница в иерархии
   // как определить, может ли пользователь редактировать её - зависит от вашей реализации...

}

Теперь, когда у нас есть способ определить, может ли пользователь редактировать страницу, нам нужно сказать WordPress использовать эту функцию для проверки прав пользователя на редактирование страницы.

Это можно сделать с помощью фильтра 'map_meta_cap'.

Например:

add_filter( 'map_meta_cap', function ( $caps, $cap, $user_id, $args ) {

    $to_filter = [ 'edit_post', 'delete_post', 'edit_page', 'delete_page' ];

    // Если проверяемая способность нас не интересует, просто возвращаем текущее значение
    if ( ! in_array( $cap, $to_filter, true ) ) {
        return $caps;
    }

    // Первый элемент в массиве $args должен быть ID страницы
    if ( ! $args || empty( $args[0] ) || ! wpse_user_can_edit( $user_id, $args[0] ) ) {
        // Пользователю не разрешено, сообщим об этом WordPress
        return [ 'do_not_allow' ];
    }
    // В противном случае просто возвращаем текущее значение
    return $caps;

}, 10, 4 );

На этом этапе нам осталось только найти способ связать пользователя с одной или несколькими страницами.

В зависимости от конкретного случая могут быть разные решения.

Гибким решением может быть добавление выпадающего списка "корневых" страниц (см. wp_dropdown_pages) на экране редактирования пользователя в админке и сохранение выбранных страниц как пользовательских метаданных.

Мы можем использовать 'edit_user_profile' для добавления поля выбора страниц и 'edit_user_profile_update' для сохранения выбранного значения как метаданных пользователя.

Уверен, что на этом сайте достаточно руководств о том, как сделать это подробно.

Когда страницы сохранены как метаданные пользователя, функцию wpse_user_can_edit() из предыдущего примера можно завершить, проверив, есть ли ID страницы среди значений метаданных пользователя.

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

14 мар. 2017 г. 12:07:19
Комментарии

Это намного лучше, чем мой ответ. Зачем ограничивать ссылки на редактирование, если можно просто изменить права пользователя и позволить WordPress разобраться с остальным?

ricotheque ricotheque
19 мар. 2017 г. 19:04:19

перед словом "user" следует использовать артикль "a", а не "an", так как долгий звук "u" звучит как "yu", который начинается с согласной.

Philip Philip
10 дек. 2019 г. 21:16:39
2

Для реализации этой функции требуется небольшое количество кода, даже если вы используете PHP-класс, чтобы избежать глобальных переменных. Я также не хотел скрывать запрещенные страницы для пользователя в админке. Что, если они добавили контент, который уже есть на сайте?

$user_edit_limit = new NS_User_Edit_Limit(
    15,       // ID пользователя, которого мы хотим ограничить
    [2, 17]   // Массив ID родительских страниц, которые пользователь может редактировать
                 (также принимает ID подстраниц)
);

class NS_User_Edit_Limit {

    /**
     * Хранит ID пользователя, которого мы хотим ограничить, и
     * записи, которые разрешено редактировать.
     */
    private $user_id = 0;
    private $allowed = array();

    public function __construct( $user_id, $allowed ) {

        // Сохраняем ID пользователя, которого ограничиваем
        $this->user_id = $user_id;

        // Расширяем список разрешенных страниц, включая подстраницы
        $all_pages = new WP_Query( array(
            'post_type' => 'page',
            'posts_per_page' => -1,
        ) );            
        foreach ( $allowed as $page ) {
            $this->allowed[] = $page;
            $sub_pages = get_page_children( $page, $all_pages );
            foreach ( $sub_pages as $sub_page ) {
                $this->allowed[] = $sub_page->ID;
            }
        }

        // Для запрещенного пользователя...
        // Удаляем ссылку редактирования на фронтенде, если нужно
        add_filter( 'get_edit_post_link', array( $this, 'remove_edit_link' ), 10, 3 );
        add_action( 'admin_bar_menu', array( $this, 'remove_wp_admin_edit_link' ), 10, 1 );
        // Удаляем ссылку редактирования в админке, если нужно
        add_action( 'page_row_actions', array( $this, 'remove_page_list_edit_link' ), 10, 2 );
    }

    /**
     * Вспомогательные функции для проверки, является ли текущий пользователь
     * тем, кого мы ограничиваем, и проверяет, разрешено ли редактировать
     * конкретную запись.
     */
    private function is_user_limited() {
        $current_user = wp_get_current_user();
        return ( $current_user->ID == $this->user_id );
    }
    private function is_page_allowed( $post_id ) {
        return in_array( $post_id, $this->allowed );
    }

    /**
     * Удаляет ссылку редактирования на фронтенде, если нужно.
     */
    public function remove_edit_link( $link, $post_id, $test ) {
        /**
         * Если:
         * - Запрещенный пользователь вошел в систему
         * - Страница, для которой создается ссылка редактирования, не в списке разрешенных
         * ...возвращаем пустую $link. Это также приводит к тому, что edit_post_link() ничего не выводит.
         *
         * В противном случае возвращаем ссылку как обычно.
         */
        if ( $this->is_user_limited() && !$this->is_page_allowed( $post_id ) ) {
            return '';
        }
        return $link;
    }

    /**
     * Удаляет ссылку редактирования из панели администратора WordPress
     */
    public function remove_wp_admin_edit_link( $wp_admin_bar ) {
        /**
         *  Если:
         *  - Мы на странице (не в архиве)
         *  - Запрещенный пользователь вошел в систему
         *  - Страница не в списке разрешенных
         *  ...удаляем ссылку редактирования из панели администратора
         */
        if ( 
            is_page() &&
            $this->is_user_limited() &&
            !$this->is_page_allowed( get_post()->ID )
        ) {
            $wp_admin_bar->remove_node( 'edit' );
        }
    }

    /**
     * Удаляет ссылку редактирования из списка страниц в админке (edit.php)
     */
    public function remove_page_list_edit_link( $actions, $post ) {
        /**
         * Если:
         * - Запрещенный пользователь вошел в систему
         * - Страница не в списке разрешенных
         * ...удаляем быстрые ссылки "Редактировать", "Быстрое редактирование" и "Удалить".
         */
        if ( 
            $this->is_user_limited() &&
            !$this->is_page_allowed( $post->ID )
        ) {
            unset( $actions['edit'] );
            unset( $actions['inline hide-if-no-js']);
            unset( $actions['trash'] );
        }
        return $actions;
    }
}

Приведенный выше код предотвращает работу или отображение следующих элементов при необходимости:

  1. get_edit_post_link
  2. Ссылка Редактировать страницу в панели администратора WordPress для страниц
  3. Быстрые ссылки Редактировать, Быстрое редактирование и Удалить под страницами в /wp-admin/edit.php?post_type=page

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

14 мар. 2017 г. 11:26:20
Комментарии

+1 за более полный ответ, чем у @Ben, но правильный способ работы со ссылками — это манипулирование правами доступа.

Mark Kaplun Mark Kaplun
19 мар. 2017 г. 07:35:42

Да, когда я увидел ответ gmazzap, в голове промелькнуло: "Почему я сам до этого не додумался?"

ricotheque ricotheque
19 мар. 2017 г. 19:05:07
1

Если вы хотите обойтись без плагинов, вы можете использовать вариацию приведённого ниже кода в файле functions.php или в своём собственном плагине.

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

Часть 1 предназначена для указания одного пользователя и ограничения его доступа к определённой записи.

Часть 2 позволяет создать карту соответствий пользователей и ID записей, разрешая доступ к нескольким записям.

Приведённый код работает только со страницами, но если вы хотите применить его к записям или пользовательским типам записей, вам нужно изменить строку в $screen->id == 'page' на соответствующую.

Список ID экранов в wp-admin можно найти здесь

function my_pre_get_posts( $query ){

    $screen = get_current_screen();
    $current_user = wp_get_current_user();

    /**
     * Указываем одного пользователя и ограничиваем доступ к одной записи
     */
    $restricted_user_id = 10; // ID ограничиваемого пользователя
    $allowed_post_id = 1234; // ID разрешённой записи

    $current_post_id = isset( $_GET['post'] ) ? (int)$_GET['post'] : false ;

    // Затрагиваем только определённого пользователя
    if( $current_user->ID !== $restricted_user_id ){
        return;
    }

    // Затрагиваем только страницу редактирования
    if( ! $current_post_id ){
        return;
    }

    if( $screen->id == 'page' && $current_post_id !== $allowed_post_id ){
        wp_redirect( admin_url( ) );
        exit;
    }

    /**
     * Создаём карту соответствий user_id => $allowed_posts
     */
    $restrictions_map = [
        10 => [ 123 ], // Разрешаем пользователю с ID 10 редактировать страницу с ID 123
        11 => [ 152, 186 ] // Разрешаем пользователю с ID 11 редактировать страницы с ID 152 и 186
    ];

    if( array_key_exists( $current_user->ID, $restrictions_map ) ){

        $allowed_posts = $restrictions_map[$current_user->ID];

        if( $screen->id == 'page' && ! in_array( $current_user->ID, $allowed_posts ) ){
            wp_redirect( admin_url( ) );
            exit;
        }

    }

}
add_action( 'pre_get_posts', 'my_pre_get_posts' );
14 мар. 2017 г. 11:26:51
Комментарии

+1, так как это может работать для основной функциональности, но ссылки для редактирования страниц всё равно выводятся пользователям, которые не могут их редактировать, что ухудшает пользовательский интерфейс

Mark Kaplun Mark Kaplun
19 мар. 2017 г. 07:29:56
5
-4

Я использовал User Role Editor несколько раз, и он довольно хорош. Возможно, он поможет и вам. Вот ссылка Редактор ролей пользователей

16 июн. 2015 г. 17:31:25
Комментарии

Кажется, это надежный плагин, но я не могу найти способ ограничить пользователя в редактировании определенных страниц.

naf naf
16 июн. 2015 г. 17:35:42

Сделайте пользователей, которых вы хотите ограничить, пользователями уровня "автор" Добавьте возможность "edit_pages" для уровня пользователя "автор" (используя User Role Editor) Установите автором страницы пользователя, которому вы хотите предоставить право редактирования. Пользователь уровня "автор" с возможностью edit_pages может видеть список страниц в админке, но не имеет возможности редактировать, кроме страниц, автором которых он является.

user2319361 user2319361
16 июн. 2015 г. 17:46:00

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

naf naf
16 июн. 2015 г. 17:59:38

Для ограничения пользователей доступом к определенным страницам вам потребуется приобрести Pro версию. Я искал то же самое и выяснил это. http://wordpress.stackexchange.com/questions/191658/allowing-user-to-edit-only-certain-pages/191661#191661?s=f87626a8cf184588bca7c4e397c972a4

Ricardo Andres Ricardo Andres
3 мар. 2017 г. 16:32:08

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

Mark Kaplun Mark Kaplun
14 мар. 2017 г. 06:25:41