PluginProbe
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar / 3.2.11
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar v3.2.11
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.11, at includes/Extensions/ExitIntent/ExitIntentNotification.php

2,280 lines 128.3 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 // Build With AI tab — Pro feature. Free plugin only registers the tab
1101 // shell + field type; the Pro plugin supplies the actual builder via
1102 // the `nx_build_ai_render` filter (see PressBar's `nxbar_build_with_ai`
1103 // for the same pattern already shipped for Notification Bar).
1104 $tab[] = [
1105 'label' => __( 'Build With AI', 'notificationx' ),
1106 'name' => 'exit_intent_ai_tab',
1107 'id' => 'exit_intent_ai_tab',
1108 'type' => 'section',
1109 'icon' => NOTIFICATIONX_ADMIN_URL . 'images/icons/build-with-ai-icon.svg',
1110 'rules' => Rules::is( 'source', $this->id ),
1111 'fields' => [
1112 'exit_intent_ai_tab' => [
1113 'label' => __( 'Build With AI', 'notificationx' ),
1114 'name' => 'exit_intent_ai_tab',
1115 'id' => 'exit_intent_ai_tab',
1116 'type' => 'section',
1117 'icon' => NOTIFICATIONX_ADMIN_URL . 'images/responsive/desktop.svg',
1118 'fields' => [
1119 'exit_intent_ai_tab_fields' => [
1120 'name' => 'exit_intent_ai_tab_fields',
1121 'type' => 'exit-intent-build_with_ai',
1122 'label' => __( 'Exit Intent', 'notificationx' ),
1123 'priority' => 10,
1124 ],
1125 ],
1126 ],
1127 ],
1128 ];
1129
1130 return $fields;
1131 }
1132
1133 public function display_fields( $fields ) {
1134 if ( isset( $fields['image-section'] ) ) {
1135 $fields['image-section'] = Rules::is( 'source', $this->id, true, $fields['image-section'] );
1136 }
1137 return $fields;
1138 }
1139
1140 public function content_fields( $fields ) {
1141 // Hide standard content fields for this source
1142 if ( isset( $fields['utm_options'] ) ) {
1143 $fields['utm_options'] = Rules::is( 'source', $this->id, true, $fields['utm_options'] );
1144 }
1145 if ( isset( $fields['content'] ) ) {
1146 $fields['content'] = Rules::is( 'source', $this->id, true, $fields['content'] );
1147 }
1148 if ( isset( $fields['link_options'] ) ) {
1149 $fields['link_options'] = Rules::is( 'source', $this->id, true, $fields['link_options'] );
1150 }
1151
1152 // ── Theme Two content fields ─────────────────────────────────────────────
1153 $fields['exit_intent_theme_two_section'] = [
1154 'label' => __( 'Exit Intent Content', 'notificationx' ),
1155 'name' => 'exit_intent_theme_two_section',
1156 'type' => 'section',
1157 'priority' => 5,
1158 'rules' => Rules::logicalRule( [
1159 Rules::is( 'source', $this->id ),
1160 Rules::is( 'themes', $this->id . '_theme-two' ),
1161 ] ),
1162 'fields' => [
1163 [
1164 'label' => __( 'Right Panel Image', 'notificationx' ),
1165 'name' => 'exit_intent_image_url',
1166 'type' => 'media',
1167 'priority' => 5,
1168 'default' => [
1169 'url' => 'https://notificationx.com/wp-content/uploads/2026/05/exit-intend-theme-two-five-seven.jpg',
1170 ],
1171 'help' => __( 'Upload or select the image to display in the right panel.', 'notificationx' ),
1172 ],
1173 [
1174 'label' => __( 'Sale Badge Text', 'notificationx' ),
1175 'name' => 'exit_intent_sale_badge',
1176 'type' => 'text',
1177 'priority' => 10,
1178 'default' => __( 'Flash Sale', 'notificationx' ),
1179 ],
1180 [
1181 'label' => __( 'Sale Headline', 'notificationx' ),
1182 'name' => 'exit_intent_sale_headline',
1183 'type' => 'text',
1184 'priority' => 20,
1185 'default' => __( '50% OFF', 'notificationx' ),
1186 ],
1187 [
1188 'label' => __( 'Sale Description', 'notificationx' ),
1189 'name' => 'exit_intent_sale_desc',
1190 'type' => 'text',
1191 'priority' => 30,
1192 'default' => __( 'ON ENTIRE ORDER', 'notificationx' ),
1193 ],
1194 [
1195 'label' => __( 'Button Text', 'notificationx' ),
1196 'name' => 'exit_intent_button_text',
1197 'type' => 'text',
1198 'priority' => 60,
1199 'default' => __( 'Shop The Flash Sale Now', 'notificationx' ),
1200 ],
1201 [
1202 'label' => __( 'Button URL', 'notificationx' ),
1203 'name' => 'exit_intent_button_url',
1204 'type' => 'text',
1205 'priority' => 61,
1206 'default' => '',
1207 'help' => __( 'Where the CTA button sends visitors. Leave empty to just dismiss the popup.', 'notificationx' ),
1208 ],
1209 [
1210 'label' => __( 'Open in New Tab', 'notificationx' ),
1211 'name' => 'exit_intent_button_new_tab',
1212 'type' => 'toggle',
1213 'priority' => 62,
1214 'default' => true,
1215 ],
1216 [
1217 'label' => __( 'Dismiss Link Text', 'notificationx' ),
1218 'name' => 'exit_intent_dismiss_text',
1219 'type' => 'text',
1220 'priority' => 70,
1221 'default' => __( 'NO, THANKS!', 'notificationx' ),
1222 ],
1223 ],
1224 ];
1225
1226 // ── Theme Three content fields ────────────────────────────────────────────
1227 $fields['exit_intent_theme_three_section'] = [
1228 'label' => __( 'Exit Intent Content', 'notificationx' ),
1229 'name' => 'exit_intent_theme_three_section',
1230 'type' => 'section',
1231 'priority' => 5,
1232 'rules' => Rules::logicalRule( [
1233 Rules::is( 'source', $this->id ),
1234 Rules::is( 'themes', $this->id . '_theme-three' ),
1235 ] ),
1236 'fields' => [
1237 [
1238 'label' => __( 'Character Image', 'notificationx' ),
1239 'name' => 'exit_intent_image_url',
1240 'type' => 'media',
1241 'priority' => 5,
1242 'default' => [
1243 'url' => 'https://notificationx.com/wp-content/uploads/2026/05/exit-intend-theme-three.png',
1244 ],
1245 'help' => __( 'Upload or select a character/illustration image. It will appear above the popup card.', 'notificationx' ),
1246 ],
1247 [
1248 'label' => __( 'Headline', 'notificationx' ),
1249 'name' => 'exit_intent_t3_title',
1250 'type' => 'text',
1251 'priority' => 10,
1252 'default' => __( "Wait, don't go!", 'notificationx' ),
1253 ],
1254 [
1255 'label' => __( 'Subtitle', 'notificationx' ),
1256 'name' => 'exit_intent_t3_subtitle',
1257 'type' => 'text',
1258 'priority' => 20,
1259 'default' => __( 'Before you leave, we have a special offer just for you!', 'notificationx' ),
1260 ],
1261 [
1262 'label' => __( 'Offer Text', 'notificationx' ),
1263 'name' => 'exit_intent_t3_offer',
1264 'type' => 'text',
1265 'priority' => 30,
1266 'default' => __( 'Get 15% off your next purchase!', 'notificationx' ),
1267 ],
1268 [
1269 'label' => __( 'Coupon / Details Text', 'notificationx' ),
1270 'name' => 'exit_intent_t3_coupon_text',
1271 'type' => 'text',
1272 'priority' => 40,
1273 'default' => __( "Use code STAY15 at checkout. Don't miss out on this limited-time offer.", 'notificationx' ),
1274 ],
1275 [
1276 'label' => __( 'Button Text', 'notificationx' ),
1277 'name' => 'exit_intent_button_text',
1278 'type' => 'text',
1279 'priority' => 50,
1280 'default' => __( 'Claim Offer', 'notificationx' ),
1281 ],
1282 [
1283 'label' => __( 'Button URL', 'notificationx' ),
1284 'name' => 'exit_intent_button_url',
1285 'type' => 'text',
1286 'priority' => 51,
1287 'default' => '',
1288 'help' => __( 'Where the CTA button sends visitors. Leave empty to just dismiss the popup.', 'notificationx' ),
1289 ],
1290 [
1291 'label' => __( 'Open in New Tab', 'notificationx' ),
1292 'name' => 'exit_intent_button_new_tab',
1293 'type' => 'toggle',
1294 'priority' => 52,
1295 'default' => true,
1296 ],
1297 [
1298 'label' => __( 'Dismiss Link Text', 'notificationx' ),
1299 'name' => 'exit_intent_dismiss_text',
1300 'type' => 'text',
1301 'priority' => 60,
1302 'default' => __( 'No, thanks!', 'notificationx' ),
1303 ],
1304 ],
1305 ];
1306
1307 // ── Theme Four content fields ─────────────────────────────────────────────
1308 $fields['exit_intent_theme_four_section'] = [
1309 'label' => __( 'Exit Intent Content', 'notificationx' ),
1310 'name' => 'exit_intent_theme_four_section',
1311 'type' => 'section',
1312 'priority' => 5,
1313 'rules' => Rules::logicalRule( [
1314 Rules::is( 'source', $this->id ),
1315 Rules::is( 'themes', $this->id . '_theme-four' ),
1316 ] ),
1317 'fields' => [
1318 [
1319 'label' => __( 'Video Thumbnail', 'notificationx' ),
1320 'name' => 'exit_intent_image_url',
1321 'type' => 'media',
1322 'priority' => 5,
1323 'default' => [
1324 'url' => 'https://notificationx.com/wp-content/uploads/2026/05/exit-intend-theme-four.jpg',
1325 ],
1326 'help' => __( 'Upload or select the video thumbnail/preview image.', 'notificationx' ),
1327 ],
1328 [
1329 'label' => __( 'Badge Text', 'notificationx' ),
1330 'name' => 'exit_intent_t4_badge',
1331 'type' => 'text',
1332 'priority' => 10,
1333 'default' => __( 'Before you go...', 'notificationx' ),
1334 ],
1335 [
1336 'label' => __( 'Headline', 'notificationx' ),
1337 'name' => 'exit_intent_t4_title',
1338 'type' => 'text',
1339 'priority' => 20,
1340 'default' => __( 'Watch this short demo video', 'notificationx' ),
1341 ],
1342 [
1343 'label' => __( 'Subtitle', 'notificationx' ),
1344 'name' => 'exit_intent_t4_subtitle',
1345 'type' => 'text',
1346 'priority' => 30,
1347 'default' => __( 'See how our product simplifies your workflow.', 'notificationx' ),
1348 ],
1349 [
1350 'label' => __( 'Video URL', 'notificationx' ),
1351 'name' => 'exit_intent_t4_video_url',
1352 'type' => 'text',
1353 'priority' => 40,
1354 'default' => '',
1355 'placeholder' => 'https://www.youtube.com/watch?v=...',
1356 'help' => __( 'Paste a YouTube, Vimeo, or other video platform URL.', 'notificationx' ),
1357 ],
1358 ],
1359 ];
1360
1361 // ── Theme Five content fields ────────────────────────────────────────────
1362 $fields['exit_intent_theme_five_section'] = [
1363 'label' => __( 'Exit Intent Content', 'notificationx' ),
1364 'name' => 'exit_intent_theme_five_section',
1365 'type' => 'section',
1366 'priority' => 5,
1367 'rules' => Rules::logicalRule( [
1368 Rules::is( 'source', $this->id ),
1369 Rules::is( 'themes', $this->id . '_theme-five' ),
1370 ] ),
1371 'fields' => [
1372 [
1373 'label' => __( 'Right Panel Image', 'notificationx' ),
1374 'name' => 'exit_intent_image_url',
1375 'type' => 'media',
1376 'priority' => 5,
1377 'default' => [
1378 'url' => 'https://notificationx.com/wp-content/uploads/2026/05/exit-intend-theme-two-five-seven.jpg',
1379 ],
1380 'help' => __( 'Upload or select the image to display in the right panel.', 'notificationx' ),
1381 ],
1382 [
1383 'label' => __( 'Title', 'notificationx' ),
1384 'name' => 'exit_intent_t5_title',
1385 'type' => 'text',
1386 'priority' => 10,
1387 'default' => __( 'Flash Sale', 'notificationx' ),
1388 ],
1389 [
1390 'label' => __( 'Headline', 'notificationx' ),
1391 'name' => 'exit_intent_t5_headline',
1392 'type' => 'text',
1393 'priority' => 20,
1394 'default' => __( '50% OFF', 'notificationx' ),
1395 ],
1396 [
1397 'label' => __( 'Description', 'notificationx' ),
1398 'name' => 'exit_intent_t5_desc',
1399 'type' => 'text',
1400 'priority' => 30,
1401 'default' => __( 'ON ENTIRE ORDER', 'notificationx' ),
1402 ],
1403 [
1404 'label' => __( 'Button Text', 'notificationx' ),
1405 'name' => 'exit_intent_button_text',
1406 'type' => 'text',
1407 'priority' => 60,
1408 'default' => __( 'Shop The Flash Sale Now', 'notificationx' ),
1409 ],
1410 [
1411 'label' => __( 'Button URL', 'notificationx' ),
1412 'name' => 'exit_intent_button_url',
1413 'type' => 'text',
1414 'priority' => 61,
1415 'default' => '',
1416 'help' => __( 'Where the CTA button sends visitors. Leave empty to just dismiss the popup.', 'notificationx' ),
1417 ],
1418 [
1419 'label' => __( 'Open in New Tab', 'notificationx' ),
1420 'name' => 'exit_intent_button_new_tab',
1421 'type' => 'toggle',
1422 'priority' => 62,
1423 'default' => true,
1424 ],
1425 [
1426 'label' => __( 'Dismiss Link Text', 'notificationx' ),
1427 'name' => 'exit_intent_dismiss_text',
1428 'type' => 'text',
1429 'priority' => 70,
1430 'default' => __( 'NO, THANKS!', 'notificationx' ),
1431 ],
1432 ],
1433 ];
1434
1435 // ── Theme Five Timer Settings ────────────────────────────────────────────
1436 $fields['exit_intent_theme_five_timer_section'] = [
1437 'label' => __( 'Timer Settings', 'notificationx' ),
1438 'name' => 'exit_intent_theme_five_timer_section',
1439 'type' => 'section',
1440 'priority' => 6,
1441 'rules' => Rules::logicalRule( [
1442 Rules::is( 'source', $this->id ),
1443 Rules::is( 'themes', $this->id . '_theme-five' ),
1444 ] ),
1445 'fields' => [
1446 [
1447 'label' => __( 'Show Countdown Timer', 'notificationx' ),
1448 'name' => 'exit_intent_t5_show_timer',
1449 'type' => 'toggle',
1450 'priority' => 5,
1451 'default' => true,
1452 ],
1453 [
1454 'label' => __( 'Countdown Label', 'notificationx' ),
1455 'name' => 'exit_intent_t5_countdown_label',
1456 'type' => 'text',
1457 'priority' => 10,
1458 'default' => __( 'LIMITED-TIME OFFER! SALE ENDS IN', 'notificationx' ),
1459 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ),
1460 ],
1461 [
1462 'label' => __( 'Sale End Date & Time', 'notificationx' ),
1463 'name' => 'exit_intent_countdown_end',
1464 'type' => 'date',
1465 'priority' => 20,
1466 'default' => '',
1467 'help' => __( 'Pick the date and time when the sale ends. Leave empty to display static demo numbers.', 'notificationx' ),
1468 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ),
1469 ],
1470 [
1471 'label' => __( 'Days Label', 'notificationx' ),
1472 'name' => 'exit_intent_t5_days_label',
1473 'type' => 'text',
1474 'priority' => 30,
1475 'default' => __( 'DAYS', 'notificationx' ),
1476 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ),
1477 ],
1478 [
1479 'label' => __( 'Hours Label', 'notificationx' ),
1480 'name' => 'exit_intent_t5_hours_label',
1481 'type' => 'text',
1482 'priority' => 40,
1483 'default' => __( 'HRS', 'notificationx' ),
1484 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ),
1485 ],
1486 [
1487 'label' => __( 'Minutes Label', 'notificationx' ),
1488 'name' => 'exit_intent_t5_minutes_label',
1489 'type' => 'text',
1490 'priority' => 50,
1491 'default' => __( 'MIN', 'notificationx' ),
1492 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ),
1493 ],
1494 [
1495 'label' => __( 'Seconds Label', 'notificationx' ),
1496 'name' => 'exit_intent_t5_seconds_label',
1497 'type' => 'text',
1498 'priority' => 60,
1499 'default' => __( 'SEC', 'notificationx' ),
1500 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ),
1501 ],
1502 [
1503 'label' => __( 'Timer Box Background', 'notificationx' ),
1504 'name' => 'exit_intent_t5_timer_bg',
1505 'type' => 'colorpicker',
1506 'priority' => 70,
1507 'default' => '#fff0f5',
1508 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ),
1509 ],
1510 [
1511 'label' => __( 'Timer Number Color', 'notificationx' ),
1512 'name' => 'exit_intent_t5_timer_color',
1513 'type' => 'colorpicker',
1514 'priority' => 80,
1515 'default' => '#e91e63',
1516 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ),
1517 ],
1518 ],
1519 ];
1520
1521 // ── Theme Seven content fields ───────────────────────────────────────────
1522 $fields['exit_intent_theme_seven_section'] = [
1523 'label' => __( 'Exit Intent Content', 'notificationx' ),
1524 'name' => 'exit_intent_theme_seven_section',
1525 'type' => 'section',
1526 'priority' => 5,
1527 'rules' => Rules::logicalRule( [
1528 Rules::is( 'source', $this->id ),
1529 Rules::is( 'themes', $this->id . '_theme-seven' ),
1530 ] ),
1531 'fields' => [
1532 [
1533 'label' => __( 'Left Panel Image', 'notificationx' ),
1534 'name' => 'exit_intent_image_url',
1535 'type' => 'media',
1536 'priority' => 5,
1537 'default' => [
1538 'url' => 'https://notificationx.com/wp-content/uploads/2026/05/exit-intend-theme-two-five-seven.jpg',
1539 ],
1540 'help' => __( 'Upload or select the image to display in the left panel.', 'notificationx' ),
1541 ],
1542 [
1543 'label' => __( 'Headline', 'notificationx' ),
1544 'name' => 'exit_intent_t7_headline',
1545 'type' => 'text',
1546 'priority' => 10,
1547 'default' => __( 'Home Is Where Your Story Begins', 'notificationx' ),
1548 ],
1549 [
1550 'label' => __( 'Discount Banner Text', 'notificationx' ),
1551 'name' => 'exit_intent_t7_discount_text',
1552 'type' => 'text',
1553 'priority' => 20,
1554 'default' => __( 'Get 15% Off Your First Order!', 'notificationx' ),
1555 ],
1556 [
1557 'label' => __( 'Description', 'notificationx' ),
1558 'name' => 'exit_intent_t7_description',
1559 'type' => 'text',
1560 'priority' => 30,
1561 'default' => __( 'Discover timeless pieces that turn any space into a sanctuary.', 'notificationx' ),
1562 ],
1563 [
1564 'label' => __( 'Email Placeholder', 'notificationx' ),
1565 'name' => 'exit_intent_t7_email_placeholder',
1566 'type' => 'text',
1567 'priority' => 40,
1568 'default' => __( 'Enter your email', 'notificationx' ),
1569 ],
1570 [
1571 'label' => __( 'Button Text', 'notificationx' ),
1572 'name' => 'exit_intent_button_text',
1573 'type' => 'text',
1574 'priority' => 50,
1575 'default' => __( 'SEND COUPON', 'notificationx' ),
1576 ],
1577 ],
1578 ];
1579
1580 // ── Theme Six content fields ─────────────────────────────────────────────
1581 $fields['exit_intent_theme_six_section'] = [
1582 'label' => __( 'Exit Intent Content', 'notificationx' ),
1583 'name' => 'exit_intent_theme_six_section',
1584 'type' => 'section',
1585 'priority' => 5,
1586 'rules' => Rules::logicalRule( [
1587 Rules::is( 'source', $this->id ),
1588 Rules::is( 'themes', $this->id . '_theme-six' ),
1589 ] ),
1590 'fields' => [
1591 [
1592 'label' => __( 'Product Image', 'notificationx' ),
1593 'name' => 'exit_intent_image_url',
1594 'type' => 'media',
1595 'priority' => 5,
1596 'default' => [
1597 'url' => 'https://notificationx.com/wp-content/uploads/2026/05/exit-intend-theme-six.png',
1598 ],
1599 'help' => __( 'Upload or select the product image to display at the top of the popup.', 'notificationx' ),
1600 ],
1601 [
1602 'label' => __( 'Headline', 'notificationx' ),
1603 'name' => 'exit_intent_t6_title',
1604 'type' => 'text',
1605 'priority' => 10,
1606 'default' => __( 'Limited Edition Bass Boost Headphones', 'notificationx' ),
1607 ],
1608 [
1609 'label' => __( 'Button Text', 'notificationx' ),
1610 'name' => 'exit_intent_button_text',
1611 'type' => 'text',
1612 'priority' => 60,
1613 'default' => __( 'Grab Now', 'notificationx' ),
1614 ],
1615 [
1616 'label' => __( 'Button URL', 'notificationx' ),
1617 'name' => 'exit_intent_button_url',
1618 'type' => 'text',
1619 'priority' => 61,
1620 'default' => '',
1621 'help' => __( 'Where the CTA button sends visitors. Leave empty to just dismiss the popup.', 'notificationx' ),
1622 ],
1623 [
1624 'label' => __( 'Open in New Tab', 'notificationx' ),
1625 'name' => 'exit_intent_button_new_tab',
1626 'type' => 'toggle',
1627 'priority' => 62,
1628 'default' => true,
1629 ],
1630 ],
1631 ];
1632
1633 // ── Theme Six Timer Settings ─────────────────────────────────────────────
1634 $fields['exit_intent_theme_six_timer_section'] = [
1635 'label' => __( 'Timer Settings', 'notificationx' ),
1636 'name' => 'exit_intent_theme_six_timer_section',
1637 'type' => 'section',
1638 'priority' => 6,
1639 'rules' => Rules::logicalRule( [
1640 Rules::is( 'source', $this->id ),
1641 Rules::is( 'themes', $this->id . '_theme-six' ),
1642 ] ),
1643 'fields' => [
1644 [
1645 'label' => __( 'Show Countdown Timer', 'notificationx' ),
1646 'name' => 'exit_intent_t6_show_timer',
1647 'type' => 'toggle',
1648 'priority' => 5,
1649 'default' => true,
1650 ],
1651 [
1652 'label' => __( 'Countdown Label', 'notificationx' ),
1653 'name' => 'exit_intent_t6_countdown_label',
1654 'type' => 'text',
1655 'priority' => 10,
1656 'default' => __( 'Offer Ends In', 'notificationx' ),
1657 'rules' => Rules::is( 'exit_intent_t6_show_timer', true ),
1658 ],
1659 [
1660 'label' => __( 'Sale End Date & Time', 'notificationx' ),
1661 'name' => 'exit_intent_countdown_end',
1662 'type' => 'date',
1663 'priority' => 20,
1664 'default' => '',
1665 'help' => __( 'Pick the date and time when the sale ends. Leave empty to display static demo numbers.', 'notificationx' ),
1666 'rules' => Rules::is( 'exit_intent_t6_show_timer', true ),
1667 ],
1668 [
1669 'label' => __( 'Days Label', 'notificationx' ),
1670 'name' => 'exit_intent_t6_days_label',
1671 'type' => 'text',
1672 'priority' => 30,
1673 'default' => __( 'DAYS', 'notificationx' ),
1674 'rules' => Rules::is( 'exit_intent_t6_show_timer', true ),
1675 ],
1676 [
1677 'label' => __( 'Hours Label', 'notificationx' ),
1678 'name' => 'exit_intent_t6_hours_label',
1679 'type' => 'text',
1680 'priority' => 40,
1681 'default' => __( 'HOURS', 'notificationx' ),
1682 'rules' => Rules::is( 'exit_intent_t6_show_timer', true ),
1683 ],
1684 [
1685 'label' => __( 'Minutes Label', 'notificationx' ),
1686 'name' => 'exit_intent_t6_minutes_label',
1687 'type' => 'text',
1688 'priority' => 50,
1689 'default' => __( 'MIN', 'notificationx' ),
1690 'rules' => Rules::is( 'exit_intent_t6_show_timer', true ),
1691 ],
1692 [
1693 'label' => __( 'Seconds Label', 'notificationx' ),
1694 'name' => 'exit_intent_t6_seconds_label',
1695 'type' => 'text',
1696 'priority' => 60,
1697 'default' => __( 'SEC', 'notificationx' ),
1698 'rules' => Rules::is( 'exit_intent_t6_show_timer', true ),
1699 ],
1700 ],
1701 ];
1702
1703 // ── Theme One content fields ─────────────────────────────────────────────
1704 $fields['exit_intent_content_section'] = [
1705 'label' => __( 'Exit Intent Content', 'notificationx' ),
1706 'name' => 'exit_intent_content_section',
1707 'type' => 'section',
1708 'priority' => 5,
1709 'rules' => Rules::logicalRule( [
1710 Rules::is( 'source', $this->id ),
1711 Rules::is( 'themes', $this->id . '_theme-two', true ),
1712 Rules::is( 'themes', $this->id . '_theme-three', true ),
1713 Rules::is( 'themes', $this->id . '_theme-four', true ),
1714 Rules::is( 'themes', $this->id . '_theme-five', true ),
1715 Rules::is( 'themes', $this->id . '_theme-six', true ),
1716 Rules::is( 'themes', $this->id . '_theme-seven', true ),
1717 ] ),
1718 'fields' => [
1719 // ── Main copy ────────────────────────────────────────────
1720 [
1721 'label' => __( 'Title', 'notificationx' ),
1722 'name' => 'exit_intent_title',
1723 'type' => 'text',
1724 'priority' => 10,
1725 'default' => __( 'Wait! Before You Go...', 'notificationx' ),
1726 ],
1727 [
1728 'label' => __( 'Subtitle', 'notificationx' ),
1729 'name' => 'exit_intent_subtitle',
1730 'type' => 'text',
1731 'priority' => 20,
1732 'default' => __( "We'd love to understand what's holding you back", 'notificationx' ),
1733 ],
1734 // ── Form fields ──────────────────────────────────────────
1735 [
1736 'label' => __( 'Show Name Field', 'notificationx' ),
1737 'name' => 'exit_intent_show_name',
1738 'type' => 'toggle',
1739 'default' => true,
1740 'priority' => 70,
1741 'is_pro' => true,
1742 ],
1743 [
1744 'label' => __( 'Name Placeholder', 'notificationx' ),
1745 'name' => 'exit_intent_name_label',
1746 'type' => 'text',
1747 'default' => __( 'Name *', 'notificationx' ),
1748 'priority' => 75,
1749 'is_pro' => true,
1750 'rules' => Rules::is( 'exit_intent_show_name', true ),
1751 ],
1752 [
1753 'label' => __( 'Show Email Field', 'notificationx' ),
1754 'name' => 'exit_intent_show_email',
1755 'type' => 'toggle',
1756 'default' => true,
1757 'priority' => 80,
1758 'is_pro' => true,
1759 ],
1760 [
1761 'label' => __( 'Email Placeholder', 'notificationx' ),
1762 'name' => 'exit_intent_email_label',
1763 'type' => 'text',
1764 'default' => __( 'Enter Your Email *', 'notificationx' ),
1765 'priority' => 85,
1766 'is_pro' => true,
1767 'rules' => Rules::is( 'exit_intent_show_email', true ),
1768 ],
1769 [
1770 'label' => __( 'Show Message Field', 'notificationx' ),
1771 'name' => 'exit_intent_show_message',
1772 'type' => 'toggle',
1773 'default' => true,
1774 'priority' => 87,
1775 ],
1776 [
1777 'label' => __( 'Message Placeholder', 'notificationx' ),
1778 'name' => 'exit_intent_message_placeholder',
1779 'type' => 'text',
1780 'default' => __( 'Your message...', 'notificationx' ),
1781 'priority' => 88,
1782 'rules' => Rules::is( 'exit_intent_show_message', true ),
1783 ],
1784
1785 // ── Button ───────────────────────────────────────────────
1786 [
1787 'label' => __( 'Button Text', 'notificationx' ),
1788 'name' => 'exit_intent_button_text',
1789 'type' => 'text',
1790 'default' => __( 'SUBMIT', 'notificationx' ),
1791 'priority' => 90,
1792 ],
1793 ],
1794 ];
1795
1796 return $fields;
1797 }
1798
1799 public function design_fields( $fields ) {
1800 // Hide the inner sub-sections of the global advance_design_section for this source,
1801 // but keep advance_design_section itself visible so its `advance_edit` toggle renders.
1802 foreach ( [ 'design', 'typography', 'image-appearance', 'link_button_design' ] as $key ) {
1803 if ( isset( $fields['advance_design_section']['fields'][ $key ] ) ) {
1804 $fields['advance_design_section']['fields'][ $key ] = Rules::is(
1805 'source', $this->id, true, $fields['advance_design_section']['fields'][ $key ]
1806 );
1807 }
1808 }
1809
1810 // Inline every theme's design fields directly into advance_design_section so they appear
1811 // flat under the existing "Advanced Design" heading — no per-theme sub-headers.
1812 // Priorities are auto-assigned starting at 20 so all theme controls sort BEFORE the
1813 // global Custom CSS section (priority 150).
1814 $design = &$fields['advance_design_section']['fields'];
1815 $priority = 20;
1816 $merge = function( $theme_slug, $list ) use ( &$design, &$priority ) {
1817 $rule = $this->theme_design_rules( $theme_slug );
1818 foreach ( $list as $field ) {
1819 if ( ! empty( $field['rules'] ) ) {
1820 $field['rules'] = Rules::logicalRule( [ $rule, $field['rules'] ] );
1821 } else {
1822 $field['rules'] = $rule;
1823 }
1824 if ( ! isset( $field['priority'] ) ) {
1825 $field['priority'] = $priority;
1826 }
1827 $priority++;
1828 $design[ $field['name'] ] = $field;
1829 }
1830 };
1831
1832 $merge( 'theme-one', $this->theme_one_design_fields() );
1833 $merge( 'theme-two', $this->theme_two_design_fields() );
1834 $merge( 'theme-three', $this->theme_three_design_fields() );
1835 $merge( 'theme-four', $this->theme_four_design_fields() );
1836 $merge( 'theme-five', $this->theme_five_design_fields() );
1837 $merge( 'theme-six', $this->theme_six_design_fields() );
1838 $merge( 'theme-seven', $this->theme_seven_design_fields() );
1839
1840 return $fields;
1841 }
1842
1843 /** Build a rule scoped to source + advance_edit + a specific theme. */
1844 private function theme_design_rules( $theme_slug ) {
1845 return Rules::logicalRule( [
1846 Rules::is( 'source', $this->id ),
1847 Rules::is( 'advance_edit', true ),
1848 Rules::is( 'themes', $this->id . '_' . $theme_slug ),
1849 ] );
1850 }
1851
1852 private function font_weight_options() {
1853 return GlobalFields::get_instance()->normalize_fields( [
1854 '400' => __( 'Normal (400)', 'notificationx' ),
1855 '500' => __( 'Medium (500)', 'notificationx' ),
1856 '600' => __( 'Semi Bold (600)', 'notificationx' ),
1857 '700' => __( 'Bold (700)', 'notificationx' ),
1858 '800' => __( 'Extra Bold (800)', 'notificationx' ),
1859 ] );
1860 }
1861
1862 /** ───────────────────────── Theme One — Feedback Form ───────────────────────── */
1863 private function theme_one_design_fields() {
1864 return [
1865 // Container
1866 [ 'label' => __( 'Popup Max Width', 'notificationx' ), 'name' => 'exit_intent_max_width', 'type' => 'number', 'default' => 540, 'description' => 'px' ],
1867 [ 'label' => __( 'Border Radius', 'notificationx' ), 'name' => 'exit_intent_border_radius', 'type' => 'number', 'default' => 12, 'description' => 'px' ],
1868 [ 'label' => __( 'Background Color', 'notificationx' ), 'name' => 'exit_intent_bg_color', 'type' => 'colorpicker', 'default' => '#EDE7FF' ],
1869 [ 'label' => __( 'Overlay Background Color', 'notificationx' ),'name' => 'exit_intent_overlay_color', 'type' => 'colorpicker', 'default' => 'rgba(0,0,0,0.5)',
1870 'help' => __( 'Color of the backdrop behind the popup.', 'notificationx' ) ],
1871 [ 'label' => __( 'Show Background Pattern', 'notificationx' ), 'name' => 'exit_intent_show_pattern', 'type' => 'toggle', 'default' => true ],
1872 [ 'label' => __( 'Pattern Color', 'notificationx' ), 'name' => 'exit_intent_pattern_color', 'type' => 'colorpicker', 'default' => '#D4C3FF',
1873 'rules' => Rules::is( 'exit_intent_show_pattern', true ) ],
1874
1875 // Title
1876 [ 'label' => __( 'Title Color', 'notificationx' ), 'name' => 'exit_intent_title_color', 'type' => 'colorpicker', 'default' => '#1a1a2e' ],
1877 [ 'label' => __( 'Title Font Size', 'notificationx' ), 'name' => 'exit_intent_title_font_size', 'type' => 'number', 'default' => 26, 'description' => 'px' ],
1878 [ 'label' => __( 'Title Font Weight', 'notificationx' ), 'name' => 'exit_intent_title_font_weight', 'type' => 'select', 'default' => '700',
1879 'options' => $this->font_weight_options() ],
1880
1881 // Subtitle
1882 [ 'label' => __( 'Subtitle Color', 'notificationx' ), 'name' => 'exit_intent_subtitle_color', 'type' => 'colorpicker', 'default' => '#4a4a6a' ],
1883 [ 'label' => __( 'Subtitle Font Size', 'notificationx' ), 'name' => 'exit_intent_subtitle_font_size', 'type' => 'number', 'default' => 14, 'description' => 'px' ],
1884
1885 // Inputs
1886 [ 'label' => __( 'Input Background Color', 'notificationx' ), 'name' => 'exit_intent_input_bg', 'type' => 'colorpicker', 'default' => '#ffffff' ],
1887 [ 'label' => __( 'Input Border Color', 'notificationx' ), 'name' => 'exit_intent_input_border_color', 'type' => 'colorpicker', 'default' => '#dddddd' ],
1888 [ 'label' => __( 'Input Border Radius', 'notificationx' ), 'name' => 'exit_intent_input_border_radius', 'type' => 'number', 'default' => 6, 'description' => 'px' ],
1889 [ 'label' => __( 'Input Text Color', 'notificationx' ), 'name' => 'exit_intent_input_text_color', 'type' => 'colorpicker', 'default' => '#333333' ],
1890
1891 // Button
1892 [ 'label' => __( 'Button Background Color', 'notificationx' ), 'name' => 'exit_intent_btn_bg', 'type' => 'colorpicker', 'default' => '#6B21A8' ],
1893 [ 'label' => __( 'Button Text Color', 'notificationx' ), 'name' => 'exit_intent_btn_color', 'type' => 'colorpicker', 'default' => '#ffffff' ],
1894 [ 'label' => __( 'Button Border Radius', 'notificationx' ), 'name' => 'exit_intent_btn_border_radius', 'type' => 'number', 'default' => 6, 'description' => 'px' ],
1895 [ 'label' => __( 'Button Font Size', 'notificationx' ), 'name' => 'exit_intent_btn_font_size', 'type' => 'number', 'default' => 14, 'description' => 'px' ],
1896 [ 'label' => __( 'Button Font Weight', 'notificationx' ), 'name' => 'exit_intent_btn_font_weight', 'type' => 'select', 'default' => '700',
1897 'options' => $this->font_weight_options() ],
1898
1899 // Close button
1900 [ 'label' => __( 'Close Button Color', 'notificationx' ), 'name' => 'exit_intent_close_color', 'type' => 'colorpicker', 'default' => '#666666' ],
1901 [ 'label' => __( 'Close Button Size', 'notificationx' ), 'name' => 'exit_intent_close_size', 'type' => 'number', 'default' => 20, 'description' => 'px' ],
1902 ];
1903 }
1904
1905 /** ───────────────────────── Theme Two — Flash Sale w/ Countdown ───────────────────────── */
1906 private function theme_two_design_fields() {
1907 return [
1908 // Container / overlay / close
1909 [ 'label' => __( 'Popup Max Width', 'notificationx' ), 'name' => 'exit_intent_t2_max_width', 'type' => 'number', 'default' => 760, 'description' => 'px' ],
1910 [ 'label' => __( 'Border Radius', 'notificationx' ), 'name' => 'exit_intent_t2_border_radius', 'type' => 'number', 'default' => 12, 'description' => 'px' ],
1911 [ 'label' => __( 'Left Panel Background', 'notificationx' ), 'name' => 'exit_intent_t2_bg_color', 'type' => 'colorpicker', 'default' => '#ffffff' ],
1912 [ 'label' => __( 'Overlay Background Color', 'notificationx' ), 'name' => 'exit_intent_overlay_color', 'type' => 'colorpicker', 'default' => 'rgba(0,0,0,0.5)' ],
1913 [ 'label' => __( 'Close Button Color', 'notificationx' ), 'name' => 'exit_intent_close_color', 'type' => 'colorpicker', 'default' => '#666666' ],
1914 [ 'label' => __( 'Close Button Size', 'notificationx' ), 'name' => 'exit_intent_close_size', 'type' => 'number', 'default' => 20, 'description' => 'px' ],
1915
1916 // Sale badge
1917 [ 'label' => __( 'Badge Background', 'notificationx' ), 'name' => 'exit_intent_t2_badge_bg', 'type' => 'colorpicker', 'default' => '#ffe4ec' ],
1918 [ 'label' => __( 'Badge Text Color', 'notificationx' ),'name' => 'exit_intent_t2_badge_color', 'type' => 'colorpicker', 'default' => '#e91e63' ],
1919 [ 'label' => __( 'Badge Font Size', 'notificationx' ), 'name' => 'exit_intent_t2_badge_font_size', 'type' => 'number', 'default' => 12, 'description' => 'px' ],
1920
1921 // Headline
1922 [ 'label' => __( 'Headline Color', 'notificationx' ), 'name' => 'exit_intent_t2_headline_color', 'type' => 'colorpicker', 'default' => '#1a1a2e' ],
1923 [ 'label' => __( 'Headline Font Size', 'notificationx' ), 'name' => 'exit_intent_t2_headline_font_size', 'type' => 'number', 'default' => 56, 'description' => 'px' ],
1924 [ 'label' => __( 'Headline Font Weight', 'notificationx' ), 'name' => 'exit_intent_t2_headline_font_weight', 'type' => 'select', 'default' => '800',
1925 'options' => $this->font_weight_options() ],
1926
1927 // Description
1928 [ 'label' => __( 'Description Color', 'notificationx' ), 'name' => 'exit_intent_t2_desc_color', 'type' => 'colorpicker', 'default' => '#4a4a6a' ],
1929 [ 'label' => __( 'Description Font Size', 'notificationx' ), 'name' => 'exit_intent_t2_desc_font_size', 'type' => 'number', 'default' => 14, 'description' => 'px' ],
1930
1931 // CTA button
1932 [ 'label' => __( 'Button Background', 'notificationx' ), 'name' => 'exit_intent_t2_btn_bg', 'type' => 'colorpicker', 'default' => '#e91e63' ],
1933 [ 'label' => __( 'Button Text Color', 'notificationx' ), 'name' => 'exit_intent_t2_btn_color', 'type' => 'colorpicker', 'default' => '#ffffff' ],
1934 [ 'label' => __( 'Button Border Radius', 'notificationx' ), 'name' => 'exit_intent_t2_btn_border_radius', 'type' => 'number', 'default' => 6, 'description' => 'px' ],
1935 [ 'label' => __( 'Button Font Size', 'notificationx' ), 'name' => 'exit_intent_t2_btn_font_size', 'type' => 'number', 'default' => 14, 'description' => 'px' ],
1936 [ 'label' => __( 'Button Font Weight', 'notificationx' ), 'name' => 'exit_intent_t2_btn_font_weight', 'type' => 'select', 'default' => '700',
1937 'options' => $this->font_weight_options() ],
1938
1939 // Dismiss link
1940 [ 'label' => __( 'Dismiss Text Color', 'notificationx' ), 'name' => 'exit_intent_t2_dismiss_color', 'type' => 'colorpicker', 'default' => '#9a9aa8' ],
1941 [ 'label' => __( 'Dismiss Font Size', 'notificationx' ), 'name' => 'exit_intent_t2_dismiss_font_size', 'type' => 'number', 'default' => 12, 'description' => 'px' ],
1942 ];
1943 }
1944
1945 /** ───────────────────────── Theme Three — Coupon Offer ───────────────────────── */
1946 private function theme_three_design_fields() {
1947 return [
1948 // Container / overlay / close
1949 [ 'label' => __( 'Popup Max Width', 'notificationx' ), 'name' => 'exit_intent_t3_max_width', 'type' => 'number', 'default' => 460, 'description' => 'px' ],
1950 [ 'label' => __( 'Border Radius', 'notificationx' ), 'name' => 'exit_intent_t3_border_radius', 'type' => 'number', 'default' => 16, 'description' => 'px' ],
1951 [ 'label' => __( 'Background Color', 'notificationx' ), 'name' => 'exit_intent_t3_bg_color', 'type' => 'colorpicker', 'default' => '#ffffff' ],
1952 [ 'label' => __( 'Overlay Background Color', 'notificationx' ), 'name' => 'exit_intent_overlay_color', 'type' => 'colorpicker', 'default' => 'rgba(0,0,0,0.5)' ],
1953 [ 'label' => __( 'Close Button Color', 'notificationx' ), 'name' => 'exit_intent_close_color', 'type' => 'colorpicker', 'default' => '#666666' ],
1954 [ 'label' => __( 'Close Button Size', 'notificationx' ), 'name' => 'exit_intent_close_size', 'type' => 'number', 'default' => 20, 'description' => 'px' ],
1955
1956 // Title
1957 [ 'label' => __( 'Title Color', 'notificationx' ), 'name' => 'exit_intent_t3_title_color', 'type' => 'colorpicker', 'default' => '#1a1a2e' ],
1958 [ 'label' => __( 'Title Font Size', 'notificationx' ), 'name' => 'exit_intent_t3_title_font_size', 'type' => 'number', 'default' => 26, 'description' => 'px' ],
1959 [ 'label' => __( 'Title Font Weight', 'notificationx' ), 'name' => 'exit_intent_t3_title_font_weight', 'type' => 'select', 'default' => '700',
1960 'options' => $this->font_weight_options() ],
1961
1962 // Subtitle
1963 [ 'label' => __( 'Subtitle Color', 'notificationx' ), 'name' => 'exit_intent_t3_subtitle_color', 'type' => 'colorpicker', 'default' => '#4a4a6a' ],
1964 [ 'label' => __( 'Subtitle Font Size', 'notificationx' ), 'name' => 'exit_intent_t3_subtitle_font_size', 'type' => 'number', 'default' => 14, 'description' => 'px' ],
1965
1966 // Offer line
1967 [ 'label' => __( 'Offer Color', 'notificationx' ), 'name' => 'exit_intent_t3_offer_color', 'type' => 'colorpicker', 'default' => '#e91e63' ],
1968 [ 'label' => __( 'Offer Font Size', 'notificationx' ), 'name' => 'exit_intent_t3_offer_font_size', 'type' => 'number', 'default' => 18, 'description' => 'px' ],
1969 [ 'label' => __( 'Offer Font Weight', 'notificationx' ), 'name' => 'exit_intent_t3_offer_font_weight', 'type' => 'select', 'default' => '700',
1970 'options' => $this->font_weight_options() ],
1971
1972 // Coupon block
1973 [ 'label' => __( 'Coupon Block Background', 'notificationx' ), 'name' => 'exit_intent_t3_coupon_bg', 'type' => 'colorpicker', 'default' => '#fff7fb' ],
1974 [ 'label' => __( 'Coupon Text Color', 'notificationx' ), 'name' => 'exit_intent_t3_coupon_color', 'type' => 'colorpicker', 'default' => '#1a1a2e' ],
1975 [ 'label' => __( 'Coupon Font Size', 'notificationx' ), 'name' => 'exit_intent_t3_coupon_font_size', 'type' => 'number', 'default' => 14, 'description' => 'px' ],
1976 [ 'label' => __( 'Coupon Block Border Radius', 'notificationx' ), 'name' => 'exit_intent_t3_coupon_border_radius', 'type' => 'number', 'default' => 8, 'description' => 'px' ],
1977
1978 // CTA button
1979 [ 'label' => __( 'Button Background', 'notificationx' ), 'name' => 'exit_intent_t3_btn_bg', 'type' => 'colorpicker', 'default' => '#e91e63' ],
1980 [ 'label' => __( 'Button Text Color', 'notificationx' ), 'name' => 'exit_intent_t3_btn_color', 'type' => 'colorpicker', 'default' => '#ffffff' ],
1981 [ 'label' => __( 'Button Border Radius', 'notificationx' ), 'name' => 'exit_intent_t3_btn_border_radius', 'type' => 'number', 'default' => 6, 'description' => 'px' ],
1982 [ 'label' => __( 'Button Font Size', 'notificationx' ), 'name' => 'exit_intent_t3_btn_font_size', 'type' => 'number', 'default' => 14, 'description' => 'px' ],
1983 [ 'label' => __( 'Button Font Weight', 'notificationx' ), 'name' => 'exit_intent_t3_btn_font_weight', 'type' => 'select', 'default' => '700',
1984 'options' => $this->font_weight_options() ],
1985
1986 // Dismiss link
1987 [ 'label' => __( 'Dismiss Text Color', 'notificationx' ), 'name' => 'exit_intent_t3_dismiss_color', 'type' => 'colorpicker', 'default' => '#9a9aa8' ],
1988 [ 'label' => __( 'Dismiss Font Size', 'notificationx' ), 'name' => 'exit_intent_t3_dismiss_font_size', 'type' => 'number', 'default' => 12, 'description' => 'px' ],
1989 ];
1990 }
1991
1992 /** ───────────────────────── Theme Four — Video Popup ───────────────────────── */
1993 private function theme_four_design_fields() {
1994 return [
1995 // Container / overlay / close
1996 [ 'label' => __( 'Popup Max Width', 'notificationx' ), 'name' => 'exit_intent_t4_max_width', 'type' => 'number', 'default' => 520, 'description' => 'px' ],
1997 [ 'label' => __( 'Border Radius', 'notificationx' ), 'name' => 'exit_intent_t4_border_radius', 'type' => 'number', 'default' => 16, 'description' => 'px' ],
1998 [ 'label' => __( 'Background Color', 'notificationx' ), 'name' => 'exit_intent_t4_bg_color', 'type' => 'colorpicker', 'default' => '#f4ecff' ],
1999 [ 'label' => __( 'Overlay Background Color', 'notificationx' ), 'name' => 'exit_intent_overlay_color', 'type' => 'colorpicker', 'default' => 'rgba(0,0,0,0.5)' ],
2000 [ 'label' => __( 'Close Button Color', 'notificationx' ), 'name' => 'exit_intent_close_color', 'type' => 'colorpicker', 'default' => '#666666' ],
2001 [ 'label' => __( 'Close Button Size', 'notificationx' ), 'name' => 'exit_intent_close_size', 'type' => 'number', 'default' => 20, 'description' => 'px' ],
2002
2003 // Badge
2004 [ 'label' => __( 'Badge Background', 'notificationx' ), 'name' => 'exit_intent_t4_badge_bg', 'type' => 'colorpicker', 'default' => '#ffffff' ],
2005 [ 'label' => __( 'Badge Text Color', 'notificationx' ),'name' => 'exit_intent_t4_badge_color', 'type' => 'colorpicker', 'default' => '#6B21A8' ],
2006 [ 'label' => __( 'Badge Font Size', 'notificationx' ), 'name' => 'exit_intent_t4_badge_font_size', 'type' => 'number', 'default' => 12, 'description' => 'px' ],
2007
2008 // Title
2009 [ 'label' => __( 'Title Color', 'notificationx' ), 'name' => 'exit_intent_t4_title_color', 'type' => 'colorpicker', 'default' => '#1a1a2e' ],
2010 [ 'label' => __( 'Title Font Size', 'notificationx' ), 'name' => 'exit_intent_t4_title_font_size', 'type' => 'number', 'default' => 24, 'description' => 'px' ],
2011 [ 'label' => __( 'Title Font Weight', 'notificationx' ), 'name' => 'exit_intent_t4_title_font_weight', 'type' => 'select', 'default' => '700',
2012 'options' => $this->font_weight_options() ],
2013
2014 // Subtitle
2015 [ 'label' => __( 'Subtitle Color', 'notificationx' ), 'name' => 'exit_intent_t4_subtitle_color', 'type' => 'colorpicker', 'default' => '#4a4a6a' ],
2016 [ 'label' => __( 'Subtitle Font Size', 'notificationx' ), 'name' => 'exit_intent_t4_subtitle_font_size', 'type' => 'number', 'default' => 14, 'description' => 'px' ],
2017
2018 // Video wrap + play icon
2019 [ 'label' => __( 'Video Wrapper Background', 'notificationx' ), 'name' => 'exit_intent_t4_video_bg', 'type' => 'colorpicker', 'default' => '#000000' ],
2020 [ 'label' => __( 'Video Wrapper Border Radius', 'notificationx' ), 'name' => 'exit_intent_t4_video_radius', 'type' => 'number', 'default' => 12, 'description' => 'px' ],
2021 [ 'label' => __( 'Play Icon Background', 'notificationx' ), 'name' => 'exit_intent_t4_play_bg', 'type' => 'colorpicker', 'default' => '#ffffff' ],
2022 [ 'label' => __( 'Play Icon Color', 'notificationx' ), 'name' => 'exit_intent_t4_play_color', 'type' => 'colorpicker', 'default' => '#1a1a2e' ],
2023 ];
2024 }
2025
2026 /** ───────────────────────── Theme Five — Live Flash Sale ───────────────────────── */
2027 private function theme_five_design_fields() {
2028 return [
2029 // Container / overlay / close
2030 [ 'label' => __( 'Popup Max Width', 'notificationx' ), 'name' => 'exit_intent_t5_max_width', 'type' => 'number', 'default' => 900, 'description' => 'px' ],
2031 [ 'label' => __( 'Border Radius', 'notificationx' ), 'name' => 'exit_intent_t5_border_radius', 'type' => 'number', 'default' => 12, 'description' => 'px' ],
2032 [ 'label' => __( 'Left Panel Background', 'notificationx' ), 'name' => 'exit_intent_t5_bg_color', 'type' => 'colorpicker', 'default' => '#ffffff' ],
2033 [ 'label' => __( 'Overlay Background Color', 'notificationx' ), 'name' => 'exit_intent_overlay_color', 'type' => 'colorpicker', 'default' => 'rgba(0,0,0,0.6)' ],
2034 [ 'label' => __( 'Close Button Color', 'notificationx' ), 'name' => 'exit_intent_close_color', 'type' => 'colorpicker', 'default' => '#666666' ],
2035 [ 'label' => __( 'Close Button Size', 'notificationx' ), 'name' => 'exit_intent_close_size', 'type' => 'number', 'default' => 20, 'description' => 'px' ],
2036
2037 // Title
2038 [ 'label' => __( 'Title Color', 'notificationx' ), 'name' => 'exit_intent_t5_title_color', 'type' => 'colorpicker', 'default' => '#1a1a2e' ],
2039 [ 'label' => __( 'Title Font Size', 'notificationx' ), 'name' => 'exit_intent_t5_title_font_size', 'type' => 'number', 'default' => 18, 'description' => 'px' ],
2040 [ 'label' => __( 'Title Font Weight', 'notificationx' ), 'name' => 'exit_intent_t5_title_font_weight', 'type' => 'select', 'default' => '700',
2041 'options' => $this->font_weight_options() ],
2042
2043 // Headline
2044 [ 'label' => __( 'Headline Color', 'notificationx' ), 'name' => 'exit_intent_t5_headline_color', 'type' => 'colorpicker', 'default' => '#1a1a2e' ],
2045 [ 'label' => __( 'Headline Font Size', 'notificationx' ), 'name' => 'exit_intent_t5_headline_font_size', 'type' => 'number', 'default' => 56, 'description' => 'px' ],
2046 [ 'label' => __( 'Headline Font Weight', 'notificationx' ), 'name' => 'exit_intent_t5_headline_font_weight', 'type' => 'select', 'default' => '800',
2047 'options' => $this->font_weight_options() ],
2048
2049 // Description
2050 [ 'label' => __( 'Description Color', 'notificationx' ), 'name' => 'exit_intent_t5_desc_color', 'type' => 'colorpicker', 'default' => '#4a4a6a' ],
2051 [ 'label' => __( 'Description Font Size', 'notificationx' ), 'name' => 'exit_intent_t5_desc_font_size', 'type' => 'number', 'default' => 14, 'description' => 'px' ],
2052
2053 // Countdown label + numbers + unit labels
2054 [ 'label' => __( 'Countdown Label Color', 'notificationx' ), 'name' => 'exit_intent_t5_cd_label_color', 'type' => 'colorpicker', 'default' => '#1a1a2e',
2055 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ) ],
2056 [ 'label' => __( 'Countdown Label Font Size', 'notificationx' ), 'name' => 'exit_intent_t5_cd_label_font_size', 'type' => 'number', 'default' => 12, 'description' => 'px',
2057 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ) ],
2058 [ 'label' => __( 'Countdown Number Background', 'notificationx' ), 'name' => 'exit_intent_t5_cd_num_bg', 'type' => 'colorpicker', 'default' => '#fff0f5',
2059 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ) ],
2060 [ 'label' => __( 'Countdown Number Color', 'notificationx' ), 'name' => 'exit_intent_t5_cd_num_color', 'type' => 'colorpicker', 'default' => '#e91e63',
2061 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ) ],
2062 [ 'label' => __( 'Countdown Number Font Size', 'notificationx' ), 'name' => 'exit_intent_t5_cd_num_font_size', 'type' => 'number', 'default' => 22, 'description' => 'px',
2063 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ) ],
2064 [ 'label' => __( 'Countdown Number Border Radius', 'notificationx' ),'name' => 'exit_intent_t5_cd_num_radius', 'type' => 'number', 'default' => 6, 'description' => 'px',
2065 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ) ],
2066 [ 'label' => __( 'Countdown Unit Label Color', 'notificationx' ), 'name' => 'exit_intent_t5_cd_unit_color', 'type' => 'colorpicker', 'default' => '#4a4a6a',
2067 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ) ],
2068 [ 'label' => __( 'Countdown Unit Label Font Size', 'notificationx' ),'name' => 'exit_intent_t5_cd_unit_font_size', 'type' => 'number', 'default' => 11, 'description' => 'px',
2069 'rules' => Rules::is( 'exit_intent_t5_show_timer', true ) ],
2070
2071 // CTA button
2072 [ 'label' => __( 'Button Background', 'notificationx' ), 'name' => 'exit_intent_t5_btn_bg', 'type' => 'colorpicker', 'default' => '#e91e63' ],
2073 [ 'label' => __( 'Button Text Color', 'notificationx' ), 'name' => 'exit_intent_t5_btn_color', 'type' => 'colorpicker', 'default' => '#ffffff' ],
2074 [ 'label' => __( 'Button Border Radius', 'notificationx' ), 'name' => 'exit_intent_t5_btn_border_radius', 'type' => 'number', 'default' => 6, 'description' => 'px' ],
2075 [ 'label' => __( 'Button Font Size', 'notificationx' ), 'name' => 'exit_intent_t5_btn_font_size', 'type' => 'number', 'default' => 14, 'description' => 'px' ],
2076 [ 'label' => __( 'Button Font Weight', 'notificationx' ), 'name' => 'exit_intent_t5_btn_font_weight', 'type' => 'select', 'default' => '700',
2077 'options' => $this->font_weight_options() ],
2078
2079 // Dismiss link
2080 [ 'label' => __( 'Dismiss Text Color', 'notificationx' ), 'name' => 'exit_intent_t5_dismiss_color', 'type' => 'colorpicker', 'default' => '#9a9aa8' ],
2081 [ 'label' => __( 'Dismiss Font Size', 'notificationx' ), 'name' => 'exit_intent_t5_dismiss_font_size', 'type' => 'number', 'default' => 12, 'description' => 'px' ],
2082 ];
2083 }
2084
2085 /** ───────────────────────── Theme Six — Product Countdown ───────────────────────── */
2086 private function theme_six_design_fields() {
2087 return [
2088 // Container / overlay / close
2089 [ 'label' => __( 'Popup Max Width', 'notificationx' ), 'name' => 'exit_intent_t6_max_width', 'type' => 'number', 'default' => 600, 'description' => 'px' ],
2090 [ 'label' => __( 'Border Radius', 'notificationx' ), 'name' => 'exit_intent_t6_border_radius', 'type' => 'number', 'default' => 12, 'description' => 'px' ],
2091 [ 'label' => __( 'Background Start Color', 'notificationx' ), 'name' => 'exit_intent_t6_bg_start', 'type' => 'colorpicker', 'default' => '#ffffff',
2092 'help' => __( 'Center color of the radial background gradient.', 'notificationx' ) ],
2093 [ 'label' => __( 'Background Mid Color', 'notificationx' ), 'name' => 'exit_intent_t6_bg_mid', 'type' => 'colorpicker', 'default' => '#fdf2f8' ],
2094 [ 'label' => __( 'Background End Color', 'notificationx' ), 'name' => 'exit_intent_t6_bg_end', 'type' => 'colorpicker', 'default' => '#f5f3ff',
2095 'help' => __( 'Outer color of the radial background gradient.', 'notificationx' ) ],
2096 [ 'label' => __( 'Overlay Background Color', 'notificationx' ), 'name' => 'exit_intent_overlay_color', 'type' => 'colorpicker', 'default' => 'rgba(0,0,0,0.5)' ],
2097 [ 'label' => __( 'Close Button Color', 'notificationx' ), 'name' => 'exit_intent_close_color', 'type' => 'colorpicker', 'default' => '#1f2937' ],
2098 [ 'label' => __( 'Close Button Size', 'notificationx' ), 'name' => 'exit_intent_close_size', 'type' => 'number', 'default' => 20, 'description' => 'px' ],
2099
2100 // Title
2101 [ 'label' => __( 'Title Color', 'notificationx' ), 'name' => 'exit_intent_t6_title_color', 'type' => 'colorpicker', 'default' => '#1f2937' ],
2102 [ 'label' => __( 'Title Font Size', 'notificationx' ), 'name' => 'exit_intent_t6_title_font_size', 'type' => 'number', 'default' => 36, 'description' => 'px' ],
2103 [ 'label' => __( 'Title Font Weight', 'notificationx' ), 'name' => 'exit_intent_t6_title_font_weight', 'type' => 'select', 'default' => '700',
2104 'options' => $this->font_weight_options() ],
2105
2106 // Countdown label + numbers + unit labels
2107 [ 'label' => __( 'Countdown Label Color', 'notificationx' ), 'name' => 'exit_intent_t6_cd_label_color', 'type' => 'colorpicker', 'default' => '#4b5563',
2108 'rules' => Rules::is( 'exit_intent_t6_show_timer', true ) ],
2109 [ 'label' => __( 'Countdown Label Font Size', 'notificationx' ), 'name' => 'exit_intent_t6_cd_label_font_size', 'type' => 'number', 'default' => 18, 'description' => 'px',
2110 'rules' => Rules::is( 'exit_intent_t6_show_timer', true ) ],
2111 [ 'label' => __( 'Countdown Number Background', 'notificationx' ), 'name' => 'exit_intent_t6_cd_num_bg', 'type' => 'colorpicker', 'default' => '#f3e8f2',
2112 'rules' => Rules::is( 'exit_intent_t6_show_timer', true ) ],
2113 [ 'label' => __( 'Countdown Number Color', 'notificationx' ), 'name' => 'exit_intent_t6_cd_num_color', 'type' => 'colorpicker', 'default' => '#374151',
2114 'rules' => Rules::is( 'exit_intent_t6_show_timer', true ) ],
2115 [ 'label' => __( 'Countdown Number Font Size', 'notificationx' ), 'name' => 'exit_intent_t6_cd_num_font_size', 'type' => 'number', 'default' => 24, 'description' => 'px',
2116 'rules' => Rules::is( 'exit_intent_t6_show_timer', true ) ],
2117 [ 'label' => __( 'Countdown Number Border Radius', 'notificationx' ),'name' => 'exit_intent_t6_cd_num_radius', 'type' => 'number', 'default' => 2, 'description' => 'px',
2118 'rules' => Rules::is( 'exit_intent_t6_show_timer', true ) ],
2119 [ 'label' => __( 'Countdown Unit Label Color', 'notificationx' ), 'name' => 'exit_intent_t6_cd_unit_color', 'type' => 'colorpicker', 'default' => '#9f1239',
2120 'rules' => Rules::is( 'exit_intent_t6_show_timer', true ) ],
2121 [ 'label' => __( 'Countdown Unit Label Font Size', 'notificationx' ),'name' => 'exit_intent_t6_cd_unit_font_size', 'type' => 'number', 'default' => 12, 'description' => 'px',
2122 'rules' => Rules::is( 'exit_intent_t6_show_timer', true ) ],
2123
2124 // CTA button
2125 [ 'label' => __( 'Button Background', 'notificationx' ), 'name' => 'exit_intent_t6_btn_bg', 'type' => 'colorpicker', 'default' => '#845e7c' ],
2126 [ 'label' => __( 'Button Text Color', 'notificationx' ), 'name' => 'exit_intent_t6_btn_color', 'type' => 'colorpicker', 'default' => '#ffffff' ],
2127 [ 'label' => __( 'Button Border Radius', 'notificationx' ), 'name' => 'exit_intent_t6_btn_border_radius', 'type' => 'number', 'default' => 4, 'description' => 'px' ],
2128 [ 'label' => __( 'Button Font Size', 'notificationx' ), 'name' => 'exit_intent_t6_btn_font_size', 'type' => 'number', 'default' => 24, 'description' => 'px' ],
2129 [ 'label' => __( 'Button Font Weight', 'notificationx' ), 'name' => 'exit_intent_t6_btn_font_weight', 'type' => 'select', 'default' => '700',
2130 'options' => $this->font_weight_options() ],
2131 ];
2132 }
2133
2134 /** ───────────────────────── Theme Seven — Lead Capture w/ Image ───────────────────────── */
2135 private function theme_seven_design_fields() {
2136 $font_family_options = GlobalFields::get_instance()->normalize_fields( [
2137 'inherit' => __( 'Default (inherit)', 'notificationx' ),
2138 "'Playfair Display', Georgia, serif" => __( 'Playfair Display (serif)', 'notificationx' ),
2139 "Georgia, 'Times New Roman', serif" => __( 'Georgia (serif)', 'notificationx' ),
2140 "'Times New Roman', Times, serif" => __( 'Times New Roman (serif)', 'notificationx' ),
2141 "Inter, 'Helvetica Neue', Arial, sans-serif" => __( 'Inter (sans-serif)', 'notificationx' ),
2142 "'Helvetica Neue', Helvetica, Arial, sans-serif" => __( 'Helvetica (sans-serif)', 'notificationx' ),
2143 ] );
2144
2145 return [
2146 // Container / overlay / close
2147 [ 'label' => __( 'Popup Max Width', 'notificationx' ), 'name' => 'exit_intent_t7_max_width', 'type' => 'number', 'default' => 750, 'description' => 'px' ],
2148 [ 'label' => __( 'Border Radius', 'notificationx' ), 'name' => 'exit_intent_t7_border_radius', 'type' => 'number', 'default' => 12, 'description' => 'px' ],
2149 [ 'label' => __( 'Background Color', 'notificationx' ), 'name' => 'exit_intent_t7_bg_color', 'type' => 'colorpicker', 'default' => '#413532',
2150 'help' => __( 'Right (content) panel background.', 'notificationx' ) ],
2151 [ 'label' => __( 'Image Panel Background', 'notificationx' ), 'name' => 'exit_intent_t7_image_bg', 'type' => 'colorpicker', 'default' => '#534542',
2152 'help' => __( 'Shown behind the image (visible only if the image leaves transparent areas or fails to load).', 'notificationx' ) ],
2153 [ 'label' => __( 'Overlay Background Color', 'notificationx' ), 'name' => 'exit_intent_overlay_color', 'type' => 'colorpicker', 'default' => 'rgba(0,0,0,0.5)' ],
2154 [ 'label' => __( 'Close Button Color', 'notificationx' ), 'name' => 'exit_intent_close_color', 'type' => 'colorpicker', 'default' => '#f3d5a2' ],
2155 [ 'label' => __( 'Close Button Size', 'notificationx' ), 'name' => 'exit_intent_close_size', 'type' => 'number', 'default' => 22, 'description' => 'px' ],
2156
2157 // Headline
2158 [ 'label' => __( 'Headline Color', 'notificationx' ), 'name' => 'exit_intent_t7_headline_color', 'type' => 'colorpicker', 'default' => '#f3d5a2' ],
2159 [ 'label' => __( 'Headline Font Size', 'notificationx' ), 'name' => 'exit_intent_t7_headline_font_size', 'type' => 'number', 'default' => 30, 'description' => 'px' ],
2160 [ 'label' => __( 'Headline Font Weight', 'notificationx' ), 'name' => 'exit_intent_t7_headline_font_weight', 'type' => 'select', 'default' => '700',
2161 'options' => $this->font_weight_options() ],
2162 [ 'label' => __( 'Headline Font Family', 'notificationx' ), 'name' => 'exit_intent_t7_headline_font_family', 'type' => 'select', 'default' => "'Playfair Display', Georgia, serif",
2163 'options' => $font_family_options ],
2164
2165 // Discount banner
2166 [ 'label' => __( 'Discount Banner Background', 'notificationx' ), 'name' => 'exit_intent_t7_discount_bg', 'type' => 'colorpicker', 'default' => 'rgba(255,255,255,0.1)' ],
2167 [ 'label' => __( 'Discount Banner Border Color', 'notificationx' ), 'name' => 'exit_intent_t7_discount_border', 'type' => 'colorpicker', 'default' => 'rgba(255,255,255,0.05)' ],
2168 [ 'label' => __( 'Discount Banner Text Color', 'notificationx' ), 'name' => 'exit_intent_t7_discount_color', 'type' => 'colorpicker', 'default' => '#f3d5a2' ],
2169 [ 'label' => __( 'Discount Banner Font Size', 'notificationx' ), 'name' => 'exit_intent_t7_discount_font_size', 'type' => 'number', 'default' => 16, 'description' => 'px' ],
2170 [ 'label' => __( 'Discount Banner Border Radius', 'notificationx' ), 'name' => 'exit_intent_t7_discount_radius', 'type' => 'number', 'default' => 2, 'description' => 'px' ],
2171
2172 // Description
2173 [ 'label' => __( 'Description Color', 'notificationx' ), 'name' => 'exit_intent_t7_desc_color', 'type' => 'colorpicker', 'default' => 'rgba(243,213,162,0.9)' ],
2174 [ 'label' => __( 'Description Font Size', 'notificationx' ), 'name' => 'exit_intent_t7_desc_font_size', 'type' => 'number', 'default' => 16, 'description' => 'px' ],
2175
2176 // Email input
2177 [ 'label' => __( 'Input Background Color', 'notificationx' ), 'name' => 'exit_intent_t7_input_bg', 'type' => 'colorpicker', 'default' => '#ffffff' ],
2178 [ 'label' => __( 'Input Border Color', 'notificationx' ), 'name' => 'exit_intent_t7_input_border_color', 'type' => 'colorpicker', 'default' => '#6b7280' ],
2179 [ 'label' => __( 'Input Border Radius', 'notificationx' ), 'name' => 'exit_intent_t7_input_border_radius','type' => 'number', 'default' => 0, 'description' => 'px' ],
2180 [ 'label' => __( 'Input Text Color', 'notificationx' ), 'name' => 'exit_intent_t7_input_text_color', 'type' => 'colorpicker', 'default' => '#1f2937' ],
2181
2182 // CTA button
2183 [ 'label' => __( 'Button Background', 'notificationx' ), 'name' => 'exit_intent_t7_btn_bg', 'type' => 'colorpicker', 'default' => '#f3d5a2' ],
2184 [ 'label' => __( 'Button Text Color', 'notificationx' ), 'name' => 'exit_intent_t7_btn_color', 'type' => 'colorpicker', 'default' => '#4d3e3e' ],
2185 [ 'label' => __( 'Button Border Radius', 'notificationx' ), 'name' => 'exit_intent_t7_btn_border_radius', 'type' => 'number', 'default' => 0, 'description' => 'px' ],
2186 [ 'label' => __( 'Button Font Size', 'notificationx' ), 'name' => 'exit_intent_t7_btn_font_size', 'type' => 'number', 'default' => 14, 'description' => 'px' ],
2187 [ 'label' => __( 'Button Font Weight', 'notificationx' ), 'name' => 'exit_intent_t7_btn_font_weight', 'type' => 'select', 'default' => '700',
2188 'options' => $this->font_weight_options() ],
2189 ];
2190 }
2191
2192 public function customize_fields( $fields ) {
2193 // Hide standard timing/behaviour irrelevant to exit intent
2194 foreach ( [ 'timing', 'behaviour', 'sound_section', 'queue_management', 'appearance', 'animation' ] as $key ) {
2195 if ( isset( $fields[ $key ] ) ) {
2196 $fields[ $key ] = Rules::is( 'source', $this->id, true, $fields[ $key ] );
2197 }
2198 }
2199
2200 // Add center position option
2201 if ( isset( $fields['appearance']['fields']['position']['options'] ) ) {
2202 $fields['appearance']['fields']['position']['options']['center'] = [
2203 'label' => __( 'Center', 'notificationx' ),
2204 'value' => 'center',
2205 'rules' => Rules::is( 'source', $this->id ),
2206 ];
2207 }
2208
2209 // NOTE: keep this key unique. The Announcement extension (PopupNotification)
2210 // also registers a section literally named `exit_intent_settings` for its
2211 // "Convert to Exit Intent" feature; sharing the key here let Popup's filter
2212 // (same `nx_customize_fields` priority, registered later) overwrite this
2213 // section with a `source == popup_notification` rule, hiding it for the
2214 // Exit Intent type and leaving the whole Customize tab blank.
2215 $fields['exit_intent_popup_settings'] = [
2216 'label' => __( 'Exit Intent Settings', 'notificationx' ),
2217 'name' => 'exit_intent_popup_settings',
2218 'type' => 'section',
2219 'priority' => 15,
2220 'rules' => Rules::is( 'source', $this->id ),
2221 'fields' => [
2222 'show_close_button' => [
2223 'label' => __( 'Show Close Button', 'notificationx' ),
2224 'name' => 'show_close_button',
2225 'type' => 'toggle',
2226 'default' => true,
2227 ],
2228 'exit_intent_position' => [
2229 'label' => __( 'Position', 'notificationx' ),
2230 'name' => 'exit_intent_position',
2231 'type' => 'select',
2232 'default' => 'center',
2233 'options' => GlobalFields::get_instance()->normalize_fields( [
2234 'center' => __( 'Center', 'notificationx' ),
2235 'bottom-left' => __( 'Bottom Left', 'notificationx' ),
2236 'bottom-right' => __( 'Bottom Right', 'notificationx' ),
2237 ] ),
2238 ],
2239 'exit_intent_sensitivity' => [
2240 'label' => __( 'Trigger Sensitivity', 'notificationx' ),
2241 'name' => 'exit_intent_sensitivity',
2242 'type' => 'select',
2243 'default' => '20',
2244 'help' => __( 'Distance from top of viewport (px) that triggers the popup.', 'notificationx' ),
2245 'options' => GlobalFields::get_instance()->normalize_fields( [
2246 '10' => __( 'High (10px)', 'notificationx' ),
2247 '20' => __( 'Medium (20px)', 'notificationx' ),
2248 '50' => __( 'Low (50px)', 'notificationx' ),
2249 ] ),
2250 ],
2251 'exit_intent_cookie_days' => [
2252 'label' => __( 'Do Not Show Again For', 'notificationx' ),
2253 'name' => 'exit_intent_cookie_days',
2254 'type' => 'number',
2255 'default' => 7,
2256 'description' => __( 'days', 'notificationx' ),
2257 'help' => __( 'Once dismissed, hide the popup for this many days.', 'notificationx' ),
2258 ],
2259 'exit_intent_mobile_disable' => [
2260 'label' => __( 'Disable on Mobile', 'notificationx' ),
2261 'name' => 'exit_intent_mobile_disable',
2262 'type' => 'toggle',
2263 'default' => true,
2264 'help' => __( 'Exit intent detection is unreliable on touch devices.', 'notificationx' ),
2265 ],
2266 ],
2267 ];
2268
2269 return $fields;
2270 }
2271
2272 public function doc() {
2273 return sprintf(__('
2274 <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>',
2275 'notificationx'),
2276 'https://notificationx.com/docs/how-to-configure-exit-intent-popup/',
2277 );
2278 }
2279 }
2280