dev_mode = defined('TEMPLATELY_DEV') && TEMPLATELY_DEV; $this->api_key = Options::get_instance()->get('api_key'); $this->add_ajax_action('import_settings', $this); $this->add_ajax_action('import_status', $this); $this->add_ajax_action('import', $this); $this->add_ajax_action('import_revert', $this); $this->add_ajax_action('import_info', $this); $this->add_ajax_action('import_close_feedback_modal', $this); $this->add_ajax_action('feedback_form', $this); $this->add_ajax_action('google_font', $this); add_action('admin_init', [$this, 'admin_init']); // add_action('admin_notices', [$this, 'add_revert_button']); if(isset($_GET['action']) && ($_GET['action'] == 'templately_pack_import' || $_GET['action'] == 'templately_pack_import_status')) { add_filter('wp_redirect', '__return_false', 999); } if ($this->dev_mode) { add_filter('http_request_host_is_external', '__return_true'); add_filter('http_request_args', function ($args) { $args['sslverify'] = false; return $args; }); } } public function add_ajax_action($action, $object) { add_action("wp_ajax_templately_pack_$action", function() use ($action, $object) { // Check nonce $nonce = null; if(isset($_POST['nonce'])){ $nonce = $_POST['nonce']; } if(isset($_GET['nonce'])){ $nonce = $_GET['nonce']; } if (!$nonce || !wp_verify_nonce($nonce, 'templately_nonce')) { wp_send_json_error(['message' => __('Invalid nonce', 'templately')]); wp_die(); } // Check user capability if (!current_user_can('install_plugins') || !current_user_can('install_themes')) { wp_send_json_error(['message' => __('Insufficient permissions', 'templately')]); wp_die(); } // Call the actual handler method call_user_func([$object, $action]); }); } public function admin_init() { if (get_option('templately_flush_rewrite_rules', false)) { flush_rewrite_rules(); delete_option('templately_flush_rewrite_rules'); } } public function import_settings() { $data = wp_unslash($_POST); update_option(self::SESSION_OPTION_KEY, $data); delete_option('templately_fsi_imported_list'); delete_option('templately_fsi_log'); wp_send_json_success([ 'is_lightspeed' => !Helper::should_flush(), ]); } public function import_close_feedback_modal() { $return = null; if(isset($_GET['closeAction']) && $_GET['closeAction']){ $review_email = isset($_POST['review-email']) ? sanitize_email($_POST['review-email']) : ''; $pack_id = get_user_meta(get_current_user_id(), 'templately_fsi_pack_id', true); // Prepare the body of the request $body = json_encode([ 'action' => $_GET['closeAction'], 'email' => $review_email, 'pack_id' => (int) $pack_id, ]); // Send the request to the API $response = wp_remote_post($this->get_api_url('v2', 'feedback/close'), [ 'timeout' => 30, 'headers' => [ 'Content-Type' => 'application/json', 'Authorization' => 'Bearer ' . $this->api_key, 'x-templately-ip' => Helper::get_ip(), 'x-templately-url' => home_url('/'), 'x-templately-version' => TEMPLATELY_VERSION, ], 'body' => $body, ]); $body = wp_remote_retrieve_body($response); $return = json_decode($body, true); } update_user_meta(get_current_user_id(), 'templately_fsi_complete', 'done'); wp_send_json_success($return); } public function feedback_form() { // Get data from $_POST $review_description = isset($_POST['review-description']) ? sanitize_textarea_field($_POST['review-description']) : ''; $review_email = isset($_POST['review-email']) ? sanitize_email($_POST['review-email']) : ''; $rating = isset($_POST['rating']) ? sanitize_text_field($_POST['rating']) : ''; $pack_id = get_user_meta(get_current_user_id(), 'templately_fsi_pack_id', true); // Prepare the body of the request $body = json_encode([ 'description' => $review_description, 'email' => $review_email, 'rating' => (int) $rating, 'pack_id' => (int) $pack_id, ]); // Send the request to the API $response = wp_remote_post($this->get_api_url('v2', 'feedback/store'), [ 'timeout' => 30, 'headers' => [ 'Content-Type' => 'application/json', 'Authorization' => 'Bearer ' . $this->api_key, 'x-templately-ip' => Helper::get_ip(), 'x-templately-url' => home_url('/'), 'x-templately-version' => TEMPLATELY_VERSION, ], 'body' => $body, ]); if (is_wp_error($response)) { wp_send_json_error($response->get_error_message()); } if (wp_remote_retrieve_response_code($response) != 200 && wp_remote_retrieve_response_code($response) != 201) { wp_send_json_error('API request failed with response code ' . wp_remote_retrieve_response_code($response)); } $body = wp_remote_retrieve_body($response); $data = json_decode($body, true); if (!isset($data['status']) || $data['status'] !== 'success') { wp_send_json_error('API response indicates failure.'); } if (!isset($data['message'])) { wp_send_json_error('API response missing data.'); } $result = $data['message']; wp_send_json_success($result); } private function update_session_data($data): bool { $old_data = $this->get_session_data(); return update_option(self::SESSION_OPTION_KEY, wp_parse_args($data, $old_data)); } protected function CallingFunctionName($id = null) { $return = 'unknown'; $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3); // Check if the trace has at least three elements if (isset($trace[2])) { $final_call = $trace[2]; // Check if 'class' and 'function' indexes exist if (isset($final_call['class']) && isset($final_call['function'])) { $return = "{$final_call['class']}::{$final_call['function']}"; } else if(isset($final_call['function'])){ $return = $final_call['function']; } if(!empty($id)){ $return .= "::$id"; } } // Return a default value if 'class' or 'function' index does not exist, or if the trace doesn't have at least three elements return $return; } public function get_progress($defaults = [], $unique_id = null) { $calling_class = $this->CallingFunctionName($unique_id); if(isset($this->request_params['progress'][$calling_class])){ return $this->request_params['progress'][$calling_class]; } return $defaults; } public function update_progress( $progress, $imported_data = null, $unique_id = null ): bool { $calling_class = $this->CallingFunctionName($unique_id); $old_data = $this->get_session_data(); $new_data = []; if($progress !== null){ $new_data['progress'] = [$calling_class => $progress]; } if($imported_data !== null){ $new_data['imported_data'] = $imported_data; } $this->request_params = $this->recursive_wp_parse_args( $new_data, $old_data ); return update_option( self::SESSION_OPTION_KEY, $this->request_params ); } public function recursive_wp_parse_args( $args, $defaults ) { $args = (array) $args; $defaults = (array) $defaults; $r = $defaults; foreach ( $args as $key => $value ) { if ( is_array( $value ) && isset( $r[ $key ] ) ) { $r[ $key ] = $this->recursive_wp_parse_args( $value, $r[ $key ] ); } else { $r[ $key ] = $value; } } return $r; } public function get_session_data(): array { $data = get_option(self::SESSION_OPTION_KEY, []); $options = []; if ( is_array( $data ) && ! empty( $data ) ) { foreach ( $data as $key => $value ) { $json = is_string($value) ? json_decode( $value, true ) : null; $options[ $key ] = $json !== null ? $json : $value; } } return $options; } public function initialize_props() { $data = $this->get_session_data(); if (isset($data['session_id'])) { $this->session_id = $data['session_id']; } if (isset($data['dir_path'])) { $this->dir_path = $data['dir_path']; } if (isset($data['download_key'])) { $this->download_key = $data['download_key']; } if (isset($data['dependency_data'])) { $this->dependency_data = $data['dependency_data']; } } private function clear_session_data(): bool { return delete_site_option(self::SESSION_OPTION_KEY); } private function finishRequestHeaders() { header( "Cache-Control: no-store, no-cache" ); // header( 'Content-Type: text/event-stream, charset=UTF-8' ); // header( "Connection: Keep-Alive" ); // Ignore user aborts and allow the script to run forever // (Use with caution, consider progress updates or timeouts) ignore_user_abort(true); // Time to run the import! Set no limit set_time_limit(0); if ( !empty($GLOBALS['is_nginx']) ) { header( 'X-Accel-Buffering: no' ); header( 'Content-Encoding: none' ); } // Send output as soon as possible during long-running process if (function_exists('fastcgi_finish_request')) { fastcgi_finish_request(); } elseif (function_exists('litespeed_finish_request')) { litespeed_finish_request(); } else { wp_ob_end_flush_all(); } } public function import() { if ( ! $this->dev_mode && ! wp_doing_ajax() ) { exit; } // delete_option( 'templately_fsi_log' ); $this->sse_message( [ 'type' => 'start', 'action' => 'eventLog', 'results' => __METHOD__ . '::' . __LINE__, ] ); register_shutdown_function( [ $this, 'register_shutdown' ] ); $this->finishRequestHeaders(); try { // TODO: Need to check if user is connected or not $this->request_params = $this->get_session_data(); $this->initialize_props(); $this->add_revert_hooks(); $progress = $this->request_params['progress'] ?? []; $_id = isset($this->request_params['id']) ? (int) $this->request_params['id'] : null; if ($_id === null) { $this->throw(__('Invalid Pack ID.', 'templately')); } if(empty($progress['download_zip'])){ //clear previous revert backup $options = Utils::get_backup_options(); foreach ($options as $key => $value) { delete_option("__templately_$key"); } /** * Check Writing Permission */ $this->check_writing_permission(); /** * Download the zip */ $this->download_zip( $_id ); $progress['download_zip'] = true; $this->update_session_data( [ 'progress' => $progress, ] ); $this->sse_message( [ 'type' => 'continue', 'action' => 'continue', 'info' => 'download_zip', 'results' => __METHOD__ . '::' . __LINE__, ] ); exit; } if(empty($progress['download_dependencies'])){ /** * Checking & Installing Plugin Dependencies */ $this->install_dependencies(); $progress['download_dependencies'] = true; $this->update_session_data( [ 'progress' => $progress, ] ); $this->sse_message( [ 'type' => 'continue', 'action' => 'continue', 'results' => 'download_dependencies', ] ); exit; } /** * Reading Manifest File */ $this->read_manifest(); /** * Version Check */ if ( ! empty( $this->manifest['version'] ) && version_compare( $this->manifest['version'], $this->version, '>' ) ) { /** * FIXME: The message should be re-written (by content/support team). */ $this->throw( __( 'Please update the templately plugin.', 'templately' ) ); } /** * Should Revert Old Data */ // $this->revert(); /** * Platform Based Templates Import */ $this->start_content_import(); } catch ( Exception $e ) { $this->handle_import_status('failed', $e->getMessage()); $this->sse_message([ 'action' => 'error', 'status' => 'error', 'type' => "error", 'title' => __("Oops!", "templately"), 'message' => $e->getMessage() ]); } // if($_GET['part'] === 'import'){ // TODO: cleanup // $this->clear_session_data(); // } } public function import_status(){ $log = get_option( 'templately_fsi_log' ); if(!empty($log) && is_array($log) && isset($_GET['lastLogIndex'])){ $lastLogIndex = (int) $_GET['lastLogIndex']; $log = array_slice($log, $lastLogIndex); } wp_send_json( ['count' => $log ? count($log) : 0, 'log' => $log] ); } /** * @throws Exception */ private function throw($message, $code = 0) { if ($this->dev_mode) { error_log(print_r($message, 1)); } throw new Exception($message); } /** * @throws Exception */ private function check_writing_permission() { $upload_dir = wp_upload_dir(); if (!is_writable($upload_dir['basedir'])) { $this->throw(__('Upload directory is not writable.', 'templately')); } $this->tmp_dir = trailingslashit($upload_dir['basedir']) . 'templately' . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR; if (!is_dir($this->tmp_dir)) { wp_mkdir_p($this->tmp_dir); } $this->sse_log('writing_permission_check', __('Permission Passed', 'templately'), 100); } private function get_api_url($version, $end_point): string { return $this->dev_mode ? "https://app.templately.dev/api/$version/" . $end_point : "https://app.templately.com/api/$version/" . $end_point; } private function info_get_api_url($id): string { return $this->dev_mode ? 'https://app.templately.dev/api/v1/import/info/pack/' . $id : 'https://app.templately.com/api/v1/import/info/pack/' . $id; } /** * @throws Exception */ private function download_zip( $id ) { $this->sse_log( 'download', __( 'Downloading Template Pack', 'templately' ), 1 ); $response = wp_remote_get( $this->get_api_url( "v2", "import/pack/$id" ), [ 'timeout' => 30, 'headers' => [ 'Content-Type' => 'application/json', 'Authorization' => 'Bearer ' . $this->api_key, 'x-templately-ip' => Helper::get_ip(), 'x-templately-url' => home_url('/'), 'x-templately-version' => TEMPLATELY_VERSION, ] ]); $response_code = wp_remote_retrieve_response_code($response); $content_type = wp_remote_retrieve_header($response, 'content-type'); $this->download_key = wp_remote_retrieve_header($response, 'download-key'); if (is_wp_error($response)) { $this->throw(__('Template pack download failed', 'templately') . $response->get_error_message()); } else if ($response_code != 200) { if (strpos($content_type, 'application/json') !== false) { // Retrieve Data from Response Body. $response_body = json_decode(wp_remote_retrieve_body($response), true); // If the response body is JSON and it contains an error, throw an exception with the error message if (isset($response_body['status']) && $response_body['status'] === 'error') { $this->throw($response_body['message']); } } $this->throw(__('Template pack download failed with response code: ', 'templately') . $response_code); } $this->sse_log('download', __('Template is getting ready', 'templately'), 57); $session_id = uniqid(); $this->dir_path = $this->tmp_dir . $session_id . DIRECTORY_SEPARATOR; $this->filePath = $this->tmp_dir . "{$session_id}.zip"; $this->session_id = $session_id; $this->update_session_data([ 'session_id' => $this->session_id, 'dir_path' => $this->dir_path, 'download_key' => $this->download_key, ]); if (file_put_contents($this->filePath, $response['body'])) { // phpcs:ignore $this->sse_log('download', __('Template is getting ready', 'templately'), 100); $this->unzip(); } else { $this->throw(__('Downloading Failed. Please try again', 'templately')); } } /** * @throws Exception */ protected function unzip() { if (!WP_Filesystem()) { $this->throw(__('WP_Filesystem cannot be initialized', 'templately')); } $unzip = unzip_file($this->filePath, $this->dir_path); if (is_wp_error($unzip)) { $unzip = $this->unzip_file($this->filePath, $this->dir_path); } if (is_wp_error($unzip)) { $error = $unzip->get_error_message(); if (empty($error)) { // Generic error message Helper::log($unzip); $error_message = sprintf(__("It seems we're experiencing technical difficulties. Please try again or contact support.", "templately"), 'https://wpdeveloper.com/support'); $this->throw($error_message); } else { $this->throw($unzip->get_error_message()); } } if ($unzip) { unlink($this->filePath); } } /** * Unzip a specified ZIP file to a location on the Filesystem. * * @param string $file Full path and filename of ZIP archive. * @param string $to Full path on the filesystem to extract archive to. * @return true|WP_Error True on success, WP_Error on failure. */ function unzip_file($file, $to) { try { $zip = new \ZipArchive; $res = $zip->open($file); if ($res === TRUE) { $zip->extractTo($to); $zip->close(); return true; } } catch (\Throwable $th) { return new \WP_Error('exception_caught', $th->getMessage()); } if (isset($zip)) { return new \WP_Error('zip_error_' . $zip->status, $zip->getStatusString()); } else { return new \WP_Error('unknown_error', ''); } } /** * @throws Exception */ private function read_manifest() { $manifest_content = file_get_contents($this->dir_path . DIRECTORY_SEPARATOR . 'manifest.json'); if (empty($manifest_content)) { $this->throw(__('Cannot be imported, as the manifest file is corrupted', 'templately')); } $this->manifest = json_decode($manifest_content, true); $this->removeLog('temp'); // TODO: Read & Broadcast the LOG for waiting list // $this->sse_log( 'plugin', 'Installing required plugins', '--', 'updateLog', 'processing' ); // // $this->sse_log( 'extra-content', 'Import Extra Contents (i.e: Forms)', '--', 'updateLog', 'processing' ); // $this->sse_log( 'templates', 'Import Templates (i.e: Header, Footer etc)', '--', 'updateLog', 'processing' ); // // $this->sse_log( 'content', 'Import Pages, Posts etc', '--', 'updateLog', 'processing' ); // $this->sse_log( 'wp-content', 'Importing Pages, Posts, Navigation, etc', '--', 'updateLog', 'processing' ); // $this->sse_log( 'finalize', 'Finalizing Your Imports', '--', 'updateLog', 'processing' ); } private function skipped_plugin(): bool { return empty($this->request_params['plugins']) || !is_array($this->request_params['plugins']); } private function install_dependencies() { $progress = $this->request_params['progress'] ?? []; if ( empty($progress['theme_dependency']) && ! empty( $this->request_params['theme'] ) && is_array( $this->request_params['theme'] ) ) { // activate theme $theme = $this->request_params['theme']; // $this->before_install_hook(); if (isset($theme['stylesheet'])) { // do_action('before_theme_activation', $theme); // Trigger action before theme activation $this->sse_log('theme', 'Installing and activating theme: ' . $theme['name'], 0); if (!get_option("__templately_stylesheet")) { $stylesheet = get_option('stylesheet'); add_option("__templately_stylesheet", $stylesheet, '', 'no'); } $plugin_status = Installer::get_instance()->install_and_activate_theme($theme['stylesheet']); if (!$plugin_status['success']) { $this->sse_message([ 'action' => 'updateLog', 'status' => 'error', 'message' => "Failed to activate theme: " . $theme['name'], 'type' => "theme", 'progress' => 0 ]); $this->dependency_data['theme'] = [ 'success' => false, 'name' => $theme['name'], 'slug' => $theme['stylesheet'], 'message' => $plugin_status['message'] ?? '' ]; $this->update_session_data( [ 'dependency_data' => $this->dependency_data, ] ); } else { // do_action('after_theme_activation', $theme); // Trigger action after theme activation $this->sse_message([ 'action' => 'updateLog', 'status' => 'complete', 'message' => "Activated theme: " . $theme['name'], 'type' => "theme", 'progress' => 100 ]); $this->dependency_data['theme'] = [ 'success' => true, 'name' => $theme['name'], 'slug' => $theme['stylesheet'], 'message' => $plugin_status['message'] ?? '' ]; $this->update_session_data( [ 'dependency_data' => $this->dependency_data, ] ); $progress['theme_dependency'] = true; $this->update_session_data( [ 'progress' => $progress, ] ); } // If it's not the last item, send the SSE message and exit $this->sse_message( [ 'type' => 'continue', 'action' => 'continue', 'results' => __METHOD__ . '::' . __LINE__, ] ); exit; } // $this->after_install_hook(); } else if(empty($progress['theme_dependency'])) { $this->removeLog( 'theme' ); } if ( ! empty( $this->request_params['plugins'] ) && is_array( $this->request_params['plugins'] ) ) { // $this->sse_log( 'plugin', 'Installing Plugins', 1 ); $total_plugin = count($this->request_params['plugins']); // $total_plugin_installed = $total_plugin; $_installed_plugins = $this->dependency_data['_installed_plugins'] ?? 0; $progress['plugin_dependency'] = $progress['plugin_dependency'] ?? []; // $this->before_install_hook(); foreach ( $this->request_params['plugins'] as $dependency ) { if(in_array($dependency['plugin_original_slug'], $progress['plugin_dependency'])){ continue; } $_dependency = $dependency; $this->sse_log( 'plugin', 'Installing required plugins: ' . $dependency['name'], floor( ( 100 * $_installed_plugins / $total_plugin ) ) ); $dependency['slug'] = $dependency['plugin_original_slug']; $plugin_status = Installer::get_instance()->install($dependency); if (!$plugin_status['success']) { $this->sse_message([ 'position' => 'plugin', 'action' => 'updateLog', 'status' => 'error', 'message' => 'Installation Failed: ' . $dependency['name'] . ' (' . ($plugin_status['message'] ?? '') . ')', 'type' => "plugin_{$dependency['plugin_original_slug']}", 'progress' => 0 ]); if (isset($dependency['mustHave']) && $dependency['mustHave']) { $this->removeLog('plugin'); $this->throw('Installation Failed: ' . $dependency['name'] . ' (' . ($plugin_status['message'] ?? '') . ')'); } $this->dependency_data['plugins']['failed'][] = [ 'name' => $dependency['name'], 'slug' => $dependency['slug'], 'link' => $dependency['link'], 'message' => $plugin_status['message'] ?? '' ]; } else { $_installed_plugins++; // $total_plugin_installed--; $this->dependency_data['_installed_plugins'] = $_installed_plugins; } $this->update_session_data( [ 'dependency_data' => $this->dependency_data, ] ); $progress['plugin_dependency'][] = $dependency['slug']; $this->update_session_data( [ 'progress' => $progress, ] ); // If it's not the last item, send the SSE message and exit if( end($this->request_params['plugins']) !== $_dependency ) { $this->sse_message( [ 'type' => 'continue', 'action' => 'continue', 'results' => __METHOD__ . '::' . __LINE__, ] ); exit; } } // $this->after_install_hook(); $this->sse_message([ 'action' => 'updateLog', 'status' => 'complete', 'message' => "Installed required plugins ($_installed_plugins/$total_plugin)", 'type' => "plugin", 'progress' => 100 ]); $this->dependency_data['plugins']['total'] = $total_plugin; $this->dependency_data['plugins']['succeed'] = $_installed_plugins; } else { $this->removeLog('plugin'); } $this->update_session_data([ 'dependency_data' => json_encode($this->dependency_data), ]); // $this->sse_log( 'plugin', 'Skipped Installing Plugins', '--', 'updateLog', 'skipped' ); } private function before_install_hook() { // remove_all_actions( 'wp_loaded' ); // remove_all_actions( 'after_setup_theme' ); // remove_all_actions( 'plugins_loaded' ); // remove_all_actions( 'init' ); // making sure so that no redirection happens during plugin installation and hooks triggered bellow. add_filter('wp_redirect', '__return_false', 999); } private function after_install_hook() { // do_action( 'wp_loaded' ); // do_action( 'after_setup_theme' ); // do_action( 'plugins_loaded' ); // do_action( 'init' ); } /** * @throws Exception */ private function start_content_import() { add_filter('upload_mimes', array($this, 'allow_svg_upload')); add_filter('elementor/files/allow_unfiltered_upload', '__return_true'); $import = new Import($this); $imported_data = $import->run(); $import_status = $this->handle_import_status('success'); update_option('templately_flush_rewrite_rules', true, false); $this->sse_message([ 'type' => 'complete', 'action' => 'complete', 'results' => $this->normalize_imported_data($imported_data) ]); update_user_meta(get_current_user_id(), 'templately_fsi_pack_id', $this->request_params["id"]); if(!empty($import_status['hasFeedback'])){ update_user_meta(get_current_user_id(), 'templately_fsi_complete', 'done'); } else{ update_user_meta(get_current_user_id(), 'templately_fsi_complete', true); } } private function normalize_imported_data($data) { $templates = !empty($data['templates']['succeed']) ? count($data['templates']['succeed']) : 0; $template_types = !empty($data['templates']['template_types']) ? $data['templates']['template_types'] : []; $post_types = []; $content_templates = []; if (!empty($data['content']) && is_array($data['content'])) { foreach ($data['content'] as $type => $type_data) { $content_templates[$type] = !empty($type_data['succeed']) ? count($type_data['succeed']) : 0; $post_types[] = $this->get_post_type_label_by_slug($type); } } $contents = []; if (!empty($data['wp-content']) && is_array($data['wp-content'])) { foreach ($data['wp-content'] as $type => $type_data) { $contents[$type] = !empty($type_data['succeed']) ? count($type_data['succeed']) : 0; if (!in_array($type, ['wp_navigation', 'nav_menu_item'])) { $post_types[] = $this->get_post_type_label_by_slug($type); } } } Helper::log($data); return [ 'templates' => $templates, 'contents' => $content_templates, 'wp-content' => $contents, 'post_types' => $post_types, 'template_types' => $template_types, 'dependency_data' => $this->dependency_data, ]; } public function get_request_params() { return $this->request_params; } private function revert() { // $request = $this->get_request_params(); // if ( isset( $request['revert'] ) && $request['revert'] ) { // // TODO: Implement the Revert Process. // } } public function redirect_for_archives($link, $post_id) { $archive_settings = get_option('templately_post_archive'); if (!empty($archive_settings) && intval($archive_settings['post_id']) === intval($post_id)) { $link = str_replace($post_id, $archive_settings['archive_id'], $link); } return $link; } public function allow_svg_upload($mimes) { // Allow SVG $mimes['svg'] = 'image/svg+xml'; return $mimes; } public function register_shutdown() { $status = connection_status(); $last_error = error_get_last(); if ($status != CONNECTION_NORMAL && $last_error && $last_error['type'] === E_ERROR) { if ((defined('WP_DEBUG') && WP_DEBUG || defined('TEMPLATELY_EVENT_LOG') && TEMPLATELY_EVENT_LOG) && !empty($last_error['message'])) { $full_message = $last_error['message']; // Split the message at the first newline to remove the stack trace $message_parts = preg_split('/\n/', $full_message); // The error message is the first part $error_message = $message_parts[0]; } else { // Generic error message $error_message = sprintf(__("It seems we're experiencing technical difficulties. Please try again or contact support.", "templately"), 'https://wpdeveloper.com/support'); } $this->handle_import_status('failed', $error_message); // Handle the error, e.g. log it or display a message to the user $this->sse_message([ 'action' => 'error', 'status' => 'error', 'type' => "error", 'title' => __("Oops!", "templately"), 'message' => $error_message, // 'position' => 'plugin', // 'progress' => '--', ]); } $this->debug_log("Shutdown:....."); $this->debug_log("connection_status: " . $this->getConnectionStatusText()); $this->debug_log($last_error); } public function handle_import_status($status, $description = '') { if ($this->is_import_status_handled) { Helper::log("Import status already handled: $status"); return null; } $this->is_import_status_handled = $status; $download_key = $this->download_key; $headers = [ 'Content-Type' => 'application/json', 'Authorization' => 'Bearer ' . $this->api_key, 'download_key' => $download_key, 'download-key' => $download_key, 'x-templately-ip' => Helper::get_ip(), 'x-templately-url' => home_url('/'), ]; $args = [ 'headers' => $headers, ]; if ($status === 'success') { $url = $this->get_api_url("v1", 'import/success'); $args['body'] = json_encode(['type' => 'pack']); $response = wp_remote_post($url, $args); } elseif ($status === 'failed') { $url = $this->get_api_url("v1", 'import/failed'); $args['body'] = json_encode(['type' => 'pack', 'description' => $description ?: "Something Went wrong....."]); $response = wp_remote_post($url, $args); } Helper::log($response); if (is_wp_error($response)) { // Handle error Helper::log($response->get_error_message()); } else { // Handle success $body = wp_remote_retrieve_body($response); $data = json_decode($body, true); // Do something with $body return $data; } return null; } protected function getConnectionStatusText() { $status = connection_status(); switch ($status) { case CONNECTION_NORMAL: return "Normal"; case CONNECTION_ABORTED: return "Aborted"; case CONNECTION_TIMEOUT: return "Timeout"; default: return "Unknown"; } } protected function get_post_type_label_by_slug($slug) { $post_type_obj = get_post_type_object($slug); if ($post_type_obj) { return $post_type_obj->label; } return null; } public function import_info() { $platform = isset($_GET['platform']) ? $_GET['platform'] : 'elementor'; $id = isset($_GET['id']) ? intval($_GET['id']) : 0; $response = wp_remote_get($this->info_get_api_url($id), [ 'timeout' => 30, 'headers' => [ 'Authorization' => 'Bearer ' . $this->api_key, 'x-templately-ip' => Helper::get_ip(), 'x-templately-url' => home_url('/'), 'x-templately-version' => TEMPLATELY_VERSION, ] ]); if (is_wp_error($response)) { wp_send_json_error($response->get_error_message()); return; } // If the response code is not 200, return the error message if (wp_remote_retrieve_response_code($response) != 200) { wp_send_json_error(json_decode(wp_remote_retrieve_body($response))); return; } // If the response body is JSON and it contains an error, return the error message // Retrieve Data from Response Body. $body = wp_remote_retrieve_body($response); $data = json_decode($body, true); if (isset($data['error'])) { wp_send_json_error($data['error']); return; } if (isset($data['data']['manifest'])) { $data['data']['manifest'] = json_decode($data['data']['manifest'], true); } if (isset($data['data']['settings'])) { $data['data']['settings'] = json_decode($data['data']['settings'], true); } // Return the response body wp_send_json($data); } public function update_imported_list($type, $id) { $imported_list = get_option('templately_fsi_imported_list', []); $imported_list[$type][] = $id; update_option('templately_fsi_imported_list', $imported_list); } /** * * * @return void */ protected function add_revert_hooks() { add_action('wp_insert_post', function ($post_id) { $this->update_imported_list('posts', $post_id); }); add_action('add_attachment', function ($post_id) { $this->update_imported_list('attachment', $post_id); }); add_action('created_term', function ($term_id, $tt_id, $taxonomy, $args) { $this->update_imported_list('term', [$term_id, $taxonomy]); }, 10, 4); add_action('registered_taxonomy', function ($taxonomy, $object_type, $taxonomy_object) { $this->update_imported_list('taxonomy', $taxonomy); }, 10, 3); add_action('fluentform/form_imported', function ($formId){ $this->update_imported_list('fluentform', $formId); }, 10, 1); } public static function has_revert(){ $options = Utils::get_backup_options(); $imported_list = get_option('templately_fsi_imported_list', []); if(!empty($options) || !empty($imported_list)){ return true; } return false; } public function import_revert() { // // Get the nonce value from the request (usually from $_POST or $_GET) // $received_nonce = isset($_REQUEST['_wpnonce']) ? $_REQUEST['_wpnonce'] : ''; // // Verify the nonce using wp_verify_nonce() // $verified = wp_verify_nonce($received_nonce, 'templately_pack_import_revert_nonce'); // if (!$verified) { // wp_send_json_error("Nonce not verified."); // } $option_active = null; $options_deleted = false; $imported_list_deleted = false; $options = Utils::get_backup_options(); $status_args = [ 'post_type' => 'templately_library' ]; $all_post_url = admin_url(add_query_arg( $status_args, 'edit.php' )); // wp_send_json_success([$options]); if(class_exists('Elementor\Plugin')){ $kits_manager = Plugin::$instance->kits_manager; $option_active = $kits_manager::OPTION_ACTIVE; $kit = $kits_manager->get_active_kit(); if ( ! $kit->get_id() ) { $kit = $kits_manager->create_default(); update_option( $kits_manager::OPTION_ACTIVE, $kit ); } } if (!empty($options) && is_array($options)) { foreach ($options as $key => $value) { if ('stylesheet' === $key) { if (get_option('stylesheet') !== $value) { switch_theme($value); } } else if($option_active === $key && class_exists('Elementor\Plugin')) { $kits_manager->revert( (int) $kits_manager->get_active_id(), (int) $value, 0 ); $kit = $kits_manager->get_active_kit(); $settings = $kit->get_data('settings'); if ( isset( $settings['site_logo'] ) ) { set_theme_mod( 'custom_logo', $settings['site_logo']['id'] ); } } else { update_option($key, $value); } delete_option("__templately_$key"); $options_deleted = true; } } $imported_list = get_option('templately_fsi_imported_list', []); if (!empty($imported_list) && is_array($imported_list)) { $_GET['force_delete_kit'] = 1; // Fallback GET Ready! foreach ($imported_list as $type => $list) { if (empty($list) || !is_array($list)) { continue; } // Loop through each item ID and delete it foreach ($list as $key => $item_id) { switch ($type) { case 'posts': // making sure default kit don't get deleted. if($option_active && isset($options[$option_active]) && $options[$option_active] == $item_id){ break; } wp_delete_post($item_id, true); // Set true for permanent deletion break; case 'attachment': wp_delete_attachment($item_id, true); // Set true for permanent deletion break; case 'term': list($term_id, $taxonomy) = $item_id; wp_delete_term($term_id, $taxonomy); // Use corresponding taxonomy break; case 'taxonomy': // Taxonomies cannot be directly deleted. Consider de-registering it. break; case 'fluentform': if(class_exists('\FluentForm\App\Models\Form')){ \FluentForm\App\Models\Form::remove($item_id); } break; } } } $imported_list_deleted = true; delete_option('templately_fsi_imported_list'); } if($options_deleted || $imported_list_deleted){ sleep(5); wp_send_json_success([ 'options' => $options_deleted, 'imported_list' => $imported_list_deleted, 'site_url' => home_url(), 'redirect' => $all_post_url ]); } wp_send_json_error([ 'options' => $options_deleted, 'imported_list' => $imported_list_deleted, 'site_url' => home_url() ]); } public function google_font() { $result = get_transient('templately-google-fonts'); if (false == $result) { $response = wp_remote_get($this->get_api_url('v2', 'google-font'), [ 'timeout' => 30, 'headers' => [ 'Authorization' => 'Bearer ' . $this->api_key, 'x-templately-ip' => Helper::get_ip(), 'x-templately-url' => home_url( '/' ), 'x-templately-version' => TEMPLATELY_VERSION, ] ]); if (is_wp_error($response)) { wp_send_json_error($response->get_error_message()); } if (wp_remote_retrieve_response_code($response) != 200) { wp_send_json_error('API request failed with response code ' . wp_remote_retrieve_response_code($response)); } $body = wp_remote_retrieve_body($response); $data = json_decode($body, true); if (!isset($data['status']) || $data['status'] !== 'success') { wp_send_json_error('API response indicates failure.'); } if (!isset($data['data'])) { wp_send_json_error('API response missing data.'); } $result = $data['data']; set_transient('templately-google-fonts', $result, DAY_IN_SECONDS); } wp_send_json_success($result); } }