PluginProbe
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar / 3.2.9
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar v3.2.9
3.3.1 3.3.0 3.2.14 3.2.13 3.2.12 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 trunk 0.2.5.5 0.2.5.6 0.2.5.7 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.2.0 1.2.1 All 156 releases
notificationx / includes / Extensions / ExitIntent / ExitIntentNotification.php

ExitIntentNotification.php in NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar 3.2.9, at includes/Extensions/ExitIntent/ExitIntentNotification.php

2,250 lines 126.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Exit Intent Popup Extension
4 *
5 * @package NotificationX\Extensions
6 */
7
8 namespace NotificationX\Extensions\ExitIntent;
9
10 use NotificationX\NotificationX;
11 use NotificationX\GetInstance;
12 use NotificationX\Core\Rules;
13 use NotificationX\Core\Helper;
14 use NotificationX\Extensions\GlobalFields;
15 use NotificationX\Extensions\Extension;
16
17 /**
18 * Exit Intent Popup Extension
19 * @method static ExitIntentNotification get_instance($args = null)
20 */
21 class ExitIntentNotification extends Extension {
22 use GetInstance;
23
24 public $priority = 16;
25 public $id = 'exit_intent_custom';
26 public $doc_link = 'https://notificationx.com/docs/';
27 public $types = 'exit_intent';
28 public $module = 'modules_exit_intent';
29
30 /**
31 * Elementor seed-theme registry for the "Build With Elementor" modal.
32 * Populated alongside the JSON files in jsons/ (see Task 07).
33 *
34 * @var array<string, array{label:string, value:string, icon:string, column:string, title:string}>
35 */
36 public $elementor_themes = [];
37
38 public function __construct() {
39 parent::__construct();
40 add_action( 'init', [ $this, 'register_post_type' ] );
41 add_filter( 'get_edit_post_link', [ $this, 'filter_edit_post_link' ], 10, 3 );
42 add_filter( 'nx_filtered_post', [ $this, 'inject_elementor_html' ], 10, 2 );
43 add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_elementor_assets' ], 20 );
44 add_action( 'wp_head', [ $this, 'print_section_constraint_css' ], 99 );
45 add_action( 'elementor/documents/register_controls', [ $this, 'register_popup_layout_controls' ] );
46 add_action( 'elementor/editor/after_enqueue_scripts', [ $this, 'enqueue_editor_live_preview' ] );
47 }
48
49 /**
50 * Print the popup section's width constraint inline in <head>.
51 *
52 * Two cases:
53 * 1. Sections that have the `nx-exit-intent-section` class baked in via the
54 * seed JSON's css_classes setting — constrained by the first rule.
55 * 2. The Elementor editor preview iframe loads the nx_exit_intent post
56 * directly as its own page (body.single-nx_exit_intent). The second
57 * rule constrains ANY section on that page, including legacy imports
58 * made before css_classes was added to the seed JSON.
59 */
60 public function print_section_constraint_css() {
61 // Width is governed by the Layout panel's Width control via the
62 // `--nx-exit-width` CSS variable; fall back to the historical 540px cap
63 // when it is unset (older popups / default).
64 $vars = '';
65 if ( is_singular( 'nx_exit_intent' ) ) {
66 // Editor preview / direct view: resolve the variable from the saved
67 // Layout-panel settings on this document.
68 $layout = $this->get_popup_layout_settings( get_the_ID() );
69 if ( ! empty( $layout['width'] ) ) {
70 $vars .= '--nx-exit-width:' . $layout['width'] . ';';
71 }
72 if ( ! empty( $layout['height'] ) ) {
73 $vars .= '--nx-exit-height:' . $layout['height'] . ';';
74 }
75 }
76 echo "<style id='nx-exit-intent-section-constraint'>\n";
77 if ( '' !== $vars ) {
78 echo "body.single-nx_exit_intent{" . $vars . "}\n";
79 }
80 echo ".nx-exit-intent-section{width:100%!important;max-width:var(--nx-exit-width,540px)!important;margin-left:auto!important;margin-right:auto!important;}\n";
81 if ( is_singular( 'nx_exit_intent' ) ) {
82 echo "body.single-nx_exit_intent .elementor-section,body.single-nx_exit_intent .e-con{width:100%!important;max-width:var(--nx-exit-width,540px)!important;margin-left:auto!important;margin-right:auto!important;}\n";
83 }
84 echo "</style>\n";
85 }
86
87 /**
88 * Server-side: inject the Elementor-rendered HTML + a `mode` flag into the
89 * REST payload so the React popup shell can render it.
90 *
91 * Runs for every campaign settings array via the `nx_filtered_post` filter;
92 * scoped to Exit Intent campaigns that have a linked, published nx_exit_intent.
93 */
94 public function inject_elementor_html( $settings, $params ) {
95 if ( empty( $settings['source'] ) || $settings['source'] !== $this->id ) {
96 return $settings;
97 }
98 $elementor_id = isset( $settings['elementor_id'] ) ? (int) $settings['elementor_id'] : 0;
99 if ( ! $elementor_id || ! class_exists( '\\Elementor\\Plugin' ) ) {
100 $settings['mode'] = 'built_in';
101 return $settings;
102 }
103 if ( get_post_status( $elementor_id ) !== 'publish' ) {
104 $settings['mode'] = 'built_in';
105 return $settings;
106 }
107
108 $resolved_id = apply_filters( 'wpml_object_id', $elementor_id, 'nx_exit_intent', true );
109 $html = \Elementor\Plugin::$instance->frontend->get_builder_content_for_display( $resolved_id, false );
110
111 // Surface the Layout-panel settings (registered in register_popup_layout_controls)
112 // so the popup runtime can honour them, and set --nx-exit-width on a wrapper so
113 // the section width constraint reflects the configured Width on the frontend.
114 $layout = $this->get_popup_layout_settings( $resolved_id );
115 $wrapper_vars = '';
116 if ( ! empty( $layout['width'] ) ) {
117 $wrapper_vars .= '--nx-exit-width:' . $layout['width'] . ';';
118 }
119 if ( ! empty( $layout['height'] ) ) {
120 $wrapper_vars .= '--nx-exit-height:' . $layout['height'] . ';';
121 }
122 if ( '' !== $wrapper_vars ) {
123 $html = '<div class="nx-exit-intent-elementor-wrap" style="' . esc_attr( $wrapper_vars ) . '">' . $html . '</div>';
124 }
125
126 $settings['mode'] = 'elementor';
127 $settings['elementor_html'] = $html;
128 $settings['popup_layout'] = $layout;
129 return $settings;
130 }
131
132 /**
133 * Read the Layout-panel settings off an nx_exit_intent Elementor document and
134 * normalise them into a flat array the popup runtime can consume.
135 *
136 * @param int $elementor_id
137 * @return array
138 */
139 protected function get_popup_layout_settings( $elementor_id ) {
140 $defaults = [
141 'width' => '',
142 'height_mode' => 'fit',
143 'height' => '',
144 'horizontal' => 'center',
145 'vertical' => 'center',
146 'overlay' => true,
147 'close_button' => true,
148 'entrance_animation' => '',
149 'exit_animation' => '',
150 ];
151
152 if ( ! class_exists( '\\Elementor\\Plugin' ) ) {
153 return $defaults;
154 }
155 $document = \Elementor\Plugin::$instance->documents->get( $elementor_id );
156 if ( ! $document ) {
157 return $defaults;
158 }
159
160 $size = static function ( $value ) {
161 if ( is_array( $value ) && isset( $value['size'] ) && '' !== $value['size'] ) {
162 return $value['size'] . ( isset( $value['unit'] ) ? $value['unit'] : 'px' );
163 }
164 return '';
165 };
166
167 $height_mode = $document->get_settings( 'nx_popup_height' );
168
169 // Width precedence: the Layout-panel Width control if the user set one,
170 // otherwise the design's own top-level container width (boxed_width).
171 // Without this, every popup falls back to the CSS 540px default, which
172 // crushes wider designs (e.g. the two-column 896px themes).
173 $width = $size( $document->get_settings( 'nx_popup_width' ) );
174 if ( '' === $width ) {
175 $width = $this->resolve_design_width( $document );
176 }
177
178 return [
179 'width' => $width,
180 'height_mode' => $height_mode ? $height_mode : 'fit',
181 'height' => 'custom' === $height_mode ? $size( $document->get_settings( 'nx_popup_custom_height' ) ) : '',
182 'horizontal' => $document->get_settings( 'nx_popup_horizontal' ) ?: 'center',
183 'vertical' => $document->get_settings( 'nx_popup_vertical' ) ?: 'center',
184 'overlay' => 'yes' === $document->get_settings( 'nx_popup_overlay' ),
185 'close_button' => 'yes' === $document->get_settings( 'nx_popup_close_button' ),
186 'entrance_animation' => (string) $document->get_settings( 'nx_popup_entrance_animation' ),
187 'exit_animation' => (string) $document->get_settings( 'nx_popup_exit_animation' ),
188 ];
189 }
190
191 /**
192 * Derive the popup's intended width from its Elementor design — the widest
193 * px width among the top-level elements (boxed_width / width / content_width).
194 * Used as the default popup width when no Layout-panel Width is configured,
195 * so each design keeps its own width instead of the 540px CSS fallback.
196 * Only top-level elements are inspected so inner column widths are ignored.
197 *
198 * @param \Elementor\Core\Base\Document $document
199 * @return string e.g. "896px", or '' when no explicit px width is defined.
200 */
201 protected function resolve_design_width( $document ) {
202 if ( ! $document || ! method_exists( $document, 'get_elements_data' ) ) {
203 return '';
204 }
205 $data = $document->get_elements_data();
206 if ( empty( $data ) || ! is_array( $data ) ) {
207 return '';
208 }
209 $max = 0;
210 foreach ( $data as $element ) {
211 if ( empty( $element['settings'] ) || ! is_array( $element['settings'] ) ) {
212 continue;
213 }
214 foreach ( [ 'boxed_width', 'width', 'content_width' ] as $key ) {
215 $val = isset( $element['settings'][ $key ] ) ? $element['settings'][ $key ] : null;
216 if ( is_array( $val ) && isset( $val['size'] ) && is_numeric( $val['size'] )
217 && ( ! isset( $val['unit'] ) || 'px' === $val['unit'] ) ) {
218 $max = max( $max, (float) $val['size'] );
219 }
220 }
221 }
222 return $max > 0 ? $max . 'px' : '';
223 }
224
225 /**
226 * Make sure Elementor's per-document CSS/JS is enqueued on every page where
227 * an Exit Intent campaign can fire — get_builder_content_for_display alone
228 * registers some assets, but not on pages other than the document's own URL.
229 */
230 public function enqueue_elementor_assets() {
231 if ( ! class_exists( '\\Elementor\\Core\\Files\\CSS\\Post' ) ) {
232 return;
233 }
234 $ids = [];
235 try {
236 $posts = \NotificationX\Core\PostType::get_instance()->get_posts( [ 'source' => $this->id ] );
237 foreach ( $posts as $post ) {
238 if ( ! empty( $post['elementor_id'] ) && empty( $post['enabled'] ) === false ) {
239 $ids[] = (int) $post['elementor_id'];
240 }
241 }
242 } catch ( \Exception $e ) {
243 return;
244 }
245 foreach ( $ids as $id ) {
246 try {
247 $css = \Elementor\Core\Files\CSS\Post::create( $id );
248 if ( $css ) {
249 $css->enqueue();
250 }
251 } catch ( \Exception $e ) {
252 // swallow — one broken doc shouldn't break the rest.
253 }
254 }
255 }
256
257 /**
258 * Register the post type that backs Elementor-designed Exit Intent popups.
259 *
260 * Mirrors PressBar's `nx_bar`: not public, but publicly_queryable so Elementor's
261 * preview routes resolve. `supports[]` must include `elementor` for Elementor's
262 * documents API to treat this as a first-class document.
263 *
264 * @return void
265 */
266 public static function register_post_type() {
267 register_post_type( 'nx_exit_intent', [
268 'label' => __( 'NotificationX Exit Intent', 'notificationx' ),
269 'public' => false,
270 'publicly_queryable' => true,
271 'show_ui' => false,
272 'show_in_menu' => true,
273 'show_in_nav_menus' => false,
274 'exclude_from_search' => true,
275 'rewrite' => false,
276 'capability_type' => 'post',
277 'hierarchical' => false,
278 'menu_icon' => 'dashicons-admin-page',
279 'supports' => [ 'title', 'content', 'author', 'elementor' ],
280 ] );
281 }
282
283 /**
284 * Add a "Layout" section to the Elementor document-settings panel, but ONLY
285 * for nx_exit_intent documents. Mirrors Elementor Pro's Popup → Layout panel
286 * (Width / Height / Position / Overlay / Close Button / Animations).
287 *
288 * Hooked on `elementor/documents/register_controls`, which fires for every
289 * document right after its built-in controls register. We bail for any other
290 * post type so these controls never leak into normal pages/posts.
291 *
292 * Width is wired live via the `--nx-exit-width` CSS variable that
293 * print_section_constraint_css()/inject_elementor_html() read; the remaining
294 * controls persist into the document's page settings (`_elementor_page_settings`)
295 * so the popup runtime can consume them.
296 *
297 * @param \Elementor\Core\Base\Document $document
298 * @return void
299 */
300 public function register_popup_layout_controls( $document ) {
301 if ( ! is_object( $document ) || ! method_exists( $document, 'get_post' ) ) {
302 return;
303 }
304 $post = $document->get_post();
305 if ( ! $post || 'nx_exit_intent' !== $post->post_type ) {
306 return;
307 }
308
309 $cm = '\Elementor\Controls_Manager';
310
311 $document->start_controls_section(
312 'nx_popup_layout',
313 [
314 'label' => __( 'Layout', 'notificationx' ),
315 'tab' => $cm::TAB_SETTINGS,
316 ]
317 );
318
319 $document->add_responsive_control(
320 'nx_popup_width',
321 [
322 'label' => __( 'Width', 'notificationx' ),
323 'type' => $cm::SLIDER,
324 'size_units' => [ 'px', '%', 'vw' ],
325 'range' => [
326 'px' => [ 'min' => 100, 'max' => 1140 ],
327 '%' => [ 'min' => 10, 'max' => 100 ],
328 'vw' => [ 'min' => 10, 'max' => 100 ],
329 ],
330 // No default: when the user hasn't set a Width, the popup falls back
331 // to the design's own container width (resolve_design_width()), not a
332 // fixed 540px — otherwise wider designs (e.g. the 896px two-column
333 // themes) get crushed. An explicit value here still wins.
334 //
335 // NOTE: no `selectors` key — Elementor silently drops document-level
336 // controls that carry `selectors`. The value is applied server-side
337 // via the --nx-exit-width variable in print_section_constraint_css()
338 // (preview) and inject_elementor_html() (frontend) instead.
339 'default' => [ 'unit' => 'px', 'size' => '' ],
340 ]
341 );
342
343 $document->add_control(
344 'nx_popup_height',
345 [
346 'label' => __( 'Height', 'notificationx' ),
347 'type' => $cm::SELECT,
348 'default' => 'fit',
349 'options' => [
350 'fit' => __( 'Fit To Content', 'notificationx' ),
351 'custom' => __( 'Custom Height', 'notificationx' ),
352 ],
353 ]
354 );
355
356 $document->add_responsive_control(
357 'nx_popup_custom_height',
358 [
359 'label' => __( 'Custom Height', 'notificationx' ),
360 'type' => $cm::SLIDER,
361 'size_units' => [ 'px', 'vh' ],
362 'range' => [
363 'px' => [ 'min' => 100, 'max' => 1000 ],
364 'vh' => [ 'min' => 10, 'max' => 100 ],
365 ],
366 'default' => [ 'unit' => 'px', 'size' => 480 ],
367 'condition' => [ 'nx_popup_height' => 'custom' ],
368 // No `selectors` (see nx_popup_width note); applied via --nx-exit-height.
369 ]
370 );
371
372 $document->add_control(
373 'nx_popup_position_heading',
374 [
375 'label' => __( 'Position', 'notificationx' ),
376 'type' => $cm::HEADING,
377 'separator' => 'before',
378 ]
379 );
380
381 $document->add_responsive_control(
382 'nx_popup_horizontal',
383 [
384 'label' => __( 'Horizontal', 'notificationx' ),
385 'type' => $cm::CHOOSE,
386 'default' => 'center',
387 'options' => [
388 'start' => [ 'title' => __( 'Start', 'notificationx' ), 'icon' => 'eicon-h-align-left' ],
389 'center' => [ 'title' => __( 'Center', 'notificationx' ), 'icon' => 'eicon-h-align-center' ],
390 'end' => [ 'title' => __( 'End', 'notificationx' ), 'icon' => 'eicon-h-align-right' ],
391 ],
392 ]
393 );
394
395 $document->add_responsive_control(
396 'nx_popup_vertical',
397 [
398 'label' => __( 'Vertical', 'notificationx' ),
399 'type' => $cm::CHOOSE,
400 'default' => 'center',
401 'options' => [
402 'start' => [ 'title' => __( 'Top', 'notificationx' ), 'icon' => 'eicon-v-align-top' ],
403 'center' => [ 'title' => __( 'Middle', 'notificationx' ), 'icon' => 'eicon-v-align-middle' ],
404 'end' => [ 'title' => __( 'Bottom', 'notificationx' ), 'icon' => 'eicon-v-align-bottom' ],
405 ],
406 ]
407 );
408
409 $document->add_control(
410 'nx_popup_overlay',
411 [
412 'label' => __( 'Overlay', 'notificationx' ),
413 'type' => $cm::SWITCHER,
414 'label_on' => __( 'Show', 'notificationx' ),
415 'label_off' => __( 'Hide', 'notificationx' ),
416 'return_value' => 'yes',
417 'default' => 'yes',
418 'separator' => 'before',
419 ]
420 );
421
422 $document->add_control(
423 'nx_popup_close_button',
424 [
425 'label' => __( 'Close Button', 'notificationx' ),
426 'type' => $cm::SWITCHER,
427 'label_on' => __( 'Show', 'notificationx' ),
428 'label_off' => __( 'Hide', 'notificationx' ),
429 'return_value' => 'yes',
430 'default' => 'yes',
431 ]
432 );
433
434 $document->add_control(
435 'nx_popup_entrance_animation',
436 [
437 'label' => __( 'Entrance Animation', 'notificationx' ),
438 'type' => $cm::ANIMATION,
439 'separator' => 'before',
440 ]
441 );
442
443 $document->add_control(
444 'nx_popup_exit_animation',
445 [
446 'label' => __( 'Exit Animation', 'notificationx' ),
447 'type' => $cm::EXIT_ANIMATION,
448 ]
449 );
450
451 $document->end_controls_section();
452 }
453
454 /**
455 * Live-preview bridge for the Layout panel inside the Elementor editor.
456 *
457 * Document-level controls can't carry a `selectors` key (Elementor drops
458 * them), so Width/Height don't get Elementor's built-in live CSS injection.
459 * This registers page-settings change callbacks that write the
460 * `--nx-exit-width` / `--nx-exit-height` variables straight onto the preview
461 * iframe's <body> as the slider moves — so changes reflect instantly instead
462 * of only after a reload.
463 *
464 * Scoped to nx_exit_intent documents only.
465 *
466 * @return void
467 */
468 public function enqueue_editor_live_preview() {
469 if ( ! class_exists( '\\Elementor\\Plugin' ) ) {
470 return;
471 }
472 $post_id = \Elementor\Plugin::$instance->editor->get_post_id();
473 if ( ! $post_id || 'nx_exit_intent' !== get_post_type( $post_id ) ) {
474 return;
475 }
476
477 $js = <<<'JS'
478 ( function ( $ ) {
479 function toCss( value ) {
480 if ( value && '' !== value.size && null != value.size ) {
481 return value.size + ( value.unit || 'px' );
482 }
483 return '';
484 }
485 function previewBody() {
486 var frame = elementor.$preview && elementor.$preview[0];
487 var win = frame && frame.contentWindow;
488 return win && win.document ? win.document.body : null;
489 }
490 function applyVar( name, value ) {
491 var body = previewBody();
492 if ( ! body ) { return; }
493 var css = toCss( value );
494 if ( css ) { body.style.setProperty( name, css ); }
495 else { body.style.removeProperty( name ); }
496 }
497 $( window ).on( 'elementor:init', function () {
498 if ( 'undefined' === typeof elementor || ! elementor.settings || ! elementor.settings.page ) {
499 return;
500 }
501 elementor.settings.page.addChangeCallback( 'nx_popup_width', function ( value ) {
502 applyVar( '--nx-exit-width', value );
503 } );
504 elementor.settings.page.addChangeCallback( 'nx_popup_custom_height', function ( value ) {
505 applyVar( '--nx-exit-height', value );
506 } );
507 } );
508 } )( jQuery );
509 JS;
510
511 wp_add_inline_script( 'elementor-editor', $js );
512 }
513
514 /**
515 * Create a new `nx_exit_intent` Elementor document from a seed theme and
516 * respond to the admin with the new post ID + Elementor edit URL.
517 *
518 * Counterpart of PressBar::create_bar_of_type_bar_with_elementor().
519 *
520 * @param array $params { theme_id: string }
521 * @return void Always responds via wp_send_json_{success,error}.
522 */
523 public function create_exit_intent_with_elementor( $params ) {
524 if ( empty( $params['theme_id'] ) ) {
525 wp_send_json_error( 'missing_theme_id' );
526 }
527
528 $theme = sanitize_text_field( $params['theme_id'] );
529 $importer = new Importer();
530
531 $ID = $importer->create_nx( [
532 'theme' => $theme,
533 'post_title' => 'Design for NotificationX Exit Intent - ',
534 ] );
535
536 if ( $ID && ! is_wp_error( $ID ) ) {
537 // Strip theme chrome — popup HTML inlines into the host page.
538 update_post_meta( $ID, '_wp_page_template', 'elementor_canvas' );
539 wp_send_json_success( [
540 'context' => [
541 'themes' => null,
542 'elementor_id' => $ID,
543 'elementor_edit_link' => \Elementor\Plugin::$instance->documents->get( $ID )->get_edit_url(),
544 ],
545 ] );
546 } else {
547 wp_send_json_error( is_wp_error( $ID ) ? $ID->get_error_message() : 'failed' );
548 }
549 }
550
551 /**
552 * Delete the linked `nx_exit_intent` Elementor post (and its WPML translations).
553 *
554 * @param int|string $elementor_id
555 * @return void
556 */
557 public function delete_elementor_post( $elementor_id ) {
558 if ( empty( $elementor_id ) ) {
559 return;
560 }
561 $languages = apply_filters( 'wpml_active_languages', null );
562 if ( is_array( $languages ) ) {
563 foreach ( $languages as $lang => $val ) {
564 $translated_id = apply_filters( 'wpml_object_id', $elementor_id, 'nx_exit_intent', false, $lang );
565 if ( $translated_id ) {
566 wp_delete_post( $translated_id, true );
567 }
568 }
569 return;
570 }
571 wp_delete_post( $elementor_id, true );
572 }
573
574 /**
575 * Redirect WP "Edit" links for nx_exit_intent posts straight into the Elementor editor.
576 *
577 * @param string $link
578 * @param int $id
579 * @param string $context
580 * @return string
581 */
582 public function filter_edit_post_link( $link, $id, $context ) {
583 $post = get_post( $id );
584 if ( $post && 'nx_exit_intent' === $post->post_type && class_exists( '\\Elementor\\Plugin' ) ) {
585 return \Elementor\Plugin::$instance->documents->get( $id )->get_edit_url();
586 }
587 return $link;
588 }
589
590 public function init_extension() {
591 $this->title = __( 'Exit Intent Popup', 'notificationx' );
592 $this->module_title = __( 'Exit Intent Popup', 'notificationx' );
593 $this->themes = [
594 'theme-one' => [
595 'source' => NOTIFICATIONX_ADMIN_URL . 'images/extensions/themes/exit-intent/exit-intent-theme-one.png',
596 'defaults' => [
597 'exit_intent_title' => __( 'Wait! Before You Go……', 'notificationx' ),
598 'exit_intent_subtitle' => __( "We'd love to get your feedback and help us make this better for everyone.", 'notificationx' ),
599 'exit_intent_button_text' => __( 'SUBMIT', 'notificationx' ),
600 // 'exit_intent_show_name' => true,
601 // 'exit_intent_show_email' => true,
602 'exit_intent_name_label' => __( 'Name *', 'notificationx' ),
603 'exit_intent_email_label' => __( 'Enter Your Email *', 'notificationx' ),
604 // 'exit_intent_show_message' => false,
605 'exit_intent_message_placeholder' => __( 'Your message...', 'notificationx' ),
606 'position' => 'center',
607 ],
608 'column' => '5',
609 ],
610 'theme-four' => [
611 'source' => NOTIFICATIONX_ADMIN_URL . 'images/extensions/themes/exit-intent/exit-intent-theme-four.png',
612 'defaults' => [
613 'exit_intent_t4_badge' => __( 'Before you go...', 'notificationx' ),
614 'exit_intent_t4_title' => __( 'Watch this short demo video', 'notificationx' ),
615 'exit_intent_t4_subtitle' => __( 'See how our product simplifies your workflow.', 'notificationx' ),
616 'exit_intent_image_url' => [ 'url' => 'https://notificationx.com/wp-content/uploads/2026/05/exit-intend-theme-four.jpg' ],
617 'exit_intent_t4_video_url' => '',
618 'position' => 'center',
619 ],
620 'column' => '5',
621 ],
622 'theme-three' => [
623 'source' => NOTIFICATIONX_ADMIN_URL . 'images/extensions/themes/exit-intent/exit-intent-theme-three.png',
624 'defaults' => [
625 'exit_intent_t3_title' => __( "Wait, don't go!", 'notificationx' ),
626 'exit_intent_t3_subtitle' => __( 'Before you leave, we have a special offer just for you!', 'notificationx' ),
627 'exit_intent_t3_offer' => __( 'Get 15% off your next purchase!', 'notificationx' ),
628 'exit_intent_t3_coupon_text' => __( "Use code STAY15 at checkout. Don't miss out on this limited-time offer.", 'notificationx' ),
629 'exit_intent_button_text' => __( 'Claim Offer', 'notificationx' ),
630 'exit_intent_dismiss_text' => __( 'No, thanks!', 'notificationx' ),
631 'exit_intent_image_url' => [ 'url' => 'https://notificationx.com/wp-content/uploads/2026/05/exit-intend-theme-three.png' ],
632 'position' => 'center',
633 ],
634 'column' => '5',
635 ],
636 'theme-six' => [
637 'source' => NOTIFICATIONX_ADMIN_URL . 'images/extensions/themes/exit-intent/exit-intent-theme-seven.png',
638 'defaults' => [
639 'exit_intent_t6_title' => __( 'Limited Edition Bass Boost Headphones', 'notificationx' ),
640 // 'exit_intent_t6_show_timer' => true,
641 'exit_intent_t6_countdown_label' => __( 'Offer Ends In', 'notificationx' ),
642 'exit_intent_countdown_end' => '',
643 'exit_intent_t6_days_label' => __( 'DAYS', 'notificationx' ),
644 'exit_intent_t6_hours_label' => __( 'HOURS', 'notificationx' ),
645 'exit_intent_t6_minutes_label' => __( 'MIN', 'notificationx' ),
646 'exit_intent_t6_seconds_label' => __( 'SEC', 'notificationx' ),
647 'exit_intent_button_text' => __( 'Grab Now', 'notificationx' ),
648 'exit_intent_image_url' => [ 'url' => 'https://notificationx.com/wp-content/uploads/2026/05/exit-intend-theme-six.png' ],
649 'position' => 'center',
650 ],
651 'column' => '5',
652 'is_pro' => true,
653 ],
654 'theme-two' => [
655 'source' => NOTIFICATIONX_ADMIN_URL . 'images/extensions/themes/exit-intent/exit-intent-theme-two.png',
656 'defaults' => [
657 'exit_intent_sale_badge' => __( 'Flash Sale', 'notificationx' ),
658 'exit_intent_sale_headline' => __( '50% OFF', 'notificationx' ),
659 'exit_intent_sale_desc' => __( 'ON ENTIRE ORDER', 'notificationx' ),
660 'exit_intent_button_text' => __( 'Shop The Flash Sale Now', 'notificationx' ),
661 'exit_intent_dismiss_text' => __( 'NO, THANKS!', 'notificationx' ),
662 'exit_intent_image_url' => [ 'url' => 'https://notificationx.com/wp-content/uploads/2026/05/exit-intend-theme-two.jpg' ],
663 'position' => 'center',
664 ],
665 'column' => '5',
666 'is_pro' => true,
667 ],
668 'theme-seven' => [
669 'source' => NOTIFICATIONX_ADMIN_URL . 'images/extensions/themes/exit-intent/exit-intent-theme-six.png',
670 'defaults' => [
671 'exit_intent_t7_headline' => __( 'Turn Your House Into a Home', 'notificationx' ),
672 'exit_intent_t7_discount_text' => __( 'Your First Order Comes With a Surprise Deal!', 'notificationx' ),
673 'exit_intent_t7_description' => __( 'Handpicked decor that feels like home the moment it arrives.', 'notificationx' ),
674 'exit_intent_t7_email_placeholder' => __( 'Enter your email', 'notificationx' ),
675 'exit_intent_button_text' => __( 'SEND COUPON', 'notificationx' ),
676 'exit_intent_image_url' => [ 'url' => 'https://notificationx.com/wp-content/uploads/2026/05/exit-intend-theme-five.png' ],
677 'position' => 'center',
678 ],
679 'column' => '5',
680 'is_pro' => true,
681 ],
682 'theme-five' => [
683 'source' => NOTIFICATIONX_ADMIN_URL . 'images/extensions/themes/exit-intent/exit-intent-theme-five.png',
684 'defaults' => [
685 'exit_intent_t5_title' => __( 'Flash Sale', 'notificationx' ),
686 'exit_intent_t5_headline' => __( '50% OFF', 'notificationx' ),
687 'exit_intent_t5_desc' => __( 'ON ENTIRE ORDER', 'notificationx' ),
688 'exit_intent_t5_countdown_label' => __( 'LIMITED-TIME OFFER! SALE ENDS IN', 'notificationx' ),
689 'exit_intent_countdown_end' => '',
690 'exit_intent_t5_days_label' => __( 'DAYS', 'notificationx' ),
691 'exit_intent_t5_hours_label' => __( 'HRS', 'notificationx' ),
692 'exit_intent_t5_minutes_label' => __( 'MIN', 'notificationx' ),
693 'exit_intent_t5_seconds_label' => __( 'SEC', 'notificationx' ),
694 'exit_intent_t5_timer_bg' => '#fff0f5',
695 'exit_intent_t5_timer_color' => '#e91e63',
696 'exit_intent_button_text' => __( 'Shop The Flash Sale Now', 'notificationx' ),
697 'exit_intent_dismiss_text' => __( 'NO, THANKS!', 'notificationx' ),
698 'exit_intent_image_url' => [ 'url' => 'https://notificationx.com/wp-content/uploads/2026/05/exit-intend-theme-six.jpg' ],
699 'position' => 'center',
700 ],
701 'column' => '5',
702 'is_pro' => true,
703 ],
704 ];
705
706 // Elementor seed themes for the "Build With Elementor" modal.
707 // Each entry has a matching JSON file under jsons/{value}.json (Task 07).
708 // Preview images live under assets/admin/images/extensions/themes/exit-intent-elementor/.
709 // Until per-theme Elementor previews are rendered, we fall back to the existing
710 // built-in screenshots so the modal renders with a real image.
711 // Order intentionally mirrors the built-in $themes preset order above
712 // (one, four, three, six, two, seven, five) so the Elementor modal lists
713 // the same designs in the same sequence as the Default-theme picker.
714 //
715 // Unlike $themes (processed by Extension::__nx_themes), this array is fed
716 // straight to the radio-card field, so we must resolve the pro badge here:
717 // only flag a theme as pro when the Pro plugin is NOT active.
718 $is_pro_badge = ! NotificationX::is_pro();
719 $this->elementor_themes = [
720 'theme-one' => [
721 'label' => 'theme-one',
722 'value' => 'theme-one',
723 'icon' => NOTIFICATIONX_ADMIN_URL . 'images/extensions/themes/exit-intent/exit-intent-theme-one.png',
724 'column' => '6',
725 'title' => 'Exit Intent Theme One',
726 ],
727 'theme-four' => [
728 'label' => 'theme-four',
729 'value' => 'theme-four',
730 'icon' => NOTIFICATIONX_ADMIN_URL . 'images/extensions/themes/exit-intent/exit-intent-theme-four.png',
731 'column' => '6',
732 'title' => 'Exit Intent Theme Four',
733 ],
734 'theme-three' => [
735 'label' => 'theme-three',
736 'value' => 'theme-three',
737 'icon' => NOTIFICATIONX_ADMIN_URL . 'images/extensions/themes/exit-intent/exit-intent-theme-three.png',
738 'column' => '6',
739 'title' => 'Exit Intent Theme Three',
740 ],
741 'theme-six' => [
742 'label' => 'theme-six',
743 'value' => 'theme-six',
744 'icon' => NOTIFICATIONX_ADMIN_URL . 'images/extensions/themes/exit-intent/exit-intent-theme-six.png',
745 'column' => '6',
746 'title' => 'Exit Intent Theme Six',
747 'is_pro' => $is_pro_badge,
748 ],
749 'theme-two' => [
750 'label' => 'theme-two',
751 'value' => 'theme-two',
752 'icon' => NOTIFICATIONX_ADMIN_URL . 'images/extensions/themes/exit-intent/exit-intent-theme-two.png',
753 'column' => '6',
754 'title' => 'Exit Intent Theme Two',
755 'is_pro' => $is_pro_badge,
756 ],
757 'theme-seven' => [
758 'label' => 'theme-seven',
759 'value' => 'theme-seven',
760 'icon' => NOTIFICATIONX_ADMIN_URL . 'images/extensions/themes/exit-intent/exit-intent-theme-seven.png',
761 'column' => '6',
762 'title' => 'Exit Intent Theme Seven',
763 'is_pro' => $is_pro_badge,
764 ],
765 'theme-five' => [
766 'label' => 'theme-five',
767 'value' => 'theme-five',
768 'icon' => NOTIFICATIONX_ADMIN_URL . 'images/extensions/themes/exit-intent/exit-intent-theme-five.png',
769 'column' => '6',
770 'title' => 'Exit Intent Theme Five',
771 'is_pro' => $is_pro_badge,
772 ],
773 ];
774 }
775
776 public function init_fields() {
777 parent::init_fields();
778 add_filter( 'nx_content_fields', [ $this, 'content_fields' ], 999 );
779 add_filter( 'nx_design_tab_fields', [ $this, 'design_fields' ], 99 );
780 add_filter( 'nx_design_tab_fields', [ $this, 'builder_tabs_fields' ], 100 );
781 add_filter( 'nx_customize_fields', [ $this, 'customize_fields' ], 999 );
782 add_filter( 'nx_display_fields', [ $this, 'display_fields' ], 999 );
783
784 // Hide per-theme content sections when an Elementor doc is linked (Task 06).
785 // We deliberately do NOT hide the themes radio-card itself — keeping it
786 // visible on the Default tab lets users switch back to a built-in theme
787 // after they've imported an Elementor design.
788 add_filter( 'nx_content_fields', [ $this, 'suppress_when_elementor' ], 1001 );
789
790 // Hide the whole Content wizard step when an Elementor design is linked —
791 // suppress_when_elementor() empties every content section in that case, so
792 // the step would otherwise render as a blank tab.
793 add_filter( 'nx_metabox_tabs', [ $this, 'hide_content_tab_for_elementor' ] );
794 }
795
796 /**
797 * Remove the Content step from the wizard for Exit Intent campaigns that are
798 * built with Elementor. Elementor owns all of the popup's content there (every
799 * `exit_intent_*_section` is suppressed by suppress_when_elementor()), leaving
800 * the Content tab empty. Built-in themes keep the Content step, and all other
801 * sources are untouched.
802 *
803 * The tab stays visible UNLESS (source is Exit Intent AND elementor_id is a
804 * number), expressed below as the OR'd "show when" rule.
805 */
806 public function hide_content_tab_for_elementor( $tabs ) {
807 if ( empty( $tabs['content_tab'] ) ) {
808 return $tabs;
809 }
810 $show_rule = Rules::_logicalRule( [
811 Rules::_is( 'source', $this->id, true ),
812 Rules::_isOfType( 'elementor_id', 'number', true ),
813 ], 'or' );
814 $tabs['content_tab'] = Rules::add( $show_rule, $tabs['content_tab'] );
815 return $tabs;
816 }
817
818 /**
819 * Hide every per-theme content section once an Elementor design is linked.
820 * Elementor owns all of these fields; showing them would let users edit
821 * values with no visible effect on the rendered popup.
822 */
823 public function suppress_when_elementor( $fields ) {
824 foreach ( $fields as $key => $field ) {
825 if ( strpos( $key, 'exit_intent_' ) === 0 && substr( $key, -8 ) === '_section' ) {
826 $fields[ $key ] = Rules::isOfType( 'elementor_id', 'number', true, $field );
827 }
828 }
829 return $fields;
830 }
831
832 /**
833 * @deprecated Kept for back-compat only; the filter that called this has
834 * been removed so the themes radio stays visible on the Default tab even
835 * when an Elementor design is linked (lets users switch back).
836 */
837 public function suppress_themes_radio( $fields ) {
838 if ( ! isset( $fields['themes']['fields']['themes']['rules'] ) ) {
839 return $fields;
840 }
841 $existing = $fields['themes']['fields']['themes']['rules'];
842 // Additional clause: either we're NOT on Exit Intent (so this rule
843 // shouldn't change anything for other sources), OR elementor_id is
844 // not yet set. Combined via AND with the existing tab-gate so other
845 // sources (e.g. PressBar) keep their tab-based hiding intact.
846 $additional = Rules::logicalRule( [
847 Rules::is( 'source', $this->id, true ),
848 Rules::isOfType( 'elementor_id', 'number', true ),
849 ], 'or' );
850 $fields['themes']['fields']['themes']['rules'] = Rules::logicalRule( [
851 $existing,
852 $additional,
853 ], 'and' );
854 return $fields;
855 }
856
857 /**
858 * Restructures the Themes section into two tabs:
859 * 1. Default — original 7 React themes grid (the `themes` radio-card,
860 * already gated to themes_tab='for_desktop' in GlobalFields).
861 * 2. Custom — Build With Elementor button + modal, plus Edit/Remove
862 * and Install fallback after a doc is linked.
863 *
864 * Matches Notification Bar's Default/Custom tab structure.
865 */
866 public function builder_tabs_fields( $fields ) {
867 if ( empty( $fields['themes']['fields']['themes_section']['fields']['themes_tab']['fields'] ) ) {
868 return $fields;
869 }
870 $tab =& $fields['themes']['fields']['themes_section']['fields']['themes_tab']['fields'];
871
872 // Hide the global "For Desktop" / "For Mobile" tabs for Exit Intent only — we
873 // ship our own Default + Custom tabs below.
874 foreach ( [ 'for_desktop', 'for_mobile' ] as $key ) {
875 if ( isset( $tab[ $key ] ) ) {
876 $tab[ $key ] = Rules::is( 'source', $this->id, true, $tab[ $key ] );
877 }
878 }
879
880 // Expand the global themes radio-card so it ALSO renders when our new
881 // Default tab is active. Without this, the radio would never appear for
882 // Exit Intent — its existing rule is hard-coded to themes_tab='for_desktop'.
883 if ( isset( $fields['themes']['fields']['themes'] ) ) {
884 $fields['themes']['fields']['themes']['rules'] = Rules::logicalRule( [
885 Rules::is( 'themes_tab', 'for_desktop' ),
886 Rules::is( 'themes_tab', 'exit_intent_default_tab' ),
887 ], 'or' );
888 }
889
890 $is_installed = Helper::is_plugin_installed( 'elementor/elementor.php' );
891 $install_activate_text = $is_installed
892 ? __( 'Activate Elementor', 'notificationx' )
893 : __( 'Install Elementor', 'notificationx' );
894
895 // Default tab — unique name (no collision with global for_desktop).
896 $tab[] = [
897 'label' => __( 'Default', 'notificationx' ),
898 'name' => 'exit_intent_default_tab',
899 'id' => 'exit_intent_default_tab',
900 'type' => 'section',
901 'icon' => NOTIFICATIONX_ADMIN_URL . 'images/icons/nxbar-presets-icon.svg',
902 'rules' => Rules::is( 'source', $this->id ),
903 ];
904
905 // The Custom tab — only renders for Exit Intent campaigns.
906 $tab[] = [
907 'label' => __( 'Custom', 'notificationx' ),
908 'name' => 'exit_intent_custom_tab',
909 'id' => 'exit_intent_custom_tab',
910 'type' => 'section',
911 'icon' => NOTIFICATIONX_ADMIN_URL . 'images/icons/nxbar-custom-tab.svg',
912 'rules' => Rules::is( 'source', $this->id ),
913 'fields' => [
914
915 // Preview image / empty-state illustration (reuses NxBarPresets).
916 'exit_intent_custom_preview' => [
917 'name' => 'exit_intent_custom_preview',
918 'type' => 'exit-intent-custom',
919 'label' => __( 'Exit Intent', 'notificationx' ),
920 'priority' => 5,
921 ],
922
923 // Edit With Elementor — shown when an Elementor doc is linked.
924 'elementor_edit_link' => [
925 'name' => 'elementor_edit_link',
926 'type' => 'button',
927 'text' => __( 'Edit With Elementor', 'notificationx' ),
928 'href' => -1,
929 'priority' => 10,
930 'target' => '_blank',
931 'rules' => Rules::logicalRule( [
932 Rules::is( 'elementor_edit_link', false, true ),
933 Rules::isOfType( 'elementor_edit_link', 'string' ),
934 Rules::is( 'elementor_id', false, true ),
935 ] ),
936 ],
937
938 // Remove — deletes the Elementor doc and resets state.
939 'nx-exit-intent_with_elementor-remove' => [
940 'name' => 'nx-exit-intent_with_elementor-remove',
941 'type' => 'button',
942 'text' => __( 'Remove', 'notificationx' ),
943 'priority' => 15,
944 'rules' => Rules::logicalRule( [
945 Rules::is( 'elementor_id', false, true ),
946 Rules::is( 'is_elementor', true ),
947 Rules::is( 'source', $this->id ),
948 ] ),
949 'ajax' => [
950 'on' => 'click',
951 'api' => '/notificationx/v1/exit-intent/elementor/remove',
952 'data' => [ 'elementor_id' => '@elementor_id' ],
953 'hideSwal' => true,
954 ],
955 'trigger' => [
956 [
957 'type' => 'setFieldValue',
958 'action' => [
959 'elementor_id' => false,
960 'elementor_edit_link' => '',
961 'elementor_exit_theme' => 'theme-one',
962 'is_confirmed' => false,
963 'themes' => $this->id . '_theme-one',
964 ],
965 ],
966 ],
967 ],
968
969 // Build With Elementor — modal with seed-theme picker.
970 'nx-exit-intent_with_elementor' => [
971 'name' => 'nx-exit-intent_with_elementor',
972 'type' => 'modal',
973 'priority' => 20,
974 'button' => [
975 'name' => 'build_with_elementor',
976 'text' => __( 'Build With Elementor', 'notificationx' ),
977 'trigger' => [
978 [
979 'type' => 'setFieldValue',
980 'action' => [ 'import_elementor_theme' => false ],
981 ],
982 ],
983 ],
984 'confirm_button' => [
985 'type' => 'button',
986 'name' => 'import_elementor_theme',
987 'group' => true,
988 'fields' => [
989 [
990 'type' => 'button',
991 'name' => 'import_elementor_theme',
992 'default' => false,
993 'text' => [
994 'normal' => __( 'Import', 'notificationx' ),
995 'saved' => __( 'Import', 'notificationx' ),
996 'loading' => __( 'Importing...', 'notificationx' ),
997 ],
998 'ajax' => [
999 'on' => 'click',
1000 'api' => '/notificationx/v1/exit-intent/elementor/import',
1001 'data' => [ 'theme_id' => '@elementor_exit_theme' ],
1002 'trigger' => '@is_confirmed:true',
1003 'hideSwal' => true,
1004 ],
1005 'rules' => Rules::is( 'is_confirmed', true, true ),
1006 ],
1007 [
1008 'type' => 'button',
1009 'name' => 'import_elementor_theme_next',
1010 'default' => false,
1011 'text' => __( 'Next', 'notificationx' ),
1012 'rules' => Rules::is( 'is_confirmed', true ),
1013 'trigger' => [
1014 [
1015 'type' => 'setContext',
1016 'action' => [ 'config.active' => 'display_tab' ],
1017 ],
1018 [
1019 'type' => 'setFieldValue',
1020 'action' => [ 'import_elementor_theme_next' => true ],
1021 ],
1022 ],
1023 ],
1024 ],
1025 ],
1026 'cancel' => 'import_elementor_theme_next',
1027 'body' => [
1028 'header' => __( 'Choose Your ', 'notificationx' ),
1029 'fields' => [
1030 'themes' => [
1031 'type' => 'radio-card',
1032 'name' => 'elementor_exit_theme',
1033 'style' => [ 'label' => [ 'position' => 'top' ] ],
1034 'rules' => Rules::is( 'is_confirmed', true, true ),
1035 'default' => 'theme-one',
1036 'options' => $this->elementor_themes,
1037 ],
1038 ],
1039 ],
1040 'rules' => Rules::logicalRule( [
1041 Rules::is( 'elementor_id', false ),
1042 Rules::is( 'is_elementor', true ),
1043 Rules::is( 'is_confirmed', true, true ),
1044 Rules::is( 'source', $this->id ),
1045 ] ),
1046 ],
1047
1048 // Install / Activate Elementor — fallback when Elementor isn't active.
1049 'nx-exit-intent_with_elementor_install' => [
1050 'name' => 'nx-exit-intent_with_elementor_install',
1051 'type' => 'button',
1052 'priority' => 25,
1053 'text' => [
1054 'normal' => $install_activate_text,
1055 'saved' => $is_installed ? __( 'Activated Elementor', 'notificationx' ) : __( 'Installed Elementor', 'notificationx' ),
1056 'loading' => $is_installed ? __( 'Activating Elementor...', 'notificationx' ) : __( 'Installing Elementor...', 'notificationx' ),
1057 ],
1058 'rules' => Rules::logicalRule( [
1059 Rules::is( 'is_elementor', false ),
1060 Rules::is( 'source', $this->id ),
1061 ] ),
1062 'ajax' => [
1063 'on' => 'click',
1064 'api' => '/notificationx/v1/core-install',
1065 'data' => [
1066 'source' => $this->id,
1067 'slug' => 'elementor',
1068 'file' => 'elementor.php',
1069 'is_installed' => $is_installed,
1070 ],
1071 'swal' => [
1072 'icon' => 'success',
1073 'text' => __( 'Successfully Activated', 'notificationx' ),
1074 ],
1075 'trigger' => '@is_elementor:true',
1076 ],
1077 ],
1078
1079 // Hidden state fields (Task 05).
1080 'is_elementor' => [
1081 'name' => 'is_elementor',
1082 'type' => 'hidden',
1083 'default' => class_exists( '\\Elementor\\Plugin' ),
1084 'rules' => Rules::is( 'source', $this->id ),
1085 ],
1086 'elementor_id' => [
1087 'name' => 'elementor_id',
1088 'type' => 'hidden',
1089 'default' => false,
1090 'rules' => Rules::is( 'source', $this->id ),
1091 ],
1092 'is_confirmed' => [
1093 'name' => 'is_confirmed',
1094 'type' => 'hidden',
1095 'default' => false,
1096 ],
1097 ],
1098 ];
1099
1100 return $fields;
1101 }
1102
1103 public function display_fields( $fields ) {
1104 if ( isset( $fields['image-section'] ) ) {
1105 $fields['image-section'] = Rules::is( 'source', $this->id, true, $fields['image-section'] );
1106 }
1107 return $fields;
1108 }
1109
1110 public function content_fields( $fields ) {
1111 // Hide standard content fields for this source
1112 if ( isset( $fields['utm_options'] ) ) {
1113 $fields['utm_options'] = Rules::is( 'source', $this->id, true, $fields['utm_options'] );
1114 }
1115 if ( isset( $fields['content'] ) ) {
1116 $fields['content'] = Rules::is( 'source', $this->id, true, $fields['content'] );
1117 }
1118 if ( isset( $fields['link_options'] ) ) {
1119 $fields['link_options'] = Rules::is( 'source', $this->id, true, $fields['link_options'] );
1120 }
1121
1122 // ── Theme Two content fields ─────────────────────────────────────────────
1123 $fields['exit_intent_theme_two_section'] = [
1124 'label' => __( 'Exit Intent Content', 'notificationx' ),
1125 'name' => 'exit_intent_theme_two_section',
1126 'type' => 'section',
1127 'priority' => 5,
1128 'rules' => Rules::logicalRule( [
1129 Rules::is( 'source', $this->id ),
1130 Rules::is( 'themes', $this->id . '_theme-two' ),
1131 ] ),
1132 'fields' => [
1133 [
1134 'label' => __( 'Right Panel Image', 'notificationx' ),
1135 'name' => 'exit_intent_image_url',
1136 'type' => 'media',
1137 'priority' => 5,
1138 'default' => [
1139 'url' => 'https://notificationx.com/wp-content/uploads/2026/05/exit-intend-theme-two-five-seven.jpg',
1140 ],
1141 'help' => __( 'Upload or select the image to display in the right panel.', 'notificationx' ),
1142 ],
1143 [
1144 'label' => __( 'Sale Badge Text', 'notificationx' ),
1145 'name' => 'exit_intent_sale_badge',
1146 'type' => 'text',
1147 'priority' => 10,
1148 'default' => __( 'Flash Sale', 'notificationx' ),
1149 ],
1150 [
1151 'label' => __( 'Sale Headline', 'notificationx' ),
1152 'name' => 'exit_intent_sale_headline',
1153 'type' => 'text',
1154 'priority' => 20,
1155 'default' => __( '50% OFF', 'notificationx' ),
1156 ],
1157 [
1158 'label' => __( 'Sale Description', 'notificationx' ),
1159 'name' => 'exit_intent_sale_desc',
1160 'type' => 'text',
1161 'priority' => 30,
1162 'default' => __( 'ON ENTIRE ORDER', 'notificationx' ),
1163 ],
1164 [
1165 'label' => __( 'Button Text', 'notificationx' ),
1166 'name' => 'exit_intent_button_text',
1167 'type' => 'text',
1168 'priority' => 60,
1169 'default' => __( 'Shop The Flash Sale Now', 'notificationx' ),
1170 ],
1171 [
1172 'label' => __( 'Button URL', 'notificationx' ),
1173 'name' => 'exit_intent_button_url',
1174 'type' => 'text',
1175 'priority' => 61,
1176 'default' => '',
1177 'help' => __( 'Where the CTA button sends visitors. Leave empty to just dismiss the popup.', 'notificationx' ),
1178 ],
1179 [
1180 'label' => __( 'Open in New Tab', 'notificationx' ),
1181 'name' => 'exit_intent_button_new_tab',
1182 'type' => 'toggle',
1183 'priority' => 62,
1184 'default' => true,
1185 ],
1186 [
1187 'label' => __( 'Dismiss Link Text', 'notificationx' ),
1188 'name' => 'exit_intent_dismiss_text',
1189 'type' => 'text',
1190 'priority' => 70,
1191 'default' => __( 'NO, THANKS!', 'notificationx' ),
1192 ],
1193 ],
1194 ];
1195
1196 // ── Theme Three content fields ────────────────────────────────────────────
1197 $fields['exit_intent_theme_three_section'] = [
1198 'label' => __( 'Exit Intent Content', 'notificationx' ),
1199 'name' => 'exit_intent_theme_three_section',
1200 'type' => 'section',
1201 'priority' => 5,
1202 'rules' => Rules::logicalRule( [
1203 Rules::is( 'source', $this->id ),
1204 Rules::is( 'themes', $this->id . '_theme-three' ),
1205 ] ),
1206 'fields' => [
1207 [
1208 'label' => __( 'Character Image', 'notificationx' ),
1209 'name' => 'exit_intent_image_url',
1210 'type' => 'media',
1211 'priority' => 5,
1212 'default' => [
1213 'url' => 'https://notificationx.com/wp-content/uploads/2026/05/exit-intend-theme-three.png',
1214 ],
1215 'help' => __( 'Upload or select a character/illustration image. It will appear above the popup card.', 'notificationx' ),
1216 ],
1217 [
1218 'label' => __( 'Headline', 'notificationx' ),
1219 'name' => 'exit_intent_t3_title',
1220 'type' => 'text',
1221 'priority' => 10,
1222 'default' => __( "Wait, don't go!", 'notificationx' ),
1223 ],
1224 [
1225 'label' => __( 'Subtitle', 'notificationx' ),
1226 'name' => 'exit_intent_t3_subtitle',
1227 'type' => 'text',
1228 'priority' => 20,
1229 'default' => __( 'Before you leave, we have a special offer just for you!', 'notificationx' ),
1230 ],
1231 [
1232 'label' => __( 'Offer Text', 'notificationx' ),
1233 'name' => 'exit_intent_t3_offer',
1234 'type' => 'text',
1235 'priority' => 30,
1236 'default' => __( 'Get 15% off your next purchase!', 'notificationx' ),
1237 ],
1238 [
1239 'label' => __( 'Coupon / Details Text', 'notificationx' ),
1240 'name' => 'exit_intent_t3_coupon_text',
1241 'type' => 'text',
1242 'priority' => 40,
1243 'default' => __( "Use code STAY15 at checkout. Don't miss out on this limited-time offer.", 'notificationx' ),
1244 ],
1245 [
1246 'label' => __( 'Button Text', 'notificationx' ),
1247 'name' => 'exit_intent_button_text',
1248 'type' => 'text',
1249 'priority' => 50,
1250 'default' => __( 'Claim Offer', 'notificationx' ),
1251 ],
1252 [
1253 'label' => __( 'Button URL', 'notificationx' ),
1254 'name' => 'exit_intent_button_url',
1255 'type' => 'text',
1256 'priority' => 51,
1257 'default' => '',
1258 'help' => __( 'Where the CTA button sends visitors. Leave empty to just dismiss the popup.', 'notificationx' ),
1259 ],
1260 [
1261 'label' => __( 'Open in New Tab', 'notificationx' ),
1262 'name' => 'exit_intent_button_new_tab',
1263 'type' => 'toggle',
1264 'priority' => 52,
1265 'default' => true,
1266 ],
1267 [
1268 'label' => __( 'Dismiss Link Text', 'notificationx' ),
1269 'name' => 'exit_intent_dismiss_text',
1270 'type' => 'text',
1271 'priority' => 60,
1272 'default' => __( 'No, thanks!', 'notificationx' ),
1273 ],
1274 ],
1275 ];
1276
1277 // ── Theme Four content fields ─────────────────────────────────────────────
1278 $fields['exit_intent_theme_four_section'] = [
1279 'label' => __( 'Exit Intent Content', 'notificationx' ),
1280 'name' => 'exit_intent_theme_four_section',
1281 'type' => 'section',
1282 'priority' => 5,
1283 'rules' => Rules::logicalRule( [
1284 Rules::is( 'source', $this->id ),
1285 Rules::is( 'themes', $this->id . '_theme-four' ),
1286 ] ),
1287 'fields' => [
1288 [
1289 'label' => __( 'Video Thumbnail', 'notificationx' ),
1290 'name' => 'exit_intent_image_url',
1291 'type' => 'media',
1292 'priority' => 5,
1293 'default' => [
1294 'url' => 'https://notificationx.com/wp-content/uploads/2026/05/exit-intend-theme-four.jpg',
1295 ],
1296 'help' => __( 'Upload or select the video thumbnail/preview image.', 'notificationx' ),
1297 ],
1298 [
1299 'label' => __( 'Badge Text', 'notificationx' ),
1300 'name' => 'exit_intent_t4_badge',
1301 'type' => 'text',
1302 'priority' => 10,
1303 'default' => __( 'Before you go...', 'notificationx' ),
1304 ],
1305 [
1306 'label' => __( 'Headline', 'notificationx' ),
1307 'name' => 'exit_intent_t4_title',
1308 'type' => 'text',
1309 'priority' => 20,
1310 'default' => __( 'Watch this short demo video', 'notificationx' ),
1311 ],
1312 [
1313 'label' => __( 'Subtitle', 'notificationx' ),
1314 'name' => 'exit_intent_t4_subtitle',
1315 'type' => 'text',
1316 'priority' => 30,
1317 'default' => __( 'See how our product simplifies your workflow.', 'notificationx' ),
1318 ],
1319 [
1320 'label' => __( 'Video URL', 'notificationx' ),
1321 'name' => 'exit_intent_t4_video_url',
1322 'type' => 'text',
1323 'priority' => 40,
1324 'default' => '',
1325 'placeholder' => 'https://www.youtube.com/watch?v=...',
1326 'help' => __( 'Paste a YouTube, Vimeo, or other video platform URL.', 'notificationx' ),
1327 ],
1328 ],
1329 ];
1330
1331 // ── Theme Five content fields ────────────────────────────────────────────
1332 $fields['exit_intent_theme_five_section'] = [
1333 'label' => __( 'Exit Intent Content', 'notificationx' ),
1334 'name' => 'exit_intent_theme_five_section',
1335 'type' => 'section',
1336 'priority' => 5,
1337 'rules' => Rules::logicalRule( [
1338 Rules::is( 'source', $this->id ),
1339 Rules::is( 'themes', $this->id . '_theme-five' ),
1340 ] ),
1341 'fields' => [
1342 [
1343 'label' => __( 'Right Panel Image', 'notificationx' ),
1344 'name' => 'exit_intent_image_url',
1345 'type' => 'media',
1346 'priority' => 5,
1347 'default' => [
1348 'url' => 'https://notificationx.com/wp-content/uploads/2026/05/exit-intend-theme-two-five-seven.jpg',
1349 ],
1350 'help' => __( 'Upload or select the image to display in the right panel.', 'notificationx' ),
1351 ],
1352 [
1353 'label' => __( 'Title', 'notificationx' ),
1354 'name' => 'exit_intent_t5_title',
1355 'type' => 'text',
1356 'priority' => 10,
1357 'default' => __( 'Flash Sale', 'notificationx' ),
1358 ],
1359 [
1360 'label' => __( 'Headline', 'notificationx' ),
1361 'name' => 'exit_intent_t5_headline',
1362 'type' => 'text',
1363 'priority' => 20,
1364 'default' => __( '50% OFF', 'notificationx' ),
1365 ],
1366 [
1367 'label' => __( 'Description', 'notificationx' ),
1368 'name' => 'exit_intent_t5_desc',
1369 'type' => 'text',
1370 'priority' => 30,
1371 'default' => __( 'ON ENTIRE ORDER', 'notificationx' ),
1372 ],
1373 [
1374 'label' => __( 'Button Text', 'notificationx' ),
1375 'name' => 'exit_intent_button_text',
1376 'type' => 'text',
1377 'priority' => 60,
1378 'default' => __( 'Shop The Flash Sale Now', 'notificationx' ),
1379 ],
1380 [
1381 'label' => __( 'Button URL', 'notificationx' ),
1382 'name' => 'exit_intent_button_url',
1383 'type' => 'text',
1384 'priority' => 61,
1385 'default' => '',
1386 'help' => __( 'Where the CTA button sends visitors. Leave empty to just dismiss the popup.', 'notificationx' ),
1387 ],
1388 [
1389 'label' => __( 'Open in New Tab', 'notificationx' ),
1390 'name' => 'exit_intent_button_new_tab',
1391 'type' => 'toggle',
1392 'priority' => 62,
1393 'default' => true,
1394 ],
1395 [
1396 'label' => __( 'Dismiss Link Text', 'notificationx' ),
1397 'name' => 'exit_intent_dismiss_text',
1398 'type' => 'text',
1399 'priority' => 70,
1400 'default' => __( 'NO, THANKS!', 'notificationx' ),
1401 ],
1402 ],
1403 ];
1404
1405 // ── Theme Five Timer Settings ────────────────────────────────────────────
1406 $fields['exit_intent_theme_five_timer_section'] = [
1407 'label' => __( 'Timer Settings', 'notificationx' ),
1408 'name' => 'exit_intent_theme_five_timer_section',
1409 'type' => 'section',
1410 'priority' => 6,
1411 'rules' => Rules::logicalRule( [
1412 Rules::is( 'source', $this->id ),
1413 Rules::is( 'themes', $this->id . '_theme-five' ),
1414 ] ),
1415 'fields' => [
1416 [
1417 'label' => __( 'Show Countdown Timer', 'notificationx' ),
1418 'name' => 'exit_intent_t5_show_timer',
1419 'type' => 'toggle',
1420 'priority' => 5,
1421 'default' => true,
1422 ],
1423 [
1424 'label' => __( 'Countdown Label', 'notificationx' ),
1425 'name' => 'exit_intent_t5_countdown_label',
1426 'type' => 'text',
1427 'priority' => 10,
1428 'default' => __( 'LIMITED-TIME OFFER! SALE ENDS IN', 'notificationx' ),
1429 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ),
1430 ],
1431 [
1432 'label' => __( 'Sale End Date & Time', 'notificationx' ),
1433 'name' => 'exit_intent_countdown_end',
1434 'type' => 'date',
1435 'priority' => 20,
1436 'default' => '',
1437 'help' => __( 'Pick the date and time when the sale ends. Leave empty to display static demo numbers.', 'notificationx' ),
1438 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ),
1439 ],
1440 [
1441 'label' => __( 'Days Label', 'notificationx' ),
1442 'name' => 'exit_intent_t5_days_label',
1443 'type' => 'text',
1444 'priority' => 30,
1445 'default' => __( 'DAYS', 'notificationx' ),
1446 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ),
1447 ],
1448 [
1449 'label' => __( 'Hours Label', 'notificationx' ),
1450 'name' => 'exit_intent_t5_hours_label',
1451 'type' => 'text',
1452 'priority' => 40,
1453 'default' => __( 'HRS', 'notificationx' ),
1454 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ),
1455 ],
1456 [
1457 'label' => __( 'Minutes Label', 'notificationx' ),
1458 'name' => 'exit_intent_t5_minutes_label',
1459 'type' => 'text',
1460 'priority' => 50,
1461 'default' => __( 'MIN', 'notificationx' ),
1462 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ),
1463 ],
1464 [
1465 'label' => __( 'Seconds Label', 'notificationx' ),
1466 'name' => 'exit_intent_t5_seconds_label',
1467 'type' => 'text',
1468 'priority' => 60,
1469 'default' => __( 'SEC', 'notificationx' ),
1470 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ),
1471 ],
1472 [
1473 'label' => __( 'Timer Box Background', 'notificationx' ),
1474 'name' => 'exit_intent_t5_timer_bg',
1475 'type' => 'colorpicker',
1476 'priority' => 70,
1477 'default' => '#fff0f5',
1478 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ),
1479 ],
1480 [
1481 'label' => __( 'Timer Number Color', 'notificationx' ),
1482 'name' => 'exit_intent_t5_timer_color',
1483 'type' => 'colorpicker',
1484 'priority' => 80,
1485 'default' => '#e91e63',
1486 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ),
1487 ],
1488 ],
1489 ];
1490
1491 // ── Theme Seven content fields ───────────────────────────────────────────
1492 $fields['exit_intent_theme_seven_section'] = [
1493 'label' => __( 'Exit Intent Content', 'notificationx' ),
1494 'name' => 'exit_intent_theme_seven_section',
1495 'type' => 'section',
1496 'priority' => 5,
1497 'rules' => Rules::logicalRule( [
1498 Rules::is( 'source', $this->id ),
1499 Rules::is( 'themes', $this->id . '_theme-seven' ),
1500 ] ),
1501 'fields' => [
1502 [
1503 'label' => __( 'Left Panel Image', 'notificationx' ),
1504 'name' => 'exit_intent_image_url',
1505 'type' => 'media',
1506 'priority' => 5,
1507 'default' => [
1508 'url' => 'https://notificationx.com/wp-content/uploads/2026/05/exit-intend-theme-two-five-seven.jpg',
1509 ],
1510 'help' => __( 'Upload or select the image to display in the left panel.', 'notificationx' ),
1511 ],
1512 [
1513 'label' => __( 'Headline', 'notificationx' ),
1514 'name' => 'exit_intent_t7_headline',
1515 'type' => 'text',
1516 'priority' => 10,
1517 'default' => __( 'Home Is Where Your Story Begins', 'notificationx' ),
1518 ],
1519 [
1520 'label' => __( 'Discount Banner Text', 'notificationx' ),
1521 'name' => 'exit_intent_t7_discount_text',
1522 'type' => 'text',
1523 'priority' => 20,
1524 'default' => __( 'Get 15% Off Your First Order!', 'notificationx' ),
1525 ],
1526 [
1527 'label' => __( 'Description', 'notificationx' ),
1528 'name' => 'exit_intent_t7_description',
1529 'type' => 'text',
1530 'priority' => 30,
1531 'default' => __( 'Discover timeless pieces that turn any space into a sanctuary.', 'notificationx' ),
1532 ],
1533 [
1534 'label' => __( 'Email Placeholder', 'notificationx' ),
1535 'name' => 'exit_intent_t7_email_placeholder',
1536 'type' => 'text',
1537 'priority' => 40,
1538 'default' => __( 'Enter your email', 'notificationx' ),
1539 ],
1540 [
1541 'label' => __( 'Button Text', 'notificationx' ),
1542 'name' => 'exit_intent_button_text',
1543 'type' => 'text',
1544 'priority' => 50,
1545 'default' => __( 'SEND COUPON', 'notificationx' ),
1546 ],
1547 ],
1548 ];
1549
1550 // ── Theme Six content fields ─────────────────────────────────────────────
1551 $fields['exit_intent_theme_six_section'] = [
1552 'label' => __( 'Exit Intent Content', 'notificationx' ),
1553 'name' => 'exit_intent_theme_six_section',
1554 'type' => 'section',
1555 'priority' => 5,
1556 'rules' => Rules::logicalRule( [
1557 Rules::is( 'source', $this->id ),
1558 Rules::is( 'themes', $this->id . '_theme-six' ),
1559 ] ),
1560 'fields' => [
1561 [
1562 'label' => __( 'Product Image', 'notificationx' ),
1563 'name' => 'exit_intent_image_url',
1564 'type' => 'media',
1565 'priority' => 5,
1566 'default' => [
1567 'url' => 'https://notificationx.com/wp-content/uploads/2026/05/exit-intend-theme-six.png',
1568 ],
1569 'help' => __( 'Upload or select the product image to display at the top of the popup.', 'notificationx' ),
1570 ],
1571 [
1572 'label' => __( 'Headline', 'notificationx' ),
1573 'name' => 'exit_intent_t6_title',
1574 'type' => 'text',
1575 'priority' => 10,
1576 'default' => __( 'Limited Edition Bass Boost Headphones', 'notificationx' ),
1577 ],
1578 [
1579 'label' => __( 'Button Text', 'notificationx' ),
1580 'name' => 'exit_intent_button_text',
1581 'type' => 'text',
1582 'priority' => 60,
1583 'default' => __( 'Grab Now', 'notificationx' ),
1584 ],
1585 [
1586 'label' => __( 'Button URL', 'notificationx' ),
1587 'name' => 'exit_intent_button_url',
1588 'type' => 'text',
1589 'priority' => 61,
1590 'default' => '',
1591 'help' => __( 'Where the CTA button sends visitors. Leave empty to just dismiss the popup.', 'notificationx' ),
1592 ],
1593 [
1594 'label' => __( 'Open in New Tab', 'notificationx' ),
1595 'name' => 'exit_intent_button_new_tab',
1596 'type' => 'toggle',
1597 'priority' => 62,
1598 'default' => true,
1599 ],
1600 ],
1601 ];
1602
1603 // ── Theme Six Timer Settings ─────────────────────────────────────────────
1604 $fields['exit_intent_theme_six_timer_section'] = [
1605 'label' => __( 'Timer Settings', 'notificationx' ),
1606 'name' => 'exit_intent_theme_six_timer_section',
1607 'type' => 'section',
1608 'priority' => 6,
1609 'rules' => Rules::logicalRule( [
1610 Rules::is( 'source', $this->id ),
1611 Rules::is( 'themes', $this->id . '_theme-six' ),
1612 ] ),
1613 'fields' => [
1614 [
1615 'label' => __( 'Show Countdown Timer', 'notificationx' ),
1616 'name' => 'exit_intent_t6_show_timer',
1617 'type' => 'toggle',
1618 'priority' => 5,
1619 'default' => true,
1620 ],
1621 [
1622 'label' => __( 'Countdown Label', 'notificationx' ),
1623 'name' => 'exit_intent_t6_countdown_label',
1624 'type' => 'text',
1625 'priority' => 10,
1626 'default' => __( 'Offer Ends In', 'notificationx' ),
1627 'rules' => Rules::is( 'exit_intent_t6_show_timer', true ),
1628 ],
1629 [
1630 'label' => __( 'Sale End Date & Time', 'notificationx' ),
1631 'name' => 'exit_intent_countdown_end',
1632 'type' => 'date',
1633 'priority' => 20,
1634 'default' => '',
1635 'help' => __( 'Pick the date and time when the sale ends. Leave empty to display static demo numbers.', 'notificationx' ),
1636 'rules' => Rules::is( 'exit_intent_t6_show_timer', true ),
1637 ],
1638 [
1639 'label' => __( 'Days Label', 'notificationx' ),
1640 'name' => 'exit_intent_t6_days_label',
1641 'type' => 'text',
1642 'priority' => 30,
1643 'default' => __( 'DAYS', 'notificationx' ),
1644 'rules' => Rules::is( 'exit_intent_t6_show_timer', true ),
1645 ],
1646 [
1647 'label' => __( 'Hours Label', 'notificationx' ),
1648 'name' => 'exit_intent_t6_hours_label',
1649 'type' => 'text',
1650 'priority' => 40,
1651 'default' => __( 'HOURS', 'notificationx' ),
1652 'rules' => Rules::is( 'exit_intent_t6_show_timer', true ),
1653 ],
1654 [
1655 'label' => __( 'Minutes Label', 'notificationx' ),
1656 'name' => 'exit_intent_t6_minutes_label',
1657 'type' => 'text',
1658 'priority' => 50,
1659 'default' => __( 'MIN', 'notificationx' ),
1660 'rules' => Rules::is( 'exit_intent_t6_show_timer', true ),
1661 ],
1662 [
1663 'label' => __( 'Seconds Label', 'notificationx' ),
1664 'name' => 'exit_intent_t6_seconds_label',
1665 'type' => 'text',
1666 'priority' => 60,
1667 'default' => __( 'SEC', 'notificationx' ),
1668 'rules' => Rules::is( 'exit_intent_t6_show_timer', true ),
1669 ],
1670 ],
1671 ];
1672
1673 // ── Theme One content fields ─────────────────────────────────────────────
1674 $fields['exit_intent_content_section'] = [
1675 'label' => __( 'Exit Intent Content', 'notificationx' ),
1676 'name' => 'exit_intent_content_section',
1677 'type' => 'section',
1678 'priority' => 5,
1679 'rules' => Rules::logicalRule( [
1680 Rules::is( 'source', $this->id ),
1681 Rules::is( 'themes', $this->id . '_theme-two', true ),
1682 Rules::is( 'themes', $this->id . '_theme-three', true ),
1683 Rules::is( 'themes', $this->id . '_theme-four', true ),
1684 Rules::is( 'themes', $this->id . '_theme-five', true ),
1685 Rules::is( 'themes', $this->id . '_theme-six', true ),
1686 Rules::is( 'themes', $this->id . '_theme-seven', true ),
1687 ] ),
1688 'fields' => [
1689 // ── Main copy ────────────────────────────────────────────
1690 [
1691 'label' => __( 'Title', 'notificationx' ),
1692 'name' => 'exit_intent_title',
1693 'type' => 'text',
1694 'priority' => 10,
1695 'default' => __( 'Wait! Before You Go...', 'notificationx' ),
1696 ],
1697 [
1698 'label' => __( 'Subtitle', 'notificationx' ),
1699 'name' => 'exit_intent_subtitle',
1700 'type' => 'text',
1701 'priority' => 20,
1702 'default' => __( "We'd love to understand what's holding you back", 'notificationx' ),
1703 ],
1704 // ── Form fields ──────────────────────────────────────────
1705 [
1706 'label' => __( 'Show Name Field', 'notificationx' ),
1707 'name' => 'exit_intent_show_name',
1708 'type' => 'toggle',
1709 'default' => true,
1710 'priority' => 70,
1711 'is_pro' => true,
1712 ],
1713 [
1714 'label' => __( 'Name Placeholder', 'notificationx' ),
1715 'name' => 'exit_intent_name_label',
1716 'type' => 'text',
1717 'default' => __( 'Name *', 'notificationx' ),
1718 'priority' => 75,
1719 'is_pro' => true,
1720 'rules' => Rules::is( 'exit_intent_show_name', true ),
1721 ],
1722 [
1723 'label' => __( 'Show Email Field', 'notificationx' ),
1724 'name' => 'exit_intent_show_email',
1725 'type' => 'toggle',
1726 'default' => true,
1727 'priority' => 80,
1728 'is_pro' => true,
1729 ],
1730 [
1731 'label' => __( 'Email Placeholder', 'notificationx' ),
1732 'name' => 'exit_intent_email_label',
1733 'type' => 'text',
1734 'default' => __( 'Enter Your Email *', 'notificationx' ),
1735 'priority' => 85,
1736 'is_pro' => true,
1737 'rules' => Rules::is( 'exit_intent_show_email', true ),
1738 ],
1739 [
1740 'label' => __( 'Show Message Field', 'notificationx' ),
1741 'name' => 'exit_intent_show_message',
1742 'type' => 'toggle',
1743 'default' => true,
1744 'priority' => 87,
1745 ],
1746 [
1747 'label' => __( 'Message Placeholder', 'notificationx' ),
1748 'name' => 'exit_intent_message_placeholder',
1749 'type' => 'text',
1750 'default' => __( 'Your message...', 'notificationx' ),
1751 'priority' => 88,
1752 'rules' => Rules::is( 'exit_intent_show_message', true ),
1753 ],
1754
1755 // ── Button ───────────────────────────────────────────────
1756 [
1757 'label' => __( 'Button Text', 'notificationx' ),
1758 'name' => 'exit_intent_button_text',
1759 'type' => 'text',
1760 'default' => __( 'SUBMIT', 'notificationx' ),
1761 'priority' => 90,
1762 ],
1763 ],
1764 ];
1765
1766 return $fields;
1767 }
1768
1769 public function design_fields( $fields ) {
1770 // Hide the inner sub-sections of the global advance_design_section for this source,
1771 // but keep advance_design_section itself visible so its `advance_edit` toggle renders.
1772 foreach ( [ 'design', 'typography', 'image-appearance', 'link_button_design' ] as $key ) {
1773 if ( isset( $fields['advance_design_section']['fields'][ $key ] ) ) {
1774 $fields['advance_design_section']['fields'][ $key ] = Rules::is(
1775 'source', $this->id, true, $fields['advance_design_section']['fields'][ $key ]
1776 );
1777 }
1778 }
1779
1780 // Inline every theme's design fields directly into advance_design_section so they appear
1781 // flat under the existing "Advanced Design" heading — no per-theme sub-headers.
1782 // Priorities are auto-assigned starting at 20 so all theme controls sort BEFORE the
1783 // global Custom CSS section (priority 150).
1784 $design = &$fields['advance_design_section']['fields'];
1785 $priority = 20;
1786 $merge = function( $theme_slug, $list ) use ( &$design, &$priority ) {
1787 $rule = $this->theme_design_rules( $theme_slug );
1788 foreach ( $list as $field ) {
1789 if ( ! empty( $field['rules'] ) ) {
1790 $field['rules'] = Rules::logicalRule( [ $rule, $field['rules'] ] );
1791 } else {
1792 $field['rules'] = $rule;
1793 }
1794 if ( ! isset( $field['priority'] ) ) {
1795 $field['priority'] = $priority;
1796 }
1797 $priority++;
1798 $design[ $field['name'] ] = $field;
1799 }
1800 };
1801
1802 $merge( 'theme-one', $this->theme_one_design_fields() );
1803 $merge( 'theme-two', $this->theme_two_design_fields() );
1804 $merge( 'theme-three', $this->theme_three_design_fields() );
1805 $merge( 'theme-four', $this->theme_four_design_fields() );
1806 $merge( 'theme-five', $this->theme_five_design_fields() );
1807 $merge( 'theme-six', $this->theme_six_design_fields() );
1808 $merge( 'theme-seven', $this->theme_seven_design_fields() );
1809
1810 return $fields;
1811 }
1812
1813 /** Build a rule scoped to source + advance_edit + a specific theme. */
1814 private function theme_design_rules( $theme_slug ) {
1815 return Rules::logicalRule( [
1816 Rules::is( 'source', $this->id ),
1817 Rules::is( 'advance_edit', true ),
1818 Rules::is( 'themes', $this->id . '_' . $theme_slug ),
1819 ] );
1820 }
1821
1822 private function font_weight_options() {
1823 return GlobalFields::get_instance()->normalize_fields( [
1824 '400' => __( 'Normal (400)', 'notificationx' ),
1825 '500' => __( 'Medium (500)', 'notificationx' ),
1826 '600' => __( 'Semi Bold (600)', 'notificationx' ),
1827 '700' => __( 'Bold (700)', 'notificationx' ),
1828 '800' => __( 'Extra Bold (800)', 'notificationx' ),
1829 ] );
1830 }
1831
1832 /** ───────────────────────── Theme One — Feedback Form ───────────────────────── */
1833 private function theme_one_design_fields() {
1834 return [
1835 // Container
1836 [ 'label' => __( 'Popup Max Width', 'notificationx' ), 'name' => 'exit_intent_max_width', 'type' => 'number', 'default' => 540, 'description' => 'px' ],
1837 [ 'label' => __( 'Border Radius', 'notificationx' ), 'name' => 'exit_intent_border_radius', 'type' => 'number', 'default' => 12, 'description' => 'px' ],
1838 [ 'label' => __( 'Background Color', 'notificationx' ), 'name' => 'exit_intent_bg_color', 'type' => 'colorpicker', 'default' => '#EDE7FF' ],
1839 [ 'label' => __( 'Overlay Background Color', 'notificationx' ),'name' => 'exit_intent_overlay_color', 'type' => 'colorpicker', 'default' => 'rgba(0,0,0,0.5)',
1840 'help' => __( 'Color of the backdrop behind the popup.', 'notificationx' ) ],
1841 [ 'label' => __( 'Show Background Pattern', 'notificationx' ), 'name' => 'exit_intent_show_pattern', 'type' => 'toggle', 'default' => true ],
1842 [ 'label' => __( 'Pattern Color', 'notificationx' ), 'name' => 'exit_intent_pattern_color', 'type' => 'colorpicker', 'default' => '#D4C3FF',
1843 'rules' => Rules::is( 'exit_intent_show_pattern', true ) ],
1844
1845 // Title
1846 [ 'label' => __( 'Title Color', 'notificationx' ), 'name' => 'exit_intent_title_color', 'type' => 'colorpicker', 'default' => '#1a1a2e' ],
1847 [ 'label' => __( 'Title Font Size', 'notificationx' ), 'name' => 'exit_intent_title_font_size', 'type' => 'number', 'default' => 26, 'description' => 'px' ],
1848 [ 'label' => __( 'Title Font Weight', 'notificationx' ), 'name' => 'exit_intent_title_font_weight', 'type' => 'select', 'default' => '700',
1849 'options' => $this->font_weight_options() ],
1850
1851 // Subtitle
1852 [ 'label' => __( 'Subtitle Color', 'notificationx' ), 'name' => 'exit_intent_subtitle_color', 'type' => 'colorpicker', 'default' => '#4a4a6a' ],
1853 [ 'label' => __( 'Subtitle Font Size', 'notificationx' ), 'name' => 'exit_intent_subtitle_font_size', 'type' => 'number', 'default' => 14, 'description' => 'px' ],
1854
1855 // Inputs
1856 [ 'label' => __( 'Input Background Color', 'notificationx' ), 'name' => 'exit_intent_input_bg', 'type' => 'colorpicker', 'default' => '#ffffff' ],
1857 [ 'label' => __( 'Input Border Color', 'notificationx' ), 'name' => 'exit_intent_input_border_color', 'type' => 'colorpicker', 'default' => '#dddddd' ],
1858 [ 'label' => __( 'Input Border Radius', 'notificationx' ), 'name' => 'exit_intent_input_border_radius', 'type' => 'number', 'default' => 6, 'description' => 'px' ],
1859 [ 'label' => __( 'Input Text Color', 'notificationx' ), 'name' => 'exit_intent_input_text_color', 'type' => 'colorpicker', 'default' => '#333333' ],
1860
1861 // Button
1862 [ 'label' => __( 'Button Background Color', 'notificationx' ), 'name' => 'exit_intent_btn_bg', 'type' => 'colorpicker', 'default' => '#6B21A8' ],
1863 [ 'label' => __( 'Button Text Color', 'notificationx' ), 'name' => 'exit_intent_btn_color', 'type' => 'colorpicker', 'default' => '#ffffff' ],
1864 [ 'label' => __( 'Button Border Radius', 'notificationx' ), 'name' => 'exit_intent_btn_border_radius', 'type' => 'number', 'default' => 6, 'description' => 'px' ],
1865 [ 'label' => __( 'Button Font Size', 'notificationx' ), 'name' => 'exit_intent_btn_font_size', 'type' => 'number', 'default' => 14, 'description' => 'px' ],
1866 [ 'label' => __( 'Button Font Weight', 'notificationx' ), 'name' => 'exit_intent_btn_font_weight', 'type' => 'select', 'default' => '700',
1867 'options' => $this->font_weight_options() ],
1868
1869 // Close button
1870 [ 'label' => __( 'Close Button Color', 'notificationx' ), 'name' => 'exit_intent_close_color', 'type' => 'colorpicker', 'default' => '#666666' ],
1871 [ 'label' => __( 'Close Button Size', 'notificationx' ), 'name' => 'exit_intent_close_size', 'type' => 'number', 'default' => 20, 'description' => 'px' ],
1872 ];
1873 }
1874
1875 /** ───────────────────────── Theme Two — Flash Sale w/ Countdown ───────────────────────── */
1876 private function theme_two_design_fields() {
1877 return [
1878 // Container / overlay / close
1879 [ 'label' => __( 'Popup Max Width', 'notificationx' ), 'name' => 'exit_intent_t2_max_width', 'type' => 'number', 'default' => 760, 'description' => 'px' ],
1880 [ 'label' => __( 'Border Radius', 'notificationx' ), 'name' => 'exit_intent_t2_border_radius', 'type' => 'number', 'default' => 12, 'description' => 'px' ],
1881 [ 'label' => __( 'Left Panel Background', 'notificationx' ), 'name' => 'exit_intent_t2_bg_color', 'type' => 'colorpicker', 'default' => '#ffffff' ],
1882 [ 'label' => __( 'Overlay Background Color', 'notificationx' ), 'name' => 'exit_intent_overlay_color', 'type' => 'colorpicker', 'default' => 'rgba(0,0,0,0.5)' ],
1883 [ 'label' => __( 'Close Button Color', 'notificationx' ), 'name' => 'exit_intent_close_color', 'type' => 'colorpicker', 'default' => '#666666' ],
1884 [ 'label' => __( 'Close Button Size', 'notificationx' ), 'name' => 'exit_intent_close_size', 'type' => 'number', 'default' => 20, 'description' => 'px' ],
1885
1886 // Sale badge
1887 [ 'label' => __( 'Badge Background', 'notificationx' ), 'name' => 'exit_intent_t2_badge_bg', 'type' => 'colorpicker', 'default' => '#ffe4ec' ],
1888 [ 'label' => __( 'Badge Text Color', 'notificationx' ),'name' => 'exit_intent_t2_badge_color', 'type' => 'colorpicker', 'default' => '#e91e63' ],
1889 [ 'label' => __( 'Badge Font Size', 'notificationx' ), 'name' => 'exit_intent_t2_badge_font_size', 'type' => 'number', 'default' => 12, 'description' => 'px' ],
1890
1891 // Headline
1892 [ 'label' => __( 'Headline Color', 'notificationx' ), 'name' => 'exit_intent_t2_headline_color', 'type' => 'colorpicker', 'default' => '#1a1a2e' ],
1893 [ 'label' => __( 'Headline Font Size', 'notificationx' ), 'name' => 'exit_intent_t2_headline_font_size', 'type' => 'number', 'default' => 56, 'description' => 'px' ],
1894 [ 'label' => __( 'Headline Font Weight', 'notificationx' ), 'name' => 'exit_intent_t2_headline_font_weight', 'type' => 'select', 'default' => '800',
1895 'options' => $this->font_weight_options() ],
1896
1897 // Description
1898 [ 'label' => __( 'Description Color', 'notificationx' ), 'name' => 'exit_intent_t2_desc_color', 'type' => 'colorpicker', 'default' => '#4a4a6a' ],
1899 [ 'label' => __( 'Description Font Size', 'notificationx' ), 'name' => 'exit_intent_t2_desc_font_size', 'type' => 'number', 'default' => 14, 'description' => 'px' ],
1900
1901 // CTA button
1902 [ 'label' => __( 'Button Background', 'notificationx' ), 'name' => 'exit_intent_t2_btn_bg', 'type' => 'colorpicker', 'default' => '#e91e63' ],
1903 [ 'label' => __( 'Button Text Color', 'notificationx' ), 'name' => 'exit_intent_t2_btn_color', 'type' => 'colorpicker', 'default' => '#ffffff' ],
1904 [ 'label' => __( 'Button Border Radius', 'notificationx' ), 'name' => 'exit_intent_t2_btn_border_radius', 'type' => 'number', 'default' => 6, 'description' => 'px' ],
1905 [ 'label' => __( 'Button Font Size', 'notificationx' ), 'name' => 'exit_intent_t2_btn_font_size', 'type' => 'number', 'default' => 14, 'description' => 'px' ],
1906 [ 'label' => __( 'Button Font Weight', 'notificationx' ), 'name' => 'exit_intent_t2_btn_font_weight', 'type' => 'select', 'default' => '700',
1907 'options' => $this->font_weight_options() ],
1908
1909 // Dismiss link
1910 [ 'label' => __( 'Dismiss Text Color', 'notificationx' ), 'name' => 'exit_intent_t2_dismiss_color', 'type' => 'colorpicker', 'default' => '#9a9aa8' ],
1911 [ 'label' => __( 'Dismiss Font Size', 'notificationx' ), 'name' => 'exit_intent_t2_dismiss_font_size', 'type' => 'number', 'default' => 12, 'description' => 'px' ],
1912 ];
1913 }
1914
1915 /** ───────────────────────── Theme Three — Coupon Offer ───────────────────────── */
1916 private function theme_three_design_fields() {
1917 return [
1918 // Container / overlay / close
1919 [ 'label' => __( 'Popup Max Width', 'notificationx' ), 'name' => 'exit_intent_t3_max_width', 'type' => 'number', 'default' => 460, 'description' => 'px' ],
1920 [ 'label' => __( 'Border Radius', 'notificationx' ), 'name' => 'exit_intent_t3_border_radius', 'type' => 'number', 'default' => 16, 'description' => 'px' ],
1921 [ 'label' => __( 'Background Color', 'notificationx' ), 'name' => 'exit_intent_t3_bg_color', 'type' => 'colorpicker', 'default' => '#ffffff' ],
1922 [ 'label' => __( 'Overlay Background Color', 'notificationx' ), 'name' => 'exit_intent_overlay_color', 'type' => 'colorpicker', 'default' => 'rgba(0,0,0,0.5)' ],
1923 [ 'label' => __( 'Close Button Color', 'notificationx' ), 'name' => 'exit_intent_close_color', 'type' => 'colorpicker', 'default' => '#666666' ],
1924 [ 'label' => __( 'Close Button Size', 'notificationx' ), 'name' => 'exit_intent_close_size', 'type' => 'number', 'default' => 20, 'description' => 'px' ],
1925
1926 // Title
1927 [ 'label' => __( 'Title Color', 'notificationx' ), 'name' => 'exit_intent_t3_title_color', 'type' => 'colorpicker', 'default' => '#1a1a2e' ],
1928 [ 'label' => __( 'Title Font Size', 'notificationx' ), 'name' => 'exit_intent_t3_title_font_size', 'type' => 'number', 'default' => 26, 'description' => 'px' ],
1929 [ 'label' => __( 'Title Font Weight', 'notificationx' ), 'name' => 'exit_intent_t3_title_font_weight', 'type' => 'select', 'default' => '700',
1930 'options' => $this->font_weight_options() ],
1931
1932 // Subtitle
1933 [ 'label' => __( 'Subtitle Color', 'notificationx' ), 'name' => 'exit_intent_t3_subtitle_color', 'type' => 'colorpicker', 'default' => '#4a4a6a' ],
1934 [ 'label' => __( 'Subtitle Font Size', 'notificationx' ), 'name' => 'exit_intent_t3_subtitle_font_size', 'type' => 'number', 'default' => 14, 'description' => 'px' ],
1935
1936 // Offer line
1937 [ 'label' => __( 'Offer Color', 'notificationx' ), 'name' => 'exit_intent_t3_offer_color', 'type' => 'colorpicker', 'default' => '#e91e63' ],
1938 [ 'label' => __( 'Offer Font Size', 'notificationx' ), 'name' => 'exit_intent_t3_offer_font_size', 'type' => 'number', 'default' => 18, 'description' => 'px' ],
1939 [ 'label' => __( 'Offer Font Weight', 'notificationx' ), 'name' => 'exit_intent_t3_offer_font_weight', 'type' => 'select', 'default' => '700',
1940 'options' => $this->font_weight_options() ],
1941
1942 // Coupon block
1943 [ 'label' => __( 'Coupon Block Background', 'notificationx' ), 'name' => 'exit_intent_t3_coupon_bg', 'type' => 'colorpicker', 'default' => '#fff7fb' ],
1944 [ 'label' => __( 'Coupon Text Color', 'notificationx' ), 'name' => 'exit_intent_t3_coupon_color', 'type' => 'colorpicker', 'default' => '#1a1a2e' ],
1945 [ 'label' => __( 'Coupon Font Size', 'notificationx' ), 'name' => 'exit_intent_t3_coupon_font_size', 'type' => 'number', 'default' => 14, 'description' => 'px' ],
1946 [ 'label' => __( 'Coupon Block Border Radius', 'notificationx' ), 'name' => 'exit_intent_t3_coupon_border_radius', 'type' => 'number', 'default' => 8, 'description' => 'px' ],
1947
1948 // CTA button
1949 [ 'label' => __( 'Button Background', 'notificationx' ), 'name' => 'exit_intent_t3_btn_bg', 'type' => 'colorpicker', 'default' => '#e91e63' ],
1950 [ 'label' => __( 'Button Text Color', 'notificationx' ), 'name' => 'exit_intent_t3_btn_color', 'type' => 'colorpicker', 'default' => '#ffffff' ],
1951 [ 'label' => __( 'Button Border Radius', 'notificationx' ), 'name' => 'exit_intent_t3_btn_border_radius', 'type' => 'number', 'default' => 6, 'description' => 'px' ],
1952 [ 'label' => __( 'Button Font Size', 'notificationx' ), 'name' => 'exit_intent_t3_btn_font_size', 'type' => 'number', 'default' => 14, 'description' => 'px' ],
1953 [ 'label' => __( 'Button Font Weight', 'notificationx' ), 'name' => 'exit_intent_t3_btn_font_weight', 'type' => 'select', 'default' => '700',
1954 'options' => $this->font_weight_options() ],
1955
1956 // Dismiss link
1957 [ 'label' => __( 'Dismiss Text Color', 'notificationx' ), 'name' => 'exit_intent_t3_dismiss_color', 'type' => 'colorpicker', 'default' => '#9a9aa8' ],
1958 [ 'label' => __( 'Dismiss Font Size', 'notificationx' ), 'name' => 'exit_intent_t3_dismiss_font_size', 'type' => 'number', 'default' => 12, 'description' => 'px' ],
1959 ];
1960 }
1961
1962 /** ───────────────────────── Theme Four — Video Popup ───────────────────────── */
1963 private function theme_four_design_fields() {
1964 return [
1965 // Container / overlay / close
1966 [ 'label' => __( 'Popup Max Width', 'notificationx' ), 'name' => 'exit_intent_t4_max_width', 'type' => 'number', 'default' => 520, 'description' => 'px' ],
1967 [ 'label' => __( 'Border Radius', 'notificationx' ), 'name' => 'exit_intent_t4_border_radius', 'type' => 'number', 'default' => 16, 'description' => 'px' ],
1968 [ 'label' => __( 'Background Color', 'notificationx' ), 'name' => 'exit_intent_t4_bg_color', 'type' => 'colorpicker', 'default' => '#f4ecff' ],
1969 [ 'label' => __( 'Overlay Background Color', 'notificationx' ), 'name' => 'exit_intent_overlay_color', 'type' => 'colorpicker', 'default' => 'rgba(0,0,0,0.5)' ],
1970 [ 'label' => __( 'Close Button Color', 'notificationx' ), 'name' => 'exit_intent_close_color', 'type' => 'colorpicker', 'default' => '#666666' ],
1971 [ 'label' => __( 'Close Button Size', 'notificationx' ), 'name' => 'exit_intent_close_size', 'type' => 'number', 'default' => 20, 'description' => 'px' ],
1972
1973 // Badge
1974 [ 'label' => __( 'Badge Background', 'notificationx' ), 'name' => 'exit_intent_t4_badge_bg', 'type' => 'colorpicker', 'default' => '#ffffff' ],
1975 [ 'label' => __( 'Badge Text Color', 'notificationx' ),'name' => 'exit_intent_t4_badge_color', 'type' => 'colorpicker', 'default' => '#6B21A8' ],
1976 [ 'label' => __( 'Badge Font Size', 'notificationx' ), 'name' => 'exit_intent_t4_badge_font_size', 'type' => 'number', 'default' => 12, 'description' => 'px' ],
1977
1978 // Title
1979 [ 'label' => __( 'Title Color', 'notificationx' ), 'name' => 'exit_intent_t4_title_color', 'type' => 'colorpicker', 'default' => '#1a1a2e' ],
1980 [ 'label' => __( 'Title Font Size', 'notificationx' ), 'name' => 'exit_intent_t4_title_font_size', 'type' => 'number', 'default' => 24, 'description' => 'px' ],
1981 [ 'label' => __( 'Title Font Weight', 'notificationx' ), 'name' => 'exit_intent_t4_title_font_weight', 'type' => 'select', 'default' => '700',
1982 'options' => $this->font_weight_options() ],
1983
1984 // Subtitle
1985 [ 'label' => __( 'Subtitle Color', 'notificationx' ), 'name' => 'exit_intent_t4_subtitle_color', 'type' => 'colorpicker', 'default' => '#4a4a6a' ],
1986 [ 'label' => __( 'Subtitle Font Size', 'notificationx' ), 'name' => 'exit_intent_t4_subtitle_font_size', 'type' => 'number', 'default' => 14, 'description' => 'px' ],
1987
1988 // Video wrap + play icon
1989 [ 'label' => __( 'Video Wrapper Background', 'notificationx' ), 'name' => 'exit_intent_t4_video_bg', 'type' => 'colorpicker', 'default' => '#000000' ],
1990 [ 'label' => __( 'Video Wrapper Border Radius', 'notificationx' ), 'name' => 'exit_intent_t4_video_radius', 'type' => 'number', 'default' => 12, 'description' => 'px' ],
1991 [ 'label' => __( 'Play Icon Background', 'notificationx' ), 'name' => 'exit_intent_t4_play_bg', 'type' => 'colorpicker', 'default' => '#ffffff' ],
1992 [ 'label' => __( 'Play Icon Color', 'notificationx' ), 'name' => 'exit_intent_t4_play_color', 'type' => 'colorpicker', 'default' => '#1a1a2e' ],
1993 ];
1994 }
1995
1996 /** ───────────────────────── Theme Five — Live Flash Sale ───────────────────────── */
1997 private function theme_five_design_fields() {
1998 return [
1999 // Container / overlay / close
2000 [ 'label' => __( 'Popup Max Width', 'notificationx' ), 'name' => 'exit_intent_t5_max_width', 'type' => 'number', 'default' => 900, 'description' => 'px' ],
2001 [ 'label' => __( 'Border Radius', 'notificationx' ), 'name' => 'exit_intent_t5_border_radius', 'type' => 'number', 'default' => 12, 'description' => 'px' ],
2002 [ 'label' => __( 'Left Panel Background', 'notificationx' ), 'name' => 'exit_intent_t5_bg_color', 'type' => 'colorpicker', 'default' => '#ffffff' ],
2003 [ 'label' => __( 'Overlay Background Color', 'notificationx' ), 'name' => 'exit_intent_overlay_color', 'type' => 'colorpicker', 'default' => 'rgba(0,0,0,0.6)' ],
2004 [ 'label' => __( 'Close Button Color', 'notificationx' ), 'name' => 'exit_intent_close_color', 'type' => 'colorpicker', 'default' => '#666666' ],
2005 [ 'label' => __( 'Close Button Size', 'notificationx' ), 'name' => 'exit_intent_close_size', 'type' => 'number', 'default' => 20, 'description' => 'px' ],
2006
2007 // Title
2008 [ 'label' => __( 'Title Color', 'notificationx' ), 'name' => 'exit_intent_t5_title_color', 'type' => 'colorpicker', 'default' => '#1a1a2e' ],
2009 [ 'label' => __( 'Title Font Size', 'notificationx' ), 'name' => 'exit_intent_t5_title_font_size', 'type' => 'number', 'default' => 18, 'description' => 'px' ],
2010 [ 'label' => __( 'Title Font Weight', 'notificationx' ), 'name' => 'exit_intent_t5_title_font_weight', 'type' => 'select', 'default' => '700',
2011 'options' => $this->font_weight_options() ],
2012
2013 // Headline
2014 [ 'label' => __( 'Headline Color', 'notificationx' ), 'name' => 'exit_intent_t5_headline_color', 'type' => 'colorpicker', 'default' => '#1a1a2e' ],
2015 [ 'label' => __( 'Headline Font Size', 'notificationx' ), 'name' => 'exit_intent_t5_headline_font_size', 'type' => 'number', 'default' => 56, 'description' => 'px' ],
2016 [ 'label' => __( 'Headline Font Weight', 'notificationx' ), 'name' => 'exit_intent_t5_headline_font_weight', 'type' => 'select', 'default' => '800',
2017 'options' => $this->font_weight_options() ],
2018
2019 // Description
2020 [ 'label' => __( 'Description Color', 'notificationx' ), 'name' => 'exit_intent_t5_desc_color', 'type' => 'colorpicker', 'default' => '#4a4a6a' ],
2021 [ 'label' => __( 'Description Font Size', 'notificationx' ), 'name' => 'exit_intent_t5_desc_font_size', 'type' => 'number', 'default' => 14, 'description' => 'px' ],
2022
2023 // Countdown label + numbers + unit labels
2024 [ 'label' => __( 'Countdown Label Color', 'notificationx' ), 'name' => 'exit_intent_t5_cd_label_color', 'type' => 'colorpicker', 'default' => '#1a1a2e',
2025 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ) ],
2026 [ 'label' => __( 'Countdown Label Font Size', 'notificationx' ), 'name' => 'exit_intent_t5_cd_label_font_size', 'type' => 'number', 'default' => 12, 'description' => 'px',
2027 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ) ],
2028 [ 'label' => __( 'Countdown Number Background', 'notificationx' ), 'name' => 'exit_intent_t5_cd_num_bg', 'type' => 'colorpicker', 'default' => '#fff0f5',
2029 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ) ],
2030 [ 'label' => __( 'Countdown Number Color', 'notificationx' ), 'name' => 'exit_intent_t5_cd_num_color', 'type' => 'colorpicker', 'default' => '#e91e63',
2031 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ) ],
2032 [ 'label' => __( 'Countdown Number Font Size', 'notificationx' ), 'name' => 'exit_intent_t5_cd_num_font_size', 'type' => 'number', 'default' => 22, 'description' => 'px',
2033 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ) ],
2034 [ 'label' => __( 'Countdown Number Border Radius', 'notificationx' ),'name' => 'exit_intent_t5_cd_num_radius', 'type' => 'number', 'default' => 6, 'description' => 'px',
2035 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ) ],
2036 [ 'label' => __( 'Countdown Unit Label Color', 'notificationx' ), 'name' => 'exit_intent_t5_cd_unit_color', 'type' => 'colorpicker', 'default' => '#4a4a6a',
2037 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ) ],
2038 [ 'label' => __( 'Countdown Unit Label Font Size', 'notificationx' ),'name' => 'exit_intent_t5_cd_unit_font_size', 'type' => 'number', 'default' => 11, 'description' => 'px',
2039 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ) ],
2040
2041 // CTA button
2042 [ 'label' => __( 'Button Background', 'notificationx' ), 'name' => 'exit_intent_t5_btn_bg', 'type' => 'colorpicker', 'default' => '#e91e63' ],
2043 [ 'label' => __( 'Button Text Color', 'notificationx' ), 'name' => 'exit_intent_t5_btn_color', 'type' => 'colorpicker', 'default' => '#ffffff' ],
2044 [ 'label' => __( 'Button Border Radius', 'notificationx' ), 'name' => 'exit_intent_t5_btn_border_radius', 'type' => 'number', 'default' => 6, 'description' => 'px' ],
2045 [ 'label' => __( 'Button Font Size', 'notificationx' ), 'name' => 'exit_intent_t5_btn_font_size', 'type' => 'number', 'default' => 14, 'description' => 'px' ],
2046 [ 'label' => __( 'Button Font Weight', 'notificationx' ), 'name' => 'exit_intent_t5_btn_font_weight', 'type' => 'select', 'default' => '700',
2047 'options' => $this->font_weight_options() ],
2048
2049 // Dismiss link
2050 [ 'label' => __( 'Dismiss Text Color', 'notificationx' ), 'name' => 'exit_intent_t5_dismiss_color', 'type' => 'colorpicker', 'default' => '#9a9aa8' ],
2051 [ 'label' => __( 'Dismiss Font Size', 'notificationx' ), 'name' => 'exit_intent_t5_dismiss_font_size', 'type' => 'number', 'default' => 12, 'description' => 'px' ],
2052 ];
2053 }
2054
2055 /** ───────────────────────── Theme Six — Product Countdown ───────────────────────── */
2056 private function theme_six_design_fields() {
2057 return [
2058 // Container / overlay / close
2059 [ 'label' => __( 'Popup Max Width', 'notificationx' ), 'name' => 'exit_intent_t6_max_width', 'type' => 'number', 'default' => 600, 'description' => 'px' ],
2060 [ 'label' => __( 'Border Radius', 'notificationx' ), 'name' => 'exit_intent_t6_border_radius', 'type' => 'number', 'default' => 12, 'description' => 'px' ],
2061 [ 'label' => __( 'Background Start Color', 'notificationx' ), 'name' => 'exit_intent_t6_bg_start', 'type' => 'colorpicker', 'default' => '#ffffff',
2062 'help' => __( 'Center color of the radial background gradient.', 'notificationx' ) ],
2063 [ 'label' => __( 'Background Mid Color', 'notificationx' ), 'name' => 'exit_intent_t6_bg_mid', 'type' => 'colorpicker', 'default' => '#fdf2f8' ],
2064 [ 'label' => __( 'Background End Color', 'notificationx' ), 'name' => 'exit_intent_t6_bg_end', 'type' => 'colorpicker', 'default' => '#f5f3ff',
2065 'help' => __( 'Outer color of the radial background gradient.', 'notificationx' ) ],
2066 [ 'label' => __( 'Overlay Background Color', 'notificationx' ), 'name' => 'exit_intent_overlay_color', 'type' => 'colorpicker', 'default' => 'rgba(0,0,0,0.5)' ],
2067 [ 'label' => __( 'Close Button Color', 'notificationx' ), 'name' => 'exit_intent_close_color', 'type' => 'colorpicker', 'default' => '#1f2937' ],
2068 [ 'label' => __( 'Close Button Size', 'notificationx' ), 'name' => 'exit_intent_close_size', 'type' => 'number', 'default' => 20, 'description' => 'px' ],
2069
2070 // Title
2071 [ 'label' => __( 'Title Color', 'notificationx' ), 'name' => 'exit_intent_t6_title_color', 'type' => 'colorpicker', 'default' => '#1f2937' ],
2072 [ 'label' => __( 'Title Font Size', 'notificationx' ), 'name' => 'exit_intent_t6_title_font_size', 'type' => 'number', 'default' => 36, 'description' => 'px' ],
2073 [ 'label' => __( 'Title Font Weight', 'notificationx' ), 'name' => 'exit_intent_t6_title_font_weight', 'type' => 'select', 'default' => '700',
2074 'options' => $this->font_weight_options() ],
2075
2076 // Countdown label + numbers + unit labels
2077 [ 'label' => __( 'Countdown Label Color', 'notificationx' ), 'name' => 'exit_intent_t6_cd_label_color', 'type' => 'colorpicker', 'default' => '#4b5563',
2078 'rules' => Rules::is( 'exit_intent_t6_show_timer', true ) ],
2079 [ 'label' => __( 'Countdown Label Font Size', 'notificationx' ), 'name' => 'exit_intent_t6_cd_label_font_size', 'type' => 'number', 'default' => 18, 'description' => 'px',
2080 'rules' => Rules::is( 'exit_intent_t6_show_timer', true ) ],
2081 [ 'label' => __( 'Countdown Number Background', 'notificationx' ), 'name' => 'exit_intent_t6_cd_num_bg', 'type' => 'colorpicker', 'default' => '#f3e8f2',
2082 'rules' => Rules::is( 'exit_intent_t6_show_timer', true ) ],
2083 [ 'label' => __( 'Countdown Number Color', 'notificationx' ), 'name' => 'exit_intent_t6_cd_num_color', 'type' => 'colorpicker', 'default' => '#374151',
2084 'rules' => Rules::is( 'exit_intent_t6_show_timer', true ) ],
2085 [ 'label' => __( 'Countdown Number Font Size', 'notificationx' ), 'name' => 'exit_intent_t6_cd_num_font_size', 'type' => 'number', 'default' => 24, 'description' => 'px',
2086 'rules' => Rules::is( 'exit_intent_t6_show_timer', true ) ],
2087 [ 'label' => __( 'Countdown Number Border Radius', 'notificationx' ),'name' => 'exit_intent_t6_cd_num_radius', 'type' => 'number', 'default' => 2, 'description' => 'px',
2088 'rules' => Rules::is( 'exit_intent_t6_show_timer', true ) ],
2089 [ 'label' => __( 'Countdown Unit Label Color', 'notificationx' ), 'name' => 'exit_intent_t6_cd_unit_color', 'type' => 'colorpicker', 'default' => '#9f1239',
2090 'rules' => Rules::is( 'exit_intent_t6_show_timer', true ) ],
2091 [ 'label' => __( 'Countdown Unit Label Font Size', 'notificationx' ),'name' => 'exit_intent_t6_cd_unit_font_size', 'type' => 'number', 'default' => 12, 'description' => 'px',
2092 'rules' => Rules::is( 'exit_intent_t6_show_timer', true ) ],
2093
2094 // CTA button
2095 [ 'label' => __( 'Button Background', 'notificationx' ), 'name' => 'exit_intent_t6_btn_bg', 'type' => 'colorpicker', 'default' => '#845e7c' ],
2096 [ 'label' => __( 'Button Text Color', 'notificationx' ), 'name' => 'exit_intent_t6_btn_color', 'type' => 'colorpicker', 'default' => '#ffffff' ],
2097 [ 'label' => __( 'Button Border Radius', 'notificationx' ), 'name' => 'exit_intent_t6_btn_border_radius', 'type' => 'number', 'default' => 4, 'description' => 'px' ],
2098 [ 'label' => __( 'Button Font Size', 'notificationx' ), 'name' => 'exit_intent_t6_btn_font_size', 'type' => 'number', 'default' => 24, 'description' => 'px' ],
2099 [ 'label' => __( 'Button Font Weight', 'notificationx' ), 'name' => 'exit_intent_t6_btn_font_weight', 'type' => 'select', 'default' => '700',
2100 'options' => $this->font_weight_options() ],
2101 ];
2102 }
2103
2104 /** ───────────────────────── Theme Seven — Lead Capture w/ Image ───────────────────────── */
2105 private function theme_seven_design_fields() {
2106 $font_family_options = GlobalFields::get_instance()->normalize_fields( [
2107 'inherit' => __( 'Default (inherit)', 'notificationx' ),
2108 "'Playfair Display', Georgia, serif" => __( 'Playfair Display (serif)', 'notificationx' ),
2109 "Georgia, 'Times New Roman', serif" => __( 'Georgia (serif)', 'notificationx' ),
2110 "'Times New Roman', Times, serif" => __( 'Times New Roman (serif)', 'notificationx' ),
2111 "Inter, 'Helvetica Neue', Arial, sans-serif" => __( 'Inter (sans-serif)', 'notificationx' ),
2112 "'Helvetica Neue', Helvetica, Arial, sans-serif" => __( 'Helvetica (sans-serif)', 'notificationx' ),
2113 ] );
2114
2115 return [
2116 // Container / overlay / close
2117 [ 'label' => __( 'Popup Max Width', 'notificationx' ), 'name' => 'exit_intent_t7_max_width', 'type' => 'number', 'default' => 750, 'description' => 'px' ],
2118 [ 'label' => __( 'Border Radius', 'notificationx' ), 'name' => 'exit_intent_t7_border_radius', 'type' => 'number', 'default' => 12, 'description' => 'px' ],
2119 [ 'label' => __( 'Background Color', 'notificationx' ), 'name' => 'exit_intent_t7_bg_color', 'type' => 'colorpicker', 'default' => '#413532',
2120 'help' => __( 'Right (content) panel background.', 'notificationx' ) ],
2121 [ 'label' => __( 'Image Panel Background', 'notificationx' ), 'name' => 'exit_intent_t7_image_bg', 'type' => 'colorpicker', 'default' => '#534542',
2122 'help' => __( 'Shown behind the image (visible only if the image leaves transparent areas or fails to load).', 'notificationx' ) ],
2123 [ 'label' => __( 'Overlay Background Color', 'notificationx' ), 'name' => 'exit_intent_overlay_color', 'type' => 'colorpicker', 'default' => 'rgba(0,0,0,0.5)' ],
2124 [ 'label' => __( 'Close Button Color', 'notificationx' ), 'name' => 'exit_intent_close_color', 'type' => 'colorpicker', 'default' => '#f3d5a2' ],
2125 [ 'label' => __( 'Close Button Size', 'notificationx' ), 'name' => 'exit_intent_close_size', 'type' => 'number', 'default' => 22, 'description' => 'px' ],
2126
2127 // Headline
2128 [ 'label' => __( 'Headline Color', 'notificationx' ), 'name' => 'exit_intent_t7_headline_color', 'type' => 'colorpicker', 'default' => '#f3d5a2' ],
2129 [ 'label' => __( 'Headline Font Size', 'notificationx' ), 'name' => 'exit_intent_t7_headline_font_size', 'type' => 'number', 'default' => 30, 'description' => 'px' ],
2130 [ 'label' => __( 'Headline Font Weight', 'notificationx' ), 'name' => 'exit_intent_t7_headline_font_weight', 'type' => 'select', 'default' => '700',
2131 'options' => $this->font_weight_options() ],
2132 [ 'label' => __( 'Headline Font Family', 'notificationx' ), 'name' => 'exit_intent_t7_headline_font_family', 'type' => 'select', 'default' => "'Playfair Display', Georgia, serif",
2133 'options' => $font_family_options ],
2134
2135 // Discount banner
2136 [ 'label' => __( 'Discount Banner Background', 'notificationx' ), 'name' => 'exit_intent_t7_discount_bg', 'type' => 'colorpicker', 'default' => 'rgba(255,255,255,0.1)' ],
2137 [ 'label' => __( 'Discount Banner Border Color', 'notificationx' ), 'name' => 'exit_intent_t7_discount_border', 'type' => 'colorpicker', 'default' => 'rgba(255,255,255,0.05)' ],
2138 [ 'label' => __( 'Discount Banner Text Color', 'notificationx' ), 'name' => 'exit_intent_t7_discount_color', 'type' => 'colorpicker', 'default' => '#f3d5a2' ],
2139 [ 'label' => __( 'Discount Banner Font Size', 'notificationx' ), 'name' => 'exit_intent_t7_discount_font_size', 'type' => 'number', 'default' => 16, 'description' => 'px' ],
2140 [ 'label' => __( 'Discount Banner Border Radius', 'notificationx' ), 'name' => 'exit_intent_t7_discount_radius', 'type' => 'number', 'default' => 2, 'description' => 'px' ],
2141
2142 // Description
2143 [ 'label' => __( 'Description Color', 'notificationx' ), 'name' => 'exit_intent_t7_desc_color', 'type' => 'colorpicker', 'default' => 'rgba(243,213,162,0.9)' ],
2144 [ 'label' => __( 'Description Font Size', 'notificationx' ), 'name' => 'exit_intent_t7_desc_font_size', 'type' => 'number', 'default' => 16, 'description' => 'px' ],
2145
2146 // Email input
2147 [ 'label' => __( 'Input Background Color', 'notificationx' ), 'name' => 'exit_intent_t7_input_bg', 'type' => 'colorpicker', 'default' => '#ffffff' ],
2148 [ 'label' => __( 'Input Border Color', 'notificationx' ), 'name' => 'exit_intent_t7_input_border_color', 'type' => 'colorpicker', 'default' => '#6b7280' ],
2149 [ 'label' => __( 'Input Border Radius', 'notificationx' ), 'name' => 'exit_intent_t7_input_border_radius','type' => 'number', 'default' => 0, 'description' => 'px' ],
2150 [ 'label' => __( 'Input Text Color', 'notificationx' ), 'name' => 'exit_intent_t7_input_text_color', 'type' => 'colorpicker', 'default' => '#1f2937' ],
2151
2152 // CTA button
2153 [ 'label' => __( 'Button Background', 'notificationx' ), 'name' => 'exit_intent_t7_btn_bg', 'type' => 'colorpicker', 'default' => '#f3d5a2' ],
2154 [ 'label' => __( 'Button Text Color', 'notificationx' ), 'name' => 'exit_intent_t7_btn_color', 'type' => 'colorpicker', 'default' => '#4d3e3e' ],
2155 [ 'label' => __( 'Button Border Radius', 'notificationx' ), 'name' => 'exit_intent_t7_btn_border_radius', 'type' => 'number', 'default' => 0, 'description' => 'px' ],
2156 [ 'label' => __( 'Button Font Size', 'notificationx' ), 'name' => 'exit_intent_t7_btn_font_size', 'type' => 'number', 'default' => 14, 'description' => 'px' ],
2157 [ 'label' => __( 'Button Font Weight', 'notificationx' ), 'name' => 'exit_intent_t7_btn_font_weight', 'type' => 'select', 'default' => '700',
2158 'options' => $this->font_weight_options() ],
2159 ];
2160 }
2161
2162 public function customize_fields( $fields ) {
2163 // Hide standard timing/behaviour irrelevant to exit intent
2164 foreach ( [ 'timing', 'behaviour', 'sound_section', 'queue_management', 'appearance', 'animation' ] as $key ) {
2165 if ( isset( $fields[ $key ] ) ) {
2166 $fields[ $key ] = Rules::is( 'source', $this->id, true, $fields[ $key ] );
2167 }
2168 }
2169
2170 // Add center position option
2171 if ( isset( $fields['appearance']['fields']['position']['options'] ) ) {
2172 $fields['appearance']['fields']['position']['options']['center'] = [
2173 'label' => __( 'Center', 'notificationx' ),
2174 'value' => 'center',
2175 'rules' => Rules::is( 'source', $this->id ),
2176 ];
2177 }
2178
2179 // NOTE: keep this key unique. The Announcement extension (PopupNotification)
2180 // also registers a section literally named `exit_intent_settings` for its
2181 // "Convert to Exit Intent" feature; sharing the key here let Popup's filter
2182 // (same `nx_customize_fields` priority, registered later) overwrite this
2183 // section with a `source == popup_notification` rule, hiding it for the
2184 // Exit Intent type and leaving the whole Customize tab blank.
2185 $fields['exit_intent_popup_settings'] = [
2186 'label' => __( 'Exit Intent Settings', 'notificationx' ),
2187 'name' => 'exit_intent_popup_settings',
2188 'type' => 'section',
2189 'priority' => 15,
2190 'rules' => Rules::is( 'source', $this->id ),
2191 'fields' => [
2192 'show_close_button' => [
2193 'label' => __( 'Show Close Button', 'notificationx' ),
2194 'name' => 'show_close_button',
2195 'type' => 'toggle',
2196 'default' => true,
2197 ],
2198 'exit_intent_position' => [
2199 'label' => __( 'Position', 'notificationx' ),
2200 'name' => 'exit_intent_position',
2201 'type' => 'select',
2202 'default' => 'center',
2203 'options' => GlobalFields::get_instance()->normalize_fields( [
2204 'center' => __( 'Center', 'notificationx' ),
2205 'bottom-left' => __( 'Bottom Left', 'notificationx' ),
2206 'bottom-right' => __( 'Bottom Right', 'notificationx' ),
2207 ] ),
2208 ],
2209 'exit_intent_sensitivity' => [
2210 'label' => __( 'Trigger Sensitivity', 'notificationx' ),
2211 'name' => 'exit_intent_sensitivity',
2212 'type' => 'select',
2213 'default' => '20',
2214 'help' => __( 'Distance from top of viewport (px) that triggers the popup.', 'notificationx' ),
2215 'options' => GlobalFields::get_instance()->normalize_fields( [
2216 '10' => __( 'High (10px)', 'notificationx' ),
2217 '20' => __( 'Medium (20px)', 'notificationx' ),
2218 '50' => __( 'Low (50px)', 'notificationx' ),
2219 ] ),
2220 ],
2221 'exit_intent_cookie_days' => [
2222 'label' => __( 'Do Not Show Again For', 'notificationx' ),
2223 'name' => 'exit_intent_cookie_days',
2224 'type' => 'number',
2225 'default' => 7,
2226 'description' => __( 'days', 'notificationx' ),
2227 'help' => __( 'Once dismissed, hide the popup for this many days.', 'notificationx' ),
2228 ],
2229 'exit_intent_mobile_disable' => [
2230 'label' => __( 'Disable on Mobile', 'notificationx' ),
2231 'name' => 'exit_intent_mobile_disable',
2232 'type' => 'toggle',
2233 'default' => true,
2234 'help' => __( 'Exit intent detection is unreliable on touch devices.', 'notificationx' ),
2235 ],
2236 ],
2237 ];
2238
2239 return $fields;
2240 }
2241
2242 public function doc() {
2243 return sprintf(__('
2244 <p>Show a targeted message at the exact moment someone is about to close your tab & bring them back into the funnel. Need help? Check out our <a target="_blank" href="%1$s">documentation</a>.</p>',
2245 'notificationx'),
2246 'https://notificationx.com/docs/how-to-configure-exit-intent-popup/',
2247 );
2248 }
2249 }
2250