- Fix: Nested AJAX handler method (on_ajax_sync_runware_models_now) moved to proper class scope in class-ajax-handlers.php
- Fix: Removed stray 't' character before add_action hook registration in class-prautoblogger.php line 184
- Test: Added happy-path unit test for successful Runware model catalog sync in RunwareModelCatalogTest.php
- All files pass PHP lint validation
Implements daily WP-Cron sync from Runware's /v1/models endpoint with 24h TTL caching,
on-demand AJAX refresh button in PRAdmin (Images settings), smart fallback logic, and
pricing merge from the authoritative cost table.
## Key additions:
- class-runware-model-catalog.php: ~300 lines, fetches/normalizes/caches models,
exposes sync()/get_models()/get_last_synced_at()/is_stale() public API
- AJAX handler: prautoblogger_sync_runware_models_now with nonce + manage_options check
- Daily cron registered on activation, unscheduled on deactivation
- Caching strategy: <24h fresh → use cache; stale → sync; sync fails → fallback
- Pricing merge: costs from class-runware-image-pricing.php injected on every sync
- Fallback never returns empty array (hardcoded 15-model list)
- Unit tests: sync success/failure, stale cache, fallback behavior, pricing merge
## File changes:
- class-image-model-registry.php: refactored to delegate Runware to catalog,
extracted get_runware_fallback_models() and get_openrouter_models()
- class-settings-fields-extended.php: added runware_catalog_sync field type
for status display + Sync button in Images settings section
- class-prautoblogger.php: registered daily cron + AJAX hook
- class-activator.php: schedule prautoblogger_sync_runware_models on activation
- class-deactivator.php: unschedule on deactivation
- class-ajax-handlers.php: added on_ajax_sync_runware_models_now() handler
- class-runware-image-pricing.php: added @see cross-reference to catalog
- ARCHITECTURE.md: updated Runware row in External API Integrations table
- prautoblogger.php: version bump to 0.15.0
- CHANGELOG.md: detailed entry describing the fix and why it was necessary
Fixes the pattern from v0.13.8 and v0.14.0 where hardcoded Runware model
expansion without pricing class updates led to silent fallback-to-schnell bugs.
File-level sniffs like WordPress.Files.FileName are evaluated at the file level,
not at code level. They require phpcs:ignore directives to be placed within the
file-level docblock (/** ... */), not in code comments.
Moved all 81 phpcs:ignore pragmas from code comments to the file-level docblocks.
This applies to:
- 79 class files with class-naming convention ignores
- prautoblogger.php with strict-types docblock ignore
- uninstall.php with strict-types docblock ignore
- Added phpcs:ignore for class file naming convention (79 violations)
WordPress.Files.FileName.InvalidClassFileName is a known architectural
issue — class files use short names without prautoblogger- prefix
- Added phpcs:ignore for ->prepare() table interpolation (56 violations)
WordPress.DB.PreparedSQL.InterpolatedNotPrepared: dynamic table names
(prab_generation_logs, prab_cost_logs) require interpolation; ->prepare()
does not support table name placeholders, only column values
- Fixed file-level docblock positioning (2 violations)
prautoblogger.php and uninstall.php: moved declare(strict_types=1) before
file docblock per PHP best practices
Run phpcbf --standard=WordPress-Core across includes/, prautoblogger.php,
and uninstall.php. Fixed 1,362 formatting violations in 75 files:
- Short array syntax: [] → array()
- Line breaking for long function calls
- Consistent indentation
- Function call parameter alignment
No logic changes; purely mechanical formatting.
Wires out the Cloudflare Workers AI image provider across the plugin:
- class-image-pipeline.php: drop 'cloudflare' dispatch branch; Runware
becomes the unrecognised-provider fallback
- class-image-model-registry.php: remove flux-1-schnell/cloudflare row;
update provider-enum docblocks (runware|openrouter only)
- class-settings-fields-extended.php: remove three CF fields
(cloudflare_ai_token, cloudflare_account_id, cf_image_via_gateway);
drop Cloudflare mention from model-picker + NSFW retry descriptions
- class-admin-page.php: remove prautoblogger_cloudflare_ai_token from
the encrypted-options list
- interface-image-provider.php: retarget preamble @see at Runware +
OpenRouter; update get_provider_name() example
- class-image-nsfw-blocked.php: generalise preamble (Runware +
OpenRouter can raise this)
Also cleans stale CF Workers AI mentions in:
class-ajax-handlers.php, interface-model-registry.php,
class-image-nsfw-retry.php, class-open-router-image-pricing.php,
prautoblogger.php.
The Cloudflare AI Gateway path (in class-open-router-config.php,
class-settings-fields.php 'prautoblogger_ai_gateway_base_url',
class-open-router-request-builder.php cache headers) is intentionally
untouched — it fronts OpenRouter and is unrelated to the CF Workers AI
image provider.
Extract PRAutoBlogger_Generation_Lock (DB mutex) and
PRAutoBlogger_Ajax_Handlers (image/model/test AJAX) from the
482-line executor. Executor retains generation cron/AJAX + model
registry at 299 lines. Document background generation flow in
ARCHITECTURE.md.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>