-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
REST API for annotations (back-end comments, take 2) #4685
REST API for annotations (back-end comments, take 2) #4685
Conversation
@@ -0,0 +1,1065 @@ | |||
<?php |
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.
Hey Jason, isn't there a way to break down this humongous file into smaller modules? There is so much going on in here, it will be hard to maintain imo. Same as the utils class above. The separation of what is covered by each is not clear to me either. Maybe start by extracting the permission checks for a start, then gradually organise things maybe per CRUD operation., identify reusable patterns, etc.
This is obviously a big task, and by all means kudos for writing so much code.
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.
@chriskmnds Thanks for the review 😄
lib/class-wp-rest-annotations-controller.php
break down this humongous file into smaller modules?
WP_REST_Annotations_Controller extends WP_REST_Comments_Controller in core. There's a nice article in the handbook that summarizes the infrastructure.
While I'm not opposed to separating areas of concern, I think it's important to follow the precedent that's been set and to maintain a consistent pattern.
class-wp-annotation-utils.php
extracting the permission checks for a start
I agree. Pulling the permissions out of there seems like a great idea.
@@ -0,0 +1,1244 @@ | |||
<?php |
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 haven't gone through all the tests here, but I am wondering if you have created test cases to handle all the parameter values and types that are passed to the API. For example, do you check the expected return values when a required parameter is missing, when a wrong value is passed in the request, whether errors are communicated correctly, etc? For example, I get back a status 200 OK
with a value of Unexpected '<'
in the body of the response when I attempt to create an annotation with the parameters:
{
"post": 1,
"via": "gutenberg",
"content": " ",
"author": "123"
}
Is this normal, am I doing something wrong? Obviously author: "123"
erred there. I believe a strong enumeration of all the expected values to/from the API would give a lot of value to this branch. Again, I am not sure if you are already doing that and there are a few edge cases that slipped through.
Similarly, I notice that passing an empty string for content content: ""
results in a 400 Bad Request
, while if I pass just a space with content: " "
results in 200 OK
. I can see in the response though that the rendered
content is null/empty ""
. Why allow that then and not treat it like the former case? etc..
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.
@chriskmnds Awesome work, thank you! 👁
It's great to have another pair of eyes on this.
test cases to handle all the parameter values and types that are passed to the API.
Yes, there were some like this already, but most had a focus on user permissions. I've been in the process of restructuring the unit tests for this branch and that work is done now. I just pushed the improved unit tests to this PR and I'll post a summary shortly. Always room for improvement though, so if you find anything else just let me know.
Both great finds, and both bugs. Nice work!
-
🐛 "Unexpected '<' in the body of the response"... Triggered by a nonexistent
author
ID. This was resulting in an internalWP_Error
response that went unhandled, resulting in a parse error and a malformed response instead of the error message and code. Fixed by adding these three lines and unit tests now cover this. -
🐛 "if I pass just a space with content: " " results in 200 OK." ... Yeah, I think it should be smarter than this. The same behavior seems to exist in WordPress core. I corrected this for annotations by adding a smarter analysis of the content and unit tests also. I'm considering a trac ticket for this in core.
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.
Awesome, thanks for the follow up. My point was really just to make sure you solidify everything that is expected to/from the endpoints. I will try and go through the specs later this week and see if I spot anything else. Cool stuff :-)
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.
Thanks again Chris. I really appreciate you taking the time to look over this with me. Anything I can help you with just hit me on Slack! :-)
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.
No problem! and thanks, I will definitely ping you if/when needed :-)
Unit tests for this API have been restructured to improve their organization, readability, and to expand coverage. Tests now run approx 45k assertions, with new tests having been added to check things like invalid parameter responses, max string lengths, and more CRUD permutations. Four Sets of Tests
|
🐛 Bug Fixes
|
Fresh rebase on master branch and I updated links to commits in my earlier comments. |
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've looked at the first part of the code changes and had these remarks.
My main feeling when I look at this PR is that its a ton of changes all at once. I think it could be a lot cleaner if WordPress had first-class support for comment types and private comments.
I am going to look into making this possible in core.
/** | ||
* Annotations API: WP_Annotation_Caps class | ||
* | ||
* @package gutenberg |
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 think these can have capital letters, so Gutenberg
is probably more appropriate.
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.
A capital seems right to me too. The rest of the PHP files in Gutenberg use lowercase though, so if this changes it should probably happen in one fell swoop as a separate PR. Do you agree?
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.
Ah, you did it for consistency. That makes sense. I would leave it like this then. And indeed if we want to change it, it needs to happen in one rename PR.
* @param array $caps Required capabilities. | ||
* @param string $cap Capability to check/map. | ||
* @param int $user_id User ID (empty if not logged in). | ||
* @param array $args Arguments to {@see map_meta_cap()}. |
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.
You should describe here what this function can have as $args
.
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.
Oh, yes. That's a good idea, ty.
* @param array $caps Required capabilities. | ||
* @param string $cap Capability to check/map. | ||
* @param int $user_id User ID (empty if not logged in). | ||
* @param array $args Arguments to {@see map_meta_cap()}. |
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.
You should describe here what this function can have as $args
.
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 this function forks itself out to the other cap-specific handlers, I documented the arguments separately in each one to help clarify. Thanks again!
lib/class-wp-annotation-caps.php
Outdated
$wp_trash_meta_status = $wp_trash_meta_status ? $wp_trash_meta_status : '0'; | ||
$comment_status = WP_Annotation_Utils::translate_comment_status( $wp_trash_meta_status ); | ||
} | ||
if ( ( 'trash' === $actual_comment_status && ( ! $user_id || (int) $comment->user_id !== $user_id ) ) |
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.
This if statement requires a bit more docs 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.
Agree, thanks.
* | ||
* @since [version] | ||
*/ | ||
final class WP_Annotation_Caps { |
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.
There is a lot of duplication in these files, especially with the array_merge
's at the end. Maybe you can find a way to resolve this?
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.
Great observation, thank you. I was thinking the same thing when I wrote this and tried to avoid some of that with the get_comment_info()
and get_post_info()
utils. But the extraction of those variables are now in duplicate and I'd like to improve. Really want to avoid the use of extract()
. I'll dig in and see if there's anything I can do.
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 did some work on this in recent commits. Thanks!
* | ||
* @return array Array of required capabilities. | ||
*/ | ||
public static function on_map_meta_cap( $caps, $cap, $user_id, $args ) { |
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.
Making all these methods static makes this class more like a pseudo-namespace than an actual object. What's wrong with instantiating and calling the instance method in the filter?
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.
Yeah, singleton vs. static. I don't have a strong personal preference between them. There was nothing that needed instantiation in these, so I went with static as one step above global functions. If there are strong opinions about it I'm happy to change.
* @see WP_Annotation_Utils::on_comments_clauses() | ||
* @see WP_REST_Comments_Controller::get_items() | ||
*/ | ||
public static function on_rest_comment_query( $query_vars, $request ) { |
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.
You can type-hint the $request variable using WP_Request $request
in the list of params. This works in PHP5.2.
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.
Cool, yes. I didn't realize class hints went all the way back to 5.0.
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'm totally in favor of type hints anywhere they're supported, on just about everything. And I got excited when you mentioned that some work all the way back to 5.x. Woohoo! However, since this is not a practice that WordPress has adopted, and there's no mention of hints in the coding standards, I'm going to hold off for now and ask around. Maybe it's fine, I just haven't seen them used in core, have you?
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 asked about this on Slack and the impression I have is that it's probably OK to use type hints, but there needs to be some further discussion and a precedent set. Ideally, there would be something added to the WP code standards on this topic before we start using them. https://wordpress.slack.com/archives/C02RQBWTW/p1517600728000053
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.
Don't worry about creating that Trac ticket @jaswrks I mentioned, this PR will suffice for said discussion 💯
|
||
$meta_queries = array(); | ||
|
||
$vias = $request['via']; |
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 prefer to use get_param
because there is less 'magic'.
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.
For the sake of consistency, array access matches controllers in core; e.g., https://github.com/WordPress/wordpress-develop/blob/master/src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php
Props @atimmer and @chriskmnds for your reviews. I'm attaching a summary of recent improvements following your suggestions. If you have time to take another look and find any other issues please let know. Thank you both 😄 Summary of recent commits:
|
Referencing a trac ticket I was previously unaware of: I invited others from that discussion to leave feedback here and I'm looking forward to other opinions and ideas. My comment here: https://core.trac.wordpress.org/ticket/40031#comment:24 |
@atimmer writes...
I agree. As some of you may already know, I went back and forth on this and even completed a large chunk of work in two previous iterations of this API. My first attempt was with a custom post type, then with both front-end and back-end annotations as two different comment types. I left my thoughts and a list of pros/cons in each of those previous iterations. Then I honed in on private backend annotations only, using this PR with a single custom comment type. Only private backend annotations right now, because that's the current Gutenberg objective, but also because I concluded a few things from my experimentation. Front-End Annotation ConclusionsIf front-end annotations ever do become a thing, I think they'd be better implemented in a way that would simply extend the existing default That way front-end comments and front-end annotations are both the same thing. The only real Back-End Annotation ConclusionsThat's the focus of this PR. What would have made this work 1000% easier, lighter, and more tightly integrated with core, is if custom comment types were a first-class citizen in core. If core had a My hope is that this work will:
|
Referencing existing trac ticket for custom comment types: https://core.trac.wordpress.org/ticket/35214 |
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 have done a more thorough review of the PR. The main changes I would like to see are:
- The annotation status should be in comment meta. I think saving the status in
comment_approved
is an unwise decision. - Annotations should have an
annotation_type
field (not mentioned in other code review comments). The default should be "comment". Grammatical suggestions or SEO suggestions are of a different subtype. We (@omarreiss and I) think we should have built-in support for different types of annotations from the start.
lib/class-wp-annotation-utils.php
Outdated
* | ||
* @return stdClass|null Data object. Null on failure. | ||
*/ | ||
public static function get_comment_data( $comment ) { |
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.
You should consider returning a value object here. This looks a whole lot like a WP_Annotation
object.
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.
Good suggestion. I don't see any reason we can't have a WP_Annotation
class, and I agree it would simplify things quite a bit.
lib/class-wp-annotation-utils.php
Outdated
global $wpdb; | ||
|
||
if ( ! $comment ) { | ||
if ( $error ) { |
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.
Why this $error
check? This is never done in WordPress core as far as I am aware. Why not just return a WP_Error
?
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 see what you mean. I'm not sure I would have written it this way either, were it not already like this in wp_set_comment_status()
. My intent was mainly to model this function after wp_set_comment_status()
and add support for custom statuses.
That said, in the end, that $error
parameter has not been needed by any code in this PR. So I don't see any reason to keep this either.
lib/class-wp-annotation-utils.php
Outdated
} | ||
|
||
// @codeCoverageIgnoreStart | ||
// Testing would require a DB write failure. |
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 do not think this is a good reason to ignore coverage. I know that WordPress is very hard to test because of tight coupling, but when you ignore the code coverage like this you are hiding this problem from daylight.
A very simple (and pragmatic!) solution to this is:
- Inject
$wpdb
through the constructor. (I would argue all new classes should do this) - Mock $wpdb in your tests where necessary.
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.
Good points, thank you. There were three or four sections like this I was unable to cover. I'll start by just removing those comments and then reassess once the next iteration is ready for review. The idea that it's "not possible" is presumptuous.
lib/class-wp-annotation-utils.php
Outdated
if ( $meta_queries ) { | ||
if ( ! empty( $query_vars['meta_query'] ) ) { | ||
// @codeCoverageIgnoreStart | ||
// Testing would require a plugin modifying query. |
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.
Like above, this is not a very good reason. The inputs to this function can be changed to be able to test this code path.
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.
lib/class-wp-annotation-utils.php
Outdated
* | ||
* @param array Comment types allowed for annotations. | ||
*/ | ||
$allow_types = apply_filters( 'annotation_allow_types', self::$types ); |
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.
This filter will never work because adding a type here will not show up in the query when querying comments.
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.
Hmm. I'm not sure I follow on querying. Maybe if you explain further.
That said, I do agree that this filter should change.
At present, multiple annotation comment types are supported in all areas of this PR. The default annotation comment type is annotation
. If this filter were moved and renamed it would more accurately describe the intention, which is to allow for additional annotation types added by plugins.
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 mean that this filter should be applied in the on_comments_clauses
method. Otherwise, a type added by this filter will be allowed, but will also be shown in default comment overview. Such as the front-end.
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.
Right, I see what you meant now. That will get fixed when I move the filter and change the name. Definitely agree.
// @codeCoverageIgnoreStart | ||
// Not possible to test at this time. | ||
// Strengthens security in custom post types and on sites with permission mods. | ||
if ( ! current_user_can( 'edit_annotations', $type ) ) { |
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.
Why is a user that is not allowed to edit_annotations
not allowed to create an annotation with a certain date/meta? I think this warrants a comment about the why.
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.
Great suggestion. I'll elaborate on this in the comments. The rationale for this is not great at the moment, as it is currently impossible to create_annotations
if you can't edit_annotations
.
I left this in only because it would prevent date/meta from being set in the case of a custom post type or plugin altering permissions in such a way that it allows annotation creation, but locks editing. Those two fields would then be restricted in such a case, which seems desirable in that scenario.
I'm going review this again though, because it is very confusing and way out on the edge. I'd prefer to get rid of it in favor of a more straightforward approach.
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.
Hmm, but I would argue that you should be allowed to at least set meta on an annotation if you are not allowed to edit it. For example, in the scenario where we would persist annotations from Yoast SEO, we would like to save some extra data in meta. But then users who can only create annotations (not edit) would not be able to set this extra data.
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.
Good point. I have no problem loosening permissions here by removing meta
from the list.
A scenario where a user can create, but not edit, is not one that would occur unless permissions were altered by a plugin. I will leave a portion of this in to protect the date
and date_gmt
fields in that scenario, but I'll remove meta
as you point out.
} | ||
} // @codeCoverageIgnoreEnd | ||
|
||
if ( ! current_user_can( 'edit_others_annotations', $type ) ) { |
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.
This is more obvious to me 👍 . Maybe it also should have a comment describing the implication if this check wasn't there. Something like:
// Without this check, users would essentially be able to impersonate other authors by modifying this field.
|
||
if ( ! $post_ids ) { | ||
return new WP_Error( 'rest_missing_annotation_posts', __( 'Missing post(s).', 'gutenberg' ), array( | ||
'status' => 400, |
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 know how this is implemented in the REST API code, but isn't there a way to have a validation step? 400 status codes don't belong in a permissions check.
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 agree with 400
error codes being out of place here.
The REST API is rather interesting in its approach to permissions. To properly check permissions one must take the current WP_REST_Request
into consideration, which is a variable that's passed into these permission checks.
The only problem with this is that rest_send_allow_header()
filters every API response, and it calls each of the permission checks with the current WP_REST_Request
, which may or may not contain the type of request parameters expected to have been validated already; e.g., it may call get_items_permissions_check( $request )
with request parameters originally intended to create a new annotation.
That makes it more difficult to write a permission check that considers the current request, because at times the current request contains, or doesn't contain, all the information necessary to check permissions properly.
There might be something I can do to improve this though.
$is_current_user_query = $current_user_id && array( $current_user_id ) === $request['author']; | ||
|
||
foreach ( array( | ||
'author', |
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.
Does this mean that you are not allowed to filter annotations on other authors unless you can edit their annotations? That sounds wrong, or am I not understanding the capabilities correctly?
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.
The intention here is to prevent non-administrative users (e.g., authors/contributors) from looking at another user's history. The author
, author_exclude
, and author_email
parameters are also guarded in core, in a similar way, for comments. A useful exception to this rule is that any user who can edit, can list their own annotations; i.e., note the $is_current_user_query
variable a few lines below this.
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.
That makes sense. I think it warrants an inline comment.
* | ||
* @return array Test arrays. | ||
*/ | ||
protected function generate_standard_meta_cap_tests() { |
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.
Do you know about @dataProvider
? This makes PHPUnit aware of the data set and tests will continue if one of the data points fails.
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.
Thank you. I experimented with data providers a bit in the unit tests for this API. One thing I have against them is that they slow down unit tests that cover 1000's of permutations. Slower, because each dataset delivered by a data provider results in setUp()
and tearDown()
being called on each of those iterations; e.g., 45k permutations x 2 setup/teardown calls.
I found that tests ran much faster if they were generated in groups of permutations being run together. Resulting in just one setUp()
and tearDown()
for each group, which is all that was needed in most of the tests for this API.
Another thing I noticed is that all data providers run before any testing begins. So if a data-provider depends on any database-driven objects, those are lost when tests run, given all the heavy lifting done by WP_UnitTestCase
.
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.
Ah, then it is not feasible.
@atimmer Thanks for digging in with me here. Your review is much appreciated and I'll take a look at each of the items you pointed out shortly. 😄 |
@atimmer Very helpful review. I'll go over the rest a bit later. Thanks again! |
What would you like to shoot for in support of multiple annotation types? I see two workable solutions:
Can you think of any pros/cons associated with each of those? One reason I went with option 1 is because I felt it would be easier to merge into a future WordPress core that supports |
@jaswrks The goal of multiple annotation types is to make sure the UI can default to only showing one type of annotation. I think that is possible using different annotation types. I'll discuss this with @omarreiss again to see if that achieves the goals we want to hit. |
I've discussed this and we think that having different comment types is 👌🏻. |
👁👁 I could use another pair of eyes on this now. I think I've covered all recent requests and enhancements. I've added two new classes, some new functions, and new filters to make it easier for plugins to extend annotations.
Getting an Annotation Instance<?php
$annotation = get_annotation( 123 ); // WP_Annotation
$selector = $annotation->get_selector(); // WP_Annotation_Selector
echo $selector->type; // e.g., XPathSelector How to Add Annotation TypesThese are comment types. <?php
add_filter( 'get_annotation_types', function( $types ) {
return array_merge( $types, array( 'seo_annotation' ) );
} ); How to Add Annotation Statuses<?php
add_filter( 'get_annotation_statuses', function( $statuses ) {
return array_merge( $statuses, array( 'accepted' ) );
} ); |
Is the work here still relevant, and can it be reasonably be brought up to date with current master? Or can we close it? |
I just rebased this and squashed all commits to clean things up. All of the unit tests are passing and I ran a lint check on this again and corrected a few things that were caught by what looks to be an updated PHPCS configuration since this was worked on before. So I don't see any reason this couldn't be used. LGTM! 🚢
I haven't been in on recent discussions about Annotations. @atimmer is working on some portions though. Do you still intend to use this REST API? The docs for this API are here: |
The work is still relevant, however, I haven't prioritized this part. That's because a full-fledged commenting API with persistence is a ton more work than I have the capacity for. So I have focused on getting client side annotations to work because it will give us a feature that will work right now. Client-side annotation is also required for feature parity of the Yoast plugin with the classic editor. It's good to note that I am keeping in mind this PR, so all my work is future compatible with the commenting API. |
@atimmer should we move it to Trac? |
@gziolo I don't see us working on this in the very short term, so I don't know if there is a lot of value of moving this to trac now. |
It seems like it isn't actionable in the upcoming months. It wasn't listed on the roadmap for 2019: https://make.wordpress.org/core/2018/12/08/9-priorities-for-2019/. Collaborative editing is planned for the 3rd phase of Gutenberg development. Let's close this PR and get back to it later. We can always reopen 😄 @jaswrks many thanks for your work done so far. I hope we can reuse most of the code in the future 🙇 |
Description
Alternative approaches explored: #4385 and #4386.
A WP REST API endpoint for annotations (back-end comments). Implemented as a custom comment type. The API uses the W3C annotation data model for annotation selectors and maintains some parity with the W3C annotation object model and protocol — while still doing things the WordPress way, which maximizes compatibility with WP REST API utilities, including those in JavaScript.
Overview of Changes
Introduces:
lib/class-wp-annotation-caps.php
to deal with annotation capabilities.lib/class-wp-rest-annotations-controller.php
is the REST API controller.lib/class-wp-annotation-utils.php
are a few annotation utilities.Modifies:
lib/load.php
lib/register.php
Near 100% coverage by unit tests
phpunit/annotations/*
API Documentation
See: 📄 https://speca.io/jaswrks/wp-annotations
How can you test the WP REST API for Annotations?
Install the Basic Auth plugin for the WP REST API. This allows you to run tests with only a username/password via Postman.
1
while testing. If you go this route, be sure to delete the file after testing.wp-content/mu-plugins/rest-api-auth-bypass.php
Now, visit this page and click "Run in Postman". You can then run your own tests locally in Postman. Either that, or follow along with the Annotation API docs and run your own tests over HTTP in any other way you'd like.
How Has This Been Tested?
Types of changes
This approach requires a comment query filter to keep annotations out of the comments admin area, and away from plugins that might mistake them as being a more typical comment type. In this PR, the following alters
comments_clauses
in core.Back-End Annotation Permissions
Simplified Explanation
If you can
edit_posts
, and you canedit_post
(this post). Or, if you're the post author. Then you can read all, and create, edit, delete your own back-end annotations in this post.Administrators and Editors can edit and delete any post, so they can read, edit, and delete any annotation without restriction.
Subscribers and the public have no access to back-end annotations whatsoever.
TODO
Non-Blocking TODOs
WP_Annotation_Utils::on_map_meta_cap()
— move logic in each 'case' to a separate function, making a somewhat complex routine easier to follow along with.Consider typehinting WP_REST_Request, REST API for annotations (back-end comments, take 2) #4685 (comment)@since [version]
with version in docBlocks.Client Side Exploration of Selectors
jsFiddle: Building and highlighting a W3C Annotation Selector using XPath.
https://jsfiddle.net/jaswrks/1cLaeyfd/