Skip to main content

WPStack

Pagination and Caching for WordPress REST API Endpoints

Pagination and Caching for WordPress REST API Endpoints

A WordPress REST API endpoint may work perfectly when it returns 20 records. However, the same endpoint can become extremely slow, consume excessive memory, or time out when the database grows to 20,000 records.

Scalable WordPress REST API endpoints require more than a functioning database query. They need controlled response sizes, predictable ordering, efficient database access, secure caching, and a clear cache invalidation process.

Developers should treat pagination and caching as essential parts of an endpoint’s architecture rather than optional performance improvements added after launch.

This guide explains how to implement reliable pagination and caching for WordPress REST API endpoints while protecting authorization, response accuracy, and overall website performance.

Why WordPress REST API Performance Matters

REST API endpoints often support mobile applications, plugin dashboards, JavaScript interfaces, external integrations, reporting tools, and headless WordPress websites.

A poorly optimized endpoint can create several problems:

  • Slow page or application loading
  • High database usage
  • PHP memory exhaustion
  • Request timeouts
  • Increased hosting costs
  • Poor user experience
  • Server instability during traffic spikes

The main challenge is that API traffic can grow faster than expected. A single dashboard may make several requests, while external applications may repeatedly request the same data.

Good endpoint design ensures that performance remains predictable as data volume and request frequency increase.

Make Pagination Part of the API Contract

Illustration showing a WordPress REST API pagination workflow with page, per_page, offset, order, and orderby parameters.
Image Source: AI-generated visual by Wpstack

Every REST API collection endpoint should use pagination. An endpoint should never allow clients to request an unlimited number of records in one response.

Pagination divides a large collection into smaller, manageable pages. This reduces database workload, PHP memory usage, response size, and network transfer time.

A well-designed endpoint should define:

  • A default number of records per page
  • A hard maximum page size
  • A stable sorting method
  • Clear pagination parameters
  • Pagination information in the response

WordPress commonly uses parameters such as:

  • page
  • per_page
  • offset
  • order
  • orderby

The endpoint should document which parameters are supported and how clients should use them.

Set a Default and Maximum Page Size

Every collection endpoint should have a conservative default page size.

For example, an endpoint might return 20 records by default and allow clients to request up to 100 records.

A client requesting 500, 1,000, or every available record should not be allowed to create an unbounded database query.

The ideal page size depends on several factors:

  • Size of each record
  • Number of fields returned
  • Database query complexity
  • Server resources
  • Client requirements
  • Network conditions
  • Expected request frequency

There is no universal page-size value for every endpoint. A lightweight endpoint returning names and IDs may safely return more records than an endpoint containing large metadata fields, nested objects, or calculated values.

The best approach is to begin with a conservative limit and test it using production-like data.

Use Stable and Predictable Ordering

Pagination only works correctly when the endpoint returns records in a stable order.

Suppose an endpoint sorts posts only by publication date. If several posts have the same date, their order may change between requests. A client browsing multiple pages could then see duplicate records or miss some records entirely.

Use a deterministic secondary field as a tie-breaker.

For example, records can be ordered by:

  1. Modified date
  2. Record ID

The unique ID ensures that records with the same date still appear in a consistent order.

Stable ordering is especially important when:

  • Records are frequently created or updated
  • Multiple records share the same timestamp
  • Clients request pages over several minutes
  • Results are cached
  • The endpoint supports synchronization

The chosen ordering rules should be documented as part of the endpoint contract.

Understand Offset Pagination

Illustration showing WordPress REST API offset pagination with three result pages using offsets 0, 20, and 40.
Image Source: AI-generated visual by Wpstack

Offset pagination is the simplest and most familiar pagination method.

It asks the database to skip a specific number of records before returning the next group.

For example:

  • Page 1 returns records 1–20
  • Page 2 skips 20 records and returns records 21–40
  • Page 3 skips 40 records and returns records 41–60

Offset pagination is easy for clients to understand and works well for relatively small or stable collections.

However, it has two important limitations.

Deep Pages Can Become Expensive

The database may still need to scan or sort a large number of records before reaching a deep offset.

Requesting page 500 can therefore require significantly more work than requesting page 1.

The Performance Budget impact depends on the query, indexes, database size, and ordering fields.

Results Can Shift Between Requests

If a new record is inserted while a client is browsing, records may move from one page to another.

This can lead to duplicate or missing records during pagination.

Offset pagination is still suitable for many WordPress endpoints, but developers should test deep-page performance rather than assuming every page has the same cost.

Consider Cursor Pagination for Large Datasets

Cursor pagination can be more reliable for large and frequently changing datasets.

Instead of requesting a page number, the client sends a cursor representing the last record received. The next request asks for records that come after that cursor.

A cursor may be based on:

  • A timestamp
  • A unique record ID
  • A combination of timestamp and ID
  • Another indexed sorting field

For example, a cursor could represent the last modified timestamp and database ID from the previous response.

Cursor pagination can provide several benefits:

  • Better performance on deep pages
  • More stable results when new records are added
  • Efficient sequential processing
  • Improved support for feeds and synchronization

However, cursor pagination requires careful design.

The cursor fields must be:

  • Indexed
  • Stable
  • Deterministic
  • Suitable for the selected ordering
  • Properly validated

Cursor values should also be treated as untrusted user input.

Developers should select either offset or cursor pagination based on the endpoint’s actual data volume and usage pattern. The pagination model should not be changed silently after clients begin using the endpoint.

Limit the Work Behind Every Response

Pagination reduces the number of returned records, but it does not automatically make an endpoint efficient.

An endpoint returning 20 records can still be slow if it performs many database queries for every record.

Developers should review the complete workload behind each request.

Validate and Allowlist Query Parameters

Every request parameter should be validated before it affects a database query.

Do not pass arbitrary client-provided values directly into query arguments.

Instead, define a list of permitted values.

For example, an endpoint may allow clients to sort by:

  • Created date
  • Modified date
  • Title
  • Record ID

Any unsupported value should be rejected or replaced with a documented default.

The same principle applies to filters, status values, taxonomy parameters, date ranges, and search options.

Allowlisting protects both security and performance. Without it, clients may trigger expensive or unexpected database queries.

Avoid N+1 Query Patterns

An N+1 query problem occurs when the endpoint runs one main query and then performs additional database queries for every returned record.

For example:

  1. Fetch 50 posts.
  2. Query the author for every post.
  3. Query custom metadata for every post.
  4. Run a separate permission check for every post.
  5. Fetch related records individually.

A response containing 50 records may then generate hundreds of database queries.

Developers should look for ways to:

  • Load related data in batches
  • Use WordPress caching functions
  • Prime metadata caches
  • Avoid repeated lookups
  • Reuse previously loaded objects
  • Move unnecessary calculations outside loops

Authorization checks must not be removed for performance reasons. Instead, they should be designed and executed efficiently.

Return Only Necessary Fields

WordPress REST API listing endpoint returning only necessary fields while complete data is retrieved through a separate detail endpoint.
Image Source: AI-generated visual by Wpstack

Large API responses take longer to generate, transfer, parse, and display.

An endpoint should return only the fields required by its intended clients.

For example, a listing endpoint may only need:

  • Record ID
  • Title
  • Status
  • Updated date
  • Thumbnail URL

The complete record can then be requested from a separate detail endpoint.

This approach helps reduce:

  • Payload size
  • Database work
  • Serialization time
  • Bandwidth usage
  • Client-side processing

However, selective fields should not be used as a replacement for authorization. The endpoint must still verify that the current user is permitted to access the requested record.

Build an Explicit Caching Strategy

Caching can significantly improve REST API performance by storing previously generated responses and reusing them for matching requests.

However, caching an endpoint safely requires more than setting an expiration time.

A useful caching strategy must define:

  • What can be cached
  • Where the response is stored
  • How cache keys are created
  • How long cached data remains valid
  • What events invalidate the cache
  • Which users may share a cached response

Caching should never cause users to receive outdated, unauthorized, or private information belonging to someone else.

Create Complete Cache Keys

A cache key must include every input that can change the response.

Depending on the endpoint, this may include:

  • Endpoint or route version
  • Normalized query parameters
  • Page number or cursor
  • Page size
  • Sort order
  • Filters
  • Language
  • Website or multisite blog ID
  • Relevant user ID
  • User role or capability context
  • Data-generation version

Consider two users requesting the same route. One user may have permission to view private records, while the other can only view public records.

If the cache key does not include the relevant authorization context, the private response could be served to the wrong user.

This is a serious security issue.

Public responses can often share cache entries. Private or personalized responses require more careful key separation and storage decisions.

Normalize Parameters Before Creating Keys

Different URLs can produce the same logical result.

For example:

  • per_page=20&page=1
  • page=1&per_page=20

These should generally map to the same cache entry.

Before creating the cache key:

  1. Apply default values.
  2. Validate the parameters.
  3. Convert values into consistent types.
  4. Sort parameters into a predictable order.
  5. Remove unsupported or irrelevant values.
  6. Generate the cache key from the normalized result.

Parameter normalization improves cache-hit rates and prevents unnecessary duplicate cache entries.

Invalidate the Cache When Data Changes

Expiration alone is not a complete cache invalidation strategy.

Suppose a cached endpoint response remains valid for 30 minutes. If an administrator updates a record immediately after the response is cached, clients may receive outdated data for the remaining 29 minutes.

Whenever possible, invalidate related cache entries when the source data changes.

Invalidation may be connected to events such as:

  • A post being created
  • A post being updated
  • A post being deleted
  • Metadata changing
  • Taxonomy relationships changing
  • Plugin settings being updated
  • User permissions changing

One practical approach is to include a data-generation version in the cache key.

When relevant data changes, increment the version. Future requests then use a new cache key, making the old entries unreachable until they expire naturally.

This can be easier than tracking and deleting every possible cached variation individually.

Use WordPress Transients Carefully

The WordPress Transients API can be useful for caching generated API responses.

However, a transient’s expiration value represents the maximum time it should remain available. It is not a guarantee that the transient will exist until that time.

A transient may disappear early because of:

  • Object-cache eviction
  • Cache flushing
  • Database cleanup
  • Hosting configuration
  • Plugin behavior
  • Memory limits

Endpoint code must therefore be able to regenerate the response whenever the cache is missing.

A safe caching flow is:

  1. Generate a normalized cache key.
  2. Check for a cached response.
  3. Return it when available and authorized.
  4. Generate the response when the cache is missing.
  5. Store the response with an appropriate expiration.
  6. Return the newly generated response.

The endpoint must remain correct even when the cache is unavailable.

Avoid Caching Authorization Mistakes

Caching must never bypass permission checks.

Permission handling should remain part of the endpoint design, regardless of whether the response comes from the database or a cache.

Be especially careful when caching:

  • Account information
  • Order records
  • Customer data
  • Draft posts
  • Private content
  • Membership data
  • Reports
  • User-specific settings
  • Capability-dependent fields

For private responses, the cache key may need to include a user ID or another authorization-specific value.

In some cases, caching only the underlying shared data is safer than caching the final personalized response.

Measure the User-Visible Performance Budget

Performance optimization should be based on measurement rather than assumptions.

Track the metrics that affect real clients and server stability.

Important REST API metrics include:

  • Total response time
  • Database query count
  • Database query duration
  • PHP memory usage
  • Response payload size
  • Cache-hit rate
  • Cache-miss rate
  • Error rate
  • Timeout rate
  • Slowest page depth
  • Concurrent request performance

Test both cold and warm requests.

A cold request generates the response without an existing cache entry. A warm request returns a previously cached result.

Both paths matter. A fast warm response does not solve the problem if cold requests overload the server whenever the cache is cleared.

Test with Realistic Data Volumes

Testing an endpoint with 20 development records may hide serious performance problems.

Use production-like datasets that reflect:

  • Expected record count
  • Metadata volume
  • Taxonomy relationships
  • User roles
  • Permission rules
  • Search behavior
  • Concurrent traffic

Testing should cover:

  • First-page requests
  • Deep-page requests
  • Maximum page sizes
  • Invalid parameters
  • Cold-cache requests
  • Warm-cache requests
  • Concurrent requests
  • Source-data updates
  • Cache invalidation
  • Authenticated and anonymous users

Performance tests should also confirm response correctness. A fast endpoint is not successful if it returns incomplete, outdated, duplicated, or unauthorized data.

WordPress REST API Performance Checklist

WordPress REST API performance checklist covering pagination, query validation, caching, authorization, database optimization, and performance testing
Image Source: AI-generated visual by Wpstack

Use this checklist when designing or reviewing collection endpoints:

  • Set a conservative default page size.
  • Enforce a hard maximum page size.
  • Use stable ordering with a unique tie-breaker.
  • Validate and allowlist all query parameters.
  • Avoid unbounded searches and filters.
  • Test the cost of deep offset pagination.
  • Consider cursor pagination for large changing datasets.
  • Avoid repeated per-record database queries.
  • Return only the fields clients need.
  • Include every response-changing input in the cache key.
  • Include authorization context in private cache keys.
  • Normalize parameters before generating cache keys.
  • Invalidate cached data when source records change.
  • Use expiration as a safety net, not the only correctness mechanism.
  • Allow responses to regenerate after early cache eviction.
  • Measure cold, warm, deep-page, and concurrent performance.
  • Test with production-like data volumes.

Improve Your WordPress REST API Performance with WPStack

Slow endpoints, inefficient pagination, oversized responses, and unsafe caching can affect your website’s speed, reliability, and scalability. A well-built REST API requires optimized queries, stable ordering, secure cache handling, and careful performance testing.

WPStack offers custom plugin development and WordPress REST API optimization services to help businesses create fast, secure, and maintainable API endpoints that perform reliably as traffic and data increase.

Planning a new API integration or struggling with a slow existing endpoint? Contact WPStack today for a custom plugin development consultation and discuss your project with an experienced WordPress development team.

Frequently Asked Questions

What is a good page size for a WordPress REST API?

There is no universal page size for every endpoint. The correct limit depends on payload size, query complexity, client requirements, database performance, and server capacity.
A conservative default such as 20 records may be appropriate for many endpoints, but the final value should be based on testing. Always enforce a maximum.

Are WordPress transients guaranteed to remain until expiration?

No. Transients can disappear before their expiration time because of object-cache eviction, cache flushing, cleanup processes, or hosting configuration.
The endpoint must always be able to recreate the response when the transient is unavailable.

Should authenticated REST API responses be cached?

Authenticated responses can be cached, but the cache key and storage method must prevent data from crossing user, role, website, or permission boundaries.
For sensitive endpoints, caching shared underlying data may be safer than caching the complete personalized response.

When is cursor pagination better than offset pagination?

Cursor pagination is useful for large, frequently changing collections where deep offsets become slow or records may move between pages.
The cursor should be based on indexed, deterministic fields such as a timestamp combined with a unique record ID.

Should every REST API endpoint use caching?

Not necessarily. Small, inexpensive, rarely requested, or highly dynamic endpoints may not benefit enough from response caching.
Caching should be introduced when measurement shows that it reduces meaningful database work or improves user-visible response times without weakening correctness.

How can developers prevent duplicate records between pages?

Use stable ordering with a unique tie-breaker. For example, sort by modified date and then by record ID.
For rapidly changing datasets, cursor pagination may provide more consistent sequential results than offset pagination.

Post a Comment