AJAX Request
The AJAX_Request class provides a declarative way to register WordPress AJAX handlers. It handles nonce verification, capability checks, input sanitization, and standardized JSON responses automatically — so you can focus on the business logic of your callback.
Key Features
Section titled “Key Features”- Automatic Nonce Verification: Generates and verifies nonces per action name
- Built-in Sanitization: 14+ sanitizer types (text, email, int, html, array_int, etc.)
- Required Fields: Validates presence of required fields before calling your callback
- Capability Checks: Optionally restrict to users with a specific WordPress capability
- Standardized Responses:
send_success(),send_error(), andsend_paginated()helpers - Public/Private: Control whether non-logged-in users can access the endpoint
Parameters
Section titled “Parameters”- action (string, required): The AJAX action name. Becomes the
wp_ajax_{action}hook. - callback (callable, required): The function to execute. Receives
($data, $ajax)— where$datais the pre-sanitized input array. - public (bool): Allow non-logged-in users. Default:
false. - verify_nonce (bool): Verify nonce automatically. Default:
true. - nonce_name (string): Custom nonce field name. Default:
'nonce'. - capability (string): Required WordPress capability (e.g.,
edit_posts). Default:null. - method (string): HTTP method:
'POST','GET', or'ANY'. Default:'POST'. - required (array): Fields that must be present in the request.
- sanitize (array): Sanitization rules per field (see table below).
Sanitization Types
Section titled “Sanitization Types”| Type | Aliases | WordPress Function |
|---|---|---|
text | string | sanitize_text_field() |
textarea | — | sanitize_textarea_field() |
int | integer | intval() |
float | number | floatval() |
bool | boolean | filter_var(FILTER_VALIDATE_BOOLEAN) |
email | — | sanitize_email() |
url | — | esc_url_raw() |
html | — | wp_kses_post() |
key | slug | sanitize_key() |
filename | file | sanitize_file_name() |
array_int | — | intval() on each element |
array_text | — | sanitize_text_field() on each element |
raw | none | No sanitization |
| callable | — | Your own custom function |
01. Basic Example
Section titled “01. Basic Example”A simple public AJAX handler for a contact form:
<?php// In functions/project/config/ajax_config.php
return [ [ 'action' => 'submit_contact', 'public' => true, 'verify_nonce' => true, 'method' => 'POST', 'required' => ['email', 'message'], 'sanitize' => [ 'name' => 'text', 'email' => 'email', 'message' => 'textarea', ], 'callback' => function ($data, $ajax) { // $data is already sanitized $sent = wp_mail('info@example.com', 'Contact', $data['message']);
if ($sent) { AJAX_Request::send_success( ['email' => $data['email']], 'Message sent!' ); } else { AJAX_Request::send_error('mail_failed', 'Could not send.', 500); } }, ],];02. Load More (Paginated) Example
Section titled “02. Load More (Paginated) Example”For paginated content loading (e.g., “Load More” buttons):
<?php[ 'action' => 'loadmore_posts', 'public' => true, 'verify_nonce' => true, 'sanitize' => [ 'page' => 'int', 'per_page' => 'int', 'post_type' => 'text', 'template' => 'text', ], 'callback' => function ($data) { $query = new WP_Query([ 'post_type' => $data['post_type'] ?: 'post', 'posts_per_page' => $data['per_page'] ?: 6, 'paged' => $data['page'] ?: 1, ]);
ob_start(); while ($query->have_posts()) { $query->the_post(); include(locate_template('components/card/' . $data['template'] . '.php')); } wp_reset_postdata(); $html = ob_get_clean();
AJAX_Request::send_paginated( $html, $data['page'] < $query->max_num_pages, (int) $data['page'], $query->found_posts ); },],03. With Capability Check
Section titled “03. With Capability Check”Restrict the handler to logged-in users with the edit_posts capability:
<?php[ 'action' => 'admin_update_status', 'public' => false, 'capability' => 'edit_posts', 'required' => ['post_id', 'status'], 'sanitize' => [ 'post_id' => 'int', 'status' => 'text', ], 'callback' => function ($data) { wp_update_post([ 'ID' => $data['post_id'], 'post_status' => $data['status'], ]); AJAX_Request::send_success([], 'Status updated.'); },],04. Custom Sanitizer
Section titled “04. Custom Sanitizer”Use a closure for complex sanitization logic:
<?php'sanitize' => [ 'ids' => function ($value) { if (!is_array($value)) return []; return array_filter(array_map('absint', $value)); },],Response Methods
Section titled “Response Methods”Use these static methods inside your callback:
<?php// Success (HTTP 200)AJAX_Request::send_success(['key' => 'value'], 'It worked!');
// Error (custom HTTP status)AJAX_Request::send_error('error_code', 'Something went wrong.', 400);
// Paginated (for load-more patterns)AJAX_Request::send_paginated($html, $has_more, $current_page, $total);Calling from JavaScript
Section titled “Calling from JavaScript”The nonce for each action is available via terra_ajax_nonce() in PHP. Pass it in your form data:
const formData = new FormData();formData.append('action', 'submit_contact');formData.append('nonce', window.base_wp_api.nonces.submit_contact);formData.append('email', 'user@example.com');formData.append('message', 'Hello!');
fetch(window.base_wp_api.ajax_url, { method: 'POST', body: formData,}).then(res => res.json()).then(json => { if (json.success) { console.log(json.message); } else { console.error(json.error.message); }});Knowledge Check
Test your understanding of this section
Loading questions...