title = __('Announcement', 'notificationx'); $this->module_title = __('Announcement', 'notificationx'); $this->themes = [ 'theme-one' => [ 'source' => NOTIFICATIONX_ADMIN_URL . 'images/extensions/themes/popup/popup-theme-one.png', 'defaults' => [ 'popup_title' => __('Want to build credibility & boost sales?', 'notificationx'), 'popup_content' => __('We help you optimize conversions & drive sales', 'notificationx'), 'popup_button_text' => __('Get Started with Free Plan', 'notificationx'), 'position' => 'center', ], 'column' => "5", ], 'theme-two' => [ 'source' => NOTIFICATIONX_ADMIN_URL . 'images/extensions/themes/popup/popup-theme-two.png', 'defaults' => [ 'popup_title' => __('Boost your sales using SureCart', 'notificationx'), 'popup_content' => __('', 'notificationx'), 'popup_button_text' => __('See How', 'notificationx'), 'position' => 'center', ], 'column' => "5", ], 'theme-four' => [ 'source' => NOTIFICATIONX_ADMIN_URL . 'images/extensions/themes/popup/popup-theme-four.webp', 'defaults' => [ 'popup_title' => __('Need Help?', 'notificationx'), 'popup_content' => __('Get the latest news and updates delivered to your inbox.', 'notificationx'), 'popup_button_text' => __('Submit', 'notificationx'), 'position' => 'center', ], 'column' => "5", ], 'theme-five' => [ 'source' => NOTIFICATIONX_ADMIN_URL . 'images/extensions/themes/popup/popup-theme-five.webp', 'defaults' => [ 'popup_title' => __('Need Help?', 'notificationx'), 'popup_content' => __('Subscribe to receive exclusive offers and updates directly in your inbox.', 'notificationx'), 'popup_email_placeholder' => __('Enter your email address', 'notificationx'), 'popup_button_text' => __('Submit', 'notificationx'), 'position' => 'center', ], 'is_pro' => true, 'column' => "5", ], 'theme-seven' => [ 'source' => NOTIFICATIONX_ADMIN_URL . 'images/extensions/themes/popup/popup-theme-seven.webp', 'defaults' => [ 'popup_title' => __('Want latest updates?', 'notificationx'), 'popup_subtitle' => __('Would like to get the lastes news & updates instantly?', 'notificationx'), 'popup_email_placeholder' => __('Enter email address', 'notificationx'), 'popup_button_text' => __('Get In Touch', 'notificationx'), 'popup_icon' => 'mail_icon.svg', 'popup_button_icon' => 'mail_icon.svg', 'position' => 'center', ], 'is_pro' => true, 'column' => "5", ], 'theme-six' => [ 'source' => NOTIFICATIONX_ADMIN_URL . 'images/extensions/themes/popup/popup-theme-six.webp', 'defaults' => [ 'popup_title' => __('Get latest news & updates', 'notificationx'), 'popup_email_placeholder' => __('Your email address', 'notificationx'), 'popup_button_text' => __('Submit Now', 'notificationx'), 'position' => 'center', ], 'is_pro' => true, 'column' => "5", ], 'theme-three' => [ 'source' => NOTIFICATIONX_ADMIN_URL . 'images/extensions/themes/popup/popup-theme-three.png', 'defaults' => [ 'popup_title' => __('All Offers', 'notificationx'), 'popup_button_text' => __('Latest Offers', 'notificationx'), 'popup_button_icon' => 'latest_offer.svg', 'position' => 'center', ], 'column' => "5", ], // Coupon Popup card (light) — headline + description + copyable // coupon code + "Get Coupon" CTA + dismiss link. 'theme-eight' => [ 'source' => NOTIFICATIONX_ADMIN_URL . 'images/extensions/themes/popup/popup-theme-eight.png', 'defaults' => [ 'popup_title' => __('35% OFF NOW', 'notificationx'), 'popup_content' => __('Get an extra 35% off on all products!', 'notificationx'), 'popup_coupon_code' => __('GET35OFF', 'notificationx'), 'popup_button_text' => __('Get Coupon', 'notificationx'), 'popup_button_url' => '#', 'position' => 'center', ], 'column' => "5", ], // Festive/seasonal coupon popup — doodle-textured colored header // with a wavy divider, big discount headline, an eyebrow tagline, // a headline + copyable coupon code + soft dismiss link (no CTA). 'theme-eleven' => [ 'source' => NOTIFICATIONX_ADMIN_URL . 'images/extensions/themes/popup/popup-theme-eleven.png?v=2', 'defaults' => [ 'popup_subtitle' => __('Back to School Deal', 'notificationx'), 'popup_title' => __('25% OFF!', 'notificationx'), 'popup_content' => __('Get a ready-to-go healthy lunchbox kit', 'notificationx'), 'popup_coupon_code' => __('BTS2025', 'notificationx'), 'position' => 'center', ], 'column' => "5", ], // High-impact electronics flash-sale coupon popup — bold yellow // card, a rotated "%OFF" sticker badge (subtitle = the big number), // headline + subtext + copyable coupon code (no CTA / dismiss). 'theme-twelve' => [ 'source' => NOTIFICATIONX_ADMIN_URL . 'images/extensions/themes/popup/popup-theme-twelve.png', 'defaults' => [ 'popup_subtitle' => __('64%', 'notificationx'), 'popup_title' => __('Enjoy 64% Electronics Sale', 'notificationx'), 'popup_content' => __('Upgrade your gadgets at unbeatable prices.', 'notificationx'), 'popup_coupon_code' => __('ELEC 4512658', 'notificationx'), 'position' => 'center', ], 'column' => "5", ], // Multi-tier discount popup — gift hero, two-tone heading, a list of // coupon "tickets" (percent + code + validity) and a "Claim Now" CTA. 'theme-thirteen' => [ 'source' => NOTIFICATIONX_ADMIN_URL . 'images/extensions/themes/popup/popup-theme-thirteen.png', 'defaults' => [ 'popup_title' => __('Buy Upto $500', 'notificationx'), 'popup_subtitle' => __('And Get Discount Now', 'notificationx'), 'popup_content' => __('Take discount in your next order', 'notificationx'), 'popup_button_text' => __('Claim Now', 'notificationx'), 'popup_button_url' => '#', 'popup_coupon_repeater' => [ [ 'coupon_percent' => __('20%', 'notificationx'), 'coupon_code' => __('#SAVE20', 'notificationx'), 'coupon_validity' => __('Valid for 7 Days', 'notificationx'), ], ], 'position' => 'center', ], 'column' => "5", ], ]; } public function init_fields() { parent::init_fields(); add_filter('nx_design_tab_fields', [$this, 'design_fields'], 99); add_filter('nx_content_fields', [$this, 'content_fields'], 999); add_filter('nx_customize_fields', [$this, 'customize_fields'], 999); add_filter('nx_display_fields', [$this, 'display_fields'], 999); } public function display_fields($fields) { // Hide image selection if (isset($fields['image-section'])) { $fields['image-section'] = Rules::is('source', $this->id, true, $fields['image-section']); } return $fields; } public function design_fields( $fields ) { if (isset($fields['advance_design_section']['fields']['design'])) { $fields['advance_design_section']['fields']['design'] = Rules::is('source', $this->id, true, $fields['advance_design_section']['fields']['design']); } if (isset($fields['advance_design_section']['fields']['typography'])) { $fields['advance_design_section']['fields']['typography'] = Rules::is('source', $this->id, true, $fields['advance_design_section']['fields']['typography']); } if (isset($fields['advance_design_section']['fields']['image-appearance'])) { $fields['advance_design_section']['fields']['image-appearance'] = Rules::is('source', $this->id, true, $fields['advance_design_section']['fields']['image-appearance']); } if (isset($fields['advance_design_section']['fields']['link_button_design'])) { $fields['advance_design_section']['fields']['link_button_design'] = Rules::is('source', $this->id, true, $fields['advance_design_section']['fields']['link_button_design']); } // Popup Container Design Section $fields['advance_design_section']['fields']['popup_design'] = [ 'label' => __("Popup Design", 'notificationx'), 'name' => "popup_design", 'type' => "section", 'priority' => 5, 'rules' => Rules::logicalRule([ Rules::is('source', $this->id, false), Rules::is('advance_edit', true), ]), 'fields' => [ [ 'label' => __("Background Color", 'notificationx'), 'name' => "popup_bg_color", 'type' => "colorpicker", ], [ 'label' => __("Overlay Background Color", 'notificationx'), 'name' => "overlay_color", 'type' => "colorpicker", 'help' => __('Background color of the overlay behind the popup', 'notificationx'), ], [ 'label' => __('Popup Width', 'notificationx'), 'name' => "popup_width", 'type' => "number", 'description' => 'px', 'help' => __('Maximum width of the popup container', 'notificationx'), ], [ 'label' => __('Border Radius', 'notificationx'), 'name' => "popup_border_radius", 'type' => "number", 'description' => 'px', 'help' => __('Rounded corners for the popup container', 'notificationx'), ], [ 'label' => __('Popup Padding', 'notificationx'), 'name' => "popup_padding", 'type' => "text", 'help' => __('Internal spacing of popup content (e.g., 30px or 20px 30px)', 'notificationx'), ], [ 'label' => __("Close Button Color", 'notificationx'), 'name' => "close_btn_color", 'type' => "colorpicker", ], [ 'label' => __('Close Button Size', 'notificationx'), 'name' => "close_btn_size", 'type' => "number", 'description' => 'px', ], ] ]; // Typography Section $fields['advance_design_section']['fields']['popup_typography'] = [ 'label' => __("Typography", 'notificationx'), 'name' => "popup_typography", 'type' => "section", 'priority' => 6, 'rules' => Rules::logicalRule([ Rules::is('source', $this->id, false), Rules::is('advance_edit', true), ]), 'fields' => [ [ 'label' => __("Title Color", 'notificationx'), 'name' => "popup_title_color", 'type' => "colorpicker", ], [ 'label' => __('Title Font Size', 'notificationx'), 'name' => "popup_title_font_size", 'type' => "number", 'description' => 'px', 'help' => __('Font size for the popup title', 'notificationx'), ], [ 'label' => __('Title Font Weight', 'notificationx'), 'name' => "popup_title_font_weight", 'type' => "select", 'options' => GlobalFields::get_instance()->normalize_fields([ '300' => __('Light (300)', 'notificationx'), '400' => __('Normal (400)', 'notificationx'), '500' => __('Medium (500)', 'notificationx'), '600' => __('Semi Bold (600)', 'notificationx'), '700' => __('Bold (700)', 'notificationx'), '800' => __('Extra Bold (800)', 'notificationx'), ]), ], [ 'label' => __("Subtitle Color", 'notificationx'), 'name' => "popup_subtitle_color", 'type' => "colorpicker", 'rules' => Rules::is('themes', 'popup_notification_theme-seven'), ], [ 'label' => __('Subtitle Font Size', 'notificationx'), 'name' => "popup_subtitle_font_size", 'type' => "number", 'description' => 'px', 'help' => __('Font size for the popup subtitle', 'notificationx'), 'rules' => Rules::is('themes', 'popup_notification_theme-seven'), ], [ 'label' => __("Content/Message Color", 'notificationx'), 'name' => "popup_content_color", 'type' => "colorpicker", 'rules' => Rules::logicalRule([ Rules::is('themes', 'popup_notification_theme-one'), Rules::is('themes', 'popup_notification_theme-two'), Rules::is('themes', 'popup_notification_theme-three'), Rules::is('themes', 'popup_notification_theme-four'), Rules::is('themes', 'popup_notification_theme-five'), ], 'or'), ], [ 'label' => __('Content/Message Font Size', 'notificationx'), 'name' => "popup_content_font_size", 'type' => "number", 'description' => 'px', 'help' => __('Font size for the popup content/message text', 'notificationx'), 'rules' => Rules::logicalRule([ Rules::is('themes', 'popup_notification_theme-one'), Rules::is('themes', 'popup_notification_theme-two'), Rules::is('themes', 'popup_notification_theme-three'), Rules::is('themes', 'popup_notification_theme-four'), Rules::is('themes', 'popup_notification_theme-five'), ], 'or'), ], ] ]; // Button Design Section $fields['advance_design_section']['fields']['popup_button_design'] = [ 'label' => __("Button Design", 'notificationx'), 'name' => "popup_button_design", 'type' => "section", 'priority' => 7, 'rules' => Rules::logicalRule([ Rules::is('source', $this->id, false), Rules::is('advance_edit', true), ]), 'fields' => [ [ 'label' => __("Background Color", 'notificationx'), 'name' => "popup_button_bg_color", 'type' => "colorpicker", ], [ 'label' => __("Hover Background Color", 'notificationx'), 'name' => "popup_button_hover_bg_color", 'type' => "colorpicker", 'help' => __('Background color when button is hovered', 'notificationx'), ], [ 'label' => __("Text Color", 'notificationx'), 'name' => "popup_button_text_color", 'type' => "colorpicker", ], [ 'label' => __("Hover Text Color", 'notificationx'), 'name' => "popup_button_hover_text_color", 'type' => "colorpicker", 'help' => __('Text color when button is hovered', 'notificationx'), ], [ 'label' => __("Border Color", 'notificationx'), 'name' => "popup_button_border_color", 'type' => "colorpicker", ], [ 'label' => __("Hover Border Color", 'notificationx'), 'name' => "popup_button_border_hover_color", 'type' => "colorpicker", ], [ 'label' => __('Border Width', 'notificationx'), 'name' => "popup_button_border_width", 'type' => "number", 'description' => 'px', 'help' => __('Width of the button border', 'notificationx'), ], [ 'label' => __('Font Size', 'notificationx'), 'name' => "popup_button_font_size", 'type' => "number", 'description' => 'px', ], [ 'label' => __('Font Weight', 'notificationx'), 'name' => "popup_button_font_weight", 'type' => "select", 'options' => GlobalFields::get_instance()->normalize_fields([ '300' => __('Light (300)', 'notificationx'), '400' => __('Normal (400)', 'notificationx'), '500' => __('Medium (500)', 'notificationx'), '600' => __('Semi Bold (600)', 'notificationx'), '700' => __('Bold (700)', 'notificationx'), ]), ], [ 'label' => __('Border Radius', 'notificationx'), 'name' => "popup_button_border_radius", 'type' => "number", 'description' => 'px', 'help' => __('Rounded corners for the button', 'notificationx'), ], [ 'label' => __('Padding', 'notificationx'), 'name' => "popup_button_padding", 'type' => "text", 'help' => __('Button spacing in CSS format (e.g., 12px 24px)', 'notificationx'), ], [ 'label' => __('Button Width', 'notificationx'), 'name' => "popup_button_width", 'type' => "select", 'default' => 'auto', 'options' => GlobalFields::get_instance()->normalize_fields([ 'auto' => __('Auto Width', 'notificationx'), '100%' => __('Full Width', 'notificationx'), 'custom' => __('Custom Width', 'notificationx'), ]), ], [ 'label' => __('Custom Button Width', 'notificationx'), 'name' => "popup_button_custom_width", 'type' => "number", 'description' => 'px', 'rules' => Rules::is('popup_button_width', 'custom'), ], ] ]; // Email Input Design Section (for email collection themes) $fields['advance_design_section']['fields']['popup_email_design'] = [ 'label' => __("Email Input Design", 'notificationx'), 'name' => "popup_email_design", 'type' => "section", 'priority' => 8, 'rules' => Rules::logicalRule([ Rules::is('source', $this->id, false), Rules::is('advance_edit', true), Rules::logicalRule([ Rules::is('themes', 'popup_notification_theme-five'), Rules::is('themes', 'popup_notification_theme-six'), Rules::is('themes', 'popup_notification_theme-seven'), ], 'or'), ]), 'fields' => [ [ 'label' => __("Input Background Color", 'notificationx'), 'name' => "popup_email_bg_color", 'type' => "colorpicker", ], [ 'label' => __("Input Text Color", 'notificationx'), 'name' => "popup_email_text_color", 'type' => "colorpicker", ], [ 'label' => __("Input Border Color", 'notificationx'), 'name' => "popup_email_border_color", 'type' => "colorpicker", ], [ 'label' => __("Input Focus Border Color", 'notificationx'), 'name' => "popup_email_focus_border_color", 'type' => "colorpicker", 'help' => __('Border color when input is focused', 'notificationx'), ], [ 'label' => __("Placeholder Text Color", 'notificationx'), 'name' => "popup_email_placeholder_color", 'type' => "colorpicker", ], [ 'label' => __('Input Font Size', 'notificationx'), 'name' => "popup_email_font_size", 'type' => "number", 'description' => 'px', ], [ 'label' => __('Input Border Width', 'notificationx'), 'name' => "popup_email_border_width", 'type' => "number", 'description' => 'px', ], [ 'label' => __('Input Border Radius', 'notificationx'), 'name' => "popup_email_border_radius", 'type' => "number", 'description' => 'px', ], [ 'label' => __('Input Padding', 'notificationx'), 'name' => "popup_email_padding", 'type' => "text", 'help' => __('Input field spacing in CSS format (e.g., 12px 16px)', 'notificationx'), ], [ 'label' => __('Input Height', 'notificationx'), 'name' => "popup_email_height", 'type' => "number", 'description' => 'px', 'help' => __('Height of the email input field', 'notificationx'), ], ] ]; // Repeater Items Design Section (for theme-three only) $fields['advance_design_section']['fields']['popup_repeater_design'] = [ 'label' => __("Content Items Design", 'notificationx'), 'name' => "popup_repeater_design", 'type' => "section", 'priority' => 9, 'rules' => Rules::logicalRule([ Rules::is('source', $this->id, false), Rules::is('advance_edit', true), Rules::is('themes', 'popup_notification_theme-three'), ]), 'fields' => [ [ 'label' => __("Item Background Color", 'notificationx'), 'name' => "popup_repeater_item_bg_color", 'type' => "colorpicker", 'help' => __('Background color for each content item', 'notificationx'), ], [ 'label' => __("Highlight Text Color", 'notificationx'), 'name' => "popup_repeater_highlight_color", 'type' => "colorpicker", 'help' => __('Color for the highlight text (e.g., "30% OFF")', 'notificationx'), ], [ 'label' => __("Item Title Color", 'notificationx'), 'name' => "popup_repeater_title_color", 'type' => "colorpicker", ], [ 'label' => __('Item Title Font Size', 'notificationx'), 'name' => "popup_repeater_title_font_size", 'type' => "number", 'description' => 'px', ], [ 'label' => __('Item Title Font Weight', 'notificationx'), 'name' => "popup_repeater_title_font_weight", 'type' => "select", 'options' => GlobalFields::get_instance()->normalize_fields([ '400' => __('Normal (400)', 'notificationx'), '500' => __('Medium (500)', 'notificationx'), '600' => __('Semi Bold (600)', 'notificationx'), '700' => __('Bold (700)', 'notificationx'), ]), ], [ 'label' => __("Item Subtitle Color", 'notificationx'), 'name' => "popup_repeater_subtitle_color", 'type' => "colorpicker", ], [ 'label' => __('Item Subtitle Font Size', 'notificationx'), 'name' => "popup_repeater_subtitle_font_size", 'type' => "number", 'description' => 'px', ], [ 'label' => __('Item Border Radius', 'notificationx'), 'name' => "popup_repeater_item_border_radius", 'type' => "number", 'description' => 'px', 'help' => __('Rounded corners for each content item', 'notificationx'), ], [ 'label' => __('Item Padding', 'notificationx'), 'name' => "popup_repeater_item_padding", 'type' => "text", 'help' => __('Internal spacing for each content item (e.g., 16px)', 'notificationx'), ], [ 'label' => __('Item Spacing', 'notificationx'), 'name' => "popup_repeater_item_spacing", 'type' => "number", 'description' => 'px', 'help' => __('Space between content items', 'notificationx'), ], ] ]; return $fields; } public function content_fields( $fields ) { if (isset($fields['utm_options'])) { $fields['utm_options'] = Rules::is('source', $this->id, true, $fields['utm_options']); } if (isset($fields['content'])) { $fields['content'] = Rules::is('source', $this->id, true, $fields['content']); } $fields['popup_content'] = [ 'label' => __('Popup Content', 'notificationx'), 'name' => 'popup_content', 'type' => 'section', 'priority' => 5, 'rules' => Rules::is('source', $this->id), 'fields' => [ [ 'label' => __('Title', 'notificationx'), 'name' => 'popup_title', 'type' => 'text', 'priority' => 10, 'default' => __('Special Offer!', 'notificationx'), ], [ 'label' => __('Subtitle', 'notificationx'), 'name' => 'popup_subtitle', 'type' => 'text', 'priority' => 12, // No global field-level default: a hardcoded value here pre-fills the // field and blocks each theme's own `defaults` (subtitle) from applying // on selection, so coupon themes (eleven/twelve/thirteen) inherited the // wrong subtitle. Leave empty so the selected theme's default fills it. 'default' => '', 'rules' => Rules::logicalRule([ Rules::is('themes', 'popup_notification_theme-seven'), Rules::is('themes', 'popup_notification_theme-eleven'), Rules::is('themes', 'popup_notification_theme-twelve'), Rules::is('themes', 'popup_notification_theme-thirteen'), ], 'or'), ], [ 'label' => __('Popup Icon', 'notificationx'), 'name' => 'popup_icon', 'type' => 'icon-picker', 'priority' => 15, 'iconPrefix' => NOTIFICATIONX_ADMIN_URL . 'images/icons/', 'default' => 'mail_icon.svg', 'rules' => Rules::is('themes', 'popup_notification_theme-seven'), 'options' => [ [ 'icon' => 'mail_icon.svg', 'label' => __('Mail Icon', 'notificationx') ], ], ], [ 'label' => __('Content', 'notificationx'), 'name' => 'popup_content', 'type' => 'textarea', 'priority' => 20, 'default' => __('Don\'t miss out on this amazing deal!', 'notificationx'), 'rules' => Rules::logicalRule([ Rules::is('themes', 'popup_notification_theme-one'), Rules::is('themes', 'popup_notification_theme-two'), Rules::is('themes', 'popup_notification_theme-seven'), Rules::is('themes', 'popup_notification_theme-eight'), Rules::is('themes', 'popup_notification_theme-eleven'), Rules::is('themes', 'popup_notification_theme-twelve'), Rules::is('themes', 'popup_notification_theme-thirteen'), ], 'or'), ], // Coupon code (with copy-to-clipboard) for the coupon-popup card // themes (theme-eight / -eleven / -twelve). [ 'label' => __('Coupon Code', 'notificationx'), 'name' => 'popup_coupon_code', 'type' => 'text', 'priority' => 22, // No global field-level default: it pre-filled the field with theme-eight's // code and blocked theme-eleven/-twelve's own coupon-code defaults from // applying on selection. Leave empty so the selected theme's default fills it. 'default' => '', 'placeholder' => __('GET35OFF', 'notificationx'), 'rules' => Rules::logicalRule([ Rules::is('themes', 'popup_notification_theme-eight'), Rules::is('themes', 'popup_notification_theme-eleven'), Rules::is('themes', 'popup_notification_theme-twelve'), ], 'or'), ], // Multi-tier coupon "tickets" (percent + code + validity) for the // multi-tier discount popup (theme-thirteen). [ 'label' => __('Coupon Tickets', 'notificationx'), 'name' => 'popup_coupon_repeater', 'type' => 'repeater', 'priority' => 23, 'rules' => Rules::is('themes', 'popup_notification_theme-thirteen'), 'button' => [ 'label' => __('Add Coupon', 'notificationx'), ], 'fields' => [ [ 'label' => __('Discount', 'notificationx'), 'name' => 'coupon_percent', 'type' => 'text', 'placeholder' => __('e.g. 20%', 'notificationx'), 'help' => __('Big discount value shown on the left (e.g. "20%").', 'notificationx'), ], [ 'label' => __('Coupon Code', 'notificationx'), 'name' => 'coupon_code', 'type' => 'text', 'placeholder' => __('e.g. #SAVE20', 'notificationx'), ], [ 'label' => __('Validity', 'notificationx'), 'name' => 'coupon_validity', 'type' => 'text', 'placeholder' => __('e.g. Valid for 7 Days', 'notificationx'), ], ], // One starter coupon by default. The QuickBuilder repeater always // renders a single row for an unsaved field, so a one-row default // keeps the editor, the saved data and the front end consistent // (all show one coupon); users add more with the Add Coupon button. 'default' => [ [ 'coupon_percent' => __('20%', 'notificationx'), 'coupon_code' => __('#SAVE20', 'notificationx'), 'coupon_validity' => __('Valid for 7 Days', 'notificationx'), ], ], ], // Form Field Toggles - only for form submission themes (4-7) [ 'label' => __('Show Name Field', 'notificationx'), 'name' => 'popup_show_name_field', 'type' => 'toggle', 'priority' => 25, 'default' => false, 'rules' => Rules::logicalRule([ Rules::is('themes', 'popup_notification_theme-four'), Rules::is('themes', 'popup_notification_theme-five'), Rules::is('themes', 'popup_notification_theme-six'), Rules::is('themes', 'popup_notification_theme-seven'), ], 'or'), 'is_pro' => true, ], [ 'label' => __('Name Field Text', 'notificationx'), 'name' => 'popup_name_placeholder', 'type' => 'text', 'priority' => 30, 'default' => __('Enter your name', 'notificationx'), 'rules' => Rules::logicalRule([ Rules::logicalRule([ Rules::is('themes', 'popup_notification_theme-four'), Rules::is('themes', 'popup_notification_theme-five'), Rules::is('themes', 'popup_notification_theme-six'), Rules::is('themes', 'popup_notification_theme-seven'), ], 'or'), Rules::is('popup_show_name_field', true), ]), ], [ 'label' => __('Show Email Field', 'notificationx'), 'name' => 'popup_show_email_field', 'type' => 'toggle', 'priority' => 35, 'info' => InfoTooltipManager::get_instance()->render('popup_notification_email_field'), 'rules' => Rules::logicalRule([ Rules::is('themes', 'popup_notification_theme-four'), Rules::is('themes', 'popup_notification_theme-five'), Rules::is('themes', 'popup_notification_theme-six'), Rules::is('themes', 'popup_notification_theme-seven'), ], 'or'), 'is_pro' => true, ], [ 'label' => __('Email Field Text', 'notificationx'), 'name' => 'popup_email_placeholder', 'type' => 'text', 'priority' => 40, 'default' => __('Enter your email', 'notificationx'), 'rules' => Rules::logicalRule([ Rules::logicalRule([ Rules::is('themes', 'popup_notification_theme-four'), Rules::is('themes', 'popup_notification_theme-five'), Rules::is('themes', 'popup_notification_theme-six'), Rules::is('themes', 'popup_notification_theme-seven'), ], 'or'), Rules::is('popup_show_email_field', true), ]), ], [ 'label' => __('Show Message Field', 'notificationx'), 'name' => 'popup_show_message_field', 'type' => 'toggle', 'priority' => 45, 'info' => InfoTooltipManager::get_instance()->render('popup_notification_message_field'), 'rules' => Rules::logicalRule([ Rules::is('themes', 'popup_notification_theme-four'), Rules::is('themes', 'popup_notification_theme-five'), Rules::is('themes', 'popup_notification_theme-six'), Rules::is('themes', 'popup_notification_theme-seven'), ], 'or'), 'default' => true, ], [ 'label' => __('Message Field Text', 'notificationx'), 'name' => 'popup_message_placeholder', 'type' => 'text', 'priority' => 50, 'default' => __('Enter your message...', 'notificationx'), 'rules' => Rules::logicalRule([ Rules::logicalRule([ Rules::is('themes', 'popup_notification_theme-four'), Rules::is('themes', 'popup_notification_theme-five'), Rules::is('themes', 'popup_notification_theme-six'), Rules::is('themes', 'popup_notification_theme-seven'), ], 'or'), Rules::is('popup_show_message_field', true), ]), ], // Common Button Text field for all themes (theme-eleven and // theme-twelve have no CTA — the copyable coupon code is the CTA). [ 'label' => __('Button Text', 'notificationx'), 'name' => 'popup_button_text', 'type' => 'text', 'priority' => 55, 'default' => __('Get Offer', 'notificationx'), 'rules' => Rules::logicalRule([ Rules::is('themes', 'popup_notification_theme-eleven', true), Rules::is('themes', 'popup_notification_theme-twelve', true), ], 'and'), ], // Button URL field - only for themes 1-3 (promotional themes with external links) [ 'label' => __('Button URL', 'notificationx'), 'name' => 'popup_button_url', 'type' => 'text', 'priority' => 60, 'default' => '#', 'rules' => Rules::logicalRule([ Rules::is('themes', 'popup_notification_theme-one'), Rules::is('themes', 'popup_notification_theme-two'), Rules::is('themes', 'popup_notification_theme-three'), Rules::is('themes', 'popup_notification_theme-eight'), Rules::is('themes', 'popup_notification_theme-thirteen'), ], 'or'), ], // Button Icon field - only for theme-three and theme-seven [ 'label' => __('Button Icon', 'notificationx'), 'name' => 'popup_button_icon', 'type' => 'icon-picker', 'priority' => 62, 'iconPrefix' => NOTIFICATIONX_ADMIN_URL . 'images/icons/', 'default' => 'mail_icon.svg', 'options' => [ [ 'icon' => 'mail_icon.svg', 'label' => __('Mail Icon', 'notificationx') ], [ 'icon' => 'latest_offer.svg', 'label' => __('Latest OFfer', 'notificationx') ], [ 'icon' => 'shop_now.svg', 'label' => __('Shop Now', 'notificationx') ], [ 'icon' => 'shop_now_white.svg', 'label' => __('Shop Now White', 'notificationx') ], ], 'description' => __('Select an icon to display with the button text', 'notificationx'), 'rules' => Rules::logicalRule([ Rules::is('themes', 'popup_notification_theme-three'), Rules::is('themes', 'popup_notification_theme-seven'), ], 'or'), ], 'open_in_new_tab' => [ 'label' => __('Open URL in New Tab', 'notificationx'), 'name' => 'open_in_new_tab', 'type' => 'toggle', 'default' => false, 'rules' => Rules::logicalRule([ Rules::is('themes', 'popup_notification_theme-one'), Rules::is('themes', 'popup_notification_theme-two'), Rules::is('themes', 'popup_notification_theme-three'), Rules::is('themes', 'popup_notification_theme-eight'), Rules::is('themes', 'popup_notification_theme-thirteen'), ], 'or'), ], // Repeater fields - only for theme-three [ 'label' => __('Content Items', 'notificationx'), 'name' => 'popup_content_repeater', 'type' => 'repeater', 'priority' => 65, 'rules' => Rules::is('themes', 'popup_notification_theme-three'), 'button' => [ 'label' => __('Add New', 'notificationx') ], 'fields' => [ [ 'label' => __('Highlight Text', 'notificationx'), 'name' => 'repeater_highlight_text', 'type' => 'text', 'default' => __('30% OFF', 'notificationx'), 'help' => __('Text that will be highlighted in a different color (e.g., "30% OFF")', 'notificationx'), ], [ 'label' => __('Title', 'notificationx'), 'name' => 'repeater_title', 'type' => 'text', 'default' => __('Feature Title', 'notificationx'), ], [ 'label' => __('Subtitle', 'notificationx'), 'name' => 'repeater_subtitle', 'type' => 'text', 'default' => __('Feature description', 'notificationx'), ], ], 'default' => [ [ 'repeater_highlight_text' => __('30% OFF', 'notificationx'), 'repeater_title' => __('Boost Sales', 'notificationx'), 'repeater_subtitle' => __('Increase conversions with social proof', 'notificationx'), ], [ 'repeater_highlight_text' => __('50% OFF', 'notificationx'), 'repeater_title' => __('Build Trust', 'notificationx'), 'repeater_subtitle' => __('Show real customer activity', 'notificationx'), ], [ 'repeater_highlight_text' => __('LIMITED', 'notificationx'), 'repeater_title' => __('Drive Action', 'notificationx'), 'repeater_subtitle' => __('Create urgency and FOMO', 'notificationx'), ], ], ], ] ]; return $fields; } /** * Fill EMPTY theme-specific fields from the selected theme's `defaults`. * * Why this is needed: the builder applies a theme's `defaults` on selection, but * fields that are rules-gated OUT of the initial theme (e.g. popup_subtitle, * popup_coupon_code, popup_coupon_repeater) get re-initialized to their own * field-level default when they mount, clobbering the theme default. As a result * the coupon themes (eleven/twelve/thirteen) ended up with the wrong/empty * subtitle, coupon code and coupon tickets on a default (untouched) publish — so * both the live Preview and the front end didn't match the design. * * This safety net fills only EMPTY values, so anything the user actually typed is * preserved. A repeater row that holds only framework metadata (index/chosen/ * selected) with no real content counts as empty. * * @param array $data Flat settings array (content fields at top level). * @param string $theme_full Selected theme key, e.g. "popup_notification_theme-twelve". * @return array */ private function fill_theme_defaults( $data, $theme_full ) { if ( empty( $theme_full ) || empty( $this->themes ) || ! is_array( $data ) ) { return $data; } // Strip the source-id prefix ("popup_notification_") to get the raw theme key. $prefix = $this->id . '_'; $theme_key = ( strpos( $theme_full, $prefix ) === 0 ) ? substr( $theme_full, strlen( $prefix ) ) : $theme_full; if ( empty( $this->themes[ $theme_key ]['defaults'] ) || ! is_array( $this->themes[ $theme_key ]['defaults'] ) ) { return $data; } // Keys the repeater/field framework injects into each row that carry no // user content — a row made up only of these is effectively empty. $meta_keys = array( 'index', 'chosen', 'selected' ); foreach ( $this->themes[ $theme_key ]['defaults'] as $key => $value ) { $current = isset( $data[ $key ] ) ? $data[ $key ] : null; $is_empty = ( null === $current || '' === $current ); if ( is_array( $current ) ) { // Empty array, or an array whose rows only hold framework metadata // (e.g. a clobbered repeater like [{index, chosen, selected}]). $has_real = false; foreach ( $current as $item ) { if ( is_array( $item ) ) { foreach ( $item as $ik => $iv ) { if ( ! in_array( $ik, $meta_keys, true ) && '' !== $iv && null !== $iv ) { $has_real = true; break 2; } } } elseif ( '' !== $item && null !== $item ) { $has_real = true; break; } } $is_empty = ! $has_real; } if ( $is_empty ) { $data[ $key ] = $value; } } return $data; } /** * Apply theme defaults to empty fields at save time (persisted + front end). * Hooked automatically via nx_save_post_{$this->id} (see Extension::init()). * * @param array $post Post row about to be persisted; settings live in $post['data']. * @param array $data Full submitted settings. * @param int $nx_id Notification id (0 on create). * @return array */ public function save_post( $post, $data, $nx_id ) { if ( isset( $post['data'] ) && is_array( $post['data'] ) ) { $theme_full = ! empty( $data['themes'] ) ? $data['themes'] : ( ! empty( $post['theme'] ) ? $post['theme'] : '' ); $post['data'] = $this->fill_theme_defaults( $post['data'], $theme_full ); $post['data'] = $this->strip_empty_repeater_rows( $post['data'] ); } return $post; } /** * Drop repeater rows that hold only framework metadata (index/chosen/selected) * and no real content. The QuickBuilder repeater commits a freshly "Add"ed row * with just an "index" until its inputs are edited, so an untouched extra coupon * would otherwise persist as an empty ticket that renders as a broken blank * ticket on the front end. Only the known coupon repeater is cleaned, so no other * data is affected. * * @param array $data Flat settings array. * @return array */ private function strip_empty_repeater_rows( $data ) { $meta_keys = array( 'index', 'chosen', 'selected' ); $repeater_fields = array( 'popup_coupon_repeater' ); foreach ( $repeater_fields as $field ) { if ( empty( $data[ $field ] ) || ! is_array( $data[ $field ] ) ) { continue; } $data[ $field ] = array_values( array_filter( $data[ $field ], function ( $row ) use ( $meta_keys ) { if ( ! is_array( $row ) ) { return '' !== $row && null !== $row; } foreach ( $row as $k => $v ) { if ( ! in_array( $k, $meta_keys, true ) && '' !== $v && null !== $v ) { return true; } } return false; } ) ); } return $data; } /** * Apply theme defaults to empty fields for the live builder Preview, so the * preview matches the design even before anything is saved. * Hooked automatically via nx_preview_settings_{$this->id} (see Extension::init()). * * @param array $settings Flat preview settings. * @return array */ public function preview_settings( $settings ) { $theme_full = ! empty( $settings['themes'] ) ? $settings['themes'] : ( ! empty( $settings['theme'] ) ? $settings['theme'] : '' ); return $this->fill_theme_defaults( $settings, $theme_full ); } /** * Generate entry key * * @param string $key * @return string */ public function key($key = '') { return $this->id . '_' . $key; } /** * Handle popup form submission * * @param WP_REST_Request $request * @return WP_REST_Response */ public function handle_popup_submission($request) { $params = $request->get_params(); $id = $params['nx_id']; $notificationx = PostType::get_instance()->get_post( $id ); if( !$notificationx ) { return new \WP_REST_Response([ 'success' => false, 'message' => __('Notification not found', 'notificationx'), ], 404); } // Prepare entry data $data = [ 'title' => $params['title'] ?: __('Popup Submission', 'notificationx'), 'timestamp' => time(), ]; // Add email if provided if (!empty($params['email'])) { $data['email'] = $params['email']; } // Add message if provided if (!empty($params['message'])) { $data['message'] = $params['message']; } if (!empty($params['name'])) { $data['name'] = $params['name']; } // Add theme information if (!empty($params['theme'])) { $data['theme'] = $params['theme']; } // Add IP address $data['ip'] = $this->get_user_ip(); // Use the post's own source so exit-intent submissions aren't mis-tagged as // popup_notification (the same /popup-submit endpoint serves both types). $source = ! empty( $notificationx['source'] ) ? $notificationx['source'] : $this->id; $entry_key = $source . '_' . $params['nx_id']; $entry = [ 'nx_id' => $params['nx_id'], 'source' => $source, 'entry_key' => $entry_key, 'data' => $data, ]; // Save the entry $this->update_notification($entry); return new \WP_REST_Response([ 'success' => true, 'message' => __('Submission saved successfully', 'notificationx'), ], 200); } /** * Get user IP address * * @return string */ private function get_user_ip() { if (!empty($_SERVER['HTTP_CLIENT_IP'])) { return sanitize_text_field(wp_unslash($_SERVER['HTTP_CLIENT_IP'])); } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { return sanitize_text_field(wp_unslash($_SERVER['HTTP_X_FORWARDED_FOR'])); } else { return isset($_SERVER['REMOTE_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR'])) : ''; } } /** * This method is an implementable method for All Extension coming forward. * * @param array $args Settings arguments. * @return mixed */ public function customize_fields($fields) { $fields["timing"]['fields']['delay_between'] = Rules::is('source', $this->id, true, $fields["timing"]['fields']['delay_between']); $fields["timing"]['fields']['display_for'] = Rules::is('source', $this->id, true, $fields["timing"]['fields']['display_for']); if (isset($fields['behaviour'])) { $fields['behaviour'] = Rules::is('source', $this->id, true, $fields['behaviour']); } if (isset($fields['sound_section'])) { $fields['sound_section'] = Rules::is('source', $this->id, true, $fields['sound_section']); } if (isset($fields['queue_management'])) { $fields['queue_management'] = Rules::is('source', $this->id, true, $fields['queue_management']); } $_fields = &$fields["appearance"]['fields']; $conversion_position = &$_fields['position']['options']; $conversion_position['center'] = [ 'label' => __('Center', 'notificationx'), 'value' => 'center', 'rules' => Rules::is('source', $this->id), ]; // Exit Intent Popup conversion (Announcement type). $fields['exit_intent_settings'] = [ 'label' => __('Exit Intent Popup', 'notificationx'), 'name' => 'exit_intent_settings', 'type' => 'section', 'priority' => 14, 'rules' => Rules::_is('source', $this->id), 'fields' => [ 'convert_to_exit_intent' => [ 'label' => __('Convert to Exit Intent Popup', 'notificationx'), 'name' => 'convert_to_exit_intent', 'type' => 'checkbox', 'default' => false, 'priority' => 5, 'description' => __('Show this Announcement as a centered popup when the visitor is about to leave the page.', 'notificationx'), ], 'exit_intent_cookie_duration' => [ 'label' => __('Cookie Duration', 'notificationx'), 'name' => 'exit_intent_cookie_duration', 'type' => 'number', 'default' => 7, 'min' => 1, 'max' => 365, 'priority' => 10, 'description' => __('Days', 'notificationx'), 'help' => __('Suppress the popup for this many days after it has been shown to a visitor.', 'notificationx'), 'rules' => Rules::_is('convert_to_exit_intent', true), ], ], ]; $hide_when_exit_intent = Rules::logicalRule([ Rules::_is('source', $this->id, true), Rules::_is('convert_to_exit_intent', true, true), ], 'or'); if (isset($fields['timing']['fields']['display_for'])) { $fields['timing']['fields']['display_for'] = Rules::add( $hide_when_exit_intent, $fields['timing']['fields']['display_for'] ); } if (isset($fields['timing']['fields']['delay_between'])) { $fields['timing']['fields']['delay_between'] = Rules::add( $hide_when_exit_intent, $fields['timing']['fields']['delay_between'] ); } if (isset($_fields['position'])) { $_fields['position'] = Rules::add( $hide_when_exit_intent, $_fields['position'] ); } // Popup specific settings $fields['popup_settings'] = [ 'label' => __('Popup Settings', 'notificationx'), 'name' => 'popup_settings', 'type' => 'section', 'priority' => 15, 'rules' => Rules::is('source', $this->id), 'fields' => [ 'show_close_button' => [ 'label' => __('Show Close Button', 'notificationx'), 'name' => 'show_close_button', 'type' => 'toggle', 'default' => true, ], 'close_on_button_click' => [ 'label' => __('Close on Button Click', 'notificationx'), 'name' => 'close_on_button_click', 'type' => 'toggle', 'default' => true, ], 'close_button_position' => [ 'label' => __('Close Button Position', 'notificationx'), 'name' => 'close_button_position', 'type' => 'select', 'default' => 'top-right', 'options' => GlobalFields::get_instance()->normalize_fields([ 'top-right' => __('Top Right', 'notificationx'), 'top-left' => __('Top Left', 'notificationx'), 'bottom-right' => __('Bottom Right', 'notificationx'), 'bottom-left' => __('Bottom Left', 'notificationx'), ]), 'rules' => Rules::is('show_close_button', true), ], ] ]; return $fields; } public function doc(){ /* translators: %1$s: step-by-step guides link URL, %2$s: tutorial link URL, %3$s: URL */ return sprintf(__('

Create compelling Announcements that capture visitor interest and help you generate more leads on your WordPress site. Need help? Check out our step-by-step guides to build impactful Announcements.

🎦 Watch the quick video tutorial for an easy walk-through.

Recommended Blogs:

🔥 How to Create High-Performing Announcements with NotificationX?

Pro Tips:

✨ Use attention-grabbing headlines and clear action prompts to encourage more sign-ups.

', 'notificationx'), 'https://notificationx.com/docs/how-to-show-announcement-using-notificationx/', 'https://www.youtube.com/playlist?list=PLWHp1xKHCfxAj4AAs3kmzmDZKvjv6eycK', 'https://notificationx.com/blog/announcement-notifications-on-wordpress' ); } }