Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Change default rows for product grid blocks to 3 #1613

Merged
merged 17 commits into from Jan 22, 2020

Conversation

mikejolley
Copy link
Member

@mikejolley mikejolley commented Jan 20, 2020

Changes default rows for all grid blocks from 1 to 3. 3 feels like a better default, and specifically for the all products block it matches the 'grid' icon the block current has (3x3 grid of boxes).

Note: For SSR blocks, existing blocks rows will change to 3, unless the user already changed them away from 1. Gutenberg does not save default values to the block, so it's not possible to know if the user really set it to 1, or left the default enabled.

For the all products block we are handling deprecation, so existing blocks will not change. New blocks will be inserted with 3.

Additionally, all attributes, even defaults, will be saved to the block now. We're doing this using some filters. This will prevent future issues if defaults are changed.

Fixes #1262

How to test the changes in this Pull Request:

  • Add all products block, or any "products by x" block and confirm 3 rows and 3 columns by default. Ensure you're using a default WP theme in case of overrides.
  • Add a all products block using master (should have 1 row), save, then switch branches. Confirm there is still 1 row shown and there are no validation errors.
  • Save a all products block. Check the post content source. Ensure all attributes are saved to the HTML comment.

Changelog

Changed default rows and columns for product grid blocks to 3x3.

@mikejolley mikejolley requested a review from a team January 20, 2020 16:27
@mikejolley mikejolley self-assigned this Jan 20, 2020
Copy link
Contributor

@Aljullu Aljullu left a comment

Choose a reason for hiding this comment

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

This seems to also update blocks that are currently in a page or post.

Steps to reproduce:

  • In master create a post with a Best Seeling Products block and notice it has only one row.
  • git checkout fix/1262-default-rows
  • Reload the post and see now it has three rows.

Should we do something to prevent that? I'm afraid changing the number of rows of already-added blocks might break some user pages.

@mikejolley
Copy link
Member Author

@Aljullu Hmm I assumed the current setting would be saved to the existing blocks. Ill investigate.

@mikejolley
Copy link
Member Author

@Aljullu @nerrad It seems that the only settings saved to blocks are those which differ from defaults, so anyone who left it as the default 1 value will be affected.

Struggling to see a solution to this. I guess we could introduce versioning i.e. an attribute thats stored to a block noting when it was saved/created and then changing default based on that, but it feels hacky.

Maybe just need to bite the bullet and swap defaults if we want to go this direction...

@senadir
Copy link
Member

senadir commented Jan 20, 2020

There is no direct way to deprecate default attributes, I agree with Mike, we should go ahead, while the adoption is small, chances are, not a lot of people have the 1/3 default, we should also leave a dev note explaining this, might be worth getting this into WC 3.9 and not wait until next version where the surface area will be larger

@Aljullu
Copy link
Contributor

Aljullu commented Jan 20, 2020

Would a solution like this work?

  • Update product grid blocks so they always save the columns and rows attributes from now on.
  • Make it so when adding a new block, it uses the new defaults (3x3).
  • For blocks that don't have the columns and rows attributes defined, keep using the old defaults (3x1).

Not sure if it's possible (I didn't take a deep look at the code) and it has the drawback that we will always need to maintain the old defaults. But thought it was worth sharing in case it seems feasible.

@senadir
Copy link
Member

senadir commented Jan 20, 2020

For blocks that don't have the columns and rows attributes defined, keep using the old defaults (3x1).

we don’t have a way to detect this, any newly inserted block or already saved block will fall under this case since default block attributes are parsed from the settings.attributes object of the block.

@nerrad
Copy link
Contributor

nerrad commented Jan 20, 2020

I don't think we should merge this as is because it will lead to the broken behaviour for merchants that have published a block with the defaults because that's what they want.

Here's a suggested solution:

  • For server rendered blocks, we should keep the default attributes at 1 row. This will ensure that any existing blocks that don't have this attribute set will keep the original default.
  • We might be able to hook into block insertion and update the attributes for the block so that the row count is 3 (if the attribute is not set yet). That will help with only applying the defaults to NEW created blocks.

@nerrad
Copy link
Contributor

nerrad commented Jan 20, 2020

Alright I played around with this and I still don't have a solution. However, I discovered the following:

  • If we just change the js side default to 3, and ensure we save attributes for server-side rendered blocks, this will ensure existing rendered blocks on the frontend will stay with 1 row, but as soon as that existing content is edited, the block would get updated to the new default and if the user saves without noticing, the frontend will be affected.
  • Doing the above (or what's in this pull) for the All Products block without a deprecation on the attribute will result in validation error because what is saved for the block is different from what the default is from the server. This isn't an issue if a merchant has picked a different value for the rows and saved.

I'm not sure on a resolution yet to change the default from 3 rows to 1 row for all grid type blocks but it will involve either:

  • deprecating and transforming the existing rows attribute for All Products to take care of potential block validation issues.
  • figuring out how to hook into the Gutenberg block insertion/validation to conditionally update what is used as the rows default when a block is first inserted (leaving things alone for existing blocks in the content). I spent some time seeing if I could figure this out but no luck yet.

Either way, this issue is looking like it's not as easy as I thought it might be initially :(

One final thing, I noticed that the default attributes php side are filled from theme support for the values if it exists. Does this mean that themes can override the defaults? If so, this could be problematic for the All Products block because it means switching themes that change the defaults could end up invalidating any existing All Products block that did not have it's defaults changed to something before saving.

@mikejolley
Copy link
Member Author

Does this mean that themes can override the defaults?

Yes they can. And as we've seen, if defaults change, existing blocks change.

@mikejolley
Copy link
Member Author

Looks like we're been stung by the decision in WordPress/gutenberg#7342 to not save defaults.

Copy link
Contributor

@nerrad nerrad 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 a genius solution that tests really well. Excellent work on coming up with a usable solution Mike! I have a few comments (and I know you're probably already acting on some of them based on our discussion in slack).

assets/js/blocks/products/all-products/index.js Outdated Show resolved Hide resolved
Comment on lines 99 to 109
addFilter(
'blocks.getBlockAttributes',
'woocommerce-blocks/get-block-attributes',
setBlockAttributeDefaults
);

addFilter(
'editor.BlockListBlock',
'woocommerce-blocks/with-default-attributes',
withDefaultAttributes
);
Copy link
Contributor

Choose a reason for hiding this comment

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

As discussed in slack, let's move these into their own location. Since this is an editor only thing, we can probably put this in js/editor/filters.js then in the main entry file (which is built to the wc-blocks handle) we can import it directly. This will also require updating the sideEffects property in package.json to keep webpack from dropping the import during treeshaking.

Copy link
Member Author

Choose a reason for hiding this comment

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

I've added to assets/js/filters and handled in sideEffects. You can see the latest code now.

assets/js/blocks/products/utils.js Outdated Show resolved Hide resolved
* @return {Object} Filtered block attributes.
*/
export const setBlockAttributeDefaults = ( blockAttributes, blockType ) => {
Object.keys( blockType.attributes ).map( ( key ) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Would be good to only run this on our blocks. We're using a non-official property on the block config here, there's risk another block somewhere might be using defaults in a different way.

This also applies to the other filter implementations in this pull (I won't repeat this comment for withDefaultAttributes).

Copy link
Member Author

Choose a reason for hiding this comment

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

Done. Added a check for the block prefix.

*
* @param object BlockListBlock The BlockListBlock element.
*/
const withDefaultAttributes = createHigherOrderComponent(
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this should be moved outside of the js/hocs folder. The hoc here has a very specific use case so it'd be nice to keep it separate for the more general hoc usages. probably would be good to keep it in editor/hocs (staying connected with the filters there) maybe?

Copy link
Member Author

Choose a reason for hiding this comment

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

What about in the filter js file itself since it's so specific?

Copy link
Member Author

Choose a reason for hiding this comment

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

Done 👍

Copy link
Contributor

@nerrad nerrad left a comment

Choose a reason for hiding this comment

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

Looks great! However, I missed a prop mutation that was happening on withDefaultAttributes that will need addressed.

I tested the work with npm run build (which is when tree shaking happens, it doesn't happen on dev builds) and there was no breakage so sideEffects are configured correctly 👍 .

typeof blockType.defaults !== 'undefined' &&
typeof blockType.defaults[ key ] !== 'undefined'
) {
props.attributes[ key ] = blockType.defaults[ key ];
Copy link
Contributor

Choose a reason for hiding this comment

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

I just realized, we shouldn't be directly mutating props. While on the surface this works well, I'm concerned about unexpected bugs surfacing in the future because of this mutation. Instead, I think we should create a new attributes object based off the old and feed that to an attributes prop. So essentially:

return function( { attributes, ...props } ) {
   //below would be inside your blockType.name conditional block ...basically creating a new object.
   attributes = Object.assign( {}, attributes );
   // then you'd have your logic replacing undefined keys if needed.
  return <BlockListBlock attributes={ attributes } { ...props } />
}

Copy link
Contributor

@nerrad nerrad left a comment

Choose a reason for hiding this comment

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

:shipit: 🎉 🌮

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

Successfully merging this pull request may close these issues.

All Products block - rows default
5 participants