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

Refactor BlockTemplatesController #44537

Merged
merged 28 commits into from Feb 27, 2024
Merged

Conversation

Aljullu
Copy link
Contributor

@Aljullu Aljullu commented Feb 12, 2024

Changes proposed in this Pull Request:

Part of #42251.
Closes #44264.
Closes #42191.
Closes #44453. (Update: the testing steps for this issue have been added to the PR description after merge, that's because we didn't notice this PR was fixing #44453 until after merge)

This PR refactors BlockTemplatesController.php with the goal to extract all the logic which is specific to certain templates to their own files.

Based on that, every template and template part now has its own class, where the slug, title, description and fallback template are define, as well as any custom logic needed for the template to work. Templates inherit from the AbstractTemplate class, which takes care of registering the template into the BlockTemplatesRegistry, that's a class that keeps an up-to-date list of registered templates, to make it easy to retrieve data from them (ie: titles, descriptions, etc.).

Next steps:

How to test the changes in this Pull Request:

Make sure there are no regressions related to block templates

Test it as you wish and feel free to go outside of what's described below. In any case, some ideas of things to test:

With a classic theme (ie: Storefront).

  1. Make sure there are no regressions when visiting WooCommerce pages. Ie, try going to the Shop page, then visit a single product page, add it to the cart and visit Cart and Checkout pages. Make sure there aren't PHP errors and there isn't anything abnormal.

With a block theme without custom WooCommerce templates (ie: Twenty Twenty-Four)

  1. Without any template customizations, make sure you can visit the Shop page and the single product page in the frontend without issues.
  2. Now, go to Appearance > Editor > Templates and edit the Product Catalog, Single Product and Page: Cart templates and the Mini-Cart template part. You can make a dummy edit like adding a "Hello world from the user-customized template" paragraph.
  3. Now, visit the Shop page, the Products by Category page (it should inherit the design from the Shop page), Single Product page and Cart page. Verify the edits are visible in all of them. Add the Mini-Cart to the header of your site or to a new post and verify that when opening the Mini-Cart drawer, the custom template is loaded.
  4. Go back to Appearance > Editor > Templates and revert some of the edits you just did (don't revert all). Verify reverting them works and there are no errors.

With a block theme with custom WooCommerce templates (ie: Tsubaki)

  1. Visit some templates in the frontend and verify the theme templates are visible.
  2. Go to Appearance > Editor > Templates and make some edits. When starting to edit the template, verify that the template from the theme is rendered, instead of the template from WooCommerce (note: Cart, Checkout and Order Confirmation don't have specific templates in Tsubaki, that's expected).
  3. Save the edits and verify they are visible in the frontend.
  4. Make sure edits can be reverted without errors.

Make sure Mini-Cart template part from the theme is correctly assigned to the Mini-Cart template part area (#44264)

  1. With a block theme with a custom Mini-Cart template part (ie: Tsubaki).
  2. Go to Appearance > Editor > Patterns (/wp-admin/site-editor.php?path=%2Fpatterns&categoryType=wp_template_part)
  3. Verify the Mini-Cart template part is in the Mini-Cart template part area.

Verify correct template is rendered with certain settings (#44453)

  1. With a theme with custom WooCommerce templates (ie: Tsubaki).
  2. Go to WooCommerce > Settings > Products > Advanced and disable Use the product attributes lookup table for catalog filtering.
  3. With a block theme with custom WooCommerce templates (ie: Tsubaki) go to /shop/?product_cat=Clothing&filter_size=large. Note: the values of product_cat and filter_xyz might vary depending on the categories and attributes of your store. In case of doubt, you can import the products from sample-data.
  4. Verify the page is rendered correctly.
Before After
image image

Changelog entry

  • Automatically create a changelog entry from the details below.

Significance

  • Patch
  • Minor
  • Major

Type

  • Fix - Fixes an existing bug
  • Add - Adds functionality
  • Update - Update existing functionality
  • Dev - Development related task
  • Tweak - A minor adjustment to the codebase
  • Performance - Address performance issues
  • Enhancement - Improvement to existing functionality

Message

Updated the template logic used by block themes, to make it more performant and resilient

Comment

@Aljullu Aljullu added focus: template Issue related to WooCommerce templates. team: Kirigami & Origami labels Feb 12, 2024
@Aljullu Aljullu self-assigned this Feb 12, 2024
@Aljullu Aljullu changed the title Update/block templates controller refactor Refactor BlockTemplatesController Feb 12, 2024
@github-actions github-actions bot added the plugin: woocommerce Issues related to the WooCommerce Core plugin. label Feb 12, 2024
Copy link
Contributor

github-actions bot commented Feb 12, 2024

Test Results Summary

Commit SHA: 1326883

Test 🧪Passed ✅Failed 🚨Broken 🚧Skipped ⏭️Unknown ❔Total 📊Duration ⏱️
API Tests25900202610m 38s
E2E Tests332001503478m 23s

To view the full API test report, click here.
To view the full E2E test report, click here.
To view all test reports, visit the WooCommerce Test Reports Dashboard.

@Aljullu Aljullu force-pushed the update/BlockTemplatesController-refactor branch from b55c752 to d8261bf Compare February 13, 2024 08:26
@Aljullu Aljullu marked this pull request as ready for review February 13, 2024 09:20
@woocommercebot woocommercebot requested review from a team and dinhtungdu and removed request for a team February 13, 2024 09:21
Copy link
Contributor

github-actions bot commented Feb 13, 2024

Hi @gigitux, @dinhtungdu, @tjcafferkey,

Apart from reviewing the code changes, please make sure to review the testing instructions as well.

You can follow this guide to find out what good testing instructions should look like:
https://github.com/woocommerce/woocommerce/wiki/Writing-high-quality-testing-instructions

@Aljullu Aljullu force-pushed the update/BlockTemplatesController-refactor branch 2 times, most recently from 028714b to fdf0310 Compare February 13, 2024 10:35
@Aljullu Aljullu mentioned this pull request Feb 13, 2024
11 tasks
@tjcafferkey
Copy link
Contributor

Thanks @Aljullu, great work on this. I will make sure I get around to reviewing this today/tomorrow!

@tjcafferkey
Copy link
Contributor

tjcafferkey commented Feb 15, 2024

@Aljullu It looks like with this PR we have just moved the individual template rendering logic into its own controller. Can you confirm that's right? Whereas a bunch of the logic still remains in the main BlockTemplatesController class?

I also notice that we are still creating fallbacks for alternative product archive templates. For example if the Product Catalog has been customised it will be used for the other archive templates such as Products by Category etc.

I think it was agreed that we could do the following during this refactor:

  • Remove the other product archive templates and only load the Product Catalog template into the site editor. This will be used for all product archive pages. (I notice you have mentioned this in the PR description)
  • Allow users to add alternative templates via the editor > add new option within the UI.

I think if we achieved these two things as part of this PR it would do two things:

  1. Allow us to remove a bunch of complex code.
  2. Reduce our testing surface area since the longer we keep this logic in the controller the longer its going to test for regressions.

My only concern is with this PR at the moment is that we have created a bunch of new files and code and spread the complexity rather than reduce it.

/**
* Renders the default block template from Woo Blocks if no theme templates exist.
*/
public function render_block_template() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we not use this class more generically to render the other product archive templates and remove the additional classes?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I guess it could be done, but what would be the benefit of doing so?

One of the benefits I see from having one file per template is that there is a clear relation between:

  • The template PHP file where we define title, description, specific hooks...
  • Templates stored in the database.
  • Template files from themes.

All of them sharing the same slug. While we could move the logic from other archive templates into this file, that would break the 1:1 relation between the above, which IMO would make things more confusing. 🤔

Copy link
Contributor

Choose a reason for hiding this comment

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

I guess the change only makes sense if/once we remove the other product archive templates altogether and render the Product Catalog template in every case unless the user has added a specific template via the Add New UI in the Site Editor.

Copy link
Contributor

@gigitux gigitux left a comment

Choose a reason for hiding this comment

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

Thanks for your work!
As @tjcafferkey noticed, in the Site Editor, we decided to list only the Product Catalog in the Site Editor. As Tom sustains (and I agree), this would allow us to reduce some complexity.

I added a few comments on the BlockTemplatesController containing specific functions for the Product Catalog template and the fallback system. I don't recall the logic (maybe we can remove them), but we should keep the Controller with general-purpose logic. Any dedicated logic for a specific template should be in the class-specific of that template. I'm afraid if we keep some dedicated logic in this class, there is the risk that, in the future, we start to add dedicated logic for a specific template, and we will be back to where we started.

Also, I noticed that the priority of the templates during the theme switch differs from WordPress's behavior.

In this video, using TT4, I update the Index template and the Single Product Template. After the switch to Tsubaki:

  • The Index template uses the Tsubaki template.
  • The Single Product template uses the previously saved version. Instead, it seems that the correct behavior is that it should use the Tsubaki one.
Screen.Capture.Feb.15.at.10-47-21.mp4

@Aljullu
Copy link
Contributor Author

Aljullu commented Feb 15, 2024

Thanks for taking a look and all the suggestions, @tjcafferkey!

@Aljullu It looks like with this PR we have just moved the individual template rendering logic into its own controller. Can you confirm that's right? Whereas a bunch of the logic still remains in the main BlockTemplatesController class?

Correct, the idea is that all the logic specific to a single template is in the template file, while the logic which is template-agnostic is kept in BlockTemplatesController.

There is some logic which could still be moved somewhere else. Ie, we could create an AbstractTemplateWithFallback class that would contain all the logic related to a template "fallbacking" to another one. But given that this PR is already 1000 lines long, I preferred to leave it as-is.

Edit: ok, I see @gigitux also suggested moving the "fall back" logic out of BlockTemplatesController, so let's do it. 😄

I also notice that we are still creating fallbacks for alternative product archive templates. For example if the Product Catalog has been customised it will be used for the other archive templates such as Products by Category etc.

I think it was agreed that we could do the following during this refactor:

  • Remove the other product archive templates and only load the Product Catalog template into the site editor. This will be used for all product archive pages. (I notice you have mentioned this in the PR description)
  • Allow users to add alternative templates via the editor > add new option within the UI.

I think if we achieved these two things as part of this PR it would do two things:

  1. Allow us to remove a bunch of complex code.
  2. Reduce our testing surface area since the longer we keep this logic in the controller the longer its going to take for regressions.

My understanding is that you are referring to what's described in these two issues: #42531 and #42532, right?

What I'm not sure to understand is how that would simplify the code. My understanding is that it's mostly a UI change (how we present the templates in the Site Editor UI), but the "fallback logic" will still need to exist, no? There will still be the case that the user or the theme have customized a specific template (ie: Products by Category) and we will need some logic to decide which template is loaded both in the frontend and in the Site Editor. I might be missing some previous conversations on this, though.

Don't get me wrong, I'm happy to include those changes in this PR, but my understanding is that they would only increase the lines of code modified and would increase the testing surface area. As mentioned, the PR is already 1000 lines of code and I didn't want it to grow bigger to make it easier to review. 😟

My only concern is with this PR at the moment is that we have created a bunch of new files and code and spread the complexity rather than reduce it.

It's true this PR creates a lot more files, but all of them are quite small and there is not much complexity in them: each template file defines the slug, title, description and any hooks required by that specific template. Are there any specific areas where you think we could reduce the complexity? I guess the fall backing system 😄 , but as mentioned above I'm not sure if it could be simplified much.

@Aljullu
Copy link
Contributor Author

Aljullu commented Feb 15, 2024

Thanks for your review as well, @gigitux! (Sorry I answered to @tjcafferkey before seeing your reply)

As @tjcafferkey noticed, in the Site Editor, we decided to list only the Product Catalog in the Site Editor. As Tom sustains (and I agree), this would allow us to reduce some complexity.

As mentioned in Tom's reply. Could you clarify how that would simply the codebase? What I understand from the issues is that it's mostly a UI change (and that's why I left it for a task after the refactor), but I might be missing something.

I added a few comments on the BlockTemplatesController containing specific functions for the Product Catalog template and the fallback system. I don't recall the logic (maybe we can remove them), but we should keep the Controller with general-purpose logic. Any dedicated logic for a specific template should be in the class-specific of that template. I'm afraid if we keep some dedicated logic in this class, there is the risk that, in the future, we start to add dedicated logic for a specific template, and we will be back to where we started.

Makes sense. My initial thought was to create an agnostic AbstractTemplateWithFallback class. I will play around with that approach and with moving the logic to the ProductCatalogTemplate and see what looks cleaner.

Also, I noticed that the priority of the templates during the theme switch differs from WordPress's behavior.

Did you investigate if this is a regression? I could reproduce the same in WooCommerce 8.5 and seems to be an instance of what's described in #42181. (Customized WooCommerce templates persist after a theme switch)

@gigitux
Copy link
Contributor

gigitux commented Feb 15, 2024

As mentioned in Tom's reply. Could you clarify how that would simply the codebase? What I understand from the issues is that it's mostly a UI change (and that's why I left it for a task after the refactor), but I might be missing something.

Mainly, I was referring to the BlockTemplatesController. Moving the code to the specific template makes the class easier to read and understand.

Makes sense. My initial thought was to create an agnostic AbstractTemplateWithFallback class. I will play around with that approach and with moving the logic to the ProductCatalogTemplate and see what looks cleaner.

Thanks!

Did you investigate if this is a regression? I could reproduce the same in WooCommerce 8.5 and seems to be an instance of what's described in #42181. (Customized WooCommerce templates persist after a theme switch)

Yeah, it is a regression. I was convicted that the refactor included this kind of bug fixing. It is fine for me if we decide to work on this fix on a dedicated PR 👍

@tjcafferkey
Copy link
Contributor

@gigitux @Aljullu can you remind me what logic like this is for again? What would make a template eligible or ineligible for a fallback?

My thinking was (and maybe I'm over simplifying it):

  • We render the Product Catalog template on all Woo archive pages (except search results?)
  • If a user adds a taxonomy specific template via the UI wouldn't Gutenberg take care of this rendering logic?

I am just trying to identify if we can remove things like this.

@Aljullu
Copy link
Contributor Author

Aljullu commented Feb 15, 2024

Mainly, I was referring to the BlockTemplatesController. Moving the code to the specific template makes the class easier to read and understand.

I started working on #42531 and #42532 in parallel. Hopefully, by the end of tomorrow I will publish another PR (or update this one) with these changes.

Yeah, it is a regression. I was convicted that the refactor included this kind of bug fixing. It is fine for me if we decide to work on this fix on a dedicated PR 👍

Sorry for not being clear with that. My goal with the refactor was not to fix all existing bugs, but just to improve the code and leave things working as they did, that means not intentionally fixing bugs. #44264 is fixed in this PR, but it was mostly a fix that we got "for free".

If a user adds a taxonomy specific template via the UI wouldn't Gutenberg take care of this rendering logic?

I would need to check, but AFAIK it doesn't. Gutenberg supports specific taxonomy templates (ie: a template for the Clothing category). But it's not possible to create a generic "Product Category" template.

@gigitux
Copy link
Contributor

gigitux commented Feb 15, 2024

@gigitux @Aljullu can you remind me what logic like this is for again? What would make a template eligible or ineligible for a fallback?

I don't recall tbh. From a quick look, it seems that we checked the slug of the template: https://github.com/woocommerce/woocommerce/blob/e49543b03cfbfddfad96643acc7080b6bcd82f86/plugins/woocommerce/src/Blocks/Utils/BlockTemplateUtils.php/#L495-L506

Sorry for not being clear with that. My goal with the refactor was not to fix all existing bugs, but just to improve the code and leave things working as they did, that means not intentionally fixing bugs. #44264 is fixed in this PR, but it was mostly a fix that we got "for free".

No worries! Feel free to create a dedicated PR 👍 !

I think that we should aim to make the Controller generic-purpose; the rest of the feedback/suggestions could be implemented with dedicated PRs!

@Aljullu Aljullu force-pushed the update/BlockTemplatesController-refactor branch from b53dc77 to d8b07a5 Compare February 16, 2024 12:24
@ralucaStan
Copy link
Contributor

I'm just doing a smoke test of the PR as I don't have enough context to evaluate the implementation.
Screenshot 2024-02-19 at 13 54 00

Things look good so far. Just 1 thing I noticed when using Tsubaki, the checkout templates still default to WooCommerce. Is this expected?

Also, in this image, I notice that Tsubaki is written in 2 ways: Tsubaki and tsubaki

@gigitux
Copy link
Contributor

gigitux commented Feb 27, 2024

I'm currently experimenting with changes in the template fallback system in #44778. But I would prefer to keep it as a separate PR, as I fear that trying to tackle that in this PR would only increase the amount of code changes and would increase the surface of things to test.

How does it sound?

Completely agree! Thanks for your effort!

Copy link
Member

@dinhtungdu dinhtungdu left a comment

Choose a reason for hiding this comment

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

@Aljullu Thanks so much for working on this PR. The code change (especially class structure and organization) looks great to me.

Testing the PR again with the latest commits, I can see the PR passes the testing instruction except a potential issue, please refer to my testing log below to grab the full context. I'm happy to approve this PR once we're clear about that.

With a classic theme (ie: Storefront).

I tested the following templates and they all loaded as normal.

  • Shop page: ✅
  • Single product page: ✅
  • Cart page: ✅
  • Checkout page: ✅
  • Category: ✅
  • Thank you page: ✅

With a block theme without custom WooCommerce templates (ie: Twenty Twenty-Four)

  • I can visit shop, single product, cart, and checkout pages.
  • I can edit templates in the editor and see the change applied on the front end.
  • I can revert the templates and both reverted or customized work as expected. I have a small issue though, but I don't think it belongs to the scope of this PR:
    • When I edit the product catalog template, all templates inheriting it are marked as customized, like Category or Tag. If I revert one of those templates, all templates and the Product Catalog get reverted as well.

With a block theme with custom WooCommerce templates (ie: Tsubaki)

I first tested with Twenty Twenty-Four and had some customized templates. After I installed and activated Tsubaki, Woo still used the customized templates from Twenty Twenty-Four. Is that expected behavior? If not, does it happen on trunk?

Apart from the above issue, I can edit the templates and see the change applied on the frontend. I can also revert the changes without error.

Make sure Mini-Cart template part from the theme is correctly assigned to the Mini-Cart template part area (#44264)

I can see the Mini Cart provide by Tsubaki is assigned to the correct area.

@Aljullu
Copy link
Contributor Author

Aljullu commented Feb 27, 2024

Thanks for the in-depth review, @dinhtungdu!

  • When I edit the product catalog template, all templates inheriting it are marked as customized, like Category or Tag. If I revert one of those templates, all templates and the Product Catalog get reverted as well.

Good catch! I tested and it's the same in trunk and WooCommerce 8.6, so I would say it shouldn't be a blocker. Also, with the UI changes expected in #42531 and #42532, this won't be reproducible anymore, as we won't be listing the templates which fallback to the Product Catalog template if they haven't been customized. That means there won't be a way to revert their customizations.

I first tested with Twenty Twenty-Four and had some customized templates. After I installed and activated Tsubaki, Woo still used the customized templates from Twenty Twenty-Four. Is that expected behavior? If not, does it happen on trunk?

If I'm not wrong, this is what @gigitux highlighted earlier and what the issue #42181 is about. Customized WooCommerce templates persist after a theme switch, while any non-WC customized template is "attached" to the theme, so they don't persist after a theme switch. That causes some weird issues with customized WooCommerce templates after a theme switch, for example, that they are pointing to the wrong header template part (that's what's described in #42181).

But given that this issue is also present in trunk and WC 8.6, I would also lean towards it not being a blocker of this PR.

Copy link
Contributor

@WunderBart WunderBart left a comment

Choose a reason for hiding this comment

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

I've followed the testing instructions, and everything seems to work as expected! 🎉


I did find two issues, though, but they're likely unrelated to / out of context of this PR:

  1. When opening the Product Catalog template with Tsubaki for the first time, I was presented with the non-blockified template. It transformed seamlessly, though, so no real issue here.

    image

  2. Each time I open the All Templates view, the list seems to be in a different order. For example, when I edited the Product Catalog (Tsubaki) and went back to All Templates, it got pushed to the very top, while the rest of the templates don't seem to be in any specific order:

    Screenshot 2024-02-27 at 17 10 50

    As agreed with @Aljullu, this one will be reported as a separate issue.

Copy link
Member

@dinhtungdu dinhtungdu left a comment

Choose a reason for hiding this comment

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

But given that this issue is also present in trunk and WC 8.6, I would also lean towards it not being a blocker of this PR.

I agree. This PR is LGTM then! 🚢

@gigitux gigitux removed their request for review February 27, 2024 17:54
@gigitux gigitux dismissed their stale review February 27, 2024 17:54

I removed myself as a reviewer given that I didn't follow the progress of this PR given my AFK

@Aljullu
Copy link
Contributor Author

Aljullu commented Feb 27, 2024

Thanks for the reviews, folks! I will go ahead and merge this PR.

@Aljullu Aljullu merged commit b95c15f into trunk Feb 27, 2024
65 checks passed
@Aljullu Aljullu deleted the update/BlockTemplatesController-refactor branch February 27, 2024 18:05
@github-actions github-actions bot added this to the 8.8.0 milestone Feb 27, 2024
@github-actions github-actions bot added the needs: analysis Indicates if the PR requires a PR testing scrub session. label Feb 27, 2024
@WunderBart
Copy link
Contributor

2. Each time I open the All Templates view, the list seems to be in a different order. For example, when I edited the Product Catalog (Tsubaki) and went back to All Templates, it got pushed to the very top, while the rest of the templates don't seem to be in any specific order:
Screenshot 2024-02-27 at 17 10 50
As agreed with @Aljullu, this one will be reported as a separate issue.

Reported in #45180

@alvarothomas alvarothomas added needs: external testing Indicates if the PR requires further testing conducted by testers external to the development team. needs: internal testing Indicates if the PR requires further testing conducted by Solaris status: analysis complete Indicates if a PR has been analysed by Solaris and removed needs: analysis Indicates if the PR requires a PR testing scrub session. labels Feb 28, 2024
Konamiman pushed a commit that referenced this pull request Mar 13, 2024
* Cleanup BlockTemplatesController constructor

* Remove unnecessary elseif

* Remove unnecessary param comment

* Move Single Product Template responsibilities to the SingleProductTemplate.php file

* Move Mini-Cart Template reposnibility to the MiniCartTemplate.php file

* Create the other template files

* Code cleanup

* Move template redirect into template files

* PHP cleanup

* Add changelog entry

* Fix PHP tests

* Replace hardcoded 'archive-product' slug with ProductCatalogTemplate::SLUG

* Make it so AbstractTemplatePart extends AbstractTemplate

* Register templates in BlockTemplatesRegistry

* Fix slug usage in AbstractPageTemplate.php

* Add get_template_title and get_template_description methods to AbstractTemplate

* Cleanup

* Make init functions protected in template classes

* Avoid using static constants and methods in BlockTemplatesRegistry

* Avoid using static constants and methods in block template classes

* Fix lint errors

* Fix Single Product classes not being applied

* Fix tests

* Get BlockTemplatesRegistry directly from BlockTemplateUtils to simplify code

* Init BlockTemplatesRegistry and BlockTemplatesController from Bootstrap.php

* Fix wrong static::SLUG call

* Init template classes from BlockTemplatesRegistry

* Revert "Fix wrong static::SLUG call"

This reverts commit 866c9b9.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
focus: template Issue related to WooCommerce templates. needs: external testing Indicates if the PR requires further testing conducted by testers external to the development team. needs: internal testing Indicates if the PR requires further testing conducted by Solaris plugin: woocommerce Issues related to the WooCommerce Core plugin. status: analysis complete Indicates if a PR has been analysed by Solaris team: Kirigami & Origami
Projects
None yet
7 participants