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.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 +93 -211 3.7.53.4.9 View file →
@@ -2,10 +2,8 @@
2 2
3 3 namespace Templately\Core\Importer\Utils;
4 4
5 5 use Exception;
6 -use Templately\Builder\PageTemplates;
7 -use Templately\Builder\Factory\TemplateFactory;
8 6 use Templately\Core\Importer\FullSiteImport;
9 7 use Templately\Core\Importer\WPImport;
10 8 use Templately\Utils\Base;
11 9 use Templately\Utils\Helper;
@@ -11,26 +9,9 @@
11 9 use Templately\Utils\Helper;
12 10
13 11 class Utils extends Base {
14 12
15 - /**
16 - * Filter callback to prefer the GD image editor over Imagick during imports.
17 - * Imagick can fail on certain server configurations; GD is more reliable for
18 - * the resize/crop operations triggered by wp_generate_attachment_metadata().
19 - */
20 - public static function prefer_gd_editor( $editors ) {
21 - if ( is_callable( [ 'WP_Image_Editor_GD', 'test' ] ) && call_user_func( [ 'WP_Image_Editor_GD', 'test' ] ) ) {
22 - return [ 'WP_Image_Editor_GD' ];
23 - }
24 - return $editors;
25 - }
26 13
27 - public static function add_gd_editor_filter() {
28 - if ( ! has_filter( 'wp_image_editors', [ self::class, 'prefer_gd_editor' ] ) ) {
29 - add_filter( 'wp_image_editors', [ self::class, 'prefer_gd_editor' ] );
30 - }
31 - }
32 -
33 14 /**
34 15 * @throws Exception
35 16 */
36 17 public static function read_json_file( $path ) {
@@ -166,137 +147,8 @@
166 147 self::backup_option_value($key, $autoload);
167 148 return update_option($key, $value, $autoload);
168 149 }
169 150
170 - /**
171 - * Create the WordPress page an archive-type template attaches to, and wire up
172 - * the matching WP/WooCommerce/LearnDash setting.
173 - *
174 - * Shared by the FSI Templates runner and single-template Library imports so both
175 - * produce the same companion page + settings (page_for_posts,
176 - * woocommerce_shop_page_id, LearnDash courses slug).
177 - *
178 - * @param array $template_settings Needs 'type'; optional 'title' and 'page_settings.archive_page_id'.
179 - * @param string $platform 'elementor' | 'gutenberg'.
180 - * @param array $manifest FSI manifest (optional). Only used to skip creation when the
181 - * archive page is already part of the imported content.
182 - *
183 - * @return false|int New page ID, or false on skip/failure.
184 - */
185 - public static function create_archive_page( $template_settings, $platform, $manifest = [] ) {
186 - try {
187 - $archive_page_id = $template_settings['page_settings']['archive_page_id'] ?? null;
188 - if ( $archive_page_id && ! empty( $manifest['content']['page'][ $archive_page_id ] ) ) {
189 - return false;
190 - }
191 -
192 - $type = $template_settings['type'];
193 -
194 - $archive_page = wp_insert_post( [
195 - 'post_title' => $template_settings['title'] ?? ucfirst( $type ) . ' - (by Templately)',
196 - 'post_status' => 'publish',
197 - 'post_type' => 'page',
198 - 'post_content' => '',
199 - 'page_template' => $platform === 'elementor' ? 'elementor_header_footer' : PageTemplates::TEMPLATE_HEADER_FOOTER,
200 - ] );
201 -
202 - if ( is_wp_error( $archive_page ) ) {
203 - return false;
204 - }
205 -
206 - if ( $type === 'archive' ) {
207 - self::update_option( 'page_for_posts', $archive_page );
208 - }
209 -
210 - if ( $type === 'product_archive' ) {
211 - self::update_option( 'woocommerce_shop_page_id', $archive_page );
212 - }
213 -
214 - if ( $type === 'course_archive' ) {
215 - // get page slug from $archive_page id and update learndash_settings_permalinks option to courses.
216 - $post_name = get_post_field( 'post_name', $archive_page );
217 -
218 - if ( class_exists( '\LearnDash_Settings_Section' ) ) {
219 - $section = \LearnDash_Settings_Section::get_section_instance( 'LearnDash_Settings_Section_Permalinks' );
220 - if ( ! empty( $section ) ) {
221 - $section->set_setting( 'courses', $post_name );
222 - if ( function_exists( 'learndash_setup_rewrite_flush' ) ) {
223 - learndash_setup_rewrite_flush();
224 - }
225 - }
226 - }
227 - }
228 -
229 - return $archive_page;
230 - } catch ( \Exception $e ) {
231 - return false;
232 - }
233 - }
234 -
235 - /**
236 - * Create a single-page Library template carrying a post-content widget/block,
237 - * so a fluent_product_single import has a page template to render into.
238 - *
239 - * Shared by the FSI Templates runner and single-template Library imports.
240 - *
241 - * @param string $platform 'elementor' | 'gutenberg'.
242 - *
243 - * @return void
244 - */
245 - public static function create_page_template( $platform ) {
246 - try {
247 - $meta = [];
248 - $data = [];
249 -
250 - $post_data = [
251 - 'post_title' => 'Single Page - (by Templately)',
252 - 'post_status' => 'publish',
253 - 'post_type' => 'templately_library',
254 - ];
255 -
256 - if ( $platform === 'elementor' ) {
257 - $meta['_wp_page_template'] = 'elementor_header_footer';
258 - $data = json_decode( '{"content":[{"id":"4a86515d","settings":[],"elements":[{"id":"30a46db1","settings":{"content_width":"full"},"elements":[],"isInner":false,"widgetType":"tl-post-content","elType":"widget"}],"isInner":false,"elType":"container"}],"settings":{"template":"elementor_header_footer"},"metadata":[]}', true );
259 - } elseif ( $platform === 'gutenberg' ) {
260 - $meta['_wp_page_template'] = PageTemplates::TEMPLATE_HEADER_FOOTER;
261 - $data = [ 'content' => '<!-- wp:post-content /-->' ];
262 - }
263 -
264 - $factory = new TemplateFactory( $platform );
265 - $template = $factory->create( 'page_single', $post_data, $meta );
266 - $template->import( $data );
267 - } catch ( \Exception $e ) {
268 - return;
269 - }
270 - }
271 -
272 - /**
273 - * Run the companion-content side effects for a freshly imported Library template.
274 - *
275 - * Dispatches by resolved Builder type:
276 - * - archive / product_archive / course_archive → attached WP page + settings
277 - * - fluent_product_single → single-page template
278 - *
279 - * Convenience wrapper for single-template imports, which have no FSI manifest.
280 - *
281 - * @param string $type Resolved Builder type key.
282 - * @param string $title Template title (used for the created page).
283 - * @param string $platform 'elementor' | 'gutenberg'.
284 - *
285 - * @return false|int|null Archive page ID for archive types, null otherwise.
286 - */
287 - public static function create_companion_content( $type, $title, $platform ) {
288 - if ( in_array( $type, [ 'archive', 'product_archive', 'course_archive' ], true ) ) {
289 - return self::create_archive_page( [ 'title' => $title, 'type' => $type ], $platform );
290 - }
291 -
292 - if ( $type === 'fluent_product_single' ) {
293 - self::create_page_template( $platform );
294 - }
295 -
296 - return null;
297 - }
298 -
299 151 public static function import_page_settings( $id, $settings ) {
300 152 $extra_settings = [
301 153 'page_on_front' => [
302 154 'show_on_front' => 'page'
@@ -349,26 +201,8 @@
349 201 ];
350 202 }
351 203
352 204 /**
353 - * Get a remote logo URL from the supported import payload shapes.
354 - *
355 - * @param mixed $logo A URL string or an array containing a URL.
356 - * @return string
357 - */
358 - public static function get_logo_url( $logo ) {
359 - if ( is_string( $logo ) ) {
360 - return $logo;
361 - }
362 -
363 - if ( is_array( $logo ) && isset( $logo['url'] ) && is_string( $logo['url'] ) ) {
364 - return $logo['url'];
365 - }
366 -
367 - return '';
368 - }
369 -
370 - /**
371 205 * Upload base64 encoded image to media library
372 206 *
373 207 * @param string $base64 Base64 encoded image data (with or without data URI scheme)
374 208 * @param string $session_id Session ID for tracking (reserved for future use)
@@ -396,19 +230,11 @@
396 230 * Upload base64 encoded image without dependency on prepare_post_data
397 231 * Handles MIME type detection and proper file extension assignment
398 232 *
399 233 * @param string $base64 Base64 encoded image data (with or without data URI scheme)
400 - * @return int|\WP_Error Attachment ID on success, WP_Error on failure
234 + * @return int|WP_Error Attachment ID on success, WP_Error on failure
401 235 */
402 236 public static function upload_base64_image($base64) {
403 - // Strip data URL prefix if present (e.g., "data:image/png;base64,")
404 - if (strpos($base64, 'data:image/') === 0) {
405 - $base64_parts = explode(',', $base64, 2);
406 - if (isset($base64_parts[1])) {
407 - $base64 = $base64_parts[1];
408 - }
409 - }
410 -
411 237 // Decode base64 string
412 238 $decoded_image = base64_decode($base64, true);
413 239 if ($decoded_image === false) {
414 240 return new \WP_Error('invalid_base64', __('Invalid base64 data.', 'templately'));
@@ -537,16 +363,12 @@
537 363 * @param mixed $data
538 364 * @param int $postId
539 365 * @return array
540 366 */
541 - public static function import_and_replace_attachments($content, $postId = 0, $attachment_options = []) {
367 + public static function import_and_replace_attachments($content, $postId = 0) {
542 368 // Instantiate GutenbergHelper
543 369 $helper = new GutenbergHelper();
544 370
545 - if ( ! empty( $attachment_options ) ) {
546 - $helper->set_attachment_options( $attachment_options );
547 - }
548 -
549 371 $data = [
550 372 'content' => $content,
551 373 ];
552 374
@@ -606,50 +428,62 @@
606 428
607 429 return $post_data;
608 430 }
609 431
610 - // ============================================================================
611 - // Session Data Functions - DEPRECATED: Use SessionData class instead
612 - // ============================================================================
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 + }
613 437
614 - /**
615 - * @deprecated 3.4.7 Use SessionData::get_session_id() instead
616 - */
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 +
617 462 public static function get_session_id(){
618 - _deprecated_function(__METHOD__, '3.4.7', 'SessionData::get_session_id()');
619 - return SessionData::get_session_id();
463 + $session_id = null;
464 + if(!empty($_REQUEST['session_id'])){
465 + $session_id = sanitize_text_field($_REQUEST['session_id']);
466 + }
467 + return $session_id;
620 468 }
621 469
622 - /**
623 - * @deprecated 3.4.7 Use SessionData::save() or SessionData::set() instead
624 - */
625 - public static function update_session_data_by_id($data): bool {
626 - _deprecated_function(__METHOD__, '3.4.7', 'SessionData::save() or SessionData::set()');
627 - if($session_id = SessionData::get_session_id()){
628 - $existing = SessionData::get_data($session_id);
629 - return SessionData::save($session_id, array_merge($existing, $data));
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);
630 473 }
631 - return false;
474 + throw new Exception(__('Invalid Session ID.', 'templately'));
632 475 }
633 476
634 - /**
635 - * @deprecated 3.4.7 Use SessionData::clean_by_pack_id() instead
636 - */
637 - public static function clean_session_data_by_pack_id($pack_id, $current_session_id) {
638 - _deprecated_function(__METHOD__, '3.4.7', 'SessionData::clean_by_pack_id()');
639 - return SessionData::clean_by_pack_id($pack_id, $current_session_id);
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'));
640 482 }
641 483
642 - /**
643 - * @deprecated 3.4.7 Use SessionData::cleanup_expired() instead
644 - */
645 - public static function cleanup_expired_sessions($max_age_days = 7) {
646 - _deprecated_function(__METHOD__, '3.4.7', 'SessionData::cleanup_expired()');
647 - return SessionData::cleanup_expired($max_age_days);
648 - }
649 484
650 485
651 -
652 486 /**
653 487 * Clean up directory using RecursiveIteratorIterator approach
654 488 * This method handles directory cleanup with proper validation
655 489 *
@@ -677,6 +511,54 @@
677 511 } catch (Exception $e) {
678 512 return false;
679 513 }
680 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 +
681 563
682 564 }