Developing an in-browser preview and editing interface for L&L

I’ve been working on an idea, a tool for sharing L&L snippets that can be edited and run in the browser.

Snippet Player - https://play.tangible.one/snippet/

It’s a static site with a template editor and a preview pane. It runs an empty WordPress site that’s created purely in the browser, a new site on every visit. As you edit the template, it generates a unique shareable link with the exported template embedded in the URL.

Here’s a link to demonstrate the dialog template above. I’m curious if such a long URL will actually work.

I’m hoping this tool might grow and improve to be of practical use, for example, sharing runnable snippets in this discussion forum.


A related project is in progress for shareable demo sites.

Tangible Playground - https://play.tangible.one/

It uses the same technique: a static site that creates a new WordPress site in the browser on every visit.

There’s a full site import/export button on the top right. Currently the zip package is about 7MB which is a bit hefty for email attachment or posting on a forum. Also, for now this zip package is specific to the Playground environment, because it contains an SQLite database; it cannot be imported into, or exported from, a regular WP site.

These experiments are powered by WordPress on WebAssembly, which can run self-contained in the browser (and on the server side with Node.js, or even in the code editor).

Soon I think we’ll see more runnable, editable code snippets with live preview within documentation and articles. And I imagine instant demo sites with pre-installed plugins/themes, demo content, blueprints and scenarios.

6 Likes

Would it make sense to pre-populate the database a bit to make it easier to test loop types that rely on more data being present?

Yes, I agree, some demo content would be useful for the Snippet Player.

I found a few example WordPress export files in WXR/XML format, like the Theme Test Data, and figured out how to import the content into the Playground data file. The content isn’t that great though - I’d prefer something closer to what Faker.js or FakerPress generates.

The wp.data file loaded in the browser is currently about 10 MB, which includes all of WordPress and L&L bundled. There are some larger files in the plugin, like script source maps, which can be removed to make the bundle smaller. With the demo content, the size gets to 26 MB, probably from images. That takes a while to load (but then cached for next visit), which may be acceptable for the Snippet Player.

But for the main tool, Tangible Playground, it’s better to have an empty site with no content, because it’s meant for users to start from scratch and import/export an entire site. A use case I’m picturing is for people to demonstrate bugs or template examples on a blank site, then export and share the minimal site package. With the demo content, the export zip package gets too big for comfortably sharing.

A technical difficulty I’m solving at the moment, is how to create two separate “site starter” data files: an empty one for the site playground, and a full one for the snippet player with demo content.

This in-browser WP playground/sandbox concept is turning out to be a good catalyst to envision the next steps for the Template Editor and Design System. It would be a perfect way to try out and further develop the new editor based on CodeMirror 6, with a live preview as you edit the template/snippet.

2 Likes

I learned that Discourse has a setting for “allowed iframes”, so I added play.tangible.one.

I’ll try embedding a Snippet Player…

<iframe width="100%" height="420" src="https://play.tangible.one/snippet/?import=%7B%22post_types%22%3A%7B%22tangible_layout%22%3A%5B%7B%22id%22%3A2578%2C%22name%22%3A%22dialog-example%22%2C%22title%22%3A%22Dialog%20Example%22%2C%22content%22%3A%22%3CLoop%20type%3Dpost%3E%5Cn%20%20%3Cbutton%20onclick%3D%5C%22document.getElementById('postDialog%7BField%20id%7D').showModal()%3B%5C%22%3E%5Cn%20%20%20%20%3CField%20title%20%5C%2F%3E%3C%5C%2Fbutton%3E%5Cn%5Cn%20%20%3Cdialog%20id%3D%5C%22postDialog%7BField%20id%7D%5C%22%20aria-labelledby%3D%5C%22dialog_title%7BField%20id%7D%5C%22%20aria-describedby%3D%5C%22dialog_description%7BField%20id%7D%5C%22%20%3E%5Cn%20%20%20%20%3Ch2%20id%3D%5C%22dialog_title%7BField%20id%7D%5C%22%3E%3CField%20title%20%5C%2F%3E%3C%5C%2Fh2%3E%5Cn%20%20%20%20%3Cimg%20src%3D%5C%22%7BField%20image_url%7D%5C%22%20width%3D150%3E%5Cn%20%20%20%20%3Cp%20id%3D%5C%22dialog_description%7BField%20id%7D%5C%22%3E%5Cn%20%20%20%20%20%20%3CField%20excerpt%20auto%3Dtrue%20%5C%2F%3E%5Cn%20%20%20%20%3C%5C%2Fp%3E%5Cn%20%20%20%20%3Cdiv%3E%5Cn%20%20%20%20%20%20%3Cbutton%20id%3D%5C%22close_dialog%5C%22%20onclick%3D%5C%22document.getElementById('postDialog%7BField%20id%7D').close()%3B%5C%22%3EClose%3C%5C%2Fbutton%3E%5Cn%20%20%20%20%3C%5C%2Fdiv%3E%5Cn%20%20%3C%5C%2Fdialog%3E%5Cn%3C%5C%2FLoop%3E%22%2C%22style%22%3A%22%22%2C%22script%22%3A%22%22%2C%22assets%22%3A%5B%5D%2C%22location%22%3A%7B%22description%22%3A%22Entire%20Site%22%2C%22rule_groups%22%3A%5B%5B%7B%22field%22%3A%22all%22%7D%5D%5D%7D%2C%22theme_position%22%3A%22%22%2C%22theme_header%22%3A%22%22%2C%22theme_footer%22%3A%22%22%2C%22controls_template%22%3A%22%22%2C%22controls_settings%22%3A%5B%5D%2C%22universal_id%22%3A%22d95f1498d6c64e85ad3c541938296711%22%2C%22menu_order%22%3A0%2C%22post_status%22%3A%22publish%22%2C%22taxonomies%22%3A%7B%22tangible_template_category%22%3A%5B%5D%7D%7D%5D%7D%2C%22shared_assets%22%3A%5B%5D%2C%22taxonomies%22%3A%5B%5D%7D"></iframe>

OK, needs some improvement but interesting proof of concept. I added a “Copy iframe” button so it’s easy to paste into Discourse.

1 Like

I can imagine these embeds getting out of hand if several were embedded in the same discussion thread. We probably need to take an approach similar to best practices on embedded YouTube videos of having a preview image that only loads in the YouTube embed when clicked on to avoid loading up a bunch of stuff that may or may not be used. I guess that would need to be done on the Discourse side somehow, perhaps a custom extension.

embeds getting out of hand

True, I already saw this with just two embed links, the page starts to get heavy and slow to load.

best practices on embedded YouTube videos of having a preview image that only loads in the YouTube embed when clicked on to avoid loading up a bunch of stuff that may or may not be used.

I wonder if the YouTube embed iframe does this by default, to return a light-weight preview screen first, then start loading the video when clicked.

Mm, but the Snippet Player and the Playground have no way to generate a preview image unless the WordPress environment is loaded, to be able to render the template / visited page. And the template preview needs L&L and demo content.

As a small improvement, I added the attribute loading="lazy" in the generated iframe code, to defer loading until it’s in viewport.


Well, embedding live snippets in Discourse is one possible use case. It may turn out that shareable links are more practical for that purpose. Or we need to develop more specific functionality to provide better embeds.

But the general idea of an online tool to create and share snippets and build entire sites with L&L/Blocks to import/export - I think it has potential. It’s convenient that it’s just a static site, completely public with no login necessary - that makes it easy for anyone to try WordPress+L&L and learn how it works. Eventually we’ll probably want server features, so we can login and have access to a cloud library of blocks/templates/snippets - and site blueprints with demo content.

Speaking of demo content, you can see in the snippet player above that I added some posts and featured images. I wish it had more variety though - I think it’s inevitable that we will integrate the Faker library somehow, to generate demo content on demand - either automatically for the snippet player, or by some kind of template definitions (“generate 50 users with these custom fields”).

1 Like

a preview image that only loads in the embed when clicked

It’s being solved here:

When the corresponding pull request is merged, the Playground will support an option to load only a Start button at first, then load the actual embed when it’s clicked.

By the way, the issue report was posted by the founder of Yoast, who wrote a plugin Playground Embedder that provides a shortcode to embed the WP Playground.

1 Like

I’m realizing that this could be a much cleaner way to add examples to the documentation. Instead of writing the examples inline within the documentation (which makes things look cluttered and a little overwhelming for new users), I could just link out to a playground instance where the user could actually try modifying the code themselves. Maybe during the eventual move over to Docusaurus we can make that happen.

I was also thinking about how this could be used to make an interactive L&L tutorial, but loading up a whole new WordPress instance for each lesson seems a little overkill hahaha!

2 Likes

Yes, I was going to recommend pretty much this exact thing a while ago but I assumed it would big job so never bothered.

It would be handy just to have an editor available in the docs to try out code snippets and see how they behave. Would just have to call out the tags that are supported by the WP instance.

It would also be a good marketing tool as people will see how easy it is to generate content with L&L. :slight_smile:

2 Likes

I was working on a app building project for a client using vue js then came across a plugin call swiper ended up using this covering 70%. I was able to complete the whole project in a short time because swiper has a really efficient documentation site that enable to fire up web based virtual environment to display every examples of its features and use case, in this case it displays a VScode-alike interface. Pivoting from this example, I can see perhaps L&L can do the same approach using WP instead of VScode.

The demo page of swiper: https://swiperjs.com/demos

– Each demo presented with multiple links for different frameworks like react, vue, core(for svelte and solidjs)


**After the completion of vue js project, I now restructuring my wp project that uses L&L like how I did with vue js. Layout template = main component parent, template = components (child), template attr = props, come to think about it, L&L does look like vue js in comparison.

2 Likes

Hey @eliot ,

Some people in the community have started playing around with these previews and we’re quickly finding that virtually any template we attempt to create winds up hitting the URL character limit.
It seems like we’ll have to develop a solution that gets around that limitation before we can start making wide us of this in the docs and snippet library.

Of course the advantage of the current system is that it requires no storage on our end. Perhaps the solution is to have a parameter with a URL to a public Github gist or bitbucket snippet so anyone can just point it to their file there?

any template we attempt to create winds up hitting the URL character limit.

Oh, that’s too bad - I wasn’t sure what the limit of URL length was, but I’m not surprised that it turned out to be impractical to embed larger templates.

The import parameter used for the JSON string also accepts a URL to a JSON file - as long as the server has CORS enabled in their response headers.

The feature isn’t so easy to use yet, the link needs to be put together manually.

For now, the base URL is:

https://play.tangible.one/snippet/?import=

I made a quick Bitbucket repo to serve the static files - but it’s not so convenient of a workflow: from the repo URL, click the three dots icon, then Add File; copy & paste the template export JSON, and make a commit; click on the uploaded file, and the three dots icon, then Open Raw to get the JSON file’s URL. Add that to the base URL, and it’s:

https://play.tangible.one/snippet/?import=https://bitbucket.org/tangibleinc/snippets/raw/e73f0b0b61197a43934f0364df3fb36e018da38b/dialog-example-202306241458.json

Visiting the link, I see that it immediately replaces the file URL after import= with a JSON string. That’s not intentional - it can probably be improved to treat file URLs as the default method of import/export. It’d be good to add an “Import from URL” button.

It’s not as quick and easy to share a template this way, compared to embedding the JSON in the URL directly. Currently, from the snippet player, I export the template as JSON file, upload it to a server, then create the link manually. But I suppose the only way to make it simpler is to provide a central server to save/load snippets.

I might be able to get a bit more capacity out of the direct URL embed method by zip compressing the export file (and convert to base64 string to safely pass in URL query string).


By the way, I saw that the creator of Yoast plugin put an embedded playground on their website.

Inspired by this, I started a new page on the L&L site.

https://loopsandlogic.com/playground/

For now it’s an iframe embed of the standard WordPress Playground, as described in: Build your first app: Embed WordPress on your website.

2 Likes

It would be great to have run/edit-able code examples in the documentation. I picture something like a CodePen iframe embed, where you can see the source code and its preview - the result of running the code, or rendering the template - side by side (or above/below).

With the current iframe embed method, it’s a whole WordPress site for every code example - and there can be many examples on a tutorial page. It’s fairly common for people to embed multiple iframes like Codepen examples, but I think they do tend to weigh down the page, even with browser-cached static files and the iframe attribute loading="lazy".

A more scalable solution would be to have a single Playground instance that runs all the examples on the page. It could be implemented as a dynamic tag or Gutenberg block for the L&L site articles, and as a React component for the docs site (Docusaurus: MDX and React).


I like these screenshots from WordPress Playground’s public site (different from its dev docs site).

Each code example is a live editor with a preview under it. They’re planning to embed these interactive examples on learn.wordpress.org.

There’s a VS Code extension for WordPress Playground, which starts a new WP site instance right in the editor for plugin/theme and site development. I’d love to have a playground preview integrated in the new template editor.

It would be so convenient and accessible to have an instant WP site with L&L installed, right in the browser. I can see it growing into an online development tool with import/export of templates and entire sites (technically feasible but currently doesn’t support import/export into regular sites, due to the playground using an SQLite database instead of MySQL).


Thanks for sharing this, that’s a good reference I’d like to study deeper.

L&L does look like vue js in comparison

It’s part of a larger trend in web development to extend HTML into a template language with dynamic features - like React, Vue.js, Angular; and more recently, a different direction with HTMX, Alpine, etc.

WordPress itself has an experimental project called Block Interactivity API with custom HTML attributes to add interactive behavior without writing JavaScript. I’m thinking it could be a natural evolution of L&L to include something like this, so that it becomes more of a “full-stack” language.

1 Like