{"id":345526,"date":"2026-08-14T07:37:17","date_gmt":"2026-08-14T07:37:17","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/nginx-cache-purger\/"},"modified":"2026-08-14T07:36:53","modified_gmt":"2026-08-14T07:36:53","slug":"reqad-cache-purger","status":"publish","type":"plugin","link":"https:\/\/tzm.wordpress.org\/plugins\/reqad-cache-purger\/","author":23092285,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.1.1","stable_tag":"1.1.1","tested":"7.0.4","requires":"6.0","requires_php":"7.4","requires_plugins":null,"header_name":"Reqad Cache Purger for Nginx","header_author":"Webdev","header_description":"Manages Nginx FastCGI cache for WordPress with global and automatic purging for posts, pages, and WooCommerce products\/categories.","assets_banners_color":"","last_updated":"2026-08-14 07:36:53","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/github.com\/wbdv\/reqad-cache-purger","header_author_uri":"https:\/\/www.webdev.ro","rating":0,"author_block_rating":0,"active_installs":0,"downloads":34,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.1.1":{"tag":"1.1.1","author":"wbdv","date":"2026-08-14 07:36:53"}},"upgrade_notice":{"1.1.1":"<p>Fixes the Site Health &quot;Page cache is not detected&quot; warning and adds a conflict\nwarning when another page cache plugin is active.<\/p>","1.1.0":"<p>Adds an optional background cache warmer and a Settings page. Existing behaviour\nis unchanged unless you turn these on.<\/p>","1.0.2":"<p>Adds comment, theme, menu, widget and Customizer purge triggers.<\/p>","1.0.1":"<p>Fixes a spoofable Host header used to build the outbound purge URL, enables SSL\nverification, and purges the home page and archives - not just the edited post.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3647059,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3647059,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":[],"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.1.1"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3646863,"resolution":"1","location":"assets","locale":"","width":1568,"height":919}},"screenshots":{"1":"The Settings page: the requirements banner, optional cache warmer, purge-endpoint override, WP-Cron helper and one-click cache self-test."}},"plugin_section":[],"plugin_tags":[146,45947,2437,7914,286],"plugin_category":[45,52],"plugin_contributors":[275655],"plugin_business_model":[],"class_list":["post-345526","plugin","type-plugin","status-publish","hentry","plugin_tags-cache","plugin_tags-fastcgi","plugin_tags-nginx","plugin_tags-purge","plugin_tags-woocommerce","plugin_category-ecommerce","plugin_category-performance","plugin_contributors-wbdv","plugin_committers-wbdv"],"banners":[],"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/reqad-cache-purger\/assets\/icon-128x128.png?rev=3647059","icon_2x":"https:\/\/ps.w.org\/reqad-cache-purger\/assets\/icon-256x256.png?rev=3647059","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/reqad-cache-purger\/assets\/screenshot-1.png?rev=3646863","caption":"The Settings page: the requirements banner, optional cache warmer, purge-endpoint override, WP-Cron helper and one-click cache self-test."}],"raw_content":"<!--section=description-->\n<p>Reqad Cache Purger keeps an Nginx FastCGI page cache in step with WordPress. It\nadds a \"Purge Nginx Cache\" button to the admin bar for clearing the whole site,\nand purges the affected pages by itself whenever content changes.<\/p>\n\n<p>It works with nothing configured: the plugin sends an HTTP request to a <code>\/purge<\/code>\nlocation that Nginx handles, and the caching policy itself lives entirely in\nyour Nginx configuration. A Settings page exists for the optional extras - a\nbackground cache warmer, a purge-endpoint override for sites behind a proxy, and\na cache self-test - but you can ignore all of it.<\/p>\n\n<p><strong>What it purges<\/strong><\/p>\n\n<ul>\n<li>Admin-bar button - the entire cache, in a single wildcard request.<\/li>\n<li>A post or page published, updated, unpublished or trashed - its permalink, the\nhome page and its public taxonomy archives.<\/li>\n<li>A WooCommerce product - the above, plus the shop page.<\/li>\n<li>A term created, edited or deleted in any public taxonomy - its archive and the\nhome page.<\/li>\n<\/ul>\n\n<p>Post types with no front-end URL (menu items, revisions, WooCommerce orders and\nsimilar) are skipped, because they were never cached in the first place.<\/p>\n\n<p><strong>Requirements<\/strong><\/p>\n\n<p>This plugin does not cache anything itself - Nginx does. It requires Nginx built\nwith the ngx_cache_purge module from https:\/\/github.com\/nginx-modules\/ngx_cache_purge\n- the actively maintained continuation of Piotr Sikora's original module, which\npassed through torden's fork around 2017. If you have seen it called \"the Torden\nfork\", that is the same lineage.<\/p>\n\n<p>The abandoned FRiCKLE repository will not work: the admin-bar button clears the\nsite with a single wildcard request, and wildcard purging landed after FRiCKLE\ndevelopment stopped around 2015.<\/p>\n\n<p>Check yours with:<\/p>\n\n<pre><code>nginx -V 2&gt;&amp;1 | tr ' ' '\\n' | grep cache_purge\n<\/code><\/pre>\n\n<p>Full Nginx configuration, including a tested FastCGI cache setup with\nWooCommerce-safe bypass rules, is in README.md in the plugin folder.<\/p>\n\n<!--section=installation-->\n<h4>1. Nginx<\/h4>\n\n<p>You need a working FastCGI cache and a purge location. Minimal version - see\nREADME.md for the complete configuration:<\/p>\n\n<p>In the <code>http<\/code> context (the top of your site's file in <code>conf.d\/<\/code> is fine):<\/p>\n\n<pre><code>fastcgi_cache_path \/var\/cache\/nginx\/wpcache levels=1:2 keys_zone=wpcache:100m\n                   inactive=12h max_size=512m;\n<\/code><\/pre>\n\n<p>In <code>server { }<\/code>:<\/p>\n\n<pre><code>location ~ ^\/purge(\/.*) {\n    allow 127.0.0.1;\n    allow ::1;\n    allow 203.0.113.10;   # this server's own public IP\n    deny  all;\n\n    cache_purge_response_type json;\n    fastcgi_cache_purge wpcache \"$scheme$host$1\";\n}\n<\/code><\/pre>\n\n<p>In the PHP location:<\/p>\n\n<pre><code>open_file_cache          off;\nfastcgi_cache            wpcache;\nfastcgi_cache_key        \"$scheme$host$request_uri\";\nfastcgi_cache_methods    GET;\nfastcgi_cache_valid      200 301 302 12h;\nfastcgi_ignore_headers   Cache-Control Expires;\n<\/code><\/pre>\n\n<p>Three things that catch people out:<\/p>\n\n<ul>\n<li>Use <code>$request_uri<\/code>, not <code>$uri<\/code>, in the cache key. WordPress routes everything\nthrough <code>try_files ... \/index.php<\/code>, so <code>$uri<\/code> becomes <code>\/index.php<\/code> and the\nwhole site collapses onto one cache entry.<\/li>\n<li>Leave <code>$request_method<\/code> out of the key, and set <code>fastcgi_cache_methods GET<\/code>.\nOtherwise GET and HEAD are stored separately and the HEAD copies can never be\npurged.<\/li>\n<li>If you set a global <code>open_file_cache<\/code>, turn it off in the cached location.\nNginx caches the descriptors of cache files too, so purges appear to do\nnothing for up to <code>open_file_cache_valid<\/code> seconds.<\/li>\n<\/ul>\n\n<p>The key expression in the purge location must match <code>fastcgi_cache_key<\/code> exactly,\nwith <code>$1<\/code> in place of the path. If they differ, every purge returns 412.<\/p>\n\n<p>Then:<\/p>\n\n<pre><code>nginx -t &amp;&amp; systemctl reload nginx\n<\/code><\/pre>\n\n<h4>2. The plugin<\/h4>\n\n<ol>\n<li>Upload the <code>reqad-cache-purger<\/code> folder to <code>wp-content\/plugins\/<\/code>, or install\nthe zip through Plugins &gt; Add New &gt; Upload Plugin.<\/li>\n<li>Activate it through the Plugins menu.<\/li>\n<\/ol>\n\n<p>There is nothing to configure. The purge URL is derived from your site address.<\/p>\n\n<h4>3. Check it<\/h4>\n\n<pre><code>curl -sI https:\/\/example.com\/ | grep -i x-fastcgi-cache   # MISS\ncurl -sI https:\/\/example.com\/ | grep -i x-fastcgi-cache   # HIT\ncurl -s  https:\/\/example.com\/purge\/                       # {\"Status\": \"purged\"}\ncurl -s  \"https:\/\/example.com\/purge\/*\"                    # 200 = correct module\n<\/code><\/pre>\n\n<p>Add <code>add_header X-FastCGI-Cache $upstream_cache_status always;<\/code> while testing.<\/p>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20this%20plugin%20cache%20my%20pages%3F\"><h3>Does this plugin cache my pages?<\/h3><\/dt>\n<dd><p>No. Nginx does the caching; this plugin only tells it what to throw away.<\/p><\/dd>\n<dt id=\"why%20doesn%27t%20it%20work%20with%20the%20frickle%20ngx_cache_purge%20module%3F\"><h3>Why doesn't it work with the FRiCKLE ngx_cache_purge module?<\/h3><\/dt>\n<dd><p>That module purges one exact key per request and has no wildcard support, so the\n\"purge everything\" button cannot work. It has also been unmaintained since 2015\nand no longer builds against current Nginx. Use\nhttps:\/\/github.com\/nginx-modules\/ngx_cache_purge instead.<\/p><\/dd>\n<dt id=\"purges%20return%20403.\"><h3>Purges return 403.<\/h3><\/dt>\n<dd><p>The request is not reaching Nginx from an address in your <code>allow<\/code> list. The\nplugin calls the site's own public hostname, so the source address is normally\nthe server's public IP - not 127.0.0.1. Behind a proxy that sets\n    real_ip_header, <code>$remote_addr<\/code> becomes the visitor's address instead; in that\ncase point the plugin at your origin with the <code>ngxcp_purge_endpoint<\/code> filter.<\/p><\/dd>\n<dt id=\"purges%20return%20412.\"><h3>Purges return 412.<\/h3><\/dt>\n<dd><p>412 means \"this key was not in the cache\". For a page nobody has requested yet\nthat is normal and the plugin treats it as success. If it happens for pages that\nare definitely cached, your purge-location key expression does not match\n    fastcgi_cache_key.<\/p><\/dd>\n<dt id=\"nothing%20happens%20when%20content%20changes.\"><h3>Nothing happens when content changes.<\/h3><\/dt>\n<dd><p>Enable <code>WP_DEBUG<\/code> and <code>WP_DEBUG_LOG<\/code>. Every purge attempt is logged to\n    wp-content\/debug.log with an <code>NGXCP:<\/code> prefix, including the URL and HTTP status.<\/p><\/dd>\n<dt id=\"can%20i%20change%20where%20purge%20requests%20are%20sent%3F\"><h3>Can I change where purge requests are sent?<\/h3><\/dt>\n<dd><p>Yes, with the <code>ngxcp_purge_endpoint<\/code> filter. <code>ngxcp_purge_sslverify<\/code> controls\ncertificate verification, and <code>ngxcp_paths_for_post<\/code> controls which paths are\npurged when a post changes. See README.md.<\/p><\/dd>\n<dt id=\"does%20it%20work%20with%20woocommerce%3F\"><h3>Does it work with WooCommerce?<\/h3><\/dt>\n<dd><p>Yes. Product and product-category purging switch on automatically. Make sure\nyour Nginx bypass rules exclude cart, checkout, my-account and the WooCommerce\nsession cookies - the configuration in README.md does.<\/p><\/dd>\n<dt id=\"can%20i%20use%20it%20with%20wp%20rocket%2C%20w3%20total%20cache%20or%20litespeed%20cache%3F\"><h3>Can I use it with WP Rocket, W3 Total Cache or LiteSpeed Cache?<\/h3><\/dt>\n<dd><p>Not for page caching, no. Those plugins store rendered HTML themselves, and\nNginx then caches <em>their<\/em> output - two caches with two lifetimes and two purge\nmechanisms that know nothing about each other, so pages go stale in ways no\nsingle purge fixes. Turn page caching off in the other plugin (its minification,\ndatabase and CDN features are fine to keep), or drop the fastcgi_cache\ndirectives from your vhost and let that plugin do the caching. The Settings page\nwarns you when it detects one.<\/p>\n\n<p>Object caches such as Redis Object Cache work fine - they are a different layer.<\/p><\/dd>\n<dt id=\"site%20health%20says%20%22page%20cache%20is%20not%20detected%22.\"><h3>Site Health says \"Page cache is not detected\".<\/h3><\/dt>\n<dd><p>Core's test looks for a fixed list of caching headers and does not know\n    x-fastcgi-cache. The plugin registers the header with core, so the test should\npass once this plugin is active. If it still does not, either the cache status\nheader is missing from your vhost, or the home page is being bypassed - run the\ncache self-test on the Settings page to see which. You can also emit the name\ncore already knows: <code>add_header X-Cache-Status $upstream_cache_status always;<\/code>.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.1.1<\/h4>\n\n<ul>\n<li>New: the Settings page warns when another full-page cache plugin is active\n(WP Rocket, W3 Total Cache, WP Super Cache, LiteSpeed Cache and others), or\nwhen an unidentified advanced-cache.php drop-in is loaded. Two page caches\nstacked on each other cause stale pages that a purge cannot fix.<\/li>\n<li>New: also warns, less loudly, about other Nginx purgers.<\/li>\n<li>Fixed: WordPress Site Health reported \"Page cache is not detected\" on properly\nconfigured sites, because core does not know the X-FastCGI-Cache header. The\nplugin now registers it.<\/li>\n<li>The cache self-test and warmer accept X-Cache-Status and X-Proxy-Cache as well\nas X-FastCGI-Cache.<\/li>\n<li>Settings page polish: a requirements note, the conflict warning shown as a red\nWARNING box, a WP-Cron panel that confirms (and hides its setup steps) once the\nworker has run in the last 3 minutes, and footer links to the setup guide and a\nGitHub star.<\/li>\n<\/ul>\n\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>New: optional background cache warmer. When enabled, purged URLs are re-fetched\non a cron tick so visitors keep hitting cached pages. A full purge warms a\nbounded set (home page + recent posts), never the whole sitemap at once.<\/li>\n<li>New: Settings page (Settings -&gt; Nginx Cache Purger) - toggle the warmer, set a\npurge-endpoint \/ SSL-verify override, a WP-Cron panel that can add\nDISABLE_WP_CRON to wp-config.php and shows the last worker run, and a one-click\ncache self-test built on the X-FastCGI-Cache header.<\/li>\n<li>The purge endpoint and SSL-verify can now be set from the Settings page as well\nas the filters; a code filter still wins.<\/li>\n<li>New: Settings link on the plugin's row in the Plugins list.<\/li>\n<li>All optional - with nothing configured the plugin behaves exactly as before.<\/li>\n<\/ul>\n\n<h4>1.0.2<\/h4>\n\n<ul>\n<li>New purge triggers: a new or edited comment (and approve\/unapprove\/spam\/trash)\nnow purges the post it belongs to.<\/li>\n<li>Theme switch, nav-menu changes, widget changes and Customizer saves now purge\nthe whole cache, since they affect every page.<\/li>\n<li>Multiple site-wide triggers firing in one request collapse into a single\nwildcard purge.<\/li>\n<\/ul>\n\n<h4>1.0.1<\/h4>\n\n<ul>\n<li>Security: the purge URL is built from the site address instead of the\nclient-supplied Host header, which could be spoofed into making the site issue\nan outbound request to an attacker-chosen host.<\/li>\n<li>Security: SSL verification on the purge request is enabled by default, with\nthe <code>ngxcp_purge_sslverify<\/code> filter for setups that need it off.<\/li>\n<li>Purging a post now also clears the home page, its taxonomy archives and, for\nproducts, the shop page - previously only its own permalink.<\/li>\n<li>Unpublishing, trashing and permanently deleting a post now purge. Previously\nonly transitions to <code>publish<\/code> did, so content pulled offline stayed cached.<\/li>\n<li>Deleting a term now purges; the old handler always bailed out because\n  delete_term fires after the term is already gone.<\/li>\n<li>Term purging covers every public taxonomy, not only <code>product_cat<\/code>.<\/li>\n<li>Post types that are not publicly viewable no longer trigger purge requests.<\/li>\n<li>A 412 response (key not in cache) counts as success instead of an error.<\/li>\n<li>The admin-bar button reports through a WordPress notice instead of a\nJavaScript alert, with a working spinner.<\/li>\n<li>Fixed the front-end admin-bar button, whose script only loaded in wp-admin.<\/li>\n<li>Added the <code>ngxcp_purge_endpoint<\/code>, <code>ngxcp_purge_sslverify<\/code> and <code>ngxcp_paths_for_post<\/code>\nfilters.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release: admin-bar purge button, automatic purging on post save, and\nWooCommerce product and product-category purging.<\/li>\n<\/ul>","raw_excerpt":"Purges the Nginx FastCGI cache when content changes - automatically on publish, update and delete, or site-wide from the admin bar.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/tzm.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/345526","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tzm.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/tzm.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/tzm.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=345526"}],"author":[{"embeddable":true,"href":"https:\/\/tzm.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/wbdv"}],"wp:attachment":[{"href":"https:\/\/tzm.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=345526"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/tzm.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=345526"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/tzm.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=345526"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/tzm.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=345526"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/tzm.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=345526"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/tzm.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=345526"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}