O WordPress possui uma série de recursos para tratar os erros de processamento do sistema, como o sistema de Debug, a classe WP_Error e a função wp_die. Com essas funcionalidades a manipulação e o tratamento dos mais variados tipos de erros no WordPress pode ser feito de modo bem estruturado. Análise detalhada do código, organização dos erros gerados, interrupção da execução do script, exibir erros em tela e outras funcionalidades você começa a conhecer agora.

WP_DEBUG – Debug no WordPress

Por padrão o debug no WordPress está desativado. Para ativá-lo você precisa ter acesso ao arquivo wp-config.php da sua instalação WordPress. Dentro do arquivo de configuração altere a linha de comando que atribui o debug como false, para verdadeiro:

define( 'WP_DEBUG', true );

Para desabilitar o debug, basta retornar o valor da constante como sendo falso. Você pode definir, ainda dentro do wp-config.php, a criação de um log dos erros obtidos pelo debug.

WP_DEBUG_LOG – Alterar arquivo de log de erros (debug.log)

A definição de WP_DEBUG_LOG permite que todos os tipos de erros colhidos durante uma requisição ao WordPress sejam salvos no arquivo debug.log dentro do diretório /wp-content.

define( 'WP_DEBUG_LOG', true );

Caso prefira, você pode alterar o nome ou esse arquivo de lugar para manter os registros em um local mais reservado a equipe de desenvolvimento. Para fazer essa alteração do local e o nome do arquivo que receberão os registros de log, configure através do PHP puro:

@ini_set( 'error_log','/public/logs/wp_errors.log' );

debug.log e novas entradas

Uma aplicação para esse arquivo de log de erros (debug.log) seria usá-lo como estratégia para controle de ações de um site em WordPress. Situações críticas do Tema, permissões do Plugin e o comportamento do usuário diante do site pode ser arquivado dentro do arquivo de log para verificações futuras. A criação de uma nova entrada no arquivo de log é feita através da função error_log do PHP.

Um exemplo prático para fazer uso desse arquivo de log é verificar as tentativas de acesso a posts privados do seu WordPress. Em geral esses posts não são listados para usuários deslogados, então caso exista um volume muito grande de requisições a essas URL’s algo pode estar acontecendo de errado. Abaixo está demonstrada a verificação para todos os conteúdos do tipo post.

add_action( 'wp', 'fn_user_logged' );

function fn_user_logged()
{
    $path = get_query_var( 'name' );
    $p = get_page_by_path( $path, OBJECT, 'post' );
    if ( !is_a( $p, 'WP_Post' ) )
        return false;

    $log = '';
    if ( !is_user_logged_in() && ( $p->post_status == 'private' ) )
        $log = sprintf(
            'Usuário não logado tentando acessar o post [%d] "%s"',
            $p->ID, $p->post_title
        );

    if ( $log )
        error_log( $log );
}

WP_DEBUG_DISPLAY – Erros em tela

Com o debug ativo, você pode optar por exibir ou não os erros capturados em tela através da constante WP_DEBUG_DISPLAY.

define( 'WP_DEBUG_DISPLAY', true );

Caso a constante esteja habilitada (setada como verdadeira), os erros são exibidos logo que ocorrem. Da mesma forma que você pôde alterar as configurações de log, fique a vontade para personalizar os tipos de erros a serem exibidos em tela com o PHP nativo:

// Especifique o tipo de erro ou false se não deseja exibí-los de forma alguma
@ini_set( 'display_errors', E_ALL );

A definição completa do debug para códigos PHP no arquivo de configurações com as três constantes:

define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', true);

Assim como foi visto nos exemplos acima, a função ini_set do PHP pode substituir a definição das constantes por:

ini_set( 'display_errors', 1 );
ini_set( 'log_errors', 1 );

Utilize ainda o parâmetro error_reporting para definir quais erros devem ser capturados pela aplicação:

ini_set( 'error_reporting', E_ALL );

No entanto, vale a ressalva que ao fazer uso da funcionalidade debug no WordPress (com as constantes) você garante a compatibilidade com Temas e Plugins que eventualmente fazem uso desse sistema de debug para controle interno de seus respectivos códigos.

SCRIPT_DEBUG – Debug de códigos JavaScript no WordPress

Quando você está realizando o debug de um projeto, outra parte muito importante desse processo é analisar também os códigos JavaScript. Para que seja possível analisar melhor o que está acontecendo dentro do WordPress é preciso definir o uso de uma constante específica:

define( 'SCRIPT_DEBUG', true );

Perceba que os arquivos de script do WordPress que são incorporados ao sistema são todos compactados, de modo que sua leitura e compreensão ficam dificultados aos humanos (porém otimizados as máquinas). Ao atribuir a constante SCRIPT_DEBUG como verdadeira, esse comportamento se inverte; o WordPress passa a incorporar os mesmos arquivos porém sem a minificação. Desse modo se algum erro acontecer, você consegue saber em qual arquivo, linha e instrução ele está sendo disparado.

new WP_Error();

Melhor que tratar os erros que aparecem em seu site é a prevenção dos mesmos. Prever a ocorrência de erros é uma tarefa fundamental para manter a consistência de seu projeto. Para auxiliar no processo de testes, verificação e validação do código em recursos WordPress; você pode optar por utilizar a classe WP_Error. Através da criação de objetos dessa classe você será capaz de organizar e exibir (quando necessário) a ocorrência de erros em sua aplicação.

Especificações da classe

Com o propósito de manipular os erros em seusprojetos, o WordPress disponibiliza a classe WP_Error. Tanto para plugins, quanto para os próprios arquivos do WordPress a classe armazena códigos e mensagens de cada erro por ela captado.

Para trabalhar com a classe WP_Error, é importante conhecer suas propriedades e métodos. A classe é constituída por Código, Mensagem e Dados. Entenda um pouco da estrutura da classe através de suas duas propriedades, $errors e $error_data.

A propriedade $errors é um array que contém uma lista de erros. A outra propriedade, $error_data também é um array, mas este contém listas de dados referentes aos erros organizados por código.

Métodos da classe WP_Error

Além dessas duas propriedades, a classe WP_Error possui alguns métodos úteis para a manipulação dos problemas encontrados:

__construct – O construtor da classe permite atribuir um erro no momento em que é definido. O parâmetro $code será responsável por organizar as mensagens e dados dos erros, portanto trate de estabelecer um valor a ele;

get_error_codes – Recupera todos os códigos de erro através de um array;

get_error_code – Retorna apenas o primeiro código de erro disponível. Retorna vazio caso não houver nenhum código de erro definido;

get_error_messages – Obtém as mensagens de erro de um ou mais códigos passados como parâmetro;

get_error_message – Uma única mensagem de erro, a primeira encontrada é obtida;

get_error_data – De acordo com o código passado, retorna os dados atrelados a ele;

add – Adicione novas mensagens de erro ao objeto criado;

add_data – Inserção de um dado para um código de erro, cada código de erro pode conter apenas um dado atribuído;

remove – Apague todas as mensagens e dados vinculados ao código de erro passado como parâmetro.

WP_Error em funcionamento

Agora que você já conheceu a classe WP_Error com seus métodos e propriedades, veja como poderá colocar essa técnica de tratamento de erros em prática. Em uma sistema que requer dados provenientes de requisições a serviços externos, caso os dados não tenham sido obtidos você pode definir:

$err = new WP_Error( 'remote', 'Nenhum dado obtido pelo servidor remoto...', 'Problemas com o servidor remoto' );

Com isso você terá um objeto WP_Error definido e já com um erro atribuído. Imagine agora que a solicitação ao outro servidor foi feita, porém não retornou o conteúdo esperado; você pode então adicionar um novo erro a sua instância:

$err->add( 'remote', 'Dados inconsistentes' );

Perceba que o valor de $error_data não foi passado, caso tivesse sido ele iria sobrepor o valor inicialmente criado. Outro detalhe importante é notar a organização dos erros: um único código possui um único dado (em nosso exemplo a definição do erro, do que ele trata), porém várias mensagens (pois diferentes tipos de erros podem ocorrer acerca de um mesmo assunto).

Uso aplicado da classe WP_Error em formulários

Veja no exemplo abaixo como você poderá aplicar as definições apresentadas para a validação de um formulário. A validação verifica a ocorrência de erros e atribui diferentes mensagens para cada campo analisado.

// $fields = array( 'name', 'email', 'message' );
function form_validate( $fields )
{
    $v = array();
    $err = new WP_Error;
    foreach ( $fields as $field ) {
        $v[ $field ] = ( isset( $_POST[ $field ] ) ) ? sanitize_text_field( $_POST[ $field ] ) : false;
        if ( !$v[ $field ] )
            $err->add( 'field', sprintf( 'Campo $_POST[ "%s" ] vazio', $field ) );
    }

    if ( !ctype_alpha( $v[ 'name' ] ) )
        $err->add( 'field-name', 'Nome inválido', 'Campo "Nome"' );

    if ( !is_email( $v[ 'email' ] ) )
        $err->add( 'field-email', 'E-mail inválido', 'Campo "E-mail"' );

    if ( strlen( $v[ 'message' ] ) < 10 ) 
        $err->add( 'field-message', 'Mensagem muito curta', 'Campo "Mensagem"' );

    if ( strlen( $v[ 'message' ] ) > 255 )
        $err->add( 'field-message', 'Mensagem muito longa' );

    if ( is_wp_error( $err ) ) {
        echo '<ul>';
        foreach ( $err->get_error_messages() as $msg ) {
            printf( '<li>%s</li>', $msg );
        }
        echo '</ul>';
    }
}

Note que no início, ao fazer a varredura e sanitização de todos os campos, o mesmo erro de campo vazio adiciona diferentes mensagens ao objeto WP_Error, referenciando cada campo com o problema encontrado. Caso todos os campos estejam sem preenchimento, o objeto terá três mensagens de erros diferentes para o mesmo código.

Em sequência os campos são verificados separadamente e criado um código para cada um deles a fim de evidenciar problemas específicos. Os dados dos erros estão sendo usados para explicar a que o código se refere (no caso, o campo em questão). Por tal razão não foi atribuído um novo valor para o campo mensagem na segunda condição, pois trata-se do mesmo campo e não é pretendido sobrescrever essa descrição. Ao final as mensagens são recuperadas e exibidas em formato de lista no HTML do site.

wp_die();

Muitas vezes ao programar um recurso você precisa interromper bruscamente o acesso e a navegação do seu usuário. Seja por problemas com os dados trafegados, acesso não permitido, problemas de validação de dados ou autenticação; sempre que isso ocorre no WordPress, o sistema exibe essa tela a você.

WordPress wp_die()

Você também pode fazer uso desse recurso do WordPress e interromper a execução do seu código a qualquer instante com a função wp_die.

<?php wp_die( 'Não foi possível processar sua requisição...' ); ?>

Como foi exemplificado acima esse recurso é muito útil em várias situações e uma técnica muito interessante de ser empregada em seu Tema ou Plugin é justamente a personalização dessa tela de erro. Desse modo você pode criar uma tela específica para exibir erros ao seu visitante, essa tela pode conter algum formulário de reportar problemas ou talvez você queira disparar notificações automáticas ao admin quando algum problema do gênero acontecer.

Personalizar erros de execução no WordPress com wp_die

A função wp_die permite o uso de três parâmetros, sendo eles a mensagem do erro, um título e argumentos diversos que você queira transmitir do erro a sua função.

// a definição da função é
wp_die( $message = '', $title = '', $args = array() ){ ... }

O primeiro passo a ser feito é definir qual a função de callback deve ser chamada quando for usada a função wp_die, ou seja, você troca o manipulador das rotinas padrões do WordPress (que estão na função wp_die_handler) e passa a utilizar uma função própria.

add_filter( 'wp_die_handler', function(){ return 'fn_die'; } );

function fn_die( $msg, $title, $args ) 
{
    if ( !$title ) $title = 'Erro de execução'; ?>
    <div class="error-section">
        <h1 class="error-title">
            <?php echo $title; ?>
        </h1>
        <div class="error-content">
            <?php echo $msg; ?>
        </div>
    </div>
    <?php
    die();
}

Faça o teste disparando um erro qualquer, como:

wp_die( 'Informe o código antes de seguir', 'Código inválido' );

Como sugestão ao terceiro parâmetro você pode passar alguma informação que diz repeito a continuidade de navegação do seu usuário. Em uma situação onde ele tentou acessar uma área restrita sem permissão, você pode exibir a ele um link de login para que ele possa entrar no sistema e seguir a utilização normal do site.

function fn_die( ...
    // antes do comando die
    <?php
    if ( isset( $args[ 'login' ] ) && $args[ 'login' ] ) {
        printf(
            '<p><a href="%1$s" title="%2$s">%2$s</a></p>',
            wp_login_url(),
            'Fazer login'
        );
    }
    die();
}
// teste usando
wp_die( 'Sua sessão expirou', false, array( 'login' => true ) );

Erros com wp_die em requisições AJAX

Outra customização bem interessante de ser feita é criar um manipulador (handler) personalizado para os erros disparados com wp_die dentro de requisições AJAX. Com essa personalização você consegue estruturar um padrão de resposta aos seus códigos de scripts e poderá usar a mesma função para tratar os erros desse tipo de requisição.

Ao invés de criar o filtro para wp_die_handler, você deve utilizar agora wp_die_ajax_handler e definir qual será sua função de callback. Depois disso, basta a você personalizar o retorno dos dados ao JavaScript como bem entender; seja em HTML, XML, JSON ou qualquer outro formato que preferir.

add_action( 'wp_die_ajax_handler', function(){ return 'fn_die_ajax'; } );

function fn_die_ajax( $msg, $code )
{
    $error = array(
        'error' => true,
        'code' => $code,
        'msg' => $msg
    );
    die( json_encode( $error ) );
}

Admin Notices

Saber prevenir e tratar os erros no WordPress é fundamental para a realização do trabalho de um WordPress Developer. Desenvolvendo recursos para o painel de controle (Dashboard) é importante apresentar mensagens de erro, sucesso e aviso aos demais usuários. Isso permite informar a situação do recurso diante das ações que estão sendo realizadas.

Uma vez que determinada ação foi processada no Dashboard pelo seu Tema ou Plugin, através do gancho admin_notices você pode exibir mensagens no topo da tela.

Notificações no Dashboard do WordPress

Através de classes específicas é possível definir a formatação padrão dessas mensagens como sendo de sucesso (ação ocorreu como previsto), erro (algo não aconteceu como previsto) ou alerta (evidenciando algo que precisa ser feito).

add_action( 'admin_notices', 'fn_notices' );
function fn_notices()
{
    ?>
    <div class="notice notice-success is-dismissible">
        <p>Alguma atualização aconteceu, boa!</p>
    </div>
    <div class="notice notice-error is-dismissible">
        <p>Ops, algo de errado com o recurso...</p>
    </div>
    <div class="notice notice-warning is-dismissible" id="custom-dismiss">
        <p>A ação aconteceu, mas atenção com suas ações.</p>
    </div>
    <?php
}

A classe da tag HTML notice faz a formatação comum a todas as mensagens e as classes notice-successnotice-error e notice-warning são responsáveis pelas diferentes formatações. O uso de is-dismissible permite inserir um botão de fechar na mensagem.

Controle de Admin Notices via AJAX

Uma forma interessante de incrementar essa funcionalidade padrão do WordPress é exibir os erros ou avisos até que o usuário opte por não recebê-los mais.

Como foi mostrado acima, usando a exibição das mensagens com o gancho admin_notices e o uso da classe is-dismissible, o usuário tem a possibilidade de fechar as mensagens exibidas. No entanto, caso nenhum tratamento seja feito essa mensagem tornará a aparecer caso qualquer página do Dashboard seja aberta em seguida.

Para resolver esse problema é preciso inserir uma ação via AJAX no momento em que o clique do botão fechar é feito. A verificação se o clique no botão fechar da mensagem foi ou não feito será controlado por uma opção (da tabela wp_options).

add_action( 'admin_notices', 'fn_notices' );
function fn_notices()
{
    ?>
    if ( !get_option( 'custom_dismiss' ) ) { ?>
    <div class="notice notice-warning is-dismissible" id="custom-dismiss">
        <p>A ação aconteceu, mas atenção com suas ações.</p>
    </div>
    <?php }
}

A mensagem apenas é exibida se a opção não existir. O id na tag HTML foi inserido para facilitar a identificação do elemento na chamada AJAX:

add_action( 'admin_print_footer_scripts', 'fn_notices_js', 11 );
function fn_notices_js()
{
    ?>
    <script type="text/javascript">
        jQuery(document).on( 'click', '#custom-dismiss .notice-dismiss', function() {
            jQuery.ajax({
                url: ajaxurl,
                data: {
                    action: 'custom_dismiss'
                }
            })
        })
    </script>
    <?php
}

Inserido o script no rodapé do Dashboard (após ter sido carregada a jQuery), basta criar um callback na chamada AJAX para criar a opção no banco de dados.

add_action( 'wp_ajax_custom_dismiss', 'fn_notices_dismiss' );
function fn_notices_dismiss()
{
    add_option( 'custom_dismiss', '1' );
}