Дозволяє користувачеві редагувати лише певні сторінки


16

Я хотів би дозволити певному користувачеві редагувати лише одну сторінку та це підсторінки. Як це було б можливо? Я спробував старого ролевого Scoper, але, схоже, є багато проблем і помилок.


2
Я видалив ваш запит щодо рекомендації щодо плагіну, оскільки це вирішило питання поза темою. Так, це має бути можливо за допомогою плагіна, але коли я бачу спроби робити такі речі, які вимагають такого злому базової функціональності, я не можу не допомогти, але думаю, що ви невірний підхід. Чи можете ви пояснити проект детальніше?
s_ha_dum

Відповіді:


14

Перше, що потрібно зробити для реалізації такого завдання - це вміти розпізнавати, яку сторінку може редагувати користувач.

Існують різні способи зробити це. Це може бути мета користувача, якесь значення конфігурації ... Заради цієї відповіді я вважаю, що функція lile така існує:

function wpse_user_can_edit( $user_id, $page_id ) {

   $page = get_post( $page_id );

   // let's find the topmost page in the hierarchy
   while( $page && (int) $page->parent ) {
     $page = get_post( $page->parent );
   }

   if ( ! $page ) {
     return false;
   }

   // now $page is the top page in the hierarchy
   // how to know if an user can edit it, it's up to you...

}

Тепер, коли у нас є спосіб визначити, чи може користувач редагувати сторінку, нам просто потрібно сказати 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 the capability being filtered isn't of our interest, just return current value
    if ( ! in_array( $cap, $to_filter, true ) ) {
        return $caps;
    }

    // First item in $args array should be page ID
    if ( ! $args || empty( $args[0] ) || ! wpse_user_can_edit( $user_id, $args[0] ) ) {
        // User is not allowed, let's tell that to WP
        return [ 'do_not_allow' ];
    }
    // Otherwise just return current value
    return $caps;

}, 10, 4 );

На даний момент нам потрібен лише спосіб підключення користувача до однієї або декількох сторінок.

Можуть бути різні рішення залежно від випадку використання.

Гнучким рішенням може бути додавання випадаючого "кореневих" сторінок (див. wp_dropdown_pages) На екран редагування користувача адміністратора та збереження вибраних сторінок як мета користувачів.

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

Я впевнений, що на цьому веб-сайті є досить вказівки щодо того, як це докладно.

Коли сторінки (сторінки) зберігаються як мета користувача, wpse_user_can_edit()функцію зверху можна закінчити перевіряючи, чи ідентифікатор сторінки є частиною мета-значення користувача.

Видаляючи можливість редагування сторінки, WordPress зробить все інше: видалить будь-яке посилання для редагування з бекенда та фронту, запобіжить прямий доступ ... тощо.


3
Це набагато краще, ніж моя відповідь. Навіщо обмежувати редагування посилань, коли ви можете просто змінити можливості користувача та дозволити WordPress обробляти решту?
ricotheque

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

7

Для реалізації цієї функції потрібно невелика кількість коду, навіть якщо ви використовуєте клас PHP, щоб уникнути глобальних змінних. Я також не хотів приховувати заборонені сторінки для користувача на інформаційній панелі. Що робити, якщо вони додали вміст, який вже був на сайті?

$user_edit_limit = new NS_User_Edit_Limit(
    15,       // User ID we want to limit
    [2, 17]   // Array of parent page IDs user is allowed to edit
                 (also accepts sub-page IDs)
);

class NS_User_Edit_Limit {

    /**
     * Store the ID of the user we want to control, and the
     * posts we will let the user edit.
     */
    private $user_id = 0;
    private $allowed = array();

    public function __construct( $user_id, $allowed ) {

        // Save the ID of the user we want to limit.
        $this->user_id = $user_id;

        // Expand the list of allowed pages to include sub pages
        $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;
            }
        }

        // For the prohibited user...
        // Remove the edit link from the front-end as needed
        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 );
        // Remove the edit link from wp-admin as needed
        add_action( 'page_row_actions', array( $this, 'remove_page_list_edit_link' ), 10, 2 );
    }

    /**
     * Helper functions that check if the current user is the one
     * we want to limit, and check if a specific post is in our
     * list of posts that we allow the user to edit.
     */
    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 );
    }

    /**
     * Removes the edit link from the front-end as needed.
     */
    public function remove_edit_link( $link, $post_id, $test ) {
        /**
         * If...
         * - The limited user is logged in
         * - The page the edit link is being created for is not in the allowed list
         * ...return an empty $link. This also causes edit_post_link() to show nothing.
         *
         * Otherwise, return link as normal.
         */
        if ( $this->is_user_limited() && !$this->is_page_allowed( $post_id ) ) {
            return '';
        }
        return $link;
    }

    /**
     * Removes the edit link from WP Admin Bar
     */
    public function remove_wp_admin_edit_link( $wp_admin_bar ) {
        /**
         *  If:
         *  - We're on a single page
         *  - The limited user is logged in
         *  - The page is not in the allowed list
         *  ...Remove the edit link from the WP Admin Bar
         */
        if ( 
            is_page() &&
            $this->is_user_limited() &&
            !$this->is_page_allowed( get_post()->ID )
        ) {
            $wp_admin_bar->remove_node( 'edit' );
        }
    }

    /**
     * Removes the edit link from WP Admin's edit.php
     */
    public function remove_page_list_edit_link( $actions, $post ) {
        /**
         * If:
         * -The limited user is logged in
         * -The page is not in the allowed list
         * ...Remove the "Edit", "Quick Edit", and "Trash" quick links.
         */
        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. Edit Page посилання на панелі адміністратора WP, що відображається для Сторінок
  3. Edit, Quick Editта Trashшвидкі посилання під Сторінками в/wp-admin/edit.php?post_type=page

Це працювало на моїй локальній програмі WordPress 4.7. Якщо припустити, що сторінки на сайті не змінюватимуться часто, може бути краще ввести жорсткі коди ідентифікаторів сторінки та її підсторінок та видалити метод WP_Queryвсередині __construct. Це дозволить значно заощадити на дзвінках до бази даних.


+1 для більш повної відповіді, ніж @ Бен, але правильним способом обробляти посилання є маніпулювання можливостями,
Марк Каплун

Так, коли я побачив відповідь gmazzap, я в кінцевому підсумку подумав: "А чому я цього не придумав?"
Рікотека

5

Якщо ви хочете триматися подалі від плагінів, ви можете змінити код нижче у файлі function.php або користувацькому плагіні.

У цьому коді є дві окремі частини, вам потрібно буде використовувати лише 1 з них, але яка залежить від складності вимог.

Частина 1 вказує одного користувача та обмежує їх конкретною публікацією.

Частина 2 дозволяє створити карту користувачів та ідентифікаторів публікацій та дозволяє декілька публікацій

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

Ви можете знайти посилання на екран Ідентифікатор навколо Wp-адміністратора тут

function my_pre_get_posts( $query ){

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

    /**
     * Specify a single user and restrict to a single page
     */
    $restricted_user_id = 10; //User ID of the restricted user
    $allowed_post_id = 1234; //Post ID of the allowed post

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

    //Only affecting a specific user
    if( $current_user->ID !== $restricted_user_id ){
        return;
    }

    //Only Affecting EDIT page.
    if( ! $current_post_id ){
        return;
    }

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

    /**
     * Specify a map of user_id => $allowed_posts
     */
    $restrictions_map = [
        10 => [ 123 ], //Allow user ID to edit Page ID 123
        11 => [ 152, 186 ] //Allow user ID to edit Page ID 123 and 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' );

1
+1, як це може працювати для створення основних функціональних можливостей, але це все ще залишає посилання для редагування виданих сторінок навіть тим користувачам, які не можуть їх редагувати, що робить поганий інтерфейс користувача
Марк Каплун

-4

Я користувався User Role Editorпару разів і досить непогано. Можливо, це теж могло б вам допомогти. Ось посилання редактора ролей користувача


Здається, це суцільний плагін, але я не можу знайти спосіб обмеження користувача редагувати певні сторінки.
нафта

Зробіть так, щоб користувачі, які ви хочете обмежити таким чином, користувачі авторського рівня Додайте можливість "edit_pages" до рівня користувача користувача (використовуючи редактор ролей користувача) Встановіть автора сторінки користувачеві, якому ви хочете надати привілей редагувати його. Користувач рівня автора, що надає можливість edit_pages, може переглядати список сторінок на інформаційній панелі, але не має можливості редагувати, крім сторінок, на яких вони є авторами.
користувач2319361

4
Дякую, це працює певною мірою. У якийсь момент мені, можливо, доведеться обмежувати кількість користувачів, щоб змінювати певну сторінку, тому мав би бути спосіб встановити кілька авторів на сторінку.
наф

Щоб обмежити користувачів певними сторінками, вам потрібно придбати версію Pro. Я шукав те саме, що і з’ясував це. wordpress.stackexchange.com/questions/191658/…
Рікардо Андрес

1
хоча цей конкретний плагін є суттєвою справою зараз, напевно, простіше написати код для цього, ніж розширити всі параметри, які пропонує плагін. (якщо це навіть дозволить вам робити те, що просить ОП)
Марк Каплун
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.