Skip to content

Commit c7dfdf0

Browse files
authored
Apply suggestions from code review
Co-authored-by: Pascal Birchler <pascal.birchler@gmail.com>
1 parent bb9e9b2 commit c7dfdf0

1 file changed

Lines changed: 67 additions & 55 deletions

File tree

src/Menu_Item_Command.php

Lines changed: 67 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -643,58 +643,54 @@ private function add_or_update_item( $method, $type, $args, $assoc_args ) {
643643
// Fetch all menu items sorted by their raw menu_order to determine
644644
// normalized (1-indexed) ranks, since wp_get_nav_menu_items(ARRAY_A)
645645
// normalises menu_order to 1,2,3… which may differ from the raw DB values.
646-
$sorted_items = get_posts(
647-
[
648-
'post_type' => 'nav_menu_item',
649-
'numberposts' => -1,
650-
'orderby' => 'menu_order',
651-
'order' => 'ASC',
652-
'post_status' => 'any',
653-
'tax_query' => [
654-
[
655-
'taxonomy' => 'nav_menu',
656-
'field' => 'term_taxonomy_id',
657-
'terms' => $menu->term_taxonomy_id,
658-
],
659-
],
660-
]
661-
);
662-
663-
// Clamp the requested position to the valid range of menu items.
664-
$max_position = count( $sorted_items );
665-
if ( $max_position > 0 && $new_position > $max_position ) {
666-
// Treat out-of-range positions as "move to end", consistent with core behavior.
667-
$new_position = $max_position;
668-
}
669-
670-
// Find the 1-indexed normalized rank of the item being moved.
671-
$old_position_normalized = 0;
672-
foreach ( $sorted_items as $idx => $sorted_item ) {
673-
if ( (int) $sorted_item->ID === (int) $menu_item_db_id ) {
674-
$old_position_normalized = $idx + 1;
675-
break;
676-
}
677-
}
678-
679-
if ( $old_position_normalized > 0 && $new_position !== $old_position_normalized ) {
680-
if ( $new_position < $old_position_normalized ) {
681-
// Moving up: items at 0-indexed [new_pos-1, old_pos-2] shift down by +1.
682-
for ( $i = $new_position - 1; $i <= $old_position_normalized - 2; $i++ ) {
683-
$pending_menu_order_updates[] = [
684-
'ID' => $sorted_items[ $i ]->ID,
685-
'menu_order' => $i + 2,
686-
];
687-
}
688-
} else {
689-
// Moving down: items at 0-indexed [old_pos, new_pos-1] shift up by -1.
690-
for ( $i = $old_position_normalized; $i <= $new_position - 1; $i++ ) {
691-
$pending_menu_order_updates[] = [
692-
'ID' => $sorted_items[ $i ]->ID,
693-
'menu_order' => $i,
694-
];
695-
}
696-
}
697-
}
646+
$sorted_item_ids = get_posts(
647+
[
648+
'post_type' => 'nav_menu_item',
649+
'numberposts' => -1,
650+
'orderby' => 'menu_order',
651+
'order' => 'ASC',
652+
'post_status' => 'any',
653+
'tax_query' => [
654+
[
655+
'taxonomy' => 'nav_menu',
656+
'field' => 'term_taxonomy_id',
657+
'terms' => $menu->term_taxonomy_id,
658+
],
659+
],
660+
'fields' => 'ids',
661+
]
662+
);
663+
664+
// Clamp the requested position to the valid range of menu items.
665+
$max_position = count( $sorted_item_ids );
666+
if ( $max_position > 0 && $new_position > $max_position ) {
667+
// Treat out-of-range positions as "move to end", consistent with core behavior.
668+
$new_position = $max_position;
669+
}
670+
671+
// Find the 1-indexed normalized rank of the item being moved.
672+
$item_idx = array_search( (string) $menu_item_db_id, $sorted_item_ids, true );
673+
$old_position_normalized = ( false !== $item_idx ) ? $item_idx + 1 : 0;
674+
675+
if ( $old_position_normalized > 0 && $new_position !== $old_position_normalized ) {
676+
if ( $new_position < $old_position_normalized ) {
677+
// Moving up: items at 0-indexed [new_pos-1, old_pos-2] shift down by +1.
678+
for ( $i = $new_position - 1; $i <= $old_position_normalized - 2; $i++ ) {
679+
$pending_menu_order_updates[] = [
680+
'ID' => $sorted_item_ids[ $i ],
681+
'menu_order' => $i + 2,
682+
];
683+
}
684+
} else {
685+
// Moving down: items at 0-indexed [old_pos, new_pos-1] shift up by -1.
686+
for ( $i = $old_position_normalized; $i <= $new_position - 1; $i++ ) {
687+
$pending_menu_order_updates[] = [
688+
'ID' => $sorted_item_ids[ $i ],
689+
'menu_order' => $i,
690+
];
691+
}
692+
}
693+
}
698694
}
699695
}
700696

@@ -710,9 +706,25 @@ private function add_or_update_item( $method, $type, $args, $assoc_args ) {
710706
}
711707
} else {
712708
// Apply deferred reordering of other menu items only after a successful update.
713-
foreach ( $pending_menu_order_updates as $update_args ) {
714-
wp_update_post( $update_args );
715-
}
709+
if ( ! empty( $pending_menu_order_updates ) ) {
710+
global $wpdb;
711+
712+
$ids_to_update = [];
713+
$case_clauses = '';
714+
foreach ( $pending_menu_order_updates as $update_args ) {
715+
$item_id = (int) $update_args['ID'];
716+
$ids_to_update[] = $item_id;
717+
$case_clauses .= $wpdb->prepare( ' WHEN %d THEN %d', $item_id, $update_args['menu_order'] );
718+
}
719+
720+
$ids_sql = implode( ',', $ids_to_update );
721+
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- $case_clauses and $ids_sql are constructed from prepared/safe values.
722+
$wpdb->query( "UPDATE {$wpdb->posts} SET menu_order = CASE ID {$case_clauses} END WHERE ID IN ({$ids_sql})" );
723+
724+
foreach ( $ids_to_update as $id ) {
725+
clean_post_cache( $id );
726+
}
727+
}
716728

717729
if ( ( 'add' === $method ) && $menu_item_args['menu-item-position'] ) {
718730
$this->reorder_menu_items( $menu->term_id, $menu_item_args['menu-item-position'], +1, $result );

0 commit comments

Comments
 (0)