PluginProbe
King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder / 51.1.14
King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder v51.1.14
51.1.87 51.1.86 51.1.84 51.1.85 51.1.83 51.1.82 51.1.81 51.1.79 51.1.78 51.1.77 51.1.76 51.1.74 51.1.75 51.1.65 51.1.64 51.1.63 trunk 51.1.14 51.1.2 51.1.35 51.1.36 51.1.37 51.1.38 51.1.39 51.1.44 All 41 releases
king-addons / includes / extensions / Template_Catalog_Button / Template_Catalog_Button.php

Template_Catalog_Button.php in King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder 51.1.14, at includes/extensions/Template_Catalog_Button/Template_Catalog_Button.php

888 lines 32.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Template Catalog Button Extension
5 *
6 * Adds a button to Elementor editor panel that opens King Addons template catalog in popup
7 */
8
9 namespace King_Addons;
10
11 if (!defined('ABSPATH')) {
12 exit; // Exit if accessed directly.
13 }
14
15 class Template_Catalog_Button
16 {
17 /**
18 * Instance
19 *
20 * @var Template_Catalog_Button|null The single instance of the class.
21 */
22 private static ?Template_Catalog_Button $_instance = null;
23
24 /**
25 * Instance
26 *
27 * Ensures only one instance of the class is loaded or can be loaded.
28 *
29 * @return Template_Catalog_Button An instance of the class.
30 */
31 public static function instance(): Template_Catalog_Button
32 {
33 if (is_null(self::$_instance)) {
34 self::$_instance = new self();
35 }
36 return self::$_instance;
37 }
38
39 /**
40 * Constructor
41 */
42 public function __construct()
43 {
44 // Only load if templates catalog is enabled
45 if (!KING_ADDONS_EXT_TEMPLATES_CATALOG) {
46 return;
47 }
48
49 // Hook into Elementor editor
50 add_action('elementor/editor/before_enqueue_scripts', [$this, 'enqueue_editor_scripts'], 10);
51 add_action('elementor/editor/after_enqueue_styles', [$this, 'enqueue_editor_styles'], 10);
52
53 // AJAX endpoints for template catalog in editor
54 add_action('wp_ajax_king_addons_get_template_catalog', [$this, 'get_template_catalog']);
55 add_action('wp_ajax_king_addons_import_template_to_page', [$this, 'import_template_to_page']);
56 add_action('wp_ajax_king_addons_import_template_content', [$this, 'import_template_content']);
57
58 // New endpoint for merging with existing page
59 add_action('wp_ajax_king_addons_merge_with_existing_page', [$this, 'merge_with_existing_page']);
60
61 // Sections catalog endpoint
62 add_action('wp_ajax_king_addons_get_sections_catalog', [$this, 'get_sections_catalog']);
63
64 // Section import endpoints
65 add_action('wp_ajax_king_addons_import_section_to_page', [$this, 'import_section_to_page']);
66 }
67
68 /**
69 * Enqueue scripts for Elementor editor
70 */
71 public function enqueue_editor_scripts(): void
72 {
73 wp_enqueue_script(
74 'king-addons-template-catalog-button',
75 KING_ADDONS_URL . 'includes/extensions/Template_Catalog_Button/assets/template-catalog-button.js',
76 ['jquery', 'elementor-editor'],
77 KING_ADDONS_VERSION,
78 true
79 );
80
81 // Get current post ID if available
82 $current_post_id = 0;
83 if (isset($_GET['post'])) {
84 $current_post_id = intval($_GET['post']);
85 } elseif (isset($_GET['post_id'])) {
86 $current_post_id = intval($_GET['post_id']);
87 }
88
89 // Localize script with template catalog data
90 wp_localize_script(
91 'king-addons-template-catalog-button',
92 'kingAddonsTemplateCatalog',
93 [
94 'templateCatalogUrl' => admin_url('admin.php?page=king-addons-templates'),
95 'templatesEnabled' => KING_ADDONS_EXT_TEMPLATES_CATALOG,
96 'buttonText' => $this->get_button_text(),
97 'nonce' => wp_create_nonce('king_addons_template_catalog'),
98 'ajaxUrl' => admin_url('admin-ajax.php'),
99 'isPremium' => function_exists('king_addons_freemius') && king_addons_freemius()->can_use_premium_code(),
100 'currentPostId' => $current_post_id,
101 'adminUrl' => admin_url(),
102 'pluginUrl' => KING_ADDONS_URL,
103 ]
104 );
105 }
106
107 /**
108 * Enqueue styles for Elementor editor
109 */
110 public function enqueue_editor_styles(): void
111 {
112 wp_enqueue_style(
113 'king-addons-template-catalog-popup',
114 KING_ADDONS_URL . 'includes/extensions/Template_Catalog_Button/assets/template-catalog-popup.css',
115 [],
116 KING_ADDONS_VERSION
117 );
118 }
119
120 /**
121 * Get button text based on user's subscription level
122 */
123 private function get_button_text(): string
124 {
125 if (function_exists('king_addons_freemius') && king_addons_freemius()->can_use_premium_code()) {
126 return esc_html__('Templates Pro', 'king-addons');
127 }
128
129 return esc_html__('Free Templates', 'king-addons');
130 }
131
132 /**
133 * AJAX handler for getting template catalog data
134 */
135 public function get_template_catalog(): void
136 {
137 if (!current_user_can('edit_posts')) {
138 wp_send_json_error('Insufficient permissions');
139 return;
140 }
141
142 if (!wp_verify_nonce($_POST['nonce'], 'king_addons_template_catalog')) {
143 wp_send_json_error('Invalid nonce');
144 return;
145 }
146
147 $templates = \King_Addons\TemplatesMap::getTemplatesMapArray();
148 $collections = \King_Addons\CollectionsMap::getCollectionsMapArray();
149
150 $is_premium_active = function_exists('king_addons_freemius') && king_addons_freemius()->can_use_premium_code();
151
152 // Get filters from request
153 $search_query = isset($_POST['search']) ? sanitize_text_field($_POST['search']) : '';
154 $selected_category = isset($_POST['category']) ? sanitize_text_field($_POST['category']) : '';
155 $selected_collection = isset($_POST['collection']) ? sanitize_text_field($_POST['collection']) : '';
156 $current_page = isset($_POST['page']) ? max(1, intval($_POST['page'])) : 1;
157
158 // Get categories and tags
159 $categories = [];
160 $tags = [];
161 $category_counts = [];
162
163 foreach ($templates['templates'] as $template) {
164 if (!in_array($template['category'], $categories)) {
165 $categories[] = $template['category'];
166 }
167
168 foreach ($template['tags'] as $tag) {
169 if (!in_array($tag, $tags)) {
170 $tags[] = $tag;
171 }
172 }
173
174 $category = $template['category'];
175 $category_counts[$category] = isset($category_counts[$category]) ? $category_counts[$category] + 1 : 1;
176 }
177
178 sort($categories);
179
180 // Filter templates
181 $filtered_templates = $templates['templates'];
182
183 // Apply filters
184 if (!empty($search_query)) {
185 $matched_by_title = [];
186 $matched_by_tags = [];
187
188 foreach ($filtered_templates as $template_key => $template) {
189 $found_in_title = stripos($template['title'], $search_query) !== false;
190 $found_in_tags = false;
191
192 foreach ($template['tags'] as $tag) {
193 if (stripos($tag, $search_query) !== false) {
194 $found_in_tags = true;
195 break;
196 }
197 }
198
199 if ($found_in_title) {
200 $template['template_key'] = $template_key;
201 $matched_by_title[] = $template;
202 } elseif ($found_in_tags) {
203 $template['template_key'] = $template_key;
204 $matched_by_tags[] = $template;
205 }
206 }
207
208 $filtered_templates = array_merge($matched_by_title, $matched_by_tags);
209 } else {
210 // Add template keys for non-search results
211 $temp_templates = [];
212 foreach ($filtered_templates as $key => $template) {
213 $template['template_key'] = $key;
214 $temp_templates[] = $template;
215 }
216 $filtered_templates = $temp_templates;
217 }
218
219 if (!empty($selected_category)) {
220 $filtered_templates = array_filter($filtered_templates, function($template) use ($selected_category) {
221 return $template['category'] === $selected_category;
222 });
223 }
224
225 if (!empty($selected_collection)) {
226 $filtered_templates = array_filter($filtered_templates, function($template) use ($selected_collection) {
227 return $template['collection'] == $selected_collection;
228 });
229 }
230
231 // Pagination
232 $items_per_page = 20;
233 $total_templates = count($filtered_templates);
234 $total_pages = ceil($total_templates / $items_per_page);
235 $offset = ($current_page - 1) * $items_per_page;
236 $paged_templates = array_slice($filtered_templates, $offset, $items_per_page);
237
238 wp_send_json_success([
239 'templates' => $paged_templates,
240 'categories' => $categories,
241 'collections' => $collections,
242 'category_counts' => $category_counts,
243 'pagination' => [
244 'current_page' => $current_page,
245 'total_pages' => $total_pages,
246 'total_templates' => $total_templates,
247 'items_per_page' => $items_per_page
248 ],
249 'is_premium_active' => $is_premium_active
250 ]);
251 }
252
253 /**
254 * AJAX handler for importing template to current page
255 */
256 public function import_template_to_page(): void
257 {
258 if (!current_user_can('edit_posts')) {
259 wp_send_json_error('Insufficient permissions');
260 return;
261 }
262
263 if (!wp_verify_nonce($_POST['nonce'], 'king_addons_template_catalog')) {
264 wp_send_json_error('Invalid nonce');
265 return;
266 }
267
268 $template_key = sanitize_text_field($_POST['template_key']);
269 $template_plan = sanitize_text_field($_POST['template_plan']);
270 $is_premium_active = function_exists('king_addons_freemius') && king_addons_freemius()->can_use_premium_code();
271
272 // Determine API URL and install ID
273 if ($is_premium_active && $template_plan === 'premium') {
274 $api_url = 'https://api.kingaddons.com/get-template.php';
275
276 // Use the same method as original templates catalog
277 if (function_exists('king_addons_freemius')) {
278 $freemius_site = king_addons_freemius()->get_site();
279 $install_id = $freemius_site ? $freemius_site->id : 0;
280 } else {
281 $install_id = 0;
282 }
283
284 error_log('King Addons Premium Template: Using install_id: ' . $install_id . ' for premium template: ' . $template_key);
285 } elseif ($template_plan === 'free') {
286 $api_url = 'https://api.kingaddons.com/get-template-free.php';
287 $install_id = 0;
288 error_log('King Addons Free Template: Fetching free template: ' . $template_key);
289 } else {
290 error_log('King Addons Template Error: Premium template requires premium license. Template: ' . $template_key . ', Plan: ' . $template_plan . ', Premium Active: ' . ($is_premium_active ? 'Yes' : 'No'));
291 wp_send_json_error('Premium template requires premium license');
292 return;
293 }
294
295 // Get template data from API
296 $response = wp_remote_post($api_url, [
297 'headers' => ['Content-Type' => 'application/json'],
298 'body' => json_encode([
299 'key' => $template_key,
300 'install' => $install_id,
301 ]),
302 'timeout' => 60
303 ]);
304
305 if (is_wp_error($response)) {
306 wp_send_json_error('Failed to fetch template: ' . $response->get_error_message());
307 return;
308 }
309
310 $body = wp_remote_retrieve_body($response);
311 $data = json_decode($body, true);
312
313 error_log('King Addons API Response: ' . substr($body, 0, 500) . (strlen($body) > 500 ? '...' : ''));
314
315 if (!$data) {
316 error_log('King Addons Template Error: Failed to decode JSON response');
317 wp_send_json_error('Invalid JSON response from template API');
318 return;
319 }
320
321 if (!isset($data['success']) || !$data['success']) {
322 $error_message = isset($data['message']) ? $data['message'] : 'Unknown API error';
323 error_log('King Addons Template Error: API returned error: ' . $error_message);
324 wp_send_json_error('Template API error: ' . $error_message);
325 return;
326 }
327
328 // Return template data for frontend processing
329 wp_send_json_success([
330 'template_data' => $data['landing'],
331 'message' => 'Template data retrieved successfully'
332 ]);
333 }
334
335 /**
336 * AJAX handler for importing template content directly into current page
337 */
338 public function import_template_content(): void
339 {
340 if (!current_user_can('edit_posts')) {
341 wp_send_json_error('Insufficient permissions');
342 return;
343 }
344
345 if (!wp_verify_nonce($_POST['nonce'], 'king_addons_template_catalog')) {
346 wp_send_json_error('Invalid nonce');
347 return;
348 }
349
350 $template_data = json_decode(stripslashes($_POST['template_data']), true);
351 $page_id = intval($_POST['page_id']);
352
353 error_log('King Addons Template Import: Starting import for page ID: ' . $page_id);
354 error_log('King Addons Template Import: Template data keys: ' . json_encode(array_keys($template_data ?: [])));
355
356 if (!$template_data || !$page_id) {
357 error_log('King Addons Template Import: Invalid data - template_data: ' . (!empty($template_data) ? 'valid' : 'invalid') . ', page_id: ' . $page_id);
358 wp_send_json_error('Invalid template data or page ID');
359 return;
360 }
361
362 // Get current page Elementor data
363 $current_data = get_post_meta($page_id, '_elementor_data', true);
364 $current_elements = json_decode($current_data, true);
365
366 if (!is_array($current_elements)) {
367 $current_elements = [];
368 }
369
370 // Parse template content
371 $template_content = isset($template_data['content']) ? $template_data['content'] : null;
372 if (!$template_content) {
373 wp_send_json_error('No template content found');
374 return;
375 }
376
377 // If template_content is a string, decode it
378 if (is_string($template_content)) {
379 $template_content = json_decode($template_content, true);
380 }
381
382 if (!is_array($template_content)) {
383 wp_send_json_error('Invalid template content format');
384 return;
385 }
386
387 // Process images in template content
388 $image_map = [];
389 $images_processed = 0;
390 $images_failed = 0;
391
392 if (isset($template_data['images']) && is_array($template_data['images'])) {
393 error_log('King Addons Template Import: Processing ' . count($template_data['images']) . ' images');
394
395 foreach ($template_data['images'] as $image) {
396 // Download and import image
397 $new_image_id = $this->download_and_import_image($image['url']);
398 if ($new_image_id) {
399 $image_map[$image['id']] = $new_image_id;
400 $images_processed++;
401 error_log('King Addons Template Import: Successfully imported image ' . $image['url'] . ' as ID ' . $new_image_id);
402 } else {
403 $images_failed++;
404 error_log('King Addons Template Import: Failed to import image ' . $image['url']);
405 }
406 }
407
408 error_log('King Addons Template Import: Images summary - processed: ' . $images_processed . ', failed: ' . $images_failed);
409 } else {
410 error_log('King Addons Template Import: No images to process');
411 }
412
413 // Replace image IDs in template content
414 $template_content = $this->replace_image_ids($template_content, $image_map);
415
416 // Merge template content with current page content
417 $current_count = count($current_elements);
418 $new_count = count($template_content);
419 $merged_elements = array_merge($current_elements, $template_content);
420 $total_count = count($merged_elements);
421
422 error_log('King Addons Template Import: Merging content - current: ' . $current_count . ', new: ' . $new_count . ', total: ' . $total_count);
423
424 // Update page meta
425 $update_result = update_post_meta($page_id, '_elementor_data', wp_slash(json_encode($merged_elements)));
426 update_post_meta($page_id, '_elementor_edit_mode', 'builder');
427
428 error_log('King Addons Template Import: Page meta updated - result: ' . ($update_result ? 'success' : 'failed'));
429
430 // Clear Elementor cache
431 if (class_exists('\Elementor\Plugin')) {
432 \Elementor\Plugin::$instance->files_manager->clear_cache();
433 error_log('King Addons Template Import: Elementor cache cleared');
434 } else {
435 error_log('King Addons Template Import: Elementor Plugin class not found, cache not cleared');
436 }
437
438 error_log('King Addons Template Import: Import completed successfully');
439
440 wp_send_json_success([
441 'message' => 'Template imported successfully',
442 'imported_elements' => $new_count,
443 'images_processed' => $images_processed,
444 'images_failed' => $images_failed,
445 'page_id' => $page_id,
446 'current_elements_before' => $current_count,
447 'total_elements_after' => $total_count
448 ]);
449 }
450
451 /**
452 * Download and import image to WordPress media library
453 */
454 private function download_and_import_image($image_url): ?int
455 {
456 try {
457 $response = wp_remote_get($image_url, ['timeout' => 30]);
458
459 if (is_wp_error($response)) {
460 return null;
461 }
462
463 $status_code = wp_remote_retrieve_response_code($response);
464 if ($status_code !== 200) {
465 return null;
466 }
467
468 $image_data = wp_remote_retrieve_body($response);
469 if (empty($image_data)) {
470 return null;
471 }
472
473 $image_name = pathinfo(basename($image_url), PATHINFO_FILENAME);
474 $image_extension = pathinfo(basename($image_url), PATHINFO_EXTENSION);
475 $unique_image_name = $image_name . '-' . time() . '.' . $image_extension;
476
477 $upload_dir = wp_upload_dir();
478 if (!file_exists($upload_dir['path'])) {
479 wp_mkdir_p($upload_dir['path']);
480 }
481 $image_file = $upload_dir['path'] . '/' . $unique_image_name;
482
483 if (file_put_contents($image_file, $image_data) === false) {
484 return null;
485 }
486
487 $wp_filetype = wp_check_filetype($unique_image_name);
488 $attachment = [
489 'post_mime_type' => $wp_filetype['type'],
490 'post_title' => sanitize_file_name($unique_image_name),
491 'post_content' => '',
492 'post_status' => 'inherit',
493 ];
494
495 $attach_id = wp_insert_attachment($attachment, $image_file);
496
497 require_once(ABSPATH . 'wp-admin/includes/image.php');
498 $attach_data = wp_generate_attachment_metadata($attach_id, $image_file);
499 wp_update_attachment_metadata($attach_id, $attach_data);
500
501 return $attach_id;
502
503 } catch (\Exception $e) {
504 return null;
505 }
506 }
507
508 /**
509 * Replace image IDs in template content
510 */
511 private function replace_image_ids($content, $image_map): array
512 {
513 if (!is_array($content)) {
514 return $content;
515 }
516
517 foreach ($content as &$element) {
518 if (isset($element['settings'])) {
519 $element['settings'] = $this->replace_image_ids_in_settings($element['settings'], $image_map);
520 }
521
522 if (isset($element['elements']) && is_array($element['elements'])) {
523 $element['elements'] = $this->replace_image_ids($element['elements'], $image_map);
524 }
525 }
526
527 return $content;
528 }
529
530 /**
531 * Generate new unique IDs for all elements to avoid conflicts on repeated imports
532 */
533 private function regenerate_element_ids($content): array
534 {
535 if (!is_array($content)) {
536 return $content;
537 }
538
539 foreach ($content as &$element) {
540 // Generate new unique ID for this element
541 if (isset($element['id'])) {
542 $element['id'] = $this->generate_unique_elementor_id();
543 }
544
545 // Process nested elements recursively
546 if (isset($element['elements']) && is_array($element['elements'])) {
547 $element['elements'] = $this->regenerate_element_ids($element['elements']);
548 }
549 }
550
551 return $content;
552 }
553
554 /**
555 * Generate a unique Elementor-style ID
556 */
557 private function generate_unique_elementor_id(): string
558 {
559 // Elementor uses 7-character alphanumeric IDs
560 $chars = '0123456789abcdef';
561 $id = '';
562 for ($i = 0; $i < 7; $i++) {
563 $id .= $chars[rand(0, strlen($chars) - 1)];
564 }
565 return $id;
566 }
567
568 /**
569 * Replace image IDs in element settings
570 */
571 private function replace_image_ids_in_settings($settings, $image_map): array
572 {
573 if (!is_array($settings)) {
574 return $settings;
575 }
576
577 foreach ($settings as $key => &$value) {
578 if (is_array($value)) {
579 $value = $this->replace_image_ids_in_settings($value, $image_map);
580 } elseif (isset($image_map[$value])) {
581 // Replace image ID
582 $value = $image_map[$value];
583 }
584 }
585
586 return $settings;
587 }
588
589 /**
590 * Merge processed template content with existing page
591 */
592 public function merge_with_existing_page(): void
593 {
594 if (!current_user_can('edit_posts')) {
595 wp_send_json_error('Insufficient permissions');
596 return;
597 }
598
599 if (!wp_verify_nonce($_POST['nonce'], 'king_addons_template_catalog')) {
600 wp_send_json_error('Invalid nonce');
601 return;
602 }
603
604 $page_id = intval($_POST['page_id']);
605
606 if (!$page_id) {
607 wp_send_json_error('Invalid page ID');
608 return;
609 }
610
611 // Get processed content from the original import system
612 $content = get_transient('elementor_import_content');
613 $page_title = get_transient('elementor_import_page_title');
614
615 if (!$content) {
616 wp_send_json_error('No processed content found. Import may have expired.');
617 return;
618 }
619
620 error_log('King Addons Import: Merging processed content with existing page ' . $page_id);
621
622 // Get current page Elementor data
623 $current_data = get_post_meta($page_id, '_elementor_data', true);
624 $current_elements = json_decode($current_data, true);
625
626 if (!is_array($current_elements)) {
627 $current_elements = [];
628 }
629
630 // The content is already processed by the original system (images replaced)
631 $template_content = $content;
632
633 if (!is_array($template_content)) {
634 wp_send_json_error('Invalid processed content format');
635 return;
636 }
637
638 // Generate new unique IDs for all elements to avoid conflicts
639 $template_content = $this->regenerate_element_ids($template_content);
640
641 // Merge template content with current page content
642 $current_count = count($current_elements);
643 $new_count = count($template_content);
644 $merged_elements = array_merge($current_elements, $template_content);
645 $total_count = count($merged_elements);
646
647 error_log('King Addons Import: Merging content - current: ' . $current_count . ', new: ' . $new_count . ', total: ' . $total_count);
648
649 // Update page meta with merged content
650 $update_result = update_post_meta($page_id, '_elementor_data', wp_slash(json_encode($merged_elements)));
651 update_post_meta($page_id, '_elementor_edit_mode', 'builder');
652
653 // Force update _elementor_version to trigger cache clear
654 if (defined('ELEMENTOR_VERSION')) {
655 update_post_meta($page_id, '_elementor_version', ELEMENTOR_VERSION);
656 }
657
658 // Update page modification time to force Elementor refresh
659 wp_update_post(['ID' => $page_id, 'post_modified' => current_time('mysql'), 'post_modified_gmt' => current_time('mysql', 1)]);
660
661 error_log('King Addons Import: Page meta updated - result: ' . ($update_result ? 'success' : 'failed'));
662
663 // Clear all Elementor caches
664 if (class_exists('\Elementor\Plugin')) {
665 \Elementor\Plugin::$instance->files_manager->clear_cache();
666 error_log('King Addons Import: Elementor cache cleared');
667 }
668
669 // Clean up transients
670 delete_transient('elementor_import_content');
671 delete_transient('elementor_import_images');
672 delete_transient('elementor_import_total_images');
673 delete_transient('elementor_import_images_processed');
674 delete_transient('elementor_import_image_retry_count');
675 delete_transient('elementor_import_page_title');
676 delete_transient('elementor_import_elementor_version');
677 delete_transient('elementor_import_existing_page_id');
678 delete_transient('elementor_import_create_new_page');
679
680 error_log('King Addons Import: Merge completed successfully');
681
682 wp_send_json_success([
683 'message' => 'Template merged successfully',
684 'imported_elements' => $new_count,
685 'page_id' => $page_id,
686 'current_elements_before' => $current_count,
687 'total_elements_after' => $total_count
688 ]);
689 }
690
691 /**
692 * AJAX handler for getting sections catalog data for popup
693 */
694 public function get_sections_catalog(): void
695 {
696 if (!current_user_can('edit_posts')) {
697 wp_send_json_error('Insufficient permissions');
698 return;
699 }
700
701 if (!wp_verify_nonce($_POST['nonce'], 'king_addons_template_catalog')) {
702 wp_send_json_error('Invalid nonce');
703 return;
704 }
705
706 if (!class_exists('King_Addons\\SectionsMap')) {
707 require_once KING_ADDONS_PATH . 'includes/SectionsMap.php';
708 }
709
710 $sections_map = SectionsMap::getSectionsMapArray();
711 $sections = $sections_map['sections'] ?? [];
712
713 $is_premium_active = function_exists('king_addons_freemius') && king_addons_freemius()->can_use_premium_code();
714
715 // Get filters from request
716 $search_query = sanitize_text_field($_POST['search'] ?? '');
717 $selected_category = sanitize_text_field($_POST['category'] ?? '');
718 $selected_type = sanitize_text_field($_POST['section_type'] ?? '');
719 $selected_plan = sanitize_text_field($_POST['plan'] ?? '');
720 $current_page = max(1, intval($_POST['page'] ?? 1));
721
722 // Get categories and section types for filters
723 $categories = [];
724 $section_types = [];
725
726 foreach ($sections as $section_key => $section) {
727 if (!in_array($section['category'], $categories)) {
728 $categories[] = $section['category'];
729 }
730 if (!in_array($section['section_type'], $section_types)) {
731 $section_types[] = $section['section_type'];
732 }
733 }
734
735 sort($categories);
736 sort($section_types);
737
738 // Filter sections
739 $filtered_sections = [];
740
741 foreach ($sections as $section_key => $section) {
742 // Add section key for frontend
743 $section['section_key'] = $section_key;
744
745 // Skip premium sections if user doesn't have premium license
746 if ($section['plan'] === 'premium' && !$is_premium_active) {
747 continue;
748 }
749
750 // Apply search filter
751 if (!empty($search_query)) {
752 $found_in_title = stripos($section['title'], $search_query) !== false;
753 $found_in_tags = false;
754
755 foreach ($section['tags'] ?? [] as $tag) {
756 if (stripos($tag, $search_query) !== false) {
757 $found_in_tags = true;
758 break;
759 }
760 }
761
762 if (!$found_in_title && !$found_in_tags) {
763 continue;
764 }
765 }
766
767 // Apply category filter
768 if (!empty($selected_category) && $section['category'] !== $selected_category) {
769 continue;
770 }
771
772 // Apply section type filter
773 if (!empty($selected_type) && $section['section_type'] !== $selected_type) {
774 continue;
775 }
776
777 // Apply plan filter
778 if (!empty($selected_plan) && $section['plan'] !== $selected_plan) {
779 continue;
780 }
781
782 $filtered_sections[] = $section;
783 }
784
785 // Pagination
786 $items_per_page = 20;
787 $total_sections = count($filtered_sections);
788 $total_pages = ceil($total_sections / $items_per_page);
789 $offset = ($current_page - 1) * $items_per_page;
790 $paged_sections = array_slice($filtered_sections, $offset, $items_per_page);
791
792 wp_send_json_success([
793 'sections' => $paged_sections,
794 'categories' => $categories,
795 'section_types' => $section_types,
796 'pagination' => [
797 'current_page' => $current_page,
798 'total_pages' => $total_pages,
799 'total_sections' => $total_sections,
800 'items_per_page' => $items_per_page
801 ],
802 'is_premium_active' => $is_premium_active
803 ]);
804 }
805
806 /**
807 * AJAX handler for importing section to current page
808 */
809 public function import_section_to_page(): void
810 {
811 if (!current_user_can('edit_posts')) {
812 wp_send_json_error('Insufficient permissions');
813 return;
814 }
815
816 if (!wp_verify_nonce($_POST['nonce'], 'king_addons_template_catalog')) {
817 wp_send_json_error('Invalid nonce');
818 return;
819 }
820
821 $section_key = sanitize_text_field($_POST['section_key']);
822 $section_plan = sanitize_text_field($_POST['section_plan']);
823 $is_premium_active = function_exists('king_addons_freemius') && king_addons_freemius()->can_use_premium_code();
824
825 // Determine API URL and install ID (same logic as templates)
826 if ($is_premium_active && $section_plan === 'premium') {
827 $api_url = 'https://api.kingaddons.com/get-section.php';
828
829 // Use the same method as original templates catalog
830 if (function_exists('king_addons_freemius')) {
831 $freemius_site = king_addons_freemius()->get_site();
832 $install_id = $freemius_site ? $freemius_site->id : 0;
833 } else {
834 $install_id = 0;
835 }
836
837 error_log('King Addons Premium Section: Using install_id: ' . $install_id . ' for premium section: ' . $section_key);
838 } elseif ($section_plan === 'free') {
839 $api_url = 'https://api.kingaddons.com/get-section-free.php';
840 $install_id = 0;
841 error_log('King Addons Free Section: Fetching free section: ' . $section_key);
842 } else {
843 error_log('King Addons Section Error: Premium section requires premium license. Section: ' . $section_key . ', Plan: ' . $section_plan . ', Premium Active: ' . ($is_premium_active ? 'Yes' : 'No'));
844 wp_send_json_error('Premium section requires premium license');
845 return;
846 }
847
848 // Get section data from API (same as templates)
849 $response = wp_remote_post($api_url, [
850 'headers' => ['Content-Type' => 'application/json'],
851 'body' => json_encode([
852 'key' => $section_key,
853 'install' => $install_id,
854 ]),
855 'timeout' => 60
856 ]);
857
858 if (is_wp_error($response)) {
859 wp_send_json_error('Failed to fetch section: ' . $response->get_error_message());
860 return;
861 }
862
863 $body = wp_remote_retrieve_body($response);
864 $data = json_decode($body, true);
865
866 error_log('King Addons Section API Response: ' . substr($body, 0, 500) . (strlen($body) > 500 ? '...' : ''));
867
868 if (!$data) {
869 error_log('King Addons Section Error: Failed to decode JSON response');
870 wp_send_json_error('Invalid JSON response from section API');
871 return;
872 }
873
874 if (!isset($data['success']) || !$data['success']) {
875 $error_message = isset($data['message']) ? $data['message'] : 'Unknown API error';
876 error_log('King Addons Section Error: API returned error: ' . $error_message);
877 wp_send_json_error('Section API error: ' . $error_message);
878 return;
879 }
880
881 // Return section data for frontend processing (adjust format from your API)
882 wp_send_json_success([
883 'section_data' => $data['section'], // Your API returns 'section' not 'landing'
884 'message' => 'Section data retrieved successfully'
885 ]);
886 }
887 }
888