| 1 |
<?php |
| 2 |
/** |
| 3 |
* Theme builder module (spec 035-theme-builder). |
| 4 |
* |
| 5 |
* Relocates the entire theme-builder engine from includes/Builder/ (48 |
| 6 |
* files) + includes/API/ThemeBuilderApi.php (1 file) into |
| 7 |
* modules/theme-builder/ — the orchestrator (ThemeBuilder.php), the |
| 8 |
* condition-consuming template-type registry (TemplateManager), frontend |
| 9 |
* resolution (LocationManager), page-template registration (PageTemplates), |
| 10 |
* header/footer replacement (TemplateLoader), the platform-aware factory |
| 11 |
* (TemplateFactory), the 19-file template-type hierarchy (Types/), the |
| 12 |
* render-integration strategies (Render/Strategies/), the four Elementor |
| 13 |
* widgets (Widgets/), the Elementor Documents adapter |
| 14 |
* (Platforms/Elementor/Documents/, 12 files) and the Gutenberg editor-canvas |
| 15 |
* context + admin-bar adapters (Platforms/Gutenberg/{EditorContext, |
| 16 |
* AdminBar}.php), and the REST controller for template creation |
| 17 |
* (REST/ThemeBuilderApi.php). Namespace: Templately\Builder\* -> |
| 18 |
* Templately\Modules\ThemeBuilder\*; Templately\API\ThemeBuilderApi -> |
| 19 |
* Templately\Modules\ThemeBuilder\REST\ThemeBuilderApi. |
| 20 |
* |
| 21 |
* SCOPE NOTE — Platforms/Elementor/Documents/* and Platforms/Gutenberg/ |
| 22 |
* {EditorContext,AdminBar}.php: these are platform-specific ADAPTERS, not |
| 23 |
* the platform drivers themselves (those already live in |
| 24 |
* modules/elementor-integration/ and modules/gutenberg-integration/, specs |
| 25 |
* 032/033). Builder/CLAUDE.md's own authoritative framing (written during |
| 26 |
* the 2026-07-02 spec-code-reconcile) explicitly calls these "the |
| 27 |
* Builder-specific parts each driver delegates to" — i.e. theme-builder's |
| 28 |
* own per-platform organization, not code owned by the platform-integration |
| 29 |
* modules. Spec 035's own text has one arguably-conflicting sentence |
| 30 |
* ("[Gutenberg editor-canvas rendering] is BLOCKED — owned by spec 033... |
| 31 |
* not this spec") — read in context this is about NOT implementing new |
| 32 |
* editor-canvas FRs as part of 035, not about where the existing |
| 33 |
* EditorContext.php file's namespace should live. Since spec 032 |
| 34 |
* (elementor-integration) already explicitly deferred the whole |
| 35 |
* includes/Builder/ tree "to a later spec" when it ran, and that later |
| 36 |
* spec is this one, both platform-adapter subdirectories are extracted |
| 37 |
* here. modules/elementor-integration/CLAUDE.md and |
| 38 |
* modules/gutenberg-integration/CLAUDE.md are updated to reflect this. |
| 39 |
* |
| 40 |
* CRITICAL ORDERING FIX — ThemeBuilder::get_instance() was previously |
| 41 |
* instantiated in Plugin::__construct() itself (NOT even plugins_loaded() — |
| 42 |
* the constructor runs when the main plugin file is included, which is |
| 43 |
* BEFORE the plugins_loaded ACTION even fires). Once ThemeBuilder became a |
| 44 |
* module-namespaced class, that eager call would fatal on class-not-found, |
| 45 |
* since Modules_Manager::boot() (which registers this module's autoloader) |
| 46 |
* doesn't run until INSIDE Plugin::plugins_loaded(), by definition after |
| 47 |
* the constructor has already returned. Fixed by moving the instantiation |
| 48 |
* into this module's own init_hooks() (which runs during |
| 49 |
* Modules_Manager::boot(), after the autoloader is live), assigning the |
| 50 |
* result to templately()->theme_builder (a public property on Plugin — |
| 51 |
* settable from outside the class). Verified via grep that nothing |
| 52 |
* synchronously reads templately()->theme_builder between the old |
| 53 |
* construction point and the new one: Admin's and Enqueue's constructors |
| 54 |
* (built in the same Plugin::__construct(), just before/after |
| 55 |
* ThemeBuilder) never read it; the one place Admin.php DOES read it |
| 56 |
* (admin_enqueue_scripts) fires long after plugins_loaded. ThemeBuilderApi |
| 57 |
* (the REST controller) had the same eager-instantiation problem in |
| 58 |
* Plugin::apis() — fixed via the standard lazy register_rest_routes() |
| 59 |
* pattern every module-owned REST class uses (013-034); no ordering risk |
| 60 |
* there since it was only ever needed at rest_api_init. |
| 61 |
* |
| 62 |
* @package Templately |
| 63 |
*/ |
| 64 |
|
| 65 |
namespace Templately\Modules\ThemeBuilder; |
| 66 |
|
| 67 |
use Templately\Core\Module_Base; |
| 68 |
use Templately\Modules\ThemeBuilder\REST\ThemeBuilderApi; |
| 69 |
|
| 70 |
class Module extends Module_Base { |
| 71 |
|
| 72 |
public function get_name(): string { |
| 73 |
return 'theme-builder'; |
| 74 |
} |
| 75 |
|
| 76 |
// No get_dependencies() (defaults to []): the ConditionManager is no longer |
| 77 |
// instantiated here — it is supplied by the display-conditions module via the |
| 78 |
// `templately_condition_manager` filter (registered at boot; applied on `init` |
| 79 |
// in ThemeBuilder::source_register()). The dependency direction is therefore |
| 80 |
// INVERTED — display-conditions declares theme-builder (it was extracted FROM |
| 81 |
// theme-builder in spec 034 and consumes its ThemeBuilder/Source/ThemeTemplate |
| 82 |
// types), and theme-builder no longer imports the display-conditions namespace. |
| 83 |
|
| 84 |
protected function init_hooks(): void { |
| 85 |
templately()->theme_builder = ThemeBuilder::get_instance(); |
| 86 |
} |
| 87 |
|
| 88 |
public function register_rest_routes(): void { |
| 89 |
ThemeBuilderApi::get_instance()->register_routes(); |
| 90 |
} |
| 91 |
} |
| 92 |
|