Funções de usuários e Capacidades no WordPress – Parte 3: Um exemplo prático

Este artigo é a parte 3 de 3 da série Funções de usuários e Capacidades do WordPress

Esta série de três partes é um tutorial que visa cobrir bem as Funções de usuários e capacidades no WordPress. Esta séria irá cobrir a arquitetura e funcionamento das funções de usuários no WordPress; destacar as funções mais importantes para interação com usuários e gerenciamento de funções e capacidades; e no última parte, mostrar um exemplo prático que demonstra a utilidade da API do WordPress.


Introdução

Este tutorial será focado na construção de uma solução prática, usando os papéis e sistema de capacidades do WordPress. Se você perdeu os dois tutoriais anteriores, sugiro que você volte para os links no começo deste post. A primeira parte “Funções de usuários e Capacidades do WordPress – Parte 1: O básico”, explica o projeto do sistema, enquanto a segunda parte de “Funções de usuários e Capacidades no WordPress – Parte 2: Funções interessantes” se foca nas funções e classes que o WordPress oferece para interagir com o sistema.
A solução proposta neste tutorial é a mesma que o autor original da matéria, fulano, usou para um dos seus plugins Premium. Você pode facilmente adaptá-lo para o seu próprio plugin. O código está disponível no GitHub

Passo 1: Vejamos o Cenário

Vamos abstrair um pouco e imaginar que este plugin está sendo feito para o seguinte cenário: Estamos construindo um plugin para WordPress que tem um painel de administração especial para um cliente. Este painel de administração deve ser acessível apenas para um conjunto limitado de usuários, de um nível específico. Esses usuários podem ser selecionados pelo administrador do blog. Ele pode permitir diferentes funções, usuários ou todos eles para acessar o painel de administração do cliente ou suas funcionalidades.
Além disso, precisamos ter um acesso restrito à biblioteca de mídia para os usuários com acesso ao Painel de Cliente. O WordPress tem uma capacidade especial para acessar e fazer upload de arquivos para a biblioteca de mídia: upload_files. No entanto, isso dá ao usuário (ou papel), o pleno acesso à Biblioteca de mídia. Esta não é uma coisa boa, especialmente que as fotos (ou arquivos) não podem ser hierarquizados em diferentes categorias, onde você pode restringir o acesso para cada um.
Nós precisamos restringir o acesso à biblioteca de mídia apenas para os arquivos que o usuário enviou. Ele não deve ter acesso a envios de outros usuários. Esta restrição deve ser aplicada apenas para os usuários que não têm a capacidade de upload_files. Outros usuários e funções não estão preocupados com essa restrição, uma vez que já tem um acesso total à biblioteca de mídia.
O nosso blog vai ter estas quatro categorias de usuários:
categorias de usuarios
Os dois primeiros conjuntos de usuários são os que não têm acesso ao plugin ‘Painel do Cliente’. Destacamos o fato de que existem usuários que têm acesso à biblioteca de mídia e um conjunto que não tem ese acesso. É essencial que a nossa solução não afete as duas primeiras categorias e deixe suas capacidades intactas.
Com isso em mente, a nossa classe deve fazer duas coisas:

  • Defina as permissões adequadas para o terceiro e quarto conjunto de usuários
  • Ative um acesso restrito a Biblioteca de Mídias para a quarta categoria. Certifique-se de que depois de desativar o plugin ou alterar os direitos dos usuários, que esta categoria de usuários recebe de volta suas permissões originais.

Passo 2: Plugin

Antes de criar a nossa classe, vamos ter uma ideia mais profunda sobre o plugin. O plugin tem uma estrutura bastante simples. Ele é composto de dois menus diferentes: um para o administrador e serve como um painel administrativo, acessível apenas para usuários com uma capacidade de manage_options. O segundo menu é para os clientes e dá acesso ao Painel de Cliente. Este painel requer uma capacidade de wptuts_client_page.
Este recurso não existe no WordPress, precisamos adicionar e atribuí-lo aos usuários ou funções especificados. Mas antes disso, vamos dar uma olhada no plugin.

/*
  Plugin Name: WordPress Roles Plugin
  Plugin URI: https://github.com/omarabid/WordPress-Roles-Plugin
  Description: A WordPress Roles Plugin
  Author: Abid Omar
  Author URI: http://omarabid.com
  Version: 1.0
 */

// Add an Admin user menu to the WordPress Dashboard
add_action('admin_menu', 'wptuts_admin_menu');
function wptuts_admin_menu() {
    add_menu_page('Admin Access', 'Admin Access', 'manage_options', 'wptuts-admin', 'wptuts_admin_page');
}

function wptuts_admin_page() {
    echo 'Admin Page';
}

// Add a client user menu to the WordPress Dashboard
add_action('admin_menu', 'wptuts_client_menu');
function wptuts_client_menu() {
    add_menu_page('Client Access', 'Client Access', 'wptuts_client', 'wptuts-client', 'wptuts_client_page');
}

function wptuts_client_page() {
    echo 'Client Page';
}

 

Temos dois ganchos <code>”admin_menu”</code> que agregam o menu de administração, tanto para o administrador quanto para o cliente. Podemos reduzí-lo a apenas um gancho, que acrescenta os dois, mas prefiro separá-los. Cada função <code>”add_menu_page”</code> faz um gancho para outra função que irá exibir o conteúdo da página.
Em seguida, é preciso inicializar a nossa classe de papéis de usuários. O código da classe é colocado em outro arquivo, e o processo de inicialização é feita durante o gancho <code>”init”</code>, que garante que o WordPress terminou de carregar.

A função construtora aceita três parâmetros:

<ul>
<li><em>$all</em> booleano (Opcional) – Se você quiser dar ao cliente o acesso a todos os usuários do blog, você pode definir isso como <em>true</em> e ignorar os restantes parâmetros.</li>
<li><em>$roles</em> vetor (Opcional) – Um vetor com ids dos papéis que terá acesso ao painel do cliente.</li>
<li><em>$users</em> vetor (Opcional) – Um vetor com nomes dos utilizadores que irão ter acesso ao painel de cliente.</li>
</ul>

// Loads and initialize the roles class
add_action('init', 'wptuts_start_plugin');
function wptuts_start_plugin() {
    require_once('roles_class.php');
    $all = false;
    $roles = array('subscriber');
    $users = array(3);
    new wpttuts_roles($all, $roles, $users);
}

Passo 3: Classe dos papéis (roles)

A classe tem apenas 3 propriedades: $all, $roles e $users. Estas são as mesmas variáveis ​​que você passa para a função construtora. O valor das variáveis ​​não é alterado no nosso exemplo, mas em um caso prático real, você pode querer as fundir com outra fonte. Para isso, você tem a função set_entities. Você pode utilizado para suas próprias necessidades.

/**
 * @var boolean
 */
private $all;

/**
 * @var array
 */
private $roles;

/**
 * @var array
 */
private $users;

/**
 * Set the permission entities
 *
 * @param boolean $all
 * @param array $roles
 * @param array $users
 */
private function set_entities($all, $roles, $users) {
    $this->all = $all;
    $this->roles = $roles;
    $this->users = $users;
}

Função Construtora

Em uma primeiro passo, a função construtora inicializa as variáveis $all, $roles e $users utilizando a função set_entitites (). Em seguida, ele chama uma função privada para a criação das capacidades, e outra para a restrição biblioteca de mídia. Estes são exatamente os passos que definimos no nosso cenário.

/**
 * Creates a new instance of the Roles Class
 *
 * @param boolean $all
 * @param array $roles
 * @param array $users
 */
function __construct($all = false, $roles = array(), $users = array()) {
    // Set the allowed entities
    $this->set_entities($all, $roles, $users);

    // Set the user access permission
    $this->set_permissions();

    // Media Library Filter
    $this->media_filter();
}

Funções Estáticas

Funções estáticas não requerem inicialização da classe. Eles são semelhantes às funções independentes, mas simplesmente ligados à classe especificada. Decidimos manter algumas funções estática porque eles podem ser usados ​​de forma independente, e elas podem ser úteis em outro contexto.
Estas funções são filter_roles() e filter_users() e que estes estão associados com duas outras funções role_has_caps() e user_has_caps(). As funções desempenham o papel de um filtro. Eles papéis de filtro (ou usuários), com base nos recursos que têm e não têm.
Ambas aceitam dois argumentos:

  • $include Vetor de capacidades que o papel tem.
  • $exclude Vetor de capacidades que o papel não tem
/**
 * Filter all roles of the blog based on capabilities
 *
 * @static
 * @param array $include Array of capabilities to include
 * @param array $exclude Array of capabilities to exclude
 * @return array
 */
static function filter_roles($include, $exclude) {
    $filtered_roles = array();
    global $wp_roles;
    $roles = $wp_roles->get_names();
    foreach ($roles as $role_id => $role_name) {
        $role = get_role($role_id);
        if (self::role_has_caps($role, $include) && !self::role_has_caps($role, $exclude)) {
            $filtered_roles[] = $role_id;
        }
    }
    return $filtered_roles;
}

/**
 * Filter all users of the blog based on capabilities
 *
 * @static
 * @param array $include Array of capabilities to include
 * @param array $exclude Array of capabilities to exclude
 * @return array
 */
static function filter_users($include, $exclude) {
    $filtered_users = array();
    $users = get_users();
    foreach ($users as $user) {
        $user = new WP_User($user->ID);
        if (self::user_has_caps($user, $include) && !self::user_has_caps($user, $exclude)) {
            $filtered_users[] = $user->ID;
        }
    }
    return $filtered_users;
}

A função faz um loop por todas as funções e usuários no banco de dados. Para cada função (ou usuário), ele verifica se tem as capacidades necessárias, e não tem a capacidade de excluir. Esta verificação é feita com as funções<code>role_has_caps()</code> e <code>user_has_caps()</code>.
Essas duas funções <code>(role_has_caps () e user_has_caps ())</code> aceitam dois argumentos:
<ul>
<li><code>$role (ou $ user)</code><em>String</em> O ID do papel ou do usuário.</li>
<li><code>$caps</code><em>Vetor</em> Um vetor de capacidades a serem checadas.</li>
</ul>
Se o papel (ou usuário) tem os recursos especificados no array <code>$caps</code>, a função retornará verdadeiro. No outro caso, a função retorna falso. A função basicamente percorre cada capacidade e verifica se o papel (ou usuário) tem a capacidade especificada.

/**
 * Returns true if a role has the capabilities in the passed array
 *
 * @static
 * @param $role
 * @param $caps
 * @return bool
 */
static function role_has_caps($role, $caps) {
    foreach ($caps as $cap) {
        if (!$role->has_cap($cap)) {
            return false;
        }
    }
    return true;
}

/**
 * Returns true if a user has the capabilities in the passed array
 *
 * @static
 * @param $user
 * @param $caps
 * @return bool
 */
static function user_has_caps($user, $caps) {
    foreach ($caps as $cap) {
        if (!$user->has_cap($cap)) {
            return false;
        }
    }
    return true;
}

 

Adicionando Permissões

Este é o primeiro passo para organizar nosso plugin. Distribuímos a funcionalidade dele por 3 funções: uma para definir as permissões para todos os usuários, um para definir as permissões aos papéis, e outro para definir as permissões para os usuários especificados. A principal função simplesmente decide que funcão chamar.

/**
 * Set the Menu and Pages access permissions
 */
private function set_permissions() {
    $this->set_all_permissions();
    if (!$this->all) {
        $this->set_roles_permissions();
        $this->set_users_permissions();
    }
}

A função set_all_permissions () percorre todos os usuários do blog, e adiciona (ou remove) a capacidade wptuts_client, dependendo do valor da variável $all. Temos a lista completa de usuários utilizando a função get_users () e inicializamos um novo objeto wp_user para ter acesso as funções add_cap () e remove_cap ().

/**
 * Set the permissions for ALL users
 */
private function set_all_permissions() {
    $users = get_users();
    foreach ($users as $user) {
        $user = new WP_User($user->ID);
        if ($this->all) {
            $user->add_cap('wptuts_client');
        }
        else {
            $user->remove_cap('wptuts_client');
        }
    }
}

A função set_roles_permissions() percorre todos os papéis no blog e elimina a capacidade wptuts_client. Depois disso, ele percorre papéis no array $roles e adiciona a capacidade wptuts_client. O primeiro passo foi assegurar que limpamos a capacidade de papéis podem já ter sido alterados.

/**
 * Set the permissions for Roles
 */
private function set_roles_permissions() {
    global $wp_roles;
    $roles = $wp_roles->get_names();
    foreach ($roles as $role_id => $role_name) {
        $role = get_role($role_id);
        $role->remove_cap('wptuts_client');
    }
    if (!empty($this->roles)) {
        foreach ($this->roles as $role_id) {
            $role = get_role($role_id);
            $role->add_cap('wptuts_client');
        }
    }
}

A função set_users_permissions() faz a mesma coisa da função acima, mas com a diferença de ser focada em usuários, não em papéis.

/**
 * Set the permissions for specific Users
 */
private function set_users_permissions() {
    $users = get_users();
    foreach ($users as $user) {
        $user = new WP_User($user->ID);
        $user->remove_cap('wptuts_client');
    }
    if (!empty($this->users)) {
        foreach ($this->users as $user_id) {
            $user = new WP_User($user_id);
            $user->add_cap('wptuts_client');
        }
    }
}

Filtro da Biblioteca de Mídias

Agora temos que definir as permissões corretas para as entidades adequadas. (Ser um usuário ou um papel) Temos também que restringir o acesso à biblioteca de mídia para a quarta categoria que distingue no cenário.
Esta categoria de funções (ou utilizadores) tem a capacidade wptuts_client, mas não tem a capacidade upload_files. E é aí que as nossas funções de filtro entram em jogo. Eles vão nos ajudar a filtrar e retornar esta categoria de papéis (ou usuários).
Para esta categoria, vamos adicionar duas capacidades, upload_files e remove_upload_files. O upload_files vai dar pleno acesso à Biblioteca de mídia, e a outra capacidade será usada para retirar a biblioteca de mídia dos posts, e também vai ser usada para remover a capacidade de upload_files uma vez que a capacidade de wptuts_client for removida.

/**
 * Restrict Media Access
 */
private function media_filter() {
    // Apply the media filter for current Clients
    $roles = self::filter_roles(array('wptuts_client'), array('upload_files'));
    $users = self::filter_users(array('wptuts_client'), array('upload_files'));
    $this->roles_add_cap($roles, 'upload_files');
    $this->roles_add_cap($roles, 'remove_upload_files');
    $this->users_add_cap($users, 'upload_files');
    $this->users_add_cap($users, 'remove_upload_files');

    // Restrict Media Library access
    add_filter('parse_query', array(&$this, 'restrict_media_library'));

    // For cleaning purposes
    $clean_roles = self::filter_roles(array('remove_upload_files'), array('wptuts_client'));
    $clean_users = self::filter_users(array('remove_upload_files'), array('wptuts_client'));
    $this->roles_remove_cap($clean_roles, 'upload_files');
    $this->roles_remove_cap($clean_roles, 'remove_upload_files');
    $this->users_remove_cap($clean_users, 'upload_files');
    $this->users_remove_cap($clean_users, 'remove_upload_files');
}

Depois de definir as capacidades para esta categoria, fazemos um gancho no filtro parse_query. Este filtro permite alterar as mensagens retornadas pelo WP_Query. No nosso caso, vamos definir a variável de consulta author. Isto resulta em retornar apenas as mensagens criadas pelo autor especificado.

/**
 * Restrict Media Library access
 *
 * @param $wp_query
 */
public function restrict_media_library($wp_query) {
    if (strpos($_SERVER['REQUEST_URI'], '/wp-admin/upload.php')) {
        if (current_user_can('remove_upload_files')) {
            global $current_user;
            $wp_query->set('author', $current_user->ID);
        }
    }
    else if (strpos($_SERVER['REQUEST_URI'], '/wp-admin/media-upload.php')) {
        if (current_user_can('remove_upload_files')) {
            global $current_user;
            $wp_query->set('author', $current_user->ID);
        }
    }
}

Resultado final: código completo do plugin

if (!class_exists('wpttuts_roles')) {
    class wpttuts_roles {
        /**
         * Determines if all users will have the required permissions
         *
         * @var boolean
         */
        private $all;

        /**
         * An array with the roles which have the required permissions
         *
         * @var array
         */
        private $roles;

        /**
         * An array with the user names which have the required permissions
         *
         * @var array
         */
        private $users;

        /**
         * Creates a new instance of the Roles Class 
         *
         * @param boolean $all
         * @param array $roles
         * @param array $users
         */
        function __construct($all = false, $roles = array(), $users = array()) {
            // Set the allowed entities
            $this->set_entities($all, $roles, $users);

            // Set the user access permission
            $this->set_permissions();

            // Media Library Filter
            $this->media_filter();
        }

        /**
         * Set the permission entities
         *
         * @param boolean $all
         * @param array $roles
         * @param array $users
         */
        private function set_entities($all, $roles, $users) {
            $this->all = $all;
            $this->roles = $roles;
            $this->users = $users;
        }

        /**
         * Set the Menu and Pages access permissions
         */
        private function set_permissions() {
            $this->set_all_permissions();
            if (!$this->all) {
                $this->set_roles_permissions();
                $this->set_users_permissions();
            }
        }

        /**
         * Set the permissions for ALL users
         */
        private function set_all_permissions() {
            $users = get_users();
            foreach ($users as $user) {
                $user = new WP_User($user->ID);
                if ($this->all) {
                    $user->add_cap('wptuts_client');
                }
                else {
                    $user->remove_cap('wptuts_client');
                }
            }
        }

        /**
         * Set the permissions for Roles
         */
        private function set_roles_permissions() {
            global $wp_roles;
            $roles = $wp_roles->get_names();
            foreach ($roles as $role_id => $role_name) {
                $role = get_role($role_id);
                $role->remove_cap('wptuts_client');
            }
            if (!empty($this->roles)) {
                foreach ($this->roles as $role_id) {
                    $role = get_role($role_id);
                    $role->add_cap('wptuts_client');
                }
            }
        }

        /**
         * Set the permissions for specific Users
         */
        private function set_users_permissions() {
            $users = get_users();
            foreach ($users as $user) {
                $user = new WP_User($user->ID);
                $user->remove_cap('wptuts_client');
            }
            if (!empty($this->users)) {
                foreach ($this->users as $user_id) {
                    $user = new WP_User($user_id);
                    $user->add_cap('wptuts_client');
                }
            }
        }

        /**
         * Restrict Media Access
         */
        private function media_filter() {
            // Apply the media filter for currenct AdPress Clients
            $roles = self::filter_roles(array('wptuts_client'), array('upload_files'));
            $users = self::filter_users(array('wptuts_client'), array('upload_files'));
            $this->roles_add_cap($roles, 'upload_files');
            $this->roles_add_cap($roles, 'remove_upload_files');
            $this->users_add_cap($users, 'upload_files');
            $this->users_add_cap($users, 'remove_upload_files');

            // Restrict Media Library access
            add_filter('parse_query', array(&$this, 'restrict_media_library'));

            // For cleaning purposes
            $clean_roles = self::filter_roles(array('remove_upload_files'), array('wptuts_client'));
            $clean_users = self::filter_users(array('remove_upload_files'), array('wptuts_client'));
            $this->roles_remove_cap($clean_roles, 'upload_files');
            $this->roles_remove_cap($clean_roles, 'remove_upload_files');
            $this->users_remove_cap($clean_users, 'upload_files');
            $this->users_remove_cap($clean_users, 'remove_upload_files');
        }

        /**
         * Add a capability to an Array of roles
         *
         * @param $roles
         * @param $cap
         */
        private function roles_add_cap($roles, $cap) {
            foreach ($roles as $role) {
                $role = get_role($role);
                $role->add_cap($cap);
            }
        }

        /**
         * Add a capability to an Array of users
         *
         * @param $users
         * @param $cap
         */
        private function users_add_cap($users, $cap) {
            foreach ($users as $user) {
                $user = new WP_User($user);
                $user->add_cap($cap);
            }
        }

        /**
         * Remove a capability from an Array of roles
         *
         * @param $roles
         * @param $cap
         */
        private function roles_remove_cap($roles, $cap) {
            foreach ($roles as $role) {
                $role = get_role($role);
                $role->remove_cap($cap);
            }
        }

        /**
         * Remove a capability from an Array of users
         *
         * @param $users
         * @param $cap
         */
        private function users_remove_cap($users, $cap) {
            foreach ($users as $user) {
                $user = new WP_User($user);
                $user->remove_cap($cap);
            }
        }

        /**
         * Filter all roles of the blog based on capabilities
         *
         * @static
         * @param array $include Array of capabilities to include
         * @param array $exclude Array of capabilities to exclude
         * @return array
         */
        static function filter_roles($include, $exclude) {
            $filtered_roles = array();
            global $wp_roles;
            $roles = $wp_roles->get_names();
            foreach ($roles as $role_id => $role_name) {
                $role = get_role($role_id);
                if (self::role_has_caps($role, $include) && !self::role_has_caps($role, $exclude)) {
                    $filtered_roles[] = $role_id;
                }
            }
            return $filtered_roles;
        }

        /**
         * Returns true if a role has the capabilities in the passed array
         *
         * @static
         * @param $role
         * @param $caps
         * @return bool
         */
        static function role_has_caps($role, $caps) {
            foreach ($caps as $cap) {
                if (!$role->has_cap($cap)) {
                    return false;
                }
            }
            return true;
        }

        /**
         * Filter all users of the blog based on capabilities
         *
         * @static
         * @param array $include Array of capabilities to include
         * @param array $exclude Array of capabilities to exclude
         * @return array
         */
        static function filter_users($include, $exclude) {
            $filtered_users = array();
            $users = get_users();
            foreach ($users as $user) {
                $user = new WP_User($user->ID);
                if (self::user_has_caps($user, $include) && !self::user_has_caps($user, $exclude)) {
                    $filtered_users[] = $user->ID;
                }
            }
            return $filtered_users;
        }

        /**
         * Returns true if a user has the capabilities in the passed array
         *
         * @static
         * @param $user
         * @param $caps
         * @return bool
         */
        static function user_has_caps($user, $caps) {
            foreach ($caps as $cap) {
                if (!$user->has_cap($cap)) {
                    return false;
                }
            }
            return true;
        }

        /**
         * Restrict Media Library access
         *
         * @param $wp_query
         */
        public function restrict_media_library($wp_query) {
            if (strpos($_SERVER['REQUEST_URI'], '/wp-admin/upload.php')) {
                if (current_user_can('remove_upload_files')) {
                    global $current_user;
                    $wp_query->set('author', $current_user->ID);
                }
            }
            else if (strpos($_SERVER['REQUEST_URI'], '/wp-admin/media-upload.php')) {
                if (current_user_can('remove_upload_files')) {
                    global $current_user;
                    $wp_query->set('author', $current_user->ID);
                }
            }
        }

    }
}

Conclusão

Neste tutorial, usamos o material ensinado nos dois posts anteriorespara criar uma solução personalizada para as funções e capacidades. A solução foi encapsulada em uma classe que pode ser personalizado para suas próprias necessidades ou plugins. Você pode encontrar o código no Github.

Agora sim, você domina tudo sobre Funções(papeis) e Capacidades do WordPress!

Fonte: O texto acima é uma tradução livre do artigo escrito por Abid Omar e publicado originalmente no site WP Tuts

Deixe uma resposta