PHP Cache-Control

I have a plugin that adds a custom json response context but it seems that I cannot set the Cache-Control and Expires directives. In the example below, I’ve set it to 60 seconds.

public function filterResponseContexts( $contexts )
{
	$contexts['custom-json'] = array(
		'suffix' => 'cjson',
		'headers' => array( 
			'Content-Type' => 'application/json',
			'Access-Control-Allow-Origin'=>'*',
			'Cache-Control' => 'public, max-age=60',
			'Expires' => gmdate('D, d M Y H:i:s \G\M\T', time() + 60),
		) );
	return $contexts;
}

But when I look at the response headers for the JSON file, it shows the following:

cache-control: no-store, no-cache, must-revalidate, public, max-age=3600
expires: Thu, 19 Nov 1981 08:52:00 GMT, Tue, 06 May 2025 17:07:02 GMT

So it seems like it’s adding to – but not replacing – the default values.

Any ideas why this might be?

full response

X-Firefox-Spdy: h2
access-control-allow-origin: *
cache-control: no-store, no-cache, must-revalidate, public, max-age=60
content-encoding: gzip
content-security-policy: upgrade-insecure-requests
content-type: application/json
date: Tue, 06 May 2025 17:06:01 GMT
expires: Thu, 19 Nov 1981 08:52:00 GMT, Tue, 06 May 2025 17:07:02 GMT
pragma: no-cache
referrer-policy: strict-origin-when-cross-origin
server: 
strict-transport-security: max-age=31536000; includeSubDomains
vary: Accept-Encoding,User-Agent
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: en-US,en;q=0.5
Connection: keep-alive
DNT: 1
Host: mydomain.org
Priority: u=0, i
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Sec-GPC: 1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:138.0) Gecko/20100101 Firefox/138.0

There’s a PHP setting that sends caching headers, which you’d need to change.

Explanation is here in the PHP manual, setting is session.cache_limiter.

Edit: actually, in your situation, just calling the function to change it (to '') is better, I suppose.

Ok, thanks. So I guess I can’t just set those directives when filtering the response contexts. Instead, I add it to the beginning of the actual output.

<?php
header('Expires: '.gmdate('D, d M Y H:i:s \G\M\T', time() + 60));
header("Cache-Control: public, max-age=60");
// ...begin json output 

EDIT: I was previously calling session_cache_limiter('public) above but have removed it since it doesn’t seem to matter in this particular context. But if anyone does find a need for that you’ll probably want to wrap it in something like:

<?php
// ...
if(!isset($_SESSION)){
  session_cache_limiter('public);
}