# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added - Security Bypass Rule & Enhanced Error Handling
- **Security bypass rule** - New managed Cloudflare cache rule (highest priority) to bypass caching for Imunify360 admin interfaces (`/im360`, `/imunify`)
- **Enhanced status code TTL** - Added cache bypass (TTL=0) for auth challenges (401), forbidden (403), rate limiting (429), service unavailable (503), and gateway timeout (504)
- **WooCommerce order page exclusions** - Added broad-match exclusions for `order-received` and `order-pay` paths to prevent caching of dynamic order completion data
- **New filter**: `wpr_cf_sync_security_rule_payload` - customize the security bypass rule payload

### Changed - Cache TTL Configuration
- **HTML cache duration increased** from 4 hours to 7 days (604800 seconds) for better performance with WP Rocket purge-on-publish workflow
- **200-OK status code TTL removed** from both HTML and Assets rules to eliminate TTL conflicts; Edge TTL defaults now apply (7 days for HTML, 30 days for assets)
- **Rule architecture expanded** - RuleDeployer now manages three separate Cloudflare cache rules (Security Bypass + HTML + Assets) instead of two
- **Rule ordering** - Security Bypass rule placed first (highest priority), then Assets, then HTML
- **OptionsStore schema** - Added `security` key to `cloudflare_rule_ids` array

### Fixed - TTL Conflicts & Security
- **TTL conflict resolved** - Status code TTL (200-OK = 4 hours) was overriding Edge TTL settings; removal allows proper 7-day HTML and 30-day asset caching
- **Imunify360 compatibility** - Security challenges and admin interfaces now properly bypass cache (Free/Pro plan compatible using path-based matching only)
- **WooCommerce order pages** - Order completion pages now excluded from cache regardless of custom checkout page slugs

### Affected Modules
- Cloudflare: `src/Cloudflare/RuleDeployer.php` (security bypass rule, TTL updates, 3-rule management)
- Exclusions: `src/Exclusions/WooCommerceDetector.php` (order page exclusions)
- Documentation: `CHANGELOG.md`

### Backwards Compatibility
- Existing two-rule installations automatically migrate: security bypass rule is prepended on next deploy
- Legacy `cloudflare_rule_id` option continues to work; new `cloudflare_rule_ids['security']` is populated on next successful deploy
- All existing filters remain unchanged; new security rule filter has sensible defaults
- **Note**: Response header matching (`x-ipl-status`) not included as it requires Business/Enterprise Cloudflare plan

---

### Added - Dual Cache Rules & Status Code TTL
- **Static assets rule** - New managed Cloudflare cache rule for aggressive caching of static files (CSS, JS, images, fonts, etc.) with 1-year TTL
- **Status code TTL** - Both HTML and assets rules now include per-status-code cache TTL overrides (200=4h, 301=1h, 302/404/500=0) to prevent error pages from being cached
- **Stale-while-revalidate** - Both rules now enable SWR (serve stale while revalidating) for improved performance; HTML rule behavior is filterable via `wpr_cf_sync_html_serve_stale_disabled`
- **New filters**:
  - `wpr_cf_sync_static_assets_expression` - customize the static assets file extension matcher
  - `wpr_cf_sync_status_code_ttl` - override status code TTL entries for both rules
  - `wpr_cf_sync_html_rule_payload` / `wpr_cf_sync_assets_rule_payload` - late-stage rule payload customization
  - `wpr_cf_sync_html_serve_stale_disabled` - disable SWR on HTML rule if strict freshness is required

### Changed - RuleDeployer Architecture
- **Multi-rule management** - RuleDeployer now manages two separate Cloudflare cache rules (HTML + Assets) instead of one, discovered by description tags or stored IDs
- **Rule ordering** - Assets rule is placed at higher priority (first) so static files match before the HTML rule
- **OptionsStore schema** - Added `cloudflare_rule_ids` array (keyed by 'html' and 'assets'); legacy `cloudflare_rule_id` is maintained for backward compatibility

### Fixed - Error Page Caching
- 404, 500, and 302 redirect responses are no longer cached on Cloudflare edge (TTL = 0)
- 301 permanent redirects cache for 1 hour instead of 4 hours
- 200 OK responses continue to cache for 4 hours

### Affected Modules
- Cloudflare: `src/Cloudflare/RuleDeployer.php` (major refactor)
- Sync: `src/Sync/OptionsStore.php` (new schema)
- Documentation: `CHANGELOG.md`, `readme.txt`

### Backwards Compatibility
- Existing single-rule installations automatically migrate: the HTML rule is found by description tag and updated in place with new `status_code_ttl` settings
- The assets rule is prepended on next deploy
- Legacy `cloudflare_rule_id` option is read during discovery; new `cloudflare_rule_ids` is populated on next successful deploy
- Deactivation cleans up both managed rules via description-tag discovery, even if IDs are unknown
- All new filters have sensible defaults; no breaking changes to existing filter signatures

## [1.0.1] - 2026-03-17

### Fixed - WordPress.org Plugin Check Compliance
- **Text domain corrected** from `wpr-cloudflare-sync` to `wp-rocket-cloudflare-edge-cache-sync-helper` across all 11 PHP files (79 instances)
- **ABSPATH protection added** to 4 PHP files (`src/Admin/AdminPage.php`, `src/Admin/AdminBar.php`, `src/Admin/AdminNotices.php`, `src/Plugin.php`)
- **Output escaping fixed** in `src/Admin/AdminPage.php` (wrapped `$counts` array values with `esc_html()` in printf)
- **WordPress version updated** to 6.9 in plugin header and readme.txt
- **Deprecated function removed** - `load_plugin_textdomain()` call removed (WordPress.org auto-loads translations)
- **Input sanitization improved** - Added `wp_unslash()` before `sanitize_text_field()` in `src/Plugin.php`
- **Filesystem operations documented** - Added phpcs:ignore comments explaining why direct fopen/fclose is necessary for atomic logging
- **Development functions documented** - Added phpcs:ignore comments for `error_log()` usage (atomic file operations, not debugging)
- **Global function prefixes** - All functions in `uninstall.php` now prefixed with `mtv_wpr_cf_sync_`

### Affected Modules
- Core: `wp-rocket-cloudflare-sync.php`, `uninstall.php`, `readme.txt`
- Admin: `src/Admin/AdminPage.php`, `src/Admin/AdminBar.php`, `src/Admin/AdminNotices.php`
- Sync: `src/Sync/SyncManager.php`, `src/Sync/RetryManager.php`
- Cloudflare: `src/Cloudflare/ApiClient.php`, `src/Cloudflare/AuthResolver.php`, `src/Cloudflare/RuleDeployer.php`
- Expression: `src/Expression/ExpressionDiff.php`
- Logging: `src/Logging/Logger.php`
- Plugin: `src/Plugin.php`

### Backwards Compatibility
- All changes maintain 100% backward compatibility
- No breaking changes to public API (filters/actions remain unchanged)
- Plugin functionality unchanged - only compliance and code quality improvements

### Known Issues
- Plugin name contains "WP" which WordPress.org flags as restricted trademark. This refers to "WP Rocket" (the required dependency), not "WordPress". If WordPress.org requires renaming, a future version will address this with migration logic.

## [1.0.0] - Unreleased

### Added - WP.org Readiness
- **readme.txt** in WordPress.org standard format with full plugin description, installation instructions, FAQ, and developer hooks
- **LICENSE** file (GPL-2.0-or-later)
- **POT file** for translations (`languages/wpr-cloudflare-sync.pot`)
- **Tested up to** WordPress 6.7 in plugin headers
- **Filox add-on plugin** extracted to separate plugin for cleaner architecture
- **.distignore** file for WP.org SVN deployment (excludes dev files, tests, vendor, node_modules)

### Changed - WP.org Compliance
- **Replaced Composer autoloader** with `spl_autoload_register()` for PSR-4 autoloading (no runtime dependencies)
- **Replaced all file operations** with WP_Filesystem API (`file_put_contents`, `file_get_contents`, `scandir`, `rmdir`)
- **Improved tail_file()** with fseek-based implementation to prevent memory exhaustion on large logs
- **Removed `Requires Plugins` header** (WP Rocket not on wp.org)
- **Changed Plugin URI** to public URL (https://plugin.filox.gr)
- **Added vendor/ to .gitignore**

### Fixed - Security & Documentation
- **AJAX nonce key mismatch** in admin.js (changed `_ajax_nonce` to `nonce` to match `check_ajax_referer`)
- **Zone ID masking** in logs (added to secrets list)
- **AdminBar HTML sanitization** (added `esc_attr()` and `esc_html()` to status title)
- **readme.txt constant names** (corrected from CLOUDFLARE_* to WP_ROCKET_CF_* to match actual constants)
- **readme.txt developer hooks** (corrected to match actual action hooks: `wpr_cf_sync_deployed`, `wpr_cf_sync_failed`, `wpr_cf_purge_success`, `wpr_cf_purge_failed`)

### Fixed - Performance
- **Cache purge debouncing** (static flag prevents multiple API calls in same request)
- **Logger secrets caching** (avoid repeated `get_option()` calls on every log entry)
- **Logger atomic appends** (replaced read-entire-file-then-write with atomic `error_log()` for thread-safe operations)
- **Log rotation** (added `rotate_log_if_needed()` to prevent excessive disk usage; rotates at 5MB)

### Changed - Code Quality
- **Replaced global $sitepress** with WPML filter hooks (`wpml_element_trid`, `wpml_get_element_translations`)
- **Updated filter names** to `wpr_cf_sync_excluded_*` for consistency and third-party integrations
- **Filox integration** moved to separate add-on plugin using filter hooks

### Removed
- **FiloxDetector** from main plugin (now in separate add-on)
- **Composer vendor/ directory** from repository

### Affected Modules
- Core: `wp-rocket-cloudflare-sync.php`, `uninstall.php`
- Logging: `src/Logging/Logger.php`
- Admin: `src/Admin/AdminBar.php`, `assets/js/admin.js`
- Exclusions: `src/Exclusions/ExclusionCollector.php`, `src/Exclusions/WooCommerceDetector.php`
- Plugin: `src/Plugin.php`
- Documentation: `readme.txt`, `LICENSE`, `languages/wpr-cloudflare-sync.pot`

### Backwards Compatibility
- Filter names changed from `wpr_cf_cache_excluded_*` to `wpr_cf_sync_excluded_*`
- Filox integration requires separate add-on plugin
- No breaking changes to core functionality

## [1.0.0] - Initial Release
