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 / elementor-integration / Platform / Elementor.php

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

442 lines 14.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Templately\Modules\ElementorIntegration\Platform;
3
4 use WP_Post;
5 use WP_Error;
6 use WP_Query;
7 use WP_REST_Response;
8
9 use Templately\Core\Platform_Registry;
10 use Templately\Utils\Helper;
11 use Templately\Utils\Options;
12 use Templately\Core\Platform;
13
14 use Elementor\Plugin;
15 use Elementor\Core\Kits\Documents\Kit;
16 use Elementor\Core\Settings\Manager as SettingsManager;
17 use Templately\Modules\ElementorIntegration\Elementor as ElementorImporter;
18 use Templately\Modules\FullSiteImport\Utils\Utils;
19 use Elementor\TemplateLibrary\Source_Local as ElementorLocal;
20
21 class Elementor extends Platform {
22 private $id = 'elementor';
23
24 public function __construct() {
25 Platform_Registry::get_instance()->add( (object) [
26 'id' => $this->id,
27 'object' => $this
28 ] );
29
30 $this->hooks();
31 }
32
33 /**
34 * Initializing Hooks
35 * @return void
36 */
37 public function hooks() {
38 if ( class_exists( '\Elementor\Plugin' ) ) {
39 add_action( 'elementor/preview/enqueue_styles', [ $this, 'styles' ] );
40 add_action( 'elementor/editor/before_enqueue_styles', [ $this, 'styles' ] );
41 add_action( 'elementor/editor/after_enqueue_scripts', [ $this, 'scripts' ] );
42 // Register widget frontend styles so widgets can pull them in via
43 // get_style_depends(). Fires on both the frontend and the editor preview.
44 add_action( 'elementor/frontend/after_register_styles', [ $this, 'register_widget_styles' ] );
45 }
46 }
47
48 /**
49 * Assets Enqueueing
50 * @return void
51 */
52 public function styles() {
53 templately()->assets->enqueue( 'templately-elementor-preview', 'css/elementor.css' );
54 templately()->assets->enqueue( 'templately-tailwind', 'css/tailwind.css', ['templately-elementor-preview'] );
55 }
56
57 /**
58 * Assets Enqueueing
59 * @return void
60 */
61 public function scripts() {
62 templately()->assets->enqueue( 'templately-elementor', 'css/elementor.css' );
63 templately()->assets->enqueue( 'templately-tailwind', 'css/tailwind.css', ['templately-elementor'] );
64 templately()->assets->enqueue( 'templately-elementor', 'js/elementor.js', [ 'jquery' ], true );
65 // The AI editor chat bundle (041) enqueues itself off this same
66 // `elementor/editor/after_enqueue_scripts` action from
67 // modules/ai-editor/module.php — this module does not own that asset.
68 templately()->admin->scripts( 'elementor' );
69 }
70
71 /**
72 * Register frontend widget stylesheets.
73 *
74 * Registered (not enqueued) so individual widgets can declare them via
75 * get_style_depends(); Elementor then enqueues them only when the widget is
76 * actually present on the page.
77 *
78 * @return void
79 */
80 public function register_widget_styles() {
81 templately()->assets->register( 'templately-comment-widget', 'css/comment-widget.css' );
82 }
83
84 /**
85 * Determine Active UI Theme
86 * @return string
87 */
88 public function ui_theme() {
89 $ui_theme = SettingsManager::get_settings_managers( 'editorPreferences' )->get_model()->get_settings( 'ui_theme' );
90
91 return 'light' !== $ui_theme ? 'dark' : 'light';
92 }
93
94 /**
95 * Checking the template eligibility for import.
96 *
97 * @return WP_Error|void
98 */
99 protected function is_eligible( $template, $types = [ 'page', 'section', 'block' ] ) {
100 if ( ! Helper::is_plugin_active( 'elementor-pro/elementor-pro.php' ) &&
101 isset( $template['type'] ) &&
102 ! in_array( $template['type'], $types, true )
103 ) {
104 $message = sprintf(
105 __( 'You have to install/activate %s to import %s Template.', 'templately' ),
106 sprintf(
107 '<a target="_blank" href="%s">%s</a>',
108 'https://wpdeveloper.com/go/elementor',
109 'Elementor PRO'
110 ),
111 $template['type']
112 );
113
114 return Helper::error( 'required_elementor_pro', $message, 'import/page', 404 );
115 }
116 }
117
118 public function get_saved_templates( $params = [] ) {
119 if ( ! function_exists( 'is_plugin_active' ) ){
120 require_once( ABSPATH . '/wp-admin/includes/plugin.php' );
121 }
122
123 $_page_number = isset( $params['page'] ) ? intval( $params['page'] ) : 1;
124
125 $args = [
126 'post_type' => 'elementor_library',
127 'post_status' => [ 'publish', 'draft' ],
128 'paged' => $_page_number,
129 'page' => $_page_number,
130 'posts_per_page' => isset( $params['per_page'] ) ? intval( $params['per_page'] ) : 15
131 ];
132
133 $templates = new WP_Query( $args );
134 $templates_list = $templates->posts;
135 $templateList = [];
136 $_templates = Options::get_instance()->get( 'templates_in_clouds', [] );
137
138 if ( count( $templates_list ) > 0 ) :
139 $date_format = get_option( 'date_format', 'F j, Y' );
140 foreach ( $templates_list as $post ) {
141 $templateList[] = [
142 'id' => $post->ID,
143 'title' => $post->post_title,
144 'date' => date( $date_format, strtotime( $post->post_date ) ),
145 'type' => ucwords( get_post_meta( $post->ID, '_elementor_template_type', true ) ),
146 'created_by' => get_the_author_meta( 'user_nicename', $post->post_author ),
147 'preview_url' => get_permalink( $post->ID ),
148 'export_url' => self::get_export_link( $post->ID ),
149 'is_pushed' => array_key_exists( $post->ID, $_templates )
150 ];
151 }
152 endif;
153 wp_reset_postdata();
154 wp_reset_query();
155
156 return array(
157 'current_page' => $templates->query_vars['paged'],
158 'total_page' => $templates->max_num_pages,
159 'items' => $templateList,
160 'has_elementor' => rest_sanitize_boolean( \is_plugin_active( 'elementor/elementor.php' ) ),
161 'has_elementor_pro' => rest_sanitize_boolean( \is_plugin_active( 'elementor-pro/elementor-pro.php' ) ),
162 );
163 }
164
165 private function get_export_link( $template_id ) {
166 return add_query_arg(
167 [
168 'action' => 'elementor_library_direct_actions',
169 'library_action' => 'export_template',
170 'source' => 'local',
171 '_nonce' => wp_create_nonce( 'elementor_ajax' ),
172 'template_id' => $template_id,
173 ],
174 admin_url( 'admin-ajax.php' )
175 );
176 }
177
178 public function is_kit( $post_id ) {
179 $document = Plugin::$instance->documents->get( $post_id );
180
181 return $document instanceof Kit && ! $document->is_revision();
182 }
183
184 /**
185 * Delete an item from Elementor Templates Library.
186 * Which also refers as Saved Templates.
187 *
188 * @param $params
189 *
190 * @return WP_Error|WP_REST_Response
191 */
192 public function delete( $params = [] ) {
193 $id = isset( $params['id'] ) ? intval( $params['id'] ) : false;
194 $force_delete_kit = isset( $params['force_delete_kit'] ) && $params['force_delete_kit'];
195
196 $is_kit = false;
197
198 if ( $this->is_kit( $id ) ) {
199 $is_kit = true;
200 if ( ! $force_delete_kit ) {
201 return Helper::error( 'cant_delete_kit', 'Cannot delete kit.', 'saved-templates/delete', 500, [ 'id' => $id ] );
202 } else {
203 $_GET['force_delete_kit'] = 1; // Fallback GET Ready!
204 }
205 }
206
207 $post = wp_trash_post( $id );
208 if ( $post instanceof WP_Post ) {
209 return Helper::success( [
210 'is_kit' => $is_kit,
211 'status' => 'success',
212 'message' => __( 'Successfully Deleted.', 'templately' )
213 ] );
214 }
215
216 return Helper::error(
217 'cant_delete_kit',
218 __( 'Something must went wrong.', 'templately' ),
219 'saved-templates/delete', 500,
220 [ 'id' => $id ]
221 );
222
223 // $cloud_map = DB::get_option( '_templately_cloud_map', [] );
224 // $new_cloud_map = [];
225 // array_walk( $cloud_map, function ( $cloud ) use ( &$cloud_map, $id, &$new_cloud_map ) {
226 // if ( $cloud['template_id'] !== $id ) {
227 // $new_cloud_map[] = $cloud;
228 // }
229 // } );
230 // DB::update_option( '_templately_cloud_map', $new_cloud_map );
231 // Helper::send_success( __( 'Successfully Deleted.', 'templately' ) );
232 }
233
234 protected function get_template_from_library( $id ) {
235 $local = new ElementorLocal();
236
237 return $local->get_data( [ 'template_id' => $id ] );
238 }
239
240 public function get_template_data( $id ) {
241 $data = $this->get_template_from_library( $id );
242 if ( ! empty( $data ) && isset( $data['content'] ) ) {
243 $name = get_the_title( $id );
244
245 return [
246 'name' => $name,
247 'file_content' => $data
248 ];
249 }
250
251 return null;
252 }
253
254 /**
255 * Creating an elementor page
256 *
257 * @param integer $id
258 * @param string $title
259 * @param Import $importer
260 *
261 * @since 2.0.0
262 *
263 * @return array|WP_Error array on success, WP_Error on failure.
264 */
265 public function create_page( $id, $title, $importer = null, $settings = [] ) {
266 $template_data = $importer->get_content( $id );
267
268 if ( is_wp_error( $template_data ) ) {
269 return $template_data;
270 }
271
272 if ( ! empty( $settings ) && ! empty( $template_data['content'] ) && is_array( $template_data['content'] ) ) {
273 $template_data['content'] = \Templately\Modules\ElementorKitSettings\Utils\ElementorSettingsMerger::merge( $template_data['content'], $settings );
274 }
275
276 $importer = new ElementorImporter;
277 $template_data = $importer->get_data( $template_data );
278
279 if ( ! empty( $title ) ) {
280 $template_data['page_title'] = $title;
281 }
282 /**
283 * Checking the template eligibility for import.
284 */
285 $eligible = $this->is_eligible( $template_data );
286 if( is_wp_error( $eligible ) ) {
287 return $eligible;
288 }
289
290 $inserted_ID = $importer->create_page( $template_data );
291
292 if ( is_wp_error( $inserted_ID ) ) {
293 return Helper::error(
294 'import_failed',
295 $inserted_ID->get_error_message(),
296 'import/page',
297 $inserted_ID->get_error_code(),
298 [ 'code' => $inserted_ID->get_error_code() ]
299 );
300 }
301
302 return [
303 'post_id' => $inserted_ID,
304 'edit_link' => get_edit_post_link( $inserted_ID, 'internal' ),
305 'elementor_edit_link' => Plugin::$instance->documents->get( $inserted_ID )->get_edit_url(),
306 'visit' => get_permalink( $inserted_ID )
307 ];
308 }
309
310 public function import_in_library( $id, $importer = null, $settings = [], $template_type = '', $type = '' ) {
311 $template_data = $importer->get_content( $id, 'elementor', 'remote' );
312
313 if ( is_wp_error( $template_data ) ) {
314 return $template_data;
315 }
316
317 if ( ! empty( $settings ) && ! empty( $template_data['content'] ) && is_array( $template_data['content'] ) ) {
318 $template_data['content'] = \Templately\Modules\ElementorKitSettings\Utils\ElementorSettingsMerger::merge( $template_data['content'], $settings );
319 }
320
321 // Frontend-provided template_type (from item details API) takes precedence over
322 // whatever the fetched content JSON reports.
323 if ( ! empty( $template_type ) ) {
324 $template_data['template_type'] = $template_type;
325 }
326
327 // Resolve the correct Builder Type using template_type before passing to the importer.
328 try {
329 $template_data['type'] = static::resolve_library_type( $template_data );
330 } catch ( \InvalidArgumentException $e ) {
331 return Helper::error( 'unsupported_template_type', $e->getMessage(), 'import', 400 );
332 }
333
334 $importer = new ElementorImporter;
335 $imported_template = $importer->import_in_library( $template_data );
336
337 if( is_wp_error( $imported_template ) ) {
338 return $imported_template;
339 }
340
341 $post_id = $imported_template['template_id'];
342
343 // Companion content for archive/fluent types — same side effects (Shop page,
344 // page_for_posts, LearnDash courses slug, fluent single-page template) the FSI
345 // Templates runner performs when importing these template types.
346 Utils::create_companion_content( $template_data['type'], $template_data['title'] ?? '', 'elementor' );
347
348 // Mark user as having imported a template
349 \Templately\Utils\Options::get_instance()->set( 'has_imported_template', true );
350
351 $document = Plugin::$instance->documents->get( $post_id );
352 $elementor_edit_link = $document ? $document->get_edit_url() : admin_url( 'post.php?post=' . $post_id . '&action=elementor' );
353
354 return [
355 'post_id' => $post_id,
356 'edit_link' => get_edit_post_link( $post_id, 'internal' ),
357 'elementor_edit_link' => $elementor_edit_link,
358 'visit' => $imported_template['url']
359 ];
360 }
361
362 public function get_content( $id ) {
363 $local = new ElementorLocal();
364 $content = $local->get_data( [
365 'template_id' => $id
366 ] );
367
368 $_response = [ 'status' => 'success' ];
369 $_response['data'] = $content;
370
371 if ( is_wp_error( $content ) ) {
372 /**
373 * @var WP_Error $content
374 */
375 unset( $_response['data'] );
376 $_response['status'] = 'error';
377 $_response['message'] = $content->get_error_message();
378 }
379
380 return $_response;
381 }
382
383 public function insert( $data, $postId = 0, $settings = [] ) {
384 if ( ! empty( $settings ) && is_array( $settings ) && ! empty( $data['content'] ) && is_array( $data['content'] ) ) {
385 $data['content'] = \Templately\Modules\ElementorKitSettings\Utils\ElementorSettingsMerger::merge( $data['content'], $settings );
386 }
387
388 $importer = new ElementorImporter();
389
390 return $importer->get_data( $data );
391 }
392
393 /**
394 * Register the Pro-promotion child-type fix once per request.
395 *
396 * Templates can reference Elementor Pro widgets (e.g. nested-carousel) that aren't
397 * installed. Elementor substitutes a Pro_Widget_Promotion placeholder, but its
398 * get_child_type() can't resolve the original nested children — so saving such a
399 * template fatals with "get_default_args() on array". filter_child_type() restores
400 * the correct child type. FSI imports get it via this module's own
401 * `templately_fsi_before_import` hook (see module.php — FSI no longer calls in);
402 * single-template imports go through Importer\Elementor::get_data(), which calls
403 * this so the filter is active for every import path.
404 */
405 public static function register_child_type_filter() {
406 static $registered = false;
407 if ( $registered ) {
408 return;
409 }
410 $registered = true;
411 add_filter( 'elementor/element/get_child_type', [ __CLASS__, 'filter_child_type' ], 10, 3 );
412 }
413
414 /**
415 * Filter Child Type
416 *
417 * @param $child_type
418 * @param $element_data
419 * @param $element
420 *
421 * @return mixed
422 */
423 public static function filter_child_type( $child_type, $element_data, $element ) {
424 // Fix for Elementor Pro Promotion Widget
425 if ( is_a( $element, 'Elementor\Modules\Promotions\Widgets\Pro_Widget_Promotion' ) || ( is_object( $element ) && 'pro-promotion' === $element->get_name() ) ) {
426 $el_types = array_keys( Plugin::$instance->elements_manager->get_element_types() );
427
428 if ( isset( $element_data['elType'] ) && in_array( $element_data['elType'], $el_types, true ) ) {
429 return Plugin::$instance->elements_manager->get_element_types( $element_data['elType'] );
430 }
431
432 if ( ! isset( $element_data['widgetType'] ) ) {
433 return null;
434 }
435
436 return Plugin::$instance->widgets_manager->get_widget_types( $element_data['widgetType'] );
437 }
438
439 return $child_type;
440 }
441 }
442