#40878 closed task (blessed) (fixed)
Adding menus route
Reported by: | dingo_d | Owned by: | spacedmonkey |
---|---|---|---|
Milestone: | 5.9 | Priority: | high |
Severity: | normal | Version: | 4.7 |
Component: | REST API | Keywords: | has-patch has-unit-tests needs-dev-note |
Focuses: | rest-api | Cc: |
Description
Currently there is no ${appUrl}/wp-json/wp/v2/menus
route inside REST API for WordPress.
I know I can create a custom endpoint and define a route for it, or use a plugin, but wouldn't it be better to have it in the core?
I couldn't find a ticket for this, and inspecting the routes via postman showed no menus
which means that it doesn't exists yet.
Is there any plan to add it to core?
Attachments (5)
Change History (85)
#2
@
7 years ago
Yeah, I'm aware of the plugin, but it seemed like something that would be good to include in the future :)
#4
@
7 years ago
As discussed in Slack #core-js channel, I'm uploading my current code for working with WordPress menus through the REST API.
The basic code works:
menu-locations
endpoint:
This provides basic enumeration, direct access through their slug, as well as linking and embedding the attached menus.
This is read-only, as the locations are defined in code, not stored in the database.
menus
endpoint:
Extension of the terms controller. Provides all terms functionality, with the addition of making the linked menu items embeddable, as this would be a common use case.
menu-items
endpoint:
Extension of the posts controller. Provides all posts functionality, with no customizations as of yet.
Shows the associated menu in the 'menus'
property, which can also be queried: menu-items/?menus=2
.
I assume that these implementations are still missing some subtleties, so consider this a first draft to serve as a basis for discussion.
#6
@
7 years ago
Some additional observations:
A first implementation I did created custom implementations for the menus and menu-items controllers. However, I think the more correct approach is to reuse the posts and terms controllers, and then add whatever information is needed to the post-type/taxonomy registration arguments to adapt them as needed.
With the above patch, the menu-items controller is just the standard posts controller.
The only thing that the additional menus-controller
now does is make the menu items embeddable. But I think that could actually be a default for all post-type/posts relationships.
#7
@
7 years ago
This is read-only, as the locations are defined in code, not stored in the database.
A POST
request could be made on the same endpoint where you provide location name, then a check could be made in the callback function that will check if the location name is taken using get_registered_nav_menus(), and if the check passes one could register new nav menu using register_nav_menus().
I can try to make a patch for this.
Also when I try to apply the patch it fails on src/wp-includes/taxonomy.php
(where 'rest_controller_class' => 'WP_REST_Menus_Controller'
is)...
#8
@
7 years ago
@dingo_bastard : I'm not sure I understand. Doing a POST
request would allow to add a new menu location, but it wouldn't be persisted. Unless you add a new PHP file somewhere, or start storing menu locations in the database, any changes you could make would be gone with the next page request.
#9
@
7 years ago
@dingo_bastard : I uploaded a fresh patch from a clean source tree. Apparently, the previous one started from a changed code base already, sorry for that.
#10
@
7 years ago
Oh right, my bad. I was working on a theme some time ago and we added additional menus via customizer settings, but those get saved in the database. Totally forgot about that.
We could add an option ${theme_name}_registered_menu_locations
that could be saved for each theme and would contain menu locations. Although that would probably be a case for another ticket (one concerning registering menu locations and saving them in the database programmatically).
This ticket was mentioned in Slack in #core-restapi by adamsilverstein. View the logs.
7 years ago
This ticket was mentioned in Slack in #core-restapi by dingo_d. View the logs.
7 years ago
This ticket was mentioned in Slack in #core-restapi by dingo_d. View the logs.
7 years ago
#15
@
7 years ago
40878.3.diff builds on @schlessera's earlier patch. I didn't see a controller for menu items, so this extends the WP_REST_Posts_Controller
for GET requests to menu-items
. You can now make requests like:
GET /wp/v2/menu-items/
for a full list of menu itemsGET /wp/v2/menu-items/:id
for a single menu itemGET /wp/v2/menu-items/?menus=2
for a list of menu items in menu with ID=2
I've added these so that we can get a Custom/Navigation Menu block in gutenberg, see this issue & PR. These are read-only, and they contain the extra menu-related fields like target
, classes
, attr_title
, etc. This also replaces the post's link
with the menu destination link (the link to the nav_menu_item
post type does not exist).
For reference, the endpoints from schlessera's patch:
GET /wp/v2/menus
for a list of available menusPOST /wp/v2/menus
to create a new menu (taxonomy object)GET /wp/v2/menus/:id
for a single menu objectPOST /wp/v2/menus/:id
to update a single menu objectDELETE /wp/v2/menus/:id
to delete a single menu objectGET /wp/v2/menu-locations
for a list of available menu locations (theme-dependent)
You can also do an OPTIONS
request on any of these to get more info.
Deleting a menu does not delete the sub-items in the menu, I think we'd want to call wp_delete_nav_menu
in the menus controller. This also doesn't include any tests.
Note, the two uploads (40878.diff & 40878.3.diff) are the same file, re-uploaded to get the .3
#16
@
7 years ago
@ryelle Erm... I'm pretty sure I coded a menu items controller (you can even see screenshots of its output above). Not sure what happened to it and why it wasn't in the patch, but I'll try to find the code and compare with yours to see if we did the same thing.
This ticket was mentioned in Slack in #core-restapi by kadamwhite. View the logs.
7 years ago
#18
@
7 years ago
I looked through my code to see how I handled the menu-items
endpoint.
I basically just reused the posts controller, by adding the following to the register_post_type()
call for the nav_menu_item
post type:
'show_in_rest' => true,
'rest_base' => 'menu-items',
'rest_controller_class' => 'WP_REST_Posts_Controller',
Through all the built-in mechanisms that the controller, and more specifically the posts controller provide, this allows for all general manipulations you might need.
Of course, as soon as we want to add menu-item-specific code, we'd need to extend the posts controller anyway, so @ryelle 's approach above makes sense.
This ticket was mentioned in Slack in #core-restapi by danbeil. View the logs.
7 years ago
#20
@
6 years ago
Will this be added in the 5.x release? It would be a nice feature to have out of the box.
This ticket was mentioned in Slack in #core-restapi by dingo_d. View the logs.
6 years ago
@
6 years ago
Implemented REST API endpoints for menus, menu items, menu locations, and menu settings.
#24
@
6 years ago
My latest attachment includes fully functional API endpoints for menus, menu items, menu locations, and menu settings.
There was a good bit of logic that is part of the wp_wpdate_nav_menu_item()
function that needed to be duplicated to get it working properly in the menu items endpoint. One of these was the handling of orphaned menu items.
I made menu locations writeable, but only for updating the menu ID assigned to a menu location.
Menu settings is a new introduction that provides access to the auto_add
option to automatically add top-level pages to a menu.
With all of these endpoints, it would be possible to completely replace the existing screen under Appearance
-> Menus
with a single page JavaScript app.
These endpoints are key to the initiative being explored here: https://github.com/WordPress/gutenberg/issues/13206
This ticket was mentioned in Slack in #core-restapi by wpscholar. View the logs.
6 years ago
This ticket was mentioned in Slack in #core-restapi by wpscholar. View the logs.
5 years ago
This ticket was mentioned in Slack in #core-restapi by wpscholar. View the logs.
5 years ago
This ticket was mentioned in Slack in #core-restapi by spacedmonkey. View the logs.
5 years ago
#29
@
5 years ago
- Keywords needs-unit-tests added
Thanks for everyone's work on this. I spent some time reviewing the patch and on the face of it looks good. But I personally believe that there is no way to have a meaningful code review via svn patches. I can not do code level reviews and discuss this. Any feature of this size, should start as a feature plugin.
To that end, we already have a feature plugin for this at wp-api-menus-widgets-endpoints. @wpscholar if you could take your patch and make it a pull request on that repo, we can work on it there. Once we have a solid api there, we can create a core patch from that, that should just a copy and paste in core.
#31
@
5 years ago
@spacedmonkey PR created: https://github.com/WP-API/wp-api-menus-widgets-endpoints/pull/21
#32
@
5 years ago
- Milestone changed from Awaiting Review to Future Release
- Owner set to spacedmonkey
- Status changed from new to assigned
After today’s api dev chat. We agreed that the pr, should be merged as is and work on the code from there.
We need to work on unit tests, but we need to do that after finalised the design of the api.
#33
@
5 years ago
Spent some time on this PR - https://github.com/WP-API/wp-api-menus-widgets-endpoints/pull/22 . I think it has a future, as it is pretty simple and easy to implement.
These endpoints, use override WP_REST_Terms_Controller
and WP_REST_Posts_Controller
, with some slight modifications.
If someone else from the REST API team could review, that would be extremely useful.
#34
@
5 years ago
I have merged the last PR so we now have a functional feature plugin.
I am working some two new PRs.
These PRs have been done on my fork, but future PRs will be done as branches. Any subscribed to this ticket, please give comments to these PRs.
#35
@
4 years ago
- Keywords has-unit-tests added; needs-unit-tests removed
- Milestone changed from Future Release to 5.5
- Priority changed from normal to high
The plugin has been merged into Gutenberg. Milestoning for 5.5 to handle the core merge. The navigation block is a 5.5 priority.
This ticket was mentioned in PR #319 on WordPress/wordpress-develop by spacedmonkey.
4 years ago
#36
Feature plugin - https://github.com/WP-API/menus-endpoints
Trac ticket: https://core.trac.wordpress.org/ticket/40878
#37
@
4 years ago
- Keywords needs-dev-note added
- Owner changed from spacedmonkey to TimothyBlynJacobs
I have created a pull request ready for review and merge in 5.5.
Assigning to @TimothyBlynJacobs for review.
TimothyBJacobs commented on PR #319:
4 years ago
#38
We need to add @ticket
annotations for the tests.
I'm also going to hold off on committing this until the Gutenberg merge happens for 5.5.
This ticket was mentioned in Slack in #core-restapi by timothybjacobs. View the logs.
4 years ago
spacedmonkey commented on PR #319:
4 years ago
#40
We need to add
@ticket
annotations for the tests.
I'm also going to hold off on committing this until the Gutenberg merge happens for 5.5.
Ticket number and version number comments added.
#41
@
4 years ago
- Milestone changed from 5.5 to 5.6
The Navigation Screen and Navigation Block are no longer shipping in WordPress 5.5. Based on our discussion in #core-restapi and @SergeyBiryukov's feedback I'm going to move this to 5.6. I know this will be a disappointment, but I think landing these endpoints with first party usage is critical to make sure we nail the API surface.
TimothyBJacobs commented on PR #319:
4 years ago
#43
Is this for the navigation screen? If so, not sure if it should be merged now.
Yes. I removed it from the milestone Saturday.
This ticket was mentioned in Slack in #core by hellofromtonya. View the logs.
4 years ago
#45
@
4 years ago
- Keywords needs-refresh added
Adding needs-refresh
due to PR 319 having merge conflicts.
#46
@
4 years ago
- Keywords needs-refresh removed
@hellofromTonya I have refreshed the PR, so there are now no merge conflicts.
This ticket was mentioned in Slack in #core by hellofromtonya. View the logs.
4 years ago
#48
@
4 years ago
- Keywords dev-feedback removed
Removing keyword per today's <bug-scrub>
discussion.
Also capturing the note from @TimothyBlynJacobs: this ticket will "probably be merged to Core when the Gutenberg merge happens closer to beta."
#49
@
4 years ago
- Milestone changed from 5.6 to Future Release
Removing this from 5.6 per https://make.wordpress.org/core/2020/10/01/navigation-screen-removed-from-5-6-release-features/.
This ticket was mentioned in Slack in #core-restapi by spacedmonkey. View the logs.
3 years ago
This ticket was mentioned in Slack in #core-restapi by spacedmonkey. View the logs.
3 years ago
#52
@
3 years ago
- Milestone changed from Future Release to 5.9
- Owner changed from TimothyBlynJacobs to spacedmonkey
As per this week's REST API meeting, this ticket has been moved to the 5.9 milestone, as required by the navigation block and full site editing.
#53
@
3 years ago
I have created a follow up ticket #54304, to add a way to expose menu data publically in the REST API.
#54
follow-up:
↓ 55
@
3 years ago
- Type changed from feature request to task (blessed)
AFAICT 5.9 FSE only requires the use of readonly endpoints. What's the feasibility of merging only support for GET endpoints?
#55
in reply to:
↑ 54
@
3 years ago
Replying to TimothyBlynJacobs:
AFAICT 5.9 FSE only requires the use of readonly endpoints. What's the feasibility of merging only support for GET endpoints?
This topic was discussed in the REST API weekly meeting. See slack history. I believe it was agreed to merge the endpoints, as is.
Let's discuss this in the next meeting.
#56
@
3 years ago
We discussed whether we should or not and decided to wait on that decision until more info about navigation emerges. As we're now a week away from merging the endpoints, we need to come to a decision.
We can and certainly should discuss it in a meeting, but meetings aren't a place for final decision making as it doesn't allow for async participation. Which is why I left a comment on the ticket opening up the discussion.
#58
@
3 years ago
In my testing, I believe we also need to change the wp_update_nav_menu_item
function a little as well.
These lines
if ( $menu_id && ( ! $update || ! is_object_in_term( $menu_item_db_id, 'nav_menu', (int) $menu->term_id ) ) ) {
wp_set_object_terms( $menu_item_db_id, array( $menu->term_id ), 'nav_menu' );
}
Should be changed to
if ( $menu_id && ( ! $update || ! is_object_in_term( $menu_item_db_id, 'nav_menu', (int) $menu->term_id ) ) ) {
$update_terms = wp_set_object_terms( $menu_item_db_id, array( $menu->term_id ), 'nav_menu' );
if( is_wp_error( $update_terms ) ) {
return $update_terms;
}
}
Simply this should be changed
if ( $update ) {
$post['ID'] = $menu_item_db_id;
$post['post_status'] = ( 'draft' === $args['menu-item-status'] ) ? 'draft' : 'publish';
wp_update_post( $post );
}
To
if ( $update ) {
$post['ID'] = $menu_item_db_id;
$post['post_status'] = ( 'draft' === $args['menu-item-status'] ) ? 'draft' : 'publish';
$update_post = wp_update_post( $post );
if( is_wp_error( $update_post ) ) {
return $update_post;
}
}
This will mean that if terms / post fail to update, then we get an WP_Error back. This is clear for the REST API.
This ticket was mentioned in Slack in #core-restapi by spacedmonkey. View the logs.
3 years ago
#60
follow-up:
↓ 68
@
3 years ago
@SergeyBiryukov, @welcher, @audrasjb I'd love your thoughts on comment:58. In particular, this could be interpreted as a BC break. If those calls fail to update, is this a catastrophic error that should stop the rest of the process from happening?
This ticket was mentioned in PR #1814 on WordPress/wordpress-develop by spacedmonkey.
3 years ago
#61
Feature plugin - https://github.com/WP-API/menus-endpoints
Trac ticket: https://core.trac.wordpress.org/ticket/40878
spacedmonkey commented on PR #319:
3 years ago
#62
Closing in favour #1814
#63
@
3 years ago
I have created a new PR #1814.
This refresh the patch ready for merging.
The changes include fixes for compatibility with new testing library asserts.
#64
@
3 years ago
While working on the merge we identified an issue with how permission checks are implemented. Users should need access to edit_theme_options
in order to edit menu items. However, since the controllers extend the native WP_REST_Posts_Controller
and WP_REST_Terms_Controller
, the post type and taxonomy capability APIs ended up being used instead.
To fix this, we can either override all the permission checks in the API controllers to solely check edit_theme_options
, or we can instead continue using the existing capability APIs, but properly set the nav_menu
taxonomy and nav_menu_item
CPT to have their capabilities
set to edit_them_options
.
In discussion with @spacedmonkey and @peterwilsoncc, we decided that this latter approach is ideal. It makes proper use of the APIs and allows developers the most flexibility in adapting the permission checks for their needs.
#66
@
3 years ago
(You may need to read this a couple of times: map_meta_cap
can refer to a post type registration option, a function name and a filter)
I've been rubber ducking this with @TimothyBlynJacobs.
Including map_meta_cap
in the post registration (this gist contains my original suggestion for how to change the post type and taxonomy registrations) introduces a minor BC break.
Developers using the map_meta_cap
filter to change the permissions required for edit_theme_options
will no longer affect the ability to edit menu items. For example the following code would no longer prevent editing menu items as $cap
would change to edit_post
:
<?php add_filter( 'map_meta_cap', function( $caps, $cap ) { if ( $cap === 'edit_theme_options' ) { $caps[] = 'do_not_allow'; } return $caps; }, 10, 2 );
Were map_meta_cap
set to false
in the post registration, then the function map_meta_cap()
would change the value of $cap
to edit_theme_options
before it is passed to the map_meta_cap
filter.
The question for people on this ticket are: is maintaining backward compatibility preferable despite losing some of the flexibility mapping meta capabilities provides?
Unfortunately, searching the plugin repository to determine the effect of the BC change is difficult as many plugins use the edit_theme_options
string appears for a number of capability checks. The two searches I attempted returned no results:
#67
@
3 years ago
Something probably worth noting is that while the menu endpoints are landing in 5.9 due to FSE, the new menu editing interface is not. So there wouldn't be any immediate BC breaks in this release if we stuck with map_meta_cap
enabled for the menus CPT.
I think taking away edit_theme_options
from a user is probably something people want do? But I'm also not so sure how common that filter pattern would be because edit_theme_options
is an actual capability, so it could be removed or filtered away with user_has_cap
.
I think I'd lean to keeping map_meta_cap
.
#68
in reply to:
↑ 60
@
3 years ago
Replying to TimothyBlynJacobs:
@SergeyBiryukov, @welcher, @audrasjb I'd love your thoughts on comment:58. In particular, this could be interpreted as a BC break. If those calls fail to update, is this a catastrophic error that should stop the rest of the process from happening?
At a glance, both of the suggested changes seem fine. There is a similar return if wp_insert_post()
fails just a few lines above. If the wp_set_object_terms()
or wp_update_post()
call fails, it seems unsafe to proceed as that could lead to data discrepancies.
It's worth noting, however, that for the is_wp_error()
condition to work, wp_update_post()
should be called with the $wp_error
parameter set to true
, as it's false
by default. The same applies to the check linked above: I think the is_wp_error( $menu_item_db_id )
part in line 530 doesn't work as expected, as wp_insert_post()
never returns a WP_Error
object unless the $wp_error
parameter is true
.
#69
@
3 years ago
Having considered the BC overnight and consulted with a few developers and hosts of the type of site likely to be affected; I think it's fine to make the switch and keep map_meta_cap => true
. This matches the current state of the PR, so no change is needed there.
It's probably worth noting this part of the change in a separate dev-note so it doesn't get lost in amongst the details of the new API endpoint.
#70
@
3 years ago
I was curious whether backwards compatibility could be maintained while using map_meta_cap => true
through a pattern used elsewhere in core whereby map_meta_cap()
is called twice, in this case by mapping edit_theme_options
.
For the post type, the steps might be to, first, register nav_menu_item
with:
'map_meta_cap' => true, 'capability_type' => 'nav_menu_item', 'capabilities' => array(),
which would leave no one with the post type capabilities, followed by something like (very rough):
add_filter( 'map_meta_cap', function ( $caps, $cap, $user_id, $args ) { $pt_object = get_post_type_object( 'nav_menu_item' ); if ( in_array( $cap, (array) $pt_object->cap, true ) || ( in_array( $cap, array( 'edit_post', 'read_post', 'delete_post' ), true ) && ! empty( $args[0] ) && get_post_type( $args[0] ) === $pt_object->name ) ) { $caps = map_meta_cap( 'edit_theme_options', $user_id ); } return $caps; }, 10, 4 );
to map the post type capabilities back to the mapping for edit_theme_options
. In this way, if I'm following correctly, existing filters on 'map_meta_cap'
checking for edit_theme_options
would still be applied, and if there weren't any such filters, edit_theme_options
would be checked as a primitive capability. Developers would also have their usual access to 'map_meta_cap'
(the filter) to modify the post type capabilities to taste.
The steps for the nav_menu
taxonomy would be a little different, of course, but the same principle would apply.
All that said, there's a similar discussion in #40922 for the customize_changeset
post type, including a link to ticket:36368#comment:5, which warns against introducing primitive capabilities, as this approach would. #41332 tackles this issue for attachments.
Lastly, one of the additional backwards compatibility concerns to note in passing from #40922 is that the $cap
passed to user_has_cap
also changes when map_meta_cap => true
.
#71
@
3 years ago
Thanks for exploring this @dlh! I'm going to spend some time the next few days to see if we can make that work. For now, I'm going to commit our current solution to make the feature freeze deadline today.
TimothyBJacobs commented on PR #1814:
3 years ago
#73
#74
@
3 years ago
Lastly, a new menu item type is introduced, block, that can be used to store a Block as a menu item.
I think adding this bit of functionality might be premature. It's only used by an experimental screen in the Gutenberg plugin. If we end up abandoning that experiment then this could remain unused in Core forever.
#75
@
3 years ago
I agree @noisysocks, I think it is best to remove it. Will commit a fix later today.
This ticket was mentioned in PR #1872 on WordPress/wordpress-develop by spacedmonkey.
3 years ago
#78
Trac ticket: https://core.trac.wordpress.org/ticket/40878
spacedmonkey commented on PR #1872:
3 years ago
#80
Commited!
There are no immediate plans to add support for menus to the REST API, and throughout 2017 the plans for the REST API only consist of stabilising the existing endpoints and looking into implementing them in the WordPress admin area.
There's a plugin available which adds support for menus in the REST API though: https://wordpress.org/plugins/wp-api-menus/