PluginProbe
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! / 3.4.9
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! v3.4.9
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
← All changes | includes/Core/Importer/Utils/Utils.php +411 -42 3.1.0 → 3.4.9 View file →
@@ -2,11 +2,16 @@
2 2
3 3 namespace Templately\Core\Importer\Utils;
4 4
5 5 use Exception;
6 +use Templately\Core\Importer\FullSiteImport;
7 +use Templately\Core\Importer\WPImport;
6 8 use Templately\Utils\Base;
9 +use Templately\Utils\Helper;
7 10
8 11 class Utils extends Base {
12 +
13 +
9 14 /**
10 15 * @throws Exception
11 16 */
12 17 public static function read_json_file( $path ) {
@@ -59,8 +64,14 @@
59 64 $result += $post_type['succeed'] ?? [];
60 65 }
61 66 }
62 67
68 + // add attachments data
69 + if ( !empty( $imported_data['attachments']['succeed'] ) ) {
70 + $result += $imported_data['attachments']['succeed'] ?? [];
71 + }
72 +
73 +
63 74 return $result;
64 75 }
65 76
66 77 public static function map_old_new_term_ids( array $imported_data ) {
@@ -101,17 +112,43 @@
101 112 public static function get_json_helper( string $platform ) {
102 113 return $platform === 'elementor' ? new ElementorHelper() : new GutenbergHelper();
103 114 }
104 115
105 - public static function update_option( $key, $value, $autoload = 'no' ){
106 - $bk_value = get_option("__templately_$key");
107 - if($bk_value === false){
108 - $old_value = get_option($key);
109 - add_option( "__templately_$key", $old_value, '', $autoload );
116 + public static function get_backup_options() {
117 + global $wpdb;
118 +
119 + $prefix = '__templately_';
120 + $table_name = $wpdb->options; // Assuming default options table name
121 +
122 + $sql = "SELECT option_name, option_value FROM {$table_name} WHERE option_name LIKE %s";
123 + $prepared_sql = $wpdb->prepare($sql, array("$prefix%")); // Escape wildcard for security
124 +
125 + $results = $wpdb->get_results($prepared_sql);
126 +
127 + $templately_options = array();
128 + foreach ($results as $row) {
129 + $name = str_replace($prefix, '', $row->option_name);
130 + $templately_options[$name] = maybe_unserialize($row->option_value);
110 131 }
111 - return update_option( $key, $value, $autoload );
132 +
133 + return $templately_options;
112 134 }
113 135
136 + public static function backup_option_value($key, $autoload = 'no') {
137 + $old_value = get_option($key);
138 + if ($old_value) {
139 + update_option("__templately_$key", $old_value, $autoload);
140 + }
141 + else {
142 + add_option("__templately_$key", $old_value, '', $autoload);
143 + }
144 + }
145 +
146 + public static function update_option($key, $value, $autoload = 'no') {
147 + self::backup_option_value($key, $autoload);
148 + return update_option($key, $value, $autoload);
149 + }
150 +
114 151 public static function import_page_settings( $id, $settings ) {
115 152 $extra_settings = [
116 153 'page_on_front' => [
117 154 'show_on_front' => 'page'
@@ -125,9 +162,13 @@
125 162 self::update_option( 'show_on_front', 'page' );
126 163 }
127 164 if ( ! empty( $settings['page_settings'] ) ) {
128 165 foreach ( $settings['page_settings'] as $option_name => $val ) {
129 - self::update_option( $option_name, $id );
166 + $__val = $id;
167 + if($option_name === 'fluent_cart_store_settings'){
168 + $__val = $val;
169 + }
170 + self::update_option( $option_name, $__val );
130 171 if ( array_key_exists( $option_name, $extra_settings ) ) {
131 172 foreach ( $extra_settings[ $option_name ] as $name => $value ) {
132 173 self::update_option( $name, $value );
133 174 }
@@ -135,9 +176,9 @@
135 176 }
136 177 }
137 178 }
138 179
139 - public static function upload_logo($url) {
180 + public static function upload_logo($url, $session_id) {
140 181 if(empty($url)) {
141 182 return ['error' => __('URL is empty', 'templately')];
142 183 }
143 184
@@ -145,51 +186,379 @@
145 186 if ( ! wp_http_validate_url( $url ) || !parse_url( $url, PHP_URL_SCHEME ) ) {
146 187 return ['error' => __('Invalid URL', 'templately')];
147 188 }
148 189
149 - // Download image and get MIME type
150 - $temp_file = download_url( $url );
151 - if ( is_wp_error( $temp_file ) ) {
152 - return ['error' => __('Failed to download image', 'templately')];
190 + $post_data = self::prepare_post_data($url);
191 + $wp_importer = new WPImport( null, ['fetch_attachments' => true, 'session_id' => $session_id] );
192 + $attachment_id = $wp_importer->process_attachment($post_data, $url);
193 +
194 + if(is_wp_error($attachment_id)){
195 + return ['error' => $attachment_id->get_error_message()];
153 196 }
154 197
155 - // Validate image type using wp_get_image_mime
156 - $mime_type = wp_get_image_mime( $temp_file );
157 - if ( ! $mime_type || !in_array( $mime_type, get_allowed_mime_types() ) ) {
158 - unlink( $temp_file );
159 - return ['error' => __('Invalid image type', 'templately')];
198 + return [
199 + 'id' => (int) $attachment_id,
200 + 'url' => esc_url_raw(wp_get_attachment_url($attachment_id)),
201 + ];
202 + }
203 +
204 + /**
205 + * Upload base64 encoded image to media library
206 + *
207 + * @param string $base64 Base64 encoded image data (with or without data URI scheme)
208 + * @param string $session_id Session ID for tracking (reserved for future use)
209 + * @return array Array with 'id' and 'url' on success, or ['error' => message] on failure
210 + */
211 + public static function upload_logo_base64($base64, $session_id = null) {
212 + if(empty($base64)) {
213 + return ['error' => __('Base64 is empty', 'templately')];
160 214 }
161 215
162 - $file_info = wp_check_filetype_and_ext( $temp_file, basename( $url ), get_allowed_mime_types() );
163 - if ( ! $file_info['ext'] || $file_info['type'] !== $mime_type ) {
164 - unlink( $temp_file );
165 - return ['error' => __('File type and extension check failed', 'templately')];
216 + // Upload the base64 image
217 + $attachment_id = self::upload_base64_image($base64);
218 +
219 + if(is_wp_error($attachment_id)){
220 + return ['error' => $attachment_id->get_error_message()];
166 221 }
167 222
168 - // Prepare the file for sideloading
169 - $file = array(
170 - 'name' => basename($url),
171 - 'type' => $mime_type,
172 - 'tmp_name' => $temp_file,
173 - 'error' => 0,
174 - 'size' => filesize($temp_file),
223 + return [
224 + 'id' => (int) $attachment_id,
225 + 'url' => esc_url_raw(wp_get_attachment_url($attachment_id)),
226 + ];
227 + }
228 +
229 + /**
230 + * Upload base64 encoded image without dependency on prepare_post_data
231 + * Handles MIME type detection and proper file extension assignment
232 + *
233 + * @param string $base64 Base64 encoded image data (with or without data URI scheme)
234 + * @return int|WP_Error Attachment ID on success, WP_Error on failure
235 + */
236 + public static function upload_base64_image($base64) {
237 + // Decode base64 string
238 + $decoded_image = base64_decode($base64, true);
239 + if ($decoded_image === false) {
240 + return new \WP_Error('invalid_base64', __('Invalid base64 data.', 'templately'));
241 + }
242 +
243 + // Detect MIME type from decoded image data
244 + $mime_type = self::detect_mime_type_from_data($decoded_image);
245 + if (empty($mime_type)) {
246 + return new \WP_Error('unknown_mime_type', __('Unable to determine image MIME type.', 'templately'));
247 + }
248 +
249 + // Get file extension from MIME type
250 + $extension = self::get_file_extension_by_mime_type($mime_type);
251 + if (empty($extension)) {
252 + return new \WP_Error('unsupported_mime_type', __('Unsupported image MIME type.', 'templately'));
253 + }
254 +
255 + // Generate unique filename
256 + $filename = 'templately-logo-' . \wp_generate_uuid4() . '.' . $extension;
257 +
258 + // Get upload directory
259 + $upload_dir = \wp_upload_dir();
260 + if (!$upload_dir['error']) {
261 + $upload_path = $upload_dir['path'] . '/' . $filename;
262 + } else {
263 + return new \WP_Error('upload_dir_error', __('Unable to access upload directory.', 'templately'));
264 + }
265 +
266 + // Write decoded image to file
267 + if (file_put_contents($upload_path, $decoded_image) === false) {
268 + return new \WP_Error('upload_error', __('Error uploading image.', 'templately'));
269 + }
270 +
271 + // Create attachment post
272 + $attachment_data = [
273 + 'post_mime_type' => $mime_type,
274 + 'post_title' => \sanitize_file_name(pathinfo($filename, PATHINFO_FILENAME)),
275 + 'post_content' => '',
276 + 'post_status' => 'inherit',
277 + ];
278 +
279 + $attachment_id = \wp_insert_attachment($attachment_data, $upload_path);
280 + if (is_wp_error($attachment_id)) {
281 + return $attachment_id;
282 + }
283 +
284 + // Ensure WordPress image functions are available
285 + // These functions are defined in wp-admin/includes/image.php which is not always loaded
286 + if (!function_exists('wp_generate_attachment_metadata')) {
287 + require_once(ABSPATH . 'wp-admin/includes/image.php');
288 + }
289 +
290 + // Generate and update attachment metadata
291 + $metadata = \wp_generate_attachment_metadata($attachment_id, $upload_path);
292 + \wp_update_attachment_metadata($attachment_id, $metadata);
293 +
294 + return $attachment_id;
295 + }
296 +
297 + /**
298 + * Detect MIME type from image data
299 + * Uses finfo_buffer if available, otherwise falls back to getimagesizefromstring
300 + *
301 + * @param string $image_data Raw image data
302 + * @return string|null MIME type or null if unable to detect
303 + */
304 + private static function detect_mime_type_from_data($image_data) {
305 + // Try using finfo_buffer first (most reliable)
306 + if (function_exists('finfo_buffer')) {
307 + $finfo = finfo_open(FILEINFO_MIME_TYPE);
308 + if ($finfo) {
309 + $mime_type = finfo_buffer($finfo, $image_data);
310 + finfo_close($finfo);
311 + if ($mime_type && strpos($mime_type, 'image/') === 0) {
312 + return $mime_type;
313 + }
314 + }
315 + }
316 +
317 + // Fallback: use getimagesizefromstring
318 + if (function_exists('getimagesizefromstring')) {
319 + $image_info = @getimagesizefromstring($image_data);
320 + if ($image_info && isset($image_info['mime'])) {
321 + return $image_info['mime'];
322 + }
323 + }
324 +
325 + return null;
326 + }
327 +
328 + /**
329 + * Get file extension by MIME type
330 + * Uses WordPress built-in functions for MIME type to extension conversion
331 + *
332 + * @since 3.4.5
333 + * @param string $mime_type MIME type (e.g., 'image/png')
334 + * @return string|null File extension without dot, or null if not found
335 + */
336 + private static function get_file_extension_by_mime_type($mime_type) {
337 + // Use WordPress core function if available (WordPress 5.8.1+)
338 + // wp_get_default_extension_for_mime_type() returns the default file extension for a given MIME type
339 + if (function_exists('wp_get_default_extension_for_mime_type')) {
340 + return \wp_get_default_extension_for_mime_type($mime_type);
341 + }
342 +
343 + // Fallback for WordPress < 5.8.1
344 + // Use wp_get_mime_types() which returns array with extensions as keys and MIME types as values
345 + // Example: ['jpg|jpeg|jpe' => 'image/jpeg', 'png' => 'image/png', ...]
346 + $wp_mime_types = \wp_get_mime_types();
347 +
348 + // Flip the array to get MIME type as key and extensions as value
349 + $mime_map = array_flip($wp_mime_types);
350 +
351 + if (isset($mime_map[$mime_type])) {
352 + $extensions = $mime_map[$mime_type];
353 + // Get first extension if multiple are available (e.g., 'jpg|jpeg|jpe' -> 'jpg')
354 + return strtok($extensions, '|');
355 + }
356 +
357 + return null;
358 + }
359 +
360 + /**
361 + * Inserts a template into the Gutenberg editor.
362 + *
363 + * @param mixed $data
364 + * @param int $postId
365 + * @return array
366 + */
367 + public static function import_and_replace_attachments($content, $postId = 0) {
368 + // Instantiate GutenbergHelper
369 + $helper = new GutenbergHelper();
370 +
371 + $data = [
372 + 'content' => $content,
373 + ];
374 +
375 + // Organize URLs from the content
376 + $organizedUrls = $helper->parse_images($data['content']);
377 + if(empty($organizedUrls)){
378 + return $content;
379 + }
380 +
381 + // Define template settings
382 + $template_settings = [
383 + 'post_id' => $postId,
384 + '__attachments' => $organizedUrls,
385 + ];
386 +
387 + // Map post IDs and disable logging
388 + $helper->map_post_ids[$postId] = $postId;
389 + $helper->shouldLog = false;
390 +
391 + // Prepare the helper with the data and settings
392 + $helper->prepare($data, $template_settings);
393 +
394 + // Update the content in the data array
395 + $content = wp_unslash($helper->get_content());
396 +
397 + return $content;
398 + }
399 +
400 + public static function prepare_post_data($image_url, $post_parent = null, $logger = null) {
401 + $filetype = wp_check_filetype(basename($image_url));
402 + if (!$filetype['type']) {
403 + if(is_callable($logger)){
404 + // call the logger function
405 + call_user_func($logger, 'prepare', 'Error: Unable to determine the file type.', -1, 'eventLog');
406 + }
407 + return null;
408 + }
409 +
410 + $post_data = array(
411 + 'post_title' => basename($image_url),
412 + 'post_content' => '',
413 + 'post_status' => 'inherit',
414 + 'post_mime_type' => $filetype['type'],
415 + 'guid' => $image_url,
175 416 );
176 417
177 - // Load the WordPress media handler
178 - require_once(ABSPATH . 'wp-admin/includes/media.php');
179 - require_once(ABSPATH . 'wp-admin/includes/file.php');
180 - require_once(ABSPATH . 'wp-admin/includes/image.php');
418 + if($post_parent){
419 + $post_data['post_parent'] = $post_parent; // Set the parent post
420 + }
181 421
182 - // Handle the sideload
183 - $id = media_handle_sideload($file, 0);
422 + if (preg_match('%wp-content/uploads/([0-9]{4}/[0-9]{2})%', $image_url, $matches)) {
423 + $post_data['upload_date'] = $matches[1];
424 + }
425 + else{
426 + $post_data['upload_date'] = date('Y/m');
427 + }
184 428
185 - if (is_wp_error($id)) {
186 - @unlink($file['tmp_name']);
187 - return ['error' => __('Failed to sideload image', 'templately')];
429 + return $post_data;
430 + }
431 +
432 + // Static version of get_session_data
433 + public static function get_all_session_data(): array {
434 + $data = get_option(FullSiteImport::SESSION_OPTION_KEY, []);
435 + return $data ?? [];
436 + }
437 +
438 + // Static version of get_session_data
439 + public static function get_session_data($session_id): array {
440 + $data = get_option(FullSiteImport::SESSION_OPTION_KEY, []);
441 + return $data[$session_id] ?? [];
442 + }
443 +
444 + // Static version of update_session_data
445 + public static function update_session_data($session_id, $data): bool {
446 + $old_data = get_option(FullSiteImport::SESSION_OPTION_KEY, []);
447 + return update_option(FullSiteImport::SESSION_OPTION_KEY, Helper::recursive_wp_parse_args([$session_id => $data], $old_data));
448 + }
449 +
450 + // Delete specific session data by ID
451 + public static function delete_session_data($session_id): bool {
452 + $all_data = get_option(FullSiteImport::SESSION_OPTION_KEY, []);
453 +
454 + if (!isset($all_data[$session_id])) {
455 + return false; // Session ID doesn't exist
456 + }
457 +
458 + unset($all_data[$session_id]);
459 + return update_option(FullSiteImport::SESSION_OPTION_KEY, $all_data);
460 + }
461 +
462 + public static function get_session_id(){
463 + $session_id = null;
464 + if(!empty($_REQUEST['session_id'])){
465 + $session_id = sanitize_text_field($_REQUEST['session_id']);
188 466 }
467 + return $session_id;
468 + }
189 469
190 - return [
191 - 'id' => $id,
192 - 'url' => esc_url_raw(wp_get_attachment_url($id)),
193 - ];
470 + public static function get_session_data_by_id(): array {
471 + if($session_id = self::get_session_id()){
472 + return self::get_session_data($session_id);
473 + }
474 + throw new Exception(__('Invalid Session ID.', 'templately'));
194 475 }
195 -}
476 +
477 + public static function update_session_data_by_id($data): bool {
478 + if($session_id = self::get_session_id()){
479 + return self::update_session_data($session_id, $data);
480 + }
481 + throw new Exception(__('Invalid Session ID.', 'templately'));
482 + }
483 +
484 +
485 +
486 + /**
487 + * Clean up directory using RecursiveIteratorIterator approach
488 + * This method handles directory cleanup with proper validation
489 + *
490 + * @param string $dir_path The directory path to clean up
491 + * @return bool True on success, false on failure
492 + */
493 + public static function cleanup_directory($dir_path) {
494 + if (empty($dir_path) || !file_exists($dir_path) || !is_dir($dir_path)) {
495 + return false;
496 + }
497 +
498 + try {
499 + $files = new \RecursiveIteratorIterator(
500 + new \RecursiveDirectoryIterator($dir_path, \RecursiveDirectoryIterator::SKIP_DOTS),
501 + \RecursiveIteratorIterator::CHILD_FIRST
502 + );
503 +
504 + foreach ($files as $fileinfo) {
505 + $todo = ($fileinfo->isDir() ? 'rmdir' : 'unlink');
506 + $todo($fileinfo->getRealPath());
507 + }
508 +
509 + rmdir($dir_path);
510 + return true;
511 + } catch (Exception $e) {
512 + return false;
513 + }
514 + }
515 +
516 +
517 +
518 +
519 +
520 +
521 +
522 +
523 +
524 + /**
525 + * Clean session data by pack ID, keeping only the current session
526 + * Removes all session entries with the same pack_id except the current session
527 + *
528 + * @param string $pack_id The pack ID to match for cleanup
529 + * @param string $current_session_id The current session ID to preserve
530 + * @return array Array of removed session IDs
531 + */
532 + public static function clean_session_data_by_pack_id($pack_id, $current_session_id) {
533 + if (empty($pack_id) || empty($current_session_id)) {
534 + return [];
535 + }
536 +
537 + $all_session_data = self::get_all_session_data();
538 + $removed_session_ids = [];
539 +
540 +
541 + foreach ($all_session_data as $session_id => $session_data) {
542 + // Skip the current session
543 + if ($session_id === $current_session_id) {
544 + continue;
545 + }
546 +
547 + // Remove sessions that have the same pack_id
548 + if (isset($session_data['id']) && $session_data['id'] === $pack_id) {
549 + unset($all_session_data[$session_id]);
550 + $removed_session_ids[] = $session_id;
551 + }
552 + }
553 +
554 + // Update the option with cleaned data if any sessions were removed
555 + if (!empty($removed_session_ids)) {
556 + update_option(FullSiteImport::SESSION_OPTION_KEY, $all_session_data);
557 + }
558 +
559 + return $removed_session_ids;
560 + }
561 +
562 +
563 +
564 +}