| @@ -41,13 +41,23 @@ | ||
| 41 | 41 | const ASSET_PATH = NOTIFICATIONX_ASSETS_PATH . 'public/'; |
| 42 | 42 | protected $notificationXArr = []; |
| 43 | 43 | |
| 44 | 44 | /** |
| 45 | + * Block-editor bars whose block assets are already on this page, keyed by | |
| 46 | + * the bar's `gutenberg_id` (see enqueue_gutenberg_bar_assets()). | |
| 47 | + * | |
| 48 | + * @var array<int, true> | |
| 49 | + */ | |
| 50 | + protected $gutenberg_bar_assets = []; | |
| 51 | + | |
| 52 | + /** | |
| 45 | 53 | * Initially Invoked |
| 46 | 54 | * when its initialized. |
| 47 | 55 | */ |
| 48 | 56 | public function __construct() { |
| 49 | 57 | Analytics::get_instance(); |
| 58 | + BarSpace::get_instance(); | |
| 59 | + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 50 | 60 | if (!is_admin() || !empty($_GET['frontend'])) { |
| 51 | 61 | add_action('init', [$this, 'init'], 10); |
| 52 | 62 | } |
| 53 | 63 | add_filter('nx_frontend_localize_data', [$this, 'get_localize_data']); |
| @@ -65,13 +75,134 @@ | ||
| 65 | 75 | add_filter('nx_fallback_data', [$this, 'fallback_data'], 10, 3); |
| 66 | 76 | add_filter('nx_filtered_data', [$this, 'filtered_data'], 9999, 3); |
| 67 | 77 | add_filter('nx_filtered_post', [$this, 'filtered_post'], 9999, 2); |
| 68 | 78 | add_action('wp_print_footer_scripts', [$this, 'footer_scripts']); |
| 79 | + // After wp_enqueue_scripts (wp_head priority 1) has collected the page's bars. | |
| 80 | + add_action('wp_head', [$this, 'print_bar_reserve'], 3); | |
| 69 | 81 | add_filter('body_class', [ $this, 'nx_add_body_class' ] ); |
| 82 | + add_filter('style_loader_tag', [$this, 'non_blocking_style_tag'], 10, 2); | |
| 70 | 83 | |
| 71 | 84 | } |
| 72 | 85 | |
| 73 | 86 | /** |
| 87 | + * Third-party stylesheets used by the notification themes, keyed by style | |
| 88 | + * handle. | |
| 89 | + * | |
| 90 | + * They used to be CSS `@import`s at the top of frontend.css, which the | |
| 91 | + * browser only discovers once frontend.css has downloaded: a serial, | |
| 92 | + * render-blocking chain to two more origins on every page. They are now | |
| 93 | + * enqueued next to `notificationx-public` and loaded without blocking the | |
| 94 | + * first paint (see non_blocking_style_tag()). | |
| 95 | + * | |
| 96 | + * @since 3.3.3 | |
| 97 | + * @return array<string, string> Style handle => URL. | |
| 98 | + */ | |
| 99 | + public function get_external_styles() { | |
| 100 | + $styles = []; | |
| 101 | + /** | |
| 102 | + * Filters whether NotificationX loads Open Sans from Google Fonts. | |
| 103 | + * | |
| 104 | + * Return false if the site already loads Open Sans or must not | |
| 105 | + * contact Google Fonts; the themes then fall back to sans-serif. | |
| 106 | + * | |
| 107 | + * @since 3.3.3 | |
| 108 | + * @param bool $load Default true. | |
| 109 | + */ | |
| 110 | + if (apply_filters('notificationx_load_open_sans', true)) { | |
| 111 | + $styles['notificationx-open-sans'] = 'https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;500;600;700&display=swap'; | |
| 112 | + } | |
| 113 | + /** | |
| 114 | + * Filters whether NotificationX loads FontAwesome 4.7 from cdnjs. | |
| 115 | + * | |
| 116 | + * The icons are drawn in pseudo-elements of a few themes only. Return | |
| 117 | + * false if the site already loads FontAwesome 4. | |
| 118 | + * | |
| 119 | + * @since 3.3.3 | |
| 120 | + * @param bool $load Default true. | |
| 121 | + */ | |
| 122 | + if (apply_filters('notificationx_load_fontawesome', true)) { | |
| 123 | + $styles['notificationx-fontawesome-4'] = 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css'; | |
| 124 | + } | |
| 125 | + return $styles; | |
| 126 | + } | |
| 127 | + | |
| 128 | + /** | |
| 129 | + * Enqueue the third-party font and icon stylesheets (get_external_styles()). | |
| 130 | + * | |
| 131 | + * Call this wherever `notificationx-public` (or a stylesheet that bundles | |
| 132 | + * the frontend themes) is enqueued. | |
| 133 | + * | |
| 134 | + * @since 3.3.3 | |
| 135 | + * @return void | |
| 136 | + */ | |
| 137 | + public function enqueue_external_styles() { | |
| 138 | + foreach ($this->get_external_styles() as $handle => $src) { | |
| 139 | + // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion -- Third-party URL; a ?ver= query would only split the CDN cache. | |
| 140 | + wp_enqueue_style($handle, $src, [], null); | |
| 141 | + } | |
| 142 | + } | |
| 143 | + | |
| 144 | + /** | |
| 145 | + * Load some stylesheets without blocking the first paint. | |
| 146 | + * | |
| 147 | + * - `notificationx-public` styles only what the runtime renders — bars, | |
| 148 | + * popups and shortcodes all mount from REST data after the page has | |
| 149 | + * loaded (the bar's reserved space is a separate inline style), and the | |
| 150 | + * runtime waits for this sheet before its first render (whenStyled()). | |
| 151 | + * At ~600 KB it was the largest render-blocking stylesheet on every page. | |
| 152 | + * - `notificationx-gdpr-modal` styles only the cookie-preferences modal, | |
| 153 | + * which opens on a click. | |
| 154 | + * - The font and icon stylesheets from get_external_styles(): the fonts | |
| 155 | + * swap in, and the FontAwesome glyphs are drawn only in pseudo-elements | |
| 156 | + * of notifications the runtime renders after the page has loaded. | |
| 157 | + * | |
| 158 | + * The stylesheet is requested as `print` and switched to `all` once it has | |
| 159 | + * loaded; the <noscript> copy keeps it for visitors without JavaScript. | |
| 160 | + * `data-nx-style` marks it for the runtime, which also switches it (see | |
| 161 | + * applyDeferredStyles() in external-styles.ts) in case the inline handler | |
| 162 | + * was stripped by an optimizer or blocked by a Content Security Policy. | |
| 163 | + * | |
| 164 | + * @param string $tag The link tag. | |
| 165 | + * @param string $handle Style handle. | |
| 166 | + * @return string | |
| 167 | + */ | |
| 168 | + public function non_blocking_style_tag($tag, $handle) { | |
| 169 | + $handles = ['notificationx-public', 'notificationx-gdpr-modal', 'notificationx-open-sans', 'notificationx-fontawesome-4']; | |
| 170 | + if (!in_array($handle, $handles, true) || false !== strpos($tag, 'onload=')) { | |
| 171 | + return $tag; | |
| 172 | + } | |
| 173 | + $deferred = preg_replace('/\smedia=([\'"])all\1/', ' media=$1print$1 onload="this.media=\'all\'" data-nx-style=$1print$1', $tag, 1, $count); | |
| 174 | + if (!$count) { | |
| 175 | + return $tag; | |
| 176 | + } | |
| 177 | + return $deferred . '<noscript>' . trim($tag) . "</noscript>\n"; | |
| 178 | + } | |
| 179 | + | |
| 180 | + /** | |
| 181 | + * Script dependencies of the `notificationx-public` runtime. | |
| 182 | + * | |
| 183 | + * `wp-hooks` provides `window.wp.hooks`, the registry the runtime reads its | |
| 184 | + * frontend filters from (see nxdev/notificationx/frontend/core/hooks.ts and | |
| 185 | + * docs/api/frontend-js-hooks.md). It is always kept, even if a filter drops | |
| 186 | + * it, because without it every add-on filter silently stops firing. | |
| 187 | + * | |
| 188 | + * @since 3.3.3 | |
| 189 | + * @return string[] | |
| 190 | + */ | |
| 191 | + public function get_script_dependencies() { | |
| 192 | + /** | |
| 193 | + * Filters the script dependencies of the `notificationx-public` runtime. | |
| 194 | + * | |
| 195 | + * @since 3.3.3 | |
| 196 | + * @param string[] $deps Script handles. | |
| 197 | + */ | |
| 198 | + $deps = apply_filters( 'nx_frontend_script_deps', [ 'wp-hooks' ] ); | |
| 199 | + $deps = is_array( $deps ) ? array_filter( $deps, 'is_string' ) : []; | |
| 200 | + array_unshift( $deps, 'wp-hooks' ); | |
| 201 | + return array_values( array_unique( $deps ) ); | |
| 202 | + } | |
| 203 | + | |
| 204 | + /** | |
| 74 | 205 | * This method is responsible for enqueueing scripts for public use. |
| 75 | 206 | * |
| 76 | 207 | * @return void |
| 77 | 208 | */ |
| @@ -76,10 +207,16 @@ | ||
| 76 | 207 | * @return void |
| 77 | 208 | */ |
| 78 | 209 | public function enqueue_scripts() { |
| 79 | 210 | $custom_css = $this->generate_custom_css(); |
| 80 | - wp_register_script('notificationx-public', Helper::file('public/js/frontend.js', true), [], apply_filters('nx_frontend_js_version', NOTIFICATIONX_VERSION ), true); | |
| 211 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 212 | + wp_register_script('notificationx-public', Helper::file('public/js/frontend.js', true), $this->get_script_dependencies(), apply_filters('nx_frontend_js_version', NOTIFICATIONX_VERSION ), true); | |
| 213 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 81 | 214 | wp_register_style('notificationx-public', Helper::file('public/css/frontend.css', true), [], apply_filters('nx_frontend_css_version', NOTIFICATIONX_VERSION ), 'all'); |
| 215 | + // GDPR cookie-customisation modal styles, split out of frontend.css | |
| 216 | + // (~305 KB) so only pages with an active GDPR notice load them. | |
| 217 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 218 | + wp_register_style('notificationx-gdpr-modal', Helper::file('public/css/gdpr-modal.css', true), ['notificationx-public'], apply_filters('nx_frontend_css_version', NOTIFICATIONX_VERSION ), 'all'); | |
| 82 | 219 | // wp_register_style('notificationx-icon-pack', Helper::file('public/icon/style.css', true), [], NOTIFICATIONX_VERSION, 'all'); |
| 83 | 220 | // Localize scripts for frontend |
| 84 | 221 | wp_localize_script( |
| 85 | 222 | 'notificationx-public', |
| @@ -113,12 +250,14 @@ | ||
| 113 | 250 | ) |
| 114 | 251 | ); |
| 115 | 252 | |
| 116 | 253 | $exit = false; |
| 117 | - if(isset($_SERVER['HTTP_REFERER']) && strpos($_SERVER['HTTP_REFERER'], 'wp-admin/widgets.php') !== false){ | |
| 254 | + $referer = isset($_SERVER['HTTP_REFERER']) ? esc_url_raw(wp_unslash($_SERVER['HTTP_REFERER'])) : ''; | |
| 255 | + if($referer && strpos($referer, 'wp-admin/widgets.php') !== false){ | |
| 118 | 256 | $exit = ['total' => 0]; |
| 119 | 257 | } |
| 120 | 258 | |
| 259 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 121 | 260 | $exit = apply_filters('nx_before_enqueue_scripts', $exit); |
| 122 | 261 | if(!empty($exit)){ |
| 123 | 262 | $this->notificationXArr = $exit; |
| 124 | 263 | return; |
| @@ -123,8 +262,9 @@ | ||
| 123 | 262 | $this->notificationXArr = $exit; |
| 124 | 263 | return; |
| 125 | 264 | } |
| 126 | 265 | |
| 266 | + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 127 | 267 | if (!$exit && empty($_GET['elementor-preview'])) { |
| 128 | 268 | $this->notificationXArr = $this->get_notifications_ids(); |
| 129 | 269 | if ($this->notificationXArr['total'] > 0) { |
| 130 | 270 | $lang = get_locale(); |
| @@ -144,8 +284,12 @@ | ||
| 144 | 284 | } |
| 145 | 285 | } |
| 146 | 286 | |
| 147 | 287 | wp_enqueue_style('notificationx-public'); |
| 288 | + $this->enqueue_external_styles(); | |
| 289 | + if ( ! empty( $this->notificationXArr['gdpr'] ) ) { | |
| 290 | + wp_enqueue_style('notificationx-gdpr-modal'); | |
| 291 | + } | |
| 148 | 292 | wp_enqueue_script('notificationx-public'); |
| 149 | 293 | wp_enqueue_style('dashicons'); |
| 150 | 294 | do_action('notificationx_scripts', $this->notificationXArr); |
| 151 | 295 | wp_add_inline_style( 'notificationx-public', $custom_css ); |
| @@ -155,13 +299,76 @@ | ||
| 155 | 299 | // LATER |
| 156 | 300 | } |
| 157 | 301 | } |
| 158 | 302 | |
| 303 | + /** | |
| 304 | + * Reserve the top bar's measured height before it mounts (see BarSpace). | |
| 305 | + * | |
| 306 | + * @return void | |
| 307 | + */ | |
| 308 | + public function print_bar_reserve() { | |
| 309 | + // The builder preview passes preview data here, not bar IDs. | |
| 310 | + if (!empty($this->notificationXArr['nxPreview']) || empty($this->notificationXArr['pressbar']) || !is_array($this->notificationXArr['pressbar'])) { | |
| 311 | + return; | |
| 312 | + } | |
| 313 | + $ids = array_filter($this->notificationXArr['pressbar'], 'is_numeric'); | |
| 314 | + if ($ids) { | |
| 315 | + BarSpace::get_instance()->print_reserve($ids); | |
| 316 | + } | |
| 317 | + } | |
| 318 | + | |
| 159 | 319 | public function nx_add_body_class($classes) { |
| 160 | 320 | $classes[] = 'has-notificationx'; |
| 321 | + // Tells the runtime it need not fetch these bars' pages for their assets. | |
| 322 | + foreach (array_keys($this->gutenberg_bar_assets) as $gutenberg_id) { | |
| 323 | + $classes[] = 'nx-bar-assets-' . $gutenberg_id; | |
| 324 | + } | |
| 161 | 325 | return $classes; |
| 162 | 326 | } |
| 163 | 327 | |
| 328 | + /** | |
| 329 | + * Put a block-editor bar's block assets on the current page. | |
| 330 | + * | |
| 331 | + * The bar's HTML arrives over REST after load, where anything its blocks | |
| 332 | + * enqueue is discarded. The runtime used to recover those assets by | |
| 333 | + * fetching the bar's own permalink — a full themed page (~300 KB on | |
| 334 | + * essential-blocks.com) — and loading each stylesheet and script it had | |
| 335 | + * that this page did not, one after another, before the bar could settle. | |
| 336 | + * Rendering the blocks here, while this page's assets are still being | |
| 337 | + * collected, lets each block enqueue what it needs (e.g. a countdown's | |
| 338 | + * frontend script) exactly as it would in post content; the output is | |
| 339 | + * discarded. Mirrors the Elementor branch above. | |
| 340 | + * | |
| 341 | + * Runs for page loads only: REST and admin requests have no page to add | |
| 342 | + * assets to. | |
| 343 | + * | |
| 344 | + * @param int|string $gutenberg_id The bar's block post ID. | |
| 345 | + * @return void | |
| 346 | + */ | |
| 347 | + protected function enqueue_gutenberg_bar_assets($gutenberg_id) { | |
| 348 | + $gutenberg_id = absint($gutenberg_id); | |
| 349 | + if (!$gutenberg_id || isset($this->gutenberg_bar_assets[$gutenberg_id]) || !doing_action('wp_enqueue_scripts')) { | |
| 350 | + return; | |
| 351 | + } | |
| 352 | + // Same lookup as PressBar::print_bar_notice(), which renders the HTML the runtime shows. | |
| 353 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 354 | + $post_id = apply_filters('wpml_object_id', $gutenberg_id, 'wp_block', true); | |
| 355 | + $post = $post_id ? get_post($post_id) : null; | |
| 356 | + if (!$post || '' === trim((string) $post->post_content)) { | |
| 357 | + return; | |
| 358 | + } | |
| 359 | + // This runs inside <head> (wp_enqueue_scripts). A block whose render | |
| 360 | + // callback echoes instead of returning would print into <head> and push | |
| 361 | + // every later head tag into <body>; buffer and discard all output. | |
| 362 | + ob_start(); | |
| 363 | + try { | |
| 364 | + do_blocks($post->post_content); | |
| 365 | + } finally { | |
| 366 | + ob_end_clean(); | |
| 367 | + } | |
| 368 | + $this->gutenberg_bar_assets[$gutenberg_id] = true; | |
| 369 | + } | |
| 370 | + | |
| 164 | 371 | private function separate_css($css) { |
| 165 | 372 | $media_css = ''; |
| 166 | 373 | $normal_css = ''; |
| 167 | 374 | |
| @@ -188,9 +395,10 @@ | ||
| 188 | 395 | public function generate_custom_css() { |
| 189 | 396 | $posts = Database::get_instance()->get_posts(Database::$table_posts, '*', ['enabled' => true] ); |
| 190 | 397 | $combine_css = ""; |
| 191 | 398 | foreach ($posts as $post) { |
| 192 | - if( !empty( $post['data']['add_custom_css'] ) && !empty( $post['nx_id'] ) ) { | |
| 399 | + // Raw rows (not normalize_post()), so check the type here. | |
| 400 | + if( !empty( $post['data']['add_custom_css'] ) && is_string( $post['data']['add_custom_css'] ) && !empty( $post['nx_id'] ) ) { | |
| 193 | 401 | $separatedCss = $this->separate_css($post['data']['add_custom_css']); |
| 194 | 402 | if( !empty( $post['data']['source'] ) && $post['data']['source'] == 'press_bar' ) { |
| 195 | 403 | $combine_css .= "{$separatedCss['normal_css']} {$separatedCss['media_css']} "; |
| 196 | 404 | } else if( !empty( $post['data']['source'] ) && $post['data']['source'] == 'gdpr_notification' ) { |
| @@ -205,8 +413,9 @@ | ||
| 205 | 413 | } |
| 206 | 414 | |
| 207 | 415 | public function footer_scripts() { |
| 208 | 416 | if (!empty($this->notificationXArr['total']) && $this->notificationXArr['total'] > 0) { |
| 417 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 209 | 418 | $this->notificationXArr = apply_filters('nx_frontend_localize_data', $this->notificationXArr); |
| 210 | 419 | ?> |
| 211 | 420 | <script data-no-optimize="1"> |
| 212 | 421 | (function() { |
| @@ -222,11 +431,48 @@ | ||
| 222 | 431 | public function localizeScripts() { |
| 223 | 432 | return []; |
| 224 | 433 | } |
| 225 | 434 | |
| 435 | + /** | |
| 436 | + * The URL WordPress prints for a registered stylesheet. | |
| 437 | + * | |
| 438 | + * @param string $handle Style handle. | |
| 439 | + * @return string Empty when the handle has no source. | |
| 440 | + */ | |
| 441 | + protected function style_url($handle) { | |
| 442 | + $style = wp_styles()->query($handle, 'registered'); | |
| 443 | + if (!$style || empty($style->src) || !is_string($style->src)) { | |
| 444 | + return ''; | |
| 445 | + } | |
| 446 | + $src = $style->src; | |
| 447 | + // Same version rule as WP_Styles::_css_href(). | |
| 448 | + $ver = null === $style->ver ? '' : ($style->ver ? $style->ver : get_bloginfo('version')); | |
| 449 | + if ('' !== $ver) { | |
| 450 | + $src = add_query_arg('ver', $ver, $src); | |
| 451 | + } | |
| 452 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Core filter, so CDN rewrites apply. | |
| 453 | + return (string) apply_filters('style_loader_src', $src, $handle); | |
| 454 | + } | |
| 455 | + | |
| 226 | 456 | public function get_localize_data($data) { |
| 227 | 457 | $data['rest'] = REST::get_instance()->rest_data(false); |
| 228 | 458 | $data['assets'] = self::ASSET_URL; |
| 459 | + if (empty($data['cross'])) { | |
| 460 | + // The runtime re-adds these if an optimizer combined them into a | |
| 461 | + // bundle that does not apply (e.g. a print-only one). | |
| 462 | + $styles = []; | |
| 463 | + foreach (['notificationx-public', 'notificationx-gdpr-modal'] as $handle) { | |
| 464 | + if (wp_style_is($handle, 'enqueued') || wp_style_is($handle, 'done')) { | |
| 465 | + $url = $this->style_url($handle); | |
| 466 | + if ($url) { | |
| 467 | + $styles[$handle] = $url; | |
| 468 | + } | |
| 469 | + } | |
| 470 | + } | |
| 471 | + if ($styles) { | |
| 472 | + $data['styles'] = $styles; | |
| 473 | + } | |
| 474 | + } | |
| 229 | 475 | $data['is_pro'] = false; |
| 230 | 476 | $data['gmt_offset'] = get_option('gmt_offset'); |
| 231 | 477 | $data['lang'] = get_locale(); |
| 232 | 478 | $data['common_assets'] = NOTIFICATIONX_COMMON_URL; |
| @@ -236,8 +482,12 @@ | ||
| 236 | 482 | 'queried_id' => get_queried_object_id(), |
| 237 | 483 | 'pid' => !empty($GLOBALS['post']->ID) ? $GLOBALS['post']->ID : 0, |
| 238 | 484 | ]; |
| 239 | 485 | $data['localeData'] = load_script_textdomain('notificationx-public', 'notificationx'); |
| 486 | + if (!empty($data['cross'])) { | |
| 487 | + // Cross-domain embeds have no WordPress enqueue: the runtime adds these. | |
| 488 | + $data['external_styles'] = $this->get_external_styles(); | |
| 489 | + } | |
| 240 | 490 | return $data; |
| 241 | 491 | } |
| 242 | 492 | |
| 243 | 493 | public function get_notifications_data($params) { |
| @@ -266,8 +516,13 @@ | ||
| 266 | 516 | 'shortcode' => [], |
| 267 | 517 | 'inline_shortcode' => false, |
| 268 | 518 | ] |
| 269 | 519 | ); |
| 520 | + // These come straight from the public REST `notice` request, where | |
| 521 | + // `?global=1` arrives as a string; the code below needs ID lists. | |
| 522 | + foreach (['global', 'active', 'pressbar', 'gdpr', 'popup', 'exit_intent', 'shortcode'] as $list_key) { | |
| 523 | + $params[$list_key] = NotificationX::get_instance()->normalize_multiple_value($params[$list_key]); | |
| 524 | + } | |
| 270 | 525 | $global = $params['global']; |
| 271 | 526 | $active = $params['active']; |
| 272 | 527 | $pressbar = $params['pressbar']; |
| 273 | 528 | $gdpr = $params['gdpr']; |
| @@ -306,8 +561,9 @@ | ||
| 306 | 561 | |
| 307 | 562 | $type = $settings['type']; |
| 308 | 563 | $source = $settings['source']; |
| 309 | 564 | |
| 565 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 310 | 566 | $should_continue = apply_filters("nx_entry_show_on_frontend_$source", false, $entry, $settings); |
| 311 | 567 | if ( $should_continue ) { |
| 312 | 568 | continue; |
| 313 | 569 | } |
| @@ -319,8 +575,9 @@ | ||
| 319 | 575 | if (!is_numeric($timestamp)) { |
| 320 | 576 | $entry['timestamp'] = $timestamp = is_string($timestamp) ? strtotime($timestamp) : false; |
| 321 | 577 | } |
| 322 | 578 | if ($timestamp && $display_from > $timestamp) { |
| 579 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 323 | 580 | if (apply_filters("nx_entry_display_$source", true, $entry, $settings)) { |
| 324 | 581 | continue; |
| 325 | 582 | } |
| 326 | 583 | } |
| @@ -325,19 +582,24 @@ | ||
| 325 | 582 | } |
| 326 | 583 | } |
| 327 | 584 | } |
| 328 | 585 | |
| 586 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 329 | 587 | $defaults = apply_filters("nx_fallback_data_$source", $_defaults, $entry, $settings); |
| 588 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 330 | 589 | $defaults = apply_filters('nx_fallback_data', $defaults, $entry, $settings); |
| 331 | 590 | |
| 332 | 591 | $entry = $this->apply_defaults($entry, $defaults); |
| 333 | 592 | $entry['image_data'] = $this->get_image_url($entry, $settings); |
| 334 | 593 | if (!empty($entry['title'])) { |
| 335 | - $entry['title'] = strip_tags(html_entity_decode($entry['title'])); | |
| 594 | + $entry['title'] = wp_strip_all_tags(html_entity_decode($entry['title'])); | |
| 336 | 595 | } |
| 337 | 596 | |
| 597 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 338 | 598 | $entry = apply_filters("nx_filtered_entry_$type", $entry, $settings); |
| 599 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 339 | 600 | $entry = apply_filters("nx_filtered_entry_$source", $entry, $settings); |
| 601 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 340 | 602 | $entry = apply_filters('nx_filtered_entry', $entry, $settings); |
| 341 | 603 | $entry = $this->link_url($entry, $settings, $params); |
| 342 | 604 | |
| 343 | 605 | // @todo shortcode |
| @@ -372,14 +634,19 @@ | ||
| 372 | 634 | } |
| 373 | 635 | |
| 374 | 636 | foreach ($result as &$group) { |
| 375 | 637 | foreach ($group as &$value) { |
| 638 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 376 | 639 | $value['entries'] = apply_filters("nx_filtered_data_{$value['post']['type']}", $value['entries'], $value['post'], $params); |
| 640 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 377 | 641 | $value['entries'] = apply_filters("nx_filtered_data_{$value['post']['source']}", $value['entries'], $value['post'], $params); |
| 642 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 378 | 643 | $value['entries'] = apply_filters('nx_filtered_data', $value['entries'], $value['post'], $params); |
| 644 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 379 | 645 | $value['post'] = apply_filters('nx_filtered_post', $value['post'], $params); |
| 380 | 646 | } |
| 381 | 647 | } |
| 648 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 382 | 649 | $result = apply_filters('nx_filtered_notice', $result, $params); |
| 383 | 650 | } |
| 384 | 651 | |
| 385 | 652 | if (!empty($pressbar)) { |
| @@ -398,8 +665,9 @@ | ||
| 398 | 665 | continue; |
| 399 | 666 | } |
| 400 | 667 | |
| 401 | 668 | // $settings['button_url'] = apply_filters("nx_notification_link_{$settings['source']}", $settings['button_url'], $settings); |
| 669 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 402 | 670 | $settings['button_url'] = apply_filters('nx_notification_link', $settings['button_url'], $settings); |
| 403 | 671 | if (!empty($settings['button_url']) && strpos($settings['button_url'], '//') === false && strpos($settings['button_url'], './') === false) { |
| 404 | 672 | $settings['button_url'] = "//{$settings['button_url']}"; |
| 405 | 673 | } |
| @@ -404,8 +672,9 @@ | ||
| 404 | 672 | $settings['button_url'] = "//{$settings['button_url']}"; |
| 405 | 673 | } |
| 406 | 674 | $bar_content = $this->get_bar_content($settings, false, $params); |
| 407 | 675 | if ($bar_content !== ' ' || !empty($settings['enable_countdown'])) { |
| 676 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 408 | 677 | $settings = apply_filters('nx_filtered_post', $settings, $params); |
| 409 | 678 | $result['pressbar'][$_nx_id]['post'] = $settings; |
| 410 | 679 | $result['pressbar'][$_nx_id]['content'] = $bar_content; |
| 411 | 680 | } |
| @@ -421,8 +690,9 @@ | ||
| 421 | 690 | if (!empty($_params['all_active'])) { |
| 422 | 691 | continue; |
| 423 | 692 | } |
| 424 | 693 | |
| 694 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 425 | 695 | $settings = apply_filters('nx_filtered_post', $settings, $params); |
| 426 | 696 | |
| 427 | 697 | $result['gdpr'][$_nx_id]['post'] = $settings; |
| 428 | 698 | $result['gdpr'][$_nx_id]['content'] = ""; |
| @@ -438,8 +708,9 @@ | ||
| 438 | 708 | if ( !$settings['enabled'] ) { |
| 439 | 709 | continue; |
| 440 | 710 | } |
| 441 | 711 | |
| 712 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 442 | 713 | $settings = apply_filters('nx_filtered_post', $settings, $params); |
| 443 | 714 | |
| 444 | 715 | $result['popup'][$_nx_id]['post'] = $settings; |
| 445 | 716 | $result['popup'][$_nx_id]['content'] = ""; |
| @@ -454,8 +725,9 @@ | ||
| 454 | 725 | $_nx_id = $settings['nx_id']; |
| 455 | 726 | if ( !$settings['enabled'] ) { |
| 456 | 727 | continue; |
| 457 | 728 | } |
| 729 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 458 | 730 | $settings = apply_filters('nx_filtered_post', $settings, $params); |
| 459 | 731 | $result['exit_intent'][$_nx_id]['post'] = $settings; |
| 460 | 732 | $result['exit_intent'][$_nx_id]['content'] = ""; |
| 461 | 733 | unset($_nx_id); |
| @@ -467,8 +739,9 @@ | ||
| 467 | 739 | } |
| 468 | 740 | |
| 469 | 741 | public function get_settings(){ |
| 470 | 742 | |
| 743 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 471 | 744 | $branding_url = apply_filters('nx_branding_url', NOTIFICATIONX_PLUGIN_URL . '?utm_source=' . esc_url(home_url()) . '&utm_medium=notificationx'); |
| 472 | 745 | $settings = [ |
| 473 | 746 | 'disable_powered_by' => Settings::get_instance()->get('settings.disable_powered_by'), |
| 474 | 747 | 'affiliate_link' => $branding_url, |
| @@ -540,8 +813,9 @@ | ||
| 540 | 813 | // if ($settings['hide_on_mobile'] && wp_is_mobile()) { |
| 541 | 814 | // continue; |
| 542 | 815 | // } |
| 543 | 816 | |
| 817 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 544 | 818 | $show_on_exclude = apply_filters('nx_show_on_exclude', false, $settings); |
| 545 | 819 | if ($show_on_exclude) { |
| 546 | 820 | continue; |
| 547 | 821 | } |
| @@ -568,8 +842,10 @@ | ||
| 568 | 842 | $bar_notifications[] = $return_posts ? $settings : $settings['nx_id']; |
| 569 | 843 | if (!empty($settings['elementor_id']) && class_exists('\Elementor\Plugin')) { |
| 570 | 844 | // @todo Find a function to only load css instead of building content. |
| 571 | 845 | \Elementor\Plugin::$instance->frontend->get_builder_content($settings['elementor_id'], false); |
| 846 | + } elseif (!empty($settings['gutenberg_id'])) { | |
| 847 | + $this->enqueue_gutenberg_bar_assets($settings['gutenberg_id']); | |
| 572 | 848 | } |
| 573 | 849 | } elseif($settings['source'] == 'gdpr_notification') { |
| 574 | 850 | $gdpr_notification[] = $return_posts ? $settings : $settings['nx_id']; |
| 575 | 851 | } elseif($settings['source'] == 'popup_notification') { |
| @@ -597,8 +873,9 @@ | ||
| 597 | 873 | |
| 598 | 874 | // @todo maybe combine two hooks. |
| 599 | 875 | |
| 600 | 876 | return apply_filters( |
| 877 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 601 | 878 | 'get_notifications_ids', |
| 602 | 879 | [ |
| 603 | 880 | 'global' => $global_notifications, |
| 604 | 881 | 'active' => $active_notifications, |
| @@ -634,8 +911,9 @@ | ||
| 634 | 911 | // @todo need to pass url. |
| 635 | 912 | $check_location = Locations::get_instance()->check_location($locations, $custom_ids, $taxonomy_ids); |
| 636 | 913 | } |
| 637 | 914 | |
| 915 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 638 | 916 | $check_location = apply_filters('nx_check_location', $check_location, $custom_ids, $show_on); |
| 639 | 917 | |
| 640 | 918 | if ($show_on == 'on_selected') { |
| 641 | 919 | // show if the page is on selected |
| @@ -701,8 +979,9 @@ | ||
| 701 | 979 | foreach ($ids as $id) { |
| 702 | 980 | if (!empty($notifications[$id])) { |
| 703 | 981 | $post = $notifications[$id]; |
| 704 | 982 | $global_query = " nx_id = " . absint($id) . " AND source = '" . esc_sql($post['source']) . "'"; |
| 983 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 705 | 984 | $_q = apply_filters("nx_get_entries_query_part_{$notifications[$id]['source']}",$global_query, $notifications[$id], $params ); |
| 706 | 985 | $query[$id] = " (" . $_q . ")"; |
| 707 | 986 | } |
| 708 | 987 | } |
| @@ -718,8 +997,9 @@ | ||
| 718 | 997 | } |
| 719 | 998 | if (!is_array($entries)) { |
| 720 | 999 | $entries = []; |
| 721 | 1000 | } |
| 1001 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 722 | 1002 | $entries = apply_filters('nx_frontend_get_entries', $entries, $ids, $notifications,$params); |
| 723 | 1003 | return $entries; |
| 724 | 1004 | } |
| 725 | 1005 | |
| @@ -738,9 +1018,11 @@ | ||
| 738 | 1018 | if (empty($post['link_type']) || $post['link_type'] === 'none') { |
| 739 | 1019 | $link = ''; |
| 740 | 1020 | } |
| 741 | 1021 | |
| 1022 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 742 | 1023 | $link = apply_filters("nx_notification_link_{$post['source']}", $link, $post, $entry, $params); |
| 1024 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 743 | 1025 | $entry['link'] = apply_filters('nx_notification_link', $link, $post, $entry, $params); |
| 744 | 1026 | return $entry; |
| 745 | 1027 | } |
| 746 | 1028 | |
| @@ -789,9 +1071,11 @@ | ||
| 789 | 1071 | } |
| 790 | 1072 | } |
| 791 | 1073 | |
| 792 | 1074 | $image_data['classes'] = $image_type; |
| 1075 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 793 | 1076 | $image_data = apply_filters("nx_notification_image_$source", $image_data, $data, $settings); |
| 1077 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 794 | 1078 | $image_data = apply_filters('nx_notification_image', $image_data, $data, $settings); |
| 795 | 1079 | |
| 796 | 1080 | if (!empty($image_data['url'])) { |
| 797 | 1081 | return $image_data; |
| @@ -835,8 +1119,9 @@ | ||
| 835 | 1119 | 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'])) { |
| 836 | 1120 | $entries = array_slice($entries, 0, $post['display_last']); |
| 837 | 1121 | } |
| 838 | 1122 | foreach ($entries as $index => $entry) { |
| 1123 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 839 | 1124 | $_entry = apply_filters("nx_frontend_keep_entry_{$post['source']}", [ |
| 840 | 1125 | 'nx_id' => $entry['nx_id'], |
| 841 | 1126 | 'timestamp' => isset($entry['timestamp']) ? $entry['timestamp'] : Helper::current_timestamp($entry['updated_at']), |
| 842 | 1127 | 'updated_at' => isset( $entry['updated_at'] ) ? $entry['updated_at'] : '', |
| @@ -929,8 +1214,10 @@ | ||
| 929 | 1214 | 'is_elementor', |
| 930 | 1215 | 'is_inline', |
| 931 | 1216 | 'ld_course_list', |
| 932 | 1217 | 'ld_product_control', |
| 1218 | + 'activecampaign_form', | |
| 1219 | + 'brevo_list', | |
| 933 | 1220 | 'mailchimp_list', |
| 934 | 1221 | 'max_stock', |
| 935 | 1222 | 'nx-bar_with_elementor', |
| 936 | 1223 | 'nx-bar_with_elementor-remove', |
| @@ -977,14 +1264,15 @@ | ||
| 977 | 1264 | |
| 978 | 1265 | public function get_bar_content($settings, $suppress_filters = false, $params = []){ |
| 979 | 1266 | $bar_content = PressBar::get_instance()->print_bar_notice($settings); |
| 980 | 1267 | if(!$suppress_filters){ |
| 1268 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context. | |
| 981 | 1269 | $bar_content = apply_filters("nx_filtered_data_{$settings['source']}", $bar_content, $settings, $params); |
| 982 | 1270 | } |
| 983 | 1271 | |
| 984 | 1272 | // checking if content is empty |
| 985 | 1273 | $_bar_content = str_replace(array("\r\n", "\n", "\r"), '', $bar_content); |
| 986 | - $_bar_content = trim(strip_tags($_bar_content)); | |
| 1274 | + $_bar_content = trim(wp_strip_all_tags($_bar_content)); | |
| 987 | 1275 | if (empty($_bar_content) && !empty($settings['enable_countdown'])) { |
| 988 | 1276 | $bar_content = ' '; |
| 989 | 1277 | } |
| 990 | 1278 | return $bar_content; |