()) . '&utm_medium=notificationx'); $settings = [ 'disable_powered_by' => Settings::get_instance()->get('settings.disable_powered_by'), 'affiliate_link' => $branding_url, 'enable_analytics' => Settings::get_instance()->get('settings.enable_analytics', true), 'analytics_from' => Settings::get_instance()->get('settings.analytics_from'), 'delay_before' => Settings::get_instance()->get('settings.delay_before', 5), 'display_for' => Settings::get_instance()->get('settings.display_for', 5), 'delay_between' => Settings::get_instance()->get('settings.delay_between', 5), 'loop' => Settings::get_instance()->get('settings.loop', 5), 'random' => Settings::get_instance()->get('settings.random', 5), 'analytics_nonce' => wp_create_nonce('analytics_nonce'), ]; return $settings; } public function get_notifications_ids($return_posts = false, $args = []) { $args = wp_parse_args($args, [ 'enabled' => true, 'updated_at' => ['<=', Helper::mysql_time()], // 'global_queue' => true, ]); $notifications = PostType::get_instance()->get_posts($args); $active_notifications = $global_notifications = $bar_notifications = $gdpr_notification = $popup_notifications = $exit_intent_notifications = array(); foreach ($notifications as $key => $settings) { // $settings = NotificationX::get_instance()->normalize_post($post); // IF PRESSBAR TIME RE_CONFIG THEN REMOVE COOKIE // if( $settings['source'] == 'press_bar'){ // if( $_settings->enable_countdown && ( Helper::current_timestamp($_settings->countdown_start_date) < time() || Helper::current_timestamp($_settings->countdown_end_date) > time() ) ) { // unset( $_COOKIE["notificationx_{$settings['nx_id']}"] ); // \setcookie("notificationx_{$settings['nx_id']}", null); // } // } /** * Check if it's a pro source and pro plugin is disabled. */ if(!NotificationX::is_pro()){ $ext = ExtensionFactory::get_instance()->get($settings['source']); if($ext && $ext->is_pro){ continue; } } $countdown_rand = !empty($settings['countdown_rand']) ? "-{$settings['countdown_rand']}" : ''; if (!empty($_COOKIE["notificationx_{$settings['nx_id']}$countdown_rand"]) && $_COOKIE["notificationx_{$settings['nx_id']}$countdown_rand"] == true) { unset($notifications[$key]); continue; } if($this->is_logged_in($settings['show_on_display'])){ continue; } $locations = isset($settings['all_locations']) ? $settings['all_locations'] : []; $custom_ids = isset($settings['custom_ids']) ? $settings['custom_ids'] : []; $taxonomy_ids = isset($settings['taxonomy_ids']) ? $settings['taxonomy_ids'] : []; if($this->check_show_on($locations, $custom_ids, $settings['show_on'], $taxonomy_ids)){ continue; } /** * Check for hiding in mobile device */ // if ($settings['hide_on_mobile'] && wp_is_mobile()) { // continue; // } // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. $show_on_exclude = apply_filters('nx_show_on_exclude', false, $settings); if ($show_on_exclude) { continue; } // excluding pressBar on rest request. PressBar is printed directly in head. // if((empty($args['source']) || $args['source'] !== 'press_bar') && $settings['source'] == 'press_bar'){ // continue; // } $active_global_queue = boolval($settings['global_queue']); if ($settings['source'] == 'press_bar') { // if( // !$_settings->elementor_id && // $_settings->enable_countdown && // !$_settings->evergreen_timer && // ( // strtotime($_settings->countdown_start_date) > time() || // strtotime($_settings->countdown_end_date) < time() // ) // ){ // continue; // } $bar_notifications[] = $return_posts ? $settings : $settings['nx_id']; if (!empty($settings['elementor_id']) && class_exists('\Elementor\Plugin')) { // @todo Find a function to only load css instead of building content. \Elementor\Plugin::$instance->frontend->get_builder_content($settings['elementor_id'], false); } elseif (!empty($settings['gutenberg_id'])) { $this->enqueue_gutenberg_bar_assets($settings['gutenberg_id']); } } elseif($settings['source'] == 'gdpr_notification') { $gdpr_notification[] = $return_posts ? $settings : $settings['nx_id']; } elseif($settings['source'] == 'popup_notification') { $popup_notifications[] = $settings['nx_id']; } elseif($settings['source'] == 'exit_intent_custom') { $exit_intent_notifications[] = $settings['nx_id']; // Force Elementor's frontend runtime + per-widget assets onto the // page (elementor-frontend.js, the document CSS, and each widget's // get_style_depends()/get_script_depends() — e.g. nx-countdown). // The popup HTML itself is rendered later via REST, where these // enqueues would be discarded, so the countdown widget would lose // its layout CSS and timer JS. Mirrors the press_bar branch above. if (!empty($settings['elementor_id']) && class_exists('\Elementor\Plugin')) { \Elementor\Plugin::$instance->frontend->get_builder_content($settings['elementor_id'], false); } } elseif ($active_global_queue && NotificationX::is_pro()) { $global_notifications[] = $return_posts ? $settings : $settings['nx_id']; } else { $active_notifications[] = $return_posts ? $settings : $settings['nx_id']; } unset($notifications[$key]); } // do_action('nx_active_notificationx', $notifications); // @todo maybe combine two hooks. return apply_filters( // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. 'get_notifications_ids', [ 'global' => $global_notifications, 'active' => $active_notifications, 'pressbar' => $bar_notifications, 'gdpr' => $gdpr_notification, 'popup' => $popup_notifications, 'exit_intent' => $exit_intent_notifications, 'total' => (count($global_notifications) + count($active_notifications) + count($bar_notifications) + count($gdpr_notification) + count($popup_notifications) + count($exit_intent_notifications)), ], $notifications ); } public function is_logged_in($show_on_display){ $logged_in = is_user_logged_in(); if (($logged_in && 'logged_out_user' == $show_on_display) || (!$logged_in && 'logged_in_user' == $show_on_display)) { return true; } return false; } /** * @todo filter is not extensive enough. */ public function check_show_on($locations, $custom_ids, $show_on, $taxonomy_ids = ''){ $check_location = false; if ($locations == 'is_custom' || is_array($locations) && in_array('is_custom', $locations)) { $custom_ids = !empty($custom_ids) ? $custom_ids : []; } if (!empty($locations)) { // @todo need to pass url. $check_location = Locations::get_instance()->check_location($locations, $custom_ids, $taxonomy_ids); } // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. $check_location = apply_filters('nx_check_location', $check_location, $custom_ids, $show_on); if ($show_on == 'on_selected') { // show if the page is on selected if (!$check_location) { return true; } } elseif ($show_on == 'hide_on_selected') { // hide if the page is on selected if ($check_location) { return true; } } elseif ($show_on === 'only_shortcode') { return true; } return false; } public function get_notifications($ids, $device = '') { $results = []; $notifications = PostType::get_instance()->get_posts_by_ids($ids); foreach ($notifications as $key => $value) { /** * Check for hiding in mobile device */ if (empty($value['hide_on_mobile']) && $device === 'mobile') { continue; } /** * Check for hiding in tablet device */ if (empty($value['hide_on_tab']) && $device === 'tablet') { continue; } /** * Check for hiding in desktop device */ if (empty($value['hide_on_desktop']) && $device === 'desktop') { continue; } /** * Check if it's a pro source and pro plugin is disabled. */ if(!NotificationX::is_pro()){ $ext = ExtensionFactory::get_instance()->get($value['source']); if($ext && $ext->is_pro){ continue; } } $results[$value['nx_id']] = $value; } return $results; } public function get_entries($ids, $notifications,$params) { $entries = []; if (!empty($ids) && is_array($ids)) { $query = []; foreach ($ids as $id) { if (!empty($notifications[$id])) { $post = $notifications[$id]; $global_query = " nx_id = " . absint($id) . " AND source = '" . esc_sql($post['source']) . "'"; // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. $_q = apply_filters("nx_get_entries_query_part_{$notifications[$id]['source']}",$global_query, $notifications[$id], $params ); $query[$id] = " (" . $_q . ")"; } } if (!empty($query)) { $entries = Entries::get_instance()->get_entries('WHERE' . implode(' OR ', $query)); foreach ($entries as $key => $value) { if (!empty($value['data'])) { $entries[$key] = array_merge($value, $value['data']); unset($entries[$key]['data']); } } } } if (!is_array($entries)) { $entries = []; } // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. $entries = apply_filters('nx_frontend_get_entries', $entries, $ids, $notifications,$params); return $entries; } /** * This function is responsible for make ready the link for notifications. * * @param array $data * @return void */ public static function link_url($entry, $post, $params = []) { if (empty($entry)) { return false; } $link = isset($entry['link']) ? $entry['link'] : ''; // removing link if link type is none. if (empty($post['link_type']) || $post['link_type'] === 'none') { $link = ''; } // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. $link = apply_filters("nx_notification_link_{$post['source']}", $link, $post, $entry, $params); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. $entry['link'] = apply_filters('nx_notification_link', $link, $post, $entry, $params); return $entry; } /** * This function is responsible for getting the image url * using Product ID or from default image settings. * * @param array $data * @param array $settings * @return array of image data, contains url and title as alt text */ public function get_image_url($data, $settings) { $source = $settings['source']; $alt_title = isset($data['name']) ? $data['name'] : ''; $image_type = isset($settings['show_notification_image']) ? $settings['show_notification_image'] : false; if (empty($alt_title)) { $alt_title = isset($data['title']) ? $data['title'] : ''; } $image_data = [ 'url' => '', 'alt' => $alt_title, ]; if ($settings['show_default_image']) { if (!empty($settings['image_url']['url'])) { $image_size = (string) Settings::get_instance()->get('settings.notification_image_size', '100_100'); $image_size = explode('_', $image_size); $width = 100; $height = 100; if( !empty( $image_size[0] ) && !empty( $image_size[1] ) ) { $width = $image_size[0]; $height = $image_size[1]; } $image = wp_get_attachment_image_src($settings['image_url']['id'], [$width, $height], true); $image_data['url'] = $image[0]; } else { $default_avatar = $settings['default_avatar']; $image_data['url'] = NOTIFICATIONX_PUBLIC_URL . 'image/icons/' . $default_avatar; } } else { if ($image_type === 'gravatar') { $_data = array_change_key_case($data); if (isset($_data['email'])) { $image_data['url'] = get_avatar_url($_data['email'], ['size' => '100']); } } } $image_data['classes'] = $image_type; // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. $image_data = apply_filters("nx_notification_image_$source", $image_data, $data, $settings); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. $image_data = apply_filters('nx_notification_image', $image_data, $data, $settings); if (!empty($image_data['url'])) { return $image_data; } return false; } public function apply_defaults($entry, $defaults) { foreach ($defaults as $key => $value) { // @todo mukul remove `|| empty(trim($entry[$key]))` if (empty($entry[$key]) || (is_string($entry[$key]) && empty(trim($entry[$key])))) { $entry[$key] = $value; } } return $entry; } public function fallback_data($data, $saved_data, $settings) { if ((empty($saved_data['name']) || $data['name'] == __('Someone', 'notificationx')) && isset($saved_data['first_name']) || isset($saved_data['last_name'])) { $first_name = isset($saved_data['first_name']) ? $saved_data['first_name'] : ''; $last_name = isset($saved_data['last_name']) ? $saved_data['last_name'] : ''; $data['name'] = Helper::name($first_name, $last_name); } if (!empty($saved_data['name']) && empty($saved_data['first_name']) && empty($saved_data['last_name'])) { $data['first_name'] = $saved_data['name']; } $data['title'] = isset($saved_data['post_title']) ? $saved_data['post_title'] : (isset($data['title']) ? $data['title'] : ''); return $data; } /** * Add NotificationX in Footer * * @return void */ public function filtered_data($entries, $post, $params) { if (is_array($entries) && (!defined('NX_DEBUG') || !NX_DEBUG)) { if (!empty($post['display_last']) && !in_array($post['source'], ['google', 'woo_inline', 'edd_inline', 'tutor_inline', 'learndash_inline', 'google_reviews', 'youtube','woocommerce_sales_inline','fluentcart_inline'])) { $entries = array_slice($entries, 0, $post['display_last']); } foreach ($entries as $index => $entry) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. $_entry = apply_filters("nx_frontend_keep_entry_{$post['source']}", [ 'nx_id' => $entry['nx_id'], 'timestamp' => isset($entry['timestamp']) ? $entry['timestamp'] : Helper::current_timestamp($entry['updated_at']), 'updated_at' => isset( $entry['updated_at'] ) ? $entry['updated_at'] : '', 'image_data' => $entry['image_data'], 'link' => $entry['link'], // Location is rendered by themes (e.g. conv-theme-fifteen) via the // hardcoded {{city_country}} tag, not through a notification-template // param, so the template loop below never whitelists it. Keep the // raw parts here so the frontend can compose "City, Country". 'city' => $entry['city'] ?? '', 'country' => $entry['country'] ?? '', ], $entry, $post, $params); if (!empty($params['inline_shortcode']) && isset($entry['product_id'])) { $_entry['product_id'] = $entry['product_id']; } // `notification-template` can be absent for some posts (e.g. advanced- // template notifications or imported/migrated posts), so guard against // passing null to array_values() — that is a fatal TypeError on PHP 8. $template_arr = ( ! empty( $post['notification-template'] ) && is_array( $post['notification-template'] ) ) ? array_values( $post['notification-template'] ) : []; if ( ! empty( $post['template_adv'] ) ) { $adv_template = isset( $post['advanced_template'] ) ? $post['advanced_template'] : ''; $pattern = "/{{(.+?)}}/i"; if (preg_match_all($pattern, $adv_template, $matches)) { $template_arr = $matches[1]; } } if (is_array($template_arr)) { foreach ($template_arr as $entry_key) { $_entry_key = $entry_key; if ($entry_key == 'tag_siteview' || $entry_key == 'tag_realtime_siteview') { $entry_key = 'views'; } elseif ($entry_key == 'ga_title' || $entry_key == 'ga_page_title') { $entry_key = 'title'; } elseif (strpos($entry_key, 'tag_product_') === 0) { $entry_key = str_replace('tag_product_', '', $entry_key); } elseif (strpos($entry_key, 'tag_') === 0) { $entry_key = str_replace('tag_', '', $entry_key); } elseif (strpos($entry_key, 'product_') === 0) { $entry_key = str_replace('product_', '', $entry_key); } if (isset($entry[$entry_key])) { $_entry[$entry_key] = $entry[$entry_key]; } if (isset($entry[$_entry_key])) { $_entry[$_entry_key] = $entry[$_entry_key]; } } $entries[$index] = $_entry; } } } return $entries; } /** * Remove unnecessary props from post in frontend. * * @return void */ public function filtered_post($post, $params = null) { if (is_array($post) && empty($params['inline_shortcode']) && (!defined('NX_DEBUG') || !NX_DEBUG)) { $ignore_props = [ 'all_locations', 'category_list', 'combine_multiorder_display', 'combine_multiorder_text', 'content_trim_length', 'convertkit_form', 'currentTab', 'custom_contents', 'custom_ids', 'default_avatar', 'elementor_edit_link', 'enabled', 'exclude_categories', 'exclude_products', 'form_list', 'freemius_item_type', 'freemius_plugins', 'freemius_themes', 'give_form_list', 'give_forms_control', 'image_url', 'inline_location', 'is_confirmed', 'is_elementor', 'is_inline', 'ld_course_list', 'ld_product_control', 'activecampaign_form', 'brevo_list', 'mailchimp_list', 'max_stock', 'nx-bar_with_elementor', 'nx-bar_with_elementor-remove', 'nx-bar_with_elementor_install', 'order_status', 'press_content', 'preview', 'product_control', 'product_exclude_by', 'product_list', 'rest_route', 'show_default_image', 'show_notification_image', 'show_on', 'show_on_display', 'source_error', 'utm_campaign', 'utm_medium', 'utm_source', 'wp_reviews_product_type', 'wp_reviews_slug', 'wp_stats_product_type', 'wp_stats_slug', '_locale', '__product_list', '__form_list', '__ld_course_list', '__give_form_list', ]; foreach ($ignore_props as $prop) { if (isset($post[$prop])) { unset($post[$prop]); } } } if (isset($post['template_adv'], $post['advanced_template'])) { $post['advanced_template'] = do_shortcode($post['advanced_template']); } if( !empty( $post['notification-template'] ) ) { $post['notification-template'] = array_map( 'esc_html', $post['notification-template'] ); } return $post; } public function get_bar_content($settings, $suppress_filters = false, $params = []){ $bar_content = PressBar::get_instance()->print_bar_notice($settings); if(!$suppress_filters){ // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. $bar_content = apply_filters("nx_filtered_data_{$settings['source']}", $bar_content, $settings, $params); } // checking if content is empty $_bar_content = str_replace(array("\r\n", "\n", "\r"), '', $bar_content); $_bar_content = trim(wp_strip_all_tags($_bar_content)); if (empty($_bar_content) && !empty($settings['enable_countdown'])) { $bar_content = ' '; } return $bar_content; } }