PluginProbe
Master Addons for Elementor – Elementor Addons, Widgets, Mega Menu Builder, Popup Builder, Widget Builder & Template Kits / 3.1.2
Master Addons for Elementor – Elementor Addons, Widgets, Mega Menu Builder, Popup Builder, Widget Builder & Template Kits v3.1.2
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.2, at inc/admin/templates/includes/classes/manager.php

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