PluginProbe
Master Addons for Elementor – Elementor Addons, Widgets, Mega Menu Builder, Popup Builder, Widget Builder & Template Kits / 3.1.9
Master Addons for Elementor – Elementor Addons, Widgets, Mega Menu Builder, Popup Builder, Widget Builder & Template Kits v3.1.9
3.2.2 3.2.3 3.2.1 3.2.0 3.1.9 3.1.8 3.1.7 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.9 trunk 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.3 1.1.4 1.1.5 All 174 releases
master-addons / inc / admin / templates / includes / classes / manager.php

manager.php in Master Addons for Elementor – Elementor Addons, Widgets, Mega Menu Builder, Popup Builder, Widget Builder & Template Kits 3.1.9, at inc/admin/templates/includes/classes/manager.php

748 lines 22.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace MasterAddons\Inc\Admin\Templates\Includes\Classes;
4
5 use MasterAddons\Inc\Admin\Templates;
6 use MasterAddons\Inc\Admin\Templates\Includes\Sources;
7
8 /**
9 * Author Name: Liton Arefin
10 * Author URL: https://jeweltheme.com
11 * Date: 9/8/19
12 */
13
14
15 if (!defined('ABSPATH')) exit;
16
17 if (!class_exists(__NAMESPACE__ . '\\Manager')) {
18
19
20 class Manager
21 {
22
23 private static $instance = null;
24
25 private $sources = array();
26
27
28 public function __construct()
29 {
30
31 //Register AJAX hooks
32 add_action('wp_ajax_jltma_get_templates', array($this, 'get_templates'));
33 add_action('wp_ajax_nopriv_jltma_get_templates', array($this, 'get_templates'));
34
35 add_action('wp_ajax_jltma_get_paginated_templates', array($this, 'get_paginated_templates'));
36
37 add_action('wp_ajax_jltma_inner_template', array($this, 'jltma_insert_inner_template'));
38 add_action('wp_ajax_nopriv_jltma_inner_template', array($this, 'jltma_insert_inner_template'));
39
40
41 add_action('elementor/ajax/register_actions', array($this, 'jltma_register_ajax_actions'), 20);
42
43 $this->register_sources();
44
45 add_filter('master-addons-core/assets/editor/localize', array($this, 'localize_tabs'));
46 }
47
48
49 public function localize_tabs($data)
50 {
51
52 $tabs = $this->get_template_tabs();
53 $ids = array_keys($tabs);
54 $default = $ids[0];
55
56 $data['tabs'] = $this->get_template_tabs();
57 $data['defaultTab'] = $default;
58
59 // Pass popup builder context
60 $current_post_type = get_post_type();
61 $is_popup_builder = false;
62
63 // phpcs:disable WordPress.Security.NonceVerification.Recommended -- read-only admin context, no nonce available
64 $get_post_id = isset( $_GET['post'] ) ? absint( wp_unslash( $_GET['post'] ) ) : 0;
65 $get_page = isset( $_GET['page'] ) ? sanitize_key( wp_unslash( $_GET['page'] ) ) : '';
66 if ($current_post_type === 'jltma_popup' || $current_post_type === 'popupbuilder' ||
67 ( $get_post_id && get_post_type( $get_post_id ) === 'jltma_popup' ) ||
68 ( $get_post_id && get_post_type( $get_post_id ) === 'popupbuilder' ) ||
69 ( $get_page && strpos( $get_page, 'popup' ) !== false )) {
70 $is_popup_builder = true;
71 }
72
73 if (isset($_GET['action']) && sanitize_key( wp_unslash( $_GET['action'] ) ) === 'elementor' &&
74 $get_post_id && (get_post_type( $get_post_id ) === 'ma_popup' || get_post_type( $get_post_id ) === 'jltma_popup' || get_post_type( $get_post_id ) === 'popupbuilder')) {
75 $is_popup_builder = true;
76 }
77 // phpcs:enable WordPress.Security.NonceVerification.Recommended
78
79 $data['isPopupBuilder'] = $is_popup_builder;
80
81 return $data;
82 }
83
84
85 public function register_sources()
86 {
87 $sources = array(
88 'master-api' => Sources\Api::class,
89 );
90
91 foreach ($sources as $key => $class) {
92 $this->add_source($key, $class);
93 }
94 }
95
96
97 public function get_template_tabs()
98 {
99
100 $tabs = Templates\master_addons_templates()->types->get_types_for_popup();
101 return $tabs;
102 }
103
104
105 public function add_source($key, $class)
106 {
107 $this->sources[$key] = new $class();
108 }
109
110
111 public function get_source($slug = null)
112 {
113 return isset($this->sources[$slug]) ? $this->sources[$slug] : false;
114 }
115
116
117
118 public function get_templates()
119 {
120 // Try multiple nonce actions for compatibility
121 $nonce_valid = check_ajax_referer('jltma_get_templates_nonce_action', '_wpnonce', false) ||
122 check_ajax_referer('jltma_template_library_nonce', '_wpnonce', false) || check_ajax_referer('jltma_get_templates_nonce_action', 'security', false);
123
124 // Enhanced security checks
125 if (!$nonce_valid) {
126 wp_send_json_error(array('message' => 'Permission denied - nonce failed'));
127 }
128
129 // Check user permissions
130 if (!current_user_can('edit_posts')) {
131 wp_send_json_error(array('message' => 'Permission denied - insufficient capabilities'));
132 }
133
134 // Rate limiting - prevent abuse
135 // $user_id = get_current_user_id();
136 // $rate_limit_key = "jltma_template_requests_{$user_id}";
137 // $request_count = get_transient($rate_limit_key);
138
139 // if ($request_count && $request_count > 500) {
140 // wp_send_json_error(array('message' => 'Rate limit exceeded. Please wait before making more requests.'));
141 // }
142
143 // set_transient($rate_limit_key, ($request_count ? $request_count + 1 : 1), HOUR_IN_SECONDS);
144
145 // Enhanced input validation - check both POST and GET for compatibility
146 $tab = isset($_POST['tab']) ? sanitize_key($_POST['tab']) : (isset($_GET['tab']) ? sanitize_key($_GET['tab']) : null);
147 $search = isset($_POST['search']) ? sanitize_text_field( wp_unslash( $_POST['search'] ) ) : (isset($_GET['search']) ? sanitize_text_field( wp_unslash( $_GET['search'] ) ) : '');
148 $category = isset($_POST['category']) ? sanitize_text_field( wp_unslash( $_POST['category'] ) ) : (isset($_GET['category']) ? sanitize_text_field( wp_unslash( $_GET['category'] ) ) : 'all');
149 $page = isset($_POST['page']) ? absint($_POST['page']) : (isset($_GET['page']) ? absint($_GET['page']) : 1);
150 $per_page = 15; // Templates per page
151
152
153 if (!$tab) {
154 wp_send_json_error(array('message' => 'Tab parameter is required'));
155 }
156
157 // Validate tab value against allowed values
158 $allowed_tabs = $this->get_allowed_tabs();
159 if (!in_array($tab, $allowed_tabs, true)) {
160 wp_send_json_error(array('message' => 'Invalid tab parameter'));
161 }
162
163 // Additional validation for tab data structure
164 if (!$this->validate_tab_structure($tab) && $tab !== 'master_popups') {
165 wp_send_json_error(array('message' => 'Invalid tab configuration'));
166 }
167 $tabs = $this->get_template_tabs();
168 $sources = $tabs[$tab]['sources'];
169
170 $result = array(
171 // 'ready_pages' => array(),
172 // 'ready_widgets' => array(),
173 'ready_headers' => array(),
174 'ready_footers' => array(),
175 'templates' => array(),
176 'categories' => array(),
177 'keywords' => array(),
178 );
179
180 foreach ($sources as $source_slug) {
181
182 $source = isset($this->sources[$source_slug]) ? $this->sources[$source_slug] : false;
183
184 if ($source) {
185 // $result['ready_pages'] = array_merge( $result['ready_pages'], $source->get_items( $tab ) );
186 $result['ready_headers'] = array_merge($result['ready_headers'], $source->get_items($tab));
187 $result['ready_footers'] = array_merge($result['ready_footers'], $source->get_items($tab));
188 $result['templates'] = array_merge($result['templates'], $source->get_items($tab));
189 $result['categories'] = array_merge($result['categories'], $source->get_categories($tab));
190 $result['keywords'] = array_merge($result['keywords'], $source->get_keywords($tab));
191 }
192 }
193
194
195 $all_cats = array(
196 array(
197 'slug' => '',
198 'title' => __('All Sections', 'master-addons' ),
199 ),
200 );
201
202 if (!empty($result['categories'])) {
203 $result['categories'] = array_merge($all_cats, $result['categories']);
204 }
205
206 // Filter templates by category
207 if ($category && $category !== 'all' && !empty($result['templates'])) {
208 $result['templates'] = array_filter($result['templates'], function($template) use ($category) {
209 if (isset($template['categories'])) {
210 $template_categories = is_array($template['categories']) ? $template['categories'] : array($template['categories']);
211 return in_array($category, $template_categories);
212 }
213 return false;
214 });
215 $result['templates'] = array_values($result['templates']); // Re-index array
216 }
217
218 // Filter templates by search term
219 if (!empty($search) && !empty($result['templates'])) {
220 $search_lower = strtolower($search);
221 $result['templates'] = array_filter($result['templates'], function($template) use ($search_lower) {
222 // Search in title
223 if (isset($template['title']) && stripos($template['title'], $search_lower) !== false) {
224 return true;
225 }
226 // Search in keywords
227 if (isset($template['keywords']) && is_array($template['keywords'])) {
228 foreach ($template['keywords'] as $keyword) {
229 if (stripos(strtolower($keyword), $search_lower) !== false) {
230 return true;
231 }
232 }
233 }
234 // Search in categories
235 if (isset($template['categories']) && is_array($template['categories'])) {
236 foreach ($template['categories'] as $cat) {
237 if (stripos(strtolower($cat), $search_lower) !== false) {
238 return true;
239 }
240 }
241 }
242 return false;
243 });
244 $result['templates'] = array_values($result['templates']); // Re-index array
245 }
246
247 // Calculate pagination
248 $total_templates = count($result['templates']);
249 $total_pages = ceil($total_templates / $per_page);
250 $offset = ($page - 1) * $per_page;
251
252 // Apply pagination
253 $result['templates'] = array_slice($result['templates'], $offset, $per_page);
254
255
256
257 if( $result ){
258 $base_url = wp_upload_dir()['baseurl'];
259 $extensions = ['.jpg', '.png', '.svg', '.webp'];
260 foreach($result as $type => $content){
261 if( 'ready_headers' !== $type && 'ready_footers' !== $type && 'templates' !== $type) continue;
262 if( $type === 'templates'){
263 $template_type = explode('_', $tab)[1];
264 }else{
265 $template_type = explode('_', $type)[1];
266 }
267 foreach($content as $index => $item){
268
269 $template_id = $item['template_id'];
270 $file_path = $base_url .'/master_addons/templates-library/master_' . $template_type . '/images/template-'. $template_id .'-preview';
271 foreach ( $extensions as $extension ){
272 if(file_exists($file_path . $extension )){
273 $item['preview'] = $base_url .'/master_addons/templates-library/master_' . $template_type . '/images/template-'. $template_id .'-preview' . $extension;
274 $item['thumbnail'] = $base_url .'/master_addons/templates-library/master_' . $template_type . '/images/template-'. $template_id .'-thumb' . $extension;
275 break;
276 }
277 }
278 $content[$index] = $item;
279 }
280 $result[$type] = $content;
281 }
282 }
283
284 // Add pagination metadata
285 $result['pagination'] = array(
286 'current_page' => $page,
287 'per_page' => $per_page,
288 'total_items' => $total_templates,
289 'total_pages' => $total_pages,
290 'has_more' => $page < $total_pages
291 );
292
293 wp_send_json_success($result);
294 }
295
296 public function get_paginated_templates()
297 {
298 // Enhanced security checks
299 if (!check_ajax_referer('jltma_get_templates_nonce_action', '_wpnonce', false)) {
300 wp_send_json_error(array('message' => 'Security verification failed'));
301 }
302
303 // Check user permissions
304 if (!current_user_can('edit_posts')) {
305 wp_send_json_error(array('message' => 'Insufficient permissions'));
306 }
307
308 // Get pagination parameters
309 $page = absint($_POST['page'] ?? 1);
310 $per_page = absint($_POST['per_page'] ?? 10);
311 $tab = sanitize_key($_POST['tab'] ?? 'master_section');
312
313 // Validate tab value against allowed values
314 $allowed_tabs = $this->get_allowed_tabs();
315 if (!in_array($tab, $allowed_tabs, true)) {
316 wp_send_json_error(array('message' => 'Invalid tab parameter'));
317 }
318
319 // Get all templates for the tab
320 $tabs = $this->get_template_tabs();
321 $sources = $tabs[$tab]['sources'];
322
323 $all_templates = array();
324
325 foreach ($sources as $source_slug) {
326 $source = isset($this->sources[$source_slug]) ? $this->sources[$source_slug] : false;
327 if ($source) {
328 $templates = $source->get_items($tab);
329 $all_templates = array_merge($all_templates, $templates);
330 }
331 }
332
333 // Apply pagination
334 $total_templates = count($all_templates);
335 $offset = ($page - 1) * $per_page;
336 $paginated_templates = array_slice($all_templates, $offset, $per_page);
337
338 // Update thumbnail URLs to use cache folder first, then remote fallback
339 foreach ($paginated_templates as &$template) {
340 if (class_exists('Template_Kit_Cache')) {
341 $cache_manager = Template_Kit_Cache::get_instance();
342 if (!empty($template['thumbnail'])) {
343 $cached_thumbnail = $cache_manager->get_kit_thumbnail_url('', $template['title'], $template['thumbnail']);
344 if ($cached_thumbnail) {
345 $template['thumbnail'] = $cached_thumbnail;
346 }
347 }
348 }
349 }
350
351 wp_send_json_success(array(
352 'templates' => $paginated_templates,
353 'pagination' => array(
354 'current_page' => $page,
355 'per_page' => $per_page,
356 'total_templates' => $total_templates,
357 'total_pages' => ceil($total_templates / $per_page),
358 'has_more' => ($offset + $per_page) < $total_templates
359 )
360 ));
361 }
362
363 public function get_template_source($source_name)
364 {
365 return isset($this->sources[$source_name]) ? $this->sources[$source_name] : false;
366 }
367
368 public function get_template_defaults()
369 {
370 return [
371 'template_id' => false,
372 'source' => false,
373 ];
374 }
375
376 public function sanitize_template(array $template)
377 {
378
379 $template = array_merge($this->get_template_defaults(), $template);
380
381 // Enhanced sanitization and validation
382 $template['template_id'] = isset($template['template_id']) ? sanitize_text_field($template['template_id']) : false;
383 $template['source'] = isset($template['source']) ? sanitize_text_field($template['source']) : false;
384 $template['title'] = isset($template['title']) ? sanitize_text_field($template['title']) : 'Untitled Template';
385
386 // Validate template_id format (alphanumeric and dashes only)
387 if ($template['template_id'] && !preg_match('/^[a-zA-Z0-9\-_]+$/', $template['template_id'])) {
388 $template['template_id'] = false;
389 }
390
391 // Validate source against allowed sources
392 $allowed_sources = ['master-api'];
393 if ($template['source'] && !in_array($template['source'], $allowed_sources, true)) {
394 $template['source'] = false;
395 }
396
397 return $template;
398 }
399
400 /**
401 * Get allowed tabs for validation
402 */
403 private function get_allowed_tabs()
404 {
405 return apply_filters('jltma_allowed_template_tabs', [
406 'master_section',
407 'master_pages',
408 'master_popups',
409 'master_headers',
410 'master_footers'
411 ]);
412 }
413
414 /**
415 * Validate tab structure and configuration
416 */
417 private function validate_tab_structure($tab)
418 {
419 $tabs = $this->get_template_tabs();
420
421 // Check if tab exists in configuration
422 if (!isset($tabs[$tab])) {
423 return false;
424 }
425
426 // Validate tab has required structure
427 $required_keys = ['sources'];
428 foreach ($required_keys as $key) {
429 if (!isset($tabs[$tab][$key])) {
430 return false;
431 }
432 }
433
434 // Validate sources are not empty
435 if (empty($tabs[$tab]['sources']) || !is_array($tabs[$tab]['sources'])) {
436 return false;
437 }
438
439 return true;
440 }
441
442 /**
443 * Validate template data structure
444 */
445 private function validate_template_data($template_data)
446 {
447 if (!is_array($template_data)) {
448 return false;
449 }
450
451 // Required fields
452 $required_fields = ['content'];
453 foreach ($required_fields as $field) {
454 if (!isset($template_data[$field])) {
455 return false;
456 }
457 }
458
459 // Validate content is not empty
460 if (empty($template_data['content'])) {
461 return false;
462 }
463
464 // Validate content size (prevent extremely large templates)
465 // if (strlen($template_data['content']) > 1048576) { // 1MB limit
466 // return false;
467 // }
468
469 return true;
470 }
471
472 /**
473 * Validate source name against registered sources
474 */
475 private function validate_source($source_name)
476 {
477 if (empty($source_name)) {
478 return false;
479 }
480
481 // Check if source is registered
482 if (!isset($this->sources[$source_name])) {
483 return false;
484 }
485
486 // Validate source object
487 $source = $this->sources[$source_name];
488 if (!is_object($source)) {
489 return false;
490 }
491
492 // Check if source has required methods
493 $required_methods = ['get_item', 'get_items'];
494 foreach ($required_methods as $method) {
495 if (!method_exists($source, $method)) {
496 return false;
497 }
498 }
499
500 return true;
501 }
502
503 /*
504 * Insert Template
505 */
506 public function jltma_insert_inner_template()
507 {
508 // Enhanced security verification
509 if (!check_ajax_referer('jltma_insert_templates_nonce_action', 'security', false)) {
510 wp_send_json_error(array('message' => 'Security verification failed'));
511 }
512
513 // Check user permissions
514 if (!current_user_can('edit_posts')) {
515 wp_send_json_error(array('message' => 'Insufficient permissions'));
516 }
517
518 // Rate limiting for template insertions
519 // $user_id = get_current_user_id();
520 // $rate_limit_key = "jltma_template_inserts_{$user_id}";
521 // $insert_count = get_transient($rate_limit_key);
522
523 // if ($insert_count && $insert_count > 500) {
524 // wp_send_json_error(array('message' => 'Template insertion rate limit exceeded'));
525 // }
526
527 // set_transient($rate_limit_key, ($insert_count ? $insert_count + 1 : 1), HOUR_IN_SECONDS);
528
529 // Enhanced template validation
530 if (!isset($_REQUEST['template'])) {
531 wp_send_json_error(array('message' => 'Template data is required'));
532 }
533
534 $template = $this->sanitize_template( (array) wp_unslash( $_REQUEST['template'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- sanitized inside sanitize_template()
535
536 if (!$template || empty($template['template_id']) || empty($template['source'])) {
537 wp_send_json_error(array('message' => 'Invalid template data'));
538 }
539
540 // Validate source
541 if (!$this->validate_source($template['source'])) {
542 wp_send_json_error(array('message' => 'Invalid template source'));
543 }
544
545 $source = $this->get_template_source($template['source']);
546
547 if (!$source || !$template['template_id']) {
548 wp_send_json_error(array('message' => 'Template source or ID not found'));
549 }
550
551 $template_data = $source->get_item($template['template_id']);
552
553 // Validate template data structure
554 if (!$this->validate_template_data($template_data)) {
555 wp_send_json_error(array('message' => 'Invalid template data structure'));
556 }
557
558 if (!empty($template_data['content'])) {
559 // Additional validation before post creation
560 $post_title = !empty($template['title']) ? sanitize_text_field($template['title']) : 'Master Addons Template ' . time();
561
562 // Validate post title length
563 if (strlen($post_title) > 255) {
564 $post_title = substr($post_title, 0, 255);
565 }
566
567 // Validate Elementor data format
568 $elementor_data = $template_data['content'];
569 if (is_string($elementor_data)) {
570 $decoded_data = json_decode($elementor_data, true);
571 if (json_last_error() !== JSON_ERROR_NONE) {
572 wp_send_json_error(array('message' => 'Invalid Elementor data format'));
573 }
574 }
575
576 $post_id = wp_insert_post(array(
577 'post_type' => 'elementor_library',
578 'post_title' => $post_title,
579 'post_status' => 'publish',
580 'post_author' => get_current_user_id(),
581 'meta_input' => array(
582 '_elementor_data' => $elementor_data,
583 '_elementor_edit_mode' => 'builder',
584 '_elementor_template_type' => 'section',
585 '_jltma_template_source' => sanitize_text_field($template['source']),
586 '_jltma_template_id' => sanitize_text_field($template['template_id']),
587 ),
588 ));
589
590 // Validate post creation success
591 if (!$post_id || is_wp_error($post_id)) {
592 wp_send_json_error(array('message' => 'Failed to create template post'));
593 }
594 } else {
595 wp_send_json_error(array('message' => 'Template content is empty'));
596 }
597
598 wp_send_json_success();
599 }
600
601 public function jltma_register_ajax_actions($ajax_manager)
602 {
603
604 if (empty($_REQUEST['actions'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- no nonce available for this action hook
605 return;
606 }
607
608 $actions = (array) json_decode(stripslashes(sanitize_text_field( wp_unslash( $_REQUEST['actions'] ) )), true); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- no nonce available for this action hook
609 $data = false;
610
611 foreach ($actions as $action_data) {
612 if( in_array('get_template_data', $action_data) || in_array('save_template', $action_data) ){
613 $data = $action_data;
614 }
615 }
616
617 if (!$data) {
618 return;
619 }
620
621 if (!isset($data['data'])) {
622 return;
623 }
624
625 if (!isset($data['data']['source'])) {
626 return;
627 }
628
629 // Handle both single source string and array of sources
630 $sources = $data['data']['source'];
631 if (!is_array($sources)) {
632 $sources = [$sources];
633 }
634
635 foreach ( $sources as $source ) {
636 if ( isset( $this->sources[ $source ] ) ) {
637 // Register AJAX actions only once
638 $ajax_manager->register_ajax_action( 'get_template_data', function( $data ) {
639 return $this->get_template_data_array( $data );
640 });
641
642 $ajax_manager->register_ajax_action( 'save_template', function( $data ) {
643 return $this->save_template_data_array( $data );
644 });
645
646 break; // Exit loop after registering once
647 }
648 }
649
650 }
651
652
653 public function save_template_data_array($data) {
654 if (!current_user_can('edit_posts')) {
655 return new \WP_Error('forbidden', 'You are not allowed to save templates.');
656 }
657
658 $post_id = sanitize_text_field($data['template_id'] ?? '');
659 $template_data = wp_unslash($data['template_data'] ?? '');
660
661 if ($post_id && $template_data) {
662 return \Elementor\Plugin::$instance->templates_manager->save_template(
663 $post_id,
664 $template_data
665 );
666 }
667
668 return new \WP_Error('invalid_data', 'Missing template ID or data');
669 }
670
671
672 public function get_template_data_array($data)
673 {
674
675 if (!current_user_can('edit_posts')) {
676 return false;
677 }
678
679 if (empty($data['template_id'])) {
680 return false;
681 }
682
683 $source_name = isset($data['source']) ? $data['source'] : '';
684
685 // Handle both single source string and array of sources
686 if (is_array($source_name)) {
687 $source_name = !empty($source_name) ? esc_attr($source_name[0]) : '';
688 } else {
689 $source_name = esc_attr($source_name);
690 }
691
692 if (!$source_name) {
693 return false;
694 }
695
696 $source = isset($this->sources[$source_name]) ? $this->sources[$source_name] : false;
697
698 if (!$source) {
699 return false;
700 }
701
702 if (empty($data['tab'])) {
703 return false;
704 }
705
706 $template = $source->get_item($data['template_id'], $data['tab']);
707
708 return $template;
709 }
710
711
712 public function get_template_data()
713 {
714
715 // Extract and sanitize only the specific fields we need (never forward the whole superglobal).
716 $source = isset( $_REQUEST['source'] ) ? wp_unslash( $_REQUEST['source'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only fetch gated by edit_posts capability in get_template_data_array()
717 if ( is_array( $source ) ) {
718 $source = array_map( 'sanitize_text_field', $source );
719 } else {
720 $source = sanitize_text_field( $source );
721 }
722 $request_data = array(
723 'template_id' => isset( $_REQUEST['template_id'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['template_id'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only fetch gated by edit_posts capability in get_template_data_array()
724 'tab' => isset( $_REQUEST['tab'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['tab'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only fetch gated by edit_posts capability in get_template_data_array()
725 'source' => $source,
726 );
727
728 $template = $this->get_template_data_array($request_data);
729
730 if (!$template) {
731 wp_send_json_error();
732 }
733
734 wp_send_json_success($template);
735 }
736
737
738 public static function get_instance()
739 {
740
741 // If the single instance hasn't been set, set it now.
742 if (null == self::$instance) {
743 self::$instance = new self;
744 }
745 return self::$instance;
746 }
747 }
748 }