# Cloudflare Integration

AjaxPress includes an optional Cloudflare edge caching system that deploys a Cloudflare Worker to cache pages at the CDN edge. This is a premium feature.

## Components

```
+-------------------+     +--------------------+     +------------------+
| Admin UI          |     | PHP Backend        |     | Cloudflare       |
| (Solid.js)        |     |                    |     |                  |
|                   |     | Cloudflare\API     |     | API v4           |
| CloudflareSetup --+---->| Cloudflare\Cache --+---->| Worker Scripts   |
| CloudflareSection |     | Cloudflare\Hooks   |     | Routes           |
| CloudflareStatus  |     |                    |     | Cache            |
+-------------------+     +--------------------+     +------------------+
```

### `Cloudflare\API` (`includes/cloudflare/class-cloudflare-api.php`)

Low-level Cloudflare API v4 client. Handles HTTP requests, token management, and worker script generation.

### `Cloudflare\Cache` (`includes/cloudflare/class-cloudflare-cache.php`)

High-level cache manager. Orchestrates deployment, teardown, and purge operations.

### `Cloudflare\Hooks` (`includes/cloudflare/class-cloudflare-hooks.php`)

WordPress hook integration for automatic cache purging on content changes.

## Token Security

API tokens are encrypted before storage using AES-256-CBC:

- **Algorithm:** `aes-256-cbc`
- **Key source:** `AJAXPRESS_ENCRYPTION_KEY` constant (if defined) or `wp_salt('auth')`
- **Storage:** `ajaxpress_cf_api_token` option (contains IV + encrypted data, base64-encoded)
- **Decryption:** Happens on-demand when API calls are needed

## Deployment Lifecycle

### 1. Token Verification

```
Admin enters API token
       |
       v
POST /wp-json/ajaxpress/cf/verify-token
       |
       v
API::verify_token() calls /user/tokens/verify
       |
       v
Token encrypted and stored
       |
       v
API::list_accounts() returns available accounts
```

### 2. Zone Selection

```
GET /wp-json/ajaxpress/cf/zones
       |
       v
API::list_zones() fetches zones for account
       |
       v
Cache::domain_matches_zone() identifies matching zone
       |
       v
UI shows zones with auto-detected match
```

### 3. Worker Deployment

```
POST /wp-json/ajaxpress/cf/deploy { zone_id }
       |
       v
Cache::deploy()
  ├── Fetch zone details (API::get_zone)
  ├── Generate worker script (API::get_worker_script)
  ├── Upload worker (API::upload_worker)
  ├── Create route pattern: domain.com/* (API::create_route)
  └── Save deployment info to database
```

### 4. Teardown

```
POST /wp-json/ajaxpress/cf/teardown
       |
       v
Cache::teardown()
  ├── Delete route (API::delete_route)
  ├── Delete worker (API::delete_worker)
  ├── Clear all CF options from database
  └── Delete encrypted token
```

## Worker Script

The worker is an ES module deployed to Cloudflare's edge network. Generated dynamically by `API::get_worker_script()` with site-specific configuration.

### Caching Rules

**Cached:**
- GET requests only
- HTML pages (non-asset URLs)

**Bypassed:**
- Non-GET methods (POST, PUT, etc.)
- Logged-in users (detected via cookies: `wordpress_logged_in_*`, `wp-settings-*`, `wordpress_sec_*`)
- User-defined bypass cookie patterns
- User-defined bypass URL patterns
- Static assets (`.js`, `.css`, `.png`, `.jpg`, `.gif`, `.svg`, `.woff2`, `.ico`, etc.)
- WordPress admin/login/API paths

### Response Headers

The worker adds an `X-AjaxPress-Cache` header:

| Value | Meaning |
|-------|---------|
| `HIT` | Served from edge cache |
| `MISS` | Fetched from origin, now cached |
| `BYPASS` | Request matched a bypass rule |

## Auto-Purge System

When `cf_auto_purge` is enabled, the `Cloudflare\Hooks` class registers WordPress hooks that automatically purge relevant URLs when content changes.

### Triggers

**Post changes:**
- `save_post` (priority 20) -- Published posts only, skips autosaves/revisions
- `delete_post` (priority 20)
- `trashed_post` (priority 20)
- `transition_post_status` (priority 20) -- On publish or unpublish

**Term changes:**
- `edited_term` (priority 20)
- `delete_term` (priority 20)

**Comment changes:**
- `comment_post` (priority 20) -- Approved comments only
- `edit_comment` (priority 20)
- `transition_comment_status` (priority 20) -- On approve/unapprove

### URL Collection

When a post changes, the system collects all related URLs for purging:

- Post permalink
- Post archive pages
- Category archive URLs
- Tag archive URLs
- Author archive URL
- Home page

### Debounce Strategy

URLs are queued in a static `$pending_urls` array during the request. The actual purge happens once on the `shutdown` hook:

- If fewer than 25 unique URLs: purge individually (batched in groups of 30 per API call)
- If 25 or more URLs: purge the entire cache instead

### Admin Bar Integration

When Cloudflare is connected, the admin bar shows cache controls:

- **Purge This Page** -- Purges the current URL
- **Purge All Cache** -- Purges the entire zone cache

Both use inline AJAX with visual feedback (icon opacity change).

## Database Options

| Option | Type | Description |
|--------|------|-------------|
| `ajaxpress_cf_api_token` | string | Encrypted API token |
| `ajaxpress_cf_cache_enabled` | bool | Cache active flag |
| `ajaxpress_cf_zone_id` | string | Selected zone ID |
| `ajaxpress_cf_zone_name` | string | Zone domain name |
| `ajaxpress_cf_route_id` | string | Worker route ID |
| `ajaxpress_cf_route_pattern` | string | Route pattern (e.g., `example.com/*`) |
| `ajaxpress_cf_account_id` | string | Cloudflare account ID |
| `ajaxpress_cf_auto_purge` | bool | Auto-purge enabled |
| `ajaxpress_cf_bypass_patterns` | string | Newline-separated URL patterns to bypass |
| `ajaxpress_cf_bypass_cookies` | string | Newline-separated cookie names to bypass |

## Global Helper

```php
ajaxpress_purge_cache($urls = null);
```

Purges specific URLs or all cache. Can be called from themes or other plugins.
- Pass an array of URLs to purge specific pages
- Pass `null` to purge all cache
