1

I have a page which I want user to be able to post info which I then upload into a database. I am doing my requests via ajax and I am trying to establish my database connection and sql querying via an action hook. First off is this a good pratice?

My code (the relative part):

HTML:

<div id="user_info">
    <input class="form-control" type="text" id="name" placeholder="Fullständigt namn" required autocomplete="off"/>
    <input class="form-control" type="text" id="email" placeholder="Email" required autocomplete="off"/>
    <input class="form-control" type="text" id="address" placeholder="Adress" required autocomplete="off"/>
    <input class="form-control" type="text" id="co_address" placeholder="C/O Adress"  autocomplete="off"/>
    <input class="form-control" type="text" id="city" placeholder="Namn" required autocomplete="off"/>
</div>

JS:

function updateDB(name, email, address, co_address, city){
    $.ajax({
        url: '/wp-admin/admin-ajax.php',
        type: 'post',
        dataType: 'json',
        data: {
            action: 'det_lilla_extra',
            name: name,
            email: email,
            address: address,
            co_address: co_address,
            city: city
        },
    });

PHP (action hook):

<?php

add_action('wp_ajax_det_lilla_extra', 'det_lilla_extra');
add_action( 'wp_ajax_nopriv_det_lilla_extra', 'det_lilla_extra' );
function det_lilla_extra(){
    global $wpdb;
    //var_dump($_POST);
    $wpdb->insert($wpdb->prepare("INSERT INTO orders (name, email, address, co_address, city) VALUES ('%s','%s','%s','%s','%s')",
    $_POST['name'], $_POST['email'], $_POST['address'], $_POST['co_address'], $_POST['city']));
    wp_die();
}

I've been able to get this far by following and looking at others. But my problem now is that for my action hook to work I need to create a plugin. I dont know how to do this, I've been googling to find turorials but I dont really know what to look for, so its kinda hard to pinpoint what to do.

So my questions:

  1. Is this "good" pratice what i have done? Could I do it another way (regarding having an action hook for database connection)

  2. Is a plugin what i need here? And if so, how do i go about creating it?

ALSO: Currently my action hook does not work since I have not enabled the plugin (i think this is the reason). But everything else should work though.

1
  • A plugin is a PHP file with a comment at the top, literally take your code and put /* Plugin Name: Vonhacts plugin */ at the top then place the file in the plugins folder, there's no special voodoo needed. Also there's no reason this wouldn't work in functions.php, but you shouldn't be creating tables, and updating them in a theme
    – Tom J Nowell
    Apr 13, 2017 at 12:44

1 Answer 1

1

First of all, see this WordPress Codex page: AJAX in Plugins

You don't technically need to write a plugin to do what you want to do, but it is good practise to do so, especially for the kind of functionality you are building. (Building a database table, handling form data, submitting with AJAX, etc.) Check out Writing a Plugin for a lot more info on that.

That being said, here's the main issues I see with your code right now.

Security risks

Right now, you're assuming that user-submitted data is always correct. This has an extremely high security risk. You should always assume that users will try to input incorrect data. To make your code more secure, you should first validate your data before inserting it into the database.

Here is a quick example of validating the data for the $_POST['name'] field, and sending a json error if the data is "invalid".

if ( !isset($_POST['name'] || strlen($_POST['name']) > 30 ) {
    // Check if 'name' is set, and the length is shorter than 30
    wp_send_json_error( 'Error: Your name should be no longer than 30 characters' );
}

Inserting data

While you are doing good using $wpdb->prepare for a raw SQL query, you don't actually need it for the $wpdb->insert function. See the Class Reference/wpdb for an example of how to use $wpdb->insert.

I've also used the correct way to use insert in the example below.

Putting it all together

First, we want to enqueue our Javascript so that WordPress can use it. We are also passing our ajaxurl (admin-ajax.php) through here for easy use in our Javascript.

function your_submit_order_scripts) {
    // Register your Javascript file
    wp_register_script( 'your-submit-order', plugin_dir_url(__FILE__) . 'js/your-submit-order.js', array( 'jquery' ), false, true );

    // Send ajaxurl as variable to this script
    $local_arr = array(
        'ajaxurl'   => admin_url( 'admin-ajax.php' )
    );

    wp_localize_script( 'your-submit-order', 'yourSubmitOrder', $local_arr );
    wp_enqueue_script( 'your-submit-order' );
}
add_action( 'wp_enqueue_scripts', 'your_submit_order_scripts' );

Next we add our callback, this will process the data that we post with AJAX. The add_action part makes sure that our AJAX post function knows where to send the data to.

// Use this callback function for logged in users
add_action('wp_ajax_det_lilla_extra', 'det_lilla_extra');

// Also allow this function to be used by non-logged in users
add_action( 'wp_ajax_nopriv_det_lilla_extra', 'det_lilla_extra' );

function det_lilla_extra(){

    // Convert form data to array
    $formdata = array();
    parse_str($_POST['formdata'], $formdata);

    // Check if name field is valid
    if ( !isset($formdata['name'] || strlen($formdata['name']) > 30 ) {
        // Check if 'name' is set, and the length is shorter than 30
        wp_send_json_error( 'Error: Your name should be no longer than 30 characters' );
    }

    // More validation goes here depending on your needs...
    // For example, is the email address a real email?
    // Is the address written in the correct format?
    // Is the city a real city?

    // If validation has no errors, insert data
    if ( $wpdb->insert( 
            'orders', 
            array( 
                'name' => $_POST['name'], 
                'email' => $_POST['email',
                // etc.
            ), 
            array( 
                '%s', 
                '%s',
                // etc.
            ) 
        ) 
    ) {
        // If $wpdb->insert was successful, send success message back to AJAX updateDB function
        wp_send_json_success(array('message' => 'Successfully uploaded!');

    } else {
        // If insert was unsuccessfull, send error message back to AJAX
        wp_send_json_error('Error: Something went wrong');
    }

    // Don't technically need it when using wp_send_json
    wp_die();
}

Finally, we make our Javascript. I have updated your updateDB function to work in a similar way to the examples posted on the WordPress Codex page linked above.

Also, since you are using a HTML form to enter data, we can make use of the jQuery serialize() function to make things easier.

function updateDB() {
    // Create the data to send with AJAX
    var data = {
        'action': 'det_lilla_extra',
        'formdata': $('form').serialize() // Convert entire form to data
    };

    // Note how we use yourSubmitOrder.ajaxurl to pass the url to admin-ajax.php
    // We set this our your_submit_order_scripts function earlier
    jQuery.post(yourSubmitOrder.ajaxurl, data, function(response) {
        if ( reponse.success == true ) {
            alert(response.data.message);
        } else {
            alert(response.data);
        }
    });
}

I probably spent way too much time writing up this answer, but hopefully it's useful to you. I've spent a lot of time figuring out the best way to use AJAX in WordPress, so I see this as giving back to every person and resource that has taught me!

If anything is unclear then feel free to comment.

1
  • I forgot to add the formdata conversion, so I added that now! You can see at the top of the callback function. Good luck!
    – Swen
    Apr 13, 2017 at 14:28

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.