wp/wp-includes/nav-menu.php
changeset 19 3d72ae0968f4
parent 18 be944660c56a
child 21 48c4eec2b7e6
equal deleted inserted replaced
18:be944660c56a 19:3d72ae0968f4
    48 	 */
    48 	 */
    49 	return apply_filters( 'wp_get_nav_menu_object', $menu_obj, $menu );
    49 	return apply_filters( 'wp_get_nav_menu_object', $menu_obj, $menu );
    50 }
    50 }
    51 
    51 
    52 /**
    52 /**
    53  * Check if the given ID is a navigation menu.
    53  * Determines whether the given ID is a navigation menu.
    54  *
    54  *
    55  * Returns true if it is; false otherwise.
    55  * Returns true if it is; false otherwise.
    56  *
    56  *
    57  * @since 3.0.0
    57  * @since 3.0.0
    58  *
    58  *
   157 /**
   157 /**
   158  * Retrieves all registered navigation menu locations and the menus assigned to them.
   158  * Retrieves all registered navigation menu locations and the menus assigned to them.
   159  *
   159  *
   160  * @since 3.0.0
   160  * @since 3.0.0
   161  *
   161  *
   162  * @return int[] Associative array of egistered navigation menu IDs keyed by their
   162  * @return int[] Associative array of registered navigation menu IDs keyed by their
   163  *               location name. If none are registered, an empty array.
   163  *               location name. If none are registered, an empty array.
   164  */
   164  */
   165 function get_nav_menu_locations() {
   165 function get_nav_menu_locations() {
   166 	$locations = get_theme_mod( 'nav_menu_locations' );
   166 	$locations = get_theme_mod( 'nav_menu_locations' );
   167 	return ( is_array( $locations ) ) ? $locations : array();
   167 	return ( is_array( $locations ) ) ? $locations : array();
   253 	// expected_slashed ($menu_name)
   253 	// expected_slashed ($menu_name)
   254 	return wp_update_nav_menu_object( 0, array( 'menu-name' => $menu_name ) );
   254 	return wp_update_nav_menu_object( 0, array( 'menu-name' => $menu_name ) );
   255 }
   255 }
   256 
   256 
   257 /**
   257 /**
   258  * Delete a Navigation Menu.
   258  * Deletes a navigation menu.
   259  *
   259  *
   260  * @since 3.0.0
   260  * @since 3.0.0
   261  *
   261  *
   262  * @param int|string|WP_Term $menu Menu ID, slug, name, or object.
   262  * @param int|string|WP_Term $menu Menu ID, slug, name, or object.
   263  * @return bool|WP_Error True on success, false or WP_Error object on failure.
   263  * @return bool|WP_Error True on success, false or WP_Error object on failure.
   300 
   300 
   301 	return $result;
   301 	return $result;
   302 }
   302 }
   303 
   303 
   304 /**
   304 /**
   305  * Save the properties of a menu or create a new menu with those properties.
   305  * Saves the properties of a menu or create a new menu with those properties.
   306  *
   306  *
   307  * Note that `$menu_data` is expected to be pre-slashed.
   307  * Note that `$menu_data` is expected to be pre-slashed.
   308  *
   308  *
   309  * @since 3.0.0
   309  * @since 3.0.0
   310  *
   310  *
   402 	do_action( 'wp_update_nav_menu', $menu_id, $menu_data );
   402 	do_action( 'wp_update_nav_menu', $menu_id, $menu_data );
   403 	return $menu_id;
   403 	return $menu_id;
   404 }
   404 }
   405 
   405 
   406 /**
   406 /**
   407  * Save the properties of a menu item or create a new one.
   407  * Saves the properties of a menu item or create a new one.
   408  *
   408  *
   409  * The menu-item-title, menu-item-description, and menu-item-attr-title are expected
   409  * The menu-item-title, menu-item-description and menu-item-attr-title are expected
   410  * to be pre-slashed since they are passed directly into `wp_insert_post()`.
   410  * to be pre-slashed since they are passed directly to APIs that expect slashed data.
   411  *
   411  *
   412  * @since 3.0.0
   412  * @since 3.0.0
   413  *
   413  * @since 5.9.0 Added the `$fire_after_hooks` parameter.
   414  * @param int   $menu_id         The ID of the menu. Required. If "0", makes the menu item a draft orphan.
   414  *
   415  * @param int   $menu_item_db_id The ID of the menu item. If "0", creates a new menu item.
   415  * @param int   $menu_id          The ID of the menu. If 0, makes the menu item a draft orphan.
   416  * @param array $menu_item_data  The menu item's data.
   416  * @param int   $menu_item_db_id  The ID of the menu item. If 0, creates a new menu item.
       
   417  * @param array $menu_item_data   The menu item's data.
       
   418  * @param bool  $fire_after_hooks Whether to fire the after insert hooks. Default true.
   417  * @return int|WP_Error The menu item's database ID or WP_Error object on failure.
   419  * @return int|WP_Error The menu item's database ID or WP_Error object on failure.
   418  */
   420  */
   419 function wp_update_nav_menu_item( $menu_id = 0, $menu_item_db_id = 0, $menu_item_data = array() ) {
   421 function wp_update_nav_menu_item( $menu_id = 0, $menu_item_db_id = 0, $menu_item_data = array(), $fire_after_hooks = true ) {
   420 	$menu_id         = (int) $menu_id;
   422 	$menu_id         = (int) $menu_id;
   421 	$menu_item_db_id = (int) $menu_item_db_id;
   423 	$menu_item_db_id = (int) $menu_item_db_id;
   422 
   424 
   423 	// Make sure that we don't convert non-nav_menu_item objects into nav_menu_item objects.
   425 	// Make sure that we don't convert non-nav_menu_item objects into nav_menu_item objects.
   424 	if ( ! empty( $menu_item_db_id ) && ! is_nav_menu_item( $menu_item_db_id ) ) {
   426 	if ( ! empty( $menu_item_db_id ) && ! is_nav_menu_item( $menu_item_db_id ) ) {
   524 
   526 
   525 	// New menu item. Default is draft status.
   527 	// New menu item. Default is draft status.
   526 	if ( ! $update ) {
   528 	if ( ! $update ) {
   527 		$post['ID']          = 0;
   529 		$post['ID']          = 0;
   528 		$post['post_status'] = 'publish' === $args['menu-item-status'] ? 'publish' : 'draft';
   530 		$post['post_status'] = 'publish' === $args['menu-item-status'] ? 'publish' : 'draft';
   529 		$menu_item_db_id     = wp_insert_post( $post );
   531 		$menu_item_db_id     = wp_insert_post( $post, true, $fire_after_hooks );
   530 		if ( ! $menu_item_db_id || is_wp_error( $menu_item_db_id ) ) {
   532 		if ( ! $menu_item_db_id || is_wp_error( $menu_item_db_id ) ) {
   531 			return $menu_item_db_id;
   533 			return $menu_item_db_id;
   532 		}
   534 		}
   533 
   535 
   534 		/**
   536 		/**
   546 	}
   548 	}
   547 
   549 
   548 	// Associate the menu item with the menu term.
   550 	// Associate the menu item with the menu term.
   549 	// Only set the menu term if it isn't set to avoid unnecessary wp_get_object_terms().
   551 	// Only set the menu term if it isn't set to avoid unnecessary wp_get_object_terms().
   550 	if ( $menu_id && ( ! $update || ! is_object_in_term( $menu_item_db_id, 'nav_menu', (int) $menu->term_id ) ) ) {
   552 	if ( $menu_id && ( ! $update || ! is_object_in_term( $menu_item_db_id, 'nav_menu', (int) $menu->term_id ) ) ) {
   551 		wp_set_object_terms( $menu_item_db_id, array( $menu->term_id ), 'nav_menu' );
   553 		$update_terms = wp_set_object_terms( $menu_item_db_id, array( $menu->term_id ), 'nav_menu' );
       
   554 		if ( is_wp_error( $update_terms ) ) {
       
   555 			return $update_terms;
       
   556 		}
   552 	}
   557 	}
   553 
   558 
   554 	if ( 'custom' === $args['menu-item-type'] ) {
   559 	if ( 'custom' === $args['menu-item-type'] ) {
   555 		$args['menu-item-object-id'] = $menu_item_db_id;
   560 		$args['menu-item-object-id'] = $menu_item_db_id;
   556 		$args['menu-item-object']    = 'custom';
   561 		$args['menu-item-object']    = 'custom';
   578 
   583 
   579 	// Update existing menu item. Default is publish status.
   584 	// Update existing menu item. Default is publish status.
   580 	if ( $update ) {
   585 	if ( $update ) {
   581 		$post['ID']          = $menu_item_db_id;
   586 		$post['ID']          = $menu_item_db_id;
   582 		$post['post_status'] = ( 'draft' === $args['menu-item-status'] ) ? 'draft' : 'publish';
   587 		$post['post_status'] = ( 'draft' === $args['menu-item-status'] ) ? 'draft' : 'publish';
   583 		wp_update_post( $post );
   588 
       
   589 		$update_post = wp_update_post( $post, true );
       
   590 		if ( is_wp_error( $update_post ) ) {
       
   591 			return $update_post;
       
   592 		}
   584 	}
   593 	}
   585 
   594 
   586 	/**
   595 	/**
   587 	 * Fires after a navigation menu item has been updated.
   596 	 * Fires after a navigation menu item has been updated.
   588 	 *
   597 	 *
   630 	 */
   639 	 */
   631 	return apply_filters( 'wp_get_nav_menus', get_terms( $args ), $args );
   640 	return apply_filters( 'wp_get_nav_menus', get_terms( $args ), $args );
   632 }
   641 }
   633 
   642 
   634 /**
   643 /**
   635  * Return if a menu item is valid.
   644  * Determines whether a menu item is valid.
   636  *
   645  *
   637  * @link https://core.trac.wordpress.org/ticket/13958
   646  * @link https://core.trac.wordpress.org/ticket/13958
   638  *
   647  *
   639  * @since 3.2.0
   648  * @since 3.2.0
   640  * @access private
   649  * @access private
   682 		return false;
   691 		return false;
   683 	}
   692 	}
   684 
   693 
   685 	static $fetched = array();
   694 	static $fetched = array();
   686 
   695 
   687 	$items = get_objects_in_term( $menu->term_id, 'nav_menu' );
   696 	if ( ! taxonomy_exists( 'nav_menu' ) ) {
   688 	if ( is_wp_error( $items ) ) {
       
   689 		return false;
   697 		return false;
   690 	}
   698 	}
   691 
   699 
   692 	$defaults        = array(
   700 	$defaults = array(
   693 		'order'       => 'ASC',
   701 		'order'       => 'ASC',
   694 		'orderby'     => 'menu_order',
   702 		'orderby'     => 'menu_order',
   695 		'post_type'   => 'nav_menu_item',
   703 		'post_type'   => 'nav_menu_item',
   696 		'post_status' => 'publish',
   704 		'post_status' => 'publish',
   697 		'output'      => ARRAY_A,
   705 		'output'      => ARRAY_A,
   698 		'output_key'  => 'menu_order',
   706 		'output_key'  => 'menu_order',
   699 		'nopaging'    => true,
   707 		'nopaging'    => true,
       
   708 		'tax_query'   => array(
       
   709 			array(
       
   710 				'taxonomy' => 'nav_menu',
       
   711 				'field'    => 'term_taxonomy_id',
       
   712 				'terms'    => $menu->term_taxonomy_id,
       
   713 			),
       
   714 		),
   700 	);
   715 	);
   701 	$args            = wp_parse_args( $args, $defaults );
   716 	$args     = wp_parse_args( $args, $defaults );
   702 	$args['include'] = $items;
   717 	if ( $menu->count > 0 ) {
   703 
       
   704 	if ( ! empty( $items ) ) {
       
   705 		$items = get_posts( $args );
   718 		$items = get_posts( $args );
   706 	} else {
   719 	} else {
   707 		$items = array();
   720 		$items = array();
   708 	}
   721 	}
   709 
   722 
   710 	// Get all posts and terms at once to prime the caches.
   723 	// Prime posts and terms caches.
   711 	if ( empty( $fetched[ $menu->term_id ] ) && ! wp_using_ext_object_cache() ) {
   724 	if ( empty( $fetched[ $menu->term_id ] ) ) {
   712 		$fetched[ $menu->term_id ] = true;
   725 		$fetched[ $menu->term_id ] = true;
   713 		$posts                     = array();
   726 		$post_ids                  = array();
   714 		$terms                     = array();
   727 		$term_ids                  = array();
   715 		foreach ( $items as $item ) {
   728 		foreach ( $items as $item ) {
   716 			$object_id = get_post_meta( $item->ID, '_menu_item_object_id', true );
   729 			$object_id = get_post_meta( $item->ID, '_menu_item_object_id', true );
   717 			$object    = get_post_meta( $item->ID, '_menu_item_object', true );
       
   718 			$type      = get_post_meta( $item->ID, '_menu_item_type', true );
   730 			$type      = get_post_meta( $item->ID, '_menu_item_type', true );
   719 
   731 
   720 			if ( 'post_type' === $type ) {
   732 			if ( 'post_type' === $type ) {
   721 				$posts[ $object ][] = $object_id;
   733 				$post_ids[] = (int) $object_id;
   722 			} elseif ( 'taxonomy' === $type ) {
   734 			} elseif ( 'taxonomy' === $type ) {
   723 				$terms[ $object ][] = $object_id;
   735 				$term_ids[] = (int) $object_id;
   724 			}
   736 			}
   725 		}
   737 		}
   726 
   738 
   727 		if ( ! empty( $posts ) ) {
   739 		if ( ! empty( $post_ids ) ) {
   728 			foreach ( array_keys( $posts ) as $post_type ) {
   740 			_prime_post_caches( $post_ids, false );
   729 				get_posts(
   741 		}
   730 					array(
   742 		unset( $post_ids );
   731 						'post__in'               => $posts[ $post_type ],
   743 
   732 						'post_type'              => $post_type,
   744 		if ( ! empty( $term_ids ) ) {
   733 						'nopaging'               => true,
   745 			_prime_term_caches( $term_ids );
   734 						'update_post_term_cache' => false,
   746 		}
   735 					)
   747 		unset( $term_ids );
   736 				);
       
   737 			}
       
   738 		}
       
   739 		unset( $posts );
       
   740 
       
   741 		if ( ! empty( $terms ) ) {
       
   742 			foreach ( array_keys( $terms ) as $taxonomy ) {
       
   743 				get_terms(
       
   744 					array(
       
   745 						'taxonomy'     => $taxonomy,
       
   746 						'include'      => $terms[ $taxonomy ],
       
   747 						'hierarchical' => false,
       
   748 					)
       
   749 				);
       
   750 			}
       
   751 		}
       
   752 		unset( $terms );
       
   753 	}
   748 	}
   754 
   749 
   755 	$items = array_map( 'wp_setup_nav_menu_item', $items );
   750 	$items = array_map( 'wp_setup_nav_menu_item', $items );
   756 
   751 
   757 	if ( ! is_admin() ) { // Remove invalid items only on front end.
   752 	if ( ! is_admin() ) { // Remove invalid items only on front end.
   991 	 */
   986 	 */
   992 	return apply_filters( 'wp_setup_nav_menu_item', $menu_item );
   987 	return apply_filters( 'wp_setup_nav_menu_item', $menu_item );
   993 }
   988 }
   994 
   989 
   995 /**
   990 /**
   996  * Get the menu items associated with a particular object.
   991  * Returns the menu items associated with a particular object.
   997  *
   992  *
   998  * @since 3.0.0
   993  * @since 3.0.0
   999  *
   994  *
  1000  * @param int    $object_id   Optional. The ID of the original object. Default 0.
   995  * @param int    $object_id   Optional. The ID of the original object. Default 0.
  1001  * @param string $object_type Optional. The type of object, such as 'post_type' or 'taxonomy'.
   996  * @param string $object_type Optional. The type of object, such as 'post_type' or 'taxonomy'.
  1123 		wp_update_nav_menu_item( $menu_id, 0, $args );
  1118 		wp_update_nav_menu_item( $menu_id, 0, $args );
  1124 	}
  1119 	}
  1125 }
  1120 }
  1126 
  1121 
  1127 /**
  1122 /**
  1128  * Delete auto-draft posts associated with the supplied changeset.
  1123  * Deletes auto-draft posts associated with the supplied changeset.
  1129  *
  1124  *
  1130  * @since 4.8.0
  1125  * @since 4.8.0
  1131  * @access private
  1126  * @access private
  1132  *
  1127  *
  1133  * @param int $post_id Post ID for the customize_changeset.
  1128  * @param int $post_id Post ID for the customize_changeset.
  1157 	}
  1152 	}
  1158 	add_action( 'delete_post', '_wp_delete_customize_changeset_dependent_auto_drafts' );
  1153 	add_action( 'delete_post', '_wp_delete_customize_changeset_dependent_auto_drafts' );
  1159 }
  1154 }
  1160 
  1155 
  1161 /**
  1156 /**
  1162  * Handle menu config after theme change.
  1157  * Handles menu config after theme change.
  1163  *
  1158  *
  1164  * @access private
  1159  * @access private
  1165  * @since 4.9.0
  1160  * @since 4.9.0
  1166  */
  1161  */
  1167 function _wp_menus_changed() {
  1162 function _wp_menus_changed() {