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 explains the basics of responding to ajax calls.
Here is a Gist which also describes everything you should know:
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)
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:
$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). 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 function, or build your own permissions/role system, which I had to do. In the end, I ended up with following code:
$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)
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:
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. This is my PHP code to ship my application through a shortcode:
<?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:)
Top comments (0)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.