Permitir al usuario editar solo ciertas páginas

16 jun 2015, 17:15:25
Vistas: 26.3K
Votos: 17

Me gustaría permitir que ciertos usuarios editen solo una página y sus subpáginas. ¿Cómo sería esto posible? Probé el antiguo Role Scoper, pero parece tener muchos problemas y errores.

1
Comentarios

Eliminé tu solicitud de recomendación de un plugin ya que eso hacía que la pregunta no estuviera relacionada con el tema. Sí, esto debería ser posible con un plugin, pero cuando veo intentos de hacer cosas que requieren este tipo de manipulación de la funcionalidad básica, no puedo evitar pensar que estás tomando el enfoque equivocado. ¿Puedes explicar el proyecto con más detalle?

s_ha_dum s_ha_dum
16 jun 2015 17:44:12
Todas las respuestas a la pregunta 4
2
17

Lo primero que hay que hacer para implementar esta tarea es poder reconocer qué página puede editar un usuario.

Hay diferentes formas de hacerlo. Podría ser un meta de usuario, algún valor de configuración... Para esta respuesta, asumiré que existe una función como esta:

function wpse_user_can_edit( $user_id, $page_id ) {

   $page = get_post( $page_id );

   // encontremos la página superior en la jerarquía
   while( $page && (int) $page->parent ) {
     $page = get_post( $page->parent );
   }

   if ( ! $page ) {
     return false;
   }

   // ahora $page es la página superior en la jerarquía
   // cómo saber si un usuario puede editarla, depende de ti...

}

Ahora que tenemos una forma de determinar si un usuario puede editar una página, solo necesitamos decirle a WordPress que use esta función para verificar la capacidad del usuario de editar una página.

Eso se puede hacer mediante el filtro 'map_meta_cap'.

Algo como:

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

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

    // Si la capacidad filtrada no es de nuestro interés, simplemente devolver el valor actual
    if ( ! in_array( $cap, $to_filter, true ) ) {
        return $caps;
    }

    // El primer elemento en el array $args debería ser el ID de la página
    if ( ! $args || empty( $args[0] ) || ! wpse_user_can_edit( $user_id, $args[0] ) ) {
        // El usuario no tiene permiso, informemos a WP
        return [ 'do_not_allow' ];
    }
    // De lo contrario, simplemente devolver el valor actual
    return $caps;

}, 10, 4 );

En este punto, solo necesitamos una forma de conectar un usuario a una o más páginas.

Puede haber diferentes soluciones según el caso de uso.

Una solución flexible podría ser añadir un desplegable de páginas "raíz" (ver wp_dropdown_pages) a la pantalla de edición de usuario en el administrador, y guardar la(s) página(s) seleccionada(s) como meta del usuario.

Podríamos aprovechar 'edit_user_profile' para añadir el campo desplegable de páginas y 'edit_user_profile_update' para almacenar el valor seleccionado como meta del usuario.

Estoy seguro de que en este sitio hay suficiente orientación sobre cómo hacerlo en detalle.

Cuando las páginas se almacenan como meta del usuario, la función wpse_user_can_edit() de arriba puede completarse verificando si el ID de la página es parte del valor del meta del usuario.

Al eliminar la capacidad de editar la página, WordPress hará el resto: eliminará cualquier enlace de edición del backend y frontend, evitará el acceso directo... y así sucesivamente.

14 mar 2017 12:07:19
Comentarios

Esto es mucho mejor que mi respuesta. ¿Por qué limitar los enlaces de edición cuando puedes simplemente modificar la capacidad del usuario y dejar que WordPress maneje el resto?

ricotheque ricotheque
19 mar 2017 19:04:19

deberías usar "a" antes de la palabra "user" no "an" porque una "u" larga suena como "yu" que comienza con una consonante.

Philip Philip
10 dic 2019 21:16:39
2

Implementar esta funcionalidad requiere una pequeña cantidad de código, incluso si usas una clase PHP para evitar variables globales. Tampoco quise ocultar las páginas prohibidas para el usuario en el Dashboard. ¿Qué pasaría si agregaran contenido que ya existe en el sitio?

$user_edit_limit = new NS_User_Edit_Limit(
    15,       // ID del usuario que queremos limitar
    [2, 17]   // Array de IDs de páginas padre que el usuario puede editar
                 (también acepta IDs de subpáginas)
);

class NS_User_Edit_Limit {

    /**
     * Almacena el ID del usuario que queremos controlar y los
     * posts que permitiremos que el usuario edite.
     */
    private $user_id = 0;
    private $allowed = array();

    public function __construct( $user_id, $allowed ) {

        // Guardamos el ID del usuario que queremos limitar.
        $this->user_id = $user_id;

        // Expandimos la lista de páginas permitidas para incluir subpáginas
        $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;
            }
        }

        // Para el usuario prohibido...
        // Eliminamos el enlace de edición del front-end según sea necesario
        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 );
        // Eliminamos el enlace de edición de wp-admin según sea necesario
        add_action( 'page_row_actions', array( $this, 'remove_page_list_edit_link' ), 10, 2 );
    }

    /**
     * Funciones auxiliares que verifican si el usuario actual es el que
     * queremos limitar y si un post específico está en nuestra
     * lista de posts que permitimos que el usuario edite.
     */
    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 );
    }

    /**
     * Elimina el enlace de edición del front-end según sea necesario.
     */
    public function remove_edit_link( $link, $post_id, $test ) {
        /**
         * Si...
         * - El usuario limitado está logueado
         * - La página para la que se está creando el enlace de edición no está en la lista permitida
         * ...retornamos un $link vacío. Esto también hace que edit_post_link() no muestre nada.
         *
         * De lo contrario, retornamos el enlace normalmente.
         */
        if ( $this->is_user_limited() && !$this->is_page_allowed( $post_id ) ) {
            return '';
        }
        return $link;
    }

    /**
     * Elimina el enlace de edición de la barra de administración de WP
     */
    public function remove_wp_admin_edit_link( $wp_admin_bar ) {
        /**
         *  Si:
         *  - Estamos en una página individual
         *  - El usuario limitado está logueado
         *  - La página no está en la lista permitida
         *  ...Eliminamos el enlace de edición de la barra de administración de WP
         */
        if ( 
            is_page() &&
            $this->is_user_limited() &&
            !$this->is_page_allowed( get_post()->ID )
        ) {
            $wp_admin_bar->remove_node( 'edit' );
        }
    }

    /**
     * Elimina el enlace de edición de edit.php en el admin de WP
     */
    public function remove_page_list_edit_link( $actions, $post ) {
        /**
         * Si:
         * - El usuario limitado está logueado
         * - La página no está en la lista permitida
         * ...Eliminamos los enlaces rápidos "Editar", "Edición rápida" y "Papelera".
         */
        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;
    }
}

Lo que hace el código anterior es evitar que lo siguiente funcione o aparezca según sea necesario:

  1. get_edit_post_link
  2. Enlace Editar página en la barra de administración de WP que aparece para las Páginas
  3. Enlaces rápidos Editar, Edición rápida y Papelera que aparecen debajo de las Páginas en /wp-admin/edit.php?post_type=page

Esto funcionó en mi instalación local de WordPress 4.7. Asumiendo que las páginas del sitio no cambiarán con frecuencia, podría ser mejor codificar manualmente los IDs de la página y sus subpáginas, y eliminar el WP_Query dentro del método __construct. Esto ahorrará muchas consultas a la base de datos.

14 mar 2017 11:26:20
Comentarios

+1 por la respuesta más completa que la de @Ben, pero la forma correcta de manejar los enlaces es manipulando las capacidades,

Mark Kaplun Mark Kaplun
19 mar 2017 07:35:42

Sí, cuando vi la respuesta de gmazzap terminé pensando "¿Por qué no se me ocurrió eso?"

ricotheque ricotheque
19 mar 2017 19:05:07
1

Si deseas evitar el uso de plugins, podrías utilizar una variación del código siguiente en un archivo functions.php o en un plugin personalizado.

Este código tiene 2 partes separadas. Solo necesitarías usar 1 de ellas, dependiendo de la complejidad de los requisitos.

La Parte 1 especifica un único usuario y lo restringe a una publicación específica.

La Parte 2 te permite crear un mapa de usuarios e IDs de publicaciones, permitiendo múltiples publicaciones.

El código siguiente es solo para páginas, pero si deseas cambiarlo para posts o un tipo de publicación personalizada, necesitarías cambiar la cadena en $screen->id == 'page' por otra cosa.

Puedes encontrar una referencia a los IDs de pantalla en wp-admin aquí

function my_pre_get_posts( $query ){

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

    /**
     * Especifica un único usuario y lo restringe a una única página
     */
    $restricted_user_id = 10; //ID del usuario restringido
    $allowed_post_id = 1234; //ID de la publicación permitida

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

    //Solo afecta a un usuario específico
    if( $current_user->ID !== $restricted_user_id ){
        return;
    }

    //Solo afecta la página de EDICIÓN
    if( ! $current_post_id ){
        return;
    }

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

    /**
     * Especifica un mapa de user_id => $allowed_posts
     */
    $restrictions_map = [
        10 => [ 123 ], //Permite al usuario ID editar la Página ID 123
        11 => [ 152, 186 ] //Permite al usuario ID editar las Páginas ID 123 y 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 mar 2017 11:26:51
Comentarios

+1 ya que puede funcionar para la funcionalidad principal, pero esto aún deja los enlaces para editar las páginas visibles para usuarios que no pueden editarlos, lo cual genera una mala experiencia de usuario

Mark Kaplun Mark Kaplun
19 mar 2017 07:29:56
5
-4

Utilicé User Role Editor un par de veces y es bastante bueno. Quizás también te pueda ayudar. Aquí está el enlace User Role Editor

16 jun 2015 17:31:25
Comentarios

Parece ser un plugin sólido, pero no encuentro una manera de restringir a un usuario para editar páginas específicas.

naf naf
16 jun 2015 17:35:42

Haz que los usuarios que quieras limitar sean usuarios de nivel autor Añade la capacidad "edit_pages" al nivel de usuario autor (usando User Role Editor) Establece el autor de una página como el usuario al que quieres dar privilegios de edición. Un usuario de nivel autor al que se le da la capacidad de edit_pages puede ver la lista de páginas en el panel, pero no tiene la opción de editar excepto las páginas de las que es autor.

user2319361 user2319361
16 jun 2015 17:46:00

Gracias, eso funciona hasta cierto punto. En algún momento podría necesitar tener múltiples usuarios restringidos para modificar una página específica, así que necesitaría una manera de establecer múltiples autores para una página.

naf naf
16 jun 2015 17:59:38

Para restringir a los usuarios a páginas específicas necesitarás comprar la versión Pro. Estaba buscando lo mismo y descubrí eso. http://wordpress.stackexchange.com/questions/191658/allowing-user-to-edit-only-certain-pages/191661#191661?s=f87626a8cf184588bca7c4e397c972a4

Ricardo Andres Ricardo Andres
3 mar 2017 16:32:08

aunque ese plugin específico es una buena opción ahora mismo, probablemente sea más fácil escribir código para hacerlo que navegar por todas las opciones que ofrece el plugin. (si es que incluso te permite hacer lo que pregunta el OP)

Mark Kaplun Mark Kaplun
14 mar 2017 06:25:41