Developing a REST API in WordPress allows you to securely transfer data between your website, a separate frontend, and external services via JSON. You can use standard WordPress routes or create your own endpoint, defining the data structure, request methods, and access rules in advance.

In this guide, you will understand when a REST API is needed, how to design a route, configure permission_callback and select an authorization method. We'll also cover front-end connectivity, accessing the directory via API, error checking, caching, and versioning, taking into account the limitations of the theme, plugins, and the installed WordPress version.

Before making changes, work on a staging copy and create a backup of the site: solution compatibility must be tested with a specific configuration. Any endpoint receiving data must verify user permissions, validate input values, and safely escape output.

The role of the API among themes, blocks and plugins is described in Review of custom WordPress development. Below is the route and access design.

When to Use the WordPress REST API

The REST API is suitable when you need to retrieve or modify WordPress data from a separate application, interface, or external system. The server returns structured JSON, so the content can be used independently of the site's templates. If the task is entirely solved by a theme and standard PHP templates, adding an API layer will only complicate the architecture.

Built-in routes and custom endpoints

The WordPress REST API provides built-in routes for posts, pages, categories, comments, media files, and other supported entities. For example, an application can request a list of published posts, retrieve a single post by ID, or pass filtering and pagination parameters.

A route defines the address of a resource. An endpoint associates a route with a specific HTTP method and handler: GET is typically used for reading, POST for creating, PUT or PATCH for modifying, and DELETE for deleting. A single route can handle multiple operations.

Start with built-in routes if their structure suits the task. This reduces the amount of custom code and simplifies future maintenance. For a custom post type, access via the REST API is configured separately: when registering it, the parameter show_in_rest. Check compatibility with the WordPress version, theme, and plugins you are using.

WordPress REST API custom endpoint This is necessary when standard resources don't reflect your business logic. For example, you need to combine information from multiple entities, return a calculated order status, or accept data from an internal system. However, don't create a custom route just to rename fields: first, evaluate whether you can use a standard response or correctly extend an existing resource.

Frontend and integration scenarios

WordPress REST API frontend connection It makes sense when the public interface is implemented separately from WordPress: for example, as an SPA, mobile app, or storefront on a different tech stack. In this setup, WordPress is responsible for storing and managing content, while the frontend requests JSON and generates pages independently.

Typical use cases:

  • Transferring data to a separate frontend. Editors work in the admin panel, and the application receives titles, texts, images, and metadata via an API.
  • Reading a directory via API. The external storefront requests cards, categories, and available features. The data composition depends on the catalog implementation and its plugin capabilities.
  • Exchange with an external system. The CRM, analytics service, or internal dashboard receives authorized data or sends changes to WordPress.
  • Partial interface update. A separate site block loads current posts without a full page reload.

Before choosing an API architecture, consider the volume and frequency of requests, the need for data modification, caching requirements, and the intended clients. For a small content site, a REST API may be overkill. For multiple interfaces using a single data source, it helps separate content from presentation, but requires careful consideration of the response format and integration boundaries.

Design a route and data

Before writing code, define the API contract: the route address, HTTP method, input parameters, and JSON response structure. This approach simplifies WordPress REST API development and helps align the frontend and backend separately.

Method, scheme and answer

A route consists of a namespace and a path. For example, for a directory you could use /wp-json/project/v1/catalog, Where project/v1 — namespace with version, and /catalog — route. Endpoint is a combination of a route and a specific HTTP method.

  • GET — reading a directory or a single entry;
  • POST — creating a resource or starting an operation;
  • PUT And PATCH — full or partial update;
  • DELETE — deleting a resource.

For a specific frontend, fix the field names and types in advance. For example, a catalog response might contain items, page, per_page And total. Don't transmit all record fields "just in case": this increases the response size and may reveal internal data.

If a large catalog is expected, consider pagination, filters, and stable sorting. For frequently accessed and rarely modified data, consider caching GET responses. A namespaced version allows for later release. project/v2, without changing the contract of the already connected frontend.

A basic registration of a public read route might look like this:

add_action( 'rest_api_init', function () {
    register_rest_route( 'project/v1', '/catalog', array(
        'methods'  => WP_REST_Server::READABLE,
        'callback' => 'project_get_catalog',
        'permission_callback' => '__return_true',
        'args' => array(
            'page' => array(
                'type'    => 'integer',
                'default' => 1,
                'minimum' => 1,
            ),
            'per_page' => array(
                'type'    => 'integer',
                'default' => 20,
                'minimum' => 1,
                'maximum' => 100,
            ),
        ),
    ) );
} );

__return_true Let's say here it's only for truly public reading. To change data or get private fields, you need a separate permission_callback With user experience testing. Before adding code, work on a staging environment and make a backup. Compatibility must be tested with the WordPress version, theme, and plugins being used.

Input data validation

A WordPress REST API custom endpoint shouldn't trust request parameters. First, check the format and acceptable range, then normalize the value. Validation answers the question "is the data acceptable?", and sanitization ensures it's safe.

For example, a category string filter could be described as follows:

'category' => array(
    'type'              => 'string',
    'required'          => false,
    'validate_callback' => function ( $value ) {
        return is_string( $value ) && strlen( $value ) <= 100;
    },
    'sanitize_callback' => 'sanitize_key',
),

Select the processing function based on the field's meaning: sanitize_text_field() suitable for regular text, sanitize_key() — for identifiers and slugs, absint() — for non-negative integers. SQL parameters cannot be inserted into a query using string concatenation; use the WordPress API or prepared statements.

Form the answer explicitly and return it through rest_ensure_response() or WP_REST_Response. Cast numeric identifiers to numbers, and include HTML only when required by the contract. Return an error. WP_Error with understandable machine code and correct HTTP status, without revealing file paths, SQL queries and other internal information.

Before implementation, agree on a sample request and JSON response. This is especially important when implementing WordPress REST API frontend integration: the client team will be able to rely on a stable schema rather than the internals of WordPress.

Set up permissions and authorization

In WordPress, authentication determines who is sending the request, while authorization determines whether that user is allowed to perform a specific action. For each route, separate public operations, reading private data, and modifying content. CORS, nonces, and hidden URLs alone do not replace permissions checking.

Public and private data

The public endpoint is suitable for a published catalog, category list, or other information already available to site visitors. permission_callback such a route can be used __return_true, but only if disclosure is truly permissible. Do not include service fields, internal comments, personal information, or information about unpublished records in your response.

Closed transactions require identity verification. The method chosen depends on the client's location and access level.

Authorization method Scenario Limitation
Cookie authentication and REST nonce Requests from the WordPress admin or frontend from an already logged in user Focused on on-site interactions, nonces reduce the risk of CSRF but do not replace capabilities checking.
Application password Server integration, data import, WordPress connection with a separate trusted service Credentials should only be transmitted over HTTPS. The secret should not be placed in public JavaScript or a repository.
Additional scheme via plugin Architecture with OAuth or another protocol if required by integration Compatibility and security depend on the specific plugin, theme, and WordPress version and require separate testing.

When using the "WordPress REST API frontend connection" scenario, distinguish between browser and server requests. If a separate frontend reads a public directory, authentication may not be necessary. For administrative actions, it's safer to access WordPress through the server-side application layer: this way, the application password won't be revealed to the user. The CORS setting only allows the browser to access another domain and does not grant read or modify permissions.

Checking capabilities

Every WordPress REST API custom endpoint must have a meaningful permission_callback. Check the capability of a role not by its name, but by its current_user_can(). This approach takes into account the standard WordPress permissions system and changes made by plugins.

Select a capability based on the operation. To edit a specific record, pass its ID to the check. current_user_can('edit_post', $post_id). To delete, use the appropriate delete right, and for general administrative settings, use the capability that is actually required for this operation. Do not use manage_options automatically to all closed routes: this could unnecessarily restrict editors and simultaneously hide an inaccurate access model.

If access is denied, return WP_Error With a clear code and the correct HTTP status, typically 401 for missing authentication or 403 for a user without the required permissions. Don't disclose tokens, SQL queries, server paths, or other internal information in the message.

  • Allow public access only after checking the composition of the JSON response.
  • Check the capability for each operation, including reading drafts and modifying records.
  • Validate input parameters and sanitize data before saving.
  • Escape data when subsequently outputting it in the appropriate HTML, URL, or other context.
  • Only transmit secrets over HTTPS and store them outside of client code.
  • Provide integrations with separate credentials with the minimum necessary rights and the ability to revoke them.
  • Test the implementation on a staging environment after a backup; compatibility of the theme, plugins, and WordPress version cannot be guaranteed without testing.

Check the endpoint operation

Test the endpoint in a test environment before connecting it to a production frontend or external system. Ensure that the route accepts the intended HTTP method, returns valid JSON, handles parameters correctly, and does not disclose data to unauthorized users.

Response and error codes

Start with a positive scenario: send a valid request with allowed parameters and appropriate credentials. Check not only the response body, but also the HTTP status, Content-Type header, JSON structure, and the presence of required fields. Client-side code should not rely on random field order or error message text.

Then reproduce the error queries one by one:

  • without authorization and with invalid credentials;
  • from a user who lacks rights;
  • with missing required parameter;
  • with invalid parameter type, format, or value;
  • with a non-existent object identifier;
  • with unsupported HTTP method;
  • with corrupted JSON in the request body.

A 400 error code typically indicates an invalid request, 401 indicates a lack of confirmed authorization, 403 indicates insufficient privileges, 404 indicates an unknown route or resource, and 405 indicates an unsupported method. A 500 error requires review of the server logic. The actual status may depend on the endpoint implementation, security plugins, web server, and proxy, so be sure to check the actual response for your specific configuration.

In a custom endpoint, return manageable errors, such as via the WP_Error object with a human-readable machine code, message, and HTTP status. Avoid including SQL queries, file paths, tokens, call stacks, and other internal information in the response. WordPress REST API frontend connections Provide handling for timeouts, invalid JSON, and responses without expected fields, not just success status.

Logs and test environment

Deploy changes to the staging site copy first after creating a backup. Compatibility cannot be guaranteed without checking the WordPress version, active theme, plugins, PHP, and server settings. It's especially important to reconfigure the cache, permalinks, and security features that affect REST requests.

For diagnostic purposes on a test environment, you can temporarily enable WordPress logging. Don't display technical errors to visitors and don't leave debug mode enabled on the production site. The log file may contain personal data, query parameters, and configuration fragments, so restrict access to it and delete diagnostic entries after testing.

In your logs, record the request time, route, HTTP method, status, and internal operation ID. Passwords, application passwords, cookies, the Authorization header, and the full contents of personal data should not be recorded. If the request goes through a separate frontend, correlate its log with the WordPress logs using a secure ID.

For the catalog read scenario, additionally check for empty selections, pagination, filters, large available data volumes, and cache behavior. After fixing these, retry the entire set of queries: a successful result does not confirm that access restrictions and error handling remain correct.

Support and limitations

Once an endpoint is launched, consider it a stable contract between WordPress and the external system. Changing the field name, date format, or JSON structure can break the frontend, mobile app, or import functionality. Therefore, API support includes compatibility monitoring, versioning, caching, and error monitoring.

Versioning and compatibility

Specify the version in the route namespace, for example project/v1. If an incompatible change is required, create project/v2, and temporarily keep the old version for existing customers. Adding an optional field is usually safer than deleting or renaming one already in use.

Document the endpoint contract: HTTP method, parameters, required fields, JSON structure, possible response codes, and access requirements. Specifically indicate which values can be empty. This helps distinguish an integration error from a valid response without data.

Don't promise compatibility without checking the WordPress version, active theme, and plugins. Extensions can register their own routes, change post types, limit the REST API, or affect data formatting. Test updates first on staging copies with the latest configuration and a backup.

Data volume and caching

When reading a catalog via the API, don't pass the entire product array in a single response. Use pagination, filters, and select only the necessary fields. The more records and related data the client requests, the higher the load on the database and the longer it takes to generate a response.

When connecting a separate frontend, determine a caching strategy in advance. Public catalog data can be cached client-side, on a CDN, or server-side if a slight update delay is acceptable. Personalized responses and data dependent on user permissions should not be mixed in a shared public cache.

Consider invalidating the cache: time-based, after a record is modified, or through a separate notification mechanism. Without this, the frontend may display outdated prices, inventory, or publications. The specific method depends on the infrastructure, update frequency, and acceptable expiration period.

How to estimate the amount of support

Criterion What to check Possible limitation
Data volume Number of records, JSON size, request rate Pagination, filters, and query optimization will be required.
Access level Are there any public, official and personal data? Different responses cannot be served by the same caching policy.
Caching How quickly should changes appear on the frontend? A long cache reduces relevance, a short one saves fewer resources
Versioning The number of clients depends on the current contract Old versions will have to be supported during the transition period.

After upgrades, monitor the error log, the percentage of 4xx and 5xx responses, response time, and instances of empty or unexpectedly large JSON responses. It's also helpful to keep a list of API consumers and the route versions they use. This way, you can alert teams in advance of decommissioning the old endpoint.

The WordPress REST API is suitable for many integrations, but it doesn't replace performance engineering. Large catalogs, complex relationships between entities, or intensive synchronization may require server-side caching, background jobs, or a separate integration layer. Choose a solution after verifying the actual data structure and load, not just based on the availability of a ready-made REST interface.

Official documentation: WordPress REST API And request authorization.

«"Before integrating via the REST API, I suggest creating a permissions table: who can read the data, who can change it, and how access is revoked. A successful API response doesn't necessarily mean the data is properly protected."»

Bogdan Ryaboshapka, founder and author of the Web Raketa blog. Author's comment.

Interesting on the topic