Mengizinkan pengguna mengedit hanya halaman tertentu

16

Saya ingin mengizinkan pengguna tertentu untuk mengedit hanya satu halaman dan itu adalah subhalaman. Bagaimana ini mungkin? Saya mencoba peran lama Scoper, tetapi tampaknya memiliki banyak masalah dan bug.

naf
sumber
2
Saya menghapus permintaan Anda untuk rekomendasi plugin karena membuat pertanyaan di luar topik. Ya, ini seharusnya dimungkinkan dengan sebuah plugin tetapi ketika saya melihat upaya untuk melakukan hal-hal yang memerlukan peretasan fungsi dasar seperti ini saya tidak dapat membantu tetapi berpikir bahwa Anda mengambil pendekatan yang salah. Bisakah Anda menjelaskan proyek lebih terinci?
s_ha_dum

Jawaban:

14

Hal pertama yang harus dilakukan untuk mengimplementasikan tugas tersebut adalah untuk dapat mengenali halaman mana yang dapat diedit pengguna.

Ada berbagai cara untuk melakukannya. Ini bisa berupa meta pengguna, beberapa nilai konfigurasi ... Demi jawaban ini, saya akan menganggap bahwa fungsi lile ini ada:

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...

}

Sekarang kita memiliki cara untuk menentukan apakah pengguna dapat mengedit halaman, kita hanya perlu memberitahu WordPress untuk menggunakan fungsi ini untuk memeriksa kemampuan pengguna untuk mengedit halaman.

Itu bisa dilakukan melalui 'map_meta_cap'filter.

Sesuatu seperti:

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 );

Pada titik ini, kita hanya perlu cara untuk menghubungkan pengguna ke satu halaman atau lebih.

Mungkin ada solusi berbeda tergantung penggunaannya.

Solusi yang fleksibel bisa dengan menambahkan dropdown halaman "root" (lihat wp_dropdown_pages) ke layar edit pengguna admin, dan simpan halaman yang dipilih sebagai meta pengguna.

Kita dapat memanfaatkan 'edit_user_profile'untuk menambahkan bidang dropdown halaman dan 'edit_user_profile_update'menyimpan nilai yang dipilih sebagai meta pengguna.

Saya yakin bahwa di situs web ini ada cukup panduan tentang cara melakukannya secara rinci.

Ketika halaman disimpan sebagai meta pengguna, wpse_user_can_edit()fungsi dari atas dapat diselesaikan dengan memeriksa apakah halaman id adalah bagian dari nilai meta pengguna.

Menghapus kemampuan untuk mengedit halaman, WordPress akan melakukan sisanya: akan menghapus semua tautan edit dari backend dan frontend, akan mencegah akses langsung ... dan seterusnya.

gmazzap
sumber
3
Ini jauh lebih baik daripada jawaban saya. Mengapa membatasi tautan edit ketika Anda hanya dapat memodifikasi kemampuan pengguna, dan membiarkan WordPress menangani sisanya?
ricotheque
Anda harus menggunakan "a" sebelum kata "user" bukan "an" karena panjang "u" terdengar seperti "yu" yang dimulai dengan konsonan.
Philip
7

Memang dibutuhkan sedikit kode untuk mengimplementasikan fitur ini, bahkan jika Anda menggunakan kelas PHP untuk menghindari variabel global. Saya juga tidak ingin menyembunyikan halaman yang dilarang untuk pengguna di Dasbor. Bagaimana jika mereka menambahkan konten yang sudah ada di situs?

$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;
    }
}

Apa yang dilakukan oleh kode di atas adalah mencegah yang berikut ini agar tidak berfungsi atau muncul sesuai kebutuhan:

  1. get_edit_post_link
  2. Edit Page pada Bilah Admin WP yang muncul untuk Halaman
  3. Edit,, Quick Editdan Trashtautan cepat yang muncul di bawah Halaman di/wp-admin/edit.php?post_type=page

Ini bekerja pada instalasi WordPress 4.7 lokal saya. Dengan asumsi bahwa halaman-halaman di situs tidak akan sering berubah, mungkin lebih baik untuk melakukan hardcode pada ID halaman dan sub-halamannya, dan menghapus metode WP_Querydi dalamnya __construct. Ini akan menghemat banyak pada panggilan basis data.

ricotheque
sumber
+1 untuk jawaban yang lebih lengkap daripada @ Ben tetapi cara yang tepat untuk menangani tautan adalah dengan memanipulasi kemampuan,
Mark Kaplun
Ya, ketika saya melihat jawaban gmazzap, saya akhirnya berpikir, "Sekarang kenapa saya tidak memikirkan itu?"
ricotheque
5

Jika Anda ingin menjauhi plugin, Anda bisa membuat variasi kode di bawah ini dalam file functions.php atau plugin kustom.

Ada 2 bagian yang terpisah untuk kode ini, Anda hanya perlu menggunakan 1 dari mereka, tetapi yang mana tergantung pada kompleksitas persyaratan.

Bagian 1 menentukan pengguna tunggal dan membatasi mereka ke pos tertentu.

Bagian 2 memungkinkan Anda untuk membuat peta pengguna dan memposting ID dan memungkinkan banyak posting

Kode di bawah ini hanya untuk satu halaman, tetapi jika Anda ingin mengubahnya menjadi posting, atau tipe posting khusus, Anda perlu mengubah string $screen->id == 'page'menjadi sesuatu yang lain.

Anda dapat menemukan referensi ke ID layar di sekitar wp-admin di sini

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' );
Ben Casey
sumber
1
Memberi +1 karena dapat berfungsi untuk melakukan fungsionalitas inti, tetapi ini masih menyisakan tautan untuk mengedit halaman menjadi keluaran bahkan kepada pengguna yang tidak dapat mengeditnya yang membuat UI buruk
Mark Kaplun
-4

Saya menggunakan User Role Editorbeberapa kali dan cukup bagus. Mungkin itu bisa membantu Anda juga. Berikut ini tautan Editor Peran Pengguna

pengguna2319361
sumber
Tampaknya menjadi plugin yang solid, tetapi saya tidak dapat menemukan cara bagaimana membatasi pengguna untuk mengedit halaman tertentu.
naf
Buat pengguna yang ingin Anda batasi dengan cara ini pengguna tingkat penulis Tambahkan kemampuan "edit_pages" ke tingkat pengguna penulis (menggunakan Editor Peran Pengguna) Atur penulis halaman ke pengguna yang Anda ingin memberikan hak istimewa untuk mengeditnya. Pengguna tingkat penulis yang diberi kemampuan edit_pages dapat melihat daftar halaman di dasbor, tetapi tidak memiliki opsi untuk mengedit kecuali untuk halaman yang merupakan penulisnya.
user2319361
4
Terima kasih, itu berfungsi sampai batas tertentu. Pada titik tertentu saya mungkin harus membatasi beberapa pengguna untuk memodifikasi halaman tertentu, jadi perlu ada cara untuk mengatur beberapa penulis ke halaman.
naf
Untuk membatasi pengguna ke halaman tertentu Anda harus membeli Pro versoin. Saya mencari hal yang sama dan menemukan itu. wordpress.stackexchange.com/questions/191658/…
Ricardo Andres
1
sementara itu plugin spesifik adalah hal yang solid sekarang, mungkin lebih mudah untuk menulis kode daripada melakukannya di semua opsi yang ditawarkan plugin. (jika itu bahkan memungkinkan Anda melakukan apa yang diminta OP)
Mark Kaplun