{"id":362344,"date":"2026-09-06T18:26:47","date_gmt":"2026-09-06T18:26:47","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/oh-my-cache\/"},"modified":"2026-09-06T18:26:24","modified_gmt":"2026-09-06T18:26:24","slug":"oh-my-cache","status":"publish","type":"plugin","link":"https:\/\/kk.wordpress.org\/plugins\/oh-my-cache\/","author":23510762,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.0.0","stable_tag":"1.0.0","tested":"7.1","requires":"6.2","requires_php":"8.1","requires_plugins":null,"header_name":"Oh My Cache!","header_author":"Buti\u00e1 Labs","header_description":"Clears your NGINX or Redis page cache and then Cloudflare and retries anything that fails instead of losing it.","assets_banners_color":"cdd1d5","last_updated":"2026-09-06 18:26:24","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/github.com\/butialabs\/oh-my-cache","header_author_uri":"","rating":0,"author_block_rating":0,"active_installs":0,"downloads":29,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.0":{"tag":"1.0.0","author":"butialabs","date":"2026-09-06 18:26:24","revision":3683815}},"upgrade_notice":[],"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3683815,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3683815,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3683815,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3683815,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.0.0"],"block_files":[],"assets_screenshots":[],"screenshots":[]},"plugin_section":[],"plugin_tags":[146,3863,3882,2437,45952],"plugin_category":[52,59],"plugin_contributors":[267126],"plugin_business_model":[],"class_list":["post-362344","plugin","type-plugin","status-publish","hentry","plugin_tags-cache","plugin_tags-cdn","plugin_tags-cloudflare","plugin_tags-nginx","plugin_tags-redis","plugin_category-performance","plugin_category-utilities-and-tools","plugin_contributors-butialabs","plugin_committers-butialabs"],"banners":{"banner":"https:\/\/ps.w.org\/oh-my-cache\/assets\/banner-772x250.png?rev=3683815","banner_2x":"https:\/\/ps.w.org\/oh-my-cache\/assets\/banner-1544x500.png?rev=3683815","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/oh-my-cache\/assets\/icon-128x128.png?rev=3683815","icon_2x":"https:\/\/ps.w.org\/oh-my-cache\/assets\/icon-256x256.png?rev=3683815","generated":false},"screenshots":[],"raw_content":"<!--section=description-->\n<p>Clears the page cache on your own server first, then the copy Cloudflare holds at the edge. One\nplugin, one list of URLs, so the two cannot disagree about what was cleared.<\/p>\n\n<ul>\n<li>NGINX FastCGI and proxy cache, by deleting the cache files or through ngx_cache_purge<\/li>\n<li>Redis page cache, using SCAN instead of a blocking KEYS sweep<\/li>\n<li>Cloudflare, one batch per API call, so a failed batch retries on its own<\/li>\n<li>A queue screen showing what was cleared, what failed, and who asked for it<\/li>\n<li>Sitemaps too, read from the index your site publishes rather than guessed from its name<\/li>\n<li>WooCommerce stock, prices and variations, which never fire a post save<\/li>\n<li>A switch per post type, for the ones whose changes should not clear anything<\/li>\n<li>A list of extra paths, such as \/llms.txt, cleared alongside every purge<\/li>\n<li>A setup wizard that checks your token, finds your zone and adds two cache rules<\/li>\n<li>A public API for other plugins, and WP-CLI commands for deploys<\/li>\n<\/ul>\n\n<h3>External services<\/h3>\n\n<p>The plugin talks to one outside service, the Cloudflare API. It clears the copy of your pages\nCloudflare holds at the edge, and, if you run the wizard's optional steps, reads and writes the\ncaching configuration of your own zone. Nothing else leaves your server: no update checker, no\nlicence check, no analytics.<\/p>\n\n<h4>Cloudflare API (https:\/\/api.cloudflare.com\/client\/v4\/)<\/h4>\n\n<p>Only contacted once you have configured a Cloudflare API token. Without one the plugin refuses\nthe request before anything leaves your server.<\/p>\n\n<p>What it sends, and when:<\/p>\n\n<ul>\n<li>Your Cloudflare API token, as an authorization header on every request below.<\/li>\n<li>The URLs to clear, in batches, whenever content changes on your site (a post saved, published\nor deleted, a comment or term edited, the theme switched), when you press a purge button on\nthe dashboard or admin bar, when a WP-CLI purge runs, and when the queue retries a batch that\nfailed earlier.<\/li>\n<li>Your site's hostname, once, while the wizard works out which zone belongs to it.<\/li>\n<li>Your zone identifier, on every request about that zone.<\/li>\n<li>The cache rules, if you ask the wizard to create them. They contain your WordPress and\nWooCommerce cookie name prefixes and, for a store, the cart, checkout and account paths taken\nfrom your WooCommerce settings.<\/li>\n<li>The zone settings being changed, if you ask the wizard to apply the recommended ones.<\/li>\n<\/ul>\n\n<p>It never sends visitor data, personal data or post content.<\/p>\n\n<h4>Cloudflare IP address ranges (https:\/\/api.cloudflare.com\/client\/v4\/ips)<\/h4>\n\n<p>Once a week WP-Cron fetches Cloudflare's published list of its own IP ranges. The plugin checks\nthat list to confirm a request really arrived through Cloudflare before it trusts the visitor\naddress in the CF-Connecting-IP header. The fetch carries no authentication and nothing about\nyour site beyond the user agent WordPress puts on any HTTP request. Until it first succeeds, the\nplugin falls back to a copy of the list shipped with it.<\/p>\n\n<p>This one runs whenever the plugin is active, including on sites that never configured Cloudflare.<\/p>\n\n<h4>Cloudflare's terms<\/h4>\n\n<p>Cloudflare, Inc. provides the service. Their terms and privacy policy:<\/p>\n\n<ul>\n<li>Terms of use: https:\/\/www.cloudflare.com\/website-terms\/<\/li>\n<li>Privacy policy: https:\/\/www.cloudflare.com\/privacypolicy\/<\/li>\n<\/ul>\n\n<h4>Requests to your own site<\/h4>\n\n<p>The plugin's other network requests never leave your own infrastructure and involve no third\nparty: clearing NGINX through ngx_cache_purge, reading your sitemap index, warming pages with the\npreloader, and reaching the Redis server whose address you configure yourself.<\/p>\n\n<h3>What the plugin stores<\/h3>\n\n<p>One custom table, <code>{prefix}oh_my_cache_jobs<\/code>, holds the queue of jobs waiting to run or retry.\nSettings live in the options table. WP-Cron runs the queue and cleans it up; the jobs that refresh\nthe sitemap list and the Cloudflare IP ranges are scheduled only while the features that need them\nare on, and removed when you switch them off. Turning on \"delete data on uninstall\" removes all of\nit when you delete the plugin. Leave it off and nothing is removed, so deactivating to debug a\nconflict does not cost you your configuration.<\/p>\n\n<h3>Credits<\/h3>\n\n<p>Licensed GPL-3.0-or-later, because it derives from two GPL projects and one of them is GPLv3.<\/p>\n\n<p>Nginx Helper by rtCamp, GPL-2.0-or-later, https:\/\/github.com\/rtCamp\/nginx-helper. Source of the\napproach to clearing a local page cache: the nginx cache file path derivation, the ngx_cache_purge\nalternative, the Redis key shape, and which WordPress events invalidate which URLs.<\/p>\n\n<p>App for Cloudflare by Digital Point, GPL-3.0, https:\/\/wordpress.org\/plugins\/app-for-cf\/. Source of\nthe approach to Cloudflare: the API client, resolving a zone from the hostname, the URLs a post\nchange invalidates, the guest-HTML cache rule and its s-maxage header, the static-content\nextension list, and the recommended zone settings.<\/p>\n\n<p>Both were reimplemented rather than copied. No code from App for Cloudflare Pro was used; it is\nproprietary, and has no cache clearing logic in any case. Nothing third party is bundled.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the plugin and activate it.<\/li>\n<li>Follow the wizard. It detects your NGINX cache folder and Redis, then connects Cloudflare.<\/li>\n<li>The last step runs a real purge and tells you whether it worked.<\/li>\n<\/ol>\n\n<h4>Keeping your Cloudflare token out of the database<\/h4>\n\n<p>Add this to <code>wp-config.php<\/code>:<\/p>\n\n<pre><code>define( 'OH_MY_CACHE_CF_API_TOKEN', 'your-token' );\n<\/code><\/pre>\n\n<p>or set <code>OH_MY_CACHE_CF_API_TOKEN<\/code> in the environment. The token is then never written to the\ndatabase, so it stays out of backups and staging copies, and the settings screen stops offering\na field for it.<\/p>\n\n<h4>If DISABLE_WP_CRON is set<\/h4>\n\n<p>Queued retries need something to run them:<\/p>\n\n<pre><code>* * * * * wp oh-my-cache queue run --all --quiet\n<\/code><\/pre>\n\n<p>Without a cron entry, anything that falls back to the queue never runs. The dashboard warns you\nwhen that happens.<\/p>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20it%20need%20the%20redis%20extension%3F\"><h3>Does it need the Redis extension?<\/h3><\/dt>\n<dd><p>Only if you turn the Redis driver on. It needs phpredis 6.0 or newer and does not bundle a\npure-PHP replacement. When phpredis is missing, the driver says so instead of failing quietly.<\/p><\/dd>\n<dt id=\"how%20long%20can%20a%20queued%20purge%20take%3F\"><h3>How long can a queued purge take?<\/h3><\/dt>\n<dd><p>Up to about a minute. WordPress will not spawn cron more than once every 60 seconds, so a queued\njob is never instant. Local cache clearing always runs immediately for that reason; only\nCloudflare gets deferred.<\/p><\/dd>\n<dt id=\"which%20sitemaps%20does%20it%20clear%3F\"><h3>Which sitemaps does it clear?<\/h3><\/dt>\n<dd><p>Whichever your site publishes. Core, Yoast SEO, Rank Math, All in One SEO and SEOPress are\ndetected, and the index is read twice a day for the file names, so a news sitemap, a taxonomy one\nor page two of a paginated one need no configuring. Editing a post clears its post type's files,\nits taxonomies, the author file and the news sitemap, and leaves the other types alone.<\/p>\n\n<p>The dashboard lists what was found. For anything undetected, put its index URL in the paths field\nunder When to purge, or use the <code>oh_my_cache_sitemap_urls<\/code> filter.<\/p><\/dd>\n<dt id=\"does%20it%20work%20with%20woocommerce%3F\"><h3>Does it work with WooCommerce?<\/h3><\/dt>\n<dd><p>Yes. WooCommerce writes stock, prices and variations straight to the database without saving the\npost, so the plugin listens to WooCommerce's own hooks: a price change or the last item selling\nout clears the product page, the shop page and the category archives.<\/p>\n\n<p>The cart, checkout and account pages never reach the edge, and neither do cart fragments. Twice\nover: the origin refuses to mark them cacheable, and the Cloudflare rule excludes their paths,\ntaken from your store's settings rather than the English defaults.<\/p><\/dd>\n<dt id=\"is%20it%20safe%20to%20cache%20html%20at%20the%20edge%3F\"><h3>Is it safe to cache HTML at the edge?<\/h3><\/dt>\n<dd><p>Only once clearing demonstrably works, which is why the wizard refuses a non-zero edge TTL until\na test purge has actually succeeded. Pages held at the edge while clearing is broken stay stale\nfor the whole TTL, and a visitor cannot get past them.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release.<\/li>\n<\/ul>","raw_excerpt":"Clears your NGINX or Redis page cache and then Cloudflare and retries anything that fails instead of losing it.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/kk.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/362344","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kk.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/kk.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/kk.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=362344"}],"author":[{"embeddable":true,"href":"https:\/\/kk.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/butialabs"}],"wp:attachment":[{"href":"https:\/\/kk.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=362344"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/kk.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=362344"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/kk.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=362344"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/kk.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=362344"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/kk.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=362344"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/kk.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=362344"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}