Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upTry Legacy widget block #13511
Conversation
jorgefilipecosta
force-pushed the
try/legacy-widget-block
branch
from
4af57d5
to
35e0180
Jan 25, 2019
This comment has been minimized.
This comment has been minimized.
Awesome work here. What's the plan to move forward here.
And let's get some technical feedback here. |
youknowriad
requested a review
from WordPress/gutenberg-core
Jan 29, 2019
youknowriad
added
REST API Interaction
Blocks
Widgets
labels
Jan 29, 2019
jorgefilipecosta
referenced this pull request
Jan 29, 2019
Merged
Add: className prop support to server side render. #13568
afercia
added
the
Accessibility
label
Jan 30, 2019
melchoyce
added this to In Progress
in Porting widgets to blocks
Jan 30, 2019
This comment has been minimized.
This comment has been minimized.
I think it should be divided into 3 parts:
The third part although smaller than this PR is still huge, but I don't think there is a possible usable logical division for this part. I agree this provides a good use case for feature flags. Besides conditional JS code, we may also need some conditional PHP code. I'm not sure if feature flags will/should touch PHP logic. Probably for PHP code we can keep it in the plugin without conditions and don't merge it to the core. It will be an additional source of friction if later we need to move some PHP code to core as we will need to carefully select the parts of the code that will be moved. |
This comment has been minimized.
This comment has been minimized.
@jorgefilipecosta I tried it out and am missing all the in-block widget settings. Am I missing something? |
jorgefilipecosta
force-pushed the
try/legacy-widget-block
branch
from
35e0180
to
790b2d5
Jan 31, 2019
This comment has been minimized.
This comment has been minimized.
Hi @mapk, the widget settings at least for the core blocks should just work and appear without problems. I tested in chrome and safari and they are working correctly in my case. |
This comment has been minimized.
This comment has been minimized.
@jorgefilipecosta I've got the docker install of WordPress 5.0.3 running as outlined in the Contributions doc. There are a lot of |
jorgefilipecosta
force-pushed the
try/legacy-widget-block
branch
2 times, most recently
from
0323d29
to
1fc4c1f
Feb 1, 2019
This comment has been minimized.
This comment has been minimized.
Hi @mapk, It turns out that my WordPress local install was modified with a display: none commented that I need to overwrite here. My last push adds a |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
2. The two "edit" buttons are a bit awkward. 3. Select to change widget loses settings. |
This comment has been minimized.
This comment has been minimized.
I don't know that we lost any settings when converting core widgets to blocks — what if we didn't include them here, and only used it to display third-party widgets? |
gziolo
assigned
jorgefilipecosta
Feb 5, 2019
gziolo
self-requested a review
Feb 5, 2019
jorgefilipecosta
requested a review
from
westonruter
Feb 5, 2019
This comment has been minimized.
This comment has been minimized.
For the REST API endpoint, you can cross-reference with some prior art in https://github.com/xwp/wp-js-widgets/blob/develop/php/class-js-widgets-rest-controller.php |
This comment has been minimized.
This comment has been minimized.
Is there any need for the Update button? The Customizer normally does not include it, for example. It just listens to |
gziolo
added this to the 5.2 (Gutenberg) milestone
Feb 7, 2019
jorgefilipecosta
force-pushed the
try/legacy-widget-block
branch
from
bad0884
to
bcf144c
Feb 8, 2019
jorgefilipecosta
requested a review
from
aduth
as a
code owner
Feb 8, 2019
youknowriad
approved these changes
Mar 7, 2019
Do you think it's possible to e2e test this? Otherwise, let's ship to get feedback and iterate. Ideas:
This kind of legacy work can only be properly tested in real usage. |
jorgefilipecosta
force-pushed the
try/legacy-widget-block
branch
from
0cbb272
to
daa8163
Mar 8, 2019
jorgefilipecosta
force-pushed the
try/legacy-widget-block
branch
from
daa8163
to
a974bba
Mar 8, 2019
jorgefilipecosta
merged commit b421fc9
into
master
Mar 8, 2019
jorgefilipecosta
deleted the
try/legacy-widget-block
branch
Mar 8, 2019
This comment has been minimized.
This comment has been minimized.
Thank you all for the reviews. I merge this PR so we can advance with other enhancements and discuss them separately e.g: use iframes to make the previews totally reliable making sure the editor styles are not affected. The block is behind a feature flag and marked as experimental. Feel free to continue to post your comments here, and I will open follow up PR's to address them. |
noisysocks
reviewed
Mar 11, 2019
Sorry I'm so late to review! Hoping that we can freely iterate on this since it's all behind a feature flag I focused mainly on the PHP changes. I'm a little confused about the design of the |
/** | ||
* Constructs the controller. | ||
* | ||
* @access public |
This comment has been minimized.
This comment has been minimized.
'/' . $this->rest_base . '/(?P<identifier>[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)/', | ||
array( | ||
'args' => array( | ||
'identifier' => array( |
This comment has been minimized.
This comment has been minimized.
noisysocks
Mar 11, 2019
Member
identifier
feels oddly formal. We use id
a lot in other places, including in wp-includes/widgets.php
. Up to you!
This comment has been minimized.
This comment has been minimized.
jorgefilipecosta
Mar 13, 2019
Author
Member
Hi @noisysocks,
I used identifier because this field is not the widget id, it may be the widget id for call back widgets after #14395 is landed, or it may be the class name for class widgets.
So in order to differentiate from the widget id I used identifier.
* | ||
* @see WP_REST_Controller | ||
*/ | ||
class WP_REST_Widget_Updater_Controller extends WP_REST_Controller { |
This comment has been minimized.
This comment has been minimized.
noisysocks
Mar 11, 2019
Member
We're missing unit tests for this controller. WordPress has a really great API for writing REST API tests, check out trunk for examples: https://core.trac.wordpress.org/browser/trunk/tests/phpunit/tests/rest-api?order=name
} ); | ||
} | ||
|
||
requestWidgetUpdater( instanceChanges, callback ) { |
This comment has been minimized.
This comment has been minimized.
if ( null === $instance ) { | ||
$instance = array(); | ||
} | ||
$id_to_use = $request->get_param( 'id_to_use' ); |
This comment has been minimized.
This comment has been minimized.
noisysocks
Mar 11, 2019
Member
Why does the client need to provide this? What would be wrong with the server always using -1
?
This comment has been minimized.
This comment has been minimized.
jorgefilipecosta
Mar 13, 2019
Author
Member
The server uses this value to compute the id's used in the forms. Most JavaScript widgets have a check and if an id was initialized before they do nothing. So we need a unique id per widget instance if we used -1 all the time most JS widgets would only support a single instance.
), | ||
), | ||
array( | ||
'methods' => WP_REST_Server::EDITABLE, |
This comment has been minimized.
This comment has been minimized.
noisysocks
Mar 11, 2019
Member
Does this method make any changes on the server that are visible to future requests? If not, it's considered safe and is more of a GET
request than a POST
request.
This comment has been minimized.
This comment has been minimized.
jorgefilipecosta
Mar 13, 2019
Author
Member
Initially, I used EDDITABLE because we may have a widget that has side effects (that's unexpected but we never know what plugins will do). With the improvements being made in #14395, for callback widgets now we apply a change so it makes sense to use editable.
$widget_obj = $wp_widget_factory->widgets[ $widget ]; | ||
$instance = $request->get_param( 'instance' ); |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
jorgefilipecosta
Mar 13, 2019
Author
Member
The instance represents, the previous widget instance normally saved on the database (in our case save as the block attributes). Instance changes represent the fields that are being changed. That's how the widgets work, the update method receives the previous instance and the changes and returns a new instance.
aduth
reviewed
Mar 12, 2019
@@ -46,6 +46,21 @@ function the_gutenberg_project() { | |||
<div id="metaboxes" class="hidden"> | |||
<?php the_block_editor_meta_boxes(); ?> | |||
</div> | |||
<?php | |||
/** | |||
* Start: Include for phase 2 |
This comment has been minimized.
This comment has been minimized.
aduth
Mar 12, 2019
Member
We must find another way to extend this. It's slated for removal in #13569.
This comment has been minimized.
This comment has been minimized.
aduth
Mar 12, 2019
•
Member
Does it need to occur where it is in the markup here? Or could it be done as hook handlers to admin_print_footer_scripts
and admin_footer
?
aduth
reviewed
Mar 12, 2019
@@ -872,34 +872,83 @@ function gutenberg_editor_scripts_and_styles( $hook ) { | |||
); | |||
} | |||
/** |
This comment has been minimized.
This comment has been minimized.
aduth
Mar 12, 2019
Member
As by the previous note, this function doesn't exist as of #13569.
All new functionality should extend the block editor as if it were any other plugin extending the core block editor.
aduth
reviewed
Mar 12, 2019
/** | ||
* Start: Include for phase 2 | ||
*/ | ||
'hasPermissionsToManageWidgets' => $has_permissions_to_manage_widgets, |
This comment has been minimized.
This comment has been minimized.
aduth
Mar 12, 2019
Member
It doesn't seem like this should be an editor setting. We have precedent for this sort of permissions check using REST API links.
aduth
referenced this pull request
Mar 12, 2019
Merged
Plugin: Remove replace_editor filter, extend core editor #13569
jorgefilipecosta
referenced this pull request
Mar 12, 2019
Open
Fix: Legacy widget: callback widgets with a edit form. #14395
Tug
added a commit
that referenced
this pull request
Mar 14, 2019
jorgefilipecosta
referenced this pull request
Mar 18, 2019
Merged
Bump plugin version to 5.3.0-rc.1 #14489
This comment has been minimized.
This comment has been minimized.
@jorgefilipecosta It is a real shame that this PR doesn't use WP-API's existing widget's endpoint that can be found https://github.com/WP-API/wp-api-menus-widgets-endpoints/blob/master/lib/class-wp-rest-widgets-controller.php |
Mar 20, 2019
This was referenced
youknowriad
added a commit
that referenced
this pull request
Mar 20, 2019
youknowriad
added a commit
that referenced
this pull request
Mar 20, 2019
Tug
added a commit
that referenced
this pull request
Mar 21, 2019
aduth
referenced this pull request
Mar 22, 2019
Closed
Undefined index: description in [...]/plugins/gutenberg/lib/widgets.php on line 98 #14552
This comment has been minimized.
This comment has been minimized.
alexvornoffice
commented
Mar 22, 2019
a lot of widgets will not work because of a lot of factors... so will this idea be implemented or revoked? |
mkevins
added a commit
to mkevins/gutenberg
that referenced
this pull request
Mar 26, 2019
mkevins
added a commit
to mkevins/gutenberg
that referenced
this pull request
Mar 26, 2019
This comment has been minimized.
This comment has been minimized.
Hi @spacedmonkey and @alexvornoffice thank you for sharing your thoughts.
This PR had a very specific need for an endpoint that executed the widget update logic without changing anything in the database and that also returned the HTML form. It also needs to access widgets that are installed but for which no instance is currently using them. During the research I did it seemed the endpoint you suggested would not cover these needs.
Most widgets not working fall into two categories:
Both these problems will be mitigated as soon as we use the block in the widget screen itself. Because the dom will be more similar and because the checks depending on the screen will continue to verify. That said this solution is far from perfect and we are improving it. If someone has an idea for a better/more reliable approach we can give a try, we are totally open to alternatives. |
This comment has been minimized.
This comment has been minimized.
@jorgefilipecosta So this API is not designed to a the canonical REST API for Widget to create / edit / delete / get them? It only does 2 very limited things? Then why name widgets? This stops us using that namespace for a real CRUD api latest. Creating api that have limited / confusing use seems unwise. REST api, should implement all methods where possible. |
This comment has been minimized.
This comment has been minimized.
Just wanted to mention based on my reading, I don't think it'll work for registering a widget instance. ie |
jorgefilipecosta commentedJan 25, 2019
•
edited
Description
Implements: #4770
This PR is a proof of concept of a legacy widget block. A block that allows existing WordPress widgets to be added as Gutenberg blocks.
The design is similar to the one proposed by @melchoyce in #4770 (comment) (option 1). Although it seems option two was preferred, it would require to expose each widget as a block similar to what embeds do, and it would increase the technical complexity and make testing/debugging harder, so I preferred to use option 1 for now. I will gladly iterate on the UX after this proof of concept gets more stable.
Some technical details
The available widgets are preloaded to Gutenberg similar to what happens with page templates.
REST-API user story
I want to able to pass a widget identifier to an endpoint, pass the existing widget attributes and the changes the user is making if any, and receive from the rest API, the sanitized new widget attributes ready to save and an HTML form that allows the user to edit the widget in the new state.
REST-API endpoint
A very simple REST-API endpoint was implemented. The endpoint receives the previous instance of a widget (previous attributes) the changed instance of a widget (changed attributes if any) and returns the new instance of the widget and the HTML form that allows editing this widget.
There are two ajax-admin endpoints save-widget and update-widget. It looks like each one has specificities that make using it here complex. The ajax admin code would probably require some changes to be used here. Our use case is straightforward from the backend perspective as the widget does not need to be saved anywhere, and the widget is not associated with any widget area. The most straightforward approach seemed to be using a very simple endpoint. If I missed something and adapting existing endpoints is simpler feel free to comment, and I will have a look.
Block Architecture
The edit component of the block handles the start placeholder that allows selecting a widget, and the tab mechanism that allows switching between edit and preview.
The preview is done using the ServerSideRender component.
The edit is done using two components:
WidgetEditHandler: Is responsible for server communication using the endpoint we created, and for keeping the required local state for the edition. Renders an update button, when pressed we retrieve from the dom the changed fields (using a method provided by WidgetEditDomManager) issues a request to the server and updates the legacy widget instance attribute with the server answer.
WidgetEditDomManager: Component responsible for rendering the starting dom for a widget. After the first render React never rerenders the component again, the content rendered by this component is then managed by the scripts the widgets may implement. When a new instance of the form HTML is received we manually update the dom changing .widget-content (like the customizer and the widget screen) do. This component provides a method that returns an object with the widget changed attributes. When this component is mounted it triggers a widget-added event when a new update happens and the dom is changed by the component widget-update jQuery event is triggered.
On front end widget are rendered with a simple call to the_widget.
Screenshots
Known problems
The block is not aware of any change inside the widget until the update button is pressed. This replicates the save button on the widgets screen. But it is annoying if we change something on the widget and go to the widget preview right away our changes are not reflected in the preview. Having an explicit update, makes testing and debugging easier, we may than explore other approaches e.g.: also save when preview happens, save on blur events, etc.
The text widget that contains TinyMCE crashes and fails to init. It calls wp.editor.initialize to reference TinyMCE and on Gutenberg, wp.editor is our editor module. This problem may have happened with meta boxes if it was solved probably the same approach may be applied.
The widget design may be affected by CSS that exists in Gutenberg, so the design of the widgets does not look the same. Ideally, Gutenberg CSS would not affect the widgets but as they are on the same page that's not the case.
Some third-party widgets using don't initialize correctly. That happens because the dom of the editor is not equal to the dom of the customizer and/or the widget screen. Some JS widgets use click events on the widgets screen to initialize while on Gutenberg these events don't happen, some check if they are on the customizer page (body contains customizer classes) before handling widget-updated events. Normally adapting a widget that does not initialize correctly is a matter of changing a very simple condition on the plugin.