PluginProbe
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! / 3.8.0
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! v3.8.0
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 / mcp-abilities / Abilities / ImportTemplatePageAbility.php

ImportTemplatePageAbility.php in Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! 3.8.0, at modules/mcp-abilities/Abilities/ImportTemplatePageAbility.php

167 lines 6.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * `templately/import-template-as-page` — import a single template as a new
4 * WordPress page (FR-004).
5 *
6 * Wraps `Templately\API\Import::import_as_page()` via in-process REST
7 * dispatch (research.md §2), gated by rate limiting, the dependency gate,
8 * and the Pro-entitlement gate (in that order — FR-015, FR-003 edge case,
9 * FR-010).
10 *
11 * `platform` is a REQUIRED input (Auth Tools addendum): `import_as_page()`
12 * silently defaults to `'elementor'` when the param is omitted, so any
13 * Gutenberg template imported without explicitly stating its platform would
14 * be routed through the Elementor importer and mishandled. Requiring the
15 * caller to state it removes the silent-default failure mode entirely
16 * rather than just picking a "safer" default.
17 *
18 * Page template (MCP-only — the normal single-import flow is untouched):
19 * after a successful import an Elementor page is forced to "Elementor Full
20 * Width" (`elementor_header_footer`) when the cloud item left the template
21 * empty/`default`, while a Gutenberg page is left on the theme's default
22 * (empty) template. See {@see self::enforce_page_template()}.
23 *
24 * @package Templately\Modules\McpAbilities\Abilities
25 */
26
27 namespace Templately\Modules\McpAbilities\Abilities;
28
29 use Templately\Modules\McpCore\Registry\ToolDescriptor;
30 use Templately\Modules\McpCore\Support\DependencyGateResolver;
31 use Templately\Modules\McpCore\Support\ImportRateLimiter;
32 use Templately\Modules\McpCore\Support\Permissions;
33 use Templately\Modules\McpCore\Support\ProGateResolver;
34 use Templately\Modules\McpCore\Support\RestDispatcher;
35 use WP_Error;
36
37 class ImportTemplatePageAbility {
38
39 const ID = 'templately/import-template-as-page';
40
41 public static function descriptor(): array {
42 return [
43 'id' => self::ID,
44 'label' => __( 'Import Templately Template as New Page', 'templately' ),
45 'description' => __( 'Import a single Templately template as a brand-new WordPress page.', 'templately' ),
46 'input_schema' => [
47 'type' => 'object',
48 'properties' => [
49 'id' => [ 'type' => 'integer' ],
50 'title' => [ 'type' => 'string' ],
51 'platform' => [ 'type' => 'string', 'enum' => [ 'elementor', 'gutenberg' ] ],
52 ],
53 'required' => [ 'id', 'platform' ],
54 'additionalProperties' => false,
55 ],
56 'output_schema' => [
57 'type' => 'object',
58 'properties' => [
59 'target' => [ 'type' => 'string' ],
60 'status' => [ 'type' => 'string', 'enum' => [ 'success', 'partial' ] ],
61 'post_id' => [ 'type' => 'integer' ],
62 'failed_parts' => [ 'type' => 'array' ],
63 ],
64 ],
65 'execute_callback' => [ self::class, 'execute' ],
66 'permission_callback' => [ Permissions::class, 'can_use_abilities' ],
67 'access_level' => ToolDescriptor::ACCESS_FULL,
68 'annotations' => [ 'readonly' => false, 'destructive' => true, 'idempotent' => false ],
69 ];
70 }
71
72 /**
73 * @param array $input
74 * @return array|WP_Error
75 */
76 public static function execute( array $input ) {
77 $id = (int) ( $input['id'] ?? 0 );
78 $platform = (string) ( $input['platform'] ?? '' );
79
80 if ( empty( $id ) ) {
81 return new WP_Error( 'not_found', __( 'A template id is required.', 'templately' ) );
82 }
83
84 if ( ! in_array( $platform, [ 'elementor', 'gutenberg' ], true ) ) {
85 return new WP_Error( 'invalid_platform', __( 'platform must be "elementor" or "gutenberg".', 'templately' ) );
86 }
87
88 $rate_limit_error = ImportRateLimiter::check();
89 if ( $rate_limit_error ) {
90 return $rate_limit_error;
91 }
92
93 $dependency_check = DependencyGateResolver::check( $id );
94 if ( is_wp_error( $dependency_check ) ) {
95 return $dependency_check;
96 }
97
98 $params = [ 'id' => $id, 'platform' => $platform ];
99 if ( ! empty( $input['title'] ) ) {
100 $params['title'] = sanitize_text_field( $input['title'] );
101 }
102
103 $response = RestDispatcher::dispatch( 'POST', '/templately/v1/import/page', $params );
104
105 if ( is_wp_error( $response ) ) {
106 return ProGateResolver::to_purchase_error( $response, $id );
107 }
108
109 $data = $response->get_data();
110
111 if ( empty( $data['post_id'] ) ) {
112 return new WP_Error( 'import_failed', __( 'Import failed for an unknown reason.', 'templately' ) );
113 }
114
115 $post_id = (int) $data['post_id'];
116
117 self::enforce_page_template( $post_id, $platform );
118
119 return [
120 'target' => 'page',
121 'status' => 'success',
122 'post_id' => $post_id,
123 ];
124 }
125
126 /**
127 * Set the page template on the freshly-imported page (MCP-only behavior — the
128 * normal single-import flow is deliberately untouched).
129 *
130 * - Elementor: force "Elementor Full Width" (`elementor_header_footer`) when the
131 * cloud item left the template empty or `default`. A real, non-default template
132 * coming from the cloud item is respected. Persists it the same way FSI does
133 * (see `modules/full-site-import/Utils/Utils.php`): the Elementor page setting
134 * (`_elementor_page_settings['template']`) *and* the WP `_wp_page_template` meta.
135 * - Gutenberg: explicitly pin the WP default (empty) template (`_wp_page_template`
136 * = `default`), rather than relying on the plain insert's implicit theme default,
137 * so the outcome is deterministic across themes.
138 *
139 * @param int $post_id
140 * @param string $platform 'elementor' | 'gutenberg'
141 */
142 private static function enforce_page_template( int $post_id, string $platform ): void {
143 if ( 'gutenberg' === $platform ) {
144 update_post_meta( $post_id, '_wp_page_template', 'default' );
145 return;
146 }
147
148 if ( 'elementor' !== $platform || ! class_exists( '\Elementor\Plugin' ) ) {
149 return;
150 }
151
152 $page_settings = get_post_meta( $post_id, '_elementor_page_settings', true );
153 if ( ! is_array( $page_settings ) ) {
154 $page_settings = [];
155 }
156
157 $current = $page_settings['template'] ?? '';
158 if ( '' !== $current && 'default' !== $current ) {
159 return; // Respect a real template the cloud item already carries.
160 }
161
162 $page_settings['template'] = 'elementor_header_footer';
163 update_post_meta( $post_id, '_elementor_page_settings', $page_settings );
164 update_post_meta( $post_id, '_wp_page_template', 'elementor_header_footer' );
165 }
166 }
167