0

I looked at some answers here on SO and googled a bit... But couldn't make this work. I have 0 experience with Ajax and I'm new to PHP.

What I need is to change the options of the other selects based on the value of the first one. And I need to do that without reloading the page.

Why not use jQuery? Because I will have to get the values from the selects later to register the ad, and with that I end up with extra select fields, and that kinda messes up.

I'm not getting any error and it doesn't work:

Ok, I tweaked the code and here is what I have so far:

In my 'header.php'

<script>
jQuery(function($) {
    $("#opt-categorias").change(function(){
        var opt_categorias = $("#opt-categorias").val();
        $.ajax({
            type: "GET",
            url: 'gerenciamento-categorias.php?cat='+opt_categorias,
            contentType:"application/json; charset=utf-8",
            dataType: "json",
            success: function(data){
                $("#opt_tipo").empty();
                $("#opt_tipo").append("<option value=''> Tipo de produto</option>");
                $.each(data, function(i, item){
                        $("#opt_tipo").append('<option value="'+ data[i].slug +'">'+ data[i].name +'</option>');

                });
            },
            complete:function(){

            }
        }); 
    });
});
</script>

In my 'cadastro-anuncios.php'

$categorias = 'categorias';
$tax_categorias = get_terms($categorias, array('hide_empty' => false));
<div class="detalhes-artigo">
<div class="col-md-2 categorias" id="lista-categorias">
    <select id ="opt-categorias" name="opt-categorias" class="opt-categorias">
    <option value="#"> Categoria </option>
    <?php
    foreach ($tax_categorias as $tax_categoria) {
    // Check if current term ID is equal to term ID stored in database
    $selected_categorias = ( $stored_cat_categoria ==  $tax_categoria->term_id  ) ? 'selected' : '';
    echo '<option value='. $tax_categoria->slug.'' . $selected . '>' . $tax_categoria->name. '</option>';
    }
    ?>
    </select>
</div>
<div class="col-md-2 tipos" id="lista-tipos">
    <div class="col-md-2 opt_tipo">
        <select id="opt_tipo" name="opt_tipo" class="opt_tipo">
        </select>
    </div>
</div>

In my 'gerenciamento-categorias.php' (I have more options, but gonna leave just one part of it, since all have the same structure)

$tipos_bicicletas = 'tipos_bicicletas';
$tax_tipos_bicicletas = get_terms($tipos_bicicletas, array('hide_empty' =>     false));

if ( $_GET['cat'] == 'bicicleta' ) {

json_encode($tax_tipos_bicicletas);

}
2
  • Can you post what happens inside "gerenciamento-categorias.php"? Also, are you inside the WordPress environment or trying to do this with just PHP?
    – Tom
    Oct 24, 2017 at 11:13
  • 'gerenciamento-categorias.php' is the same as 'manager.php' I'm using it inside WP. Oct 24, 2017 at 11:23

1 Answer 1

3

The first step you'll need to take is to reorganize your code a little. WordPress allows you to register Ajax calls via an action, wp_ajax. This is a safer and easier way to create an ajax call that you can use with javascript.

Below I've created everything you'll need. The first two functions will be placed inside your themes functions.php and the last piece will need to be placed inside a custom.js file inside your themes root directory.

The first function calls the custom.js and queues it for loading on your theme. This is WordPress' way of sending the script up the loading chain to load inside wp_head or wp_footer, depending on your preference. We also use wp_localize_script to set up a few variables inside of javascript so we can use ajax. These are stored inside clocal, and look like this: clocal.ajaxurl and clocal.nonce. The "nonce" are security keys we use to double check a bad guy isn't attempting to attack your site via this ajax call, among other things.

/*
 * File: functions.php
 * This function will enqueue (insert) the script into the WordPress header or footer the proper way, instead of adding it directly to the header.php
 * We use wp_localize_script to inject a javascript object, clocal, into our custom.js to gain access to the variables ajaxurl and nonce.
 *
 * Source:
 * https://developer.wordpress.org/reference/functions/wp_enqueue_script/
 * https://codex.wordpress.org/Function_Reference/wp_localize_script
 * https://codex.wordpress.org/Function_Reference/wp_create_nonce
 */

add_action( 'wp_enqueue_scripts', 'cortez_enqueue_script' );
function cortez_enqueue_script() {
    wp_enqueue_script( 'cortez_custom_js', get_stylesheet_directory_uri() . '/custom.js', array( 'jQuery' ), '1.0', true );
    wp_localize_script( 'cortez_custom_js', 'clocal', array(
        'ajaxurl' => admin_url( 'admin-ajax.php' ),
        'nonce'   => wp_create_nonce( 'cortez_nonce_security_key' ),
    ) );
}

The next function is your ajax call. We use two actions, wp_ajax and wp_ajax_nopriv to enable the ajax action "cortez_get_terms". Notice the action is right inside the WordPress action: wp_ajax_cortez_get_terms. With this defined, we can request on the javascript side the action "cortez_get_terms".

At the beginning of this function you'll notice wp_verify_nonce. This is checking that security key we created in the previous function to make sure it is a valid request.

/*
 * File: functions.php
 * Add this to your functions.php to enable the ajax call to be called from custom.js. The two actions are required if you want logged in and non-logged in users to be able to use the ajax function.
 *
 * Source:
 * https://codex.wordpress.org/AJAX_in_Plugins
 * https://codex.wordpress.org/Plugin_API/Action_Reference/wp_ajax_(action)
 * https://codex.wordpress.org/Plugin_API/Action_Reference/wp_ajax_nopriv_(action)
 * https://codex.wordpress.org/Function_Reference/wp_verify_nonce
 */
add_action( 'wp_ajax_cortez_get_terms', 'cortez_get_terms' );
add_action( 'wp_ajax_nopriv_cortez_get_terms', 'cortez_get_terms' );
function cortez_get_terms() {
    $data = esc_sql( $_POST );
    if ( ! wp_verify_nonce( $data['nonce'], 'cortez_nonce_security_key' ) ) {
        wp_die( 'Security check' );
    }
    if ( ! isset( $data['term_chosen'] ) || empty( $data['term_chosen'] ) ) {
        wp_die( 'No Term Chosen' );
    }

    $tipos_bicicletas       = 'tipos_bicicletas';
    $modelos_bicicletas     = 'modelos_bicicletas';
    $marcas_bicicletas      = 'marcas_bicicletas';
    $tax_tipos_bicicletas   = get_terms( $tipos_bicicletas, array( 'hide_empty' => false ) );
    $tax_modelos_bicicletas = get_terms( $modelos_bicicletas, array( 'hide_empty' => false ) );
    $tax_marcas_bicicletas  = get_terms( $marcas_bicicletas, array( 'hide_empty' => false ) );

    $json = json_encode( $tax_tipos_bicicletas );
    if ( $data['term_chosen'] == 'bicicleta' ) {
        echo $json;
    }


    wp_die(); //stop function once you've echoed (returned) what you need.
}

Finally, we tie everything together via custom.js. This is a file you'll need to create inside your theme (wp-content/themes/YOUR_THEME/custom.js). Once created, load the following code into it. This is the same as your ajax call, only it is using the variables we set up in wp_localize_script as the url and it is a POST request, not a GET request.

Notice I am also passing a "data" attribute. This is a set of data I am going to post to the WordPress ajax handler (admin-ajax.php). This must include an "action" node that is your ajax call, which in our case is cortez_get_terms. Without this WordPress does not know what to do.

You'll see I am passing term_chosen in this data attribute as well. This is the chosen value of whichever dropdown the user chooses. We send this to the ajax script (in the previous function inside functions.php) and if you look we can use that variable to double check the users choice and output the correct data.

/*
 * Filename: custom.js
 *
 */

jQuery(function ($) {
    $("#opt-categorias").change(function () {
        var opt_categorias = $("#opt-categorias").val();
        $.ajax({
            type: "POST",
            url: clocal.ajaxurl,
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            data: {
                'action': 'cortez_get_terms',
                'nonce': clocal.nonce,
                'term_chosen': opt_categorias,
            },
            success: function (data) {
                $("#opt_tipo").empty();
                $("#opt_tipo").append("<option value=''> Tipo de produto</option>");
                $.each(data, function (i, item) {
                    $("#opt_tipo").append('<option value="' + data[i].slug + '">' + data[i].name + '</option>');

                });
            },
            error: function(error){
            },
            complete: function () {
            }
        });
    });
});

This is a quick and dirty example and there is definitely more to suggest but I think this should get you started. Be sure to take a look at the "source" links I put in the comments of the functions and let me know if you have any questions.

12
  • Dude, first of all, thnx a lot for your time, the effort to explain each step and the sources links. I could understand a little more about AJAX. I was just reading about wp_ajax, wp_ajax_nopriv and wp_verify_nonce. I followed the steps just the way you explained, and still got no result and also, no error. I dunno if the part where I use the json_encode() isn't working. Since when I was just using PHP, the variables were working without issues. Oct 24, 2017 at 12:27
  • @MarceloHenriquesCortez You're very welcome, happy to help. Take a look at my updated answer with print_r and console.log inside the code. I'm using print_r to output the data coming into the ajax script and the json that we create. Then, I use console.log to output the raw response from the ajax script. Look for this in your browsers dev tools log. I also added an "error" function to your ajax that will output an error if the ajax call is failing.
    – Tom
    Oct 24, 2017 at 13:05
  • I tried the new code. Still don't get any error, not even on console. I don't even see the 'print_r'. Double checked if all the code is in the right pages, and everything is ok. Oct 24, 2017 at 13:11
  • If that's the case then it sounds like you aren't even reaching the ajax call at all. Can you double check to make sure you're ajax javascript is firing? Did you place it inside custom.js? If so, search your site's code (in the browser) and make sure custom.js is appearing. Also, can you post a link to the site?
    – Tom
    Oct 24, 2017 at 13:21
  • The .js is being called. For some reason, now in the console, shows a number: '0', referring to the line with 'console.log(data);' in the .js. the site isn't live and I won't be able to upload it today. Oct 24, 2017 at 13:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.