Make WordPress Core

Opened 6 weeks ago

Closed 5 weeks ago

Last modified 5 weeks ago

#63076 closed defect (bug) (fixed)

Site Editor: Remove admin bar from site preview for classic theme

Reported by: wildworks's profile wildworks Owned by: joemcgill's profile joemcgill
Milestone: 6.8 Priority: normal
Severity: normal Version:
Component: Editor Keywords: has-patch has-unit-tests
Focuses: Cc:

Description

Originally reported on https://github.com/WordPress/gutenberg/issues/69474

Starting with 6.8, classic themes with editor-style support or theme.json file can use StyleBook. At the same time, the root page of the site editor shows a front-end preview of the theme.

To remove the admin bar from this preview, there is JS code to remove it after the iframe content is loaded.

This JS code runs after the site is loaded, so the admin bar appears for a moment on initial load.

This issue can be solved by injecting CSS, as suggested in this Gutenberg PR, but other approaches have been proposed to use PHP hooks to not show the admin bar in the first place.

Using the show_admin_bar hook is probably the best solution, but I'd be happy to discuss what the best approach is.

Attachments (1)

Screenshot 2025-03-11 at 8.13.36 AM.png (349.9 KB) - added by joemcgill 5 weeks ago.
Classic Theme Site Editor design view w/ QM

Download all attachments as: .zip

Change History (23)

#1 @audrasjb
6 weeks ago

  • Keywords needs-patch added

Yes indeed a PHP solution seems doable. Using a GET parameter is probably the easiest way to fix the issue with a server side solution.

This ticket was mentioned in PR #8475 on WordPress/wordpress-develop by @wildworks.


6 weeks ago
#2

  • Keywords has-patch has-unit-tests added; needs-patch removed

Trac ticket: https://core.trac.wordpress.org/ticket/63076

This PR hides the admin bar if the get parameter wp_site_preview=1 is present.

This PR is needed to hide the admin bar from the classic theme site preview in the site editor.

This PR cannot yet be tested in the site editor, but can be tested on the frontend.

@wildworks commented on PR #8475:


6 weeks ago
#3

I'm wondering whether the JS code that disables interactive elements should also be moved to this PR and output as an inline JS.

@presstoke commented on PR #8475:


6 weeks ago
#4

I'm wondering whether the JS code that disables interactive elements should also be moved to this PR and output as an inline JS.

I think it’s a good idea because otherwise the elements can be interactive for a moment before the load event. Yet I also think we may want the flexibility to modify that logic without having to change core code. If so, we might make the inline JS merely `post a message` that the parent window can listen for.

@wildworks commented on PR #8475:


6 weeks ago
#5

@stokesman Thanks for the feedback!

I'm not familiar with the approach using postMessage, so could you provide a sample implementation?

By the way, I came up with a different approach that doesn't implement any custom JS code and simply wraps the iframe element in a Disabled component, what do you think?

This approach is used in various places, including the pattern preview.

@wildworks commented on PR #8475:


6 weeks ago
#6

By the way, I came up with a different approach that doesn't implement any custom JS code and simply wraps the iframe element in a Disabled component, what do you think?

This approach didn't work 😅 Because the <Disable> makes the iframe content unscrollable.

@wildworks commented on PR #8475:


6 weeks ago
#7

I'm wondering whether the JS code that disables interactive elements should also be moved to this PR and output as an inline JS.

Perhaps this can be addressed in a follow-up?

@presstoke commented on PR #8475:


6 weeks ago
#8

I'm not familiar with the approach using postMessage, so could you provide a sample implementation?

The inline script would be something like this:

add_action( 'wp_print_footer_scripts', function() {
                echo '<script>', <<<JS
                        if ( window.parent ) {
                                window.parent.postMessage( 'preview dom available' );
                        }
                JS, '</script>';
        } );

The only important part of that is that it appears after any other elements we’ll want to manipulate through DOM methods.

Then the Gutenberg side would listen for the message with something like this:

const messageEffect = useRefEffect(
                ( node ) => {
                        const { defaultView } = node.ownerDocument;
                        const onMessage = ( event ) => {
                                if (
                                        event.origin === siteUrl &&
                                        event.data === 'preview dom available'
                                ) {
                                        // Make interactive elements unclickable…
                                }
                        };
                        const { defaultView } = node.ownerDocument;
                        defaultView.addEventListener( 'message', onMessage );
                        return () =>
                                defaultView.removeEventListener( 'message', onMessage );
                },
                [ siteUrl ]
        );
        // attaching the ref callback to the iframe would follow…

That has to be done through the ref callback since it seems React doesn’t do onMessage. I'll go ahead and post a working example diff in the thread that started this.

#9 @faisal03
5 weeks ago

Test Report

As mentioned in the PR description, this change cannot yet be tested in the Site Editor. However, I have tested it on the frontend, and it works as expected. ✅

  • When accessing /?wp_site_preview=1, the admin bar is successfully hidden ✅
  • When accessing / or /?wp_site_preview=2, the admin bar remains visible as expected ✅
Last edited 5 weeks ago by faisal03 (previous) (diff)

@joemcgill
5 weeks ago

Classic Theme Site Editor design view w/ QM

#10 @joemcgill
5 weeks ago

Thanks @wildworks! While testing the current PR, I noticed that this not only affects the admin bar, but also other front-end code gets loaded into this preview. For example, in my testing, the Query Monitor panel is loading in the preview (cc: @johnbillion).

While the links and form elements do not seem to be functional, I suspect that things like cookie dialogues or ads might also get loaded in these previews, so we may need to find a more wholistic way of dealing with these concerns.

There may be some prior art in the way the Customizer loads front end previews that we could borrow from here.

#11 @joemcgill
5 weeks ago

  • Owner set to joemcgill
  • Status changed from new to reviewing

#12 @johnbillion
5 weeks ago

Query Monitor specifically hides itself from Customiser previews, the fact it doesn't appear there isn't anything to do with core behaviour. Same for a few other places such as the plugin info modals.

#14 @joemcgill
5 weeks ago

Thanks @johnbillion. I do think setting IFRAME_REQUEST for these previews might be exactly right. It's also worth considering adding a helper similar to is_customize_preview() for the site editor that could be incorporated directly into is_admin_bar_showing() rather than needing to filter the return value.

#15 @wildworks
5 weeks ago

Thanks for the feedback everyone. Setting IFRAME_REQUEST seems to work as expected.

Note that this PR cannot yet be tested in the Site Editor. This is because Gutenberg PR (https://github.com/WordPress/gutenberg/pull/69514) was not automatically cherry-picked. I would like to address this problem separately.

@wildworks commented on PR #8475:


5 weeks ago
#16

@stokesman We found that some plugins load code into the preview. To solve this problem, it seems best to define IFRAME_REQUEST instead of filtering show_admin_bar hook. See trac ticket for more details.

#17 @wildworks
5 weeks ago

I prepared two PRs on Gutenberg:

If using IFRAME_REQUEST constant is an ideal approach and once committed to the core, I would like to move forward these two PRs.

@Mamaduka commented on PR #8475:


5 weeks ago
#18

The capability check makes sense, but I don't know if nonce is necessary. Unlike theme previews, this flag just renders the site front-end like iframe (which is already accessible when public); it doesn't override anything else.

@wildworks commented on PR #8475:


5 weeks ago
#19

I would be happy if this PR is committed before Beta 3. I think the following two suggestions could be considered in a follow-up:

  • Use inline JS to make interactive elements unclickable instead of the onLoad prop of the iframe element
  • Use a nonce for the value of the wp_site_preview query string parameter

@peterwilsoncc commented on PR #8475:


5 weeks ago
#20

The capability check makes sense, but I don't know if nonce is necessary. Unlike theme previews, this flag just renders the site front-end like iframe (which is already accessible when public); it doesn't override anything else.

Fair point, that works for me.

#21 @joemcgill
5 weeks ago

  • Resolution set to fixed
  • Status changed from reviewing to closed

In 60003:

Editor: Support site preview mode for the Site Editor.

This allows the Site Editor to load a preview of the site as an IFRAME_REQUEST by checking for a wp_site_preview query param. By setting the IFRAME_REQUEST constant when loading the preview, the site's admin bar and some third party plugin overlays will not be shown in the preview.

Props wildworks, joemcgill, peterwilsoncc, presstoke, mamaduka, johnbillion, faisal03.
Fixes #63076.

#22 @joemcgill
5 weeks ago

Noting for any reviewers that the use of this wp_site_preview query param will be handled on in the @wordpress/edit-site package after https://github.com/WordPress/gutenberg/pull/69536 is merged.

Note: See TracTickets for help on using tickets.