Make WordPress Core

Opened 4 years ago

Closed 16 months ago

Last modified 16 months ago

#52636 closed enhancement (wontfix)

Add proper Cache-Control header to /wp-json REST endpoints

Reported by: isaumya's profile isaumya Owned by:
Milestone: Priority: normal
Severity: major Version:
Component: REST API Keywords: needs-patch
Focuses: rest-api Cc:

Description

Hi,
I've been doing some through audits with the wp-json endpoint, especially in terms of caching. Currently if you look at the Response of any WP-JSON endpoints you will see that there is no Cache-control header specified.

This leads to these responses being cached via CDN and browsers.
While digging deeper I found that the only way to do this is by reinitializing the rest-api as it is shown here.

But this seems like a hack. The REST endpoints should never be cached in the first place. Looking deeper into it I found that inside /wp-includes/rest-api/class-wp-rest-response.php on line no 160 the system is setting a Link header. Then why not set the proper cache-control header as well? We can take advantage of wp_get_nocache_headers() to pass the proper cache-control headers for the wp-json endpoints.

Another problem is currently as the /wp-json endpoint is being set and managed by PHP, adding a simply add_headers in nginx.conf does nothing as the file is generated by PHP and any response headers needs to be added at the PHP level only.

Change History (11)

#1 follow-up: @TimothyBlynJacobs
4 years ago

Hi @isaumya, thanks for the ticket and welcome back to trac!

Why shouldn't wp-json be cached? The REST API server sends no-cache headers if the user is logged in.

#2 in reply to: ↑ 1 @isaumya
4 years ago

Hi @TimothyBlynJacobs,
Thanks for looking into it. The reason it shouldn't be cached is let's imagine that you are creating an app or something which fetches the data from the API to show in the app or something like that. Now if the API endpoints are cached in a CDN then that app will only show the data that it gets from the cached endpoints. Moreover, if the data is cached and you add/update something inside your website and then inside Gutenberg, you are trying to add a hyperlink or find something which is not present in the cached content, this might lead to an issue.

It is kind of the same reason sitemaps shouldn't be cached so that it always gives the latest and most updated content. Only the things that get rarely changed like static pages, posts etc. should be cached. Do you feel otherwise?

P.S.: On a side note, as JavaScript frameworks are getting more and more popular a lot of people just using WP as a headless CMS fully depending on the API to create their website.

P.P.S: In case you feel that this shouldn't be the default behaviour for some reason, maybe WP can provide a WP Config define or a filter to enable this option for those who want it and keep it like what it is for the rest of the people.

Last edited 4 years ago by isaumya (previous) (diff)

#3 @thegulshankumar
4 years ago

+1

Some plugin uses the end point for the logged out users.

https://i.imgur.com/Li98eJJ.png

https://i.imgur.com/Bov6cOF.png

Therefore, Rest API end point should have a Cache-Control header that prevents caching in the Browser and intermediary reverse-proxy CDN.

#4 @TimothyBlynJacobs
4 years ago

WordPress doesn't send no-cache headers for the sitemap. The REST API also shouldn't for the same reasons WordPress doesn't send no-cache headers for other public pages as well.

That plugin appears to be using a GET request for something that has side effects. They should be using a POST request. If they want to keep using a GET request they can easily send no-cache headers themselves by adding it to the WP_REST_Response object they return from their endpoint.

If you want to send no-cache headers globally you can use the existing rest_send_nocache_headers filter.

#5 @isaumya
4 years ago

Thank you so much @TimothyBlynJacobs for informing me about rest_send_nocache_headers filter. I didn't found it after Googling for many days until I searched exactly for this. So happy to see there is a filter for it.

#6 @isaumya
4 years ago

  • Resolution set to wontfix
  • Status changed from new to closed

#7 @peterwilsoncc
4 years ago

  • Milestone Awaiting Review deleted

#8 @isaumya
16 months ago

  • Resolution wontfix deleted
  • Status changed from closed to reopened

Sorry to re-open this 3-year-old ticket again. But I've find something weird that I would like to share and ask for a proper way of handling this.

So, earlier @TimothyBlynJacobs suggested using the rest_send_nocache_headers filter which works great for adding no-cache Cache-Control header to all WP Core rest endpoints.

But testing over the last few years I have seen that despite using that above-mentioned filter in the code, REST endpoint added by other plugins like /wp-json/autonami-webhook/sms/twilio/123 or /wp-json/woofunnels/v1/worker and there are many more cases like these where I do not see the no-cache Cache-Control header despite that filter being enabled.

I think WP Core team should look into it and make sure if the above-mentioned filter is enabled, the proper no-cache Cache-Control header is added to the REST request regardless of whether the endpoint is WP Core endpoint or it a custom endpoint added by some external plugins.

Currently, there is no way to achieve this despite using that filter. I even spoke to some plugin devs and they said that they are using WP Coding guidelines to build their REST endpoint and they have no idea why the core filter is not adding the Cache-Control header.

#9 @TimothyBlynJacobs
16 months ago

  • Resolution set to wontfix
  • Status changed from reopened to closed

WordPress Core does not differentiate between Core endpoints and non-Core endpoints. You can see that here:

https://github.com/WordPress/wordpress-develop/blob/e707e37f23dcb6723ba3cea22d45f8f35ef95deb/src/wp-includes/rest-api/class-wp-rest-server.php#L483

I was able to find the WooFunnels code, and they are #doingitwrong by calling wp_send_json in their REST API callback. This completely stops the REST API server from sending the request.

https://plugins.trac.wordpress.org/browser/funnel-builder/trunk/woofunnels/as-data-store/class-woofunnels-as-ds.php#L280

I wasn't able to easily find the autonami-webhook code, but I'm guessing they are making a similar error.

#10 @isaumya
16 months ago

Hi @TimothyBlynJacobs,
Thanks a lot for your reply. So, can you share a link to how these plugin developers should handle this? Then I can pass this specific URL to these plugin devs and ask them to update their code by following the path shown in the URL you provide.

Currently, if I tell them that they are doing things in the wrong way then they say that they are doing it the correct way. Finally, I don't have any URL that I can send them to show how they should be doing things.

Thanks in advance.

#11 @TimothyBlynJacobs
16 months ago

Developers should be returning a WP_REST_Response object from their endpoint callback. The relevant docs can be found here: https://developer.wordpress.org/rest-api/extending-the-rest-api/adding-custom-endpoints/

Note: See TracTickets for help on using tickets.