WordPress plugin for tinify.ai — a four-stage AI image optimization pipeline: upscale (Real-ESRGAN), resize, compress (TinyPNG), and auto-generate SEO alt text. Runs in the background via ActionScheduler.
For installation instructions, feature descriptions, and FAQ see the WordPress.org plugin listing (coming soon) or
readme.txt.
Requirements: PHP 8.1+, Composer
composer install # install dependencies
composer test # run PHPUnit with --testdox# Lint
./vendor/bin/phpcs --standard=phpcs.xml.dist src/ uninstall.php
# Auto-fix style
./vendor/bin/phpcbf --standard=phpcs.xml.dist src/ uninstall.php
# Run a single test class
./vendor/bin/phpunit --filter ProcessorTest
# Run a single test method
./vendor/bin/phpunit --filter 'ProcessorTest::test_run_saves_results_on_success'Tests use PHPUnit 10 + Brain\Monkey (Mockery-backed WordPress function stubs) — no live WordPress install required.
tinify-ai.php bootstraps on plugins_loaded and calls Plugin::init(), the single wiring point for all WordPress hooks. No hooks are registered outside of Plugin.
Upload event
└─ Scheduler::queueOnUpload() wp_generate_attachment_metadata filter
└─ ActionScheduler job
└─ Processor::run()
├─ ApiClient::upload() → temp_file_id (3 retries)
├─ ApiClient::process() → job_id
├─ ApiClient::pollJob() → polls every 3s, max 5 min
├─ ApiClient::downloadProcessedFile()
├─ Replacer::swap() → atomic copy+rename, .tinify-orig backup
├─ MetaManager::saveResults() → _tinify_* meta, status=completed
└─ Processor::optimizeThumbnails() → opt-in, non-fatal
(none) → pending → processing → completed
→ failed
→ paused (credits exhausted; auto-resumes)
All status is stored in _tinify_* attachment post meta, managed exclusively by MetaManager.
- Re-entrant guard:
Replacer::swap()callswp_generate_attachment_metadata()to regenerate thumbnails, which re-fires the upload filter.Scheduler::queueOnUpload()returns early if status is alreadypending,processing, orcompleted. - Poll resume: a
PollTimeoutExceptionleavesjob_idintact so the nextProcessor::run()call skips upload+process and resumes from polling. - API key encryption: AES-256-CBC using
AUTH_KEY . SECURE_AUTH_KEYas key material; never output in plaintext.
Check the ActionScheduler queue:
/wp-admin/tools.php?page=action-scheduler&s=tinify_ai