Consentire all'utente di modificare solo determinate pagine


16

Vorrei consentire a determinati utenti di modificare solo una pagina e le sue sottopagine. Come sarebbe possibile? Ho provato il vecchio Role Scoper, ma sembra avere molti problemi e bug.


2
Ho rimosso la tua richiesta di raccomandazione per un plug-in in quanto ciò rendeva la domanda fuori tema. Sì, questo dovrebbe essere possibile con un plugin, ma quando vedo i tentativi di fare cose che richiedono questo tipo di hacking delle funzionalità di base, non posso fare a meno di pensare che stai adottando un approccio sbagliato. Puoi spiegare il progetto in modo più dettagliato?
s_ha_dum,

Risposte:


14

La prima cosa da fare per implementare tale compito è essere in grado di riconoscere quale pagina un utente può modificare.

Esistono diversi modi per farlo. Potrebbe essere una meta utente, un valore di configurazione ... Per il bene di questa risposta, assumerò che esista una funzione 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...

}

Ora che abbiamo un modo per determinare se un utente può modificare una pagina, dobbiamo solo dire a WordPress di utilizzare questa funzione per verificare la capacità dell'utente di modificare una pagina.

Questo può essere fatto tramite 'map_meta_cap'filtro.

Qualcosa di simile a:

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

A questo punto, abbiamo solo bisogno di un modo per connettere un utente a una o più pagine.

Potrebbero esserci diverse soluzioni a seconda del caso d'uso.

Una soluzione flessibile potrebbe essere quella di aggiungere un menu a discesa di pagine "root" (vedi wp_dropdown_pages) alla schermata di modifica dell'utente amministratore e salvare le pagine selezionate come meta utente.

Potremmo sfruttare 'edit_user_profile'per aggiungere il campo a discesa delle pagine e 'edit_user_profile_update'per memorizzare il valore selezionato come meta utente.

Sono sicuro che in questo sito web ci sono abbastanza indicazioni su come farlo in dettaglio.

Quando le pagine sono memorizzate come meta utente, la wpse_user_can_edit()funzione dall'alto può essere completata controllando se l'id della pagina fa parte del meta valore dell'utente.

Rimuovendo la possibilità di modificare la pagina, WordPress farà il resto: rimuoverà qualsiasi collegamento di modifica da backend e frontend, impedirà l'accesso diretto ... e così via.


3
Molto meglio della mia risposta. Perché limitare i collegamenti di modifica quando puoi semplicemente modificare le capacità dell'utente e lasciare che WordPress gestisca il resto?
Ricotheque,

dovresti usare "a" prima della parola "user" non "an" perché una lunga "u" suona come "yu" che inizia con una consonante.
Filippo,

7

Ci vuole una piccola quantità di codice per implementare questa funzione, anche se si utilizza una classe PHP per evitare variabili globali. Inoltre, non volevo nascondere le pagine vietate per l'utente nella Dashboard. E se aggiungessero contenuti che erano già sul sito?

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

Ciò che fa il codice sopra è impedire che quanto segue funzioni o appaia come necessario:

  1. get_edit_post_link
  2. Edit Page collegamento sulla barra di amministrazione di WP visualizzata per le pagine
  3. Edit, Quick Edite Trashcollegamenti rapidi che compaiono sotto le Pagine in/wp-admin/edit.php?post_type=page

Questo ha funzionato sulla mia installazione locale di WordPress 4.7. Supponendo che le pagine del sito non cambino spesso, potrebbe essere meglio codificare gli ID della pagina e delle sue pagine secondarie e rimuovere l' WP_Queryinterno del __constructmetodo. Ciò farà risparmiare molto sulle chiamate al database.


+1 per la risposta più completa di quella di @ Ben, ma il modo giusto di gestire i collegamenti è manipolare le capacità,
Mark Kaplun

Sì, quando ho visto la risposta di gmazzap ho finito per pensare "Ora, perché non ci ho pensato?"
Ricotheque,

5

Se volessi stare lontano dai plugin, potresti cambiare il codice qui sotto in un file Functions.php o in un plugin personalizzato.

Ci sono 2 parti separate in questo codice, dovresti usarne solo 1, ma quale dipende dalla complessità dei requisiti.

La parte 1 specifica un singolo utente e li limita a un post specifico.

La parte 2 ti consente di creare una mappa di utenti e pubblicare ID e consente più post

Il codice seguente è solo per una pagina, ma se si desidera modificarlo in un post o in un tipo di post personalizzato, è necessario modificare la stringa in $screen->id == 'page'qualcos'altro.

Puoi trovare un riferimento agli ID dello schermo su wp-admin qui

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 poiché può funzionare per eseguire le funzionalità di base, ma ciò lascia comunque i collegamenti per modificare le pagine in uscita anche per gli utenti che non possono modificarle, il che rende una cattiva interfaccia utente
Mark Kaplun

-4

Ho usato User Role Editorun paio di volte ed è abbastanza buono. Forse potrebbe aiutare anche te. Ecco il link Editor ruoli utente


Sembra essere un solido plugin, ma non riesco a trovare un modo per limitare un utente a modificare pagine specifiche.
naf

Rendi gli utenti a cui vuoi limitare in questo modo gli utenti a livello di autore Aggiungi la funzionalità "edit_pages" al livello utente dell'autore (usando l'Editor dei ruoli utente) Imposta l'autore di una pagina sull'utente a cui desideri concedere il privilegio di modificarlo. Un utente a livello di autore, data la possibilità di edit_pages, può vedere l'elenco delle pagine nella dashboard, ma non ha la possibilità di modificare tranne le pagine di cui è autore.
user2319361

4
Grazie, funziona fino a un certo punto. Ad un certo punto potrei avere più utenti limitati per modificare una pagina specifica, quindi dovrebbe esserci un modo per impostare più autori su una pagina.
naf

Per limitare gli utenti a pagine specifiche dovrai acquistare Pro versoin. Sto cercando la stessa cosa e l'ho scoperto. wordpress.stackexchange.com/questions/191658/…
Ricardo Andres

1
mentre quel plugin specifico è una cosa solida in questo momento, è probabilmente più facile scrivere codice per farlo che guadare in tutte le opzioni che offre il plugin. (se ti consente anche di fare ciò che l'OP chiede)
Mark Kaplun,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.