PluginProbe
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! / trunk
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! vtrunk
3.8.0 3.7.5 3.7.4 3.7.3 3.7.2 1-final 3.7.1 3.7.0 3.6.8 3.6.7 3.6.6 3.6.5 3.6.4 3.6.3 3.6.2 3.6.1 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 All 112 releases
templately / modules / ai-editor / module.php

module.php in Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! trunk, at modules/ai-editor/module.php

122 lines 4.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * In-editor AI chat module (spec 041-ai-editor).
4 *
5 * Owns the "Edit with Templately" conversational panel that mounts inside the
6 * Elementor and Gutenberg editors, the REST proxy that relays turns to the
7 * Templately cloud, and the standalone host page that wraps a post's native
8 * editor.
9 *
10 * Relocated here from the pre-modular tree:
11 * includes/API/AIEditor.php -> REST/AIEditor.php
12 * includes/Admin/EditorPage.php -> EditorPage.php
13 * react-src/ai-editor/ -> assets/js/
14 * `views/ai-editor-page.php` deliberately stays at the plugin root: every
15 * module renders through `Helper::views()`, which resolves against
16 * `TEMPLATELY_PATH . 'views/'` only (see modules/settings/Settings.php).
17 *
18 * ENQUEUE OWNERSHIP. The two `js/ai-editor.js` enqueues used to live inside
19 * Platform/Elementor.php and Platform/Gutenberg.php, which now belong to
20 * elementor-integration and gutenberg-integration. Keeping them there would
21 * make two unrelated modules responsible for this module's bundle. Both are
22 * plain action hooks (`elementor/editor/after_enqueue_scripts`,
23 * `enqueue_block_editor_assets`), so this module subscribes to them directly
24 * and the platform modules no longer mention the AI editor at all.
25 *
26 * ENTRY KEY. `webpack.config.partial.js` keeps the unprefixed `ai-editor` key
27 * rather than `modules/ai-editor`. A `modules/`-prefixed key folds the code
28 * into the SPA bundle graph (Constitution XIII) and stops emitting a real
29 * file — but this bundle is enqueued BY PATH as `js/ai-editor.js` on editor
30 * screens, and must not load on the SPA admin page. Same exception as
31 * `elementor` and `gutenberg`.
32 *
33 * @package Templately
34 */
35
36 namespace Templately\Modules\AiEditor;
37
38 use Templately\Core\Module_Base;
39 use Templately\Modules\AiEditor\REST\AIEditor;
40
41 class Module extends Module_Base {
42
43 public function get_name(): string {
44 return 'ai-editor';
45 }
46
47 /**
48 * Held back from the 3.8.0 release (2026-09-23) — see Module_Base::deferred_module_enabled().
49 * Delete this override to release it.
50 */
51 public function is_active(): bool {
52 return Module_Base::deferred_module_enabled( $this->get_name() );
53 }
54
55 /**
56 * No declared dependencies — deliberately.
57 *
58 * The only cross-module touchpoints are late and guarded:
59 * - `resolve_site_template()` reads `templately()->theme_builder` (set by
60 * theme-builder's own init_hooks) behind an `empty()` check and returns
61 * null when absent, so `@header`/`@footer` degrade instead of fatalling.
62 * - the browser calls `POST /templately/v1/insert` (single-import) over
63 * HTTP, which is a route-availability concern, not a boot-order one.
64 *
65 * Declaring either would make Modules_Manager skip this module outright if
66 * that module failed to boot — strictly worse than the graceful degradation
67 * above. Neither reference is a `use Templately\Modules\…` import, so
68 * `scripts/build/check-module-dependencies.js` does not flag them and no
69 * baseline entry is needed.
70 */
71 public function get_dependencies(): array {
72 return [];
73 }
74
75 protected function init_hooks(): void {
76 // Self-registered here rather than from includes/Plugin.php: during
77 // plugins_loaded, Plugin runs BEFORE Modules_Manager registers this
78 // module's autoloader, so an eager reference there fatals on
79 // class-not-found. See docs/CREATING-A-MODULE.md -> boot-ordering rule.
80 EditorPage::get_instance();
81
82 add_action( 'elementor/editor/after_enqueue_scripts', [ $this, 'enqueue_elementor' ] );
83 add_action( 'enqueue_block_editor_assets', [ $this, 'enqueue_gutenberg' ] );
84 }
85
86 public function register_rest_routes(): void {
87 AIEditor::get_instance()->register_routes();
88 }
89
90 /**
91 * Elementor editor. Per-post capability is enforced by the REST permission
92 * callback on every turn; `edit_posts` here only decides whether the panel
93 * is offered at all, matching the check this replaced.
94 *
95 * @return void
96 */
97 public function enqueue_elementor(): void {
98 if ( ! current_user_can( 'edit_posts' ) ) {
99 return;
100 }
101 templately()->assets->enqueue( 'templately-ai-editor', 'js/ai-editor.js' );
102 }
103
104 /**
105 * Block editor. `post-new.php` has no post ID yet, so fall back to the
106 * generic capability there — same branch as the check this replaced.
107 *
108 * @return void
109 */
110 public function enqueue_gutenberg(): void {
111 $editor_post_id = get_the_ID();
112 $can_use = $editor_post_id
113 ? current_user_can( 'edit_post', $editor_post_id )
114 : current_user_can( 'edit_posts' );
115
116 if ( ! $can_use ) {
117 return;
118 }
119 templately()->assets->enqueue( 'templately-ai-editor', 'js/ai-editor.js' );
120 }
121 }
122