Download the PHP package hryvinskyi/magento2-browser-cache-control without Composer

On this page you can find all versions of the php package hryvinskyi/magento2-browser-cache-control. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package magento2-browser-cache-control

Magento 2 & Adobe Commerce Browser Cache Control

Gives the visitor's browser a short Cache-Control lifetime on full-page-cacheable storefront responses, from inside Magento — without shortening how long the shared cache keeps them.

Description

Magento never lets a browser cache a page, and it does so for a different reason in each caching application. Normally the fix is two lines of VCL:

This module is for the installations where that edit is not available: a managed Varnish whose VCL you do not control, or a stack with no Varnish at all, running Magento's built-in full page cache.

It never invents cacheability. A response qualifies only if Magento itself declared it full-page cacheable, or served it out of the full page cache. Everything else — checkout, customer account, anything marked uncacheable — keeps the headers Magento gave it, untouched.

What Magento does today, and why that shapes everything here

Four facts out of the 2.4.x source. They are the whole design rationale.

  1. Response\Http::setPublicHeaders($ttl) emits Pragma: cache, Cache-Control: public, max-age=<ttl>, s-maxage=<ttl>, Expires: now+ttl. It is called for every cacheable page, and also by the ESI block endpoint (with the block's lifetime, which is 0 when no block matched) and by the swatch media endpoint. The last two are not page views.

  2. The built-in full page cache deliberately forbids browser caching. Framework\App\PageCache\Kernel::process() matches /public.*s-maxage=(\d+)/, then calls $response->setNoCacheHeaders() before serialising the response into the cache. So the stored entry carries no-store, no-cache, must-revalidate, max-age=0, and Kernel::load() replays those headers on every hit. A browser is told "never store this" on both a miss and a hit. That is what this module fixes.

  3. The built-in cache reads its own storage lifetime out of the s-maxage it finds in that header. Anything that drops public or s-maxage before process() runs silently switches whole-page caching off. This is why the module leaves the declaration moment strictly alone under the built-in cache.

  4. Magento's shipped VCL rewrites Cache-Control on the way out — and private is the one value that survives it. module-page-cache/etc/varnish{5,6,7}.vcl, identical in all three:

    That is the very block the VCL snippet above replaces. Its guard is also a door: a response containing private passes through untouched.

What it emits

Caching application Emitted header Reaches the browser?
Built-in (1) private, must-revalidate, max-age=<n> Always — bare, and through an unmodified Magento VCL
Varnish (2) public, must-revalidate, max-age=<n>, s-maxage=<declared> Only behind a CDN or a customised VCL

Pragma becomes cache and Expires is removed in both cases. All three headers move together, because Magento's no-cache set writes all three and any survivor would contradict the other two.

With Varnish as the caching application and a stock VCL, no origin-side solution exists. Anything public is overwritten in vcl_deliver; anything containing private is marked beresp.uncacheable by vcl_backend_response and Varnish stops caching pages altogether. The VCL snippet works only because vcl_deliver runs after Varnish has already stored the object — a moment the origin does not have. The Varnish strategy ships for CDN-fronted installations; if you can edit the VCL, edit the VCL.

The built-in caching application covers both cases this module was written for: no Varnish, and a Varnish you cannot edit.

Features

Configuration

Stores → Configuration → Hryvinskyi → Browser Cache Control, ACL resource Hryvinskyi_BrowserCacheControl::config. All fields are shown at default, website and store-view scope and are read at store scope.

Path (under hryvinskyi_browser_cache_control/general/) Field Default
enabled Enabled 0
browser_ttl Browser lifetime, in seconds 120
must_revalidate Require revalidation 1
excluded_url_patterns Excluded URL patterns ^/(media\|static)/

Notes that are easy to get wrong:

Verifying it

Expect max-age=120, must-revalidate, private under the built-in cache — alphabetically ordered, no s-maxage, no public, no Expires. Run it twice: the first request is a cache miss, the second a hit, and both must carry it. A checkout or customer page must carry none of it.

A signed-in visitor gets nothing on a built-in cache hit, and that is correct rather than a bug: a hit short-circuits before routing, so Framework\App\Http\Context is empty and its vary string is null while the visitor's X-Magento-Vary cookie is a hash. Magento's own HttpPlugin::beforeSendResponse sees the mismatch and strips the caching headers. Guests match null to null and keep them.

How it works

Three plugins, two logical write points, and none of them at response-send time.

Seam Write point Live when
after Response\Http::setPublicHeaders($ttl) SharedCacheDeclaration Varnish is the caching application
after PageCache\Kernel::process() — a miss BuiltInDelivery built-in is the caching application
after PageCache\Kernel::load() — a hit BuiltInDelivery built-in is the caching application

Why not beforeSendResponse, the obvious seam: PageCache\Model\App\Response\HttpPlugin::beforeSendResponse strips the caching headers when the visitor's X-Magento-Vary cookie disagrees with the current context. That guard has to keep winning. Writing earlier leaves it the last word for free; writing at send time would mean negotiating plugin sortOrder against core or duplicating core's vary logic. The ordering guarantee comes from which methods are plugged, which is why etc/frontend/di.xml declares no sortOrder at all.

Why the declaration moment for Varnish — nothing has stored the response yet, so what is written there is what the shared cache keeps and obeys. It is the only moment at which a lifetime meant for a shared cache can be announced.

Why not that moment under the built-in cache — see fact 3 above. The built-in path writes only after the copy has been taken, where it changes what the visitor is told and nothing else.

Why Kernel::load() matters most — see fact 2. Without it, the repeat visitor, who has already proved they come back, gains nothing at all.

Layering

The decision and everything below it work on plain values and are unit-tested without Magento present. ApplyBrowserCacheTtl contains no test for the caching application or the write point anywhere — those are asked once, of the strategy. Keeping it that way is the property to protect in review.

The five eligibility rules

All must agree. Order only decides how quickly a rejection is reached.

Rule Rejects when
RequestMethodRule the method is not GET or HEAD
ResponseStatusRule the status is not 200 or 404 — the pair Kernel::process() stores
ResponseIsCacheableRule the response is a NotCacheableInterface, or carries the NotCacheable metadata flag
ExcludedActionRule the full action name is magento_pagecache_block_esi or swatches_ajax_media
ExcludedUrlRule the request path matches a configured exclusion

Developer notes

Adding a caching application

One class implementing Api\PageCacheStrategyInterfaceownsWritePoint(), sharedTtlToPublish(), isPublic() — plus one entry in the strategy pool, keyed by the value stored in system/full_page_cache/caching_application:

No existing file changes. An unrecognised caching application leaves responses alone and logs one warning per request — it never throws, because this runs on every storefront page render.

Adding an exclusion

One class implementing Api\EligibilityRuleInterfaceisEligible(ResponseSnapshot): bool — added to the rules argument of Model\ApplyBrowserCacheTtl. Rules never know about each other, so a new reason to skip is a new class rather than a new branch.

Traps worth knowing before you touch this

Why there is no no-store option

The VCL snippet carries one, commented out, labelled "disable back/forward cache". It is not implemented here and will not be. no-store is unconditional in RFC 9111 §5.2.2.5 — a cache told no-store keeps no part of the response — so pairing it with max-age does not mean "cache briefly but skip the back/forward cache", it means "cache nothing", and the lifetime beside it is dead text. Suppressing the back/forward cache is a consequence of storing nothing, not a capability that can be had while still caching. At the origin it would also be destructive: Magento's vcl_backend_response turns a no-store backend response into hit-for-pass, so Varnish would stop caching the page entirely.

Tests

188 unit tests cover the domain, the rules, both strategies, the decision matrix and all three plugins; 8 integration tests cover the emitted headers under each caching application. The --autoload-file on the phpstan line is required for any Magento integration test: Magento\TestFramework\ is not in composer autoload, and the integration framework self-registers at runtime.

Dependencies

etc/module.xml sequences Magento_PageCache and Magento_Store, so this module's plugins load in the right relationship to Magento's own page cache plugins. Everything is registered in the frontend area only — the admin panel, the web APIs and GraphQL are deliberately untouched.

Author

Volodymyr Hryvinskyi

License

Proprietary


All versions of magento2-browser-cache-control with dependencies

PHP Build Version
Package Version
Requires php Version ~8.1.0||~8.2.0||~8.3.0||~8.4.0||~8.5.0
magento/framework Version *
magento/module-backend Version *
magento/module-config Version *
magento/module-page-cache Version *
magento/module-store Version *
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package hryvinskyi/magento2-browser-cache-control contains the following files

Loading the files please wait ...