PluginProbe
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! / 3.2.4
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! v3.2.4
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.2.4, at includes/Core/Importer/FullSiteImport.php

1,139 lines 34.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * remove 'action' => 'continue',
5 * way to retry
6 * way to skip if failed multiple times
7 *
8 * @todo: on runner check for timeout and retry
9 * @todo: use ErrorException on runner to skip item when error occurs: not useful
10 *
11 */
12
13
14 namespace Templately\Core\Importer;
15
16 use Elementor\Plugin;
17 use Error;
18 use Exception;
19 use Templately\Core\Importer\Exception\NonRetryableErrorException;
20 use Templately\Core\Importer\Exception\RetryableErrorException;
21 use Templately\Core\Importer\Exception\UnknownErrorException;
22 use Templately\Core\Importer\Utils\LogHandler;
23 use Templately\Core\Importer\Utils\Utils;
24 use Templately\Utils\Base;
25 use Templately\Utils\Helper;
26 use Templately\Utils\Installer;
27 use Templately\Utils\Options;
28
29 class FullSiteImport extends Base {
30 use LogHelper;
31
32 const SESSION_OPTION_KEY = 'templately_import_session';
33 public $manifest;
34 protected $export;
35
36 private $version = '1.0.0';
37
38 public $download_key;
39 protected $dev_mode = false;
40 protected $api_key = '';
41 protected $session_id = '';
42 protected $documents_data = [];
43 protected $dependency_data = [];
44 private $is_import_status_handled = false;
45
46 public $dir_path;
47 protected $filePath;
48 protected $tmp_dir = null;
49 public $request_params = [];
50
51 public function __construct() {
52 $this->dev_mode = defined('TEMPLATELY_DEV') && TEMPLATELY_DEV;
53 $this->api_key = Options::get_instance()->get('api_key');
54
55 $this->add_ajax_action('import_settings', $this);
56 $this->add_ajax_action('import_status', $this);
57 $this->add_ajax_action('import', $this);
58 $this->add_ajax_action('import_revert', $this);
59 $this->add_ajax_action('import_info', $this);
60 $this->add_ajax_action('import_close_feedback_modal', $this);
61 $this->add_ajax_action('feedback_form', $this);
62 $this->add_ajax_action('google_font', $this);
63
64 add_action('admin_init', [$this, 'admin_init']);
65 // add_action('admin_notices', [$this, 'add_revert_button']);
66
67 if(isset($_GET['action']) && ($_GET['action'] == 'templately_pack_import' || $_GET['action'] == 'templately_pack_import_status')) {
68 add_filter('wp_redirect', '__return_false', 999);
69 }
70
71 if ($this->dev_mode) {
72 add_filter('http_request_host_is_external', '__return_true');
73 add_filter('http_request_args', function ($args) {
74 $args['sslverify'] = false;
75
76 return $args;
77 });
78 }
79 }
80
81 public function add_ajax_action($action, $object) {
82 add_action("wp_ajax_templately_pack_$action", function() use ($action, $object) {
83 // Check nonce
84 $nonce = null;
85 if(isset($_POST['nonce'])){
86 $nonce = $_POST['nonce'];
87 }
88 if(isset($_GET['nonce'])){
89 $nonce = $_GET['nonce'];
90 }
91 if (!$nonce || !wp_verify_nonce($nonce, 'templately_nonce')) {
92 wp_send_json_error(['message' => __('Invalid nonce', 'templately')]);
93 wp_die();
94 }
95
96 // Check user capability
97 if (!current_user_can('install_plugins') || !current_user_can('install_themes')) {
98 wp_send_json_error(['message' => __('Insufficient permissions', 'templately')]);
99 wp_die();
100 }
101
102 // Call the actual handler method
103 call_user_func([$object, $action]);
104 });
105 }
106
107 public function admin_init() {
108 if (get_option('templately_flush_rewrite_rules', false)) {
109 flush_rewrite_rules();
110 delete_option('templately_flush_rewrite_rules');
111 }
112 }
113
114 public function import_settings() {
115 $data = wp_unslash($_POST);
116
117 $upload_dir = wp_upload_dir();
118 $session_id = uniqid();
119 $tmp_dir = trailingslashit($upload_dir['basedir']) . 'templately' . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR;
120
121 $this->session_id = $session_id;
122 $data['session_id'] = $session_id;
123 $data['root_dir'] = $tmp_dir;
124 $data['dir_path'] = $tmp_dir . $session_id . DIRECTORY_SEPARATOR;
125 $data['zip_path'] = $tmp_dir . "{$session_id}.zip";
126
127
128 if ( is_array( $data ) && ! empty( $data ) ) {
129 foreach ( $data as $key => $value ) {
130 $json = is_string($value) ? json_decode( $value, true ) : null;
131 $data[ $key ] = $json !== null ? $json : $value;
132 }
133 }
134
135 Utils::update_session_data($session_id, $data);
136
137
138 //clear previous revert backup
139 $options = Utils::get_backup_options();
140 foreach ($options as $key => $value) {
141 delete_option("__templately_$key");
142 }
143 delete_option('templately_fsi_imported_list');
144 delete_option('templately_fsi_log');
145
146 wp_send_json_success([
147 'is_lightspeed' => !Helper::should_flush(),
148 'session_id' => $session_id,
149 ]);
150 }
151
152 public function import_close_feedback_modal() {
153 $return = null;
154 if(isset($_GET['closeAction']) && $_GET['closeAction']){
155 $review_email = isset($_POST['review-email']) ? sanitize_email($_POST['review-email']) : '';
156 $pack_id = get_user_meta(get_current_user_id(), 'templately_fsi_pack_id', true);
157
158 // Prepare the body of the request
159 $body = json_encode([
160 'action' => $_GET['closeAction'],
161 'email' => $review_email,
162 'pack_id' => (int) $pack_id,
163 ]);
164
165 // Send the request to the API
166 $response = wp_remote_post($this->get_api_url('v2', 'feedback/close'), [
167 'timeout' => 30,
168 'headers' => [
169 'Content-Type' => 'application/json',
170 'Authorization' => 'Bearer ' . $this->api_key,
171 'x-templately-ip' => Helper::get_ip(),
172 'x-templately-url' => home_url('/'),
173 'x-templately-version' => TEMPLATELY_VERSION,
174 ],
175 'body' => $body,
176 ]);
177 $body = wp_remote_retrieve_body($response);
178 $return = json_decode($body, true);
179 }
180 update_user_meta(get_current_user_id(), 'templately_fsi_complete', 'done');
181 wp_send_json_success($return);
182 }
183 public function feedback_form() {
184 // Get data from $_POST
185 $review_description = isset($_POST['review-description']) ? sanitize_textarea_field($_POST['review-description']) : '';
186 $review_email = isset($_POST['review-email']) ? sanitize_email($_POST['review-email']) : '';
187 $rating = isset($_POST['rating']) ? sanitize_text_field($_POST['rating']) : '';
188 $pack_id = get_user_meta(get_current_user_id(), 'templately_fsi_pack_id', true);
189
190 // Prepare the body of the request
191 $body = json_encode([
192 'description' => $review_description,
193 'email' => $review_email,
194 'rating' => (int) $rating,
195 'pack_id' => (int) $pack_id,
196 ]);
197
198 // Send the request to the API
199 $response = wp_remote_post($this->get_api_url('v2', 'feedback/store'), [
200 'timeout' => 30,
201 'headers' => [
202 'Content-Type' => 'application/json',
203 'Authorization' => 'Bearer ' . $this->api_key,
204 'x-templately-ip' => Helper::get_ip(),
205 'x-templately-url' => home_url('/'),
206 'x-templately-version' => TEMPLATELY_VERSION,
207 ],
208 'body' => $body,
209 ]);
210
211 if (is_wp_error($response)) {
212 wp_send_json_error($response->get_error_message());
213 }
214
215 if (wp_remote_retrieve_response_code($response) != 200 && wp_remote_retrieve_response_code($response) != 201) {
216 wp_send_json_error('API request failed with response code ' . wp_remote_retrieve_response_code($response), wp_remote_retrieve_response_code($response));
217 }
218
219 $body = wp_remote_retrieve_body($response);
220 $data = json_decode($body, true);
221
222 if (!isset($data['status']) || $data['status'] !== 'success') {
223 wp_send_json_error('API response indicates failure.');
224 }
225
226 if (!isset($data['message'])) {
227 wp_send_json_error('API response missing data.');
228 }
229
230 $result = $data['message'];
231
232 wp_send_json_success($result);
233 }
234
235 // Modified get_session_data to use the static version
236 protected function get_session_data() {
237 return Utils::get_session_data_by_id();
238 }
239
240 // Modified update_session_data to use the static version
241 protected function update_session_data($data) {
242 return Utils::update_session_data_by_id($data);
243 }
244
245 public function initialize_props() {
246 $data = $this->get_session_data();
247 if (isset($data['session_id'])) {
248 $this->session_id = $data['session_id'];
249 }
250 if (isset($data['dir_path'])) {
251 $this->dir_path = $data['dir_path'];
252 }
253 if (isset($data['zip_path'])) {
254 $this->filePath = $data['zip_path'];
255 }
256 if (isset($data['download_key'])) {
257 $this->download_key = $data['download_key'];
258 }
259 if (isset($data['dependency_data'])) {
260 $this->dependency_data = $data['dependency_data'];
261 }
262 }
263
264 private function clear_session_data(): bool {
265 return delete_site_option(self::SESSION_OPTION_KEY);
266 }
267
268 private function finishRequestHeaders() {
269 if(Helper::should_flush()) {
270 // Disable output buffering and compression
271 @ini_set('output_buffering', 'Off');
272 @ini_set('zlib.output_compression', 'Off');
273 @ini_set('implicit_flush', 1);
274
275 // Time to run the import! Set no limit
276 set_time_limit(0);
277
278
279 // Set headers to prevent caching and buffering
280 header('Content-Type: text/event-stream, charset=UTF-8');
281 header('Cache-Control: no-cache, must-revalidate');
282 header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
283 header('Connection: Keep-Alive');
284 header('Pragma: no-cache');
285
286 if (!empty($GLOBALS['is_nginx'])) {
287 header('X-Accel-Buffering: no');
288 header('Content-Encoding: none');
289 }
290
291 flush();
292 ob_flush();
293 wp_ob_end_flush_all();
294 } else {
295 header("Cache-Control: no-store, no-cache");
296 // header( 'Content-Type: text/event-stream, charset=UTF-8' );
297 // header( "Connection: Keep-Alive" );
298
299 // Ignore user aborts and allow the script to run forever
300 // (Use with caution, consider progress updates or timeouts)
301 ignore_user_abort(true);
302
303 // Time to run the import! Set no limit
304 set_time_limit(0);
305
306
307 if (!empty($GLOBALS['is_nginx'])) {
308 header('X-Accel-Buffering: no');
309 header('Content-Encoding: none');
310 }
311
312 // Send output as soon as possible during long-running process
313 if (function_exists('fastcgi_finish_request')) {
314 fastcgi_finish_request();
315 } elseif (function_exists('litespeed_finish_request')) {
316 litespeed_finish_request();
317 } else {
318 wp_ob_end_flush_all();
319 }
320 }
321 }
322
323 public function import() {
324 if ( ! $this->dev_mode && ! wp_doing_ajax() ) {
325 exit;
326 }
327
328
329
330 define('TEMPLATELY_START_TIME', microtime(true));
331
332 // delete_option( 'templately_fsi_log' );
333
334 register_shutdown_function( [ $this, 'register_shutdown' ] );
335
336 $this->finishRequestHeaders();
337
338 try {
339 // TODO: Need to check if user is connected or not
340 if(!empty($_GET['session_id'])){
341 $this->session_id = sanitize_text_field($_GET['session_id']);
342 }
343 else {
344 $this->throw(__('Invalid Session ID.', 'templately'));
345 }
346
347
348 $this->request_params = $this->get_session_data();
349 $this->initialize_props();
350 $this->add_revert_hooks();
351 $progress = $this->request_params['progress'] ?? [];
352
353 if(empty($progress['create_log_dir'])){
354 // Create Log Directory and if fail then chose option method
355 LogHandler::create_log_dir();
356
357 $progress['create_log_dir'] = true;
358 $this->update_session_data( [
359 'progress' => $progress,
360 ] );
361 $this->sse_message( [
362 'type' => 'eventLog',
363 'action' => 'eventLog',
364 'info' => 'create_log_dir',
365 'results' => __METHOD__ . '::' . __LINE__,
366 ] );
367 }
368
369 $_id = isset($this->request_params['id']) ? (int) $this->request_params['id'] : null;
370
371 if ($_id === null) {
372 $this->throw(__('Invalid Pack ID.', 'templately'));
373 }
374
375 $this->sse_message( [
376 'type' => 'start',
377 'action' => 'eventLog',
378 'results' => __METHOD__ . '::' . __LINE__,
379 ] );
380
381 if(empty($progress['download_zip'])){
382 /**
383 * Check Writing Permission
384 */
385 $this->check_writing_permission();
386
387 /**
388 * Download the zip
389 */
390 $this->download_zip( $_id );
391
392 $progress['download_zip'] = true;
393 $this->update_session_data( [
394 'progress' => $progress,
395 ] );
396 $this->sse_message( [
397 'type' => 'continue',
398 'action' => 'continue',
399 'info' => 'download_zip',
400 'results' => __METHOD__ . '::' . __LINE__,
401 ] );
402 exit;
403 }
404
405
406
407
408 // /**
409 // * Reading Manifest File
410 // */
411 // $this->read_manifest();
412
413 /**
414 * Version Check
415 */
416 if ( ! empty( $this->manifest['version'] ) && version_compare( $this->manifest['version'], $this->version, '>' ) ) {
417 /**
418 * FIXME: The message should be re-written (by content/support team).
419 */
420 $this->throw( __( 'Please update the templately plugin.', 'templately' ) );
421 }
422
423 $platform = $this->manifest['platform'] ?? '';
424 if($platform === 'elementor') {
425 Helper::enable_elementor_container();
426 }
427
428
429 /**
430 * Should Revert Old Data
431 */
432 // $this->revert();
433
434 /**
435 * Platform Based Templates Import
436 */
437 $this->start_content_import();
438
439 } catch ( Exception $e ) {
440 $should_retry = $e instanceof RetryableErrorException;
441 if(!$should_retry){
442 $this->handle_import_status('failed', $e->getMessage());
443 }
444
445 $this->sse_message([
446 'action' => 'error',
447 'status' => 'error',
448 'type' => "error",
449 'retry' => $should_retry,
450 'title' => __("Oops!", "templately"),
451 'message' => $e->getMessage(),
452 'trace' => $e->getTraceAsString(),
453 ]);
454 }
455
456 // if($_GET['part'] === 'import'){
457 // TODO: cleanup
458 // $this->clear_session_data();
459 // }
460 }
461
462 // Updated import_status method
463 public function import_status() {
464 $request_params = $this->get_session_data();
465
466 if (isset($request_params['log_type']) && $request_params['log_type'] == 'file') {
467 $log_index = isset($_GET['lastLogIndex']) ? (int) $_GET['lastLogIndex'] : 0;
468 $log = LogHandler::read_log_file($log_index);
469
470 wp_send_json(['count' => count($log), 'log' => $log]);
471 } else {
472 $log = get_option('templately_fsi_log');
473
474 if (!empty($log) && is_array($log) && isset($_GET['lastLogIndex'])) {
475 $lastLogIndex = (int) $_GET['lastLogIndex'];
476 $log = array_slice($log, $lastLogIndex);
477 }
478 wp_send_json(['count' => $log ? count($log) : 0, 'log' => $log]);
479 }
480 }
481
482 /**
483 * @throws Exception
484 */
485 private function throw($message, $code = 0) {
486 if ($this->dev_mode) {
487 error_log(print_r($message, 1));
488 }
489 throw new Exception($message);
490 }
491 /**
492 * @throws Exception
493 */
494 private function throw_non_retryable($message, $code = 0) {
495 if ($this->dev_mode) {
496 error_log(print_r($message, 1));
497 }
498 throw new NonRetryableErrorException($message);
499 }
500 /**
501 * @throws Exception
502 */
503 private function throw_retryable($message, $code = 0) {
504 if ($this->dev_mode) {
505 error_log(print_r($message, 1));
506 }
507 throw new RetryableErrorException($message);
508 }
509 /**
510 * @throws Exception
511 */
512 private function throw_unknown($message, $code = 0) {
513 if ($this->dev_mode) {
514 error_log(print_r($message, 1));
515 }
516 throw new UnknownErrorException($message);
517 }
518
519 /**
520 * @throws Exception
521 */
522 private function check_writing_permission() {
523 $upload_dir = wp_upload_dir();
524
525 if (!is_writable($upload_dir['basedir'])) {
526 $this->throw(__('Upload directory is not writable.', 'templately'));
527 }
528
529 $this->tmp_dir = trailingslashit($upload_dir['basedir']) . 'templately' . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR;
530
531 if (!is_dir($this->tmp_dir)) {
532 wp_mkdir_p($this->tmp_dir);
533 }
534
535 $this->sse_log('writing_permission_check', __('Permission Passed', 'templately'), 100);
536 }
537
538 private function get_api_url($version, $end_point): string {
539 return $this->dev_mode ? "https://app.templately.dev/api/$version/" . $end_point : "https://app.templately.com/api/$version/" . $end_point;
540 }
541
542 private function info_get_api_url($id): string {
543 return $this->dev_mode ? 'https://app.templately.dev/api/v1/import/info/pack/' . $id : 'https://app.templately.com/api/v1/import/info/pack/' . $id;
544 }
545
546 /**
547 * @throws Exception
548 */
549 private function download_zip( $id ) {
550 $this->sse_log( 'download', __( 'Downloading Template Pack', 'templately' ), 1 );
551 $response = wp_remote_get( $this->get_api_url( "v2", "import/pack/$id" ), [
552 'timeout' => 30,
553 'headers' => [
554 'Content-Type' => 'application/json',
555 'Authorization' => 'Bearer ' . $this->api_key,
556 'x-templately-ip' => Helper::get_ip(),
557 'x-templately-url' => home_url('/'),
558 'x-templately-version' => TEMPLATELY_VERSION,
559 ]
560 ]);
561
562 $response_code = wp_remote_retrieve_response_code($response);
563 $content_type = wp_remote_retrieve_header($response, 'content-type');
564 $this->download_key = wp_remote_retrieve_header($response, 'download-key');
565
566 if (is_wp_error($response)) {
567 $this->throw_retryable(__('Template pack download failed', 'templately') . $response->get_error_message());
568 } else if ($response_code != 200) {
569 if (strpos($content_type, 'application/json') !== false) {
570 // Retrieve Data from Response Body.
571 $response_body = json_decode(wp_remote_retrieve_body($response), true);
572
573 // If the response body is JSON and it contains an error, throw an exception with the error message
574 if (isset($response_body['status']) && $response_body['status'] === 'error') {
575 $support_message = '';
576 if(strpos($response_body['message'], 'https://wpdeveloper.com/support') === false){
577 $support_message = sprintf(__(" Please try again or contact <a href='%s' target='_blank'>support</a>.", "templately"), 'https://wpdeveloper.com/support');
578 }
579 $this->throw_non_retryable($response_body['message'] . $support_message);
580 }
581 }
582 $this->throw_unknown(__('Template pack download failed with response code: ', 'templately') . $response_code);
583 }
584
585 $this->sse_log('download', __('Downloading Template Pack', 'templately'), 57);
586
587 $this->update_session_data([
588 'download_key' => $this->download_key,
589 ]);
590
591 if (file_put_contents($this->filePath, $response['body'])) { // phpcs:ignore
592 $this->sse_log('download', __('Downloading Template Pack', 'templately'), 100);
593
594 $this->unzip();
595 } else {
596 $this->throw_retryable(__('Downloading Failed. Please try again', 'templately'));
597 }
598 }
599
600 /**
601 * @throws Exception
602 */
603 protected function unzip() {
604 if (!WP_Filesystem()) {
605 $this->throw(__('WP_Filesystem cannot be initialized', 'templately'));
606 }
607
608 $unzip = unzip_file($this->filePath, $this->dir_path);
609 if (is_wp_error($unzip)) {
610 $unzip = $this->unzip_file($this->filePath, $this->dir_path);
611 }
612
613 if (is_wp_error($unzip)) {
614 $error = $unzip->get_error_message();
615 if (empty($error)) {
616 // Generic error message
617 Helper::log($unzip);
618 $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');
619 $this->throw($error_message);
620 } else {
621 $this->throw($unzip->get_error_message());
622 }
623 }
624
625 if ($unzip) {
626 unlink($this->filePath);
627 }
628 }
629
630 /**
631 * Unzip a specified ZIP file to a location on the Filesystem.
632 *
633 * @param string $file Full path and filename of ZIP archive.
634 * @param string $to Full path on the filesystem to extract archive to.
635 * @return true|WP_Error True on success, WP_Error on failure.
636 */
637 function unzip_file($file, $to) {
638 try {
639 $zip = new \ZipArchive;
640
641 $res = $zip->open($file);
642 if ($res === TRUE) {
643 $zip->extractTo($to);
644 $zip->close();
645
646 return true;
647 }
648 } catch (\Throwable $th) {
649 return new \WP_Error('exception_caught', $th->getMessage());
650 }
651
652 if (isset($zip)) {
653 return new \WP_Error('zip_error_' . $zip->status, $zip->getStatusString());
654 } else {
655 return new \WP_Error('unknown_error', '');
656 }
657 }
658
659 /**
660 * @throws Exception
661 */
662 private function read_manifest($dir_path) {
663 $manifest_content = file_get_contents($dir_path . 'manifest.json');
664 if (empty($manifest_content)) {
665 $this->throw(__('Cannot be imported, as the manifest file is corrupted', 'templately'));
666 }
667
668 $manifest_content = json_decode($manifest_content, true);
669 $this->removeLog('temp');
670
671 return $manifest_content;
672 // TODO: Read & Broadcast the LOG for waiting list
673 // $this->sse_log( 'plugin', 'Installing required plugins', '--', 'updateLog', 'processing' );
674 // // $this->sse_log( 'extra-content', 'Import Extra Contents (i.e: Forms)', '--', 'updateLog', 'processing' );
675 // $this->sse_log( 'templates', 'Import Templates (i.e: Header, Footer etc)', '--', 'updateLog', 'processing' );
676 // // $this->sse_log( 'content', 'Import Pages, Posts etc', '--', 'updateLog', 'processing' );
677 // $this->sse_log( 'wp-content', 'Importing Pages, Posts, Navigation, etc', '--', 'updateLog', 'processing' );
678 // $this->sse_log( 'finalize', 'Finalizing Your Imports', '--', 'updateLog', 'processing' );
679 }
680
681 private function skipped_plugin(): bool {
682 return empty($this->request_params['plugins']) || !is_array($this->request_params['plugins']);
683 }
684
685
686 private function before_install_hook() {
687 // remove_all_actions( 'wp_loaded' );
688 // remove_all_actions( 'after_setup_theme' );
689 // remove_all_actions( 'plugins_loaded' );
690 // remove_all_actions( 'init' );
691
692 // making sure so that no redirection happens during plugin installation and hooks triggered bellow.
693 add_filter('wp_redirect', '__return_false', 999);
694 }
695
696 private function after_install_hook() {
697 // do_action( 'wp_loaded' );
698 // do_action( 'after_setup_theme' );
699 // do_action( 'plugins_loaded' );
700 // do_action( 'init' );
701 }
702
703 /**
704 * @throws Exception
705 */
706 private function start_content_import() {
707 add_filter('upload_mimes', array($this, 'allow_svg_upload'));
708 add_filter('elementor/files/allow_unfiltered_upload', '__return_true');
709
710 $request_params = $this->get_session_data();
711 $manifest = $this->read_manifest($request_params['dir_path']);
712
713 $import = new Import(array_merge($request_params, [
714 'origin' => $this,
715 'manifest' => $manifest,
716 ]));
717 $imported_data = $import->run();
718
719 $import_status = $this->handle_import_status('success');
720
721 update_option('templately_flush_rewrite_rules', true, false);
722
723 $this->sse_message([
724 'type' => 'complete',
725 'action' => 'complete',
726 'results' => $this->normalize_imported_data($imported_data)
727 ]);
728
729 update_user_meta(get_current_user_id(), 'templately_fsi_pack_id', $request_params["id"]);
730 if(!empty($import_status['hasFeedback'])){
731 update_user_meta(get_current_user_id(), 'templately_fsi_complete', 'done');
732 }
733 else{
734 update_user_meta(get_current_user_id(), 'templately_fsi_complete', true);
735 }
736 }
737
738 private function normalize_imported_data($data) {
739 $attachments = !empty($data['attachments']['succeed']) ? count($data['attachments']['succeed']) : 0;
740 $attachments_fail = !empty($data['attachments']['failed']) ? count($data['attachments']['failed']) : 0;
741 $attachments_errors = !empty($data['attachments_errors']) ? $data['attachments_errors'] : [];
742 $templates = !empty($data['templates']['succeed']) ? count($data['templates']['succeed']) : 0;
743 $template_types = !empty($data['templates']['template_types']) ? $data['templates']['template_types'] : [];
744
745 $post_types = [];
746 $content_templates = [];
747 if (!empty($data['content']) && is_array($data['content'])) {
748 foreach ($data['content'] as $type => $type_data) {
749 $content_templates[$type] = !empty($type_data['succeed']) ? count($type_data['succeed']) : 0;
750 $post_types[] = $this->get_post_type_label_by_slug($type);
751 }
752 }
753
754 $contents = [];
755 if (!empty($data['wp-content']) && is_array($data['wp-content'])) {
756 foreach ($data['wp-content'] as $type => $type_data) {
757 $contents[$type] = !empty($type_data['succeed']) ? count($type_data['succeed']) : 0;
758 if (!in_array($type, ['wp_navigation', 'nav_menu_item'])) {
759 $post_types[] = $this->get_post_type_label_by_slug($type);
760 }
761 }
762 }
763
764 Helper::log($data);
765
766 return [
767 'attachments' => $attachments,
768 'attachments_fail' => $attachments_fail,
769 'attachments_errors' => $attachments_errors,
770 'templates' => $templates,
771 'contents' => $content_templates,
772 'wp-content' => $contents,
773 'post_types' => $post_types,
774 'template_types' => $template_types,
775 'dependency_data' => $this->dependency_data,
776 ];
777 }
778
779 public function get_request_params() {
780 return $this->request_params;
781 }
782
783 private function revert() {
784 // $request = $this->get_request_params();
785 // if ( isset( $request['revert'] ) && $request['revert'] ) {
786 // // TODO: Implement the Revert Process.
787 // }
788 }
789
790 public function redirect_for_archives($link, $post_id) {
791 $archive_settings = get_option('templately_post_archive');
792 if (!empty($archive_settings) && intval($archive_settings['post_id']) === intval($post_id)) {
793 $link = str_replace($post_id, $archive_settings['archive_id'], $link);
794 }
795
796 return $link;
797 }
798
799 public function allow_svg_upload($mimes) {
800 // Allow SVG
801 $mimes['svg'] = 'image/svg+xml';
802 return $mimes;
803 }
804
805 public function register_shutdown() {
806 $status = connection_status();
807 $last_error = error_get_last();
808 if ($last_error && ($last_error['type'] === E_ERROR || $last_error['type'] === E_CORE_ERROR || $last_error['type'] === E_COMPILE_ERROR || $last_error['type'] === E_USER_ERROR)) {
809 if (!empty($last_error['message'])) {
810 $full_message = $last_error['message'];
811 // Extract the first line from the error message
812 $firstLine = strtok($full_message, "\n");
813
814 // Remove absolute paths by replacing the WordPress directory path with a placeholder
815 $error_message = str_replace(ABSPATH, 'ABSPATH/', $firstLine);
816 } else {
817 // Generic error message
818 $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');
819 }
820
821
822 $this->handle_import_status('failed', $error_message);
823 // Handle the error, e.g. log it or display a message to the user
824 $this->sse_message([
825 'action' => 'error',
826 'status' => 'error',
827 'type' => "error",
828 'retry' => true,
829 'title' => __("Oops!", "templately"),
830 'message' => $error_message,
831 // 'position' => 'plugin',
832 // 'progress' => '--',
833 ]);
834 }
835
836 $this->debug_log("Shutdown:.....");
837 $this->debug_log("connection_status: " . $this->getConnectionStatusText());
838 $this->debug_log($last_error);
839 }
840
841 public function handle_import_status($status, $description = '') {
842 if ($this->is_import_status_handled) {
843 Helper::log("Import status already handled: $status");
844 return null;
845 }
846 $this->is_import_status_handled = $status;
847
848 $download_key = $this->download_key;
849
850 $headers = [
851 'Content-Type' => 'application/json',
852 'Authorization' => 'Bearer ' . $this->api_key,
853 'download_key' => $download_key,
854 'download-key' => $download_key,
855 'x-templately-ip' => Helper::get_ip(),
856 'x-templately-url' => home_url('/'),
857 ];
858
859 $args = [
860 'headers' => $headers,
861 ];
862
863
864 if ($status === 'success') {
865 $url = $this->get_api_url("v1", 'import/success');
866 $args['body'] = json_encode(['type' => 'pack']);
867 $response = wp_remote_post($url, $args);
868 } elseif ($status === 'failed') {
869 $url = $this->get_api_url("v1", 'import/failed');
870 $args['body'] = json_encode(['type' => 'pack', 'description' => $description ?: "Something Went wrong....."]);
871 $response = wp_remote_post($url, $args);
872 }
873
874 Helper::log($response);
875
876 if (is_wp_error($response)) {
877 // Handle error
878 Helper::log($response->get_error_message());
879 } else {
880 // Handle success
881 $body = wp_remote_retrieve_body($response);
882 $data = json_decode($body, true);
883 // Do something with $body
884 return $data;
885 }
886
887 return null;
888 }
889
890 protected function getConnectionStatusText() {
891 $status = connection_status();
892 switch ($status) {
893 case CONNECTION_NORMAL:
894 return "Normal";
895 case CONNECTION_ABORTED:
896 return "Aborted";
897 case CONNECTION_TIMEOUT:
898 return "Timeout";
899 default:
900 return "Unknown";
901 }
902 }
903
904 protected function get_post_type_label_by_slug($slug) {
905 $post_type_obj = get_post_type_object($slug);
906 if ($post_type_obj) {
907 return $post_type_obj->label;
908 }
909 return null;
910 }
911
912 public function import_info() {
913
914 $platform = isset($_GET['platform']) ? $_GET['platform'] : 'elementor';
915 $id = isset($_GET['id']) ? intval($_GET['id']) : 0;
916
917 $response = wp_remote_get($this->info_get_api_url($id), [
918 'timeout' => 30,
919 'headers' => [
920 'Authorization' => 'Bearer ' . $this->api_key,
921 'x-templately-ip' => Helper::get_ip(),
922 'x-templately-url' => home_url('/'),
923 'x-templately-version' => TEMPLATELY_VERSION,
924 ]
925 ]);
926
927 if (is_wp_error($response)) {
928 wp_send_json_error($response->get_error_message());
929 return;
930 }
931 // If the response code is not 200, return the error message
932 if (wp_remote_retrieve_response_code($response) != 200) {
933 wp_send_json_error(json_decode(wp_remote_retrieve_body($response)), wp_remote_retrieve_response_code($response));
934 return;
935 }
936 // If the response body is JSON and it contains an error, return the error message
937 // Retrieve Data from Response Body.
938 $body = wp_remote_retrieve_body($response);
939 $data = json_decode($body, true);
940
941 if (isset($data['error'])) {
942 wp_send_json_error($data['error']);
943 return;
944 }
945
946 if (isset($data['data']['manifest'])) {
947 $data['data']['manifest'] = json_decode($data['data']['manifest'], true);
948 }
949 if (isset($data['data']['settings'])) {
950 $data['data']['settings'] = json_decode($data['data']['settings'], true);
951 }
952
953 // Return the response body
954 wp_send_json($data);
955 }
956
957 public function update_imported_list($type, $id) {
958 $imported_list = get_option('templately_fsi_imported_list', []);
959 $imported_list[$type][] = $id;
960 update_option('templately_fsi_imported_list', $imported_list);
961 }
962
963 /**
964 *
965 *
966 * @return void
967 */
968 protected function add_revert_hooks() {
969 add_action('wp_insert_post', function ($post_id) {
970 $this->update_imported_list('posts', $post_id);
971 });
972 add_action('add_attachment', function ($post_id) {
973 $this->update_imported_list('attachment', $post_id);
974 });
975 add_action('created_term', function ($term_id, $tt_id, $taxonomy, $args) {
976 $this->update_imported_list('term', [$term_id, $taxonomy]);
977 }, 10, 4);
978 add_action('registered_taxonomy', function ($taxonomy, $object_type, $taxonomy_object) {
979 $this->update_imported_list('taxonomy', $taxonomy);
980 }, 10, 3);
981 add_action('fluentform/form_imported', function ($formId){
982 $this->update_imported_list('fluentform', $formId);
983 }, 10, 1);
984 }
985
986 public static function has_revert(){
987 $options = Utils::get_backup_options();
988 $imported_list = get_option('templately_fsi_imported_list', []);
989 if(!empty($options) || !empty($imported_list)){
990 return true;
991 }
992 return false;
993 }
994
995 public function import_revert() {
996
997 // // Get the nonce value from the request (usually from $_POST or $_GET)
998 // $received_nonce = isset($_REQUEST['_wpnonce']) ? $_REQUEST['_wpnonce'] : '';
999
1000 // // Verify the nonce using wp_verify_nonce()
1001 // $verified = wp_verify_nonce($received_nonce, 'templately_pack_import_revert_nonce');
1002
1003 // if (!$verified) {
1004 // wp_send_json_error("Nonce not verified.");
1005 // }
1006
1007 $option_active = null;
1008 $options_deleted = false;
1009 $imported_list_deleted = false;
1010 $options = Utils::get_backup_options();
1011 $status_args = [ 'post_type' => 'templately_library' ];
1012 $all_post_url = admin_url(add_query_arg( $status_args, 'edit.php' ));
1013 // wp_send_json_success([$options]);
1014
1015 if(class_exists('Elementor\Plugin')){
1016 $kits_manager = Plugin::$instance->kits_manager;
1017 $option_active = $kits_manager::OPTION_ACTIVE;
1018 $kit = $kits_manager->get_active_kit();
1019
1020 if ( ! $kit->get_id() ) {
1021 $kit = $kits_manager->create_default();
1022 update_option( $kits_manager::OPTION_ACTIVE, $kit );
1023 }
1024 }
1025
1026
1027 if (!empty($options) && is_array($options)) {
1028 foreach ($options as $key => $value) {
1029 if ('stylesheet' === $key) {
1030 if (get_option('stylesheet') !== $value) {
1031 switch_theme($value);
1032 }
1033 } else if($option_active === $key && class_exists('Elementor\Plugin')) {
1034 $kits_manager->revert( (int) $kits_manager->get_active_id(), (int) $value, 0 );
1035 $kit = $kits_manager->get_active_kit();
1036 $settings = $kit->get_data('settings');
1037 if ( isset( $settings['site_logo'] ) ) {
1038 set_theme_mod( 'custom_logo', $settings['site_logo']['id'] );
1039 }
1040 } else {
1041 update_option($key, $value);
1042 }
1043 delete_option("__templately_$key");
1044 $options_deleted = true;
1045 }
1046 }
1047
1048 $imported_list = get_option('templately_fsi_imported_list', []);
1049 if (!empty($imported_list) && is_array($imported_list)) {
1050 $_GET['force_delete_kit'] = 1; // Fallback GET Ready!
1051 foreach ($imported_list as $type => $list) {
1052 if (empty($list) || !is_array($list)) {
1053 continue;
1054 }
1055 // Loop through each item ID and delete it
1056 foreach ($list as $key => $item_id) {
1057 switch ($type) {
1058 case 'posts':
1059 // making sure default kit don't get deleted.
1060 if($option_active && isset($options[$option_active]) && $options[$option_active] == $item_id){
1061 break;
1062 }
1063 wp_delete_post($item_id, true); // Set true for permanent deletion
1064 break;
1065 case 'attachment':
1066 wp_delete_attachment($item_id, true); // Set true for permanent deletion
1067 break;
1068 case 'term':
1069 list($term_id, $taxonomy) = $item_id;
1070 wp_delete_term($term_id, $taxonomy); // Use corresponding taxonomy
1071 break;
1072 case 'taxonomy':
1073 // Taxonomies cannot be directly deleted. Consider de-registering it.
1074 break;
1075 case 'fluentform':
1076 if(class_exists('\FluentForm\App\Models\Form')){
1077 \FluentForm\App\Models\Form::remove($item_id);
1078 }
1079 break;
1080 }
1081 }
1082 }
1083
1084 $imported_list_deleted = true;
1085 delete_option('templately_fsi_imported_list');
1086 }
1087
1088
1089 if($options_deleted || $imported_list_deleted){
1090 sleep(5);
1091 wp_send_json_success([ 'options' => $options_deleted, 'imported_list' => $imported_list_deleted, 'site_url' => home_url(), 'redirect' => $all_post_url ]);
1092 }
1093
1094 wp_send_json_error([ 'options' => $options_deleted, 'imported_list' => $imported_list_deleted, 'site_url' => home_url() ]);
1095 }
1096
1097 public function google_font() {
1098 $result = get_transient('templately-google-fonts');
1099
1100 if (false == $result) {
1101 $response = wp_remote_get($this->get_api_url('v2', 'google-font'), [
1102 'timeout' => 30,
1103 'headers' => [
1104 'Authorization' => 'Bearer ' . $this->api_key,
1105 'x-templately-ip' => Helper::get_ip(),
1106 'x-templately-url' => home_url( '/' ),
1107 'x-templately-version' => TEMPLATELY_VERSION,
1108 ]
1109 ]);
1110
1111 if (is_wp_error($response)) {
1112 wp_send_json_error($response->get_error_message());
1113 }
1114
1115 if (wp_remote_retrieve_response_code($response) != 200) {
1116 wp_send_json_error('API request failed with response code ' . wp_remote_retrieve_response_code($response), wp_remote_retrieve_response_code($response));
1117 }
1118
1119 $body = wp_remote_retrieve_body($response);
1120 $data = json_decode($body, true);
1121
1122 if (!isset($data['status']) || $data['status'] !== 'success') {
1123 wp_send_json_error('API response indicates failure.');
1124 }
1125
1126 if (!isset($data['data'])) {
1127 wp_send_json_error('API response missing data.');
1128 }
1129
1130 $result = $data['data'];
1131 set_transient('templately-google-fonts', $result, DAY_IN_SECONDS);
1132 }
1133
1134 wp_send_json_success($result);
1135 }
1136
1137
1138 }
1139