--- a/wp/wp-includes/nav-menu.php Thu Sep 29 08:06:27 2022 +0200
+++ b/wp/wp-includes/nav-menu.php Fri Sep 05 18:40:08 2025 +0200
@@ -143,7 +143,7 @@
*
* @global array $_wp_registered_nav_menus
*
- * @return string[] Associative array of egistered navigation menu descriptions keyed
+ * @return string[] Associative array of registered navigation menu descriptions keyed
* by their location. If none are registered, an empty array.
*/
function get_registered_nav_menus() {
@@ -280,7 +280,7 @@
// Remove this menu from any locations.
$locations = get_nav_menu_locations();
foreach ( $locations as $location => $menu_id ) {
- if ( $menu_id == $menu->term_id ) {
+ if ( $menu_id === $menu->term_id ) {
$locations[ $location ] = 0;
}
}
@@ -331,7 +331,7 @@
$_possible_existing &&
! is_wp_error( $_possible_existing ) &&
isset( $_possible_existing->term_id ) &&
- $_possible_existing->term_id != $menu_id
+ $_possible_existing->term_id !== $menu_id
) {
return new WP_Error(
'menu_exists',
@@ -458,12 +458,22 @@
$args = wp_parse_args( $menu_item_data, $defaults );
- if ( 0 == $menu_id ) {
+ if ( 0 === $menu_id ) {
$args['menu-item-position'] = 1;
- } elseif ( 0 == (int) $args['menu-item-position'] ) {
- $menu_items = 0 == $menu_id ? array() : (array) wp_get_nav_menu_items( $menu_id, array( 'post_status' => 'publish,draft' ) );
- $last_item = array_pop( $menu_items );
- $args['menu-item-position'] = ( $last_item && isset( $last_item->menu_order ) ) ? 1 + $last_item->menu_order : count( $menu_items );
+ } elseif ( 0 === (int) $args['menu-item-position'] ) {
+ $menu_items = array();
+
+ if ( 0 !== $menu_id ) {
+ $menu_items = (array) wp_get_nav_menu_items( $menu_id, array( 'post_status' => 'publish,draft' ) );
+ }
+
+ $last_item = array_pop( $menu_items );
+
+ if ( $last_item && isset( $last_item->menu_order ) ) {
+ $args['menu-item-position'] = 1 + $last_item->menu_order;
+ } else {
+ $args['menu-item-position'] = count( $menu_items );
+ }
}
$original_parent = 0 < $menu_item_db_id ? get_post_field( 'post_parent', $menu_item_db_id ) : 0;
@@ -522,7 +532,7 @@
$post['post_date'] = $post_date;
}
- $update = 0 != $menu_item_db_id;
+ $update = 0 !== $menu_item_db_id;
// New menu item. Default is draft status.
if ( ! $update ) {
@@ -547,8 +557,10 @@
do_action( 'wp_add_nav_menu_item', $menu_id, $menu_item_db_id, $args );
}
- // Associate the menu item with the menu term.
- // Only set the menu term if it isn't set to avoid unnecessary wp_get_object_terms().
+ /*
+ * Associate the menu item with the menu term.
+ * Only set the menu term if it isn't set to avoid unnecessary wp_get_object_terms().
+ */
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 ) ) {
@@ -563,6 +575,11 @@
$menu_item_db_id = (int) $menu_item_db_id;
+ // Reset invalid `menu_item_parent`.
+ if ( (int) $args['menu-item-parent-id'] === $menu_item_db_id ) {
+ $args['menu-item-parent-id'] = 0;
+ }
+
update_post_meta( $menu_item_db_id, '_menu_item_type', sanitize_key( $args['menu-item-type'] ) );
update_post_meta( $menu_item_db_id, '_menu_item_menu_item_parent', (string) ( (int) $args['menu-item-parent-id'] ) );
update_post_meta( $menu_item_db_id, '_menu_item_object_id', (string) ( (int) $args['menu-item-object-id'] ) );
@@ -573,9 +590,9 @@
$args['menu-item-xfn'] = implode( ' ', array_map( 'sanitize_html_class', explode( ' ', $args['menu-item-xfn'] ) ) );
update_post_meta( $menu_item_db_id, '_menu_item_classes', $args['menu-item-classes'] );
update_post_meta( $menu_item_db_id, '_menu_item_xfn', $args['menu-item-xfn'] );
- update_post_meta( $menu_item_db_id, '_menu_item_url', esc_url_raw( $args['menu-item-url'] ) );
+ update_post_meta( $menu_item_db_id, '_menu_item_url', sanitize_url( $args['menu-item-url'] ) );
- if ( 0 == $menu_id ) {
+ if ( 0 === $menu_id ) {
update_post_meta( $menu_item_db_id, '_menu_item_orphaned', (string) time() );
} elseif ( get_post_meta( $menu_item_db_id, '_menu_item_orphaned' ) ) {
delete_post_meta( $menu_item_db_id, '_menu_item_orphaned' );
@@ -669,18 +686,21 @@
* @param array $args {
* Optional. Arguments to pass to get_posts().
*
- * @type string $order How to order nav menu items as queried with get_posts(). Will be ignored
- * if 'output' is ARRAY_A. Default 'ASC'.
- * @type string $orderby Field to order menu items by as retrieved from get_posts(). Supply an orderby
- * field via 'output_key' to affect the output order of nav menu items.
- * Default 'menu_order'.
- * @type string $post_type Menu items post type. Default 'nav_menu_item'.
- * @type string $post_status Menu items post status. Default 'publish'.
- * @type string $output How to order outputted menu items. Default ARRAY_A.
- * @type string $output_key Key to use for ordering the actual menu items that get returned. Note that
- * that is not a get_posts() argument and will only affect output of menu items
- * processed in this function. Default 'menu_order'.
- * @type bool $nopaging Whether to retrieve all menu items (true) or paginate (false). Default true.
+ * @type string $order How to order nav menu items as queried with get_posts().
+ * Will be ignored if 'output' is ARRAY_A. Default 'ASC'.
+ * @type string $orderby Field to order menu items by as retrieved from get_posts().
+ * Supply an orderby field via 'output_key' to affect the
+ * output order of nav menu items. Default 'menu_order'.
+ * @type string $post_type Menu items post type. Default 'nav_menu_item'.
+ * @type string $post_status Menu items post status. Default 'publish'.
+ * @type string $output How to order outputted menu items. Default ARRAY_A.
+ * @type string $output_key Key to use for ordering the actual menu items that get
+ * returned. Note that that is not a get_posts() argument
+ * and will only affect output of menu items processed in
+ * this function. Default 'menu_order'.
+ * @type bool $nopaging Whether to retrieve all menu items (true) or paginate
+ * (false). Default true.
+ * @type bool $update_menu_item_cache Whether to update the menu item cache. Default true.
* }
* @return array|false Array of menu items, otherwise false.
*/
@@ -691,21 +711,20 @@
return false;
}
- static $fetched = array();
-
if ( ! taxonomy_exists( 'nav_menu' ) ) {
return false;
}
$defaults = array(
- 'order' => 'ASC',
- 'orderby' => 'menu_order',
- 'post_type' => 'nav_menu_item',
- 'post_status' => 'publish',
- 'output' => ARRAY_A,
- 'output_key' => 'menu_order',
- 'nopaging' => true,
- 'tax_query' => array(
+ 'order' => 'ASC',
+ 'orderby' => 'menu_order',
+ 'post_type' => 'nav_menu_item',
+ 'post_status' => 'publish',
+ 'output' => ARRAY_A,
+ 'output_key' => 'menu_order',
+ 'nopaging' => true,
+ 'update_menu_item_cache' => true,
+ 'tax_query' => array(
array(
'taxonomy' => 'nav_menu',
'field' => 'term_taxonomy_id',
@@ -720,33 +739,6 @@
$items = array();
}
- // Prime posts and terms caches.
- if ( empty( $fetched[ $menu->term_id ] ) ) {
- $fetched[ $menu->term_id ] = true;
- $post_ids = array();
- $term_ids = array();
- foreach ( $items as $item ) {
- $object_id = get_post_meta( $item->ID, '_menu_item_object_id', true );
- $type = get_post_meta( $item->ID, '_menu_item_type', true );
-
- if ( 'post_type' === $type ) {
- $post_ids[] = (int) $object_id;
- } elseif ( 'taxonomy' === $type ) {
- $term_ids[] = (int) $object_id;
- }
- }
-
- if ( ! empty( $post_ids ) ) {
- _prime_post_caches( $post_ids, false );
- }
- unset( $post_ids );
-
- if ( ! empty( $term_ids ) ) {
- _prime_term_caches( $term_ids );
- }
- unset( $term_ids );
- }
-
$items = array_map( 'wp_setup_nav_menu_item', $items );
if ( ! is_admin() ) { // Remove invalid items only on front end.
@@ -781,6 +773,41 @@
}
/**
+ * Updates post and term caches for all linked objects for a list of menu items.
+ *
+ * @since 6.1.0
+ *
+ * @param WP_Post[] $menu_items Array of menu item post objects.
+ */
+function update_menu_item_cache( $menu_items ) {
+ $post_ids = array();
+ $term_ids = array();
+
+ foreach ( $menu_items as $menu_item ) {
+ if ( 'nav_menu_item' !== $menu_item->post_type ) {
+ continue;
+ }
+
+ $object_id = get_post_meta( $menu_item->ID, '_menu_item_object_id', true );
+ $type = get_post_meta( $menu_item->ID, '_menu_item_type', true );
+
+ if ( 'post_type' === $type ) {
+ $post_ids[] = (int) $object_id;
+ } elseif ( 'taxonomy' === $type ) {
+ $term_ids[] = (int) $object_id;
+ }
+ }
+
+ if ( ! empty( $post_ids ) ) {
+ _prime_post_caches( $post_ids, false );
+ }
+
+ if ( ! empty( $term_ids ) ) {
+ _prime_term_caches( $term_ids );
+ }
+}
+
+/**
* Decorates a menu item object with the shared navigation menu item properties.
*
* Properties:
@@ -808,6 +835,24 @@
* @return object The menu item with standard menu item properties.
*/
function wp_setup_nav_menu_item( $menu_item ) {
+
+ /**
+ * Filters whether to short-circuit the wp_setup_nav_menu_item() output.
+ *
+ * Returning a non-null value from the filter will short-circuit wp_setup_nav_menu_item(),
+ * returning that value instead.
+ *
+ * @since 6.3.0
+ *
+ * @param object|null $modified_menu_item Modified menu item. Default null.
+ * @param object $menu_item The menu item to modify.
+ */
+ $pre_menu_item = apply_filters( 'pre_wp_setup_nav_menu_item', null, $menu_item );
+
+ if ( null !== $pre_menu_item ) {
+ return $pre_menu_item;
+ }
+
if ( isset( $menu_item->post_type ) ) {
if ( 'nav_menu_item' === $menu_item->post_type ) {
$menu_item->db_id = (int) $menu_item->ID;
@@ -1003,7 +1048,7 @@
$object_id = (int) $object_id;
$menu_item_ids = array();
- $query = new WP_Query;
+ $query = new WP_Query();
$menu_items = $query->query(
array(
'meta_key' => '_menu_item_object_id',
@@ -1024,7 +1069,7 @@
} elseif (
'taxonomy' === $object_type &&
'taxonomy' === $menu_item_type &&
- get_post_meta( $menu_item->ID, '_menu_item_object', true ) == $taxonomy
+ get_post_meta( $menu_item->ID, '_menu_item_object', true ) === $taxonomy
) {
$menu_item_ids[] = (int) $menu_item->ID;
}
@@ -1111,7 +1156,7 @@
continue;
}
foreach ( $items as $item ) {
- if ( $post->ID == $item->object_id ) {
+ if ( $post->ID === (int) $item->object_id ) {
continue 2;
}
}
@@ -1266,3 +1311,31 @@
return $new_nav_menu_locations;
}
+
+/**
+ * Prevents menu items from being their own parent.
+ *
+ * Resets menu_item_parent to 0 when the parent is set to the item itself.
+ * For use before saving `_menu_item_menu_item_parent` in nav-menus.php.
+ *
+ * @since 6.2.0
+ * @access private
+ *
+ * @param array $menu_item_data The menu item data array.
+ * @return array The menu item data with reset menu_item_parent.
+ */
+function _wp_reset_invalid_menu_item_parent( $menu_item_data ) {
+ if ( ! is_array( $menu_item_data ) ) {
+ return $menu_item_data;
+ }
+
+ if (
+ ! empty( $menu_item_data['ID'] ) &&
+ ! empty( $menu_item_data['menu_item_parent'] ) &&
+ (int) $menu_item_data['ID'] === (int) $menu_item_data['menu_item_parent']
+ ) {
+ $menu_item_data['menu_item_parent'] = 0;
+ }
+
+ return $menu_item_data;
+}