PluginProbe
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! / 3.6.0
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! v3.6.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 3.1.10 All 111 releases
templately / includes / Core / Importer / Utils / Utils.php

Utils.php in Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! 3.6.0, at includes/Core/Importer/Utils/Utils.php

530 lines 15.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Templately\Core\Importer\Utils;
4
5 use Exception;
6 use Templately\Core\Importer\FullSiteImport;
7 use Templately\Core\Importer\WPImport;
8 use Templately\Utils\Base;
9 use Templately\Utils\Helper;
10
11 class Utils extends Base {
12
13 /**
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 * @throws Exception
33 */
34 public static function read_json_file( $path ) {
35 if ( ! file_exists( $path ) ) {
36 throw new Exception( __( 'JSON file not exists. ' . basename( $path ), 'templately' ) );
37 }
38
39 $file_content = self::file_get_contents( $path );
40
41 return $file_content ? json_decode( $file_content, true ) : [];
42 }
43
44 /**
45 * @param $file
46 * @param mixed ...$args
47 *
48 * @return false|string
49 */
50 public static function file_get_contents( $file, ...$args ) {
51 if ( ! is_file( $file ) || ! is_readable( $file ) ) {
52 return false;
53 }
54
55 return file_get_contents( $file, ...$args );
56 }
57
58 public static function get_builtin_wp_post_types(): array {
59 $post_type_args = [
60 'show_in_nav_menus' => true,
61 'public' => true
62 ];
63 $_post_types = get_post_types( $post_type_args, 'objects' );
64
65 return array_merge( array_keys( $_post_types ), [ 'nav_menu_item', 'wp_navigation' ] );
66 }
67
68 public static function map_old_new_post_ids( array $imported_data ) {
69 $result = [];
70
71 $result += $imported_data['templates']['succeed'] ?? [];
72
73 if ( isset( $imported_data['content'] ) ) {
74 foreach ( $imported_data['content'] as $post_type ) {
75 $result += $post_type['succeed'] ?? [];
76 }
77 }
78
79 if ( isset( $imported_data['wp-content'] ) ) {
80 foreach ( $imported_data['wp-content'] as $post_type ) {
81 $result += $post_type['succeed'] ?? [];
82 }
83 }
84
85 // add attachments data
86 if ( !empty( $imported_data['attachments']['succeed'] ) ) {
87 $result += $imported_data['attachments']['succeed'] ?? [];
88 }
89
90
91 return $result;
92 }
93
94 public static function map_old_new_term_ids( array $imported_data ) {
95 $result = [];
96
97 if ( isset( $imported_data['terms'] ) ) {
98 foreach ( $imported_data['terms'] as $post_type ) {
99 $result += $post_type['succeed'] ?? [];
100 }
101 }
102
103 return $result;
104 }
105
106 public static function map_old_new_term_ids_el( array $imported_data ): array {
107 $result = [];
108
109 if ( ! isset( $imported_data['taxonomies'] ) ) {
110 return $result;
111 }
112
113 foreach ( $imported_data['taxonomies'] as $post_type_taxonomies ) {
114 foreach ( $post_type_taxonomies as $taxonomy ) {
115 foreach ( $taxonomy as $term ) {
116 $result[ $term['old_id'] ] = $term['new_id'];
117 }
118 }
119 }
120
121 return $result;
122 }
123
124 /**
125 * @param string $platform
126 *
127 * @return ImportHelper
128 */
129 public static function get_json_helper( string $platform ) {
130 return $platform === 'elementor' ? new ElementorHelper() : new GutenbergHelper();
131 }
132
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);
148 }
149
150 return $templately_options;
151 }
152
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 public static function import_page_settings( $id, $settings ) {
169 $extra_settings = [
170 'page_on_front' => [
171 'show_on_front' => 'page'
172 ]
173 ];
174 if ( isset( $settings['page_for_posts'] ) && $settings['page_for_posts'] ) {
175 self::update_option( 'page_for_posts', $id );
176 }
177 if ( isset( $settings['show_on_front'] ) && $settings['show_on_front'] ) {
178 self::update_option( 'page_on_front', $id );
179 self::update_option( 'show_on_front', 'page' );
180 }
181 if ( ! empty( $settings['page_settings'] ) ) {
182 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 );
188 if ( array_key_exists( $option_name, $extra_settings ) ) {
189 foreach ( $extra_settings[ $option_name ] as $name => $value ) {
190 self::update_option( $name, $value );
191 }
192 }
193 }
194 }
195 }
196
197 public static function upload_logo($url, $session_id) {
198 if(empty($url)) {
199 return ['error' => __('URL is empty', 'templately')];
200 }
201
202 // Validate URL and ensure scheme is present
203 if ( ! wp_http_validate_url( $url ) || !parse_url( $url, PHP_URL_SCHEME ) ) {
204 return ['error' => __('Invalid URL', 'templately')];
205 }
206
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()];
213 }
214
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')];
231 }
232
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()];
238 }
239
240 return [
241 'id' => (int) $attachment_id,
242 'url' => esc_url_raw(wp_get_attachment_url($attachment_id)),
243 ];
244 }
245
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 }
261
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 }
267
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'));
272 }
273
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',
302 ];
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 }
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 }
530