PluginProbe
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! / 3.8.0
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! v3.8.0
3.8.0 3.7.5 3.7.4 3.7.3 3.7.2 1-final 3.7.1 3.7.0 3.6.8 3.6.7 3.6.6 3.6.5 3.6.4 3.6.3 3.6.2 3.6.1 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 All 112 releases
templately / modules / full-site-import / FullSiteImport.php

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

270 lines 8.4 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\Modules\FullSiteImport;
15
16 use Elementor\Plugin;
17 use Error;
18 use Exception;
19 use Templately\Modules\FullSiteImport\Exception\FatalErrorException;
20 use Templately\Modules\FullSiteImport\Exception\RetryableErrorException;
21 use Templately\Modules\FullSiteImport\Exception\UnknownErrorException;
22 use Templately\Modules\FullSiteImport\Runners\Finalizer;
23 use Templately\Modules\FullSiteImport\Utils\LogHandler;
24 use Templately\Modules\FullSiteImport\Utils\Utils;
25 use Templately\Modules\FullSiteImport\Utils\SessionData;
26 use Templately\Modules\FullSiteImport\Utils\AIUtils;
27 use Templately\Utils\Base;
28 use Templately\Utils\Response\AjaxResponder;
29 use Templately\Utils\Helper;
30 use Templately\Utils\Installer;
31 use Templately\Utils\Options;
32
33 class FullSiteImport extends Base {
34 use Concerns\LogHelper;
35 use Concerns\ThrowsErrors;
36 use Concerns\HandlesSession;
37 use Concerns\DownloadsPack;
38 use Concerns\RunsImport;
39 use Concerns\ReportsStatus;
40 use Concerns\NormalizesResult;
41 use Concerns\CleansUp;
42 use Concerns\TracksRevert;
43 use Concerns\HandlesAiEndpoints;
44
45 const SESSION_OPTION_KEY = 'templately_import_session';
46
47 /**
48 * Extensions a pack carries that WordPress does not accept as an upload.
49 *
50 * Everything else comes from get_allowed_mime_types(), so this list only has
51 * to name what the pack format adds on top of it:
52 *
53 * - `json` — every pack is built from JSON (manifest, templates, content),
54 * and WordPress has never allowed .json uploads.
55 * - `xml` — the WXR files under wp-content/. Also not an allowed upload:
56 * core hands .xml to the importer plugin rather than the media library.
57 * - `ai` — the marker segment in `{id}.ai.json`, an AI-generated page. Not
58 * the Illustrator format.
59 * - `svg` — packs ship SVG artwork. This plugin already allows SVG uploads
60 * for the duration of an import (see allow_svg_upload()), but that filter is
61 * only added in start_content_import(), which runs AFTER extraction — so at
62 * sweep time get_allowed_mime_types() does not have it and the pack's SVGs
63 * would be deleted. It has to be named here.
64 * - fonts — a pack may ship webfonts, and none of these are upload types.
65 * Passive assets; nothing here is executable by any server.
66 *
67 * Adding to this list is how a new pack file type gets through. It fails
68 * closed and logs, so a missing entry shows up as a dropped file in the
69 * import log — not as a silent hole.
70 *
71 * Lives on the class rather than the DownloadsPack trait that reads it:
72 * trait constants are PHP 8.2+, and the advertised floor here is 7.2.
73 */
74 const PACK_EXTENSIONS = [
75 'json', 'xml', 'ai',
76 'svg', 'svgz',
77 'woff', 'woff2', 'ttf', 'otf', 'eot',
78 ];
79 public $manifest;
80 protected $export;
81
82 private $version = '1.0.0';
83
84 public $download_key;
85 protected $dev_mode = false;
86 protected $api_key = '';
87 protected $session_id = '';
88 protected $documents_data = [];
89 private $is_import_status_handled = false;
90
91 public $dir_path;
92 protected $filePath;
93 protected $tmp_dir = null;
94 public $request_params = [];
95
96 // Polling-specific property for ai_poll_template()
97 private $polling_is_last_part = null;
98
99 public function __construct() {
100 $this->dev_mode = defined('TEMPLATELY_DEV') && TEMPLATELY_DEV;
101 $this->api_key = Options::get_instance()->get('api_key');
102
103 // Independent endpoint handlers (registered through the same nonce/cap wrapper).
104 // `import_revert` moved to modules/import-revert (2026-07-23) — it arrives
105 // through the templately_fsi_ajax_handlers seam below, like the feedback shims.
106 $asset = new Ajax\AssetController();
107 $pack_info = new Ajax\PackInfoController();
108
109 $this->add_ajax_action('import_settings', $this);
110 $this->add_ajax_action('create_session_and_download', $this);
111 $this->add_ajax_action('import_status', $this);
112 $this->add_ajax_action('import', $this);
113 $this->add_ajax_action('import_info', $pack_info);
114 $this->add_ajax_action('import_global_settings', $pack_info);
115 $this->add_ajax_action('google_font', $asset);
116 $this->add_ajax_action('ai_get_json', $this);
117 $this->add_ajax_action('ai_poll_template', $this);
118 $this->add_ajax_action('merge_settings_with_template', $asset);
119
120 // Cross-module AJAX handlers arrive through this seam instead of direct class
121 // imports (e.g. post-import-feedback supplies its two deprecated shims — see
122 // that module.php). Applied on 'init' rather than here because FSI boots before
123 // the supplying modules (alphabetical discovery order); admin-ajax.php fires
124 // wp_ajax_* well after 'init', so registration is never late.
125 add_action('init', function () {
126 $handlers = apply_filters('templately_fsi_ajax_handlers', []);
127 foreach ($handlers as $action => $handler) {
128 $this->add_ajax_action($action, $handler);
129 }
130 });
131
132 add_action('admin_init', [$this, 'admin_init']);
133
134 // Cleanup scheduling moved to `modules/utilities/` (spec 052). This module
135 // contributes tasks to the one shared sweep instead of running its own
136 // daily event, which pruned options only and never touched the disk.
137
138 if(isset($_GET['action']) && ($_GET['action'] == 'templately_pack_import' || $_GET['action'] == 'templately_pack_import_status')) {
139 add_filter('wp_redirect', '__return_false', 999);
140 }
141
142 if ($this->dev_mode) {
143 add_filter('http_request_host_is_external', '__return_true');
144 add_filter('http_request_args', function ($args) {
145 $args['sslverify'] = false;
146
147 return $args;
148 });
149 }
150 }
151
152 public function add_ajax_action($action, $object) {
153 add_action("wp_ajax_templately_pack_$action", function() use ($action, $object) {
154 // The nonce + capability gate lives in AjaxResponder::guard() so that it
155 // answers with the same envelope (and real machine codes) as everything
156 // else. It sends and dies on failure. Spec 043 / PRD PHP-5.
157 if (!AjaxResponder::guard('templately_nonce', ['install_plugins', 'install_themes'])) {
158 return;
159 }
160
161 // Every AI/FSI step arrives through here, so this is the one place that can say
162 // WHICH step a run reached and how the request ended. Without it a run that
163 // stopped between two steps was indistinguishable from one that never started
164 // the next.
165 //
166 // The end is reported from a shutdown handler and NOT gated on "did the handler
167 // return", because these handlers answer through AjaxResponder, which `die()`s —
168 // so the normal, successful path never comes back here. A flag set after
169 // `call_user_func()` would therefore mark every success as a failure. The
170 // shutdown handler states the facts instead and lets the reader judge:
171 // `connection_aborted=1` means the browser hung up (ignore_user_abort is 0, so
172 // PHP stops at the next write, silently), and a non-null `last_error` means PHP
173 // died.
174 $started = microtime( true );
175 Helper::log( sprintf( 'ajax: templately_pack_%s — start', $action ), 'fsi_ajax', 'info' );
176
177 register_shutdown_function( function () use ( $action, $started ) {
178 Helper::log(
179 sprintf(
180 'ajax: templately_pack_%s — ended after %.1fs (connection_aborted=%d, http_code=%s, last_error=%s)',
181 $action,
182 microtime( true ) - $started,
183 connection_aborted(),
184 function_exists( 'http_response_code' ) ? (string) http_response_code() : '?',
185 wp_json_encode( error_get_last() )
186 ),
187 'fsi_ajax',
188 connection_aborted() || null !== error_get_last() ? 'warning' : 'info'
189 );
190 } );
191
192 // Call the actual handler method on the registered object (defaults to $this).
193 call_user_func([$object, $action]);
194 });
195 }
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219 private function skipped_plugin(): bool {
220 return empty($this->request_params['plugins']) || !is_array($this->request_params['plugins']);
221 }
222
223
224
225
226
227
228
229
230 public function get_request_params() {
231 return $this->request_params;
232 }
233
234 /**
235 * Kept on FullSiteImport for backward compatibility (called as FullSiteImport::has_revert()).
236 * The revert surface moved to modules/import-revert (2026-07-23), which answers
237 * the `templately_has_revert` filter — no class reference in this direction.
238 */
239 public static function has_revert() {
240 return (bool) apply_filters( 'templately_has_revert', false );
241 }
242
243
244
245 public function allow_svg_upload($mimes) {
246 // Allow SVG
247 $mimes['svg'] = 'image/svg+xml';
248 return $mimes;
249 }
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269 }
270