After opening a WooCommerce template in the Site Editor, the Save button is always enabled
Prerequisites
- [X] I have carried out troubleshooting steps and I believe I have found a bug.
- [X] I have searched for similar bugs in both open and closed issues and cannot find a duplicate.
Describe the bug
For some reason, opening a WooCommerce template in the Site Editor makes it think it has been edited, so it's listed as a template to be saved.
Expected behavior
If there are no changes in the template, the Save button should be disabled.
Actual behavior
Even there were no changes in the template, the Save button is enabled.
Steps to reproduce
- With a block theme, go to Appearance > Editor > Templates and open a WooCommerce template.
- Without making any change, notice the Save button is enabled, clicking on it suggests saving the template, even though nothing was changed.
WordPress Environment
Tested with WooCommerce trunk on WordPress 6.5 and 6.6 with and without Gutenberg enabled and it could be reproduced in all instances.
Isolating the problem
- [X] I have deactivated other plugins and confirmed this bug occurs when only WooCommerce plugin is active.
- [X] This bug happens with a default WordPress theme active, or Storefront.
- [X] I can reproduce this bug consistently using the steps above.
I replicated this @Aljullu and it resulted in this on the frontend:
You can "reset" from the templates panel to get the page back, or restore from history.
This issue does not happen without gutenberg plugin active, so this seems like a serious regression.
Edit: Just to clarify:
- The "save button" issue also exists without Gutenberg plugin active
- In both instances, content is not lost if you just save on entry.
- Only with Gutenberg active, if you change the global style of a block e.g. mini cart checkout button background color, and save, this is when the content is deleted.
Thanks for the extra testing steps, @mikejolley! (And @dsas for the video in the other thread!)
I could finally reproduce it a couple of times, but it seems to be a hit-or-miss on my machine. Sometimes I can reproduce but most of the times I can't, even following the exact same steps.
I could also only reproduce in the Page: Cart template, but given that I could reproduce it so inconsistently I'm not sure if other templates might be affected or not.
Something I noticed is that when saving a template + global styles at the same time, there are two POST calls made to the template endpoint. That seems to happen with non-WooCommerce templates as well, so I guess it's per design. However, the times I could reproduce the issue the second call didn't contain a content property, so I assume the template was saved empty and that's what's causing the issue. (@dsas, I think you found something similar during your testing, right?)
Only with Gutenberg active
I could reproduce with WP 6.6 without Gutenberg enabled. In that case, I think this should have slightly higher priority.
The "save button" issue also exists without Gutenberg plugin active
Right, I think they are two different issues. However, https://github.com/Automattic/wp-calypso/issues/92191 might only be exposed because of this one. So maybe fixing this one will, in practice, fix https://github.com/Automattic/wp-calypso/issues/92191.
However, the times I could reproduce the issue the second call didn't contain a content property, so I assume the template was saved empty and that's what's causing the issue. (@dsas, I think you found something similar during your testing, right?)
Exactly 💯 The POSTed json was just {"id":"woocommerce/woocommerce//page-cart"} and so the response included "content":{"raw":"","block_version":0} which is GB-speak for empty template.
I have been investigating this issue a bit more, sharing my findings so far:
The cupid of the issue is that for some reason, <ExperimentalBlockEditorProvider /> fires an onChange() event in some WooCommerce templates which makes isEditedPostDirty() to return true, so the UI thinks the template has been modified and can be saved.
Something I also noticed is that the issue is only reproducible depending on the blocks in the template:
- Page: Coming Soon: the issue is never reproducible.
- Page: Cart, Page: Checkout, Page: Order Confirmation: the issue is reproducible because of the
wp:woocommerce/page-content-wrapperblock. Removing it from the templates fixes it. - Product Catalog, Products by Category, etc.: the issue is reproducible because of the Product Collection block. In fact, in the non-blockified templates which don't have this block, the issue isn't reproducible.
- Single Product: the issue is reproducible because of the Product SKU block. Removing it from the template would also fixes it.
The issue seems to be that the problematic blocks are updating their attributes after they are added to the editor canvas. Ie:
https://github.com/woocommerce/woocommerce/blob/3d37c92c7c45f12e3773faff79968ebb2acc8d7c/plugins/woocommerce-blocks/assets/js/blocks/page-content-wrapper/index.tsx#L50
https://github.com/woocommerce/woocommerce/blob/3d37c92c7c45f12e3773faff79968ebb2acc8d7c/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/edit.tsx#L44-L48
Next steps
I think the next steps to solve this issue is to refactor those blocks so they don't update the attributes after they are rendered. Hopefully that would also fix https://github.com/Automattic/wp-calypso/issues/92191. (Note: I'm not very familiar with any of those blocks so I'm not sure how easy/feasible it is).
Given the impact of https://github.com/Automattic/wp-calypso/issues/92191, I would say that's probably high-priority, at least updating the Page Content Wrapper block. What do you think, @mikejolley?
Thanks for looking @Aljullu
cc @ralucaStan @opr
More reproduction instructions to get the template to delete, it appears that reloading the page is required for this to happen.
- In a block theme, go to Appearance -> Editor -> Templates -> Page: Checkout
- In the top right of the screen, click the styles icon, edit any property (e.g. Color -> Text)
- Save the page.
- Reload the page
- Repeat steps 2 & 3
- Notice the template is gone.
I didn't have to refresh for the template to be deleted. It happened straight away, I tested by looking at the front-end after hitting save. That the site-editor displayed the 'new page pattern selection dialog' after saving is also a clue.
You possibly have to refresh the page for the site-editor to fully understand the template is deleted.
@dsas strange that we can reproduce differently! When looking at the front end after the first save, the block renders normally for me.
I took a look into the woocommerce/page-content-wrapper block and found:
- The block has two attributes that provide context:
postIdandpostType. These will hold the values for the cart/checkout pages. - This context is required to render the
core/post-titleandcore/post-contentblocks within. - The template does not supply a
postIdbecause it's impossible to know this and hard-code it into the template. - I believe the attribute is set during render because that is the first opportunity we get to do so, passing it earlier isn't possible, and it really should update every time the it should update if the cart/checkout
I I would appreciate some guidance on whether this is something we can solve at the PHP level. I'm not super familiar with how the templates are rendered, but I am confident that if we can supply the correct attribute to the block before it renders it would solve this problem.
I'm not super familiar with how the templates are rendered, but I am confident that if we can supply the correct attribute to the block before it renders it would solve this problem.
I don't know much about Woo, and basically zero about woo blocks, but you can change the rendering in PHP before it hits the front-end. It's called a dynamic block.
I would appreciate some guidance on whether this is something we can solve at the PHP level.
Just mentioning that I took a look as well and found the same that you mentioned. We set the attribute on render and I couldn't find an easy way to set it before. However, my thinking is that the solution will need to be implemented from the JS-side, not the PHP-side, as the Page Content Wrapper block is registered in JS and the issue happens in the Site Editor (which is in the JS-side), no? :thinking:
I could come up with a couple of ideas to solve it. I'm not really fond to any of them, but mentioning in case they are useful:
- We could register/unregister the block when navigating between templates, similar to what we do with the Classic Template block. So when opening the Cart template, we register it with the Cart default attributes, when opening the Checkout template, we register it with the Checkout default attributes, when viewing all templates at once, we default to the current behavior. This definitely increases the code complexity, though.
- An alternative would be to have two different blocks. The Checkout Page Wrapper and the Cart Page Wrapper. This way we could register them with the correct default attributes from the beginning and wouldn't need to track the user navigating through templates. The con of this approach is that it requires updating the existing HTML templates.
- I didn't experiment with it, but Gutenberg has a
__unstableMarkNextChangeAsNotPersistent()action which is used internally to mark updates in the content that shouldn't be considered as content updates. Maybe firing it before we update the attributes would fix it? The con is that it's an unstable API and it increases the complexity of the code.
None of those solutions is perfect, though. Another question that comes to my mind: why do we need the Page Content Wrapper block at all? Couldn't we simply hide the Cart & Checkouts pages in block themes and assume users will make edits to the templates instead of the pages?
I don't know much about Woo, and basically zero about woo blocks, but you can change the rendering in PHP before it hits the front-end. It's called a dynamic block.
I think this can't be used in this specific case, as we need to pass down the postId context to the inner components. :thinking:
I am experiencing this bug as well. Is there any progress on a fix?
Given that this issue affects several blocks, we created two specific issues for Product element blocks and the Product Collection block:
- https://github.com/woocommerce/woocommerce/issues/57056
- https://github.com/woocommerce/woocommerce/issues/51671
This way, things are broken into smaller tasks.
We don't have an issue specific to the Cart and Checkout "Page Content Wrapper" block, but we can refocus this one for this.