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

Use theme mods for templates and template parts #31971

Open
wants to merge 18 commits into
base: trunk
Choose a base branch
from

Conversation

@carlomanf
Copy link

@carlomanf carlomanf commented May 19, 2021

Description

Partially resolves #31954 and partially resolves #31397 (some background to this in comments there.)

To fully resolve these issues, a UI will need to be built. This branch does not attempt the UI, but implements a necessary change in the underlying infrastructure before any such UI will be possible.

The idea behind the approach is to use theme_mods to store the "slugs" of templates and template parts, rather than the post_name of the posts themselves.

This makes it trivial to assign any existing template or template part to any newly activated theme, using set_theme_mod. It doesn't even need to have the same slug in both themes. For example, you could have the same template be single in one theme and single-post in another theme.

To do the same with the existing system is near impossible, because you quickly run into issues with slug conflicts.

The API endpoint for templates and template parts can now be used in two ways: (removed for now)

  1. active theme name // slug (existing, for fetching active templates and template parts)
  2. empty string // post ID (new, for fetching inactive templates and template parts)

How has this been tested?

Tested out creating new templates in the template editor and the site editor. They correctly resolve on the front end and they are stored in the database as intended.

Screenshots

Types of changes

Nothing should break, just clears the way for new features to be added later.

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • I've tested my changes with keyboard and screen readers.
  • 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 (please manually search all *.native.js files for terms that need renaming or removal).
@github-actions
Copy link

@github-actions github-actions bot commented May 19, 2021

👋 Thanks for your first Pull Request and for helping build the future of Gutenberg and WordPress, @carlomanf! In case you missed it, we'd love to have you join us in our Slack community, where we hold regularly weekly meetings open to anyone to coordinate with each other.

If you want to learn more about WordPress development in general, check out the Core Handbook full of helpful information.

@carlomanf carlomanf force-pushed the carlomanf:try/fse-theme-mods branch from dba7b0e to 406c69d May 19, 2021
@carlomanf carlomanf changed the title Try/fse theme mods Use theme mods for templates and template parts May 19, 2021
@carlomanf carlomanf marked this pull request as ready for review May 19, 2021
@aristath
Copy link
Member

@aristath aristath commented May 20, 2021

Hey there @carlomanf, thank you for working on this PR! It does simplify things a lot and from a quick look I took, the code makes sense...
There are quite a few failures in phpunit tests, could you please fix those and make sure we're OK on that front?

@carlomanf
Copy link
Author

@carlomanf carlomanf commented May 20, 2021

There are quite a few failures in phpunit tests, could you please fix those and make sure we're OK on that front?

Yes, I was just looking at that myself. I think they're failing because they are expecting the templates to be classified using the taxonomy and post_name, rather than through theme mods. I can see if I can rewrite the tests to expect the changed format.

@carlomanf
Copy link
Author

@carlomanf carlomanf commented May 20, 2021

There are quite a few failures in phpunit tests, could you please fix those and make sure we're OK on that front?

Yes, I was just looking at that myself. I think they're failing because they are expecting the templates to be classified using the taxonomy and post_name, rather than through theme mods. I can see if I can rewrite the tests to expect the changed format.

I think this test class is failing because it switches theme to tt1-blocks before it creates the template that is not intended for tt1-blocks, so the template gets stored with tt1-blocks anyway. Suggestions?

carlomanf added 2 commits May 25, 2021
…ry/fse-theme-mods

# Conflicts:
#	lib/full-site-editing/class-gutenberg-rest-templates-controller.php
@carlomanf
Copy link
Author

@carlomanf carlomanf commented May 27, 2021

No idea why Gutenberg_REST_Templates_Controller_Test::test_update_item is failing after the merge from trunk. I tested manually and changing the title of a template works fine.

@carlomanf
Copy link
Author

@carlomanf carlomanf commented May 29, 2021

Just copying in a comment from elsewhere for reference:

I don't think the current solution is scalable because taxonomies and slugs offer too many features that are not suitable for this purpose, nor are those systems aware of the constraints that are needed here. For example, the use of get_the_terms()[0] is problematic, because if a template somehow has two theme terms, and one is deleted, it can suddenly change theme. That could then trigger a slug conflict that causes the front-end to render differently.

If the taxonomy makes it into 5.8, I can see a potentially complicated and risky database migration needing to be done in a later version, and it would be nice to avoid that.

Also see this comment for further rationale.

@youknowriad @ockham Given the feature freeze, are there any amendments that should be made to this patch to make it eligible for 5.8? (for example, temporarily disabling the additional API endpoint?)

@youknowriad youknowriad added this to 🏗️ In progress in WordPress 5.8 Must Haves via automation May 31, 2021
@youknowriad
Copy link
Contributor

@youknowriad youknowriad commented May 31, 2021

I've added this to the 5.8 board to get it properly reviewed and considered. I need to take some time to dive here and understand it properly and its impacts. Also @ockham for thoughts here.

I'm also pinging @TimothyBJacobs here because he shared some concerns about using theme mods for the Site logo block, while it might not be the same thing here, it's always good to have more perspective.

@Addison-Stavlo
Copy link
Contributor

@Addison-Stavlo Addison-Stavlo commented Jun 7, 2021

Templates & template-parts are part of the theme and they are not content.

When a user creates their own template or part, it does not become "part of" the theme but is associated with it. I would argue that customized templates/parts and custom created ones could be considered content.

With that in mind, they have no place being included in a content export.

A user isn't creating a custom template or part with the goal of further developing the theme, they are doing so to help manage their content and how it is displayed. If they were to export their site and lose all their custom created posts (templates/parts) that helps manage and display their content, would it not feel like they are 'losing content'? Their site wouldn't look or work the same, custom posts they put effort into would disappear, and the whole process from this point of view would feel broken by forcing them to recreate all that (what is essentially) custom content.

@ockham
Copy link
Contributor

@ockham ockham commented Jun 7, 2021

I think this test class is failing because it switches theme to tt1-blocks before it creates the template that is not intended for tt1-blocks, so the template gets stored with tt1-blocks anyway. Suggestions?

Switch to a different theme first:

diff --git a/phpunit/class-block-templates-test.php b/phpunit/class-block-templates-test.php
index f0ec20b7bd..685d3dbd2a 100644
--- a/phpunit/class-block-templates-test.php
+++ b/phpunit/class-block-templates-test.php
@@ -14,7 +14,6 @@ class Block_Templates_Test extends WP_UnitTestCase {
        private static $template_part_post;
 
        public static function wpSetUpBeforeClass() {
-               switch_theme( 'tt1-blocks' );
                gutenberg_register_template_post_type();
                gutenberg_register_template_part_post_type();
                gutenberg_register_wp_theme_taxonomy();
@@ -23,6 +22,7 @@ class Block_Templates_Test extends WP_UnitTestCase {
                // Set up a template post corresponding to a different theme.
                // We do this to ensure resolution and slug creation works as expected,
                // even with another post of that same name present for another theme.
+               switch_theme( 'test-theme' );
                $args       = array(
                        'post_type'    => 'wp_template',
                        'post_name'    => 'my_template',
@@ -39,6 +39,7 @@ class Block_Templates_Test extends WP_UnitTestCase {
                wp_set_post_terms( self::$post->ID, 'this-theme-should-not-resolve', 'wp_theme' );
 
                // Set up template post.
+               switch_theme( 'tt1-blocks' );
                $args       = array(
                        'post_type'    => 'wp_template',
                        'post_name'    => 'my_template',
We can also drop the taxonomy handling in that class; a more complete diff would be:
diff --git a/phpunit/class-block-templates-test.php b/phpunit/class-block-templates-test.php
index f0ec20b7bd..5125e80345 100644
--- a/phpunit/class-block-templates-test.php
+++ b/phpunit/class-block-templates-test.php
@@ -14,45 +14,34 @@ class Block_Templates_Test extends WP_UnitTestCase {
 	private static $template_part_post;
 
 	public static function wpSetUpBeforeClass() {
-		switch_theme( 'tt1-blocks' );
 		gutenberg_register_template_post_type();
 		gutenberg_register_template_part_post_type();
-		gutenberg_register_wp_theme_taxonomy();
+		// gutenberg_register_wp_theme_taxonomy();
 		gutenberg_register_wp_template_part_area_taxonomy();
 
 		// Set up a template post corresponding to a different theme.
 		// We do this to ensure resolution and slug creation works as expected,
 		// even with another post of that same name present for another theme.
+		switch_theme( 'test-theme' );
 		$args       = array(
 			'post_type'    => 'wp_template',
 			'post_name'    => 'my_template',
 			'post_title'   => 'My Template',
 			'post_content' => 'Content',
 			'post_excerpt' => 'Description of my template',
-			'tax_input'    => array(
-				'wp_theme' => array(
-					'this-theme-should-not-resolve',
-				),
-			),
 		);
 		self::$post = self::factory()->post->create_and_get( $args );
-		wp_set_post_terms( self::$post->ID, 'this-theme-should-not-resolve', 'wp_theme' );
 
 		// Set up template post.
+		switch_theme( 'tt1-blocks' );
 		$args       = array(
 			'post_type'    => 'wp_template',
 			'post_name'    => 'my_template',
 			'post_title'   => 'My Template',
 			'post_content' => 'Content',
 			'post_excerpt' => 'Description of my template',
-			'tax_input'    => array(
-				'wp_theme' => array(
-					get_stylesheet(),
-				),
-			),
 		);
 		self::$post = self::factory()->post->create_and_get( $args );
-		wp_set_post_terms( self::$post->ID, get_stylesheet(), 'wp_theme' );
 
 		// Set up template part post.
 		$template_part_args       = array(
@@ -62,9 +51,6 @@ class Block_Templates_Test extends WP_UnitTestCase {
 			'post_content' => 'Content',
 			'post_excerpt' => 'Description of my template part',
 			'tax_input'    => array(
-				'wp_theme'              => array(
-					get_stylesheet(),
-				),
 				'wp_template_part_area' => array(
 					WP_TEMPLATE_PART_AREA_HEADER,
 				),
@@ -72,7 +58,6 @@ class Block_Templates_Test extends WP_UnitTestCase {
 		);
 		self::$template_part_post = self::factory()->post->create_and_get( $template_part_args );
 		wp_set_post_terms( self::$template_part_post->ID, WP_TEMPLATE_PART_AREA_HEADER, 'wp_template_part_area' );
-		wp_set_post_terms( self::$template_part_post->ID, get_stylesheet(), 'wp_theme' );
 	}
 
 	public static function wpTearDownAfterClass() {

@ockham
Copy link
Contributor

@ockham ockham commented Jun 7, 2021

I'll try to file a minimal PR against wordpress_develop to make the taxonomy -> theme mod change.

WordPress/wordpress-develop#1341

@tobifjellner
Copy link
Contributor

@tobifjellner tobifjellner commented Jun 7, 2021

Layman question: What does "mod" mean here?
Modulator, Moderator, Mode...???

@aristath
Copy link
Member

@aristath aristath commented Jun 8, 2021

Layman question: What does "mod" mean here?
Modulator, Moderator, Mode...???

theme_mod is Theme Modifications and it's an official WordPress API. (Documentation)

} elseif ( 'custom' !== $template->source ) {
$changes->post_name = $template->slug;

This comment has been minimized.

@ockham

ockham Jun 8, 2021
Contributor

This removal caused the unit test failure in phpunit/class-gutenberg-rest-template-controller-test.php's test_update_item(). The reason is that upon creating the new wp_template post object (with its title set to My new Index Title), we're no longer using the template (file)'s slug (index), but creating a slug based on the post title -- in this case, my-new-index-title. That slug is then used in the theme mod as the key for the newly created post object's ID -- something like

array(
    'my-new-index-title` => 6
)

This means that gutenberg_get_block_template() (which is e.g. used for the network response) cannot find a wp_template post object for the slug it was given (index, via the template ID tt1-blocks//index).

I think the right fix is to add this line (and L354) back -- I don't quite see why they were removed in the first place, so I hope that adding them back won't have any ripple effects. cc/ @carlomanf

This comment has been minimized.

@carlomanf

carlomanf Jun 8, 2021
Author

I think I removed that because I was only thinking about creating new templates, and not the possibility of overwriting a file-based one via PUT request. I can't think of any reason not to add back those lines for the existing endpoint, but they may have been needed for the new endpoint that is not being back-ported to 5.8?

This comment has been minimized.

@carlomanf

carlomanf Jun 10, 2021
Author

What about adding back this line only if true === $template->has_theme_file?

This comment has been minimized.

@ockham

ockham Jun 10, 2021
Contributor

What about adding back this line only if true === $template->has_theme_file?

I think the elseif ( 'custom' !== $template->source ) check on R343 is pretty much synonymous to that, no? (Not entirely sure about the else branch, where we also had $changes->post_name = $template->slug; 🤔 )

This comment has been minimized.

@carlomanf

carlomanf Jun 10, 2021
Author

I think it can be removed from the else branch, because it would no longer be required to stop the front-end from resolving differently as a result of a slug change.

@youknowriad
Copy link
Contributor

@youknowriad youknowriad commented Jun 10, 2021

Can we try to get this ready quickly enough to be able to play with for some time in the Gutenberg plugin and make an informed decision for 5.8.

Also, I believe we should consider a migration for the plugin if we do this, there's a number of FSE sites and custom templates out there now.

@carlomanf
Copy link
Author

@carlomanf carlomanf commented Jun 10, 2021

Can we try to get this ready quickly enough to be able to play with for some time in the Gutenberg plugin and make an informed decision for 5.8.

I went ahead and implemented most of @ockham suggestions so it's now ready to test. We will still need a solution to the export/import problem though.

@ockham
Copy link
Contributor

@ockham ockham commented Jun 11, 2021

Thanks a lot for those latest changes, @carlomanf!

I had another look at the export/import problem and talked a bit with some FSE folks (@Addison-Stavlo @jeyip @creativecoder @Copons) about it over the past couple of days. Finally, I had a chat with @youknowriad and @mtias yesterday. We decided that we're not going to include this change in Core 5.8; I'll explain our reasoning below. We're still open to considering it for later versions of WordPress.


The chief reason for this decision is the amount of work that’d still be needed in order to solve the export/import problem. Per discussion with FSE folks, we’d need to fix at least the following things:

  • Make sure we’re not associating the template with the current theme on every wp_template save (since this would otherwise erroneously associate imported wp_template CPTs with the currently active theme).
  • Include theme mod information for theme/template associations when exporting (and importing).
  • Fix the Templates (and Template Parts) screens in wp-admin to display the correct theme for a given template (part) (which would currently show empty, per this PR). (See #31971 (comment).)

Sneaking in this PR (or the backport) as-is would’ve already been a bit of a stretch of the notion of a bug fix, but these additional items inflate the scope significantly beyond the kind of change that’s supposed to be merged after Feature Freeze.

At this point, given the choice between what seems it would be a rush to design, implement, and test these changes in the weeks that remain before the release, vs. including it in a later WordPress release, at the cost of requiring a migration from taxonomies to theme mods, I find the latter preferable.

Thanks again for your work, Carlo! Let’s continue the conversation about this change — just outside the scope of WP 5.8. This will also give us more time to discuss the desired behavior of theme switches (and a possible UX) in a block-template theme world — Matías pointed me to this comment where he shared thoughts on a few possible scenarios.

@jeyip
Copy link
Contributor

@jeyip jeyip commented Jun 13, 2021

Thanks for the comprehensive reply @ockham. I think you covered most of the concerns for import / export, but I'll add a bit more context to one point.

Make sure we’re not associating the template with the current theme on every wp_template save (since this would otherwise erroneously associate imported wp_template CPTs with the currently active theme).

The reasoning behind this might be unclear, so to elaborate further:

  • Because of the current structure of this PR, theme mods will be created when the save_post_template_part and save_post_template hooks are called to generate a new template / part (see here).
  • The hooks will be triggered by wp_insert_post (see here and here).
  • Normally, these hooks aren't a big deal, but wp_insert_post is also called during WXR imports (see here). It's used to clone post data into the target site's database, which means that, for every single post that's migrated, we will inadvertently create a new theme mod entry.
  • In doing so, we will "erroneously associate imported wp_template CPTs with the currently active theme."

@youknowriad youknowriad removed this from 🏗️ In progress in WordPress 5.8 Must Haves Jun 14, 2021
@TimothyBJacobs
Copy link
Member

@TimothyBJacobs TimothyBJacobs commented Jun 15, 2021

I'm also pinging @TimothyBJacobs here because he shared some concerns about using theme mods for the Site logo block, while it might not be the same thing here, it's always good to have more perspective.

Sorry for the late reply here. I don't have any specific concerns about the REST API with this issue.

@aristath
Copy link
Member

@aristath aristath commented Jul 27, 2021

Is there something blocking us here?

@carlomanf
Copy link
Author

@carlomanf carlomanf commented Jul 27, 2021

Is there something blocking us here?

Not necessarily, I was just waiting to see if anyone had any ideas on how to implement the required changes. Here are my thoughts:

Is this even necessary, since I notice that these screens are not included in core. If they stay out, then it could potentially simplify this other change:

  • Make sure we’re not associating the template with the current theme on every wp_template save (since this would otherwise erroneously associate imported wp_template CPTs with the currently active theme).

If the admin screens are disabled, then this other change could then be implemented by moving the theme mod update from the save_post hook to the create_item method of the REST API controller, since the REST API would then be the only official way of creating a template.

  • Include theme mod information for theme/template associations when exporting (and importing).

I don't actually agree with this change, because theme mods for widgets and menus don't get included in the export data and templates should mirror that precedent. I would just leave them un-associated upon import, and add a user interface for associating themes and templates on-demand.

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

Successfully merging this pull request may close these issues.

10 participants