PluginProbe
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! / 3.1.3
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! v3.1.3
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 3.1.10 All 111 releases
templately / includes / Core / Importer / FullSiteImport.php

FullSiteImport.php in Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! 3.1.3, at includes/Core/Importer/FullSiteImport.php

976 lines 29.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Templately\Core\Importer;
4
5 use Elementor\Plugin;
6 use Exception;
7 use Templately\Core\Importer\Utils\Utils;
8 use Templately\Utils\Base;
9 use Templately\Utils\Helper;
10 use Templately\Utils\Installer;
11 use Templately\Utils\Options;
12
13 class FullSiteImport extends Base {
14 use LogHelper;
15
16 const SESSION_OPTION_KEY = 'templately_import_session';
17 public $manifest;
18 protected $export;
19
20 private $version = '1.0.0';
21
22 public $session_id;
23 public $download_key;
24 public $dir_path;
25 protected $filePath;
26 protected $tmp_dir = null;
27 protected $dev_mode = false;
28 protected $api_key = '';
29 public $request_params = [];
30 protected $documents_data = [];
31 protected $dependency_data = [];
32 private $is_import_status_handled = false;
33
34 public function __construct() {
35 $this->dev_mode = defined('TEMPLATELY_DEV') && TEMPLATELY_DEV;
36 $this->api_key = Options::get_instance()->get('api_key');
37
38 add_action('wp_ajax_templately_import_settings', [$this, 'import_settings']);
39 add_action('wp_ajax_templately_pack_import_status', [$this, 'import_status']);
40 add_action('wp_ajax_templately_pack_import', [$this, 'import']);
41 add_action('wp_ajax_templately_pack_import_revert', [$this, 'import_revert']);
42 add_action('wp_ajax_templately_pack_import_info', [$this, 'import_info']);
43 add_action('admin_init', [$this, 'admin_init']);
44 // add_action('admin_notices', [$this, 'add_revert_button']);
45
46 if (isset($_GET['action']) && $_GET['action'] == 'templately_pack_import') {
47 add_filter('wp_redirect', '__return_false', 999);
48 }
49
50 if ($this->dev_mode) {
51 add_filter('http_request_host_is_external', '__return_true');
52 add_filter('http_request_args', function ($args) {
53 $args['sslverify'] = false;
54
55 return $args;
56 });
57 }
58 }
59
60 public function admin_init() {
61 if (get_option('templately_flush_rewrite_rules', false)) {
62 flush_rewrite_rules();
63 delete_option('templately_flush_rewrite_rules');
64 }
65 }
66
67 public function import_settings() {
68 if (!current_user_can('edit_posts')) {
69 // @todo show error in ui. Currently getting stack.
70 wp_send_json_error(__('Unauthorized action.', 'templately'));
71 }
72
73 $data = wp_unslash($_POST);
74
75 update_option(self::SESSION_OPTION_KEY, $data);
76
77 delete_transient('templately_fsi_log');
78
79 wp_send_json_success([
80 'is_lightspeed' => !Helper::should_flush(),
81 ]);
82 }
83
84 private function update_session_data($data): bool {
85 $old_data = get_option(self::SESSION_OPTION_KEY, []);
86
87 return update_option(self::SESSION_OPTION_KEY, wp_parse_args($data, $old_data));
88 }
89
90 public function get_session_data(): array {
91 $data = get_option(self::SESSION_OPTION_KEY, []);
92
93 $options = [];
94
95 if (is_array($data) && !empty($data)) {
96 foreach ($data as $key => $value) {
97 $json = json_decode($value, true);
98 $options[$key] = $json !== null ? $json : $value;
99 }
100 }
101
102 return $options;
103 }
104
105 public function initialize_props() {
106 $data = $this->get_session_data();
107 if (isset($data['session_id'])) {
108 $this->session_id = $data['session_id'];
109 }
110 if (isset($data['dir_path'])) {
111 $this->dir_path = $data['dir_path'];
112 }
113 if (isset($data['download_key'])) {
114 $this->download_key = $data['download_key'];
115 }
116 if (isset($data['dependency_data'])) {
117 $this->dependency_data = $data['dependency_data'];
118 }
119 }
120
121 private function clear_session_data(): bool {
122 return delete_site_option(self::SESSION_OPTION_KEY);
123 }
124
125 public function import() {
126 if (!$this->dev_mode && !wp_doing_ajax()) {
127 exit;
128 }
129
130 delete_transient('templately_fsi_log');
131 delete_option('templately_fsi_imported_list');
132
133 if (Helper::should_flush()) {
134 header("Cache-Control: no-store, no-cache");
135 header('Content-Type: text/event-stream, charset=UTF-8');
136 header("Connection: Keep-Alive");
137 }
138
139 if ($GLOBALS['is_nginx']) {
140 header('X-Accel-Buffering: no');
141 header('Content-Encoding: none');
142 }
143
144 register_shutdown_function([$this, 'register_shutdown']);
145 $this->add_revert_hooks();
146
147 // Ignore user aborts and allow the script
148 // to run forever
149 ignore_user_abort(true);
150
151 // Time to run the import!
152 set_time_limit(0);
153
154
155
156 // // Don't run cron until the request finishes, if possible.
157 // if ( PHP_VERSION_ID >= 70016 && function_exists( 'fastcgi_finish_request' ) ) {
158 // fastcgi_finish_request();
159 // } elseif ( function_exists( 'litespeed_finish_request' ) ) {
160 // litespeed_finish_request();
161 // }
162 if (Helper::should_flush()) {
163 flush();
164 wp_ob_end_flush_all();
165 }
166
167 try {
168 // TODO: Need to check if user is connected or not
169
170 $this->request_params = $this->get_session_data();
171
172 $_id = isset($this->request_params['id']) ? (int) $this->request_params['id'] : null;
173
174 if ($_id === null) {
175 $this->throw(__('Invalid Pack ID.', 'templately'));
176 }
177
178 if (!isset($_GET['part'])) {
179 $this->throw(__('Invalid request.', 'templately'));
180 }
181
182 switch ($_GET['part']) {
183 case 'download':
184 /**
185 * Check Writing Permission
186 */
187 $this->check_writing_permission();
188
189 /**
190 * Download the zip
191 */
192 $this->download_zip($_id);
193
194 /**
195 * Reading Manifest File
196 */
197 $this->read_manifest();
198
199 /**
200 * Version Check
201 */
202 if (!empty($this->manifest['version']) && version_compare($this->manifest['version'], $this->version, '>')) {
203 /**
204 * FIXME: The message should be re-written (by content/support team).
205 */
206 $this->throw(__('Please update the templately plugin.', 'templately'));
207 }
208
209 /**
210 * Checking & Installing Plugin Dependencies
211 */
212 $this->install_dependencies();
213
214 $this->sse_message([
215 'type' => 'complete',
216 'action' => 'downloadComplete',
217 'results' => '',
218 ]);
219 break;
220 case 'import':
221 /**
222 * Should Revert Old Data
223 */
224 $this->revert();
225
226
227 $this->initialize_props();
228
229 /**
230 * Reading Manifest File
231 */
232 $this->read_manifest();
233
234 /**
235 * Platform Based Templates Import
236 */
237 $this->start_content_import();
238 break;
239 default:
240 $this->throw(__('Invalid request.', 'templately'));
241 break;
242 }
243 } catch (Exception $e) {
244 $this->handle_import_status('failed', $e->getMessage());
245 $this->sse_message([
246 'action' => 'error',
247 'status' => 'error',
248 'type' => "error",
249 'title' => __("Oops!", "templately"),
250 'message' => $e->getMessage()
251 ]);
252 }
253
254 if ($_GET['part'] === 'import') {
255 // TODO: cleanup
256 $this->clear_session_data();
257 }
258 }
259
260 public function import_status() {
261 $log = get_transient('templately_fsi_log');
262 if (!empty($log) && is_array($log)) {
263 $lastLogIndex = isset($_GET['lastLogIndex']) ? (int) $_GET['lastLogIndex'] : 0;
264 $log = array_slice($log, $lastLogIndex);
265
266 // delete log after complete
267 $data = end($log);
268 if (isset($data, $data['action']) && ($data['action'] === 'complete' || $data['action'] === 'downloadComplete' || $data['action'] === 'error')) {
269 delete_transient('templately_fsi_log');
270 }
271 }
272 wp_send_json(['log' => $log]);
273 }
274
275 /**
276 * @throws Exception
277 */
278 private function throw($message, $code = 0) {
279 if ($this->dev_mode) {
280 error_log(print_r($message, 1));
281 }
282 throw new Exception($message);
283 }
284
285 /**
286 * @throws Exception
287 */
288 private function check_writing_permission() {
289 $upload_dir = wp_upload_dir();
290
291 if (!is_writable($upload_dir['basedir'])) {
292 $this->throw(__('Upload directory is not writable.', 'templately'));
293 }
294
295 $this->tmp_dir = trailingslashit($upload_dir['basedir']) . 'templately' . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR;
296
297 if (!is_dir($this->tmp_dir)) {
298 wp_mkdir_p($this->tmp_dir);
299 }
300
301 $this->sse_log('writing_permission_check', __('Permission Passed', 'templately'), 100);
302 }
303
304 private function get_api_url($version, $end_point): string {
305 return $this->dev_mode ? "https://app.templately.dev/api/$version/" . $end_point : "https://app.templately.com/api/$version/" . $end_point;
306 }
307
308 private function info_get_api_url($id): string {
309 return $this->dev_mode ? 'https://app.templately.dev/api/v1/import/info/pack/' . $id : 'https://app.templately.com/api/v1/import/info/pack/' . $id;
310 }
311
312 /**
313 * @throws Exception
314 */
315 private function download_zip($id) {
316 // $this->sse_log( 'download', __( 'Downloading Template Pack', 'templately' ), 1 );
317 $response = wp_remote_get($this->get_api_url("v2", "import/pack/$id"), [
318 'timeout' => 30,
319 'headers' => [
320 'Content-Type' => 'application/json',
321 'Authorization' => 'Bearer ' . $this->api_key,
322 'x-templately-ip' => Helper::get_ip(),
323 'x-templately-url' => home_url('/'),
324 'x-templately-version' => TEMPLATELY_VERSION,
325 ]
326 ]);
327
328 $response_code = wp_remote_retrieve_response_code($response);
329 $content_type = wp_remote_retrieve_header($response, 'content-type');
330 $this->download_key = wp_remote_retrieve_header($response, 'download-key');
331
332 if (is_wp_error($response)) {
333 $this->throw(__('Template pack download failed', 'templately') . $response->get_error_message());
334 } else if ($response_code != 200) {
335 if (strpos($content_type, 'application/json') !== false) {
336 // Retrieve Data from Response Body.
337 $response_body = json_decode(wp_remote_retrieve_body($response), true);
338
339 // If the response body is JSON and it contains an error, throw an exception with the error message
340 if (isset($response_body['status']) && $response_body['status'] === 'error') {
341 $this->throw($response_body['message']);
342 }
343 }
344 $this->throw(__('Template pack download failed with response code: ', 'templately') . $response_code);
345 }
346
347 $this->sse_log('download', __('Template is getting ready', 'templately'), 57);
348
349 $session_id = uniqid();
350 $this->dir_path = $this->tmp_dir . $session_id . DIRECTORY_SEPARATOR;
351 $this->filePath = $this->tmp_dir . "{$session_id}.zip";
352 $this->session_id = $session_id;
353
354 $this->update_session_data([
355 'session_id' => $this->session_id,
356 'dir_path' => $this->dir_path,
357 'download_key' => $this->download_key,
358 ]);
359
360 if (file_put_contents($this->filePath, $response['body'])) { // phpcs:ignore
361 $this->sse_log('download', __('Template is getting ready', 'templately'), 100);
362
363 $this->unzip();
364 } else {
365 $this->throw(__('Downloading Failed. Please try again', 'templately'));
366 }
367 }
368
369 /**
370 * @throws Exception
371 */
372 protected function unzip() {
373 if (!WP_Filesystem()) {
374 $this->throw(__('WP_Filesystem cannot be initialized', 'templately'));
375 }
376
377 $unzip = unzip_file($this->filePath, $this->dir_path);
378 if (is_wp_error($unzip)) {
379 $unzip = $this->unzip_file($this->filePath, $this->dir_path);
380 }
381
382 if (is_wp_error($unzip)) {
383 $error = $unzip->get_error_message();
384 if (empty($error)) {
385 // Generic error message
386 Helper::log($unzip);
387 $error_message = sprintf(__("It seems we're experiencing technical difficulties. Please try again or contact <a href='%s' target='_blank'>support</a>.", "templately"), 'https://wpdeveloper.com/support');
388 $this->throw($error_message);
389 } else {
390 $this->throw($unzip->get_error_message());
391 }
392 }
393
394 if ($unzip) {
395 unlink($this->filePath);
396 }
397 }
398
399 /**
400 * Unzip a specified ZIP file to a location on the Filesystem.
401 *
402 * @param string $file Full path and filename of ZIP archive.
403 * @param string $to Full path on the filesystem to extract archive to.
404 * @return true|WP_Error True on success, WP_Error on failure.
405 */
406 function unzip_file($file, $to) {
407 try {
408 $zip = new \ZipArchive;
409
410 $res = $zip->open($file);
411 if ($res === TRUE) {
412 $zip->extractTo($to);
413 $zip->close();
414
415 return true;
416 }
417 } catch (\Throwable $th) {
418 return new \WP_Error('exception_caught', $th->getMessage());
419 }
420
421 if (isset($zip)) {
422 return new \WP_Error('zip_error_' . $zip->status, $zip->getStatusString());
423 } else {
424 return new \WP_Error('unknown_error', '');
425 }
426 }
427
428 /**
429 * @throws Exception
430 */
431 private function read_manifest() {
432 $manifest_content = file_get_contents($this->dir_path . DIRECTORY_SEPARATOR . 'manifest.json');
433 if (empty($manifest_content)) {
434 $this->throw(__('Cannot be imported, as the manifest file is corrupted', 'templately'));
435 }
436
437 $this->manifest = json_decode($manifest_content, true);
438 $this->removeLog('temp');
439
440 // TODO: Read & Broadcast the LOG for waiting list
441 // $this->sse_log( 'plugin', 'Installing required plugins', '--', 'updateLog', 'processing' );
442 // // $this->sse_log( 'extra-content', 'Import Extra Contents (i.e: Forms)', '--', 'updateLog', 'processing' );
443 // $this->sse_log( 'templates', 'Import Templates (i.e: Header, Footer etc)', '--', 'updateLog', 'processing' );
444 // // $this->sse_log( 'content', 'Import Pages, Posts etc', '--', 'updateLog', 'processing' );
445 // $this->sse_log( 'wp-content', 'Importing Pages, Posts, Navigation, etc', '--', 'updateLog', 'processing' );
446 // $this->sse_log( 'finalize', 'Finalizing Your Imports', '--', 'updateLog', 'processing' );
447 }
448
449 private function skipped_plugin(): bool {
450 return empty($this->request_params['plugins']) || !is_array($this->request_params['plugins']);
451 }
452
453 private function install_dependencies() {
454 $allowed_themes = ['hello-elementor', 'twentytwentyfour'];
455
456 if (!empty($this->request_params['theme']) && is_array($this->request_params['theme'])) {
457 // activate theme
458 $theme = $this->request_params['theme'];
459
460 $this->before_install_hook();
461
462 if (isset($theme['stylesheet']) && in_array($theme['stylesheet'], $allowed_themes)) {
463 // do_action('before_theme_activation', $theme); // Trigger action before theme activation
464 $this->sse_log('theme', 'Installing and activating theme: ' . $theme['name'], 0);
465 if (!get_option("__templately_stylesheet")) {
466 $stylesheet = get_option('stylesheet');
467 add_option("__templately_stylesheet", $stylesheet, '', 'no');
468 }
469
470 $plugin_status = Installer::get_instance()->install_and_activate_theme($theme['stylesheet']);
471
472 if (!$plugin_status['success']) {
473 $this->sse_message([
474 'action' => 'updateLog',
475 'status' => 'error',
476 'message' => "Failed to activate theme: " . $theme['name'],
477 'type' => "theme",
478 'progress' => 0
479 ]);
480 $this->dependency_data['theme'] = [
481 'success' => false,
482 'name' => $theme['name'],
483 'slug' => $theme['stylesheet'],
484 'message' => $plugin_status['message'] ?? ''
485 ];
486 } else {
487 // do_action('after_theme_activation', $theme); // Trigger action after theme activation
488
489 $this->sse_message([
490 'action' => 'updateLog',
491 'status' => 'complete',
492 'message' => "Activated theme: " . $theme['name'],
493 'type' => "theme",
494 'progress' => 100
495 ]);
496 $this->dependency_data['theme'] = [
497 'success' => true,
498 'name' => $theme['name'],
499 'slug' => $theme['stylesheet'],
500 'message' => $plugin_status['message'] ?? ''
501 ];
502 }
503 }
504
505 $this->after_install_hook();
506 } else {
507 $this->removeLog('theme');
508 }
509 if (!empty($this->request_params['plugins']) && is_array($this->request_params['plugins'])) {
510 // $this->sse_log( 'plugin', 'Installing Plugins', 1 );
511 $total_plugin = count($this->request_params['plugins']);
512
513 $total_plugin_installed = $total_plugin;
514 $_installed_plugins = 0;
515
516 $this->before_install_hook();
517
518 foreach ($this->request_params['plugins'] as $dependency) {
519 $this->sse_log('plugin', 'Installing required plugins: ' . $dependency['name'], floor((100 * $_installed_plugins / $total_plugin)));
520
521 $dependency['slug'] = $dependency['plugin_original_slug'];
522 $plugin_status = Installer::get_instance()->install($dependency);
523
524 if (!$plugin_status['success']) {
525 $this->sse_message([
526 'position' => 'plugin',
527 'action' => 'updateLog',
528 'status' => 'error',
529 'message' => 'Installation Failed: ' . $dependency['name'] . ' (' . ($plugin_status['message'] ?? '') . ')',
530 'type' => "plugin_{$dependency['plugin_original_slug']}",
531 'progress' => 0
532 ]);
533
534 if (isset($dependency['mustHave']) && $dependency['mustHave']) {
535 $this->removeLog('plugin');
536 $this->throw('Installation Failed: ' . $dependency['name'] . ' (' . ($plugin_status['message'] ?? '') . ')');
537 }
538
539 $this->dependency_data['plugins']['failed'][] = [
540 'name' => $dependency['name'],
541 'slug' => $dependency['slug'],
542 'link' => $dependency['link'],
543 'message' => $plugin_status['message'] ?? ''
544 ];
545 } else {
546 $_installed_plugins++;
547 $total_plugin_installed--;
548 }
549 }
550
551 $this->after_install_hook();
552
553 $this->sse_message([
554 'action' => 'updateLog',
555 'status' => 'complete',
556 'message' => "Installed required plugins ($_installed_plugins/$total_plugin)",
557 'type' => "plugin",
558 'progress' => 100
559 ]);
560 $this->dependency_data['plugins']['total'] = $total_plugin;
561 $this->dependency_data['plugins']['succeed'] = $_installed_plugins;
562 } else {
563 $this->removeLog('plugin');
564 }
565
566
567 $this->update_session_data([
568 'dependency_data' => json_encode($this->dependency_data),
569 ]);
570 // $this->sse_log( 'plugin', 'Skipped Installing Plugins', '--', 'updateLog', 'skipped' );
571 }
572
573 private function before_install_hook() {
574 // remove_all_actions( 'wp_loaded' );
575 // remove_all_actions( 'after_setup_theme' );
576 // remove_all_actions( 'plugins_loaded' );
577 // remove_all_actions( 'init' );
578
579 // making sure so that no redirection happens during plugin installation and hooks triggered bellow.
580 add_filter('wp_redirect', '__return_false', 999);
581 }
582
583 private function after_install_hook() {
584 // do_action( 'wp_loaded' );
585 // do_action( 'after_setup_theme' );
586 // do_action( 'plugins_loaded' );
587 // do_action( 'init' );
588 }
589
590 /**
591 * @throws Exception
592 */
593 private function start_content_import() {
594 add_filter('upload_mimes', array($this, 'allow_svg_upload'));
595 add_filter('elementor/files/allow_unfiltered_upload', '__return_true');
596
597 $import = new Import($this);
598 $imported_data = $import->run();
599
600 $this->handle_import_status('success');
601
602 update_option('templately_flush_rewrite_rules', true, false);
603
604 $this->sse_message([
605 'type' => 'complete',
606 'action' => 'complete',
607 'results' => $this->normalize_imported_data($imported_data)
608 ]);
609 }
610
611 private function normalize_imported_data($data) {
612 $templates = !empty($data['templates']['succeed']) ? count($data['templates']['succeed']) : 0;
613 $template_types = !empty($data['templates']['template_types']) ? $data['templates']['template_types'] : [];
614
615 $post_types = [];
616 $content_templates = [];
617 if (!empty($data['content']) && is_array($data['content'])) {
618 foreach ($data['content'] as $type => $type_data) {
619 $content_templates[$type] = !empty($type_data['succeed']) ? count($type_data['succeed']) : 0;
620 $post_types[] = $this->get_post_type_label_by_slug($type);
621 }
622 }
623
624 $contents = [];
625 if (!empty($data['wp-content']) && is_array($data['wp-content'])) {
626 foreach ($data['wp-content'] as $type => $type_data) {
627 $contents[$type] = !empty($type_data['succeed']) ? count($type_data['succeed']) : 0;
628 if (!in_array($type, ['wp_navigation', 'nav_menu_item'])) {
629 $post_types[] = $this->get_post_type_label_by_slug($type);
630 }
631 }
632 }
633
634 Helper::log($data);
635
636 return [
637 'templates' => $templates,
638 'contents' => $content_templates,
639 'wp-content' => $contents,
640 'post_types' => $post_types,
641 'template_types' => $template_types,
642 'dependency_data' => $this->dependency_data,
643 ];
644 }
645
646 public function get_request_params() {
647 return $this->request_params;
648 }
649
650 private function revert() {
651 // $request = $this->get_request_params();
652 // if ( isset( $request['revert'] ) && $request['revert'] ) {
653 // // TODO: Implement the Revert Process.
654 // }
655 }
656
657 public function redirect_for_archives($link, $post_id) {
658 $archive_settings = get_option('templately_post_archive');
659 if (!empty($archive_settings) && intval($archive_settings['post_id']) === intval($post_id)) {
660 $link = str_replace($post_id, $archive_settings['archive_id'], $link);
661 }
662
663 return $link;
664 }
665
666 public function allow_svg_upload($mimes) {
667 // Allow SVG
668 $mimes['svg'] = 'image/svg+xml';
669 return $mimes;
670 }
671
672 public function register_shutdown() {
673 $status = connection_status();
674 $last_error = error_get_last();
675 if ($status != CONNECTION_NORMAL && $last_error && $last_error['type'] === E_ERROR) {
676 if ((defined('WP_DEBUG') && WP_DEBUG || defined('TEMPLATELY_EVENT_LOG') && TEMPLATELY_EVENT_LOG) && !empty($last_error['message'])) {
677 $full_message = $last_error['message'];
678
679 // Split the message at the first newline to remove the stack trace
680 $message_parts = preg_split('/\n/', $full_message);
681
682 // The error message is the first part
683 $error_message = $message_parts[0];
684 } else {
685 // Generic error message
686 $error_message = sprintf(__("It seems we're experiencing technical difficulties. Please try again or contact <a href='%s' target='_blank'>support</a>.", "templately"), 'https://wpdeveloper.com/support');
687 }
688
689
690 $this->handle_import_status('failed', $error_message);
691 // Handle the error, e.g. log it or display a message to the user
692 $this->sse_message([
693 'action' => 'error',
694 'status' => 'error',
695 'type' => "error",
696 'title' => __("Oops!", "templately"),
697 'message' => $error_message,
698 // 'position' => 'plugin',
699 // 'progress' => '--',
700 ]);
701 }
702
703 $this->debug_log("Shutdown:.....");
704 $this->debug_log("connection_status: " . $this->getConnectionStatusText());
705 $this->debug_log($last_error);
706 }
707
708 public function handle_import_status($status, $description = '') {
709 if ($this->is_import_status_handled) {
710 Helper::log("Import status already handled: $status");
711 return null;
712 }
713 $this->is_import_status_handled = $status;
714
715 $download_key = $this->download_key;
716
717 $headers = [
718 'Content-Type' => 'application/json',
719 'Authorization' => 'Bearer ' . $this->api_key,
720 'download_key' => $download_key,
721 'download-key' => $download_key,
722 'x-templately-ip' => Helper::get_ip(),
723 'x-templately-url' => home_url('/'),
724 ];
725
726 $args = [
727 'headers' => $headers,
728 ];
729
730
731 if ($status === 'success') {
732 $url = $this->get_api_url("v1", 'import/success');
733 $args['body'] = json_encode(['type' => 'pack']);
734 $response = wp_remote_post($url, $args);
735 } elseif ($status === 'failed') {
736 $url = $this->get_api_url("v1", 'import/failed');
737 $args['body'] = json_encode(['type' => 'pack', 'description' => $description ?: "Something Went wrong....."]);
738 $response = wp_remote_post($url, $args);
739 }
740
741 Helper::log($response);
742
743 if (is_wp_error($response)) {
744 // Handle error
745 Helper::log($response->get_error_message());
746 } else {
747 // Handle success
748 $body = wp_remote_retrieve_body($response);
749 // Do something with $body
750 return $body;
751 }
752
753 return null;
754 }
755
756 protected function getConnectionStatusText() {
757 $status = connection_status();
758 switch ($status) {
759 case CONNECTION_NORMAL:
760 return "Normal";
761 case CONNECTION_ABORTED:
762 return "Aborted";
763 case CONNECTION_TIMEOUT:
764 return "Timeout";
765 default:
766 return "Unknown";
767 }
768 }
769
770 protected function get_post_type_label_by_slug($slug) {
771 $post_type_obj = get_post_type_object($slug);
772 if ($post_type_obj) {
773 return $post_type_obj->label;
774 }
775 return null;
776 }
777
778 public function import_info() {
779
780 $platform = isset($_GET['platform']) ? $_GET['platform'] : 'elementor';
781 $id = isset($_GET['id']) ? intval($_GET['id']) : 0;
782
783 $response = wp_remote_get($this->info_get_api_url($id), [
784 'timeout' => 30,
785 'headers' => [
786 'Authorization' => 'Bearer ' . $this->api_key,
787 'x-templately-ip' => Helper::get_ip(),
788 'x-templately-url' => home_url('/'),
789 'x-templately-version' => TEMPLATELY_VERSION,
790 ]
791 ]);
792
793 if (is_wp_error($response)) {
794 wp_send_json_error($response->get_error_message());
795 return;
796 }
797 // If the response code is not 200, return the error message
798 if (wp_remote_retrieve_response_code($response) != 200) {
799 wp_send_json_error(json_decode(wp_remote_retrieve_body($response)));
800 return;
801 }
802 // If the response body is JSON and it contains an error, return the error message
803 // Retrieve Data from Response Body.
804 $body = wp_remote_retrieve_body($response);
805 $data = json_decode($body, true);
806
807 if (isset($data['error'])) {
808 wp_send_json_error($data['error']);
809 return;
810 }
811
812 if (isset($data['data']['manifest'])) {
813 $data['data']['manifest'] = json_decode($data['data']['manifest'], true);
814 }
815 if (isset($data['data']['settings'])) {
816 $data['data']['settings'] = json_decode($data['data']['settings'], true);
817 }
818
819 // Return the response body
820 wp_send_json($data);
821 }
822
823 public function update_imported_list($type, $id) {
824 $imported_list = get_option('templately_fsi_imported_list', []);
825 $imported_list[$type][] = $id;
826 update_option('templately_fsi_imported_list', $imported_list);
827 }
828
829 /**
830 *
831 *
832 * @return void
833 */
834 protected function add_revert_hooks() {
835 add_action('wp_insert_post', function ($post_id) {
836 $this->update_imported_list('posts', $post_id);
837 });
838 add_action('add_attachment', function ($post_id) {
839 $this->update_imported_list('attachment', $post_id);
840 });
841 add_action('created_term', function ($term_id, $tt_id, $taxonomy, $args) {
842 $this->update_imported_list('term', [$term_id, $taxonomy]);
843 }, 10, 4);
844 add_action('registered_taxonomy', function ($taxonomy, $object_type, $taxonomy_object) {
845 $this->update_imported_list('taxonomy', $taxonomy);
846 }, 10, 3);
847 }
848
849 public static function has_revert(){
850 $options = Utils::get_backup_options();
851 $imported_list = get_option('templately_fsi_imported_list', []);
852 if(!empty($options) || !empty($imported_list)){
853 return true;
854 }
855 return false;
856 }
857
858 public function import_revert() {
859
860 // // Get the nonce value from the request (usually from $_POST or $_GET)
861 // $received_nonce = isset($_REQUEST['_wpnonce']) ? $_REQUEST['_wpnonce'] : '';
862
863 // // Verify the nonce using wp_verify_nonce()
864 // $verified = wp_verify_nonce($received_nonce, 'templately_pack_import_revert_nonce');
865
866 // if (!$verified) {
867 // wp_send_json_error("Nonce not verified.");
868 // }
869
870 $options_deleted = false;
871 $imported_list_deleted = false;
872 $options = Utils::get_backup_options();
873 $kits_manager = Plugin::$instance->kits_manager;
874 $status_args = [ 'post_type' => 'templately_library' ];
875 $all_post_url = admin_url(add_query_arg( $status_args, 'edit.php' ));
876 // wp_send_json_success([$options]);
877
878 $kit = $kits_manager->get_active_kit();
879 if ( ! $kit->get_id() ) {
880 $kit = $kits_manager->create_default();
881 update_option( $kits_manager::OPTION_ACTIVE, $kit );
882 }
883
884
885 if (!empty($options) && is_array($options)) {
886 foreach ($options as $key => $value) {
887 if ('stylesheet' === $key) {
888 if (get_option('stylesheet') !== $value) {
889 switch_theme($value);
890 }
891 } else {
892 update_option($key, $value);
893 }
894 delete_option("__templately_$key");
895 $options_deleted = true;
896 }
897 }
898
899 $imported_list = get_option('templately_fsi_imported_list', []);
900 if (!empty($imported_list) && is_array($imported_list)) {
901 $_GET['force_delete_kit'] = 1; // Fallback GET Ready!
902 foreach ($imported_list as $type => $list) {
903 if (empty($list) || !is_array($list)) {
904 continue;
905 }
906 // Loop through each item ID and delete it
907 foreach ($list as $key => $item_id) {
908 switch ($type) {
909 case 'posts':
910 // making sure default kit don't get deleted.
911 if(isset($options[$kits_manager::OPTION_ACTIVE]) && $options[$kits_manager::OPTION_ACTIVE] == $item_id){
912 break;
913 }
914 wp_delete_post($item_id, true); // Set true for permanent deletion
915 break;
916 case 'attachment':
917 wp_delete_attachment($item_id, true); // Set true for permanent deletion
918 break;
919 case 'term':
920 list($term_id, $taxonomy) = $item_id;
921 wp_delete_term($term_id, $taxonomy); // Use corresponding taxonomy
922 break;
923 case 'taxonomy':
924 // Taxonomies cannot be directly deleted. Consider de-registering it.
925 break;
926 }
927 }
928 }
929
930 $imported_list_deleted = true;
931 delete_option('templately_fsi_imported_list');
932 }
933
934
935 if($options_deleted || $imported_list_deleted){
936 sleep(5);
937 wp_send_json_success([ 'options' => $options_deleted, 'imported_list' => $imported_list_deleted, 'site_url' => home_url(), 'redirect' => $all_post_url ]);
938 }
939
940 wp_send_json_error([ 'options' => $options_deleted, 'imported_list' => $imported_list_deleted, 'site_url' => home_url() ]);
941 }
942
943 /**
944 * Adds "Import" button on module list page
945 */
946 public function add_revert_button() {
947 $screen = get_current_screen();
948 // Not our post type, exit earlier
949 // You can remove this if condition if you don't have any specific post type to restrict to.
950 if ('templately_library' != $screen->post_type) {
951 return;
952 }
953
954 // Generate a nonce with a unique action name for security
955 $revert_nonce = wp_create_nonce('templately_pack_import_revert_nonce');
956
957 // Build the URL with the nonce
958 $revert_url = add_query_arg('action', 'templately_pack_import_revert', admin_url('admin-ajax.php'));
959 $revert_url = add_query_arg('_wpnonce', $revert_nonce, $revert_url);
960 ?>
961
962 <div class="templately-fsi-revert-wrapper clearfix" style="clear: both; background: #fff; padding: 20px; display: none;">
963 <div class="templately-fsi-revert-notice__content">
964 <h3>Revert to previous website</h3>
965
966 <p>This usually takes a few moments. Please don’t close the window until the process in finished.</p>
967
968 <div class="templately-fsi-revert-notice__actions">
969 <a href="<?php echo $revert_url;?>" class="button"><span>Revert Now</span></a>
970 </div>
971 </div>
972 </div>
973 <?php
974 }
975 }
976