Skip to content
Merged
46 changes: 46 additions & 0 deletions features/menu-item.feature
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,52 @@ Feature: Manage WordPress menu items
| custom | First | 1 | https://first.com |
| custom | Third | 2 | https://third.com |

Scenario: Menu order is recalculated on update
When I run `wp menu create "Sidebar Menu"`
Then STDOUT should not be empty

When I run `wp menu item add-custom sidebar-menu Alpha https://alpha.com --porcelain`
Then save STDOUT as {ITEM_ID_1}

When I run `wp menu item add-custom sidebar-menu Beta https://beta.com --porcelain`
Then save STDOUT as {ITEM_ID_2}

When I run `wp menu item add-custom sidebar-menu Gamma https://gamma.com --porcelain`
Then save STDOUT as {ITEM_ID_3}

When I run `wp menu item list sidebar-menu --fields=type,title,position,link`
Then STDOUT should be a table containing rows:
| type | title | position | link |
| custom | Alpha | 1 | https://alpha.com |
| custom | Beta | 2 | https://beta.com |
| custom | Gamma | 3 | https://gamma.com |

When I run `wp menu item update {ITEM_ID_3} --position=1`
Then STDOUT should be:
"""
Success: Menu item updated.
"""

When I run `wp menu item list sidebar-menu --fields=type,title,position,link`
Then STDOUT should be a table containing rows:
| type | title | position | link |
| custom | Gamma | 1 | https://gamma.com |
| custom | Alpha | 2 | https://alpha.com |
| custom | Beta | 3 | https://beta.com |

When I run `wp menu item update {ITEM_ID_1} --position=3`
Then STDOUT should be:
"""
Success: Menu item updated.
"""

When I run `wp menu item list sidebar-menu --fields=type,title,position,link`
Then STDOUT should be a table containing rows:
| type | title | position | link |
| custom | Gamma | 1 | https://gamma.com |
| custom | Beta | 2 | https://beta.com |
| custom | Alpha | 3 | https://alpha.com |

Scenario: Get menu item details
When I run `wp menu create "Sidebar Menu"`
Then STDOUT should not be empty
Expand Down
65 changes: 63 additions & 2 deletions src/Menu_Item_Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,8 @@ private function add_or_update_item( $method, $type, $args, $assoc_args ) {
$menu_item_obj = wp_setup_nav_menu_item( $menu_item_obj );

// Correct the menu position if this was the first item. See https://core.trac.wordpress.org/ticket/28140
$position = ( 0 === $menu_item_obj->menu_order ) ? 1 : $menu_item_obj->menu_order;
$position = ( 0 === $menu_item_obj->menu_order ) ? 1 : $menu_item_obj->menu_order;
$old_position = $position;
Comment thread
swissspidy marked this conversation as resolved.
Outdated

$default_args = [
'position' => $position,
Expand Down Expand Up @@ -634,7 +635,67 @@ private function add_or_update_item( $method, $type, $args, $assoc_args ) {
}

$menu_item_args['menu-item-type'] = $type;
$result = wp_update_nav_menu_item( $menu->term_id, $menu_item_db_id, $menu_item_args );

// Reorder other menu items when the position changes on update.
if ( 'update' === $method ) {
$new_position = (int) $menu_item_args['menu-item-position'];
if ( $new_position > 0 ) {
// Fetch all menu items sorted by their raw menu_order to determine
// normalized (1-indexed) ranks, since wp_get_nav_menu_items(ARRAY_A)
// normalises menu_order to 1,2,3… which may differ from the raw DB values.
$sorted_items = get_posts(
[
Comment thread
swissspidy marked this conversation as resolved.
'post_type' => 'nav_menu_item',
'numberposts' => -1,
'orderby' => 'menu_order',
'order' => 'ASC',
'post_status' => 'any',
'tax_query' => [
[
'taxonomy' => 'nav_menu',
'field' => 'term_taxonomy_id',
'terms' => $menu->term_taxonomy_id,
],
],
]
);

// Find the 1-indexed normalized rank of the item being moved.
$old_position_normalized = 0;
foreach ( $sorted_items as $idx => $sorted_item ) {
if ( (int) $sorted_item->ID === (int) $menu_item_db_id ) {
$old_position_normalized = $idx + 1;
break;
}
}

if ( $old_position_normalized > 0 && $new_position !== $old_position_normalized ) {
if ( $new_position < $old_position_normalized ) {
// Moving up: items at 0-indexed [new_pos-1, old_pos-2] shift down by +1.
for ( $i = $new_position - 1; $i <= $old_position_normalized - 2; $i++ ) {
wp_update_post(
[
'ID' => $sorted_items[ $i ]->ID,
'menu_order' => $i + 2,
]
);
}
} else {
// Moving down: items at 0-indexed [old_pos, new_pos-1] shift up by -1.
for ( $i = $old_position_normalized; $i <= $new_position - 1; $i++ ) {
wp_update_post(
[
'ID' => $sorted_items[ $i ]->ID,
'menu_order' => $i,
]
);
}
Comment thread
swissspidy marked this conversation as resolved.
Outdated
}
Comment thread
swissspidy marked this conversation as resolved.
}
}
}

$result = wp_update_nav_menu_item( $menu->term_id, $menu_item_db_id, $menu_item_args );

Comment thread
swissspidy marked this conversation as resolved.
if ( is_wp_error( $result ) ) {
WP_CLI::error( $result->get_error_message() );
Expand Down
Loading