Part of #828 (which fulfills #688).
Goal
Same shape as the CBT_Theme_Save extraction, applied to the export flow. Move the orchestration out of rest_export_theme() into a new service class so it can be invoked from REST or CLI without duplication.
Scope
New file: includes/create-theme/theme-export.php
New class: CBT_Theme_Export with one public static method:
public static function to_zip( string $output_path, array $options ): true|WP_Error;
The current REST handler streams the zip back as the HTTP response body. The service writes to a path on disk; the REST wrapper writes to a temp file, streams it, then cleans up. This keeps both REST and CLI consumers symmetric.
REST endpoint update: rest_export_theme() becomes a thin wrapper. URL, permissions, and response semantics do not change.
Tests (PHPUnit, in this PR)
- Each export option (include images, export-ready, translate-ready) produces the expected zip contents
- Output path is honored
- Permission errors / disk failures propagate as
WP_Error
- Test fixtures: a small block theme to round-trip
Out of scope
Acceptance
- Existing REST export behavior is byte-for-byte preserved (compare zip output before/after)
lint:php, test:php, test:unit all green
Part of #828 (which fulfills #688).
Goal
Same shape as the
CBT_Theme_Saveextraction, applied to the export flow. Move the orchestration out ofrest_export_theme()into a new service class so it can be invoked from REST or CLI without duplication.Scope
New file:
includes/create-theme/theme-export.phpNew class:
CBT_Theme_Exportwith one public static method:The current REST handler streams the zip back as the HTTP response body. The service writes to a path on disk; the REST wrapper writes to a temp file, streams it, then cleans up. This keeps both REST and CLI consumers symmetric.
REST endpoint update:
rest_export_theme()becomes a thin wrapper. URL, permissions, and response semantics do not change.Tests (PHPUnit, in this PR)
WP_ErrorOut of scope
Acceptance
lint:php,test:php,test:unitall green