10 /** |
10 /** |
11 * Returns a navigation menu object. |
11 * Returns a navigation menu object. |
12 * |
12 * |
13 * @since 3.0.0 |
13 * @since 3.0.0 |
14 * |
14 * |
15 * @param string $menu Menu ID, slug, or name. |
15 * @param int|string|WP_Term $menu Menu ID, slug, name, or object. |
16 * @return mixed false if $menu param isn't supplied or term does not exist, menu object if successful. |
16 * @return WP_Term|false False if $menu param isn't supplied or term does not exist, menu object if successful. |
17 */ |
17 */ |
18 function wp_get_nav_menu_object( $menu ) { |
18 function wp_get_nav_menu_object( $menu ) { |
19 if ( ! $menu ) |
19 $menu_obj = false; |
20 return false; |
20 |
21 |
21 if ( is_object( $menu ) ) { |
22 $menu_obj = get_term( $menu, 'nav_menu' ); |
22 $menu_obj = $menu; |
23 |
23 } |
24 if ( ! $menu_obj ) |
24 |
25 $menu_obj = get_term_by( 'slug', $menu, 'nav_menu' ); |
25 if ( $menu && ! $menu_obj ) { |
26 |
26 $menu_obj = get_term( $menu, 'nav_menu' ); |
27 if ( ! $menu_obj ) |
27 |
28 $menu_obj = get_term_by( 'name', $menu, 'nav_menu' ); |
28 if ( ! $menu_obj ) { |
29 |
29 $menu_obj = get_term_by( 'slug', $menu, 'nav_menu' ); |
30 if ( ! $menu_obj ) |
30 } |
|
31 |
|
32 if ( ! $menu_obj ) { |
|
33 $menu_obj = get_term_by( 'name', $menu, 'nav_menu' ); |
|
34 } |
|
35 } |
|
36 |
|
37 if ( ! $menu_obj || is_wp_error( $menu_obj ) ) { |
31 $menu_obj = false; |
38 $menu_obj = false; |
32 |
39 } |
33 return $menu_obj; |
40 |
|
41 /** |
|
42 * Filters the nav_menu term retrieved for wp_get_nav_menu_object(). |
|
43 * |
|
44 * @since 4.3.0 |
|
45 * |
|
46 * @param WP_Term|false $menu_obj Term from nav_menu taxonomy, or false if nothing had been found. |
|
47 * @param int|string|WP_Term $menu The menu ID, slug, name, or object passed to wp_get_nav_menu_object(). |
|
48 */ |
|
49 return apply_filters( 'wp_get_nav_menu_object', $menu_obj, $menu ); |
34 } |
50 } |
35 |
51 |
36 /** |
52 /** |
37 * Check if the given ID is a navigation menu. |
53 * Check if the given ID is a navigation menu. |
38 * |
54 * |
39 * Returns true if it is; false otherwise. |
55 * Returns true if it is; false otherwise. |
40 * |
56 * |
41 * @since 3.0.0 |
57 * @since 3.0.0 |
42 * |
58 * |
43 * @param int|string $menu The menu to check (ID, slug, or name). |
59 * @param int|string|WP_Term $menu Menu ID, slug, name, or object of menu to check. |
44 * @return bool Whether the menu exists. |
60 * @return bool Whether the menu exists. |
45 */ |
61 */ |
46 function is_nav_menu( $menu ) { |
62 function is_nav_menu( $menu ) { |
47 if ( ! $menu ) |
63 if ( ! $menu ) |
48 return false; |
64 return false; |
93 } |
114 } |
94 return false; |
115 return false; |
95 } |
116 } |
96 |
117 |
97 /** |
118 /** |
98 * Register a navigation menu for a theme. |
119 * Registers a navigation menu location for a theme. |
99 * |
120 * |
100 * @since 3.0.0 |
121 * @since 3.0.0 |
101 * |
122 * |
102 * @param string $location Menu location identifier, like a slug. |
123 * @param string $location Menu location identifier, like a slug. |
103 * @param string $description Menu location descriptive text. |
124 * @param string $description Menu location descriptive text. |
104 */ |
125 */ |
105 function register_nav_menu( $location, $description ) { |
126 function register_nav_menu( $location, $description ) { |
106 register_nav_menus( array( $location => $description ) ); |
127 register_nav_menus( array( $location => $description ) ); |
107 } |
128 } |
108 /** |
129 /** |
109 * Returns an array of all registered navigation menus in a theme |
130 * Retrieves all registered navigation menu locations in a theme. |
110 * |
131 * |
111 * @since 3.0.0 |
132 * @since 3.0.0 |
112 * @return array |
133 * |
|
134 * @global array $_wp_registered_nav_menus |
|
135 * |
|
136 * @return array Registered navigation menu locations. If none are registered, an empty array. |
113 */ |
137 */ |
114 function get_registered_nav_menus() { |
138 function get_registered_nav_menus() { |
115 global $_wp_registered_nav_menus; |
139 global $_wp_registered_nav_menus; |
116 if ( isset( $_wp_registered_nav_menus ) ) |
140 if ( isset( $_wp_registered_nav_menus ) ) |
117 return $_wp_registered_nav_menus; |
141 return $_wp_registered_nav_menus; |
118 return array(); |
142 return array(); |
119 } |
143 } |
120 |
144 |
121 /** |
145 /** |
122 * Returns an array with the registered navigation menu locations and the menu assigned to it |
146 * Retrieves all registered navigation menu locations and the menus assigned to them. |
123 * |
147 * |
124 * @since 3.0.0 |
148 * @since 3.0.0 |
125 * @return array |
149 * |
|
150 * @return array Registered navigation menu locations and the menus assigned them. |
|
151 * If none are registered, an empty array. |
126 */ |
152 */ |
127 |
153 |
128 function get_nav_menu_locations() { |
154 function get_nav_menu_locations() { |
129 $locations = get_theme_mod( 'nav_menu_locations' ); |
155 $locations = get_theme_mod( 'nav_menu_locations' ); |
130 return ( is_array( $locations ) ) ? $locations : array(); |
156 return ( is_array( $locations ) ) ? $locations : array(); |
131 } |
157 } |
132 |
158 |
133 /** |
159 /** |
134 * Whether a registered nav menu location has a menu assigned to it. |
160 * Determines whether a registered nav menu location has a menu assigned to it. |
135 * |
161 * |
136 * @since 3.0.0 |
162 * @since 3.0.0 |
|
163 * |
137 * @param string $location Menu location identifier. |
164 * @param string $location Menu location identifier. |
138 * @return bool Whether location has a menu. |
165 * @return bool Whether location has a menu. |
139 */ |
166 */ |
140 function has_nav_menu( $location ) { |
167 function has_nav_menu( $location ) { |
|
168 $has_nav_menu = false; |
|
169 |
141 $registered_nav_menus = get_registered_nav_menus(); |
170 $registered_nav_menus = get_registered_nav_menus(); |
142 if ( ! isset( $registered_nav_menus[ $location ] ) ) { |
171 if ( isset( $registered_nav_menus[ $location ] ) ) { |
143 return false; |
172 $locations = get_nav_menu_locations(); |
144 } |
173 $has_nav_menu = ! empty( $locations[ $location ] ); |
|
174 } |
|
175 |
|
176 /** |
|
177 * Filters whether a nav menu is assigned to the specified location. |
|
178 * |
|
179 * @since 4.3.0 |
|
180 * |
|
181 * @param bool $has_nav_menu Whether there is a menu assigned to a location. |
|
182 * @param string $location Menu location. |
|
183 */ |
|
184 return apply_filters( 'has_nav_menu', $has_nav_menu, $location ); |
|
185 } |
|
186 |
|
187 /** |
|
188 * Returns the name of a navigation menu. |
|
189 * |
|
190 * @since 4.9.0 |
|
191 * |
|
192 * @param string $location Menu location identifier. |
|
193 * @return string Menu name. |
|
194 */ |
|
195 function wp_get_nav_menu_name( $location ) { |
|
196 $menu_name = ''; |
145 |
197 |
146 $locations = get_nav_menu_locations(); |
198 $locations = get_nav_menu_locations(); |
147 return ( ! empty( $locations[ $location ] ) ); |
199 |
148 } |
200 if ( isset( $locations[ $location ] ) ) { |
149 |
201 $menu = wp_get_nav_menu_object( $locations[ $location ] ); |
150 /** |
202 |
151 * Determine whether the given ID is a nav menu item. |
203 if ( $menu && $menu->name ) { |
|
204 $menu_name = $menu->name; |
|
205 } |
|
206 } |
|
207 |
|
208 /** |
|
209 * Filters the navigation menu name being returned. |
|
210 * |
|
211 * @since 4.9.0 |
|
212 * |
|
213 * @param string $menu_name Menu name. |
|
214 * @param string $location Menu location identifier. |
|
215 */ |
|
216 return apply_filters( 'wp_get_nav_menu_name', $menu_name, $location ); |
|
217 } |
|
218 |
|
219 /** |
|
220 * Determines whether the given ID is a nav menu item. |
152 * |
221 * |
153 * @since 3.0.0 |
222 * @since 3.0.0 |
154 * |
223 * |
155 * @param int $menu_item_id The ID of the potential nav menu item. |
224 * @param int $menu_item_id The ID of the potential nav menu item. |
156 * @return bool Whether the given ID is that of a nav menu item. |
225 * @return bool Whether the given ID is that of a nav menu item. |
241 if ( |
316 if ( |
242 $_possible_existing && |
317 $_possible_existing && |
243 ! is_wp_error( $_possible_existing ) && |
318 ! is_wp_error( $_possible_existing ) && |
244 isset( $_possible_existing->term_id ) && |
319 isset( $_possible_existing->term_id ) && |
245 $_possible_existing->term_id != $menu_id |
320 $_possible_existing->term_id != $menu_id |
246 ) |
321 ) { |
247 return new WP_Error( 'menu_exists', sprintf( __('The menu name <strong>%s</strong> conflicts with another menu name. Please try another.'), esc_html( $menu_data['menu-name'] ) ) ); |
322 return new WP_Error( 'menu_exists', |
|
323 /* translators: %s: menu name */ |
|
324 sprintf( __( 'The menu name %s conflicts with another menu name. Please try another.' ), |
|
325 '<strong>' . esc_html( $menu_data['menu-name'] ) . '</strong>' |
|
326 ) |
|
327 ); |
|
328 } |
248 |
329 |
249 // menu doesn't already exist, so create a new menu |
330 // menu doesn't already exist, so create a new menu |
250 if ( ! $_menu || is_wp_error( $_menu ) ) { |
331 if ( ! $_menu || is_wp_error( $_menu ) ) { |
251 $menu_exists = get_term_by( 'name', $menu_data['menu-name'], 'nav_menu' ); |
332 $menu_exists = get_term_by( 'name', $menu_data['menu-name'], 'nav_menu' ); |
252 |
333 |
253 if ( $menu_exists ) |
334 if ( $menu_exists ) { |
254 return new WP_Error( 'menu_exists', sprintf( __('The menu name <strong>%s</strong> conflicts with another menu name. Please try another.'), esc_html( $menu_data['menu-name'] ) ) ); |
335 return new WP_Error( 'menu_exists', |
|
336 /* translators: %s: menu name */ |
|
337 sprintf( __( 'The menu name %s conflicts with another menu name. Please try another.' ), |
|
338 '<strong>' . esc_html( $menu_data['menu-name'] ) . '</strong>' |
|
339 ) |
|
340 ); |
|
341 } |
255 |
342 |
256 $_menu = wp_insert_term( $menu_data['menu-name'], 'nav_menu', $args ); |
343 $_menu = wp_insert_term( $menu_data['menu-name'], 'nav_menu', $args ); |
257 |
344 |
258 if ( is_wp_error( $_menu ) ) |
345 if ( is_wp_error( $_menu ) ) |
259 return $_menu; |
346 return $_menu; |
520 * |
600 * |
521 * @param object $item The menu item to check. |
601 * @param object $item The menu item to check. |
522 * @return bool False if invalid, otherwise true. |
602 * @return bool False if invalid, otherwise true. |
523 */ |
603 */ |
524 function _is_valid_nav_menu_item( $item ) { |
604 function _is_valid_nav_menu_item( $item ) { |
525 if ( ! empty( $item->_invalid ) ) |
605 return empty( $item->_invalid ); |
526 return false; |
606 } |
527 |
607 |
528 return true; |
608 /** |
529 } |
609 * Retrieves all menu items of a navigation menu. |
530 |
610 * |
531 /** |
611 * Note: Most arguments passed to the `$args` parameter – save for 'output_key' – are |
532 * Return all menu items of a navigation menu. |
612 * specifically for retrieving nav_menu_item posts from get_posts() and may only |
533 * |
613 * indirectly affect the ultimate ordering and content of the resulting nav menu |
534 * @since 3.0.0 |
614 * items that get returned from this function. |
535 * |
615 * |
536 * @param string $menu Menu name, ID, or slug. |
616 * @since 3.0.0 |
537 * @param array $args Optional. Arguments to pass to {@see get_posts()}. |
617 * |
538 * @return mixed $items Array of menu items, otherwise false. |
618 * @global string $_menu_item_sort_prop |
|
619 * @staticvar array $fetched |
|
620 * |
|
621 * @param int|string|WP_Term $menu Menu ID, slug, name, or object. |
|
622 * @param array $args { |
|
623 * Optional. Arguments to pass to get_posts(). |
|
624 * |
|
625 * @type string $order How to order nav menu items as queried with get_posts(). Will be ignored |
|
626 * if 'output' is ARRAY_A. Default 'ASC'. |
|
627 * @type string $orderby Field to order menu items by as retrieved from get_posts(). Supply an orderby |
|
628 * field via 'output_key' to affect the output order of nav menu items. |
|
629 * Default 'menu_order'. |
|
630 * @type string $post_type Menu items post type. Default 'nav_menu_item'. |
|
631 * @type string $post_status Menu items post status. Default 'publish'. |
|
632 * @type string $output How to order outputted menu items. Default ARRAY_A. |
|
633 * @type string $output_key Key to use for ordering the actual menu items that get returned. Note that |
|
634 * that is not a get_posts() argument and will only affect output of menu items |
|
635 * processed in this function. Default 'menu_order'. |
|
636 * @type bool $nopaging Whether to retrieve all menu items (true) or paginate (false). Default true. |
|
637 * } |
|
638 * @return false|array $items Array of menu items, otherwise false. |
539 */ |
639 */ |
540 function wp_get_nav_menu_items( $menu, $args = array() ) { |
640 function wp_get_nav_menu_items( $menu, $args = array() ) { |
541 $menu = wp_get_nav_menu_object( $menu ); |
641 $menu = wp_get_nav_menu_object( $menu ); |
542 |
642 |
543 if ( ! $menu ) |
643 if ( ! $menu ) { |
544 return false; |
644 return false; |
|
645 } |
545 |
646 |
546 static $fetched = array(); |
647 static $fetched = array(); |
547 |
648 |
548 $items = get_objects_in_term( $menu->term_id, 'nav_menu' ); |
649 $items = get_objects_in_term( $menu->term_id, 'nav_menu' ); |
549 |
650 if ( is_wp_error( $items ) ) { |
550 if ( empty( $items ) ) |
651 return false; |
551 return $items; |
652 } |
552 |
653 |
553 $defaults = array( 'order' => 'ASC', 'orderby' => 'menu_order', 'post_type' => 'nav_menu_item', |
654 $defaults = array( 'order' => 'ASC', 'orderby' => 'menu_order', 'post_type' => 'nav_menu_item', |
554 'post_status' => 'publish', 'output' => ARRAY_A, 'output_key' => 'menu_order', 'nopaging' => true ); |
655 'post_status' => 'publish', 'output' => ARRAY_A, 'output_key' => 'menu_order', 'nopaging' => true ); |
555 $args = wp_parse_args( $args, $defaults ); |
656 $args = wp_parse_args( $args, $defaults ); |
556 $args['include'] = $items; |
657 $args['include'] = $items; |
557 |
658 |
558 $items = get_posts( $args ); |
659 if ( ! empty( $items ) ) { |
559 |
660 $items = get_posts( $args ); |
560 if ( is_wp_error( $items ) || ! is_array( $items ) ) |
661 } else { |
561 return false; |
662 $items = array(); |
|
663 } |
562 |
664 |
563 // Get all posts and terms at once to prime the caches |
665 // Get all posts and terms at once to prime the caches |
564 if ( empty( $fetched[$menu->term_id] ) || wp_using_ext_object_cache() ) { |
666 if ( empty( $fetched[ $menu->term_id ] ) && ! wp_using_ext_object_cache() ) { |
565 $fetched[$menu->term_id] = true; |
667 $fetched[$menu->term_id] = true; |
566 $posts = array(); |
668 $posts = array(); |
567 $terms = array(); |
669 $terms = array(); |
568 foreach ( $items as $item ) { |
670 foreach ( $items as $item ) { |
569 $object_id = get_post_meta( $item->ID, '_menu_item_object_id', true ); |
671 $object_id = get_post_meta( $item->ID, '_menu_item_object_id', true ); |
583 } |
685 } |
584 unset($posts); |
686 unset($posts); |
585 |
687 |
586 if ( ! empty( $terms ) ) { |
688 if ( ! empty( $terms ) ) { |
587 foreach ( array_keys($terms) as $taxonomy ) { |
689 foreach ( array_keys($terms) as $taxonomy ) { |
588 get_terms($taxonomy, array('include' => $terms[$taxonomy]) ); |
690 get_terms( $taxonomy, array( |
|
691 'include' => $terms[ $taxonomy ], |
|
692 'hierarchical' => false, |
|
693 ) ); |
589 } |
694 } |
590 } |
695 } |
591 unset($terms); |
696 unset($terms); |
592 } |
697 } |
593 |
698 |
594 $items = array_map( 'wp_setup_nav_menu_item', $items ); |
699 $items = array_map( 'wp_setup_nav_menu_item', $items ); |
595 |
700 |
596 if ( ! is_admin() ) // Remove invalid items only in frontend |
701 if ( ! is_admin() ) { // Remove invalid items only in front end |
597 $items = array_filter( $items, '_is_valid_nav_menu_item' ); |
702 $items = array_filter( $items, '_is_valid_nav_menu_item' ); |
|
703 } |
598 |
704 |
599 if ( ARRAY_A == $args['output'] ) { |
705 if ( ARRAY_A == $args['output'] ) { |
600 $GLOBALS['_menu_item_sort_prop'] = $args['output_key']; |
706 $items = wp_list_sort( $items, array( |
601 usort($items, '_sort_nav_menu_items'); |
707 $args['output_key'] => 'ASC', |
|
708 ) ); |
602 $i = 1; |
709 $i = 1; |
603 foreach( $items as $k => $item ) { |
710 foreach ( $items as $k => $item ) { |
604 $items[$k]->$args['output_key'] = $i++; |
711 $items[$k]->{$args['output_key']} = $i++; |
605 } |
712 } |
606 } |
713 } |
607 |
714 |
608 /** |
715 /** |
609 * Filter the navigation menu items being returned. |
716 * Filters the navigation menu items being returned. |
610 * |
717 * |
611 * @since 3.0.0 |
718 * @since 3.0.0 |
612 * |
719 * |
613 * @param array $items An array of menu item post objects. |
720 * @param array $items An array of menu item post objects. |
614 * @param object $menu The menu object. |
721 * @param object $menu The menu object. |
615 * @param array $args An array of arguments used to retrieve menu item objects. |
722 * @param array $args An array of arguments used to retrieve menu item objects. |
616 */ |
723 */ |
617 return apply_filters( 'wp_get_nav_menu_items', $items, $menu, $args ); |
724 return apply_filters( 'wp_get_nav_menu_items', $items, $menu, $args ); |
618 } |
725 } |
619 |
726 |
620 /** |
727 /** |
621 * Decorates a menu item object with the shared navigation menu item properties. |
728 * Decorates a menu item object with the shared navigation menu item properties. |
622 * |
729 * |
623 * Properties: |
730 * Properties: |
624 * - db_id: The DB ID of this item as a nav_menu_item object, if it exists (0 if it doesn't exist). |
731 * - ID: The term_id if the menu item represents a taxonomy term. |
625 * - object_id: The DB ID of the original object this menu item represents, e.g. ID for posts and term_id for categories. |
732 * - attr_title: The title attribute of the link element for this menu item. |
626 * - type: The family of objects originally represented, such as "post_type" or "taxonomy." |
733 * - classes: The array of class attribute values for the link element of this menu item. |
627 * - object: The type of object originally represented, such as "category," "post", or "attachment." |
734 * - db_id: The DB ID of this item as a nav_menu_item object, if it exists (0 if it doesn't exist). |
628 * - type_label: The singular label used to describe this type of menu item. |
735 * - description: The description of this menu item. |
629 * - post_parent: The DB ID of the original object's parent object, if any (0 otherwise). |
736 * - menu_item_parent: The DB ID of the nav_menu_item that is this item's menu parent, if any. 0 otherwise. |
630 * - menu_item_parent: The DB ID of the nav_menu_item that is this item's menu parent, if any. 0 otherwise. |
737 * - object: The type of object originally represented, such as "category," "post", or "attachment." |
631 * - url: The URL to which this menu item points. |
738 * - object_id: The DB ID of the original object this menu item represents, e.g. ID for posts and term_id for categories. |
632 * - title: The title of this menu item. |
739 * - post_parent: The DB ID of the original object's parent object, if any (0 otherwise). |
633 * - target: The target attribute of the link element for this menu item. |
740 * - post_title: A "no title" label if menu item represents a post that lacks a title. |
634 * - attr_title: The title attribute of the link element for this menu item. |
741 * - target: The target attribute of the link element for this menu item. |
635 * - classes: The array of class attribute values for the link element of this menu item. |
742 * - title: The title of this menu item. |
636 * - xfn: The XFN relationship expressed in the link of this menu item. |
743 * - type: The family of objects originally represented, such as "post_type" or "taxonomy." |
637 * - description: The description of this menu item. |
744 * - type_label: The singular label used to describe this type of menu item. |
|
745 * - url: The URL to which this menu item points. |
|
746 * - xfn: The XFN relationship expressed in the link of this menu item. |
|
747 * - _invalid: Whether the menu item represents an object that no longer exists. |
638 * |
748 * |
639 * @since 3.0.0 |
749 * @since 3.0.0 |
640 * |
750 * |
641 * @param object $menu_item The menu item to modify. |
751 * @param object $menu_item The menu item to modify. |
642 * @return object $menu_item The menu item with standard menu item properties. |
752 * @return object $menu_item The menu item with standard menu item properties. |
643 */ |
753 */ |
644 function wp_setup_nav_menu_item( $menu_item ) { |
754 function wp_setup_nav_menu_item( $menu_item ) { |
645 if ( isset( $menu_item->post_type ) ) { |
755 if ( isset( $menu_item->post_type ) ) { |
646 if ( 'nav_menu_item' == $menu_item->post_type ) { |
756 if ( 'nav_menu_item' == $menu_item->post_type ) { |
647 $menu_item->db_id = (int) $menu_item->ID; |
757 $menu_item->db_id = (int) $menu_item->ID; |
648 $menu_item->menu_item_parent = empty( $menu_item->menu_item_parent ) ? get_post_meta( $menu_item->ID, '_menu_item_menu_item_parent', true ) : $menu_item->menu_item_parent; |
758 $menu_item->menu_item_parent = ! isset( $menu_item->menu_item_parent ) ? get_post_meta( $menu_item->ID, '_menu_item_menu_item_parent', true ) : $menu_item->menu_item_parent; |
649 $menu_item->object_id = empty( $menu_item->object_id ) ? get_post_meta( $menu_item->ID, '_menu_item_object_id', true ) : $menu_item->object_id; |
759 $menu_item->object_id = ! isset( $menu_item->object_id ) ? get_post_meta( $menu_item->ID, '_menu_item_object_id', true ) : $menu_item->object_id; |
650 $menu_item->object = empty( $menu_item->object ) ? get_post_meta( $menu_item->ID, '_menu_item_object', true ) : $menu_item->object; |
760 $menu_item->object = ! isset( $menu_item->object ) ? get_post_meta( $menu_item->ID, '_menu_item_object', true ) : $menu_item->object; |
651 $menu_item->type = empty( $menu_item->type ) ? get_post_meta( $menu_item->ID, '_menu_item_type', true ) : $menu_item->type; |
761 $menu_item->type = ! isset( $menu_item->type ) ? get_post_meta( $menu_item->ID, '_menu_item_type', true ) : $menu_item->type; |
652 |
762 |
653 if ( 'post_type' == $menu_item->type ) { |
763 if ( 'post_type' == $menu_item->type ) { |
654 $object = get_post_type_object( $menu_item->object ); |
764 $object = get_post_type_object( $menu_item->object ); |
655 if ( $object ) { |
765 if ( $object ) { |
656 $menu_item->type_label = $object->labels->singular_name; |
766 $menu_item->type_label = $object->labels->singular_name; |
657 } else { |
767 } else { |
658 $menu_item->type_label = $menu_item->object; |
768 $menu_item->type_label = $menu_item->object; |
659 $menu_item->_invalid = true; |
769 $menu_item->_invalid = true; |
660 } |
770 } |
661 |
771 |
|
772 if ( 'trash' === get_post_status( $menu_item->object_id ) ) { |
|
773 $menu_item->_invalid = true; |
|
774 } |
|
775 |
662 $menu_item->url = get_permalink( $menu_item->object_id ); |
776 $menu_item->url = get_permalink( $menu_item->object_id ); |
663 |
777 |
664 $original_object = get_post( $menu_item->object_id ); |
778 $original_object = get_post( $menu_item->object_id ); |
665 $original_title = $original_object->post_title; |
779 /** This filter is documented in wp-includes/post-template.php */ |
|
780 $original_title = apply_filters( 'the_title', $original_object->post_title, $original_object->ID ); |
666 |
781 |
667 if ( '' === $original_title ) { |
782 if ( '' === $original_title ) { |
|
783 /* translators: %d: ID of a post */ |
668 $original_title = sprintf( __( '#%d (no title)' ), $original_object->ID ); |
784 $original_title = sprintf( __( '#%d (no title)' ), $original_object->ID ); |
669 } |
785 } |
670 |
786 |
671 $menu_item->title = '' == $menu_item->post_title ? $original_title : $menu_item->post_title; |
787 $menu_item->title = '' == $menu_item->post_title ? $original_title : $menu_item->post_title; |
672 |
788 |
|
789 } elseif ( 'post_type_archive' == $menu_item->type ) { |
|
790 $object = get_post_type_object( $menu_item->object ); |
|
791 if ( $object ) { |
|
792 $menu_item->title = '' == $menu_item->post_title ? $object->labels->archives : $menu_item->post_title; |
|
793 $post_type_description = $object->description; |
|
794 } else { |
|
795 $menu_item->_invalid = true; |
|
796 $post_type_description = ''; |
|
797 } |
|
798 |
|
799 $menu_item->type_label = __( 'Post Type Archive' ); |
|
800 $post_content = wp_trim_words( $menu_item->post_content, 200 ); |
|
801 $post_type_description = '' == $post_content ? $post_type_description : $post_content; |
|
802 $menu_item->url = get_post_type_archive_link( $menu_item->object ); |
673 } elseif ( 'taxonomy' == $menu_item->type ) { |
803 } elseif ( 'taxonomy' == $menu_item->type ) { |
674 $object = get_taxonomy( $menu_item->object ); |
804 $object = get_taxonomy( $menu_item->object ); |
675 if ( $object ) { |
805 if ( $object ) { |
676 $menu_item->type_label = $object->labels->singular_name; |
806 $menu_item->type_label = $object->labels->singular_name; |
677 } else { |
807 } else { |
688 $menu_item->title = '' == $menu_item->post_title ? $original_title : $menu_item->post_title; |
818 $menu_item->title = '' == $menu_item->post_title ? $original_title : $menu_item->post_title; |
689 |
819 |
690 } else { |
820 } else { |
691 $menu_item->type_label = __('Custom Link'); |
821 $menu_item->type_label = __('Custom Link'); |
692 $menu_item->title = $menu_item->post_title; |
822 $menu_item->title = $menu_item->post_title; |
693 $menu_item->url = empty( $menu_item->url ) ? get_post_meta( $menu_item->ID, '_menu_item_url', true ) : $menu_item->url; |
823 $menu_item->url = ! isset( $menu_item->url ) ? get_post_meta( $menu_item->ID, '_menu_item_url', true ) : $menu_item->url; |
694 } |
824 } |
695 |
825 |
696 $menu_item->target = empty( $menu_item->target ) ? get_post_meta( $menu_item->ID, '_menu_item_target', true ) : $menu_item->target; |
826 $menu_item->target = ! isset( $menu_item->target ) ? get_post_meta( $menu_item->ID, '_menu_item_target', true ) : $menu_item->target; |
697 |
827 |
698 /** |
828 /** |
699 * Filter a navigation menu item's title attribute. |
829 * Filters a navigation menu item's title attribute. |
700 * |
830 * |
701 * @since 3.0.0 |
831 * @since 3.0.0 |
702 * |
832 * |
703 * @param string $item_title The menu item title attribute. |
833 * @param string $item_title The menu item title attribute. |
704 */ |
834 */ |
705 $menu_item->attr_title = empty( $menu_item->attr_title ) ? apply_filters( 'nav_menu_attr_title', $menu_item->post_excerpt ) : $menu_item->attr_title; |
835 $menu_item->attr_title = ! isset( $menu_item->attr_title ) ? apply_filters( 'nav_menu_attr_title', $menu_item->post_excerpt ) : $menu_item->attr_title; |
706 |
836 |
707 if ( empty( $menu_item->description ) ) { |
837 if ( ! isset( $menu_item->description ) ) { |
708 /** |
838 /** |
709 * Filter a navigation menu item's description. |
839 * Filters a navigation menu item's description. |
710 * |
840 * |
711 * @since 3.0.0 |
841 * @since 3.0.0 |
712 * |
842 * |
713 * @param string $description The menu item description. |
843 * @param string $description The menu item description. |
714 */ |
844 */ |
715 $menu_item->description = apply_filters( 'nav_menu_description', wp_trim_words( $menu_item->post_content, 200 ) ); |
845 $menu_item->description = apply_filters( 'nav_menu_description', wp_trim_words( $menu_item->post_content, 200 ) ); |
716 } |
846 } |
717 |
847 |
718 $menu_item->classes = empty( $menu_item->classes ) ? (array) get_post_meta( $menu_item->ID, '_menu_item_classes', true ) : $menu_item->classes; |
848 $menu_item->classes = ! isset( $menu_item->classes ) ? (array) get_post_meta( $menu_item->ID, '_menu_item_classes', true ) : $menu_item->classes; |
719 $menu_item->xfn = empty( $menu_item->xfn ) ? get_post_meta( $menu_item->ID, '_menu_item_xfn', true ) : $menu_item->xfn; |
849 $menu_item->xfn = ! isset( $menu_item->xfn ) ? get_post_meta( $menu_item->ID, '_menu_item_xfn', true ) : $menu_item->xfn; |
720 } else { |
850 } else { |
721 $menu_item->db_id = 0; |
851 $menu_item->db_id = 0; |
722 $menu_item->menu_item_parent = 0; |
852 $menu_item->menu_item_parent = 0; |
723 $menu_item->object_id = (int) $menu_item->ID; |
853 $menu_item->object_id = (int) $menu_item->ID; |
724 $menu_item->type = 'post_type'; |
854 $menu_item->type = 'post_type'; |
725 |
855 |
726 $object = get_post_type_object( $menu_item->post_type ); |
856 $object = get_post_type_object( $menu_item->post_type ); |
727 $menu_item->object = $object->name; |
857 $menu_item->object = $object->name; |
728 $menu_item->type_label = $object->labels->singular_name; |
858 $menu_item->type_label = $object->labels->singular_name; |
729 |
859 |
730 if ( '' === $menu_item->post_title ) |
860 if ( '' === $menu_item->post_title ) { |
|
861 /* translators: %d: ID of a post */ |
731 $menu_item->post_title = sprintf( __( '#%d (no title)' ), $menu_item->ID ); |
862 $menu_item->post_title = sprintf( __( '#%d (no title)' ), $menu_item->ID ); |
|
863 } |
732 |
864 |
733 $menu_item->title = $menu_item->post_title; |
865 $menu_item->title = $menu_item->post_title; |
734 $menu_item->url = get_permalink( $menu_item->ID ); |
866 $menu_item->url = get_permalink( $menu_item->ID ); |
735 $menu_item->target = ''; |
867 $menu_item->target = ''; |
736 |
868 |
896 continue 2; |
1028 continue 2; |
897 } |
1029 } |
898 wp_update_nav_menu_item( $menu_id, 0, $args ); |
1030 wp_update_nav_menu_item( $menu_id, 0, $args ); |
899 } |
1031 } |
900 } |
1032 } |
|
1033 |
|
1034 /** |
|
1035 * Delete auto-draft posts associated with the supplied changeset. |
|
1036 * |
|
1037 * @since 4.8.0 |
|
1038 * @access private |
|
1039 * |
|
1040 * @param int $post_id Post ID for the customize_changeset. |
|
1041 */ |
|
1042 function _wp_delete_customize_changeset_dependent_auto_drafts( $post_id ) { |
|
1043 $post = get_post( $post_id ); |
|
1044 |
|
1045 if ( ! $post || 'customize_changeset' !== $post->post_type ) { |
|
1046 return; |
|
1047 } |
|
1048 |
|
1049 $data = json_decode( $post->post_content, true ); |
|
1050 if ( empty( $data['nav_menus_created_posts']['value'] ) ) { |
|
1051 return; |
|
1052 } |
|
1053 remove_action( 'delete_post', '_wp_delete_customize_changeset_dependent_auto_drafts' ); |
|
1054 foreach ( $data['nav_menus_created_posts']['value'] as $stub_post_id ) { |
|
1055 if ( empty( $stub_post_id ) ) { |
|
1056 continue; |
|
1057 } |
|
1058 if ( 'auto-draft' === get_post_status( $stub_post_id ) ) { |
|
1059 wp_delete_post( $stub_post_id, true ); |
|
1060 } elseif ( 'draft' === get_post_status( $stub_post_id ) ) { |
|
1061 wp_trash_post( $stub_post_id ); |
|
1062 delete_post_meta( $stub_post_id, '_customize_changeset_uuid' ); |
|
1063 } |
|
1064 } |
|
1065 add_action( 'delete_post', '_wp_delete_customize_changeset_dependent_auto_drafts' ); |
|
1066 } |
|
1067 |
|
1068 /** |
|
1069 * Handle menu config after theme change. |
|
1070 * |
|
1071 * @access private |
|
1072 * @since 4.9.0 |
|
1073 */ |
|
1074 function _wp_menus_changed() { |
|
1075 $old_nav_menu_locations = get_option( 'theme_switch_menu_locations', array() ); |
|
1076 $new_nav_menu_locations = get_nav_menu_locations(); |
|
1077 $mapped_nav_menu_locations = wp_map_nav_menu_locations( $new_nav_menu_locations, $old_nav_menu_locations ); |
|
1078 |
|
1079 set_theme_mod( 'nav_menu_locations', $mapped_nav_menu_locations ); |
|
1080 delete_option( 'theme_switch_menu_locations' ); |
|
1081 } |
|
1082 |
|
1083 /** |
|
1084 * Maps nav menu locations according to assignments in previously active theme. |
|
1085 * |
|
1086 * @since 4.9.0 |
|
1087 * |
|
1088 * @param array $new_nav_menu_locations New nav menu locations assignments. |
|
1089 * @param array $old_nav_menu_locations Old nav menu locations assignments. |
|
1090 * @return array Nav menus mapped to new nav menu locations. |
|
1091 */ |
|
1092 function wp_map_nav_menu_locations( $new_nav_menu_locations, $old_nav_menu_locations ) { |
|
1093 $registered_nav_menus = get_registered_nav_menus(); |
|
1094 $new_nav_menu_locations = array_intersect_key( $new_nav_menu_locations, $registered_nav_menus ); |
|
1095 |
|
1096 // Short-circuit if there are no old nav menu location assignments to map. |
|
1097 if ( empty( $old_nav_menu_locations ) ) { |
|
1098 return $new_nav_menu_locations; |
|
1099 } |
|
1100 |
|
1101 // If old and new theme have just one location, map it and we're done. |
|
1102 if ( 1 === count( $old_nav_menu_locations ) && 1 === count( $registered_nav_menus ) ) { |
|
1103 $new_nav_menu_locations[ key( $registered_nav_menus ) ] = array_pop( $old_nav_menu_locations ); |
|
1104 return $new_nav_menu_locations; |
|
1105 } |
|
1106 |
|
1107 $old_locations = array_keys( $old_nav_menu_locations ); |
|
1108 |
|
1109 // Map locations with the same slug. |
|
1110 foreach ( $registered_nav_menus as $location => $name ) { |
|
1111 if ( in_array( $location, $old_locations, true ) ) { |
|
1112 $new_nav_menu_locations[ $location ] = $old_nav_menu_locations[ $location ]; |
|
1113 unset( $old_nav_menu_locations[ $location ] ); |
|
1114 } |
|
1115 } |
|
1116 |
|
1117 // If there are no old nav menu locations left, then we're done. |
|
1118 if ( empty( $old_nav_menu_locations ) ) { |
|
1119 return $new_nav_menu_locations; |
|
1120 } |
|
1121 |
|
1122 /* |
|
1123 * If old and new theme both have locations that contain phrases |
|
1124 * from within the same group, make an educated guess and map it. |
|
1125 */ |
|
1126 $common_slug_groups = array( |
|
1127 array( 'primary', 'menu-1', 'main', 'header', 'navigation', 'top' ), |
|
1128 array( 'secondary', 'menu-2', 'footer', 'subsidiary', 'bottom' ), |
|
1129 array( 'social' ), |
|
1130 ); |
|
1131 |
|
1132 // Go through each group... |
|
1133 foreach ( $common_slug_groups as $slug_group ) { |
|
1134 |
|
1135 // ...and see if any of these slugs... |
|
1136 foreach ( $slug_group as $slug ) { |
|
1137 |
|
1138 // ...and any of the new menu locations... |
|
1139 foreach ( $registered_nav_menus as $new_location => $name ) { |
|
1140 |
|
1141 // ...actually match! |
|
1142 if ( false === stripos( $new_location, $slug ) && false === stripos( $slug, $new_location ) ) { |
|
1143 continue; |
|
1144 } |
|
1145 |
|
1146 // Then see if any of the old locations... |
|
1147 foreach ( $old_nav_menu_locations as $location => $menu_id ) { |
|
1148 |
|
1149 // ...and any slug in the same group... |
|
1150 foreach ( $slug_group as $slug ) { |
|
1151 |
|
1152 // ... have a match as well. |
|
1153 if ( false === stripos( $location, $slug ) && false === stripos( $slug, $location ) ) { |
|
1154 continue; |
|
1155 } |
|
1156 |
|
1157 // Make sure this location wasn't mapped and removed previously. |
|
1158 if ( ! empty( $old_nav_menu_locations[ $location ] ) ) { |
|
1159 |
|
1160 // We have a match that can be mapped! |
|
1161 $new_nav_menu_locations[ $new_location ] = $old_nav_menu_locations[ $location ]; |
|
1162 |
|
1163 // Remove the mapped location so it can't be mapped again. |
|
1164 unset( $old_nav_menu_locations[ $location ] ); |
|
1165 |
|
1166 // Go back and check the next new menu location. |
|
1167 continue 3; |
|
1168 } |
|
1169 } // endforeach ( $slug_group as $slug ) |
|
1170 } // endforeach ( $old_nav_menu_locations as $location => $menu_id ) |
|
1171 } // endforeach foreach ( $registered_nav_menus as $new_location => $name ) |
|
1172 } // endforeach ( $slug_group as $slug ) |
|
1173 } // endforeach ( $common_slug_groups as $slug_group ) |
|
1174 |
|
1175 return $new_nav_menu_locations; |
|
1176 } |