WordPress AJAX, enqueue_script & Cron Not Running – Complete Fix
Four of the most common WordPress developer frustrations: AJAX -1,
actions that won't fire, scripts that refuse to load, and cron events that never run.
This complete guide covers all four with step‑by‑step fixes, code examples, and pro debugging tips.
1. Introduction
WordPress development often involves custom JavaScript, AJAX interactions, and scheduled tasks. When things go wrong, you might encounter:
-1response – usually a nonce or security failure.- Action not firing – your AJAX callback never runs.
- Script not loading –
wp_enqueue_script()seems ignored. - Cron event not running – scheduled tasks don't execute.
This article tackles all four, providing you with a complete diagnostic and resolution workflow. By the end, you'll be able to fix any of these issues quickly and confidently.
2. AJAX in WordPress
WordPress routes AJAX through admin-ajax.php. Your JavaScript sends an action
parameter, and WordPress looks for hooks: wp_ajax_{action} (logged‑in) and
wp_ajax_nopriv_{action} (guests). If found, your callback runs.
For scripts, wp_enqueue_script() is the standard way to load JavaScript files safely,
with dependency management and caching.
3. Fixing the -1 Error
The -1 response is WordPress's "access denied" signal. Most often it's a nonce verification
failure. Here's how to fix it.
Step 1: Generate the Nonce
// functions.php
add_action('wp_enqueue_scripts', 'my_ajax_enqueue');
function my_ajax_enqueue() {
wp_enqueue_script('my-ajax-js', get_template_directory_uri() . '/js/my-ajax.js', ['jquery'], null, true);
wp_localize_script('my-ajax-js', 'my_ajax_obj', [
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('my_ajax_nonce_action')
]);
}
Step 2: Send the Nonce in JavaScript
// my-ajax.js
jQuery(document).ready(function($) {
$('#my-button').on('click', function() {
$.ajax({
url: my_ajax_obj.ajax_url,
type: 'POST',
data: {
action: 'my_ajax_action',
_wpnonce: my_ajax_obj.nonce,
// other data
},
success: function(response) { console.log(response); }
});
});
});
Step 3: Verify the Nonce in the Callback
add_action('wp_ajax_my_ajax_action', 'my_ajax_callback');
add_action('wp_ajax_nopriv_my_ajax_action', 'my_ajax_callback');
function my_ajax_callback() {
check_ajax_referer('my_ajax_nonce_action', '_wpnonce');
// your logic
wp_send_json_success('OK');
}
Step 4: Debug with Detailed Messages
function my_ajax_callback() {
if (!isset($_POST['_wpnonce']) || !wp_verify_nonce($_POST['_wpnonce'], 'my_ajax_nonce_action')) {
wp_send_json_error('Nonce verification failed', 403);
return;
}
// ...
}
wp_send_json_error() with clear messages to pinpoint
where the failure occurs.
4. Fixing AJAX Action Not Firing
If your AJAX request returns 0 or nothing, the action hook isn't being triggered.
Common Causes
- Wrong action parameter – the
actionsent doesn't match the hook. - Missing hook registration – forgot
add_action('wp_ajax_...'). - Hook added too late – after the request is processed.
- Plugin/theme conflict – another plugin removes your hook.
- User permissions – callback checks capability and exits.
- JavaScript errors – request never sent.
Debugging Steps
- Verify action name – ensure exact match.
- Check hook registration – both
wp_ajaxandwp_ajax_noprivif needed. - Add
error_log()in callback to see if it's called. - Check for early
wp_die()– usewp_send_json_*instead. - Inspect Network tab – see payload and response.
- Verify user capabilities – adjust if needed.
- Search for
remove_actionthat might override your hook. - Test with minimal example to isolate the issue.
0, the hook likely isn't registered or the callback didn't output.
5. Fixing wp_enqueue_script Not Loading
Sometimes your JavaScript file simply doesn't appear in the page source. Here's how to diagnose and fix
wp_enqueue_script() issues.
Common Reasons Why Scripts Don't Load
- Incorrect hook –
wp_enqueue_scriptsis the right hook for frontend;admin_enqueue_scriptsfor admin. - Wrong file path –
get_template_directory_uri()vsget_stylesheet_directory_uri()(child themes). - Dependency missing – if a dependency (e.g.,
jquery) isn't registered, your script won't load. - Conditional logic – enqueue inside a condition that doesn't evaluate to true.
- Cache/versioning – browser cache might serve old version; use version parameter.
- Script handle conflict – using a handle that already exists can cause overwrites.
- Footer/header placement –
$in_footerparameter affects where it's printed. - Plugin/theme overrides –
wp_dequeue_script()orwp_deregister_script()might remove your script.
Step‑by‑Step Fix for enqueue_script
1. Use the Correct Action Hook
// For frontend
add_action('wp_enqueue_scripts', 'my_enqueue_script');
// For admin
add_action('admin_enqueue_scripts', 'my_admin_enqueue_script');
2. Verify the File Path
Use get_template_directory_uri() for parent theme, or get_stylesheet_directory_uri()
for child theme. Ensure the file exists.
wp_enqueue_script('my-script', get_template_directory_uri() . '/js/my-script.js', ['jquery'], '1.0', true);
3. Check Dependencies
If your script depends on jQuery, make sure jquery is already registered (it is by default).
For custom dependencies, register them first.
// Register dependency first
wp_register_script('my-lib', 'path/to/lib.js', [], '1.0', true);
wp_enqueue_script('my-script', 'path/to/my.js', ['jquery', 'my-lib'], '1.0', true);
4. Ensure the Enqueue Call is Executed
Add a temporary error_log('enqueue called'); in your enqueue function. If you don't see the
log, the hook isn't firing or the condition failed.
5. Check for Dequeue or Deregister
Search your codebase for wp_dequeue_script('my-script') or
wp_deregister_script('my-script') that might remove your script.
6. Force Script to Load in Footer
Set the $in_footer parameter to true to avoid blocking page load.
7. Bust Cache with Version
Use a version number or filemtime to force browser refresh.
wp_enqueue_script('my-script', get_template_directory_uri() . '/js/my-script.js', ['jquery'], filemtime(get_template_directory() . '/js/my-script.js'), true);
8. Debug with View Source
Check the page source (or Network tab) to see if the script tag is output. If not, your enqueue isn't working. Also check for PHP errors that might break the enqueue process.
wp_script_is('my-script', 'enqueued') to check if your script is enqueued at any point.
6. Fixing WordPress Cron Events Not Running
WordPress uses wp-cron.php to handle scheduled tasks (e.g., publishing future posts,
checking for updates, running backups). If your cron events aren't firing, here's how to troubleshoot
and fix them.
How wp-cron Works
Unlike a system cron, WordPress cron is triggered on every page load (or admin visit). When a visitor hits your site, WordPress checks if any scheduled events are due and runs them. This means low‑traffic sites may experience delays.
Common Causes of Cron Not Running
- Low site traffic – no visits to trigger cron.
- wp-cron disabled –
define('DISABLE_WP_CRON', true);inwp-config.php. - Server cron not set up – if you disabled wp-cron, you need a real system cron job.
- PHP timeouts – cron jobs may take too long and time out.
- Plugin/theme conflicts – a plugin may interfere with cron execution.
- Incorrect schedule – using a schedule that isn't registered.
- Memory exhaustion – cron process runs out of memory.
- HTTP/HTTPS issues – if your site is behind a firewall, cron may fail to call itself.
Debugging Steps for Cron
1. Check if wp-cron is Enabled
Look in wp-config.php for DISABLE_WP_CRON. If set to true,
cron won't run on page loads. You'll need a system cron job.
2. Check the Cron Queue with WP-CLI
If you have WP-CLI access, run:
wp cron event list
This shows all scheduled events, their next run times, and their hooks. You can also run:
wp cron event run --all
to force all due events to run immediately.
3. Check the Cron Queue via Plugin
Use plugins like WP Crontrol or Advanced Cron Manager to view and manage cron events from the admin dashboard.
4. Check for PHP Errors
Enable WP_DEBUG and WP_DEBUG_LOG. Check the debug.log for any
errors that occur during cron execution. Often, a fatal error in a cron callback will prevent the
event from completing and may block subsequent events.
5. Manually Trigger Cron
You can visit https://yoursite.com/wp-cron.php?doing_wp_cron (with a valid nonce) to
manually trigger cron. Alternatively, use WP-CLI as mentioned.
6. Check Server Logs
If cron is triggered via a system cron job (e.g., wget or curl), check the
server's cron logs for errors.
7. Increase Memory and Timeout
Add to wp-config.php:
define('WP_MEMORY_LIMIT', '256M');
set_time_limit(300);
8. Use a Real Cron Job (Recommended for High Traffic)
If you have many scheduled tasks, it's better to disable wp-cron and set up a system cron job that hits
wp-cron.php every few minutes.
// In wp-config.php
define('DISABLE_WP_CRON', true);
Then, add a cron job on your server:
*/5 * * * * wget -q -O - https://yoursite.com/wp-cron.php?doing_wp_cron >/dev/null 2>&1
Code Example: Scheduling a Custom Cron Event
// Schedule a daily event
if (!wp_next_scheduled('my_daily_event')) {
wp_schedule_event(time(), 'daily', 'my_daily_event');
}
// Hook the callback
add_action('my_daily_event', 'my_daily_callback');
function my_daily_callback() {
// Do something daily
error_log('Daily cron event ran!');
}
// Unschedule on deactivation
register_deactivation_hook(__FILE__, 'my_deactivate_cron');
function my_deactivate_cron() {
$timestamp = wp_next_scheduled('my_daily_event');
if ($timestamp) {
wp_unschedule_event($timestamp, 'my_daily_event');
}
}
wp_schedule_event() with intervals like 'hourly',
'twicedaily', or custom intervals using add_filter('cron_schedules', ...).
7. Complete Code Examples (All Fixes Combined)
Below is a robust example that includes proper nonce handling, action registration, script enqueueing, and cron scheduling, preventing all four issues.
// ==============================
// PHP (functions.php or plugin)
// ==============================
// 1. Enqueue script with nonce
add_action('wp_enqueue_scripts', 'fl365_enqueue_scripts');
function fl365_enqueue_scripts() {
$js_path = get_template_directory() . '/js/fl365-ajax.js';
if (!file_exists($js_path)) {
error_log('fl365-ajax.js not found!');
return;
}
wp_enqueue_script(
'fl365-ajax',
get_template_directory_uri() . '/js/fl365-ajax.js',
['jquery'],
filemtime($js_path),
true
);
wp_localize_script('fl365-ajax', 'fl365_ajax', [
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('fl365_ajax_nonce'),
]);
}
// 2. Register AJAX hooks
add_action('wp_ajax_fl365_ajax_action', 'fl365_ajax_handler');
add_action('wp_ajax_nopriv_fl365_ajax_action', 'fl365_ajax_handler');
// 3. AJAX callback
function fl365_ajax_handler() {
if (!check_ajax_referer('fl365_ajax_nonce', '_wpnonce', false)) {
wp_send_json_error(['message' => 'Nonce verification failed'], 403);
return;
}
if (!current_user_can('read')) {
wp_send_json_error(['message' => 'Insufficient permissions'], 403);
return;
}
$data = isset($_POST['data']) ? sanitize_text_field($_POST['data']) : '';
wp_send_json_success(['message' => 'Received: ' . $data]);
}
// 4. Cron: Schedule a daily event
if (!wp_next_scheduled('fl365_daily_event')) {
wp_schedule_event(time(), 'daily', 'fl365_daily_event');
}
add_action('fl365_daily_event', 'fl365_daily_callback');
function fl365_daily_callback() {
error_log('Daily cron ran successfully.');
// Your daily task
}
// 5. On plugin deactivation, clear cron
register_deactivation_hook(__FILE__, 'fl365_deactivate');
function fl365_deactivate() {
$timestamp = wp_next_scheduled('fl365_daily_event');
if ($timestamp) {
wp_unschedule_event($timestamp, 'fl365_daily_event');
}
}
// ==============================
// JavaScript (fl365-ajax.js)
// ==============================
jQuery(document).ready(function($) {
$('#fl365-btn').on('click', function() {
$.ajax({
url: fl365_ajax.ajax_url,
type: 'POST',
data: {
action: 'fl365_ajax_action',
_wpnonce: fl365_ajax.nonce,
data: 'Hello from frontend!'
},
success: function(res) {
if (res.success) {
alert('✅ ' + res.data.message);
} else {
alert('❌ ' + res.data.message);
}
},
error: function(xhr) {
console.error('AJAX error:', xhr.responseText);
}
});
});
});
8. Best Practices
- Always use nonces – never skip verification.
- Register both
wp_ajaxandwp_ajax_noprivif you need both user states. - Use descriptive action names to avoid collisions.
- Sanitize and validate all input – never trust user data.
- Return structured JSON with
wp_send_json_success/error. - Log errors to
error_logfor debugging. - Enqueue scripts on the correct hook (
wp_enqueue_scriptsfor frontend). - Use filemtime for cache busting during development.
- Check for script dependencies – ensure they are registered.
- For cron: use a system cron job for high‑traffic sites, and always unschedule events on deactivation.
- Test with different user roles and guest sessions.
9. Frequently Asked Questions
Click a question to expand the answer.
0 Comments
thanks for your comments!