-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Extensibility: Convert all filters for components to behave like HOCs #3827
Conversation
blocks/block-edit/index.js
Outdated
} | ||
|
||
export default BlockEdit; | ||
export default withFilters( 'BlockEdit' )( BlockEdit ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since the filters are "global", we should think of namespacing them: core/blocks/BlockEdit
. It's not allowed right now in the hooks package and it's not required for this PR I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can put Blocks.BlockEdit
until hooks
package gets updated.
blocks/hooks/index.js
Outdated
@@ -1,7 +1,7 @@ | |||
/** | |||
* WordPress dependencies | |||
*/ | |||
import { createHooks } from '@wordpress/hooks'; | |||
import * as hooks from '@wordpress/hooks'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we drop this and just import it when it's used (on each of the hooks files)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could. I need to play with unit tests, but given that they are isolated, we should be good.
Good work here, I like it but I think this doesn't address the filters ordering issue yet. Imagine a plugin using reusable components from the "blocks" module to add hooks, it still depends on the "blocks" module and will be executed after the "registerBlockType" calls. I think we should move the "registerBlockType" calls to the |
Good point. I didn't take into account such use case. Let's address it separately then :) |
7e3d4d4
to
58f7748
Compare
Codecov Report
@@ Coverage Diff @@
## master #3827 +/- ##
==========================================
+ Coverage 37.7% 38.08% +0.38%
==========================================
Files 279 279
Lines 6749 7183 +434
Branches 1228 1348 +120
==========================================
+ Hits 2545 2736 +191
- Misses 3541 3718 +177
- Partials 663 729 +66
Continue to review full report at Codecov.
|
@gziolo is it a good idea to allow hooks to change the How will a plug-in implementor know what element a hook will receive if each hook can return anything it chooses? The existing use cases for hooks are either adding a prop to |
6944810
to
7bba1db
Compare
ce2bbae
to
a46d71a
Compare
The same issue applies to all other hooks. We don't check the return value of the individual filters. I don't know how it is handled on PHP side. If the return value of the filter is validated then we should bake in a similar logic here. I feel like this is a completely different issue than what I was concerned when I proposed the changes with this PR.
We were operating inside the render method of the existing |
I rebased with the latest changes. Added some small refinements. I'm planning to merge it on Monday morning if there are no blockers discovered. |
addFilter( 'BlockEdit', 'core-custom-class-name-inspector-control', addInspectorControl ); | ||
addFilter( 'getSaveContent.extraProps', 'core-custom-class-name-save-props', addSaveProps ); | ||
export default function customClassName() { | ||
addFilter( 'blocks.registerBlockType', 'core/custom-class-name/attribute', addAttribute ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have strong opposition, but noting that there's a few implied conventions being introduced here:
- Scoping filter names by with dot-separated namespaces
- Any risk of confusion with other namespacing with
/
?
- Any risk of confusion with other namespacing with
- Multiple levels of namespacing, i.e. not just
core/
but alsocore/custom-class-name/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Slash is not allowed for hook names... we need another patch if we want to change that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can revisit namespaces, too. I’m fine with having only 2 first parts or open to other ideas.
customClassName( hooks ); | ||
generatedClassName( hooks ); | ||
matchers( hooks ); | ||
anchor(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: Do we need to export these as functions anymore, or can they just call to addFilter
when imported?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might not play well with unit tests. Need to verify.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In theory, we could export individual functions and apply filters when importing. I will open a follow-up so we could discuss it individually.
@@ -534,4 +533,5 @@ export default compose( | |||
isLocked: !! templateLock, | |||
}; | |||
} ), | |||
withFilters( 'editor.BlockListBlock' ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain the reason for this reordering?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I need to double check with Collaborative Editing. If it gets executed after connect, we can reuse props passed when filtering. Otherwise the get passed too late so we need to grab them using selectors twice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I can confirm it is correct. If withFilters
would be first in the compose chain it would become the outermost component, which means React would render it first. As explained above, we want to have it last in the chain to make sure we have all other HOCs applied so we can take advantage of their modifications. This is how it makes the most sense for Collaborative Editing. Let's see how it works in general. We can refine later.
Should a plugin implementer need to know whether it is the original BlockEdit or an enhanced one? |
Let's merge it and focus on data extensibility :) We have just released 1.9.0 so that buys some time to iterate on extensibility. |
Description
This PR tries to bring idea exercised when working on Collaborative Editing in #3741. It turned out that it would be a better idea to use Higher-Order Components approach for using filtering hook with the existing components. This seems like a more natural way of dealing with React component and is de facto a community standard. This PR also tries to address other issues mentioned in other places:
#3800 (comment):
It's going to be updated with this PR.
wp-hooks
is always registered beforewp-blocks
, so it should be possible. This change enforces plugin developer to always register a hook before the modified module is going to to be imported.#3621 (comment)
c9310eb addresses it.
How Has This Been Tested?
Manually, e2e and unit tests.
Types of changes
Refactoring. No visual changes. Everything should work as before.
Checklist: