En el tutorial sobre como comprobar el rol de un usuario, un lector me preguntaba cómo podía obtener el rol con más peso. Yo le contesté que no pensaba que ese concepto de roles con peso existiera en WordPress. Esta idea me estuvo rondado unos días y finalmente he llegado a la conclusión de que el concepto existe pero que no nos puede servir de base para decidir sobre niveles de acceso del usuario. Aquí explico por qué llegué a esa conclusión.

User levels vs roles

En WordPress 1.5 se introdujo el sistema de “user levels”, un sistema para controlar lo que cada usuario podía o no podía hacer en base al peso asignado al grupo o nivel al que perteneciera. Este sistema fue depreciado en WordPress 3.0 y se reemplazó totalmente por el sistema de roles y capacidades que había sido introducido en la versión 2.5 (voy a decir capacidades por ser la palabra utilizada en la documentación oficial en español aunque creo que sería más apropiado hablar de competencias).

En el sistema de roles y capacidades, cada rol tiene unas capacidades predeterminadas asignadas y generalmente los roles reciben nombres que rápidamente asociamos con una determinada jerarquía. Con esta jerarquía hacemos el sistema de roles equivalente al sistema de “user levels” mentalmente en un instante.

Pero, ¿por qué WordPress introduciría un nuevo sistema de usuarios igual que el anterior? Ahí está la clave, no son iguales.

Comprueba capacidades, no roles

Como decía, cada rol tiene asignado unas determinadas competencias predeterminadas. Para no desprestigiar la flexibilidad de WordPress, estas capacidades se pueden modificar a nuestro antojo. Por ejemplo, puedo quitar la capacidad para publicar posts al rol author:

$author = get_role('author');
$author->remove_cap( 'publish_posts' );

Pero el sistema de roles y capacidades no se queda ahí, también se pueden asignar capacidades concretas a usuarios individuales, del mismo modo que a un determinado usuario se le puede quitar alguna capacidad, independientemente de los roles que tenga asignados. Por ejemplo, a un usuario concreto, de rol author o no, si puedo permitirle publicar posts:

$user = new WP_User( $user_id );
$user->add_cap( 'publish_posts' );

Y más aún. Puedo definir roles y capacidades a mi antojo sin que necesariamente los nombres elegidos para los roles hagan referencia a su nivel de capacidades. Ni si quiera las capacidades tienen por qué ser mayores o menores. Es totalmente mi decisión. Por ejemplo:

add_role(
   'mind_reader',
   __( 'The Mind reader' ),
   array(
       'fly'      => false,
       'read_minds' => true
   )
);

add_role(
    'flying',
    __( 'The Flying' ),
    array(
        'fly' => true,
        'read_minds' => false
    )
);

// El usuario de ID 85 puede hacer las dos cosas
// sin importar el rol que tenga
$user = new WP_User( 85 );
$user->add_cap( 'fly' );
$user->add_cap( 'read_minds' );

¿Cuál de los dos roles tiene más peso? ¿Y qué pasa con el usuario 85?. Cómo ves, es muy fácil deducir que comprobar roles de usuario no tiene ningún sentido para decidir si el usuario puede o no hacer algo o si puede o no acceder a alguna parte privada de nuestra web. Así que en lugar de roles de usuario tenemos que comprobar capacidades de usuario. Y es muy fácil, basta con comprobar el return de la función current_user_can().

if( current_user_can( 'fly' ) ) {
    // El usuario puede volar
}

if( current_user_can( 'read_minds' ) ) {
    // El usuario puede leer mentes
}

Ejemplo: comprobar si un usuario puede moderar comentarios vs comprobar si el usuario es administrador o editor

Vamos a suponer que hemos desarrollado un plugin y queremos mostrar la página de opciones sólo a usuarios que pueden moderar comentarios. De primeras se nos puede venir a la cabeza: “Ah, tengo que comprobar si el usuario es editor o administrador, que son los roles que tienen asignadas esas capacidades de forma pedeterminada”.

Muy mal. Puede que otro plugin de la web, por el motivo que haya querido su dueño, que es su web y es libre de hacer lo que quiera, hay quitado la capacidad de moderar comentarios de los editores; o puede que a un determinado usuario le haya dado esa capacidad pero no el rol de editor ni el resto de sus capacidades. Así que la comprobación de si el usuario es “editor o superior” es un mal planteamiento.

Si queremos mostrar la página de opciones de nuestro plugin a los usuarios que pueden moderar comentarios, comprobemos eso y no otra cosa. Ya no sólo por qué las capacidades de roles y usuarios se puedan modificar y podamos acabar con resultados inesperados, sino también por que es lo conceptualmente correcto.

Así que NO haríamos esto:

$user = wp_get_current_user();

if( ! empty( $user ) && count( array_intersect( [ "editor", "administrator" ], (array) $user->roles ) ) ) {
    // Dejar acceder al usuario por que puede moderar comentarios ¿Seguro?
}

Y haríamos esto:

 if( current_user_can( "moderate_comments" ) ) {
      // Dejar acceder al usuario por que puede moderar comentarios 100% seguro
}

Otro buen ejemplo lo tenemos en el tutorial sobre el acceso a wp-admin sólo a administradores. En ese caso lo idóneo no era comprobar el rol “admin” sino la capacidad “manage_options”. En conclusión, las capacidades del usuario son lo que importa, el rol es tan sólo una etiqueta sin mucha importancia.

  • iván Ramos

    Ya he leido otros de tus post, y despues de este he estado buscando la forma de modificar la capacidad para que un usuario pueda modificar su propio perfil, es decir necesito que no puedan modificar su perfil.

    Tras una busqueda por google no encuentro nada relacionado a mi duda, lo cual me extraña. ¿seria posible hacerlo?

    • Lo siento pero este post no trata sobre la alteración ni creación de capacidades, es una reflexión sobre uno de sus más convenientes una vez que ya sabes trabajar con ellas y entender mejor que representan las capacidades en el sistema de usuarios de WordPress.

      Además, creo que modificar una capacidad no es lo que quieres, más bien sería modificar las capacidades asignadas a un usuario (¿o tal vez a un rol?). ¿O a lo mejor quieres bloquear el acceso a wp-admin/profile.php …… suerte!!! (por cierto, a mi una búsqueda rápida me ha arrojado un montón de resultados interesantes, por ejemplo este para bloquear el acceso a wp-admin/profile.php).

    • iván Ramos

      Claro perdona, me he explicado mal, me referia a que no habia encontrado ninunga capacidad(asignada a un rol) que pudiese restringir la edicion de un perfil.

      No es mi idea bloquear el wp-admin/editor.php, por que lo que necesito es que no se puedan modificar perfiles. Lo que necesito es justo lo que pones en el enlace. Quizas no busque en los terminos adecuados.

      Disculpa por las molestias.

    • Si quieres que el usuario acceda wp-admin/profile.php (no editor.php) pero que no pueda editar la información, tendrás que buscar otra técnica. Si te fijas en los roles y capacidades predeterminados, la capacidad “read” es la mínima que se necesita para a acceder a wp-admin/profile.php pero no hay nada que permita “ver” esa página sin modificar la información.

      Así que vas a tener que buscar otra técnica, se me ocurren algunas pero es un tema para pensar con paciencia. No hay ninguna capacidad para eso. De todas formas, creo que sería muchísimo mejor y mushísimo más fácil mostrar la información del usuario en el frontend y bloquear el acceso el wp-admin/profile.php.

    • iván Ramos

      Finalmente he hecho algo que me está funcionando más o menos como necesito. Resumo por si pudiese resultar de interés.

      Uso los siguientes actions ‘personal_options_update’, ‘save_custmo_user_fields’
      y he creado una función que al dispararse me permite comprobar, si el usuario
      tiene capacidad para crear usuarios, si la tiene permito que se guarden las
      modificaciones y si no es así detengo el proceso con un mensaje.

      Lo cierto es que aunque funciona, aún tengo dudas sobre lo correcto de esta solución, tendré que hacer algunas pruebas adicionales y seguir investigando, pero de momento esto me sirve.

      Gracias por todo.

    • Es un workaround que puede hacer lo que querías pero desde mi punto de visto no es la solución perfecta. Primero por que la capacidad para crear usuarios no es lo mismo que poder editar o no el perfil de uno mismo; pero bueno, este sería un detalle un tanto menor.

      Lo que si me parece mal es mostrar campos editables al usuario y luego darle un error o mensaje de que no puede hacerlo. Es una user experience mala. Muy mala. Sigo pensando que sería mucho mejor mostrar al usuario la información de su perfil de forma no editable en otro sitio que no sea wp-admin/profile.php. Si no quieres que edite, ¿para que darle acceso a wp-admin/profile.php?

      Para mejorar un poco el UX podrías, al menos, deshabilitar los inputs con JavaScript.

      De todas formas, parece que esta conversación se sigue yendo del tema del post.