wordpress-playground icon indicating copy to clipboard operation
wordpress-playground copied to clipboard

Optionally do not use playground frame

Open threadi opened this issue 1 year ago • 2 comments

In my WordPress plugin, I use a JavaScript in some essential places, which addresses the top frame to load a specific page to display the content updated by the plugin:

top.location.href=...

The background is that the plugin uses these functions in various PageBuilders, some of which use a frameset (e.g. Divi). For this reason I have to reload the top frameset here. This has worked successfully for users of the plugin for a long time. But not in the Playground.

In the Playground, started via the preview button, this now leads to the Playground being restarted as a whole and a new Playground session being started.

Would it be possible to add an option in blueprint.js to dispense with the Playground frameset when clicking on the preview button? So that you are forwarded directly to it?

If this is not possible, I would have to adapt my plugin for compatibility with the Playground so that the relevant PageBuilder is automatically recognized before I call this JavaScript. Somehow I have the uneasy feeling that this would be a customization of the plugin for the Playground.

threadi avatar May 20 '24 10:05 threadi

@threadi would you be able to provide a reproduction link or a Blueprint? It could be with your plugin or a minimal one, just so I could understand better. The sandboxing should prevent the site inside Playground from accessing or modifying top.href which is why I’m confused.

adamziel avatar May 20 '24 16:05 adamziel

Gladly. Here it is: https://playground.wordpress.net/?plugin=easy-language&blueprint-url=https://wordpress.org/plugins/wp-json/plugins/v1/plugin/easy-language/blueprint.json?rev=3079487

Don't be surprised, the German language pack will be installed. After the playground loads, go to "Pages", click on a "+" in the table and then click on "Simplify with ..". This will simplify the texts of the page. If everything worked, a confirmation dialog will appear containing the problematic links: "Show in frontend", "Edit" and "Cancel". All 3 are each connected to their own JavaScript events. This dialog is also displayed within the block editor, for example (also in Elementor, Divi etc. where I unfortunately have to do it that way).

However: I just tested this more extensively and noticed different behavior for each event. With the two blue buttons (whose target is top.location.href="xy") this error occurs in the console:

react-dom.min.js?ver=18.2.0:10 Uncaught DOMException: Failed to set the 'href' property on 'Location': The current window does not have permission to navigate the target frame to 'https://playground.wordpress.net/scope:0.7213987874346102/?page_id=10'.

The line in question is this in my script:

react__WEBPACK_IMPORTED_MODULE_0__.createElement)(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__.Button, {
 key: button.text,
 variant: button.variant,
 onClick: ()=>eval(button.action)
 }, button.text)

The cancel button has this callback:

location.reload();

And only with this does it actually lead to a complete reload of the Playground frameset.

By the way, the repository of the plugin in question is here: https://github.com/threadi/easy-language I used this script for the dialogs: https://github.com/threadi/wp-easy-dialog

If you have any further questions, please let me know :)

Great work, that's all I can say again and again ^^

threadi avatar May 20 '24 18:05 threadi

Thank you for the additional context! If Playground allowed changing top.location.href, it would redirect the entire top-level page and destroy the Playground instance, so that wouldn't be useful. Everything is running in the context of the currently loaded page and I'm not aware of any way of preserving the Playground runtime across page reloads – therefore we also can't conditionally disable the Playground frameset

Ideally, window.top would refer to the iframed Playground window object, not the actual top-level window. AFAIK we can't do that with iframes, but we can with fenced frames. The only problem is Safari and Firefox don't support them yet so this issue may need to wait until they do – I'd rather not use iframes in some browsers and fencedframes in others.

If this is not possible, I would have to adapt my plugin for compatibility with the Playground so that the relevant PageBuilder is automatically recognized before I call this JavaScript.

This might be the best way forward for now.

Somehow I have the uneasy feeling that this would be a customization of the plugin for the Playground.

I see how it might feel this way. My thinking is, while this would help with Playground, it would also make your plugin compatible with embedding in all sorts of iframes.

adamziel avatar Jul 16 '24 16:07 adamziel

Thank you for your feedback. I had feared something like that.

Why I use top.location.href at all is Divi. There I actually have to reload the all surrounding when clicking and not the iframe I am in.

I'm just thinking about making the link target possibly dependent on the environment. There could theoretically be other situations where I use the modal I'm talking about here where there is also a frameset, which, as with the Playground, should not be broken.

So one more question: is there a way for a plugin to recognize that it is running inside the playground? If so, how?

threadi avatar Jul 16 '24 19:07 threadi

So one more question: is there a way for a plugin to recognize that it is running inside the playground? If so, how?

@threadi, one option is to define a special const as a hint and check for its existence in your plugin code: https://wordpress.github.io/wordpress-playground/blueprints-api/steps-shorthands#definewpconfigconsts

Does that answer all your questions?

brandonpayton avatar Jul 18 '24 23:07 brandonpayton

Yes, thanks, I was able to solve it today. The test in the Playground ran successfully. The update of the relevant plugin in the repository will be available in a few days.

For fellow readers: it's better to do without top.location if you want to use your plugin in the Playground. I have now installed it so that top.location is only used when Divi is activated, as I need top.location for Divi to reload the page.

threadi avatar Jul 29 '24 16:07 threadi