📜 ⬆️ ⬇️

Using WordPress AJAX Handler



WordPress, being one of the most popular CMS in the world, is provided with detailed documentation, or rather, even two . In this connection, in no case should this text be perceived as a description of some “best practices” and certainly no one is blindly following what has been described. The article is just a quick answer to the question “how ?!” (next paragraph) and a detailed description of everything you need to know in order to get WordPress to respond to AJAX requests (the rest of the article).

Briefly


Traditionally, AJAX requests require two things: a script on the server (backend), which will respond to requests, and a script on the client (frontend), which will do these requests. WordPress allows you to delegate functions to refer to a special URL where the request handler is located.
')
So, it works, "WordPress-way", like this:

  1. On the backend, using the admin_url function, admin_url get a link to the AJAX request handler and pass it to the frontend in one of the ways. It is to this link that we will make our requests.
  2. On the backend, a hook is registered with a function to handle some kind of action. Let's call this action, for example, get_posts.
  3. Front-end makes requests to the URL from point 1, passing the name of the action. For example ?action=get_posts .
    On the back end, if a hook is registered on an action, the function we set is executed.


This is how simple it is. Now more.

In detail


AJAX handler on backend


Some people do an AJAX handler manually by including the wp_load file. This is considered a very, very bad practice for a whole bunch of reasons. WordPress has its own handler. Be good and use it.

After the front-end “found out” where to send requests, you need to add a hook to the backend to handle these requests. The required parameter in these requests is action : this parameter determines what exactly we want from the backend.

In order to create a new AJAX handler method, you need to hang two hooks: wp_ajax_< > and wp_ajax_nopriv_< > . For example, like this:

 add_action('wp_ajax_get_posts' , 'get_posts_callback'); add_action('wp_ajax_nopriv_get_posts', 'get_posts_callback'); 

The wp_ajax_ prefix at the beginning of the hook name will make WordPress understand that we are trying to create an AJAX request handler. The wp_ajax_nopriv prefix allows wp_ajax_nopriv to register a hook for non-logged users. Thus, you can register different handlers for logged in and unlocked users, which can be convenient. At the same time, if you need an ajax request to be executed for both, you have to hang one function on both hooks.

These hooks are the most common, the same as all other WP hooks. As a result of the registration of such hooks, when accessing an URL by wp-admin/admin-ajax.php?action=get_posts function should be get_posts_callback .

 add_action( 'wp_ajax_do_something', 'get_posts_callback' ); // For logged in users add_action( 'wp_ajax_nopriv_do_something', 'get_posts_callback' ); // For anonymous users function do_something_callback(){ echo(json_encode( array('status'=>'ok','request_vars'=>$_REQUEST) )); wp_die(); } 

As a result of executing this code, a link like wp-admin/admin-ajax.php?action=do_something should display a piece of JSON.

Some features on the backend


It probably makes sense to notice that the hooks in WordPress are hung every time. That is, the handler needs to be registered every time, preferably in a file that is included every time (in the case of a theme, this is the functions.php file) If you try to register an AJAX hook, for example, in the page.php or index.php files, the themes will not work, because when you access the handler, these files, of course, will not be executed.

It is recommended that all functions hung on AJAX handler wp_die ended by calling wp_die or the wp_send_json_success functions and the like. Or simple die , at worst, cause.

In case of an error, the request handler returns the code 0 or -1, depending on the cause of the error. In particular, in the event that such a hook does not exist (that is, it was not registered for some reason), 0 is returned.

The is_admin function, which returns true, if the user is in the site is_admin , being called from an AJAX handler, always returns true.

There is a function check_ajax_referer , which checks the referrer (checks where the request originated from) and interrupts the execution if the referrer is some kind of “not such”. This function can also check
nonce. You can read more in the relevant article of the code .

Link to frontend


The address of the request handler is something like wp-admin/admin-ajax.php . The trick is that our frontend "does not know" the addresses of this link. Therefore, if we want our theme or plugin to be as versatile and portable as possible - we need to get to WordPress and send to the front-end the actual address of this link:

 $ajax_url = admin_url('admin-ajax.php'); 

It can be transmitted to the frontend in many different ways Often this link is not the only thing that needs to be sent to the frontend, so I prefer to insert it with the help of the corresponding hook in wp_head in the <script> :

 // -  functions.php function js_variables(){ $variables = array ( 'ajax_url' => admin_url('admin-ajax.php'), 'is_mobile' => wp_is_mobile() //   -   ); echo( '<script type="text/javascript">window.wp_data = ', json_encode($variables), ';</script>' ); } add_action('wp_head','js_variables'); 

This hook will output the <script> with the registration of global JS variables with reference to the handler in the <head> section of the theme (of course, for this you need to call the wp_head function in it, which is anyway recommended for any topic)

The tag will be inserted immediately after all connected assets (scripts and style sheets registered through the WordPress asset system)

You can also send a link to the frontend using the localize_script function. I find such an approach a bit dreary: de facto, we send to the frontend not our javascript from the assets folder of the theme or from some CDN, but its modified version, without leaving the end user the choice (which he has, for example, the case with plugins that glue all the scripts together into one is whether to use these plugins for it or not). If anything - more about the approach with localize_script - in the WordPress codex, in the article AJAX In Plugins .

And, of course, you can NOT transfer this link to the frontend, but simply scramble it or her part directly into the JS file. But no one guarantees that in the next version of WordPress or simply on some other specific environment the handler URI will be 'wp-admin / admin-ajax.php'. For universality and compatibility, it is recommended to always use the admin_url function to get the actual reference to the handler and transfer it to the frontend manually.

By the way, on all admin pages this link is already forwarded to the ajaxurl global variable in JS. Some plugins also post this link for the site pages, but you shouldn’t count on it (we don’t want any extra dependencies for our plugin / theme, right?)

On the front end


Now we can quite easily make web requests to the backend from our front end. For example, if we link the link to the wp_data.ajax_url variable and jQuery is connected, it will look something like this:

 jQuery(function($){ $.ajax({ type: "GET", url: window.wp_data.ajax_url, data: { action : 'do_something' }, success: function (response) { console.log('AJAX response : ',response); } }); }); 

If everything is done correctly, at startup, the web request to the backend will be executed, which will respond with a piece of JSON, which will then be received by the frontend and output to the console.

OOP lovers


If you are trying to build your own theme architecture, with autoloader and OOP, you can define an abstract class of this type:

 abstract class AJAX_Handler { function __construct($action_name) { $this->init_hooks($action_name); } public function init_hooks($action_name) { add_action('wp_ajax_'.$action_name , array($this,'callback')); add_action('wp_ajax_nopriv_'.$action_name, array($this,'callback_nopriv')); } public function callback_nopriv() { $this->callback(); } abstract public function callback(); } 

Now it is enough to create for each action its successor of this class, in which you define the callback method, then create a new object of the successor class, passing the name of the action to the constructor:

 class Something extends AJAX_Handler { function callback() { wp_send_json_success(array('test'=>'Works!')); } } new Something('do_something'); 

On the wp_ajax_nopriv_XXX hook, the callback_nopriv method hangs up, which in the parent class simply calls the callback method, but in its successor, of course, it could be overridden. As a result of this, when accessing the URL of the form /wp-admin/admin-ajax.php?action=do_something we get an answer of the form {"success":true,"data":{"test":"Works!"}} .

CORS and possible trouble with the protocol (HTTP / HTTPS)


For security reasons, web browsers limit the ability of HTTP requests to resources whose domain is different from the domain on which the script that runs these requests is running. CORS (“cross-origin resource sharing”) is a W3C-recommended mechanism for allowing cross-domain requests to the server (from the server side). If you want to make some kind of API for accessing from third-party resources from an AJAX request handler (no matter how awful this idea may seem, this can be used) - you have to either allow cross-domain requests to the handler by adding the Access-Control-Allow-Origin , or implement an API using JSONp.

If your site is configured to work in HTTPS, the admin_url function will return a link with https. But if the site has the wrong / expired SSL certificate, it will redirect to the http version of the site and the site will be viewed using the http protocol. As a result, the frontend will get a link to the handler in another protocol, which is likely to cause problems. In particular, the Firefox browser will most likely not be happy about this, having decided that you are trying to make a cross-domain query.

Therefore, if you are using HTTPS, you are not sure that the certificate will always and everything is in order and you want to be sure that even if it falls off, the site will work fine, it makes sense to check on the frontend whether the handler reference protocol matches the page protocol on which the script is running.

Author: Ilya Andrienko, DataArt web developer.

Source: https://habr.com/ru/post/271189/


All Articles