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 / full-site-import / Runners / ElementorContent.php

ElementorContent.php in Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! 3.8.0, at modules/full-site-import/Runners/ElementorContent.php

361 lines 12.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Templately\Modules\FullSiteImport\Runners;
4
5 use Elementor\Plugin;
6 use Elementor\TemplateLibrary\Source_Local;
7 use Exception;
8 use Templately\Modules\FullSiteImport\Utils\Utils;
9 use Templately\Utils\Helper;
10
11 class ElementorContent extends BaseRunner {
12 /**
13 * Set by import_post_type_content() when the just-imported page carried
14 * source-site links, so the calling loop can flag it for the Finalizer.
15 *
16 * @var bool
17 */
18 private $pending_link_rewrite = false;
19
20 public function get_name(): string {
21 return 'content';
22 }
23
24 public function get_label(): string {
25 return __( 'Elementor', 'templately' );
26 }
27
28 public function should_run( $data, $imported_data = [] ): bool {
29 return $this->manifest['platform'] === 'elementor' && ! empty( $this->manifest['content'] );
30 }
31
32 public function should_log(): bool {
33 return true;
34 }
35
36 public function get_action(): string {
37 return 'updateLog';
38 }
39
40 public function log_message(): string {
41 return __( 'Importing Elementor Page and Post Templates', 'templately' );
42 }
43
44 /**
45 * Get kit by ID with backward compatibility.
46 *
47 * The get_kit() method was introduced in Elementor 3.13.0.
48 * For older versions, we fall back to using documents->get() directly.
49 *
50 * @param \Elementor\Core\Kits\Manager $kits_manager The kits manager instance.
51 * @param int $kit_id The kit ID to retrieve.
52 * @return \Elementor\Core\Kits\Documents\Kit|null The kit document or null.
53 */
54 private function get_kit_with_fallback( $kits_manager, $kit_id ) {
55 // Check if the get_kit method exists (Elementor 3.13.0+)
56 if ( method_exists( $kits_manager, 'get_kit' ) ) {
57 return $kits_manager->get_kit( $kit_id );
58 }
59
60 // Fallback for older Elementor versions (< 3.13.0)
61 // This replicates the old get_active_kit() behavior
62 return Plugin::$instance->documents->get( $kit_id );
63 }
64
65 /**
66 * Create a new kit with backward compatibility.
67 *
68 * The create_new_kit() method was introduced in Elementor 3.13.0.
69 * For older versions, we fall back to using documents->create() directly.
70 *
71 * @param \Elementor\Core\Kits\Manager $kits_manager The kits manager instance.
72 * @param string $kit_name The name for the new kit.
73 * @param array $settings The kit settings.
74 * @param bool $active Whether to set this kit as active.
75 * @return int The created kit ID.
76 */
77 private function create_new_kit_with_fallback( $kits_manager, $kit_name = '', $settings = [], $active = true ) {
78 // Check if the create_new_kit method exists (Elementor 3.13.0+)
79 if ( method_exists( $kits_manager, 'create_new_kit' ) ) {
80 return $kits_manager->create_new_kit( $kit_name, $settings, $active );
81 }
82
83 // Fallback for older Elementor versions (< 3.13.0)
84 $kit_name = $kit_name ? $kit_name : esc_html__( 'Custom', 'templately' );
85
86 $kit = Plugin::$instance->documents->create( 'kit', [
87 'post_type' => Source_Local::CPT,
88 'post_title' => $kit_name,
89 'post_status' => 'publish',
90 ] );
91
92 $kit_id = $kit->get_id();
93
94 // Apply settings if provided
95 if ( ! empty( $settings ) ) {
96 $kit->save( [ 'settings' => $settings ] );
97 }
98
99 // Set as active if requested
100 if ( $active ) {
101 update_option( $kits_manager::OPTION_ACTIVE, $kit_id );
102 }
103
104 return $kit_id;
105 }
106
107 /**
108 * Create a default kit with backward compatibility.
109 *
110 * The create_default() method was made public in Elementor 3.12.0.
111 * For older versions, we fall back to using documents->create() directly.
112 *
113 * @param \Elementor\Core\Kits\Manager $kits_manager The kits manager instance.
114 * @return int The created kit ID.
115 */
116 private function create_default_kit_with_fallback( $kits_manager ) {
117 // Check if create_default is publicly accessible (Elementor 3.12.0+)
118 if ( method_exists( $kits_manager, 'create_default' ) && is_callable( [ $kits_manager, 'create_default' ] ) ) {
119 return $kits_manager->create_default();
120 }
121
122 // Fallback for older Elementor versions (< 3.12.0)
123 $kit = Plugin::$instance->documents->create( 'kit', [
124 'post_type' => Source_Local::CPT,
125 'post_title' => esc_html__( 'Default Kit', 'templately' ),
126 'post_status' => 'publish',
127 ] );
128
129 return $kit->get_id();
130 }
131
132 /**
133 * @throws Exception
134 */
135 public function import( $data, $imported_data ): array {
136 $results = $data["imported_data"]["content"] ?? [];
137 $contents = $this->manifest['content'];
138 $path = $this->dir_path . 'content' . DIRECTORY_SEPARATOR;
139
140 $this->json->set_source_url( $this->manifest['site'] ?? '' );
141
142
143 // $total = array_reduce( $contents, function ( $carry, $item ) {
144 // return $carry + count( $item );
145 // }, 0 );
146 // $processed = 0;
147
148 /**
149 * Check if there is any active kit?
150 * If not, create one.
151 */
152
153 $kits_manager = Plugin::$instance->kits_manager;
154
155 $active_kit = $kits_manager->get_active_id();
156 $kit = $this->get_kit_with_fallback( $kits_manager, $active_kit );
157 $old_logo = $kit->get_settings('site_logo');
158
159 if(isset($this->manifest['has_settings']) && $this->manifest['has_settings'] && !$this->is_key_processed('global_colors', 'settings')){
160 // backing up the active kit id before updating the new one
161 if(!get_option("__templately_" . $kits_manager::OPTION_ACTIVE)){
162 add_option("__templately_" . $kits_manager::OPTION_ACTIVE, $active_kit, '', 'no');
163 }
164 else{
165 update_option("__templately_" . $kits_manager::OPTION_ACTIVE, $active_kit, 'no');
166 }
167
168 $file = $this->dir_path . "settings.json";
169 $settings = Utils::read_json_file( $file );
170
171 if(isset($settings['site_name'])){
172 unset($settings['site_name']);
173 }
174 if(isset($settings['site_description'])){
175 unset($settings['site_description']);
176 }
177 if(!empty($data['color'])){
178 if (!empty($settings['system_colors'])) {
179 foreach ($settings['system_colors'] as $key => $color) {
180 $settings['system_colors'][$key]['color'] = $data['color'][$color['_id']] ?? $color['color'];
181 }
182 }
183 if (!empty($settings['custom_colors'])) {
184 foreach ($settings['custom_colors'] as $key => $color) {
185 $settings['custom_colors'][$key]['color'] = $data['color'][$color['_id']] ?? $color['color'];
186 }
187 }
188 }
189
190 if(!empty($data['typography'])){
191 if (!empty($settings['system_typography'])) {
192 foreach ($settings['system_typography'] as $key => &$typography) {
193 if(!empty($data['typography'][$typography['_id']])){
194 $typography = array_merge($typography, $data['typography'][$typography['_id']]);
195 }
196 }
197 }
198 if (!empty($settings['custom_typography'])) {
199 foreach ($settings['custom_typography'] as $key => &$typography) {
200 if(!empty($data['typography'][$typography['_id']])){
201 $typography = array_merge($typography, $data['typography'][$typography['_id']]);
202 }
203 }
204 }
205 }
206
207 // `logo` arrives either as a bare url string or as an { id, url } array,
208 // and upload_logo() takes a URL — handing it the array made
209 // wp_http_validate_url() reject it, so a remote logo never imported.
210 $logo_url = Utils::get_logo_url($data['logo'] ?? null);
211 $logo_id = is_array($data['logo'] ?? null) ? ($data['logo']['id'] ?? 0) : 0;
212
213 if (!empty($logo_id)) {
214 $settings['site_logo'] = $data['logo'];
215 Utils::backup_option_value( 'site_logo' );
216 $this->origin->update_imported_list('attachment', $logo_id);
217 } elseif (!empty($logo_url) && strpos($logo_url, 'data:image/') === 0) {
218 // Upload base64 data URL
219 $site_logo = Utils::upload_logo_base64($logo_url, $this->session_id);
220
221 if(!empty($site_logo['id'])){
222 $settings['site_logo'] = $site_logo;
223 Utils::backup_option_value( 'site_logo' );
224 $this->origin->update_imported_list('attachment', $site_logo['id']);
225 }
226 } elseif (!empty($logo_url)) {
227 $settings['site_logo'] = $old_logo;
228
229 // Upload regular URL. If it fails, retain the old logo.
230 $site_logo = Utils::upload_logo($logo_url, $this->session_id);
231
232 if(!empty($site_logo['id'])){
233 $settings['site_logo'] = $site_logo;
234 Utils::backup_option_value( 'site_logo' );
235 $this->origin->update_imported_list('attachment', $site_logo['id']);
236 }
237 }
238
239
240 $kit_id = $this->create_new_kit_with_fallback( $kits_manager, $this->manifest['name'], $settings, true );
241
242 $kit = $this->get_kit_with_fallback( $kits_manager, $kit_id );
243
244 // $kit->update_settings( ['site_logo' => $settings['site_logo']] );
245
246 // Create an array with the post ID and the new title
247 $post_data = array(
248 'ID' => $kit_id,
249 'post_title' => $this->manifest['name'] . " Kit",
250 );
251 // Update the post
252 wp_update_post( $post_data );
253
254 $this->mark_key_processed('global_colors', 'settings');
255 }
256
257 $active_kit = $kits_manager->get_active_id();
258 $kit = $this->get_kit_with_fallback( $kits_manager, $active_kit );
259
260 if ( ! $kit->get_id() ) {
261 $kit_id = $this->create_default_kit_with_fallback( $kits_manager );
262 update_option( $kits_manager::OPTION_ACTIVE, $kit_id );
263 $kit = $this->get_kit_with_fallback( $kits_manager, $kit_id );
264 }
265
266 // $processed = 0;
267 $total = array_reduce($contents, function($carry, $item) {
268 return $carry + count($item);
269 }, 0);
270
271 $results = $this->loop( $contents, function($post_type, $post, $results ) use($path, $imported_data, $total) {
272 // Inner loop accumulates results for this post_type
273 $inner_result = $this->loop( $post, function($id, $content_settings, $result ) use ($post_type, $results, $path, $imported_data, $total) {
274 if ( post_type_exists( $post_type ) ) {
275
276 $import = $this->import_post_type_content( $id, $post_type, $path, $imported_data, $content_settings );
277
278 if ( ! $import ) {
279 $result[ $post_type ]['failed'][ $id ] = $import;
280 } else {
281 Utils::import_page_settings( $import, $content_settings );
282 $result[ $post_type ]['succeed'][ $id ] = $import;
283
284 // Flag pages carrying source-site links so the Finalizer rewrites
285 // them to the real imported permalinks (see Finalizer::prepare).
286 if ( $this->pending_link_rewrite ) {
287 $result[ $post_type ]['__link_rewrites'][ $id ] = true;
288 }
289 }
290
291 // Broadcast Log - merge with outer results for accurate counting
292 $merged = array_merge($results, $result);
293 $processed = 0;
294 foreach ($merged as $type => $data) {
295 if (is_array($data)) {
296 $processed += count($data['succeed'] ?? []) + count($data['failed'] ?? []);
297 }
298 }
299 $progress = $total > 0 ? floor( ( 100 * $processed ) / $total ) : 100;
300 $this->log( $progress );
301 }
302
303 return $result;
304 }, $post_type);
305
306 // Non-recursive merge of inner result with outer results
307 $results = array_merge($results, $inner_result);
308 return $results;
309 });
310
311 return [ 'content' => $results ];
312 }
313
314 /**
315 * @throws Exception
316 */
317 private function import_post_type_content( $id, $post_type, $path, $imported_data, $content_settings ) {
318 $this->pending_link_rewrite = false;
319 try {
320 $template = $this->factory->create( $content_settings['doc_type'], [
321 'post_title' => $content_settings['title'],
322 'post_status' => 'publish',
323 'post_type' => $post_type,
324 ] );
325
326 $file = $path . $post_type . DIRECTORY_SEPARATOR . "{$id}.json";
327 $post_data = Utils::read_json_file( $file );
328
329 if ( ! empty( $content_settings['data'] ) || $this->is_ai_content($id) ) {
330 /**
331 * TODO:
332 *
333 * We can check if there is any data for settings.
334 * if yes: ignore content from insert.
335 *
336 * Process the content while finalizing.
337 */
338 // $this->json->prepare( $post_data['content'], $id, $content_settings['data'], $imported_data );
339
340 $post_data['content'] = [];
341 }
342
343 unset($content_settings['conditions']);
344 $post_data['import_settings'] = $content_settings;
345
346 // Detect source-site links. When present, flag the page so the Finalizer
347 // rewrites them to the real imported permalinks once every page exists.
348 // (Pages with `data` are deferred — content is [] here — and are finalized
349 // anyway, so their links get resolved in Finalizer::prepare regardless.)
350 if ( ! empty( $post_data['content'] ) && $this->json->replace_source_urls( $post_data['content'] ) > 0 ) {
351 $this->pending_link_rewrite = true;
352 }
353
354 $template->import( $post_data );
355
356 return $template->get_main_id();
357 } catch ( Exception $e ) {
358 return false;
359 }
360 }
361 }