Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fascinating Behaviors - Prepping themes/functionality for transition to FSE from 5.8 as a base. #33942

Open
fwazeter opened this issue Aug 9, 2021 · 0 comments

Comments

@fwazeter
Copy link

@fwazeter fwazeter commented Aug 9, 2021

What problem does this address?

5.8 occupies a very odd point in time for the development cycle (and even stranger for theme development / business implementation) - as kind of 'halfway' to FSE. It makes sense to develop new themes using 5.8 as a starting point, but w/o reliance on the Gutenberg Plugin in production, while mimicking as much behavior of FSE as possible. Doing so allows for significantly longer testing / transition time ahead of FSE. Problem is, most use cases for a 'transitional/hybrid/universal' theme still largely rely on Gutenberg and ultimately what's needed are continuing evaluations of 'transitioning' - the faster people get to use things closer to FSE, the more enjoyable the experience is for developer, designer and end user.

I have significantly more notes and am assembling some gists to highlight interaction of behaviors. Should have a full theme ready within the next week or so built on these experimentations and further explores these use cases. Also currently isolating individual points in gists to share. Unsure if this is the exact correct category for this discussion. Probably have about ~5000 words worth of odd individual behaviors in Template Editor specific that are more suitable for a different thread.

Key areas of observation/concern:

  1. Template Editor is close enough to FSE & theme.json close enough that you can reasonably develop a nearly full featured Block Based Theme. Problem is, most implementations seem to fall on either full FSE or nearly full classic, where the block editor is often just wrapped in PHP.

  2. Gutenberg templating is very smart and theme complexity is drastically reduced. A 5.8 theme should match the behavior as close as is reasonably possible (e.g. rendering templates via post-type.html ).

  3. wp_template offers a key bridge between 5.8 and Gutenberg. wp_block / reusable blocks does as well - but that's a separate discussion for wrapping things like a nav bar ahead of the nav block, and Ari had a pretty good idea on this.

  4. Traditionally page-scoped (well, really the_content scoped) block templates in PHP could be a good bridge.

  5. Currently, default behavior of a user template (wp_template) simply overrides the PHP template-pages. Meaning headers / footers get lost by default, although this higher specificity over the theme-template is the desired behavior. Technically, being creative with reusable blocks can alleviate this.

  6. Solutions should be as close to core as humanly possible.

aside: as a small development agency owner that creates themes & plugins, overall, Block themes represent a gigantic leap forward in productivity and reducing configuration time / setup / little details. Also wonderful to have found the community!

The setup

Without the Gutenberg plugin, it's actually quite safe to setup your theme architecture to mimick the block-template / block-template-parts, even including an index.html file. If Gutenberg is activated, this setup cleanly handles the transition without breaking any behavior. You can click Gutenberg on/off at will and transfer templates between versions regardless of origin version creation within the same theme seamlessly ( well, obviously a block-template-part does not translate or Gutenberg specific blocks ) again, wp_template CPT's offer an amazing bridge.

  1. Behavior / architecture in new themes should mimic the inevitable FSE Block theme structure & behavior, while also being flexible enough to plugin to just about any theme to 'stair-step' transition and conversion.

The first setup step in this is to offer a way for PHP templates to set default theme templates via HTML. Gutenberg by default follows the classic WP template hierarchy, w/o Gutenberg we need to bridge it. Below is an extension of the basic example given in make wordpress posts utilizing the block_editor_settings_all filter hook (these sets of new classes/functions/hooks were surprisingly tricky to work with at first, mostly due to how new they are and not many example implementations. I'm sure this can be refined).

/inc/set-html-default-block-templates

// Ultimately, this'll probably be best served using a class.
function set_html_default_block_templates( $settings ) {

   $post_type = get_post(); // initial trial used get_current_screen(), but it had some quirkyish feeling, get_post() felt more stable.
   $template_file = $post_type->post_type == 'post' ? 'single.html' : 'page.html';

   $settings[ 'defaultBlockTemplate' ] = file_get_contents(
      get_theme_file_path( "/block-templates/{$template_file}" )
   );

   return $settings;

}
add_filter( 'block_editor_settings_all', 'set_html_default_block_templates', 10, 2 );

// page.php & single.php
get_header(); 

get_footer();

// header.php 

<!doctype html>
<html <?php language_attributes(); ?>>
<head>
	<meta charset="<?php bloginfo( 'charset' ); ?>" />
	<meta name="viewport" content="width=device-width, initial-scale=1" />
	<?php wp_head(); ?>
</head>
<body>

// footer.php
<?php

wp_footer(); ?>

</body>
</html>

aside: single.html & page.html contain very simple markup templates with arrangements of basic core blocks like post-title, post-featured-image, post-date, group, wide/full align settings

Template/Block Editor + Front End Behaviors.

1 - create a new post/page without the user clicking "new" to create a template (and no templates listed). To test, loaded up the template editor and the default template indeed loaded up.

With a new post/page published, the resulting front end view is completely blank - nothing loaded at all (minus header.php & footer.php data).

What this indicates in this setup is that, even though a full template is provided and read correctly, it isn't even really acting like a theme template - it's performing as if it's a simple schema for a template (as indicated by it loading in template editor).

Likely this is one of / combination of two possibilities:

  • The 'default template' passed to editor settings is just a temporary state - it's not actually stored anyhere and is simply changed on page refresh / page change. Change the page and the state is changed...so on the front end view, there's no editor state and no template to render the view.

  • Because classic does not support html templates, there's no mapping, and it's actually reading data from the corresponding .php file, which is blank for content - and why the header/footer.php files load.

Step 2

Loading a new page/post and clicking "new" on the Template Editor and saving a new user template for each.

The new user templates display the correct corresponding templates. Naturally, this is because of the wp_template loading taking priority over theme templates and completely ignoring the php files. Editing the post and adding new blocks also works and renders appropriately.

Under this method - no additional blocks are created 'magically' by the template editor. It's just the raw defaultBlockTemplate set. Our 'theme templates' at this point are just kind of...phantom templates.

Step 3

Because requiring the creation / application of only user templates (especially for the first), it would be terrible u/x, a default theme template must be loaded when just hitting "default template," so this code is added in respective post-type.php files between header & footer calls, with each corresponding to their respective .html templates:


echo do_blocks( file_get_contents(
	get_theme_file_path( '/block-templates/single.html' ) ) );

This is essentially a reworking of theme shaper's experiment, which uses gutenberg_block_template_part(); to accomplish the task, which is only available in the Gutenberg plugin, and therefore not an immediate option here.

Deleting all our existing templates and going back to make a brand new post - zero default templates populate in the template option, you can only hit "New" (which is also what happens in Step 1). If you load the Gutenberg plugin at this point, it populates "Template" setting with default template + template options derived from corresponding .html file(s).

Deactivating the plugin again, and creating a new post/page type without entering the Template Editor or touching the Template settings panel. The corresponding front end pages are now working correctly and displaying as they should.

At this point, you can infinitely create posts just using default 'theme templates' - but no 'default' option ever populates in the Template setting (until you create a user template - which then populates the drop down with two options: default & the wp_template name). This still indicates the existence of a "phantom template" it feels like we don't really have a theme template, we're just passing instructions to a result being echo'd.

If you put a static tag, like

Hello

in header.php, this actually renders - indicating that the template is truly just artificially using the output from another file to 'mimic' the .html template. The content in php is only ignored if you make a user template (expected behavior), which completely ignores any php content.

Step 4

Now, we activate gutenberg and go through activate / deactive, create user templates in both environments and swap between them. Templates + data are preserved between all switches going all ways.

If you delete all wp_templates, even in WP 5.8 Core implementation, the pages/posts remain intact on the front end.

Interesting Notes If you delete index.html in Gutenberg, and only have a single.html, if you go to page-> add new, you get a flash of an error, but the template loads and you can select between the single & default option (presumably the same option since it's the only one available). Albeit the styling is completely messed up / stretching nearly the full vertical height of the browser on the template settings tab. Selecting the other template actually renders it (theme template, no user template). Restoring index.html fixes this.

If you switch themes and create templates in a different theme, apply those user_templates (that are now locked to the 2nd theme), and then switch back to the original theme - then load those pages without editing them - in Gutenberg, it reverts to the base template in the corresponding .html file. In Core 5.8 only it still calls and correlates with the appropriate template, as long as the echo is intact - user_templates simply revert back to a 'default' template render.

Consequently - updating any content across the board appropriately updates posts using those templates in the Core 5.8.

Step 5 - All code referencing .html files to render templates is commented out, and a PHP block template is added.

function register_block_template() {
			$page_type_object = get_post_type_object( 'post' );
			$page_type_object->template = array(
				array( 'core/group', array( 'layout' => array( 'inherit' => 'true' ) ),
					array(
						array( 'core/post-terms',          array( 'term' => 'category' ) ),
						array( 'core/post-date',           array( 'textAlign' => 'center' ) ),
						array( 'core/post-featured-image', array( 'align' => 'wide' ) ),
					)
				),
			);
		}
		add_action( 'init', 'register_block_template' );

The template php files are empty between the get_header() and get_footer().

Loading up the block editor, the PHP block template loads appropriately in the block editor - unlike the other templates it displays directly in the block editor (expected behavior). Naturally, if we make a post, nothing is rendered because there's nothing in the php template file to tell it to load.

aside: the template editor settings panel appears the same way as the before examples when no user templates exist - only "New" as an option and no "default" detected - but rendering occurs even without loading the template editor (except inthe obvious case where there was zero php that could even load it).

If we uncomment the echo do_blocks(); code - the template renders according to whatever was set in the corresponding .html file at first glance...however if you scroll down you see what's actually happening: The echo'd HTML template renders first (any pre-populated field anyway, such as post-featured-image or post-title / post-category, and THEN the PHP block template loads.

If we go back and edit the post that was rendered with both html + php blocks, the block editor appears normal - just the content we edited in the default template. The same goes when you load up the Template Editor.

**As it turns out, because the PHP block templates are edited/created within the context of the block editor, what actually happened was the last line in the .html template file:

<!-- wp:post-content {"layout":{"inherit":true}} /--> we basically did a rudimentary verison of the_content() the_content().

The PHP Block Template content got pulled in because it's...block editor content.

What is interesting about this is if you add post-content block to the PHP block template array, it does not load. Because the PHP block template appears to live exclusively within the context of the actual block editor -> in the_content() (I'd say body, but

and live within the body html too).

Now, if we switch themes, create a user template (wp_template) w/gutenberg plugin, then swap back to the original theme, the page with the template from the opposite theme (obviously wp_template's are not yet transferrable between themes as the theme they were created in "owns" them), without mkaing any edits / changes to template in the post itself, the front end does this:

-Gutenberg Plugin + commented out function/echo to html: reformats to the respective .html template file (expected).
-Disable Gutenberg Plugin + above: Nothing renders except the static content in get_header() / get_footer(). (makes sense).
-Use appropriate php template tags in the post-type.php: renders the content from php (great).

-bring echo(do_blocks()) back -> page renders according to echo(do_blocks()) template...but no actual non-template content added to the post-content in the other template renders here...and the auto-generated content doesn't duplicate like it did above.

also interestingly, even though the original template was a user_template, which should ignore/override PHP, the get_header() content still loads.

Now, bring back our function that hooks into block_editor_settings_all -> no change from above.

Now, comment out the php block template function: same as above loads. Now, bringing the php block template code, refreshing: no change. Edit post -> None of the content added/inputted in the template editor screen from the other theme user template appears.

So editing this page with both php block template, and the connection to HTML content, only the HTML default template loads. as defined by block_editor_settings_all

If I create a new page though...The PHP block template code appears in the block editor editor - and what we end up getting in the Template Editor is this:

Group <- start HTML template
     Group
          Post Categories
          Post Title
          Post Date
         Post Featured Image
      Spacer
      Post Content <- End HTML Template template
          Group <- Start PHP Template
                Post Categories
                Post Title
                Post Date
                Post Featured Image <- End PHP Template. 

If I remove the <!-- wp:post-content {"layout":{"inherit":true}} /--> from the HTML template. And make a new post, we get, once again the PHP template showingin the block editor.

If however, I go to the Template editor -> Only the HTML template content appears (if I have not entered any content into the PHP Block template)

If I set a piece of content from one of the PHP Block templates -> I get the same result. So the PHP block template is there, being loaded into the block editor, but appears only cosmetic / being overwritten by the called block_editor_settings_all hook.

Sure enough, if I save the post, only the appropriate content from the user_template from template editor appears.

If I make a new post, but do not load up the custom editor, even though I enter values in the predefined areas of the PHP Block Template, only the echo content is loaded.

Now the last part - if I only keep the PHP block template active (comment out all the references to the HTML template file).

-> PHP Block template loads in block editor.
-> Load up the Template Editor...

The Template Editor (presumably by design), gets automatically wrapped with:


Group <--- start autogenerated
    Site Title
    Site Tagline
Separator
Group
    Group
        Post Title 
    Post content <--- end auto generated
        Group
           Post Categories
           Post Date
           Post Featured Image

So effectively - the PHP block templates are only scoped to the block editor (the_content()). HTML templates, or templates derived from defaultBlockTemplates via block_editor_settings_all filter hook have a scope for the entire body.

I imagine, as a work around, to the context in which PHP Block Templates were originally created (when only the block editor existed), there's a function somewhere that's appending the that extra content - I can't determine where it's being generated from though, and I can't seem to find where it's coming from.

Additionally, if the defaultBlockTemplate content is determined via hook, AND then at any point, calls the PHP post content via wp: post-content, then the PHP Block Template content can automatically be placed just about anywhere.

Whenever default templates are generated from HTML or defaultBlockTemplate, there are no 'additional' blocks auto generated. to fill the gap in the header area.

That's a little peculiar, and I havent found any references to it anywhere else (which doesn't mean it doesn't exist).

additionally, very important While you cannot add post-content block to the PHP Block template function (it'll pass without throwing any errors, it just won't render, just as if you tried to place a post-content block in the block editor - the block can't reference itself.

What you CAN do is add another Post Content block in the Template Editor (which now would have two Post Content Blocks. This Post Content Block automatically duplicates any content that was already inputted or templated into the block editor itself (such as our PHP block template -- another instance of the_content() the_content() more or less). AAnnnd....you can just keep doing this...over and over and over again...and then the content actually renders on the front ned - repeated ad nauseum.

What is your proposed solution?

Where does the 'magic' markup come from with PHP Block Templates? Why not do so with HTML generated Templates if intended?

It's a little uncertain on what the future of PHP Block Templates are (or at least I am uncertain based on readings) - like the common use cases for JavaScript Block Templates kind of got supplanted by block patterns, PHP Block Templates seem to be also occupying an odd space in light of Patterns, user templates, HTML theme templates, etc.

Currently, there are certainly some fancy tricks that can be done by theme / plugin developers - for instance, there could be a transition plugin that creates a custom post type around the PHP template and essentially assigns it to act like a 'block template part'

Problem is, PHP Block Templates are, well, arrays within arrays within arrays within arrays....Inception in array format...Arrception? These are extremely error prone - and in a lot of the cases I've encountered with making, say, missing failing to put an array in the right spot, for me, has often resulted in a white screen of doom with no immediate error code on screen. Experience has just taught me that "whelp, I messed up nesting somewhere, yet another array for a block got passed as an attribute for another block.

Up til now, they've had use cases being able to be registered alongside CPT's as default templates for them...and certainly many of the developers I know go CPT happy to solve relatively simple problems (like, say "special announcements" or "testimonials" or "faqs"). I believe Block based themes solve a lot of this (and masterfully make use of CPTs).

wp_template and wp_block are some pretty magical glues though - we need more bridges like that for conversion from classic to FSE. Plugin & Theme developers will pickup some of the more complicated pieces, but basic core tools are great.

  1. The 'magic' markup - could potentially be a a toggle on/off option, that could do something like, wrap header/nav or footer in a block or sets of blocks (with info taken from footer.php / header.php) that are then added around user templates created in the template editor.

This would ease transition by taking care of some of the most complex pieces with template creation. Although, sooner or later nav block is here and helps tremendously.

  1. The PHP Block Templates are great for end user useability in being able to see what they're editing. Problem is the complex error prone configuration and if it doesn't exactly match markup...well, that's going to be terrible ux - using a JSON file to map blocks between markup and the PHP templates (maybe you just start with JSON and it configures both), similar to the use cases for theme.json and specifically block.json would greatly reduce the duplication and complexity.

The only practical theme/plugin solution is basically, that's going to end up in a class with some kind of factory functions.

  1. There's a specificity conflict in Template editor between the block_editor_settings_all defaultBlockTemplate & the WP_Post_Type obj - unless specifically called with a wp: get-content block markup in the defaultBlockTemplate, they aren't translating into the Template Editor.

  2. It's a common use case for page builders, like Elementor and Beaver Builder to "sit on top" of WordPress's content editor. When you have a default template that the user hasn't seen yet - if they don't already know where to find the template settings button AND that they have to open it to see what the actual post template looks like, what they're essentially doing is creating post content and a layout that's specific in scope just to the block editor and then the rest of the layout "wraps" around it like a PHP template wrapping around a call to the_content().

If the theme / template designer has the foresight to primarily stick to autogenerated fields around these areas - great. But ultimately it's a big sticking point for confusion. Existing page builders get around this by making really big CTA's around the dash / in admin bars / etc to say "EDIT IN XYZ builder"

Not saying the Block Editor is necessarily trying to be like a page builder in those contexts - but it has the edge of being bult in. Adding a simple "pre-post check" like is done for tags to the "publish" button that notifies the user in the settings tool bar AND gives them a pop up notification in the lower right hand corner where the rest is that could effectively say "HEY, you've got empty content > click here to open edit in Template Editor." would be sufficient in lieu of making the block editor mimic exactly the front end and template editor.

@fwazeter fwazeter changed the title <title> Fascinating Behaviors - Prepping themes/functionality for transition to FSE from 5.8 as a base. Fascinating Behaviors - Prepping themes/functionality for transition to FSE from 5.8 as a base. Aug 9, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants