WordPress and Admin AJAX
AJAX is a powerful tool that allows a website to extend its functionality and create a more seamless end-user experience. All AJAX calls in WordPress route through the same location, called Admin AJAX. Learn when not to use Admin AJAX and how to identify which AJAX actions are being made in excess.
About Admin AJAX
AJAX is a JavaScript technology that allows data to be requested and returned on a page without actually refreshing the page. For example, in Google Maps, to view new map sections you don’t need to load another page. As you move the map, it will load in new sections without having to fully reload the page.
By default, WordPress routes all AJAX requests through an admin file located at wp-admin/admin-ajax.php
. This is why, when referring to AJAX in WordPress, we call it “Admin AJAX”.
A common example of Admin AJAX in WordPress would be a checkout page on an ecommerce website. When you enter your shipping information, the site can query the database and display an updated price without reloading the entire page.
High Admin AJAX Usage
When AJAX is called anywhere on a WordPress website, the Admin AJAX file is requested: wp-admin/admin-ajax.php
. On WP Engine, the wp-admin/admin-ajax.php
file is uncached meaning it is generated new for each request and is never served from cache storage. Uncached requests are significantly more resource-intensive than those served from cache.
NOTE: To review how WP Engine server caching works, we suggest checking out this guide.
While AJAX is a great tool, it can often run amok when set to make inefficient, unnecessary or a high number of calls. For this reason, it’s important to use AJAX calls sparingly and only when completely necessary.
For example, say that when a user visits a page it makes 5 Admin AJAX calls within a few seconds. Remember that AJAX calls are uncached, so all 5 must be sent through Apache and processed newly. When 1 or 2 users are on the page, you may not see any impact with only 10 calls in a few seconds. However, when 5,000 visitors are on the page, you now have 25,000 uncached requests within just a few seconds. With enough visitors on the site pulling resources in this inefficient manner, the server will slow down (causing 504 errors) or even fail to complete requests completely (causing 502 errors).
If you’re seeing a large number of 504 or 502 errors on your site, it’s highly possible that excess Admin AJAX requests are the culprit.
NOTE: Need a refresher on these error codes? Learn more about the 502 error here. Learn more about the 504 error here.
Admin AJAX Log
As all AJAX requests go through the wp-admin/admin-ajax.php
file, requests are easy enough to track back to a single culprit with some additional logging enabled. If you’re seeing a large amount of requests to wp-admin/admin-ajax.php
within your access logs, your next step will be to enable Admin AJAX logging.
NOTE: Before continuing, be aware that the Admin AJAX log can grow exponentially fast, which can cause issues for your site. Disable Admin AJAX as soon as possible in your troubleshooting process. We typically find 5-10 minutes to be a sufficient amount of time enabled.
Admin AJAX logging can be enabled by adding the following line to the wp-config.php
file using either SFTP or SSH Gateway. Be sure to add this just below the section that says # WP Engine Settings
.
define( 'WPE_MONITOR_ADMIN_AJAX', true );
Once the line is added and the updated wp-config.php file has been uploaded back into the site, Admin AJAX logging will begin. We suggest timing 5 minutes before editing the file again to remove the line. During this time, perform any actions on your site where you’ve seen slowness or errors, to ensure the process in question is logged during the test period.
To disable Admin AJAX logging, open the wp-config.php
file again and either remove the define above, or update the value to false
.
To review the log, download it at wp-content/__wpe_admin_ajax.log
NOTE: The Admin AJAX log can be viewed directly in the browser only if you are logged into the site as a WordPress admin.
Finally, be aware that admin AJAX logging only record POST requests. GET requests to admin-ajax.php
with arguments on the end are not logged. For example:admin-ajax.php?action=do_something&that_something=should_be_cool
Troubleshoot Admin AJAX
We recommend troubleshooting high AJAX with SSH gateway, if possible, because we have provided some commands to easily parse the log from your terminal below. This is the same approach WP Engine Support will take to troubleshoot the issue, as it’s the most direct. All of the following commands will be run from the root of your website.
With AJAX logging enabled, view the AJAX actions live as the request is made on the website:
- This is a good option if you are looking for the AJAX call causing slowness on a particular page. Enable AJAX logging, run the following command, then perform the action on the website.
tail -f wp-content/__wpe_admin_ajax.log | grep "action"
With AJAX logging disabled, search through the log to pull a list of actions made and the total times each action was requested during the logged period:
- This is a good option if you’re seeing 502 or 504 errors with high AJAX usage.
grep "action" wp-content/__wpe_admin_ajax.log | sort | uniq -c | sort -rn | head
An example output looks like this:
47608 [action] => adrotate_impression 108 [action] => ga_stats_widget 96 [action] => heartbeat 2 [action] => wp-remove-post-lock 2 [action] => adrotate_click 1 [action] => do-plugin-upgrade
If you’re seeing issues with AJAX performance, the highest number is your most likely culprit. The next step is to determine the offender.
NOTE: The heartbeat action refers to a normal WordPress process that allows for functionality like auto-saving posts and pages. For more information, review the Heartbeat API Codex here. WP Engine disables heartbeat on all non-editing admin pages, so it is unlikely this action will cause any performance issues.
Use the following command to search your website’s files for a specific action name:
ack-grep --nosql action_name
For example, to search a site for the AJAX action adrotate_impression
using the following:
ack-grep --nosql adrotate_impression
This example query was provided the following results:
wp-content/plugins/adrotate/adrotate-statistics.php 40: return "<div class="adrotate_label">" + label + "<br /><span class="adrotate_clicks">Clicks:</span> " + env.opt.values['serie1'][index] + "<br /><span class="adrotate_impressions">Impressions:</span> " + env.opt.values['serie2'][index] + "</div>"; 479: Name: adrotate_impression_callback 483:function adrotate_impression_callback() { wp-content/plugins/adrotate/library/dashboard.css 4:.adrotate_impressions { color: #F80; font-weight: normal } wp-content/plugins/adrotate/library/jquery.adrotate.dyngroup.js 85: $.post(impression_object.ajax_url, {'action': 'adrotate_impression','track': tracker}); wp-content/plugins/adrotate/dashboard/settings/statistics.php 69: <input name="adrotate_impression_timer" type="text" class="search-input" size="5" value="<?php echo $adrotate_config['impression_timer']; ?>" autocomplete="off" /> <?php _e('Seconds.', 'adrotate'); ?><br /> wp-content/plugins/adrotate/adrotate-manage-publisher.php 724: $impression_timer = trim($_POST['adrotate_impression_timer']); wp-content/plugins/adrotate/adrotate.php 68: add_action('wp_ajax_adrotate_impression', 'adrotate_impression_callback'); 69: add_action('wp_ajax_nopriv_adrotate_impression', 'adrotate_impression_callback');
NOTE: We advise creating a backup of your site before making any changes to plugins or themes.
In this example, all the results for search query are located within the plugin directory wp-content/plugins/adrotate
. The next step would be to check for any updates to the Adrotate plugin, and make sure it’s updated. (WP CLI can help with this.) Updating can often resolve issues where an asset’s AJAX usage spikes unexpectedly.
If updating doesn’t resolve the issue, then disabling the item would be the next step. Otherwise, reaching out to the plugin/theme support will ensure you’re able to get the most help, as fast as possible. We recommend providing the developer with your AJAX logs and findings covered above, as this can greatly improve the overall resolution time.
NEXT STEP: Learn how to reduce “get_refreshed_fragments” Admin AJAX calls