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

Template Loader: Introduce get_template_hierarchy(), drop gutenberg_template_include_filter() #21980

Merged
merged 9 commits into from
May 5, 2020

Conversation

ockham
Copy link
Contributor

@ockham ockham commented Apr 29, 2020

Description

Previously, the template loader made gratuitous use of filters and globals in order to communicate data from one function to another. Specifically:

  1. The gutenberg_override_query_template filter was added to ${type}_template. It served two purposed:
    1. It recorded the current template hierarchy in the _wp_current_template_hierarchy global.
    2. It returned an empty string to indicate that no old-school theme template should be rendered.
  2. The gutenberg_template_include_filter filter was added to template_include. That filter determined the relevant template post from _wp_current_template_hierarchy, and used it to render the template via the template canvas.
  3. In order to populate the $settings variable (which is passed to the client), edit-site-page.php iterated over all template getters, calling each one of them, in order to trigger the ${type}_template filters (and thus, gutenberg_override_query_template), to obtain the template hierarchies, and subsequently, the relevant template IDs. During each iteration, care had to be taken to evaluate and then reset the relevant globals.

Due to the implicit nature of globals and filters, this is harder to follow and reason about than a call stack of functions with explicit arguments and return values.

Hence, this PR makes the following changes:

  • Introduce a new get_template_hierachy() function that determines the template hierarchy for a given template type. This encapsulates adding and removing a filter (which is still required) so it doesn't have to leak a global, as the previous approach did.
  • Use that function to get the template hierarchy in edit-site-page.php (see item 3. above), getting rid of most globals involved in that file.
  • Now that determining the template hierarchy doesn't need to be a concern of gutenberg_override_query_template anymore (see item 1.1 above), re-purpose it to actually render the template canvas, cutting out the now-superfluous gutenberg_template_include_filter (item 2.), which is thus removed. This still requires two globals (_wp_current_template_id and _wp_current_template_content), to communicate the template that needs to be rendered to the canvas. However, their use is much more limited.

This PR still does not touch the _wp_current_template_part_ids global, in order to ensure that the auto-draft saving behavior isn't changed. I'm planning to work on this in another follow-up.

This is a follow-up to #21959, and another preparatory step for https://github.com/WordPress/gutenberg/pull/21877/files#r416075231.

How has this been tested?

Verify that Full Site Editing works as before.

Types of changes

Refactor for encapsulation, readability, and extensibility.

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • My code has proper inline documentation.
  • I've included developer documentation if appropriate.
  • I've updated all React Native files affected by any refactorings/renamings in this PR.

Copy link
Contributor

@epiqueras epiqueras left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking great.

We should add tests for these new functions if possible now that we are formalizing the behavior.

I think the next step should be extracting get_template_ids and get_template_part_ids from gutenberg_edit_site_init so that we can access them through a REST endpoint and for unblocking things like #21958.

lib/template-loader.php Outdated Show resolved Hide resolved
}
$settings['templateId'] = $current_template_post->ID;

$current_template_id = $template_ids['index'] ?? $template_ids['front-page'];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should load both the index template and the front-page template under any circumstances.

I mirrored Core's template-loader here:

https://github.com/WordPress/WordPress/blob/8ca76cabfc9caf75637f0e7f2689c40a0f184657/wp-includes/template-loader.php#L93-L95

lib/template-loader.php Outdated Show resolved Hide resolved
@github-actions
Copy link

github-actions bot commented Apr 30, 2020

Size Change: +135 B (0%)

Total Size: 821 kB

Filename Size Change
build/block-directory/index.js 6.6 kB +1 B
build/block-editor/index.js 101 kB +8 B (0%)
build/block-library/index.js 115 kB +45 B (0%)
build/blocks/index.js 48.1 kB -1 B
build/components/index.js 179 kB +9 B (0%)
build/data/index.js 8.44 kB -1 B
build/edit-post/index.js 28.1 kB +1 B
build/edit-site/index.js 12.3 kB +1 B
build/edit-widgets/index.js 8.37 kB +42 B (0%)
build/edit-widgets/style-rtl.css 4.68 kB +16 B (0%)
build/edit-widgets/style.css 4.68 kB +17 B (0%)
build/editor/index.js 44.3 kB -1 B
build/format-library/index.js 7.63 kB -1 B
build/viewport/index.js 1.84 kB -1 B
ℹ️ View Unchanged
Filename Size Change
build/a11y/index.js 1.02 kB 0 B
build/annotations/index.js 3.62 kB 0 B
build/api-fetch/index.js 4.08 kB 0 B
build/autop/index.js 2.82 kB 0 B
build/blob/index.js 620 B 0 B
build/block-directory/style-rtl.css 760 B 0 B
build/block-directory/style.css 761 B 0 B
build/block-editor/style-rtl.css 10.2 kB 0 B
build/block-editor/style.css 10.2 kB 0 B
build/block-library/editor-rtl.css 7.08 kB 0 B
build/block-library/editor.css 7.08 kB 0 B
build/block-library/style-rtl.css 7.24 kB 0 B
build/block-library/style.css 7.25 kB 0 B
build/block-library/theme-rtl.css 683 B 0 B
build/block-library/theme.css 685 B 0 B
build/block-serialization-default-parser/index.js 1.88 kB 0 B
build/block-serialization-spec-parser/index.js 3.1 kB 0 B
build/components/style-rtl.css 16.9 kB 0 B
build/components/style.css 16.9 kB 0 B
build/compose/index.js 6.66 kB 0 B
build/core-data/index.js 11.4 kB 0 B
build/data-controls/index.js 1.29 kB 0 B
build/date/index.js 5.47 kB 0 B
build/deprecated/index.js 772 B 0 B
build/dom-ready/index.js 568 B 0 B
build/dom/index.js 3.1 kB 0 B
build/edit-navigation/index.js 4.05 kB 0 B
build/edit-navigation/style-rtl.css 485 B 0 B
build/edit-navigation/style.css 485 B 0 B
build/edit-post/style-rtl.css 12.2 kB 0 B
build/edit-post/style.css 12.2 kB 0 B
build/edit-site/style-rtl.css 5.19 kB 0 B
build/edit-site/style.css 5.2 kB 0 B
build/editor/editor-styles-rtl.css 428 B 0 B
build/editor/editor-styles.css 431 B 0 B
build/editor/style-rtl.css 5.07 kB 0 B
build/editor/style.css 5.08 kB 0 B
build/element/index.js 4.65 kB 0 B
build/escape-html/index.js 734 B 0 B
build/format-library/style-rtl.css 502 B 0 B
build/format-library/style.css 502 B 0 B
build/hooks/index.js 2.13 kB 0 B
build/html-entities/index.js 622 B 0 B
build/i18n/index.js 3.56 kB 0 B
build/is-shallow-equal/index.js 710 B 0 B
build/keyboard-shortcuts/index.js 2.51 kB 0 B
build/keycodes/index.js 1.94 kB 0 B
build/list-reusable-blocks/index.js 3.13 kB 0 B
build/list-reusable-blocks/style-rtl.css 226 B 0 B
build/list-reusable-blocks/style.css 226 B 0 B
build/media-utils/index.js 5.29 kB 0 B
build/notices/index.js 1.79 kB 0 B
build/nux/index.js 3.4 kB 0 B
build/nux/style-rtl.css 616 B 0 B
build/nux/style.css 613 B 0 B
build/plugins/index.js 2.56 kB 0 B
build/primitives/index.js 1.5 kB 0 B
build/priority-queue/index.js 789 B 0 B
build/redux-routine/index.js 2.85 kB 0 B
build/rich-text/index.js 14.8 kB 0 B
build/server-side-render/index.js 2.67 kB 0 B
build/shortcode/index.js 1.7 kB 0 B
build/token-list/index.js 1.28 kB 0 B
build/url/index.js 4.02 kB 0 B
build/warning/index.js 1.14 kB 0 B
build/wordcount/index.js 1.18 kB 0 B

compressed-size-action

@ockham
Copy link
Contributor Author

ockham commented Apr 30, 2020

This is looking great.

We should add tests for these new functions if possible now that we are formalizing the behavior.

I think the next step should be extracting get_template_ids and get_template_part_ids from gutenberg_edit_site_init so that we can access them through a REST endpoint and for unblocking things like #21958.

Thanks @epiqueras! I tried to get PHP unit tests to run locally but unfortunately wasn't able to. I looked a bit into the PR that brings them into wp-env (and left a comment there). However, I'm afraid I won't be able to work on this (and on unit tests for this PR) today, and I won't be working tomorrow (EU Labor Day).

I can either cycle back to this next week, or you can merge on my behalf, and I'll add unit tests later.

@epiqueras
Copy link
Contributor

We can follow-up with the tests, but I am still concerned about this, #21980 (comment).

My original idea was to resolve every template that can be resolved through all the Core post types. index is only a fallback for when another template can't be found, that's why the previous code called get_index_template without clearing the template hierarchy global so that its hierarchy would be appended to the current one and act as a fallback.

This PR loads index even when it's never used in the front-end. I'm not sure that's what we want. The site editor should be like a live preview of the actual site, and if index is never used, then we probably shouldn't show it.

@ockham
Copy link
Contributor Author

ockham commented May 4, 2020

We can follow-up with the tests, but I am still concerned about this, #21980 (comment).

Ah, my bad, I forgot to address that comment!

My original idea was to resolve every template that can be resolved through all the Core post types. index is only a fallback for when another template can't be found, that's why the previous code called get_index_template without clearing the template hierarchy global so that its hierarchy would be appended to the current one and act as a fallback.

This PR loads index even when it's never used in the front-end. I'm not sure that's what we want. The site editor should be like a live preview of the actual site, and if index is never used, then we probably shouldn't show it.

Will look into this!

lib/template-loader.php Outdated Show resolved Hide resolved
lib/template-loader.php Outdated Show resolved Hide resolved
@ockham
Copy link
Contributor Author

ockham commented May 4, 2020

I think I need a bit more clarification on this 😅

My original idea was to resolve every template that can be resolved through all the Core post types. index is only a fallback for when another template can't be found, that's why the previous code called get_index_template without clearing the template hierarchy global so that its hierarchy would be appended to the current one and act as a fallback.

The previous behavior reset the $_wp_current_template_hierarchy global on each iteration of the template getters loop. This means that the only other template hierarchy that was taken into account when determining the $current_template_post was the front page template. (This behavior also pre-dates my other PR.)

To restore this behavior, the following patch would probably be enough:

diff --git a/lib/edit-site-page.php b/lib/edit-site-page.php
index acc8f1f4cf..5d53ce770e 100644
--- a/lib/edit-site-page.php
+++ b/lib/edit-site-page.php
@@ -146,7 +146,6 @@ function gutenberg_edit_site_init( $hook ) {
 	}
 
 	$template_types = array(
-		'index',
 		'404',
 		'archive',
 		'author',
@@ -156,7 +155,6 @@ function gutenberg_edit_site_init( $hook ) {
 		'date',
 		// Skip 'embed' for now because it is not a regular template type.
 		'home',
-		'front-page',
 		'privacy-policy',
 		'page',
 		'search',
@@ -180,9 +178,10 @@ function gutenberg_edit_site_init( $hook ) {
 		$_wp_current_template_part_ids = null;
 	}
 
-	$current_template_id = $template_ids['index'] ?? $template_ids['front-page'];
+	$front_page_template_hierarchy = array_merge( get_template_hierachy( 'front-page' ), get_template_hierachy( 'index' ) );
+	$front_page_template_post = gutenberg_find_template_post( $template_hierarchy );
 
-	$settings['templateId']      = $current_template_id;
+	$settings['templateId']      = $front_page_template_post->ID;
 	$settings['templateType']    = 'wp_template';
 	$settings['templateIds']     = array_values( $template_ids );
 	$settings['templatePartIds'] = array_values( $template_part_ids );
@@ -200,7 +199,7 @@ function gutenberg_edit_site_init( $hook ) {
 		'/wp/v2/types?context=edit',
 		'/wp/v2/taxonomies?per_page=-1&context=edit',
 		'/wp/v2/themes?status=active',
-		sprintf( '/wp/v2/templates/%s?context=edit', $current_template_id ),
+		sprintf( '/wp/v2/templates/%s?context=edit', $front_page_template_post->ID ),
 		array( '/wp/v2/media', 'OPTIONS' ),
 	);
 	$preload_data  = array_reduce(

However, it seems like you might be saying that we should actually return the first template post in the list (ordered as the original getters list was) for which gutenberg_find_template_post returns something, to replicate Core's template resolution. (This would change the current/pre-#21959 behavior.) Am I reading you correctly?

@epiqueras
Copy link
Contributor

Basically, index is only used when none of the other templates match.

Because in our use case, we are kind of simulating visits to every template type, we should only load index when any of the template getters fails to find a template.

array_merge( get_template_hierachy( $template_type ), get_template_hierachy( 'index' ) );

That would be the template hierarchy in every iteration of the loop.

@ockham ockham force-pushed the update/template-loader-no-template-hierarchy-global branch from aeb7a04 to 3f199c6 Compare May 5, 2020 11:15
@ockham
Copy link
Contributor Author

ockham commented May 5, 2020

Addressed feeback -- this should be ready for another look 🙂

@ockham ockham merged commit 464026a into master May 5, 2020
@ockham ockham deleted the update/template-loader-no-template-hierarchy-global branch May 5, 2020 16:03
@github-actions github-actions bot added this to the Gutenberg 8.1 milestone May 5, 2020
$settings['templateId'] = $current_template_post->ID;
$settings['homeTemplateId'] = $current_template_post->ID;

$current_template_id = $template_ids['front-page'];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now, if the block-based theme doesn't have a template file called front-page.html it throws a 404 when trying to load the page. Could it be related to this somehow?

Copy link
Member

@aduth aduth Jun 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found my way back here as well 😄 It's pretty evident in the default twentytwenty theme, which doesn't have a front-page template.

https://github.com/WordPress/twentytwenty

This causes the Site Editor to not load at all.

Seems it should be resilient to the absence of this template, possibly falling back to another applicable template?

e.g. front-page, home, index

https://developer.wordpress.org/files/2014/10/Screenshot-2019-01-23-00.20.04.png
https://developer.wordpress.org/themes/basics/template-hierarchy/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's possible I'm afraid 😬
I'm still touching this file pretty regularly, will look into fixing it 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems it should be resilient to the absence of this template, possibly falling back to another applicable template?

e.g. front-page, home, index

https://developer.wordpress.org/files/2014/10/Screenshot-2019-01-23-00.20.04.png
https://developer.wordpress.org/themes/basics/template-hierarchy/

Yeah, I'm painfully aware of the template hierarchy 😬 The function that's used to populate $template_ids actually falls back to index, see

$template_hierarchy = array_merge( get_template_hierachy( $template_type ), get_template_hierachy( 'index' ) );

I'll have to dig into why the index fallback isn't working.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix: #22954

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants