Best practices on responding to AJAX calls in Wordpress Plugins
Tags: wordpress, php
Published: 2020-11-20 10:28:28

_Preface (you can skip it, if you want): A customer came up to me with a request to build an application and combine it with an existing Wordpress installation. At the beginning I was hesitant, but I found, that using "Wordpress as a Backend" has quite a few advantages: It has baked-in user roles and capabilites and you can use already existing plugins to simplify your own development._

## Task

As I mentioned in the preface, using Wordpress as a backend comes with a few benefits, I decided to program the new application as a plugin. But I neither wanted to use the (sometimes weird) combination of PHP and HTML nor send all the needed data via forms to the backend.

I wanted to stick with tools I was more familiar with:
* I choose Vue.js as my frontend for the application.
* And the backend would be a Wordpress plugin.

When developing with a frontend framework like Vue.js, you have to use AJAX calls for communication with your backend. And that's when I found out, that the existing documentation on AJAX with Wordpress feels quite old (https://codex.wordpress.org/AJAX_in_Plugins) and there are no complete code examples and no best practices on how to work with AJAX calls when using Wordpress.

## Content
In this article I will not only cover "AJAX with Wordpress", but also a few related topics:
- Wordpress AJAX basics
- Responding to AJAX calls from your Wordpress plugin
- Authorization
- Frontend best-practices
- Ship your frontend together with your plugin
- Nonces

## Wordpress AJAX basics

Please turn on debugging (https://wordpress.org/support/article/debugging-in-wordpress/) by using both `WP_DEBUG` and `WP_DEBUG_LOG`, it will make your life easier :)

[This wordpress article](https://codex.wordpress.org/AJAX_in_Plugins#Debugging) explains the basics of responding to ajax calls.

Here is a Gist which also describes everything you should know:

{% gist https://gist.github.com/Junkern/1c94eb0e62a90ca3c902547b0de5e077 %}


One thing to remark: You always have to check for permissions in your AJAX calls


## Responding to AJAX calls

Within your functions it is highly recommended to use `wp_send_json_success` or `wp_send_json_error` functions to send data back to the client ([here is a informative stackexchange post on that](https://wordpress.stackexchange.com/questions/149158/why-use-wp-send-json-over-echo-json-encode))

On default settings, the client has to send all data as `x-www-form-url`, otherwise you cannot access it with `$_POST['something']`. I did not like that and [found a way to send parse the data when using application/json Content-Type](https://wordpress.stackexchange.com/questions/177554/allowing-admin-ajax-php-to-receive-application-json-instead-of-x-www-form-url):
```php
$data = json_decode(file_get_contents('php://input'));
```
Now your `$data` variable contains all the request data. You could now use object destructuring to access the data more easily ([but it depends on your PHP version](https://stackoverflow.com/questions/28232945/destructuring-assignment-in-php-for-objects-associative-arrays)). Skip to the *Frontend Best practices* section when you are curious on how to send data from the frontend to the AJAX handler

## Authorization

As explained in the first section, you have to do the authorization for your AJAX functions/routes yourself. It really depends on the application and use case of your plugin. You can try to use Wordpress built-in [current_user_can](https://developer.wordpress.org/reference/functions/current_user_can) function, or build your own permissions/role system, which I had to do. In the end, I ended up with following code:

```php
$data = json_decode(file_get_contents('php://input'));
$id = $data->locationId;
// I check whether the current user is allowed to access the given location
// If not the function returns wp_send_json_error(null, 401)
checkUserAccessToLocation($id);
```

## Frontend Best Practices

You should have a single component in your frontend project which handles the calls to the backend: It is easier to maintain and reduces the probability of errors. I am using Vue.js and have a simple `class` for handling the communication with the backend (I am using [axios](https://github.com/axios/axios))
```ts
export class BackendCommunicationService {

    private static async buildCall(data: {[k: string]: any}) {
        const params = new URLSearchParams()
        params.append('action',data['action'])
        delete data['action']
        const res = await Vue.axios.post('/wp-admin/admin-ajax.php', data, {params})
        return res.data
    }
// ..... other functions
}
```

Using the `buildCall` function within the `class` is easy: `this.buildCall({action: 'insert_name', name: 'Foobar'})`. This will call your (hopefully previously) defined `wp_ajax_insert_name` ajax action.


## Shipping your plugin

I wanted to ship the plugin with the full application code. So I `build` the frontend project and copy the generated `dist` folder into an `assets` folder of the plugin. Here is my bash script:
```sh
cd frontend && npm run build
cp -r dist/* ../plugin/assets/
```
In order to have predictable file names, I have to add `filenameHashing: false` to my `vue.config.js`.

Now I have my frontend code in the assets folder. How do I include the plugin with the whole application into wordpress? The easiest way I found is by using a [shortcode](https://wordpress.com/support/shortcodes/). This is my PHP code to ship my application through a shortcode:

```php
<?php
add_shortcode('get_ll_include_tags','get_ll_include_tags_func');

function get_ll_include_tags_func() {
    // Load JS files
    wp_register_script( 'vue-app.js', plugin_dir_url( __FILE__ ) . 'assets/js/app.js');
    wp_enqueue_script( 'vue-app.js' );
    wp_register_script( 'vue-vendors.js', plugin_dir_url( __FILE__ ) . 'assets/js/chunk-vendors.js');
    wp_enqueue_script( 'vue-vendors.js' );

    // Load CSS files of application
    wp_register_style( 'vue-app.css', plugin_dir_url( __FILE__ ) . 'assets/css/app.css');
    wp_enqueue_style( 'vue-app.css' );
    wp_register_style( 'vue-vendors.css', plugin_dir_url( __FILE__ ) . 'assets/css/chunk-vendors.css');
    wp_enqueue_style( 'vue-vendors.css' );


    ob_start();
    ?>
        <div id="app">
            <div class="app__loading-spinner"></div>Application is loading...
        </div>
    <?php
    return ob_get_clean();
}
?>
```
Now I can use `[get_ll_include_tags]` in any wordpress page and my application will be loaded.

## Nonces

To be honest, this is a topic I am still indecisive about. Nonces are there for a good reason, but as all AJAX calls are `POST` requests and I am checking the authorization for every call, I am not sure whether nonces are needed? But please correct me, if I am wrong! If nonces are needed, I already have a few ideas on how to implement them.

# The End

I hope this helps some people, I wish I had had such a post when starting with PHP Wordpress plugin development.

*Disclaimer: I am new to Wordpress plugin development and PHP, so please comment if you find an error or have a remark on something:)*