# ImgSmaller - ImgOptimizer

Compress and optimize your entire WordPress Media Library using the ImgSmaller API—with safe backups, individual/bulk restore, smart batching, quota awareness, and a modern dashboard.

## Features

- Easy setup: API Key + Connect, Allowed Domain, output format (WEBP/AVIF/JPG/PNG), and target size
- Professional dashboard: clear progress, image metrics, plan details, logs, and controls
- Safe backups: keep originals by default; export/import backups; restore one, many, or all
- Scalable processing: time-sliced batches, WP-Cron friendly, and optional external cron
- Quota-aware: pauses enqueue on limit reached, shows countdown, resumes automatically
- Robust networking: secure file proxy fallback when public file URLs aren’t accessible
- Exclusions: visual browser with search, size/type filters, infinite scroll, select-all

## Requirements

- WordPress 5.8+ and PHP 7.4+
- An ImgSmaller API key
- ZipArchive extension for backup import/export (optional but recommended)

## Installation

1. Upload the plugin to `wp-content/plugins/`.
2. Activate “ImgSmaller” in WP Admin → Plugins.
3. The plugin creates `wp-content/uploads/imgsmaller-backups` for originals and registers cron hooks.

## Quick Start

1. Go to WP Admin → ImgSmaller.
2. Enter your API Key and click “Connect” to verify.
3. Enter your Allowed Domain (normalized to example.com) and click “Save Domain”.
4. Choose Output Format (WEBP/AVIF/JPG/PNG), Target Size (auto or like 80KB), and ensure “Keep Backups” is enabled.
5. Click “Start Compression” or “Process Next Batch Now”.

## Dashboard Tour

- Compression Overview: optimized vs non-optimized pie, storage totals, savings, and potential savings.
- Current Plan & Quota: plan name, images used/limit, billing cycle and images remaining (hidden on Free plan).
- Available Plans: shows “Number of Images” limit, allowed domains, and Upgrade links to your billing dashboard.
- Progress: percent complete, images remaining, and live metrics (Total, Fetched, Sent, Compressed).
- Actions: Start, Pause, Resume, Process Now. Resume is allowed even when quota is blocked; server-side still gates enqueueing until reset.
- Background Cron: tokenized Cron URL and “Regenerate Cron Token”. Restore Cron URL is hidden in UI for safety.
- Recent Activity: last ~50 entries with timestamps (queued, completed, errors, restores).

## Settings

- API Key & Connect: test connectivity anytime (status badge next to API Key).
- Allowed Domain: normalized to example.com; posts to API then re-fetches authoritative list.
- Output Format: WEBP (recommended), AVIF (modern), JPG, PNG, or Original.
- Target Size: “auto” or a value like “80KB”.
- Keep Backups: enabled by default; required for restoring and exporting backups.
- Exclude Images: search/filter by type and size; select visually or paste IDs.

## How Compression Works

1. Enqueue: images are sent to ImgSmaller with their public URL.
2. 422 fallback: if the API cannot fetch the URL (private/non-public), we retry using a secure proxy URL: `/wp-json/imgsmaller/v1/file?token=...&id=...` (streams bytes). After 3 failed 422 attempts, the item is marked as permanently failed and skipped.
3. Polling: we poll results; on success we download, write to disk, update metadata and sizes, and clean up obsolete files if extension changed.
4. Quota: on 429 or remaining=0, enqueue halts, a countdown is shown, and resume is scheduled automatically after reset.

## Backups & Restore

- Backups
  - Originals are stored under `uploads/imgsmaller-backups/{attachment_id}/`. Meta tracks the backup path and original relative path.
  - Export backups (ZIP) and import them elsewhere (requires ZipArchive).
  - Import “replacements” ZIP: replace current images by matching basenames (marks as done, regenerates metadata).

- Restore
  - Bulk restore: revert all items with valid backups in time-sliced batches; continues via cron; Cancel Restore available.
  - Individual restore: search images with backups and restore selected; empty or missing backups are filtered automatically.
  - After restore, the item’s plugin status is reset to `pending`, progress cleared, metadata regenerated.
  - Danger Zone: delete all backups (type DELETE to confirm) and optionally reset plugin data.

## Exclusions

- Exclude visually via the grid (infinite scroll, filters, select-all/clear) or paste a list of IDs.
- Excluded images are not fetched, queued, or sent to the API.

## Plans & Quotas

- Current Plan & Quota
  - Plan name and usage vs limit (images).
  - Billing Cycle and Images Remaining are hidden on Free plan for clarity; shown on other plans.

- Available Plans
  - Lists “Number of Images” and allowed domains per plan with an Upgrade button linking to `https://imgsmaller.com/dashboard/billing`.

- Quota behavior
  - When daily/periodic limit is exhausted, enqueueing stops, and the dashboard shows a countdown.
  - Resume is allowed after a manual pause; actual enqueue is still gated until reset.

## Cron & Background Processing

- WordPress cron runs batch steps and schedules follow-ups when there’s remaining work.
- External Cron: ping `/wp-json/imgsmaller/v1/cron?token=YOUR_TOKEN` every 5–10 minutes if your site has low traffic.
- Restore step: `/wp-json/imgsmaller/v1/restore?token=YOUR_TOKEN` (hidden in UI); each call runs one restore chunk.
- Regenerate the cron token from the dashboard; all public URLs change immediately.

## Security

- Token-protected public endpoints for cron, restore, and file proxy.
- Never share your token publicly; regenerate it if exposed.
- The file proxy streams only the requested attachment, after token verification.

## Data Storage

- Options
  - `imgsmaller_settings`, `imgsmaller_status`, `imgsmaller_logs`

- Attachment Meta (examples)
  - `_imgsmaller_status` (pending|queued|processing|done|failed)
  - `_imgsmaller_progress_key`, `_imgsmaller_result_url`, `_imgsmaller_download_template`
  - `_imgsmaller_poll_attempts`, `_imgsmaller_retry_count`, `_imgsmaller_permanent_fail`
  - `_imgsmaller_backup_path`, `_imgsmaller_original_file`

- Backup Directory
  - `wp-content/uploads/imgsmaller-backups/`

## Troubleshooting

- “Compression paused… Resume not active”
  - The Resume button is always available after a manual pause. If quota is blocking, the system will resume enqueueing automatically at reset.

- “422 Unable to fetch file_url”
  - The plugin retries using a tokenized file proxy. After 3 repeated failures, the item is marked permanently failed to avoid loops.

- “Selected items have no backups to restore”
  - Backups might have been removed from disk. The list filters to only items with valid backup files; enable backups and re-run compression to create fresh backups.

- Daily limit reached
  - Start is disabled while blocked; Resume is permitted after a manual pause. A countdown shows when processing will continue.

- Cron not running
  - Ensure WP-Cron is enabled or use an external cron to ping the Cron URL.

## Developer Notes

- Namespaces and Structure: `src/` contains `Admin`, `Rest`, `Services`, `Tasks` with `Plugin.php` wiring everything together; `views/` and `assets/` power the dashboard.

- Public REST
  - `GET /wp-json/imgsmaller/v1/cron?token=...`
  - `GET /wp-json/imgsmaller/v1/restore?token=...`
  - `GET /wp-json/imgsmaller/v1/file?token=...&id=ATTACHMENT_ID`

- Admin AJAX
  - `imgsmaller_status`, `imgsmaller_start`, `imgsmaller_pause`, `imgsmaller_resume`, `imgsmaller_process_now`
  - `imgsmaller_restore`, `imgsmaller_restore_step`, `imgsmaller_cancel_restore`, `imgsmaller_restore_selected`, `imgsmaller_restore_search`
  - `imgsmaller_media_search`, `imgsmaller_scan`
  - `imgsmaller_plan_info`, `imgsmaller_set_domain`

- Uninstall
  - Deletes plugin settings and status; optionally remove backup directory if initiated via the plugin reset flow.

## License

GPL-2.0-or-later.

## External services

This plugin connects to the ImgSmaller API to perform image compression and fetch plan/quota information.

- Service: ImgSmaller API (https://imgsmaller.com)
- Purpose: Optimize images and provide account usage details
- Data sent:
  - On compression: attachment public URL or a secure, tokenized proxy URL when the file isn’t public; sent with your API key to request compression. The optimized bytes are then downloaded by the plugin.
  - On plan info: requests usage/limits using your API key.
- Policies:
  - Terms: https://imgsmaller.com/terms
  - Privacy: https://imgsmaller.com/privacy

You may refrain from starting compression or entering an API key if you do not wish to send data to the service.
