PluginProbe
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! / 3.1.2
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! v3.1.2
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
← All changes | includes/Core/Importer/Utils/Utils.php +42 -376 3.6.13.1.2 View file →
@@ -2,34 +2,12 @@
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;
8 6 use Templately\Utils\Base;
9 -use Templately\Utils\Helper;
10 7
11 8 class Utils extends Base {
12 -
13 9 /**
14 - * Filter callback to prefer the GD image editor over Imagick during imports.
15 - * Imagick can fail on certain server configurations; GD is more reliable for
16 - * the resize/crop operations triggered by wp_generate_attachment_metadata().
17 - */
18 - public static function prefer_gd_editor( $editors ) {
19 - if ( is_callable( [ 'WP_Image_Editor_GD', 'test' ] ) && call_user_func( [ 'WP_Image_Editor_GD', 'test' ] ) ) {
20 - return [ 'WP_Image_Editor_GD' ];
21 - }
22 - return $editors;
23 - }
24 -
25 - public static function add_gd_editor_filter() {
26 - if ( ! has_filter( 'wp_image_editors', [ self::class, 'prefer_gd_editor' ] ) ) {
27 - add_filter( 'wp_image_editors', [ self::class, 'prefer_gd_editor' ] );
28 - }
29 - }
30 -
31 - /**
32 10 * @throws Exception
33 11 */
34 12 public static function read_json_file( $path ) {
35 13 if ( ! file_exists( $path ) ) {
@@ -81,14 +59,8 @@
81 59 $result += $post_type['succeed'] ?? [];
82 60 }
83 61 }
84 62
85 - // add attachments data
86 - if ( !empty( $imported_data['attachments']['succeed'] ) ) {
87 - $result += $imported_data['attachments']['succeed'] ?? [];
88 - }
89 -
90 -
91 63 return $result;
92 64 }
93 65
94 66 public static function map_old_new_term_ids( array $imported_data ) {
@@ -129,43 +101,17 @@
129 101 public static function get_json_helper( string $platform ) {
130 102 return $platform === 'elementor' ? new ElementorHelper() : new GutenbergHelper();
131 103 }
132 104
133 - public static function get_backup_options() {
134 - global $wpdb;
135 -
136 - $prefix = '__templately_';
137 - $table_name = $wpdb->options; // Assuming default options table name
138 -
139 - $sql = "SELECT option_name, option_value FROM {$table_name} WHERE option_name LIKE %s";
140 - $prepared_sql = $wpdb->prepare($sql, array("$prefix%")); // Escape wildcard for security
141 -
142 - $results = $wpdb->get_results($prepared_sql);
143 -
144 - $templately_options = array();
145 - foreach ($results as $row) {
146 - $name = str_replace($prefix, '', $row->option_name);
147 - $templately_options[$name] = maybe_unserialize($row->option_value);
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 );
148 110 }
149 -
150 - return $templately_options;
111 + return update_option( $key, $value, $autoload );
151 112 }
152 113
153 - public static function backup_option_value($key, $autoload = 'no') {
154 - $old_value = get_option($key);
155 - if ($old_value) {
156 - update_option("__templately_$key", $old_value, $autoload);
157 - }
158 - else {
159 - add_option("__templately_$key", $old_value, '', $autoload);
160 - }
161 - }
162 -
163 - public static function update_option($key, $value, $autoload = 'no') {
164 - self::backup_option_value($key, $autoload);
165 - return update_option($key, $value, $autoload);
166 - }
167 -
168 114 public static function import_page_settings( $id, $settings ) {
169 115 $extra_settings = [
170 116 'page_on_front' => [
171 117 'show_on_front' => 'page'
@@ -179,13 +125,9 @@
179 125 self::update_option( 'show_on_front', 'page' );
180 126 }
181 127 if ( ! empty( $settings['page_settings'] ) ) {
182 128 foreach ( $settings['page_settings'] as $option_name => $val ) {
183 - $__val = $id;
184 - if($option_name === 'fluent_cart_store_settings'){
185 - $__val = $val;
186 - }
187 - self::update_option( $option_name, $__val );
129 + self::update_option( $option_name, $id );
188 130 if ( array_key_exists( $option_name, $extra_settings ) ) {
189 131 foreach ( $extra_settings[ $option_name ] as $name => $value ) {
190 132 self::update_option( $name, $value );
191 133 }
@@ -193,9 +135,9 @@
193 135 }
194 136 }
195 137 }
196 138
197 - public static function upload_logo($url, $session_id) {
139 + public static function upload_logo($url) {
198 140 if(empty($url)) {
199 141 return ['error' => __('URL is empty', 'templately')];
200 142 }
201 143
@@ -203,327 +145,51 @@
203 145 if ( ! wp_http_validate_url( $url ) || !parse_url( $url, PHP_URL_SCHEME ) ) {
204 146 return ['error' => __('Invalid URL', 'templately')];
205 147 }
206 148
207 - $post_data = self::prepare_post_data($url);
208 - $wp_importer = new WPImport( null, ['fetch_attachments' => true, 'session_id' => $session_id] );
209 - $attachment_id = $wp_importer->process_attachment($post_data, $url);
210 -
211 - if(is_wp_error($attachment_id)){
212 - return ['error' => $attachment_id->get_error_message()];
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')];
213 153 }
214 154
215 - return [
216 - 'id' => (int) $attachment_id,
217 - 'url' => esc_url_raw(wp_get_attachment_url($attachment_id)),
218 - ];
219 - }
220 -
221 - /**
222 - * Upload base64 encoded image to media library
223 - *
224 - * @param string $base64 Base64 encoded image data (with or without data URI scheme)
225 - * @param string $session_id Session ID for tracking (reserved for future use)
226 - * @return array Array with 'id' and 'url' on success, or ['error' => message] on failure
227 - */
228 - public static function upload_logo_base64($base64, $session_id = null) {
229 - if(empty($base64)) {
230 - return ['error' => __('Base64 is empty', 'templately')];
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')];
231 160 }
232 161
233 - // Upload the base64 image
234 - $attachment_id = self::upload_base64_image($base64);
235 -
236 - if(is_wp_error($attachment_id)){
237 - return ['error' => $attachment_id->get_error_message()];
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')];
238 166 }
239 167
240 - return [
241 - 'id' => (int) $attachment_id,
242 - 'url' => esc_url_raw(wp_get_attachment_url($attachment_id)),
243 - ];
244 - }
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),
175 + );
245 176
246 - /**
247 - * Upload base64 encoded image without dependency on prepare_post_data
248 - * Handles MIME type detection and proper file extension assignment
249 - *
250 - * @param string $base64 Base64 encoded image data (with or without data URI scheme)
251 - * @return int|\WP_Error Attachment ID on success, WP_Error on failure
252 - */
253 - public static function upload_base64_image($base64) {
254 - // Strip data URL prefix if present (e.g., "data:image/png;base64,")
255 - if (strpos($base64, 'data:image/') === 0) {
256 - $base64_parts = explode(',', $base64, 2);
257 - if (isset($base64_parts[1])) {
258 - $base64 = $base64_parts[1];
259 - }
260 - }
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');
261 181
262 - // Decode base64 string
263 - $decoded_image = base64_decode($base64, true);
264 - if ($decoded_image === false) {
265 - return new \WP_Error('invalid_base64', __('Invalid base64 data.', 'templately'));
266 - }
182 + // Handle the sideload
183 + $id = media_handle_sideload($file, 0);
267 184
268 - // Detect MIME type from decoded image data
269 - $mime_type = self::detect_mime_type_from_data($decoded_image);
270 - if (empty($mime_type)) {
271 - return new \WP_Error('unknown_mime_type', __('Unable to determine image MIME type.', 'templately'));
185 + if (is_wp_error($id)) {
186 + @unlink($file['tmp_name']);
187 + return ['error' => __('Failed to sideload image', 'templately')];
272 188 }
273 189
274 - // Get file extension from MIME type
275 - $extension = self::get_file_extension_by_mime_type($mime_type);
276 - if (empty($extension)) {
277 - return new \WP_Error('unsupported_mime_type', __('Unsupported image MIME type.', 'templately'));
278 - }
279 -
280 - // Generate unique filename
281 - $filename = 'templately-logo-' . \wp_generate_uuid4() . '.' . $extension;
282 -
283 - // Get upload directory
284 - $upload_dir = \wp_upload_dir();
285 - if (!$upload_dir['error']) {
286 - $upload_path = $upload_dir['path'] . '/' . $filename;
287 - } else {
288 - return new \WP_Error('upload_dir_error', __('Unable to access upload directory.', 'templately'));
289 - }
290 -
291 - // Write decoded image to file
292 - if (file_put_contents($upload_path, $decoded_image) === false) {
293 - return new \WP_Error('upload_error', __('Error uploading image.', 'templately'));
294 - }
295 -
296 - // Create attachment post
297 - $attachment_data = [
298 - 'post_mime_type' => $mime_type,
299 - 'post_title' => \sanitize_file_name(pathinfo($filename, PATHINFO_FILENAME)),
300 - 'post_content' => '',
301 - 'post_status' => 'inherit',
190 + return [
191 + 'id' => $id,
192 + 'url' => esc_url_raw(wp_get_attachment_url($id)),
302 193 ];
303 -
304 - $attachment_id = \wp_insert_attachment($attachment_data, $upload_path);
305 - if (is_wp_error($attachment_id)) {
306 - return $attachment_id;
307 - }
308 -
309 - // Ensure WordPress image functions are available
310 - // These functions are defined in wp-admin/includes/image.php which is not always loaded
311 - if (!function_exists('wp_generate_attachment_metadata')) {
312 - require_once(ABSPATH . 'wp-admin/includes/image.php');
313 - }
314 -
315 - // Generate and update attachment metadata
316 - $metadata = \wp_generate_attachment_metadata($attachment_id, $upload_path);
317 - \wp_update_attachment_metadata($attachment_id, $metadata);
318 -
319 - return $attachment_id;
320 194 }
321 -
322 - /**
323 - * Detect MIME type from image data
324 - * Uses finfo_buffer if available, otherwise falls back to getimagesizefromstring
325 - *
326 - * @param string $image_data Raw image data
327 - * @return string|null MIME type or null if unable to detect
328 - */
329 - private static function detect_mime_type_from_data($image_data) {
330 - // Try using finfo_buffer first (most reliable)
331 - if (function_exists('finfo_buffer')) {
332 - $finfo = finfo_open(FILEINFO_MIME_TYPE);
333 - if ($finfo) {
334 - $mime_type = finfo_buffer($finfo, $image_data);
335 - finfo_close($finfo);
336 - if ($mime_type && strpos($mime_type, 'image/') === 0) {
337 - return $mime_type;
338 - }
339 - }
340 - }
341 -
342 - // Fallback: use getimagesizefromstring
343 - if (function_exists('getimagesizefromstring')) {
344 - $image_info = @getimagesizefromstring($image_data);
345 - if ($image_info && isset($image_info['mime'])) {
346 - return $image_info['mime'];
347 - }
348 - }
349 -
350 - return null;
351 - }
352 -
353 - /**
354 - * Get file extension by MIME type
355 - * Uses WordPress built-in functions for MIME type to extension conversion
356 - *
357 - * @since 3.4.5
358 - * @param string $mime_type MIME type (e.g., 'image/png')
359 - * @return string|null File extension without dot, or null if not found
360 - */
361 - private static function get_file_extension_by_mime_type($mime_type) {
362 - // Use WordPress core function if available (WordPress 5.8.1+)
363 - // wp_get_default_extension_for_mime_type() returns the default file extension for a given MIME type
364 - if (function_exists('wp_get_default_extension_for_mime_type')) {
365 - return \wp_get_default_extension_for_mime_type($mime_type);
366 - }
367 -
368 - // Fallback for WordPress < 5.8.1
369 - // Use wp_get_mime_types() which returns array with extensions as keys and MIME types as values
370 - // Example: ['jpg|jpeg|jpe' => 'image/jpeg', 'png' => 'image/png', ...]
371 - $wp_mime_types = \wp_get_mime_types();
372 -
373 - // Flip the array to get MIME type as key and extensions as value
374 - $mime_map = array_flip($wp_mime_types);
375 -
376 - if (isset($mime_map[$mime_type])) {
377 - $extensions = $mime_map[$mime_type];
378 - // Get first extension if multiple are available (e.g., 'jpg|jpeg|jpe' -> 'jpg')
379 - return strtok($extensions, '|');
380 - }
381 -
382 - return null;
383 - }
384 -
385 - /**
386 - * Inserts a template into the Gutenberg editor.
387 - *
388 - * @param mixed $data
389 - * @param int $postId
390 - * @return array
391 - */
392 - public static function import_and_replace_attachments($content, $postId = 0) {
393 - // Instantiate GutenbergHelper
394 - $helper = new GutenbergHelper();
395 -
396 - $data = [
397 - 'content' => $content,
398 - ];
399 -
400 - // Organize URLs from the content
401 - $organizedUrls = $helper->parse_images($data['content']);
402 - if(empty($organizedUrls)){
403 - return $content;
404 - }
405 -
406 - // Define template settings
407 - $template_settings = [
408 - 'post_id' => $postId,
409 - '__attachments' => $organizedUrls,
410 - ];
411 -
412 - // Map post IDs and disable logging
413 - $helper->map_post_ids[$postId] = $postId;
414 - $helper->shouldLog = false;
415 -
416 - // Prepare the helper with the data and settings
417 - $helper->prepare($data, $template_settings);
418 -
419 - // Update the content in the data array
420 - $content = wp_unslash($helper->get_content());
421 -
422 - return $content;
423 - }
424 -
425 - public static function prepare_post_data($image_url, $post_parent = null, $logger = null) {
426 - $filetype = wp_check_filetype(basename($image_url));
427 - if (!$filetype['type']) {
428 - if(is_callable($logger)){
429 - // call the logger function
430 - call_user_func($logger, 'prepare', 'Error: Unable to determine the file type.', -1, 'eventLog');
431 - }
432 - return null;
433 - }
434 -
435 - $post_data = array(
436 - 'post_title' => basename($image_url),
437 - 'post_content' => '',
438 - 'post_status' => 'inherit',
439 - 'post_mime_type' => $filetype['type'],
440 - 'guid' => $image_url,
441 - );
442 -
443 - if($post_parent){
444 - $post_data['post_parent'] = $post_parent; // Set the parent post
445 - }
446 -
447 - if (preg_match('%wp-content/uploads/([0-9]{4}/[0-9]{2})%', $image_url, $matches)) {
448 - $post_data['upload_date'] = $matches[1];
449 - }
450 - else{
451 - $post_data['upload_date'] = date('Y/m');
452 - }
453 -
454 - return $post_data;
455 - }
456 -
457 - // ============================================================================
458 - // Session Data Functions - DEPRECATED: Use SessionData class instead
459 - // ============================================================================
460 -
461 - /**
462 - * @deprecated 3.4.7 Use SessionData::get_session_id() instead
463 - */
464 - public static function get_session_id(){
465 - _deprecated_function(__METHOD__, '3.4.7', 'SessionData::get_session_id()');
466 - return SessionData::get_session_id();
467 - }
468 -
469 - /**
470 - * @deprecated 3.4.7 Use SessionData::save() or SessionData::set() instead
471 - */
472 - public static function update_session_data_by_id($data): bool {
473 - _deprecated_function(__METHOD__, '3.4.7', 'SessionData::save() or SessionData::set()');
474 - if($session_id = SessionData::get_session_id()){
475 - $existing = SessionData::get_data($session_id);
476 - return SessionData::save($session_id, array_merge($existing, $data));
477 - }
478 - return false;
479 - }
480 -
481 - /**
482 - * @deprecated 3.4.7 Use SessionData::clean_by_pack_id() instead
483 - */
484 - public static function clean_session_data_by_pack_id($pack_id, $current_session_id) {
485 - _deprecated_function(__METHOD__, '3.4.7', 'SessionData::clean_by_pack_id()');
486 - return SessionData::clean_by_pack_id($pack_id, $current_session_id);
487 - }
488 -
489 - /**
490 - * @deprecated 3.4.7 Use SessionData::cleanup_expired() instead
491 - */
492 - public static function cleanup_expired_sessions($max_age_days = 7) {
493 - _deprecated_function(__METHOD__, '3.4.7', 'SessionData::cleanup_expired()');
494 - return SessionData::cleanup_expired($max_age_days);
495 - }
496 -
497 -
498 -
499 - /**
500 - * Clean up directory using RecursiveIteratorIterator approach
501 - * This method handles directory cleanup with proper validation
502 - *
503 - * @param string $dir_path The directory path to clean up
504 - * @return bool True on success, false on failure
505 - */
506 - public static function cleanup_directory($dir_path) {
507 - if (empty($dir_path) || !file_exists($dir_path) || !is_dir($dir_path)) {
508 - return false;
509 - }
510 -
511 - try {
512 - $files = new \RecursiveIteratorIterator(
513 - new \RecursiveDirectoryIterator($dir_path, \RecursiveDirectoryIterator::SKIP_DOTS),
514 - \RecursiveIteratorIterator::CHILD_FIRST
515 - );
516 -
517 - foreach ($files as $fileinfo) {
518 - $todo = ($fileinfo->isDir() ? 'rmdir' : 'unlink');
519 - $todo($fileinfo->getRealPath());
520 - }
521 -
522 - rmdir($dir_path);
523 - return true;
524 - } catch (Exception $e) {
525 - return false;
526 - }
527 - }
528 -
529 -}
195 +}