Validating and Sanitizing API Arguments in WordPress REST API
Master API security by defining argument schemas in WordPress. Learn to validate and sanitize incoming REST API requests to ensure robust data integrity.
Previously in this course, we covered Implementing REST API Permission Callbacks for Secure Plugins, which ensured that only authorized users could hit our endpoints. While permission checks handle who can access your API, they don't solve the problem of what they send you.
In this lesson, we are shifting our focus to Validation, Sanitization, and API Security. Even if a user has permission to call your endpoint, they might send malicious, malformed, or unexpected data. Accepting unvalidated input is the fastest way to corrupt your database or introduce security vulnerabilities.
Defining Argument Schemas
When you register a route using register_rest_route, WordPress allows you to define an args array. This array acts as a contract between your client and your server. By explicitly declaring what your endpoint expects, you offload the burden of manual validation to the WordPress REST API infrastructure.
Each parameter in the args array can define:
required: A boolean indicating if the field is mandatory.validate_callback: A function to check if the value is valid.sanitize_callback: A function to clean the value before it reaches your handler.type: The expected data type (string, integer, boolean).
Here is how you define a schema for a hypothetical update-kb-title endpoint:
PHPadd_action('rest_api_init', function () { register_rest_route('kb/v1', '/update-title', [ 'methods' => 'POST', 'callback' => 'handle_kb_title_update', 'permission_callback' => 'is_user_logged_in', 'args' => [ 'post_id' => [ 'required' => true, 'type' => 'integer', 'validate_callback' => function($param) { return is_numeric($param); } ], 'new_title' => [ 'required' => true, 'sanitize_callback' => 'sanitize_text_field', ] ] ]); });
Sanitization vs. Validation
It is vital to distinguish between these two concepts. As we explored in Sanitizing User Input: Secure Your WordPress Database, sanitization is about cleaning data, while validation is about verifying its structure.
- Validation: Use this to reject bad data. If a user provides an invalid
post_id, yourvalidate_callbackshould returnfalseor aWP_Errorobject. WordPress will automatically halt the request and return a400 Bad Requestresponse. - Sanitization: Use this to strip dangerous tags or trim whitespace.
sanitize_text_fieldis our go-to for standard strings; it removes line breaks, tabs, and invalid UTF-8 characters. For integers, useabsint().
Handling Invalid Request Parameters
If your validate_callback returns a WP_Error, the REST API automatically transforms that into a JSON error response. This is significantly cleaner than manually checking if (empty($request['title'])) inside your main callback function.
Consider this robust approach to your handler:
PHPfunction handle_kb_title_update($request) { #6A9955">// The arguments are already validated and sanitized by the time we get here! $post_id = $request['post_id']; $title = $request['new_title']; $result = wp_update_post([ 'ID' => $post_id, 'post_title' => $title ]); if (is_wp_error($result)) { return new WP_Error('kb_update_failed', 'Could not update post', ['status' => 500]); } return ['success' => true]; }
By using the args schema, your main logic remains clean. You don't have to worry about whether new_title contains script tags or if post_id is actually an integer.
Hands-on Exercise
For our Knowledge Base plugin, we need an endpoint that accepts a category_id to filter posts.
- Open your plugin's main file where you register routes.
- Add a
GETroute for/kb/v1/posts. - Define an
argsarray for this route that includes acategory_idparameter. - Set
requiredtofalse(as it's an optional filter). - Use a
sanitize_callbackto ensure the value is treated as an integer (hint: useabsint). - Test the endpoint by passing a non-integer string in the URL parameters and verify that your sanitization forces it to an integer or that your validation rejects it.
Common Pitfalls
- Ignoring the
typeproperty: If you definetype => 'integer', WordPress will attempt to cast the input. Don't rely on this alone for security; always pair it with avalidate_callback. - Over-sanitizing: Don't use
sanitize_text_fieldon data that needs to contain HTML (like post content). Usewp_kses_postfor content fields instead. - Assuming trust: Never assume the client (even your own React app) has correctly formatted the data. The REST API is a public interface; treat every request as potentially malicious.
- Forgetting
WP_Error: When validation fails, returningfalsewill return a generic error. Returningnew WP_Errorallows you to provide specific, helpful feedback to the user.
Recap
Securing your API starts at the entry point. By using argument schemas within register_rest_route, you enforce data integrity before your application logic even runs. Remember: Validate the structure to ensure data is correct, and Sanitize the content to ensure it is safe. For broader context on how these practices fit into your overall plugin architecture, refer to Validating Settings: Secure Your WordPress Plugin Data.
Up next: We will put these skills to work by building the POST endpoints required for our Knowledge Base plugin to save new data to the database.
Work with me

Custom WordPress Plugin Development
Custom WordPress & WooCommerce plugins built to standard โ by the developer behind a plugin with 5,000+ active installs and a SaaS with 10,000+ users.

Laravel REST API Development
Clean, secure, well-documented Laravel REST APIs โ the backend engine for your app, mobile client, or SaaS. Built by an API specialist.