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 / popup-builder / class-popup-admin.php

class-popup-admin.php in Master Addons for Elementor – Elementor Addons, Widgets, Mega Menu Builder, Popup Builder, Widget Builder & Template Kits 3.1.2, at inc/admin/popup-builder/class-popup-admin.php

540 lines 23.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Master Addons Popup Admin Page
4 * Similar to Theme Builder but for Popups
5 *
6 * @package MasterAddons
7 * @subpackage PopupBuilder
8 */
9
10 namespace MasterAddons\Inc\Admin\PopupBuilder;
11
12 use MasterAddons\Inc\Classes\Assets_Manager;
13 use MasterAddons\Inc\Classes\Template_Library_Cache;
14 use MasterAddons\Inc\Admin\Templates;
15
16 if (!defined('ABSPATH')) {
17 exit;
18 }
19
20 class Popup_Admin {
21
22 private static $instance = null;
23 private $popup_cpt;
24
25 public static function get_instance() {
26 if (self::$instance === null) {
27 self::$instance = new self();
28 }
29 return self::$instance;
30 }
31
32 public function __construct() {
33 $this->popup_cpt = Popup_CPT::get_instance();
34 $this->init_hooks();
35 }
36
37 private function init_hooks() {
38 add_action('admin_menu', [$this, 'add_admin_menu'], 55);
39 add_action('admin_enqueue_scripts', [$this, 'enqueue_admin_assets']);
40 add_action('admin_footer', [$this, 'render_popup_modals_in_footer']);
41 add_action('wp_ajax_jltma_popup_get_data', [$this, 'get_popup_data']);
42 add_action('wp_ajax_jltma_popup_save_data', [$this, 'save_popup_data']);
43 add_action('wp_ajax_jltma_popup_delete', [$this, 'delete_popup']);
44 add_action('wp_ajax_jltma_popup_get_templates', [$this, 'get_popup_templates']);
45 add_action('wp_ajax_jltma_popup_import_template', [$this, 'import_popup_template']);
46 add_filter('submenu_file', [$this, 'highlight_popup_menu'], 10, 2);
47 }
48
49 public function add_admin_menu() {
50 add_submenu_page(
51 'master-addons-settings',
52 __('Popup Builder', 'master-addons'),
53 __('Popup Builder', 'master-addons'),
54 'manage_options',
55 'edit.php?post_type=jltma_popup'
56 );
57 }
58
59 public function highlight_popup_menu($submenu_file, $parent_file) {
60 global $current_screen;
61
62 if ($current_screen && $current_screen->post_type === $this->popup_cpt->get_post_type()) {
63 $submenu_file = 'edit.php?post_type=jltma_popup';
64 }
65
66 return $submenu_file;
67 }
68
69 /**
70 * Render popup modals in footer (similar to Theme Builder)
71 */
72 public function render_popup_modals_in_footer() {
73 $screen = get_current_screen();
74 if ($screen && $screen->id === 'edit-jltma_popup') {
75 $this->render_popup_modal();
76 $this->render_templates_modal();
77 }
78 }
79
80 private function render_popup_modal() {
81 ?>
82 <!-- Popup Settings Modal - Similar to Theme Builder -->
83 <div id="jltma_popup_builder_modal" class="jltma_popup_builder_modal jltma-modal">
84 <div class="jltma-modal-backdrop"></div>
85 <div class="jltma-modal-dialog">
86 <div class="jltma-modal-content">
87 <?php include JLTMA_PATH . 'inc/admin/popup-builder/view/popup-modal-header.php'; ?>
88 <?php include JLTMA_PATH . 'inc/admin/popup-builder/view/popup-modal-body.php'; ?>
89 </div>
90 </div>
91 </div>
92 <?php
93 }
94
95 public function enqueue_admin_assets($hook) {
96 $screen = get_current_screen();
97 if (!$screen || $screen->id !== 'edit-jltma_popup') {
98 return;
99 }
100
101 // Enqueue popup builder assets via Assets Manager
102 Assets_Manager::enqueue('popup-builder-admin');
103
104 // Condition type options (Pro adds "Exclude")
105 $condition_type_options = apply_filters('master_addons/popup_builder/condition_type_options', [
106 ['value' => 'include', 'label' => __('Include', 'master-addons')],
107 ['value' => 'exclude', 'label' => __('Exclude (Pro)', 'master-addons'), 'pro' => true],
108 ]);
109
110 // Condition rule options (Pro unlocks all beyond "Entire Site")
111 $condition_rule_options = apply_filters('master_addons/popup_builder/condition_rule_options', [
112 ['value' => 'entire_site', 'label' => __('Entire Site', 'master-addons')],
113 ['value' => 'front_page', 'label' => __('Front Page (Pro)', 'master-addons'), 'pro' => true],
114 ['value' => 'singular', 'label' => __('Singular (Pro)', 'master-addons'), 'pro' => true],
115 ['value' => 'archive', 'label' => __('Archive (Pro)', 'master-addons'), 'pro' => true],
116 ['value' => 'search', 'label' => __('Search (Pro)', 'master-addons'), 'pro' => true],
117 ['value' => '404', 'label' => __('404 Page (Pro)', 'master-addons'), 'pro' => true],
118 ]);
119
120 // Localize script with REST API endpoints
121 wp_localize_script('jltma-popup-builder-admin', 'jltmaPopupAdmin', [
122 'resturl' => get_rest_url() . 'master-addons/v1/',
123 'nonce' => wp_create_nonce('wp_rest'),
124 'ajax_url' => admin_url('admin-ajax.php'),
125 'admin_url' => admin_url(),
126 'plugin_url' => JLTMA_URL,
127 'popup_nonce' => wp_create_nonce('jltma_popup_nonce'),
128 'woocommerce_active' => class_exists('WooCommerce'),
129 'is_premium' => apply_filters('master_addons/is_premium', false),
130 'condition_type_options' => $condition_type_options,
131 'condition_rule_options' => $condition_rule_options,
132 'strings' => [
133 'confirm_delete' => __('Are you sure you want to delete this popup?', 'master-addons'),
134 'saving' => __('Saving...', 'master-addons'),
135 'saved' => __('Popup saved successfully!', 'master-addons'),
136 'error' => __('An error occurred. Please try again.', 'master-addons'),
137 'popup_name_required' => __('Popup name is required.', 'master-addons'),
138 'loading_templates' => __('Loading templates...', 'master-addons'),
139 'importing_template' => __('Importing template...', 'master-addons'),
140 'template_imported' => __('Template imported successfully!', 'master-addons'),
141 'import_failed' => __('Failed to import template. Please try again.', 'master-addons'),
142 'all_categories' => __('All', 'master-addons'),
143 'use_template' => __('Import', 'master-addons'),
144 'preview' => __('Preview', 'master-addons'),
145 'no_templates' => __('No templates found.', 'master-addons'),
146 'search_placeholder' => __('Search templates...', 'master-addons'),
147 'retry' => __('Retry', 'master-addons'),
148 'load_error' => __('Failed to load templates. Please check your connection and try again.', 'master-addons'),
149 ]
150 ]);
151
152 // Global masteraddons variable for consistency
153 wp_localize_script('jltma-popup-builder-admin', 'masteraddons', [
154 'resturl' => get_rest_url() . 'masteraddons/v2/',
155 'rest_nonce' => wp_create_nonce('wp_rest'),
156 'ajax_nonce' => wp_create_nonce('jltma_frontend_ajax_nonce'),
157 'woocommerce_active' => class_exists('WooCommerce'),
158 ]);
159 }
160
161 public function get_popup_data() {
162 check_ajax_referer('jltma_popup_nonce', '_nonce');
163
164 $popup_id = isset( $_GET['popup_id'] ) ? absint( $_GET['popup_id'] ) : 0;
165
166 if (!$popup_id) {
167 wp_send_json_error(['message' => 'Invalid popup ID']);
168 }
169
170 $popup = get_post($popup_id);
171 if (!$popup || $popup->post_type !== $this->popup_cpt->get_post_type()) {
172 wp_send_json_error(['message' => 'Popup not found']);
173 }
174
175 $data = [
176 'id' => $popup_id,
177 'title' => $popup->post_title,
178 'activation' => get_post_meta($popup_id, '_jltma_popup_activation', true) ?: 'no',
179 'conditions_data' => get_post_meta($popup_id, '_jltma_popup_conditions_data', true) ?: [],
180 ];
181
182 wp_send_json_success($data);
183 }
184
185 public function save_popup_data() {
186 check_ajax_referer('jltma_popup_nonce', '_nonce');
187
188 $popup_id = isset($_POST['popup_id']) ? intval($_POST['popup_id']) : 0;
189 $title = isset($_POST['title']) ? sanitize_text_field(wp_unslash($_POST['title'])) : '';
190 $activation = isset($_POST['activation']) ? sanitize_text_field(wp_unslash($_POST['activation'])) : '';
191
192 // Handle conditions data
193 $conditions_data = $this->parse_conditions_from_post();
194
195 if ($popup_id) {
196 // Update existing popup
197 wp_update_post([
198 'ID' => $popup_id,
199 'post_title' => $title,
200 ]);
201 } else {
202 // Create new popup
203 $popup_id = wp_insert_post([
204 'post_title' => $title,
205 'post_type' => $this->popup_cpt->get_post_type(),
206 'post_status' => 'publish',
207 ]);
208
209 if (is_wp_error($popup_id)) {
210 wp_send_json_error(['message' => 'Failed to create popup']);
211 return;
212 }
213 }
214
215 // Free: only allow include + entire_site. Pro hooks this filter to return data as-is.
216 $conditions_data = apply_filters('master_addons/popup_builder/sanitize_conditions',
217 $this->sanitize_free_conditions($conditions_data)
218 );
219
220 // Save meta data
221 update_post_meta($popup_id, '_jltma_popup_activation', $activation);
222 update_post_meta($popup_id, '_jltma_popup_conditions_data', $conditions_data);
223
224 // Enable Elementor for this post with our custom document type
225 if (defined('ELEMENTOR_VERSION')) {
226 update_post_meta($popup_id, '_elementor_edit_mode', 'builder');
227 update_post_meta($popup_id, '_elementor_template_type', 'jltma_popup');
228 update_post_meta($popup_id, '_wp_page_template', 'elementor_canvas');
229 }
230
231 // Get proper Elementor edit URL
232 $edit_url = get_edit_post_link($popup_id);
233 if (defined('ELEMENTOR_VERSION')) {
234 try {
235 $document = \Elementor\Plugin::$instance->documents->get($popup_id);
236 if ($document) {
237 $edit_url = $document->get_edit_url();
238 } else {
239 // Fallback to standard Elementor URL format
240 $edit_url = admin_url('post.php?post=' . $popup_id . '&action=elementor');
241 }
242 } catch (\Exception $e) {
243 // Fallback to standard Elementor URL format
244 $edit_url = admin_url('post.php?post=' . $popup_id . '&action=elementor');
245 }
246 }
247
248 $response_data = [
249 'id' => $popup_id,
250 'title' => $title,
251 'activation' => $activation,
252 'edit_url' => $edit_url,
253 ];
254
255 wp_send_json_success($response_data);
256 }
257
258 public function delete_popup() {
259 check_ajax_referer('jltma_popup_nonce', '_nonce');
260
261 $popup_id = isset( $_POST['popup_id'] ) ? absint( $_POST['popup_id'] ) : 0;
262
263 if (!$popup_id) {
264 wp_send_json_error(['message' => 'Invalid popup ID']);
265 }
266
267 $result = wp_delete_post($popup_id, true);
268
269 if ($result) {
270 wp_send_json_success(['message' => 'Popup deleted successfully']);
271 } else {
272 wp_send_json_error(['message' => 'Failed to delete popup']);
273 }
274 }
275
276 private function render_templates_modal() {
277 ?>
278 <!-- Popup Templates Modal -->
279 <div id="jltma_popup_templates_modal" class="jltma_popup_builder_modal jltma-modal">
280 <div class="jltma-modal-backdrop"></div>
281 <div class="jltma-modal-dialog">
282 <div class="jltma-modal-content">
283 <div class="jltma-pop-contents-head">
284 <div class="jltma-header-top">
285 <div class="jltma-popup-head-content">
286 <span>
287 <img src="<?php echo esc_url( JLTMA_IMAGE_DIR . 'logo.svg' ); ?>">
288 </span>
289 <h3><?php echo esc_html__('Popup Templates', 'master-addons'); ?></h3>
290 </div>
291 <div class="jltma-templates-search">
292 <input type="text" id="jltma-popup-template-search" placeholder="<?php echo esc_attr__('Search templates...', 'master-addons'); ?>">
293 <span class="dashicons dashicons-search"></span>
294 </div>
295 <div class="jltma-pop-close">
296 <button class="close-btn" data-dismiss="modal"><span class="dashicons dashicons-no-alt"></span></button>
297 </div>
298 </div>
299 <div class="jltma-templates-categories" id="jltma-popup-template-categories"></div>
300 </div>
301
302 <div class="jltma-pop-contents-body">
303 <div class="jltma-templates-container">
304 <!-- Loading state -->
305 <div class="jltma-templates-loading" id="jltma-popup-templates-loading">
306 <div class="jltma-loading-logo">
307 <img src="<?php echo esc_url(JLTMA_URL . '/assets/images/logo.svg'); ?>" alt="Master Addons" class="ma-el-loading-logo">
308 </div>
309 <p><?php echo esc_html__('Loading Templates...', 'master-addons'); ?></p>
310 </div>
311
312 <!-- Error state -->
313 <div class="jltma-templates-error" id="jltma-popup-templates-error" style="display:none;">
314 <span class="dashicons dashicons-warning"></span>
315 <p><?php echo esc_html__('Failed to load templates. Please check your connection and try again.', 'master-addons'); ?></p>
316 <button type="button" class="button" id="jltma-popup-templates-retry"><?php echo esc_html__('Retry', 'master-addons'); ?></button>
317 </div>
318
319 <!-- Empty state -->
320 <div class="jltma-templates-empty" id="jltma-popup-templates-empty" style="display:none;">
321 <span class="dashicons dashicons-layout"></span>
322 <p><?php echo esc_html__('No templates found.', 'master-addons'); ?></p>
323 </div>
324
325 <!-- Template grid (populated by JS) -->
326 <div class="jltma-templates-grid" id="jltma-popup-templates-grid" style="display:none;"></div>
327 </div>
328 </div>
329 </div>
330 </div>
331 </div>
332 <?php
333 }
334
335 /**
336 * AJAX: Get popup templates from cache/API
337 */
338 public function get_popup_templates() {
339 check_ajax_referer('jltma_popup_nonce', '_nonce');
340
341 if (!current_user_can('manage_options')) {
342 wp_send_json_error(['message' => 'Unauthorized']);
343 return;
344 }
345
346 $cache = Template_Library_Cache::get_instance();
347 $templates = $cache->get_cached_templates('master_popups');
348 $categories = $cache->get_cached_categories('master_popups');
349
350 if ($templates === false) {
351 $templates = [];
352 }
353 if ($categories === false) {
354 $categories = [];
355 }
356
357 // Normalize categories from {"slug": "name"} object to [{slug, name}] array
358 $normalized_categories = [];
359 if (is_array($categories) || is_object($categories)) {
360 foreach ($categories as $slug => $name) {
361 $normalized_categories[] = [
362 'slug' => $slug,
363 'name' => is_string($name) ? $name : (string) $name,
364 ];
365 }
366 }
367
368 wp_send_json_success([
369 'templates' => $templates,
370 'categories' => $normalized_categories,
371 ]);
372 }
373
374 /**
375 * AJAX: Import a popup template
376 */
377 public function import_popup_template() {
378 check_ajax_referer('jltma_popup_nonce', '_nonce');
379
380 if (!current_user_can('manage_options')) {
381 wp_send_json_error(['message' => 'Unauthorized']);
382 return;
383 }
384
385 $template_id = intval($_POST['template_id'] ?? 0);
386 $title = sanitize_text_field( wp_unslash( $_POST['title'] ?? '' ) );
387
388 if (!$template_id) {
389 wp_send_json_error(['message' => 'Invalid template ID']);
390 return;
391 }
392
393 if (empty($title)) {
394 $title = 'Popup #' . $template_id;
395 }
396
397 // Fetch template content via the existing API source
398 $elementor_content = null;
399
400 if (function_exists('MasterAddons\\Inc\\Admin\\Templates\\master_addons_templates')) {
401 $templates_instance = Templates\master_addons_templates();
402 if ($templates_instance && isset($templates_instance->temp_manager)) {
403 $source = $templates_instance->temp_manager->get_source('master-api');
404 if ($source) {
405 $template_data = $source->get_item($template_id, 'master_popups');
406 if ($template_data && !empty($template_data['content'])) {
407 $elementor_content = $template_data['content'];
408 }
409 }
410 }
411 }
412
413 // Fallback: read directly from the cached template file (bulk-cached format uses 'dependencies')
414 if (empty($elementor_content) && class_exists('MasterAddons\Inc\Classes\Template_Library_Cache')) {
415 $cache_dir = wp_upload_dir()['basedir'] . '/master_addons/templates-library/master_popups/templates/';
416 $cache_file = $cache_dir . 'template-' . $template_id . '.json';
417
418 if (file_exists($cache_file)) {
419 $cached_raw = json_decode(file_get_contents($cache_file), true);
420 if ($cached_raw && !empty($cached_raw['dependencies'])) {
421 $elementor_content = $cached_raw['dependencies'];
422 } elseif ($cached_raw && !empty($cached_raw['content'])) {
423 $elementor_content = $cached_raw['content'];
424 }
425 }
426 }
427
428 // Create the popup post
429 $popup_id = wp_insert_post([
430 'post_title' => $title,
431 'post_type' => $this->popup_cpt->get_post_type(),
432 'post_status' => 'publish',
433 ]);
434
435 if (is_wp_error($popup_id)) {
436 wp_send_json_error(['message' => 'Failed to create popup']);
437 return;
438 }
439
440 // Set Elementor data if template content was fetched
441 if (!empty($elementor_content)) {
442 if (is_array($elementor_content)) {
443 $elementor_content = wp_json_encode($elementor_content);
444 }
445 update_post_meta($popup_id, '_elementor_data', wp_slash($elementor_content));
446
447 if (defined('ELEMENTOR_VERSION')) {
448 update_post_meta($popup_id, '_elementor_version', ELEMENTOR_VERSION);
449
450 // Clear Elementor cache so it picks up the new content
451 if (class_exists('\Elementor\Plugin')) {
452 \Elementor\Plugin::$instance->files_manager->clear_cache();
453 }
454 }
455 }
456
457 // Set activation and default conditions
458 $activation = sanitize_text_field( wp_unslash( $_POST['activation'] ?? 'no' ) );
459 update_post_meta($popup_id, '_jltma_popup_activation', $activation);
460
461 // Parse conditions if provided
462 $conditions_data = $this->parse_conditions_from_post();
463 if (empty($conditions_data)) {
464 $conditions_data = [['type' => 'include', 'rule' => 'entire_site', 'specific' => '', 'posts' => []]];
465 }
466 update_post_meta($popup_id, '_jltma_popup_conditions_data', $conditions_data);
467
468 // Enable Elementor for this post
469 if (defined('ELEMENTOR_VERSION')) {
470 update_post_meta($popup_id, '_elementor_edit_mode', 'builder');
471 update_post_meta($popup_id, '_elementor_template_type', 'jltma_popup');
472 update_post_meta($popup_id, '_wp_page_template', 'elementor_canvas');
473 }
474
475 // Get Elementor edit URL
476 $edit_url = admin_url('post.php?post=' . $popup_id . '&action=elementor');
477 if (defined('ELEMENTOR_VERSION')) {
478 try {
479 $document = \Elementor\Plugin::$instance->documents->get($popup_id);
480 if ($document) {
481 $edit_url = $document->get_edit_url();
482 }
483 } catch (\Exception $e) {
484 // Fallback already set above
485 }
486 }
487
488 wp_send_json_success([
489 'id' => $popup_id,
490 'title' => $title,
491 'edit_url' => $edit_url,
492 ]);
493 }
494
495 /**
496 * Parse conditions from POST data (reusable helper)
497 */
498 /**
499 * Sanitize conditions for free version — only allow include + entire_site.
500 */
501 private function sanitize_free_conditions($conditions_data) {
502 if (empty($conditions_data) || !is_array($conditions_data)) {
503 return [['type' => 'include', 'rule' => 'entire_site']];
504 }
505 $filtered = array_filter($conditions_data, function ($c) {
506 return (isset($c['type']) && $c['type'] === 'include' && isset($c['rule']) && $c['rule'] === 'entire_site');
507 });
508 return !empty($filtered) ? array_values($filtered) : [['type' => 'include', 'rule' => 'entire_site']];
509 }
510
511 private function parse_conditions_from_post() {
512 $conditions_data = [];
513 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified in calling method (import_popup_template)
514 $condition_types = isset( $_POST['jltma_condition_type'] ) ? map_deep( wp_unslash( $_POST['jltma_condition_type'] ), 'sanitize_text_field' ) : []; // phpcs:ignore WordPress.Security.NonceVerification.Missing
515 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified in calling method (import_popup_template)
516 $condition_rules = isset( $_POST['jltma_condition_rule'] ) ? map_deep( wp_unslash( $_POST['jltma_condition_rule'] ), 'sanitize_text_field' ) : []; // phpcs:ignore WordPress.Security.NonceVerification.Missing
517 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified in calling method (import_popup_template)
518 $condition_specifics = isset( $_POST['jltma_condition_specific'] ) ? map_deep( wp_unslash( $_POST['jltma_condition_specific'] ), 'sanitize_text_field' ) : []; // phpcs:ignore WordPress.Security.NonceVerification.Missing
519 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified in calling method (import_popup_template)
520 $condition_posts = isset( $_POST['jltma_condition_posts'] ) ? map_deep( wp_unslash( $_POST['jltma_condition_posts'] ), 'sanitize_text_field' ) : []; // phpcs:ignore WordPress.Security.NonceVerification.Missing
521
522 foreach ($condition_types as $index => $type) {
523 $rule = $condition_rules[$index] ?? '';
524 $specific = $condition_specifics[$index] ?? '';
525 $posts = $condition_posts[$index] ?? [];
526
527 if (!empty($type) && !empty($rule)) {
528 $conditions_data[] = [
529 'type' => sanitize_text_field($type),
530 'rule' => sanitize_text_field($rule),
531 'specific' => sanitize_text_field($specific),
532 'posts' => array_map('intval', (array) $posts),
533 ];
534 }
535 }
536
537 return $conditions_data;
538 }
539 }
540