diff --git a/includes/Core/PostType.php b/includes/Core/PostType.php index a82f0f37..b60c2f2b 100644 --- a/includes/Core/PostType.php +++ b/includes/Core/PostType.php @@ -137,6 +137,10 @@ public function get_localize_scripts() { 'admin' => NOTIFICATIONX_ADMIN_URL, 'public' => NOTIFICATIONX_PUBLIC_URL, 'common' => NOTIFICATIONX_COMMON_URL, + // Used by the PressBar "Custom" design preview to render the actual + // Elementor-built bar in an iframe (see PressBar::render_elementor_bar_preview()). + 'home' => home_url( '/' ), + 'bar_preview_nonce' => wp_create_nonce( 'nx_bar_preview' ), ]; $tabs = apply_filters( 'nx_builder_configs', $tabs ); diff --git a/includes/Extensions/PressBar/PressBar.php b/includes/Extensions/PressBar/PressBar.php index 55d01176..f083ca64 100644 --- a/includes/Extensions/PressBar/PressBar.php +++ b/includes/Extensions/PressBar/PressBar.php @@ -52,6 +52,9 @@ public function __construct() { parent::__construct(); add_action('init', [$this, 'register_post_type']); add_action('init', [$this, 'load_plugin_dependencies'], -1); + // Renders the Elementor-built bar standalone so the admin Design preview + // can show the real design instead of a static theme thumbnail. + add_action('template_redirect', [$this, 'render_elementor_bar_preview']); add_filter( 'get_edit_post_link', function($link, $id){ $post = get_post( $id ); if ( $post && 'nx_bar' === $post->post_type && class_exists('\Elementor\Plugin') ) { @@ -2094,6 +2097,134 @@ public function add_scripts($settings, $params){ return $settings; } + /** + * Renders the Elementor-built bar in a clean, standalone page so the admin + * Design preview can show the ACTUAL Elementor design in an iframe instead of + * a static theme thumbnail. + * + * Triggered on the frontend via `?nx_bar_preview={elementor_id}&_wpnonce=...`. + * It renders the same content as the live bar (get_builder_content_for_display) + * but prints ONLY Elementor's own stylesheets and no scripts / no + * wp_head()/wp_footer() — so the preview shows the bar and nothing else (no + * admin toolbar, no chat widgets, no other notifications). + * + * @hooked template_redirect + * @return void + */ + public function render_elementor_bar_preview() { + if ( ! isset( $_GET['nx_bar_preview'] ) ) { + return; + } + + $elementor_id = absint( $_GET['nx_bar_preview'] ); + $nonce = isset( $_GET['_wpnonce'] ) ? sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ) : ''; + + // Only logged-in users who can manage NotificationX may render the preview. + if ( ! $elementor_id || ! wp_verify_nonce( $nonce, 'nx_bar_preview' ) || ! current_user_can( 'edit_notificationx' ) ) { + status_header( 403 ); + exit; + } + + if ( ! class_exists( '\Elementor\Plugin' ) ) { + status_header( 404 ); + exit; + } + + $post = get_post( $elementor_id ); + if ( ! $post || 'nx_bar' !== $post->post_type || 'publish' !== get_post_status( $elementor_id ) ) { + status_header( 404 ); + exit; + } + + $frontend = \Elementor\Plugin::$instance->frontend; + + // Populate the style queue like the live frontend does, WITHOUT firing every + // plugin's wp_enqueue_scripts (which would pull in chat widgets, other + // popups, etc.). We render only Elementor's own assets. + $frontend->register_styles(); + $frontend->enqueue_styles(); + + // Same render used on the live site by print_bar_notice(); `true` inlines + // the document's generated CSS so the design styling always travels with it. + // This also enqueues the per-widget (image/heading/button) stylesheets. + $content = $frontend->get_builder_content_for_display( $elementor_id, true ); + + nocache_headers(); + + // Print ONLY Elementor-related stylesheets (base framework, global kit, + // per-widget CSS, Google Fonts). No third-party CSS, no scripts at all, + // and no wp_head()/wp_footer(). + $print_elementor_styles = function () { + $styles = wp_styles(); + if ( ! $styles ) { + return; + } + $styles->all_deps( $styles->queue ); + foreach ( $styles->to_do as $handle ) { + $reg = isset( $styles->registered[ $handle ] ) ? $styles->registered[ $handle ] : null; + $src = ( $reg && $reg->src ) ? strtolower( (string) $reg->src ) : ''; + $h = strtolower( $handle ); + $allow = ( strpos( $h, 'elementor' ) === 0 ) + || ( strpos( $h, 'e-' ) === 0 ) + || ( strpos( $h, 'eael' ) === 0 ) + || ( strpos( $h, 'font-awesome' ) === 0 || strpos( $h, 'fontawesome' ) === 0 ) + || ( strpos( $h, 'google-font' ) === 0 ) + || ( $src && strpos( $src, '/elementor/' ) !== false ) + || ( $src && strpos( $src, 'uploads/elementor' ) !== false ) + || ( $src && strpos( $src, 'essential-addons' ) !== false ) + || ( $src && ( strpos( $src, 'fonts.googleapis' ) !== false || strpos( $src, 'fonts.gstatic' ) !== false ) ); + if ( $allow ) { + $styles->do_item( $handle ); + } + } + }; + ?> + +> + + + + + + + + + + + + id, true, $fields['image-section']); return $fields; diff --git a/nxdev/notificationx/fields/NxBarPresets.jsx b/nxdev/notificationx/fields/NxBarPresets.jsx index 2a647b7a..d674cff8 100644 --- a/nxdev/notificationx/fields/NxBarPresets.jsx +++ b/nxdev/notificationx/fields/NxBarPresets.jsx @@ -9,12 +9,16 @@ const NxBarPresets = () => { const basePath = `${assets.admin}/images/extensions/themes`; + // Elementor previews render the live design in an iframe (see + // PressBar::render_elementor_bar_preview()); everything else stays an . + const isElementorPreview = values?.is_elementor && values?.elementor_id; + const previewUrl = useMemo(() => { if (!values) return ''; - // Elementor Path - if (values.is_elementor && values.elementor_id && values.elementor_bar_theme) { - return `${basePath}/bar-elementor/${values.elementor_bar_theme}.jpg`; + // Elementor: live preview of the actual Elementor-built bar. + if (values.is_elementor && values.elementor_id) { + return `${assets.home}?nx_bar_preview=${values.elementor_id}&_wpnonce=${assets.bar_preview_nonce || ''}`; } // Gutenberg Path @@ -32,7 +36,7 @@ const NxBarPresets = () => { // Fallback return values.preview_url || ''; - }, [values, basePath]); + }, [values, basePath, assets]); const showEmptyState = values?.is_gutenberg && @@ -48,8 +52,20 @@ const NxBarPresets = () => { ) : (
-
- +
+ {isElementorPreview ? ( +