Wordpress use ajax on page template

Asked

Viewed 754 times

1

Based on the topic below: http://tableless.com.br/requisicoes-ajax-no-wordpress/

I made a code to run using ajax in my WP project, the detail is that this code is in an external site area. For this area to be accessible I used a template within the theme. I thought it would be correct to put the code that registers the ajax calls in this template. Something like this:

// Adicionando um script para o Wordpress
add_action('wp_enqueue_script', 'secure_enqueue_script');
function secure_enqueue_script(){
    wp_register_script('secure-ajax-access', 
            esc_url( add_query_arg( array( 'js_global' => 1), site_url())));
    wp_enqueue_script('secure-ajax-access');
}

add_action('template_redirect', 'javascript_variaveis');
function javascript_variaveis(){
    if ( ! isset( $_GET['js_global'])) return;

    $nonce = wp_create_nonce('senha_do_dia_nonce');

    $variaveis_javascript = array(
        'senha_do_dia_nonce' => $nonce,
        'xhr_url'            => admin_url('admin-ajax.php')
    );

    $new_array = array();
    foreach ($variaveis_javascript as $key => $value) {
        $new_array[] = esc_js($key).":'".esc_js($value)."'";
    }

    header("Content-type: application/x-javascript");
    printf('var %s;','js_global',implode(',',$new_array));
    exit;
}

add_action('wp_ajax_senha_dia', 'senha_dia');
function senha_dia(){
    if ( !wp_verify_nonce($_POST['senha_do_dia_nonce'], 'senha_do_dia_nonce')) {
        echo '401';
        die();
    }

    $data_senha = $_POST['data_senha'];         
    $senha = array('senha' => calculaSenha($data_senha));

    echo json_encode($senha);
}

include_once(get_template_directory().'/painel-administrativo/index.php');

To make the call on front end, I used the code as below in a file script.js, which is loaded by the file: painel-administrativo/index.php

$(document).ready(function () {
$('#consultar').on('click', function(e){
        e.preventDefault();

        var dados_envio = {
            'senha_do_dia_nonce' : js_global.senha_do_dia_nonce,
            'data_senha' : $('#diasenha').val(),
            'action':'senha_dia'
        }

        $.ajax({
           url: js_global.xhr_url,
           type: 'POST',
           data: dados_envio,
           dataType: 'JSON',
           success: function(response){
               if (response == '401'){
                   console.error('Requisição inválida')
               } else {
                   console.log(response);
                   $('#senha').val(response);
               }

           }
        });

    });
}

It returns an error in the browser console:

ReferenceError: js_global is not defined

1 answer

5


The specific problem

The global variable js_global is not defined in the page. It seems to me that you are loading the template without using the query ?js_global=1 then the checking in template_redirect beat pass and variable is not available.

That said: this implementation is not cool. It seems a mixture of two different methods without a specific gain.

How to do Ajax in Wordpress the right way:

Before you start: There are certain ways.

  1. The most common is to request directly to the file wp-admin/admin-ajax.php and receive them on the server-side using the Hooks wp_ajax_{nome_da_funcao} and wp_ajax_nopriv_{nome_da_funcao}. This is the recommended method in Codex and in numerous other online resources. I learned using that link many years ago, and it is still current. This method has the disadvantage of not being cacheable, with each request it carries the entire back-end. It was developed primarily to be used in the back end, but also works on the front if the volume of requests is small.

  2. Less common but also very useful is to use the Rewrite API to create specific endpoints and process the data there. This method is 100% cacheable because it works by stopping loading early, and works well with higher traffic websites, for front-end requests.

  3. When Wordpress 4.7 comes out there will also be the Native REST API and then there’s another conversation and it’s gonna get a lot more interesting.

For now we will see how to implement this same code using methods 1 and 2. In both cases we will use the same form:

<form>
    <input type="text" id="dados" />
    <?php wp_nonce_field( 'recebe_dados', 'nonce' ); ?>

    <input type="submit" name="Enviar" id="botao" />
</form>

Method 1, using admin-ajax.php:

add_action( 'wp_enqueue_scripts', 'registrar_e_chamar_scripts' );
// wp_ajax_{nome} roda somente quando o usuário está logado
add_action( 'wp_ajax_funcao_que_recebe_os_dados', 'funcao_que_recebe_os_dados' );
// wp_ajax_nopriv_{nome} roda somente quando o usuário não está logado
add_action( 'wp_ajax_nopriv_funcao_que_recebe_os_dados', 'funcao_que_recebe_os_dados' );

/**
 * Essa é função que define os arquivos js a serem usados e as variáveis globais 
 * que estarão disponíveis
 * @hook wp_enqueue_scripts
 */
function registrar_e_chamar_scripts() {
    // O primeiro passo é determinar em qual arquivo está o nosso javascript, 
    // se ele tem alguma dependência, usa um numero de versão e se deve ser 
    // declarado em <head> ou ao final do HTML. wp_register_script
    wp_register_script( 'nosso_js', 
        get_template_directory_uri() . '/js/nosso.js', 
        array( 'jquery' ), false, true );

    // Uma vez registrado, colocamos na fila para ser inserido no tema. 
    // wp_enqueue_script() se encarrega de chamar o jQuery antes do nosso 
    // arquivo pra que as funções estejam disponíveis. wp_enqueue_script
    wp_enqueue_script( 'nosso_js' );

    // Agora vamos criar um objeto global 'nosso_js' para uso com o script, 
    // ele terá uma referência à url que precisamos chamar
    // wp_localize_script
    wp_localize_script( 'nosso_js', 'nosso_js', 
        array( 'ajax' => admin_url( 'admin-ajax.php' ) ) );
}

/**
 * Essa é a função que será chamada pelo Ajax. O arquivo admin_ajax age como 
 * roteador junto com as actions definidas e traz as requisições para serem 
 * recebidas aqui
 *
 * @hook wp_ajax_funcao_que_recebe_os_dados
 * @hook wp_ajax_nopriv_funcao_que_recebe_os_dados
 */
function funcao_que_recebe_os_dados() {

    // A primeira coisa a fazer é tratar o input do usuário
    $request = stripslashes_deep( $_POST );

    if ( ! wp_verify_nonce( $request['nonce'], 'recebe_dados' ) ) {
        wp_send_json_error('Nonce inválido');
    }

    // Se necessário também faça um check de permissões para o usuário
    if ( ! current_user_can( 'edit_posts' ) ) {
        wp_send_json_error('Usuário não tem permissões suficientes');
    }

    // Por fim, trate o request como desejar e envie a resposta
    $resposta = funcao_que_produz_a_resposta( $request['dados'] );

    // wp_send_json, wp_send_json_success e wp_send_json_error são funções 
    // padrão para retornar valores via Ajax. Elas se encarregam de enviar 
    // os cabeçalhos corretos e transformar os valores em JSON
    wp_send_json( $resposta );
}

in the archive nosso.js:

jQuery(document).ready(function () {
  jQuery('#botao').on('click', function(e){
    e.preventDefault();

    jQuery.ajax({
       url: nosso_js.ajax,
       type: 'POST',
       data: {
        'action': 'funcao_que_recebe_os_dados',
        'nonce': jQuery('#nonce').val(),
        'dados': jQuery('#dados').val()
       },
       success: function(response){
           // fazer alguma coisa com a resposta
           console.log(response);
       }
    });   
  });
});

Method 2, using the Rewrite API:

in the functions.php

add_action( 'init', 'criar_endpoints' );
add_action( 'template_redirect', 'funcao_que_recebe_os_dados' );
/**
 * Registra os novos endpoints. Qualquer alteração nessa função deve ser
 * seguida de uma limpeza nos permalinks. Basta salvar os permalinks novamente 
 * pelo painel.
 */
function criar_endpoints() {
    // adiciona um parâmetro "dados" às variáveis interpretadas nativamente
    add_rewrite_tag( '%dados%', '([0-9]+)' );
    // opcional, permite chamadas para URLs específicas tipo /api/dados/dado1 
    // (ao invés de ?dados=dado1), para deixar as URLs mais amigáveis. 
    // Não está sendo usado no exemplo.
    add_rewrite_rule( 'api/dados/([0-9]+)/?', 'index.php?dados=$matches[1]', 'top' );

}

/**
 * Recebe e responde às requisições
 */
function funcao_que_recebe_os_dados() {
    global $wp_query;

    $dados = $wp_query->get( 'dados' );
    $nonce = $_GET['nonce'];

    if ( empty( $dados ) || empty( $nonce ) ) {
        return;
    }

    // Conferindo o nonce
    if ( ! wp_verify_nonce( $nonce, 'recebe_dados' ) ) {
        wp_send_json_error('Nonce inválido');
    }

    // Conferindo permissões
    if ( ! current_user_can( 'edit_posts' ) ) {
        wp_send_json_error('Usuário não tem permissões suficientes');
    }

    $dados = stripslashes_deep( $dados );
    $resposta = funcao_que_produz_a_resposta( $dados ); 

    // Enviando a resposta
    wp_send_json( $resposta );
}

in the archive nosso.js:

jQuery(document).ready(function () {
  jQuery('#botao').on('click', function(e){
    e.preventDefault();

    jQuery.ajax({
       data: {
        'nonce': jQuery('#nonce').val(),
        'dados': jQuery('#dados').val()
       },
       success: function(response){
           // fazer alguma coisa com a resposta
           console.log(response);
       }
    });   
  });
});
  • Very good explanation @Ricardomaraleida, it would be interesting as soon as the Wordpress 4.7 come out you make a complement in this reply to help the people developing in Wordpress.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.