{"id":303287,"date":"2026-09-20T16:40:48","date_gmt":"2026-09-20T16:40:48","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/pigcache\/"},"modified":"2026-09-20T16:40:12","modified_gmt":"2026-09-20T16:40:12","slug":"pigcache","status":"publish","type":"plugin","link":"https:\/\/arq.wordpress.org\/plugins\/pigcache\/","author":15770015,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.0.29","stable_tag":"1.0.29","tested":"7.1.1","requires":"5.8","requires_php":"7.4","requires_plugins":null,"header_name":"PigCache","header_author":"PigCache","header_description":"Redis object-cache drop-in with optional SQL, HTML page, and fragment caching.","assets_banners_color":"","last_updated":"2026-09-20 16:40:12","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"","header_author_uri":"","rating":0,"author_block_rating":0,"active_installs":0,"downloads":47,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.29":{"tag":"1.0.29","author":"aixeiger","date":"2026-09-20 16:40:12","revision":3704447}},"upgrade_notice":{"1.0.0":"<p>Initial release.<\/p>"},"ratings":[],"assets_icons":[],"assets_banners":[],"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.0.29"],"block_files":[],"assets_screenshots":[],"screenshots":[]},"plugin_section":[],"plugin_tags":[146,67884,7913,247,45952],"plugin_category":[52,54],"plugin_contributors":[214320],"plugin_business_model":[],"class_list":["post-303287","plugin","type-plugin","status-publish","hentry","plugin_tags-cache","plugin_tags-html-cache","plugin_tags-object-cache","plugin_tags-performance","plugin_tags-redis","plugin_category-performance","plugin_category-security-and-spam-protection","plugin_contributors-aixeiger","plugin_committers-aixeiger"],"banners":[],"icons":{"svg":false,"icon":"https:\/\/s.w.org\/plugins\/geopattern-icon\/pigcache.svg","icon_2x":false,"generated":true},"screenshots":[],"raw_content":"<!--section=description-->\n<p>PigCache replaces WordPress\u2019s default object cache with <strong>Redis<\/strong> (official drop-in pattern), using PhpRedis when available or the bundled <strong>Predis<\/strong>. Configure the connection with <code>PIGCACHE_REDIS_*<\/code> constants in wp-config.php.<\/p>\n\n<p>Features:<\/p>\n\n<ul>\n<li><strong>Redis object cache<\/strong> drop-in (PhpRedis or bundled Predis)<\/li>\n<li><strong>SQL query cache<\/strong> (optional <code>db.php<\/code> drop-in) with per-table invalidation, so writing to one table does not discard results that never read it<\/li>\n<li><strong>Full-page HTML cache<\/strong> for anonymous visitors with tag-based selective invalidation on content changes<\/li>\n<li><strong>Fragment caching<\/strong> helpers backed by Redis<\/li>\n<li><strong>Tag-based selective invalidation<\/strong> \u2014 only affected pages are purged when a post, term, or comment changes<\/li>\n<\/ul>\n\n<p>Every feature listed above is included and fully enabled. The plugin has no license check, no trial period and no usage limit, and it does not contact any external service.<\/p>\n\n<p>The object cache drop-in is derived from <a href=\"https:\/\/github.com\/rhubarbgroup\/redis-cache\">Redis Object Cache<\/a> (GPLv3, Till Kr\u00fcss \/ Rhubarb Group).<\/p>\n\n<h3>External services<\/h3>\n\n<p>This plugin does not connect to any external service. All caching, invalidation and metrics happen on your own server and your own Redis instance.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the plugin files to <code>wp-content\/plugins\/pigcache<\/code>, or install through the WordPress plugins screen.<\/li>\n<li>Activate the plugin through the <strong>Plugins<\/strong> screen.<\/li>\n<li>Go to <strong>Settings \u2192 PigCache<\/strong> and use <strong>Enable object cache (copy drop-in)<\/strong> when you are ready.<\/li>\n<li>Optionally install the <strong>SQL cache<\/strong> drop-in from the same screen.<\/li>\n<li>For the full-page HTML cache, install the <code>advanced-cache.php<\/code> drop-in from the same screen and add <code>define( 'WP_CACHE', true );<\/code> to your <code>wp-config.php<\/code>. The plugin never edits <code>wp-config.php<\/code> for you.<\/li>\n<\/ol>\n\n<p>Do not run another full Redis object-cache plugin at the same time; PigCache replaces that role.<\/p>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20this%20work%20without%20redis%3F\"><h3>Does this work without Redis?<\/h3><\/dt>\n<dd><p>No. A reachable Redis server is required for the object cache (and for HTML\/fragment features that use Redis).<\/p><\/dd>\n<dt id=\"is%20this%20the%20same%20as%20%E2%80%9Credis%20object%20cache%E2%80%9D%3F\"><h3>Is this the same as \u201cRedis Object Cache\u201d?<\/h3><\/dt>\n<dd><p>PigCache includes its own drop-in and must not be used together with the separate \u201cRedis Object Cache\u201d plugin.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.0.25<\/h4>\n\n<ul>\n<li>Fixed: activating the plugin on a fresh site \u2014 or deactivating and reactivating it \u2014 could break the request outright. The constructor scheduled the plugin's WP-Cron events on <code>plugins_loaded<\/code>, before <code>init<\/code>, and building the cron label touched a translation function that early. WordPress logs that as a notice, but because it is the very first byte of output in the entire request, every later <code>header()<\/code> call in that request then fails with \"headers already sent\" \u2014 which shows up as WordPress reporting unexpected output during activation, or the plugin being silently left deactivated. Cron registration now waits for <code>init<\/code>, like it always should have.<\/li>\n<li>Fixed: with a cold object cache, a query could return another query's rows. Caching a result or invalidating one reaches the database itself, and those internal lookups overwrote the result the caller was about to read. It affected the first query of each kind in a request after a cache flush, a Redis restart or a fresh install, and the wrong rows were then cached for the full TTL. Writes were affected too: a lost <code>insert_id<\/code> could attach new rows to the wrong record.<\/li>\n<li>Fixed: the first write to a table did not invalidate SELECTs cached before it, because a freshly bumped per-table epoch was indistinguishable from a missing one. The global epoch had the same flaw.<\/li>\n<li>Fixed: <code>wp_cache_decr()<\/code> could return negative values instead of clamping at zero as WordPress core does.<\/li>\n<li>Fixed: the query-stats table was never created, because MySQL rejects a <code>DEFAULT<\/code> on a <code>TEXT<\/code> column.<\/li>\n<li>Fixed: <code>INSERT<\/code>\/<code>REPLACE<\/code> statements written without the optional <code>INTO<\/code> keyword were not attributed to their table.<\/li>\n<li>The URL firewall now learns from 404s WordPress actually returned instead of matching against a list of known permalinks. It no longer needs to be seeded or rebuilt, and it cannot 404 real content.<\/li>\n<li>Hardened: the URL firewall's <code>wp pigcache-fw report<\/code> command now strips control\/escape bytes before printing request data (IP, User-Agent) to the terminal, and the recorded IP is validated as a well-formed address instead of trusted verbatim from the <code>CF-Connecting-IP<\/code> header.<\/li>\n<li>Hardened: request headers used by the URL firewall for instrumentation (User-Agent, Referer) are explicitly sanitized before being stored.<\/li>\n<li>Fixed: the tag-index table used <code>DATETIME ... DEFAULT CURRENT_TIMESTAMP<\/code>, which MySQL only allows on <code>DATETIME<\/code> columns since 5.6.5 (older versions only allowed it on <code>TIMESTAMP<\/code>). On an older server the table silently failed to create, and worse, the very next activation queried a column on a table that didn't exist, which WordPress reported as unexpected output during activation on any install with <code>WP_DEBUG<\/code> on. The two Pro-only tables with the same pattern are fixed the same way. None of the three columns had a default anyway \u2014 the code that writes to them was already setting the value itself.<\/li>\n<li>Fixed: an inline SQL comment left inside a <code>CREATE TABLE<\/code> string was silently turned into a bogus column by <code>dbDelta()<\/code>, producing a broken <code>ALTER TABLE ADD COLUMN<\/code> on every activation after the first. Explanatory comments about column definitions now live outside the SQL string.<\/li>\n<li>Tested against WordPress 7.1.<\/li>\n<\/ul>\n\n<h4>1.0.24<\/h4>\n\n<ul>\n<li>Tag-based selective invalidation and per-table SQL invalidation are now part of the plugin for everyone, with no license check of any kind.<\/li>\n<li>The plugin no longer writes to <code>wp-config.php<\/code>; the <code>WP_CACHE<\/code> snippet is shown in the admin screen instead.<\/li>\n<li>The Redis circuit breaker keeps its state in shared memory instead of a file in the system temp directory.<\/li>\n<li>Drop-ins resolve the plugin directory through <code>WP_PLUGIN_DIR<\/code> \/ <code>WPMU_PLUGIN_DIR<\/code> when those constants are available.<\/li>\n<\/ul>\n\n<h4>1.0.1<\/h4>\n\n<ul>\n<li>Security: sanitize $_SERVER inputs in early-boot path and admin handlers.<\/li>\n<li>Security: escape all outputs in object cache stats view.<\/li>\n<li>HTML and fragment caches use tag-based selective invalidation when available, with global flush fallback.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release on WordPress.org.<\/li>\n<\/ul>","raw_excerpt":"Redis object-cache drop-in with optional SQL, HTML page, and fragment caching.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/arq.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/303287","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/arq.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/arq.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/arq.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=303287"}],"author":[{"embeddable":true,"href":"https:\/\/arq.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/aixeiger"}],"wp:attachment":[{"href":"https:\/\/arq.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=303287"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/arq.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=303287"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/arq.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=303287"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/arq.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=303287"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/arq.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=303287"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/arq.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=303287"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}