WordPress / gutenberg

The Block Editor project for WordPress and beyond. Plugin is available from the official repository.
https://wordpress.org/gutenberg/
Other
10.34k stars 4.13k forks source link

Comments Form blocks #38107

Open SantosGuillamot opened 2 years ago

SantosGuillamot commented 2 years ago

1. Goal of the project

The purpose of this project is to make the Comments Form customizable through blocks. In the same way that you can change the footer or the header with blocks and without code, it would be nice to do the same with this form.

Right now, in order to use the Comment Form in a FSE site, there is a Post Comments Form block which is just a wrapper around the comment_form function (explained later), but it doesn’t allow users to edit it through blocks.

Apart from that, it could be interesting to analyze if it makes sense to make some of these blocks (like the textarea, submit button…) reusable in other forms.

2. Out of scope

New functionalities to the Comments Form wouldn’t be covered in this project. It would consist of replicating the current form but making everything customizable from the editor.

3. Existing solution

Before diving into how the comment form blocks could be implemented, it’s interesting to understand the current workflow to post a new comment.

Excalidraw link ux-workflow

As we can see, depending on the global settings and if the user is logged in or not, the interface will be different.

In classic WordPress themes, the common way to display the comment form is to use the comment_form() function, which returns the proper HTML depending on the args. It is usually added in the themes comments.php file. For example, the twentytwenty-one theme adds it this way:

comment_form(
        array(
            'logged_in_as'       => null,
            'title_reply'        => esc_html__( 'Leave a comment', 'twentytwentyone' ),
            'title_reply_before' => '<h2 id="reply-title" class="comment-reply-title">',
            'title_reply_after'  => '</h2>',
        )
    );

You can check all the args in the comment_form documentation. This way, developers are able to modify the HTML returned by the function.

Apart from that, it includes a bunch of actions and filters that allow plugin/theme developers to interact/modify it. Probably, many current plugins are already using them, so this has to be taken into account for backward compatibility. These old hooks should be included, whenever possible, inside the new block implementations.

Once the form is filled and submitted, the data is sent to /wp-comments.php , which processes it. At this point, it checks if the form is valid and, depending on the result, it returns an error or redirects the user to the new comment.

For future reference, this is the list of actions and filters included in the comment_form documentation:

Actions
These are the actions triggered in the `comment_form()` function: 1. `comment_form_comments_closed` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_comments_closed/): Fires after the comment form if comments are closed. When `! comments_open( $post_id )` is true. 2. `comment_form_before` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_before/): Fires before the comment form. 3. `comment_form_must_log_in_after` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_must_log_in_after/): Fires after the HTML-formatted ‘must log in after’ message in the comment form. 4. `comment_form_top` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_top/) Fires at the top of the comment form, inside the form tag. 5. `comment_form_logged_in_after` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_logged_in_after/) Fires after the is_user_logged_in() check in the comment form. 6. `comment_form_before_fields` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_before_fields/): Fires before the comment fields in the comment form, excluding the textarea. 7. `comment_form_after_fields` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_after_fields/): Fires after the comment fields in the comment form, excluding the textarea. 8. `comment_form` — [Link](https://developer.wordpress.org/reference/hooks/comment_form/): Fires at the bottom of the comment form, inside the closing form tag. 9. `comment_form_after` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_after/): Fires after the comment form.
Filters
These are the filters applied in the `comment_form()` function. Most of them are used to change the form fields HTML. 1. `comment_form_default_fields` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_default_fields/): Filters the default comment form fields (author, email, url and cookies). 2. `the_permalink` — [Link](https://developer.wordpress.org/reference/hooks/the_permalink/): Filters the display of the permalink for the current post. 3. `comment_form_defaults` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_defaults/): Filters the comment form default arguments. Use {@see ‘comment_form_default_fields’} to filter the comment fields. 4. `comment_form_logged_in` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_logged_in/): Filters the ‘logged in’ message for the comment form for display. 5. `comment_form_fields` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_fields/): Filters the comment form fields, including the textarea. 6. `comment_form_field_comment` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_field_comment/): Filters the content of the comment textarea field for display. 7. `comment_form_field_{$name}` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_field_name/): Filters a comment form field for display. The dynamic portion of the filter hook, $name, refers to the name of the comment form field. Such as ‘author’, ’email’, or ‘url’. 8. `comment_form_submit_button` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_submit_button/): Filters the submit button for the comment form to display. 9. `comment_form_submit_field` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_submit_field/): Filters the submit field for the comment form to display. The submit field includes the submit button, hidden fields for the comment form, and any wrapper markup.

4. Potential solution

Just to clarify, this is just a rough initial idea about how the Comment Form blocks could be implemented. We have to properly discuss it and agree on a solution.

A Comment Form template block could be implemented, which could act as a wrapper for its inner blocks. The same way it works in the Comment Query Loop block for example.

Excalidraw link possible-implementation

Taking this into account, these could be the blocks needed. I’ve included as well the fields, actions, and filters that could be related and a list of potential settings, but I guess this would be better discussed in each individual issue once the structure is clear and they are created.

1 - Comment Form template
This would be the wrapper of the rest of the blocks, and it should include the form settings. One aspect to consider, as mentioned before, is that the interface may change based on if the user is logged in or not. It isn’t still clear how this should be handled. There is an ongoing conversation to discuss [how to handle different interfaces depending on the user state](https://github.com/WordPress/gutenberg/discussions/38108). If we follow, for example, what [WooCommerce Gutenberg Blocks plugin](https://github.com/woocommerce/woocommerce-gutenberg-products-block) is doing with [the cart block](https://github.com/woocommerce/woocommerce-gutenberg-products-block/tree/trunk/assets/js/blocks/cart-checkout/cart), we could add a setting in this wrapper to switch between the different views. For context, this is how it looks in the mentioned plugin: _When “Filled Cart” is selected_ ![screen-shot-2021-11-29-at-14 31 08 (1)](https://user-images.githubusercontent.com/34552881/150299351-2c304746-c7eb-4039-b68e-9f9919095416.png) _When “Empty Cart” is selected_ ![screen-shot-2021-11-29-at-14 31 52](https://user-images.githubusercontent.com/34552881/150299403-a46c585a-3f5f-4fb9-b449-e1bc4c26ee0e.png) ### **_Related fields_** - id_form - class_container - class_form - format - action ### **_Related actions_** - `comment_form_comments_closed` – [Link](https://developer.wordpress.org/reference/hooks/comment_form_comments_closed/). - `comment_form_before` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_before/). - `comment_form_top` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_top/). - `comment_form_logged_in_after` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_logged_in_after/). - `comment_form_before_fields` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_before_fields/). - `comment_form_after_fields` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_after_fields/). - `comment_form` — [Link](https://developer.wordpress.org/reference/hooks/comment_form/). - `comment_form_after` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_after/). ### _**Related filters**_ - `comment_form_default_fields` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_default_fields/). - `comment_form_defaults` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_defaults/). - `comment_form_fields` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_fields/). ### _**Potential settings**_ - Change the view between logged in / logged out. - Id. Related to `id_form` field. - Classname container. Related to `class_container` field. - Classname form. Related to `class_form` field. - Format. Related to `format` field. - Should we provide a setting to change the action as well?
2 - Title Reply / Reply to
In the same way we could change the view in the template block, we could implement something similar here to switch between new comments and replies. ### **_Related fields_** - title_reply - title_reply_to - title_reply_before - title_reply_after - cancel_reply_before - cancel_reply_after - cancel_reply_link ### _**Related actions**_ I think there aren’t related actions. ### **_Related filters_** - `comment_form_defaults` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_defaults/). ### **_Potential settings_** - Setting to change the view between Reply / Reply to. - Select heading level (h1, h2, h3…).
3 – Before content
Depending on the view and the settings, the message below the title will be different, but the styles could be reused. Not sure if it makes sense to have a parent block wrapping 3, 4 and 5 or just handle them separately. ### **_Related fields_** - logged_in_as - must_log_in - comment_notes_before ### **_Related actions_** - `comment_form_must_log_in_after` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_must_log_in_after/) ### **_Related filters_** - `comment_form_defaults` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_defaults/) - `the_permalink` — [Link](https://developer.wordpress.org/reference/hooks/the_permalink/) - `comment_form_logged_in` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_logged_in/)

I believe 3, 4 and 5 could be wrapped in the same block.

6 – Content
This would be the input of the comment content. ### **_Related fields_** - comment_field - comment_notes_after ### **_Related actions_** I think there aren’t related actions. ### **_Related filters_** - `comment_form_fields` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_fields/) - `comment_form_field_comment` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_field_comment/)
7 – Name
This would be the input for the name. Depending on the global settings, it may be required or not. ### **_Related fields_** - author ### **_Related actions_** I think there aren’t related actions ### **_Related filters_** - `comment_form_default_fields` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_default_fields/) - `comment_form_fields` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_fields/) - `comment_form_field_{$name}` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_field_name/)
8 – Email
This would be the input for the email. Depending on the global settings, it may be required or not. ### **_Related fields_** - email ### **_Related actions_** I think there aren’t related actions. ### **_Related filters_** - `comment_form_default_fields` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_default_fields/) - `comment_form_fields` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_fields/) - `comment_form_field_{$name}` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_field_name/)
9 – Website
This would be the input for the website field. ### **_Related fields_** - URL ### **_Related actions_** I think there aren’t related actions ### **_Related filters_** - `comment_form_default_fields` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_default_fields/) - `comment_form_fields` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_fields/) - `comment_form_field_{$name}` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_field_name/)
10 – Cookies
This would be the input of the cookies field and its message. Depending on the global settings, it may appear or not. I guess we could even overwrite the global setting from the block. ### **_Related fields_** - cookies ### **_Related actions_** I think there aren’t related actions ### **_Related filters_** - `comment_form_default_fields` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_default_fields/) - `comment_form_fields` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_fields/)
11 – Submit button
This block should handle the submit button. ### **_Related fields_** - id_submit - class_submit - name_submit - label_submit - submit_button - submit_field ### **_Related actions_** I think there aren’t related actions. ### **_Related filters_** - `comment_form_defaults` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_defaults/). - `comment_form_submit_button` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_submit_button/). - `comment_form_submit_field` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_submit_field/).

5. Requirements

I would say there are two main requirements here:

6. References

  1. comment_form_comments_closedLink: Fires after the comment form if comments are closed. When ! comments_open( $post_id ) is true.
  2. comment_form_beforeLink: Fires before the comment form.
  3. comment_form_must_log_in_afterLink: Fires after the HTML-formatted ‘must log in after’ message in the comment form.
  4. comment_form_topLink Fires at the top of the comment form, inside the form tag.
  5. comment_form_logged_in_afterLink Fires after the is_user_logged_in() check in the comment form.
  6. comment_form_before_fieldsLink: Fires before the comment fields in the comment form, excluding the textarea.
  7. comment_form_after_fieldsLink: Fires after the comment fields in the comment form, excluding the textarea.
  8. comment_formLink: Fires at the bottom of the comment form, inside the closing form tag.
  9. comment_form_afterLink: Fires after the comment form.
Relevant filters
These are the filters applied in the `comment_form()` function. Most of them are used to change the form fields HTML. 1. `comment_form_default_fields` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_default_fields/): Filters the default comment form fields (author, email, url and cookies). 2. `the_permalink` — [Link](https://developer.wordpress.org/reference/hooks/the_permalink/): Filters the display of the permalink for the current post. 3. `comment_form_defaults` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_defaults/): Filters the comment form default arguments. Use {@see ‘comment_form_default_fields’} to filter the comment fields. 4. `comment_form_logged_in` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_logged_in/): Filters the ‘logged in’ message for the comment form for display. 5. `comment_form_fields` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_fields/): Filters the comment form fields, including the textarea. 6. `comment_form_field_comment` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_field_comment/): Filters the content of the comment textarea field for display. 7. `comment_form_field_{$name}` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_field_name/): Filters a comment form field for display. The dynamic portion of the filter hook, $name, refers to the name of the comment form field. Such as ‘author’, ’email’, or ‘url’. 8. `comment_form_submit_button` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_submit_button/): Filters the submit button for the comment form to display. 9. `comment_form_submit_field` — [Link](https://developer.wordpress.org/reference/hooks/comment_form_submit_field/): Filters the submit field for the comment form to display. The submit field includes the submit button, hidden fields for the comment form, and any wrapper markup.

7. Questions

dmsnell commented 2 years ago

We can all acknowledge that this kind of interactive experience is not a challenge within a single block (and within its allowed nested block types if there are any). Spanning across multiple blocks presents a problem not there in a single block: data flow. We're taking a system that was designed as a whole unit (evidenced by the way comment_form() is called in themes) and splitting it into independent parts inside another system that guards the isolation of its parts.

How did you envision this inter-block communication happening? For instance, what is the sequence of events that occurs when we click on that form submit button? How does it find the comment content, the author's name, and the author's email address? When making the relevant API call to the server to submit a comment, how does the comment form know to update itself and how does it do that?

How broadly do we expect people to customize the comment form? Some people or plugins might want to add a captcha challenge; how would that fit in given that it would need to interact with the API call to submit the challenge?

SantosGuillamot commented 2 years ago

Thanks for sharing your thoughts 🙂

Just to clarify before trying to answer some of your questions, the goal of this overview issue is just to replicate the behaviour of the current comments form, but using blocks to make it easier to edit the layout and texts. This means that it doesn’t aim to add new functionality and it wouldn’t add any kind of client interactivity yet. I think that is a bigger and more complex project, and it could be covered in a new issue after this one.

what is the sequence of events that occurs when we click on that form submit button?

It could just include an action to .../wp-comment-post.php in the <form action="X">, as it is being done right now. That would go to the server and redirect the user to the comment link (.../test-post/comment-page-2/#comment-3 for example).

How does it find the comment content, the author's name, and the author's email address?

Those fields could be wrapped in a parent Comment Form block. That would organize the HTML properly and it would end up being something like this:

<form action="http://form.local/wp-comments-post.php" method="post" id="commentform">
    <p class="comment-form-comment">
        <label for="comment">Comment</label>
        <textarea id="comment" name="comment"></textarea>
    </p>
    <p class="comment-form-author">
        <label for="author">Name </label>
        <input id="author" name="author" type="text" value="">
    </p>
    <p class="comment-form-email">
        <label for="email">Email</label>
        <input id="email" name="email" type="email" value="" >
    </p>
    <p class="comment-form-url">
        <label for="url">Website</label> 
        <input id="url" name="url" type="url" value="">
    </p>
    <p class="form-submit wp-block-button">
        <input name="submit" type="submit" id="submit" value="Post Comment">
        <input type="hidden" name="comment_post_ID" value="1" id="comment_post_ID">
        <input type="hidden" name="comment_parent" id="comment_parent" value="0">
    </p>
</form>

That should be enough if I'm not mistaken.

When making the relevant API call to the server to submit a comment, how does the comment form know to update itself and how does it do that?

As I said previously, adding client interactivity is out of the scope of this issue, so it would just go to the server and reload the page with the new content.

How broadly do we expect people to customize the comment form?

I assume the main goal is to let people customize easily the layout of the comment form and the different texts included on it. Moreover, with the current form (without blocks), the editor isn't showing the same result as the frontend.

Some people or plugins might want to add a captcha

If there are users adding a captcha using hooks, it should keep working. Ideally, a new captcha block would be created and it could be added just inside the Comments form block.

ockham commented 2 years ago

I think even if we want the (first iteration of) the Comments Form block(s) to strictly reflect the functionality of the comment_form() function (including the redirect upon submit, which is kinda ugly 😝), we still need to present the form inside of the Comment Template (and thus, inside of the Comments Query Loop) -- in the same position as the Reply link that the user clicked. Here's what that currently looks like on the frontend of the Twenty Twenty One theme (i.e. a non-FSE theme):

comment forms

We could reflect this in the editor by mirroring that exact behavior: If the user clicks on any Reply link, it expands into the Comment Form block. This might have some interesting implications: the Comment Form would become another state of the Reply link block, or vice versa -- and the Comment Form sure has a lot of states to handle already, see the spec at the top of this issue 😅

We'd probably need to implement this via a unique "expanded reply link/comment form" marker within the query loop, much like we already handle the currently active (selected) comment within that loop. By default, we'd likely want to expand the comment form at the very bottom (that would allow the user reply directly to the post).

ClarusDignus commented 2 years ago

I posted my thoughts on the necessity of separate customizable blocks for the comment form heading, "Replying to [...]", and "Cancel reply" here.

ClarusDignus commented 2 years ago

@ockham

I like the idea of the comment form appearing below the comment being replied to.

For replies to the post, the standard, already-visible comment form should be used.

For replies to comments, regardless of whether the comment being replied to is top-level or nested, the form should appear below the comment as you've illustrated; however, the form shouldn't be indented like the comment being replied to. Otherwise, for deeply nested comments, the comment form will be too narrow. It's best to consistently use the full screen width available. Placing the comment form below the comment sufficiently implies the relationship between the comment form and the comment being replied to, without indentation.