1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Navigation Menu functions |
4
|
|
|
* |
5
|
|
|
* @package WordPress |
6
|
|
|
* @subpackage Nav_Menus |
7
|
|
|
* @since 3.0.0 |
8
|
|
|
*/ |
9
|
|
|
|
10
|
|
|
/** |
11
|
|
|
* Returns a navigation menu object. |
12
|
|
|
* |
13
|
|
|
* @since 3.0.0 |
14
|
|
|
* |
15
|
|
|
* @param string $menu Menu ID, slug, or name - or the menu object. |
16
|
|
|
* @return object|false False if $menu param isn't supplied or term does not exist, menu object if successful. |
17
|
|
|
*/ |
18
|
|
|
function wp_get_nav_menu_object( $menu ) { |
19
|
|
|
$menu_obj = false; |
20
|
|
|
|
21
|
|
|
if ( is_object( $menu ) ) { |
22
|
|
|
$menu_obj = $menu; |
23
|
|
|
} |
24
|
|
|
|
25
|
|
|
if ( $menu && ! $menu_obj ) { |
26
|
|
|
$menu_obj = get_term( $menu, 'nav_menu' ); |
27
|
|
|
|
28
|
|
|
if ( ! $menu_obj ) { |
29
|
|
|
$menu_obj = get_term_by( 'slug', $menu, 'nav_menu' ); |
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 ) ) { |
38
|
|
|
$menu_obj = false; |
39
|
|
|
} |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* Filters the nav_menu term retrieved for wp_get_nav_menu_object(). |
43
|
|
|
* |
44
|
|
|
* @since 4.3.0 |
45
|
|
|
* |
46
|
|
|
* @param object|false $menu_obj Term from nav_menu taxonomy, or false if nothing had been found. |
47
|
|
|
* @param string $menu The menu ID, slug, or name passed to wp_get_nav_menu_object(). |
48
|
|
|
*/ |
49
|
|
|
return apply_filters( 'wp_get_nav_menu_object', $menu_obj, $menu ); |
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* Check if the given ID is a navigation menu. |
54
|
|
|
* |
55
|
|
|
* Returns true if it is; false otherwise. |
56
|
|
|
* |
57
|
|
|
* @since 3.0.0 |
58
|
|
|
* |
59
|
|
|
* @param int|string $menu The menu to check (ID, slug, or name). |
60
|
|
|
* @return bool Whether the menu exists. |
61
|
|
|
*/ |
62
|
|
|
function is_nav_menu( $menu ) { |
63
|
|
|
if ( ! $menu ) |
64
|
|
|
return false; |
65
|
|
|
|
66
|
|
|
$menu_obj = wp_get_nav_menu_object( $menu ); |
67
|
|
|
|
68
|
|
|
if ( |
69
|
|
|
$menu_obj && |
70
|
|
|
! is_wp_error( $menu_obj ) && |
71
|
|
|
! empty( $menu_obj->taxonomy ) && |
72
|
|
|
'nav_menu' == $menu_obj->taxonomy |
73
|
|
|
) |
74
|
|
|
return true; |
75
|
|
|
|
76
|
|
|
return false; |
77
|
|
|
} |
78
|
|
|
|
79
|
|
|
/** |
80
|
|
|
* Registers navigation menu locations for a theme. |
81
|
|
|
* |
82
|
|
|
* @since 3.0.0 |
83
|
|
|
* |
84
|
|
|
* @global array $_wp_registered_nav_menus |
85
|
|
|
* |
86
|
|
|
* @param array $locations Associative array of menu location identifiers (like a slug) and descriptive text. |
87
|
|
|
*/ |
88
|
|
|
function register_nav_menus( $locations = array() ) { |
89
|
|
|
global $_wp_registered_nav_menus; |
90
|
|
|
|
91
|
|
|
add_theme_support( 'menus' ); |
92
|
|
|
|
93
|
|
|
$_wp_registered_nav_menus = array_merge( (array) $_wp_registered_nav_menus, $locations ); |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
/** |
97
|
|
|
* Unregisters a navigation menu location for a theme. |
98
|
|
|
* |
99
|
|
|
* @global array $_wp_registered_nav_menus |
100
|
|
|
* |
101
|
|
|
* @param string $location The menu location identifier. |
102
|
|
|
* @return bool True on success, false on failure. |
103
|
|
|
*/ |
104
|
|
|
function unregister_nav_menu( $location ) { |
105
|
|
|
global $_wp_registered_nav_menus; |
106
|
|
|
|
107
|
|
|
if ( is_array( $_wp_registered_nav_menus ) && isset( $_wp_registered_nav_menus[$location] ) ) { |
108
|
|
|
unset( $_wp_registered_nav_menus[$location] ); |
109
|
|
|
if ( empty( $_wp_registered_nav_menus ) ) { |
110
|
|
|
_remove_theme_support( 'menus' ); |
111
|
|
|
} |
112
|
|
|
return true; |
113
|
|
|
} |
114
|
|
|
return false; |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
/** |
118
|
|
|
* Registers a navigation menu location for a theme. |
119
|
|
|
* |
120
|
|
|
* @since 3.0.0 |
121
|
|
|
* |
122
|
|
|
* @param string $location Menu location identifier, like a slug. |
123
|
|
|
* @param string $description Menu location descriptive text. |
124
|
|
|
*/ |
125
|
|
|
function register_nav_menu( $location, $description ) { |
126
|
|
|
register_nav_menus( array( $location => $description ) ); |
127
|
|
|
} |
128
|
|
|
/** |
129
|
|
|
* Retrieves all registered navigation menu locations in a theme. |
130
|
|
|
* |
131
|
|
|
* @since 3.0.0 |
132
|
|
|
* |
133
|
|
|
* @global array $_wp_registered_nav_menus |
134
|
|
|
* |
135
|
|
|
* @return array Registered navigation menu locations. If none are registered, an empty array. |
136
|
|
|
*/ |
137
|
|
|
function get_registered_nav_menus() { |
138
|
|
|
global $_wp_registered_nav_menus; |
139
|
|
|
if ( isset( $_wp_registered_nav_menus ) ) |
140
|
|
|
return $_wp_registered_nav_menus; |
141
|
|
|
return array(); |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
/** |
145
|
|
|
* Retrieves all registered navigation menu locations and the menus assigned to them. |
146
|
|
|
* |
147
|
|
|
* @since 3.0.0 |
148
|
|
|
* |
149
|
|
|
* @return array Registered navigation menu locations and the menus assigned them. |
150
|
|
|
* If none are registered, an empty array. |
151
|
|
|
*/ |
152
|
|
|
|
153
|
|
|
function get_nav_menu_locations() { |
154
|
|
|
$locations = get_theme_mod( 'nav_menu_locations' ); |
155
|
|
|
return ( is_array( $locations ) ) ? $locations : array(); |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
/** |
159
|
|
|
* Determines whether a registered nav menu location has a menu assigned to it. |
160
|
|
|
* |
161
|
|
|
* @since 3.0.0 |
162
|
|
|
* |
163
|
|
|
* @param string $location Menu location identifier. |
164
|
|
|
* @return bool Whether location has a menu. |
165
|
|
|
*/ |
166
|
|
|
function has_nav_menu( $location ) { |
167
|
|
|
$has_nav_menu = false; |
168
|
|
|
|
169
|
|
|
$registered_nav_menus = get_registered_nav_menus(); |
170
|
|
|
if ( isset( $registered_nav_menus[ $location ] ) ) { |
171
|
|
|
$locations = get_nav_menu_locations(); |
172
|
|
|
$has_nav_menu = ! empty( $locations[ $location ] ); |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
/** |
176
|
|
|
* Filters whether a nav menu is assigned to the specified location. |
177
|
|
|
* |
178
|
|
|
* @since 4.3.0 |
179
|
|
|
* |
180
|
|
|
* @param bool $has_nav_menu Whether there is a menu assigned to a location. |
181
|
|
|
* @param string $location Menu location. |
182
|
|
|
*/ |
183
|
|
|
return apply_filters( 'has_nav_menu', $has_nav_menu, $location ); |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
/** |
187
|
|
|
* Determines whether the given ID is a nav menu item. |
188
|
|
|
* |
189
|
|
|
* @since 3.0.0 |
190
|
|
|
* |
191
|
|
|
* @param int $menu_item_id The ID of the potential nav menu item. |
192
|
|
|
* @return bool Whether the given ID is that of a nav menu item. |
193
|
|
|
*/ |
194
|
|
|
function is_nav_menu_item( $menu_item_id = 0 ) { |
195
|
|
|
return ( ! is_wp_error( $menu_item_id ) && ( 'nav_menu_item' == get_post_type( $menu_item_id ) ) ); |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
/** |
199
|
|
|
* Creates a navigation menu. |
200
|
|
|
* |
201
|
|
|
* Note that `$menu_name` is expected to be pre-slashed. |
202
|
|
|
* |
203
|
|
|
* @since 3.0.0 |
204
|
|
|
* |
205
|
|
|
* @param string $menu_name Menu name. |
206
|
|
|
* @return int|WP_Error Menu ID on success, WP_Error object on failure. |
207
|
|
|
*/ |
208
|
|
|
function wp_create_nav_menu( $menu_name ) { |
209
|
|
|
// expected_slashed ($menu_name) |
210
|
|
|
return wp_update_nav_menu_object( 0, array( 'menu-name' => $menu_name ) ); |
211
|
|
|
} |
212
|
|
|
|
213
|
|
|
/** |
214
|
|
|
* Delete a Navigation Menu. |
215
|
|
|
* |
216
|
|
|
* @since 3.0.0 |
217
|
|
|
* |
218
|
|
|
* @param string $menu Menu ID, slug, or name. |
219
|
|
|
* @return bool|WP_Error True on success, false or WP_Error object on failure. |
220
|
|
|
*/ |
221
|
|
|
function wp_delete_nav_menu( $menu ) { |
222
|
|
|
$menu = wp_get_nav_menu_object( $menu ); |
223
|
|
|
if ( ! $menu ) |
224
|
|
|
return false; |
225
|
|
|
|
226
|
|
|
$menu_objects = get_objects_in_term( $menu->term_id, 'nav_menu' ); |
227
|
|
|
if ( ! empty( $menu_objects ) ) { |
228
|
|
|
foreach ( $menu_objects as $item ) { |
|
|
|
|
229
|
|
|
wp_delete_post( $item ); |
230
|
|
|
} |
231
|
|
|
} |
232
|
|
|
|
233
|
|
|
$result = wp_delete_term( $menu->term_id, 'nav_menu' ); |
234
|
|
|
|
235
|
|
|
// Remove this menu from any locations. |
236
|
|
|
$locations = get_nav_menu_locations(); |
237
|
|
|
foreach ( $locations as $location => $menu_id ) { |
238
|
|
|
if ( $menu_id == $menu->term_id ) |
239
|
|
|
$locations[ $location ] = 0; |
240
|
|
|
} |
241
|
|
|
set_theme_mod( 'nav_menu_locations', $locations ); |
242
|
|
|
|
243
|
|
|
if ( $result && !is_wp_error($result) ) |
244
|
|
|
|
245
|
|
|
/** |
246
|
|
|
* Fires after a navigation menu has been successfully deleted. |
247
|
|
|
* |
248
|
|
|
* @since 3.0.0 |
249
|
|
|
* |
250
|
|
|
* @param int $term_id ID of the deleted menu. |
251
|
|
|
*/ |
252
|
|
|
do_action( 'wp_delete_nav_menu', $menu->term_id ); |
253
|
|
|
|
254
|
|
|
return $result; |
255
|
|
|
} |
256
|
|
|
|
257
|
|
|
/** |
258
|
|
|
* Save the properties of a menu or create a new menu with those properties. |
259
|
|
|
* |
260
|
|
|
* Note that `$menu_data` is expected to be pre-slashed. |
261
|
|
|
* |
262
|
|
|
* @since 3.0.0 |
263
|
|
|
* |
264
|
|
|
* @param int $menu_id The ID of the menu or "0" to create a new menu. |
265
|
|
|
* @param array $menu_data The array of menu data. |
266
|
|
|
* @return int|WP_Error Menu ID on success, WP_Error object on failure. |
267
|
|
|
*/ |
268
|
|
|
function wp_update_nav_menu_object( $menu_id = 0, $menu_data = array() ) { |
269
|
|
|
// expected_slashed ($menu_data) |
270
|
|
|
$menu_id = (int) $menu_id; |
271
|
|
|
|
272
|
|
|
$_menu = wp_get_nav_menu_object( $menu_id ); |
273
|
|
|
|
274
|
|
|
$args = array( |
275
|
|
|
'description' => ( isset( $menu_data['description'] ) ? $menu_data['description'] : '' ), |
276
|
|
|
'name' => ( isset( $menu_data['menu-name'] ) ? $menu_data['menu-name'] : '' ), |
277
|
|
|
'parent' => ( isset( $menu_data['parent'] ) ? (int) $menu_data['parent'] : 0 ), |
278
|
|
|
'slug' => null, |
279
|
|
|
); |
280
|
|
|
|
281
|
|
|
// double-check that we're not going to have one menu take the name of another |
282
|
|
|
$_possible_existing = get_term_by( 'name', $menu_data['menu-name'], 'nav_menu' ); |
283
|
|
|
if ( |
284
|
|
|
$_possible_existing && |
285
|
|
|
! is_wp_error( $_possible_existing ) && |
286
|
|
|
isset( $_possible_existing->term_id ) && |
287
|
|
|
$_possible_existing->term_id != $menu_id |
288
|
|
|
) { |
289
|
|
|
return new WP_Error( 'menu_exists', |
290
|
|
|
/* translators: %s: menu name */ |
291
|
|
|
sprintf( __( 'The menu name %s conflicts with another menu name. Please try another.' ), |
292
|
|
|
'<strong>' . esc_html( $menu_data['menu-name'] ) . '</strong>' |
293
|
|
|
) |
294
|
|
|
); |
295
|
|
|
} |
296
|
|
|
|
297
|
|
|
// menu doesn't already exist, so create a new menu |
298
|
|
|
if ( ! $_menu || is_wp_error( $_menu ) ) { |
299
|
|
|
$menu_exists = get_term_by( 'name', $menu_data['menu-name'], 'nav_menu' ); |
300
|
|
|
|
301
|
|
|
if ( $menu_exists ) { |
302
|
|
|
return new WP_Error( 'menu_exists', |
303
|
|
|
/* translators: %s: menu name */ |
304
|
|
|
sprintf( __( 'The menu name %s conflicts with another menu name. Please try another.' ), |
305
|
|
|
'<strong>' . esc_html( $menu_data['menu-name'] ) . '</strong>' |
306
|
|
|
) |
307
|
|
|
); |
308
|
|
|
} |
309
|
|
|
|
310
|
|
|
$_menu = wp_insert_term( $menu_data['menu-name'], 'nav_menu', $args ); |
311
|
|
|
|
312
|
|
|
if ( is_wp_error( $_menu ) ) |
313
|
|
|
return $_menu; |
314
|
|
|
|
315
|
|
|
/** |
316
|
|
|
* Fires after a navigation menu is successfully created. |
317
|
|
|
* |
318
|
|
|
* @since 3.0.0 |
319
|
|
|
* |
320
|
|
|
* @param int $term_id ID of the new menu. |
321
|
|
|
* @param array $menu_data An array of menu data. |
322
|
|
|
*/ |
323
|
|
|
do_action( 'wp_create_nav_menu', $_menu['term_id'], $menu_data ); |
324
|
|
|
|
325
|
|
|
return (int) $_menu['term_id']; |
326
|
|
|
} |
327
|
|
|
|
328
|
|
|
if ( ! $_menu || ! isset( $_menu->term_id ) ) |
329
|
|
|
return 0; |
330
|
|
|
|
331
|
|
|
$menu_id = (int) $_menu->term_id; |
332
|
|
|
|
333
|
|
|
$update_response = wp_update_term( $menu_id, 'nav_menu', $args ); |
334
|
|
|
|
335
|
|
|
if ( is_wp_error( $update_response ) ) |
336
|
|
|
return $update_response; |
337
|
|
|
|
338
|
|
|
$menu_id = (int) $update_response['term_id']; |
339
|
|
|
|
340
|
|
|
/** |
341
|
|
|
* Fires after a navigation menu has been successfully updated. |
342
|
|
|
* |
343
|
|
|
* @since 3.0.0 |
344
|
|
|
* |
345
|
|
|
* @param int $menu_id ID of the updated menu. |
346
|
|
|
* @param array $menu_data An array of menu data. |
347
|
|
|
*/ |
348
|
|
|
do_action( 'wp_update_nav_menu', $menu_id, $menu_data ); |
349
|
|
|
return $menu_id; |
350
|
|
|
} |
351
|
|
|
|
352
|
|
|
/** |
353
|
|
|
* Save the properties of a menu item or create a new one. |
354
|
|
|
* |
355
|
|
|
* The menu-item-title, menu-item-description, and menu-item-attr-title are expected |
356
|
|
|
* to be pre-slashed since they are passed directly into `wp_insert_post()`. |
357
|
|
|
* |
358
|
|
|
* @since 3.0.0 |
359
|
|
|
* |
360
|
|
|
* @param int $menu_id The ID of the menu. Required. If "0", makes the menu item a draft orphan. |
361
|
|
|
* @param int $menu_item_db_id The ID of the menu item. If "0", creates a new menu item. |
362
|
|
|
* @param array $menu_item_data The menu item's data. |
363
|
|
|
* @return int|WP_Error The menu item's database ID or WP_Error object on failure. |
364
|
|
|
*/ |
365
|
|
|
function wp_update_nav_menu_item( $menu_id = 0, $menu_item_db_id = 0, $menu_item_data = array() ) { |
366
|
|
|
$menu_id = (int) $menu_id; |
367
|
|
|
$menu_item_db_id = (int) $menu_item_db_id; |
368
|
|
|
|
369
|
|
|
// make sure that we don't convert non-nav_menu_item objects into nav_menu_item objects |
370
|
|
|
if ( ! empty( $menu_item_db_id ) && ! is_nav_menu_item( $menu_item_db_id ) ) |
371
|
|
|
return new WP_Error( 'update_nav_menu_item_failed', __( 'The given object ID is not that of a menu item.' ) ); |
372
|
|
|
|
373
|
|
|
$menu = wp_get_nav_menu_object( $menu_id ); |
374
|
|
|
|
375
|
|
|
if ( ! $menu && 0 !== $menu_id ) { |
376
|
|
|
return new WP_Error( 'invalid_menu_id', __( 'Invalid menu ID.' ) ); |
377
|
|
|
} |
378
|
|
|
|
379
|
|
|
if ( is_wp_error( $menu ) ) { |
380
|
|
|
return $menu; |
381
|
|
|
} |
382
|
|
|
|
383
|
|
|
$defaults = array( |
384
|
|
|
'menu-item-db-id' => $menu_item_db_id, |
385
|
|
|
'menu-item-object-id' => 0, |
386
|
|
|
'menu-item-object' => '', |
387
|
|
|
'menu-item-parent-id' => 0, |
388
|
|
|
'menu-item-position' => 0, |
389
|
|
|
'menu-item-type' => 'custom', |
390
|
|
|
'menu-item-title' => '', |
391
|
|
|
'menu-item-url' => '', |
392
|
|
|
'menu-item-description' => '', |
393
|
|
|
'menu-item-attr-title' => '', |
394
|
|
|
'menu-item-target' => '', |
395
|
|
|
'menu-item-classes' => '', |
396
|
|
|
'menu-item-xfn' => '', |
397
|
|
|
'menu-item-status' => '', |
398
|
|
|
); |
399
|
|
|
|
400
|
|
|
$args = wp_parse_args( $menu_item_data, $defaults ); |
401
|
|
|
|
402
|
|
|
if ( 0 == $menu_id ) { |
403
|
|
|
$args['menu-item-position'] = 1; |
404
|
|
|
} elseif ( 0 == (int) $args['menu-item-position'] ) { |
405
|
|
|
$menu_items = 0 == $menu_id ? array() : (array) wp_get_nav_menu_items( $menu_id, array( 'post_status' => 'publish,draft' ) ); |
406
|
|
|
$last_item = array_pop( $menu_items ); |
407
|
|
|
$args['menu-item-position'] = ( $last_item && isset( $last_item->menu_order ) ) ? 1 + $last_item->menu_order : count( $menu_items ); |
408
|
|
|
} |
409
|
|
|
|
410
|
|
|
$original_parent = 0 < $menu_item_db_id ? get_post_field( 'post_parent', $menu_item_db_id ) : 0; |
411
|
|
|
|
412
|
|
|
if ( 'custom' != $args['menu-item-type'] ) { |
413
|
|
|
/* if non-custom menu item, then: |
414
|
|
|
* use original object's URL |
415
|
|
|
* blank default title to sync with original object's |
416
|
|
|
*/ |
417
|
|
|
|
418
|
|
|
$args['menu-item-url'] = ''; |
419
|
|
|
|
420
|
|
|
$original_title = ''; |
421
|
|
|
if ( 'taxonomy' == $args['menu-item-type'] ) { |
422
|
|
|
$original_parent = get_term_field( 'parent', $args['menu-item-object-id'], $args['menu-item-object'], 'raw' ); |
423
|
|
|
$original_title = get_term_field( 'name', $args['menu-item-object-id'], $args['menu-item-object'], 'raw' ); |
424
|
|
|
} elseif ( 'post_type' == $args['menu-item-type'] ) { |
425
|
|
|
|
426
|
|
|
$original_object = get_post( $args['menu-item-object-id'] ); |
427
|
|
|
$original_parent = (int) $original_object->post_parent; |
428
|
|
|
$original_title = $original_object->post_title; |
429
|
|
|
} elseif ( 'post_type_archive' == $args['menu-item-type'] ) { |
430
|
|
|
$original_object = get_post_type_object( $args['menu-item-object'] ); |
431
|
|
|
if ( $original_object ) { |
432
|
|
|
$original_title = $original_object->labels->archives; |
433
|
|
|
} |
434
|
|
|
} |
435
|
|
|
|
436
|
|
|
if ( $args['menu-item-title'] == $original_title ) |
437
|
|
|
$args['menu-item-title'] = ''; |
438
|
|
|
|
439
|
|
|
// hack to get wp to create a post object when too many properties are empty |
440
|
|
|
if ( '' == $args['menu-item-title'] && '' == $args['menu-item-description'] ) |
441
|
|
|
$args['menu-item-description'] = ' '; |
442
|
|
|
} |
443
|
|
|
|
444
|
|
|
// Populate the menu item object |
445
|
|
|
$post = array( |
446
|
|
|
'menu_order' => $args['menu-item-position'], |
447
|
|
|
'ping_status' => 0, |
448
|
|
|
'post_content' => $args['menu-item-description'], |
449
|
|
|
'post_excerpt' => $args['menu-item-attr-title'], |
450
|
|
|
'post_parent' => $original_parent, |
451
|
|
|
'post_title' => $args['menu-item-title'], |
452
|
|
|
'post_type' => 'nav_menu_item', |
453
|
|
|
); |
454
|
|
|
|
455
|
|
|
$update = 0 != $menu_item_db_id; |
456
|
|
|
|
457
|
|
|
// New menu item. Default is draft status |
458
|
|
|
if ( ! $update ) { |
459
|
|
|
$post['ID'] = 0; |
460
|
|
|
$post['post_status'] = 'publish' == $args['menu-item-status'] ? 'publish' : 'draft'; |
461
|
|
|
$menu_item_db_id = wp_insert_post( $post ); |
462
|
|
|
if ( ! $menu_item_db_id || is_wp_error( $menu_item_db_id ) ) |
463
|
|
|
return $menu_item_db_id; |
464
|
|
|
|
465
|
|
|
/** |
466
|
|
|
* Fires immediately after a new navigation menu item has been added. |
467
|
|
|
* |
468
|
|
|
* @since 4.4.0 |
469
|
|
|
* |
470
|
|
|
* @see wp_update_nav_menu_item() |
471
|
|
|
* |
472
|
|
|
* @param int $menu_id ID of the updated menu. |
473
|
|
|
* @param int $menu_item_db_id ID of the new menu item. |
474
|
|
|
* @param array $args An array of arguments used to update/add the menu item. |
475
|
|
|
*/ |
476
|
|
|
do_action( 'wp_add_nav_menu_item', $menu_id, $menu_item_db_id, $args ); |
477
|
|
|
} |
478
|
|
|
|
479
|
|
|
// Associate the menu item with the menu term |
480
|
|
|
// Only set the menu term if it isn't set to avoid unnecessary wp_get_object_terms() |
481
|
|
|
if ( $menu_id && ( ! $update || ! is_object_in_term( $menu_item_db_id, 'nav_menu', (int) $menu->term_id ) ) ) { |
|
|
|
|
482
|
|
|
wp_set_object_terms( $menu_item_db_id, array( $menu->term_id ), 'nav_menu' ); |
|
|
|
|
483
|
|
|
} |
484
|
|
|
|
485
|
|
|
if ( 'custom' == $args['menu-item-type'] ) { |
486
|
|
|
$args['menu-item-object-id'] = $menu_item_db_id; |
487
|
|
|
$args['menu-item-object'] = 'custom'; |
488
|
|
|
} |
489
|
|
|
|
490
|
|
|
$menu_item_db_id = (int) $menu_item_db_id; |
491
|
|
|
|
492
|
|
|
update_post_meta( $menu_item_db_id, '_menu_item_type', sanitize_key($args['menu-item-type']) ); |
493
|
|
|
update_post_meta( $menu_item_db_id, '_menu_item_menu_item_parent', strval( (int) $args['menu-item-parent-id'] ) ); |
494
|
|
|
update_post_meta( $menu_item_db_id, '_menu_item_object_id', strval( (int) $args['menu-item-object-id'] ) ); |
495
|
|
|
update_post_meta( $menu_item_db_id, '_menu_item_object', sanitize_key($args['menu-item-object']) ); |
496
|
|
|
update_post_meta( $menu_item_db_id, '_menu_item_target', sanitize_key($args['menu-item-target']) ); |
497
|
|
|
|
498
|
|
|
$args['menu-item-classes'] = array_map( 'sanitize_html_class', explode( ' ', $args['menu-item-classes'] ) ); |
499
|
|
|
$args['menu-item-xfn'] = implode( ' ', array_map( 'sanitize_html_class', explode( ' ', $args['menu-item-xfn'] ) ) ); |
500
|
|
|
update_post_meta( $menu_item_db_id, '_menu_item_classes', $args['menu-item-classes'] ); |
501
|
|
|
update_post_meta( $menu_item_db_id, '_menu_item_xfn', $args['menu-item-xfn'] ); |
502
|
|
|
update_post_meta( $menu_item_db_id, '_menu_item_url', esc_url_raw($args['menu-item-url']) ); |
503
|
|
|
|
504
|
|
|
if ( 0 == $menu_id ) |
505
|
|
|
update_post_meta( $menu_item_db_id, '_menu_item_orphaned', (string) time() ); |
506
|
|
|
elseif ( get_post_meta( $menu_item_db_id, '_menu_item_orphaned' ) ) |
507
|
|
|
delete_post_meta( $menu_item_db_id, '_menu_item_orphaned' ); |
508
|
|
|
|
509
|
|
|
// Update existing menu item. Default is publish status |
510
|
|
|
if ( $update ) { |
511
|
|
|
$post['ID'] = $menu_item_db_id; |
512
|
|
|
$post['post_status'] = 'draft' == $args['menu-item-status'] ? 'draft' : 'publish'; |
513
|
|
|
wp_update_post( $post ); |
514
|
|
|
} |
515
|
|
|
|
516
|
|
|
/** |
517
|
|
|
* Fires after a navigation menu item has been updated. |
518
|
|
|
* |
519
|
|
|
* @since 3.0.0 |
520
|
|
|
* |
521
|
|
|
* @see wp_update_nav_menu_item() |
522
|
|
|
* |
523
|
|
|
* @param int $menu_id ID of the updated menu. |
524
|
|
|
* @param int $menu_item_db_id ID of the updated menu item. |
525
|
|
|
* @param array $args An array of arguments used to update a menu item. |
526
|
|
|
*/ |
527
|
|
|
do_action( 'wp_update_nav_menu_item', $menu_id, $menu_item_db_id, $args ); |
528
|
|
|
|
529
|
|
|
return $menu_item_db_id; |
530
|
|
|
} |
531
|
|
|
|
532
|
|
|
/** |
533
|
|
|
* Returns all navigation menu objects. |
534
|
|
|
* |
535
|
|
|
* @since 3.0.0 |
536
|
|
|
* @since 4.1.0 Default value of the 'orderby' argument was changed from 'none' |
537
|
|
|
* to 'name'. |
538
|
|
|
* |
539
|
|
|
* @param array $args Optional. Array of arguments passed on to get_terms(). |
540
|
|
|
* Default empty array. |
541
|
|
|
* @return array Menu objects. |
542
|
|
|
*/ |
543
|
|
|
function wp_get_nav_menus( $args = array() ) { |
544
|
|
|
$defaults = array( 'hide_empty' => false, 'orderby' => 'name' ); |
545
|
|
|
$args = wp_parse_args( $args, $defaults ); |
546
|
|
|
|
547
|
|
|
/** |
548
|
|
|
* Filters the navigation menu objects being returned. |
549
|
|
|
* |
550
|
|
|
* @since 3.0.0 |
551
|
|
|
* |
552
|
|
|
* @see get_terms() |
553
|
|
|
* |
554
|
|
|
* @param array $menus An array of menu objects. |
555
|
|
|
* @param array $args An array of arguments used to retrieve menu objects. |
556
|
|
|
*/ |
557
|
|
|
return apply_filters( 'wp_get_nav_menus', get_terms( 'nav_menu', $args), $args ); |
558
|
|
|
} |
559
|
|
|
|
560
|
|
|
/** |
561
|
|
|
* Sort menu items by the desired key. |
562
|
|
|
* |
563
|
|
|
* @since 3.0.0 |
564
|
|
|
* @access private |
565
|
|
|
* |
566
|
|
|
* @global string $_menu_item_sort_prop |
567
|
|
|
* |
568
|
|
|
* @param object $a The first object to compare |
569
|
|
|
* @param object $b The second object to compare |
570
|
|
|
* @return int -1, 0, or 1 if $a is considered to be respectively less than, equal to, or greater than $b. |
571
|
|
|
*/ |
572
|
|
|
function _sort_nav_menu_items( $a, $b ) { |
573
|
|
|
global $_menu_item_sort_prop; |
574
|
|
|
|
575
|
|
|
if ( empty( $_menu_item_sort_prop ) ) |
576
|
|
|
return 0; |
577
|
|
|
|
578
|
|
|
if ( ! isset( $a->$_menu_item_sort_prop ) || ! isset( $b->$_menu_item_sort_prop ) ) |
579
|
|
|
return 0; |
580
|
|
|
|
581
|
|
|
$_a = (int) $a->$_menu_item_sort_prop; |
582
|
|
|
$_b = (int) $b->$_menu_item_sort_prop; |
583
|
|
|
|
584
|
|
|
if ( $a->$_menu_item_sort_prop == $b->$_menu_item_sort_prop ) |
585
|
|
|
return 0; |
586
|
|
|
elseif ( $_a == $a->$_menu_item_sort_prop && $_b == $b->$_menu_item_sort_prop ) |
587
|
|
|
return $_a < $_b ? -1 : 1; |
588
|
|
|
else |
589
|
|
|
return strcmp( $a->$_menu_item_sort_prop, $b->$_menu_item_sort_prop ); |
590
|
|
|
} |
591
|
|
|
|
592
|
|
|
/** |
593
|
|
|
* Return if a menu item is valid. |
594
|
|
|
* |
595
|
|
|
* @link https://core.trac.wordpress.org/ticket/13958 |
596
|
|
|
* |
597
|
|
|
* @since 3.2.0 |
598
|
|
|
* @access private |
599
|
|
|
* |
600
|
|
|
* @param object $item The menu item to check. |
601
|
|
|
* @return bool False if invalid, otherwise true. |
602
|
|
|
*/ |
603
|
|
|
function _is_valid_nav_menu_item( $item ) { |
604
|
|
|
return empty( $item->_invalid ); |
605
|
|
|
} |
606
|
|
|
|
607
|
|
|
/** |
608
|
|
|
* Return all menu items of a navigation menu. |
609
|
|
|
* |
610
|
|
|
* @since 3.0.0 |
611
|
|
|
* |
612
|
|
|
* @global string $_menu_item_sort_prop |
613
|
|
|
* @staticvar array $fetched |
614
|
|
|
* |
615
|
|
|
* @param string $menu Menu name, ID, or slug. |
616
|
|
|
* @param array $args Optional. Arguments to pass to get_posts(). |
617
|
|
|
* @return false|array $items Array of menu items, otherwise false. |
618
|
|
|
*/ |
619
|
|
|
function wp_get_nav_menu_items( $menu, $args = array() ) { |
620
|
|
|
$menu = wp_get_nav_menu_object( $menu ); |
621
|
|
|
|
622
|
|
|
if ( ! $menu ) { |
623
|
|
|
return false; |
624
|
|
|
} |
625
|
|
|
|
626
|
|
|
static $fetched = array(); |
627
|
|
|
|
628
|
|
|
$items = get_objects_in_term( $menu->term_id, 'nav_menu' ); |
629
|
|
|
if ( is_wp_error( $items ) ) { |
630
|
|
|
return false; |
631
|
|
|
} |
632
|
|
|
|
633
|
|
|
$defaults = array( 'order' => 'ASC', 'orderby' => 'menu_order', 'post_type' => 'nav_menu_item', |
634
|
|
|
'post_status' => 'publish', 'output' => ARRAY_A, 'output_key' => 'menu_order', 'nopaging' => true ); |
635
|
|
|
$args = wp_parse_args( $args, $defaults ); |
636
|
|
|
$args['include'] = $items; |
637
|
|
|
|
638
|
|
|
if ( ! empty( $items ) ) { |
639
|
|
|
$items = get_posts( $args ); |
640
|
|
|
} else { |
641
|
|
|
$items = array(); |
642
|
|
|
} |
643
|
|
|
|
644
|
|
|
// Get all posts and terms at once to prime the caches |
645
|
|
|
if ( empty( $fetched[$menu->term_id] ) || wp_using_ext_object_cache() ) { |
646
|
|
|
$fetched[$menu->term_id] = true; |
647
|
|
|
$posts = array(); |
648
|
|
|
$terms = array(); |
649
|
|
|
foreach ( $items as $item ) { |
650
|
|
|
$object_id = get_post_meta( $item->ID, '_menu_item_object_id', true ); |
651
|
|
|
$object = get_post_meta( $item->ID, '_menu_item_object', true ); |
652
|
|
|
$type = get_post_meta( $item->ID, '_menu_item_type', true ); |
653
|
|
|
|
654
|
|
|
if ( 'post_type' == $type ) |
655
|
|
|
$posts[$object][] = $object_id; |
656
|
|
|
elseif ( 'taxonomy' == $type) |
657
|
|
|
$terms[$object][] = $object_id; |
658
|
|
|
} |
659
|
|
|
|
660
|
|
|
if ( ! empty( $posts ) ) { |
661
|
|
|
foreach ( array_keys($posts) as $post_type ) { |
662
|
|
|
get_posts( array('post__in' => $posts[$post_type], 'post_type' => $post_type, 'nopaging' => true, 'update_post_term_cache' => false) ); |
663
|
|
|
} |
664
|
|
|
} |
665
|
|
|
unset($posts); |
666
|
|
|
|
667
|
|
|
if ( ! empty( $terms ) ) { |
668
|
|
|
foreach ( array_keys($terms) as $taxonomy ) { |
669
|
|
|
get_terms( $taxonomy, array( |
670
|
|
|
'include' => $terms[ $taxonomy ], |
671
|
|
|
'hierarchical' => false, |
672
|
|
|
) ); |
673
|
|
|
} |
674
|
|
|
} |
675
|
|
|
unset($terms); |
676
|
|
|
} |
677
|
|
|
|
678
|
|
|
$items = array_map( 'wp_setup_nav_menu_item', $items ); |
679
|
|
|
|
680
|
|
|
if ( ! is_admin() ) { // Remove invalid items only in front end |
681
|
|
|
$items = array_filter( $items, '_is_valid_nav_menu_item' ); |
682
|
|
|
} |
683
|
|
|
|
684
|
|
View Code Duplication |
if ( ARRAY_A == $args['output'] ) { |
685
|
|
|
$GLOBALS['_menu_item_sort_prop'] = $args['output_key']; |
686
|
|
|
usort($items, '_sort_nav_menu_items'); |
687
|
|
|
$i = 1; |
688
|
|
|
foreach ( $items as $k => $item ) { |
689
|
|
|
$items[$k]->{$args['output_key']} = $i++; |
690
|
|
|
} |
691
|
|
|
} |
692
|
|
|
|
693
|
|
|
/** |
694
|
|
|
* Filters the navigation menu items being returned. |
695
|
|
|
* |
696
|
|
|
* @since 3.0.0 |
697
|
|
|
* |
698
|
|
|
* @param array $items An array of menu item post objects. |
699
|
|
|
* @param object $menu The menu object. |
700
|
|
|
* @param array $args An array of arguments used to retrieve menu item objects. |
701
|
|
|
*/ |
702
|
|
|
return apply_filters( 'wp_get_nav_menu_items', $items, $menu, $args ); |
703
|
|
|
} |
704
|
|
|
|
705
|
|
|
/** |
706
|
|
|
* Decorates a menu item object with the shared navigation menu item properties. |
707
|
|
|
* |
708
|
|
|
* Properties: |
709
|
|
|
* - ID: The term_id if the menu item represents a taxonomy term. |
710
|
|
|
* - attr_title: The title attribute of the link element for this menu item. |
711
|
|
|
* - classes: The array of class attribute values for the link element of this menu item. |
712
|
|
|
* - db_id: The DB ID of this item as a nav_menu_item object, if it exists (0 if it doesn't exist). |
713
|
|
|
* - description: The description of this menu item. |
714
|
|
|
* - menu_item_parent: The DB ID of the nav_menu_item that is this item's menu parent, if any. 0 otherwise. |
715
|
|
|
* - object: The type of object originally represented, such as "category," "post", or "attachment." |
716
|
|
|
* - object_id: The DB ID of the original object this menu item represents, e.g. ID for posts and term_id for categories. |
717
|
|
|
* - post_parent: The DB ID of the original object's parent object, if any (0 otherwise). |
718
|
|
|
* - post_title: A "no title" label if menu item represents a post that lacks a title. |
719
|
|
|
* - target: The target attribute of the link element for this menu item. |
720
|
|
|
* - title: The title of this menu item. |
721
|
|
|
* - type: The family of objects originally represented, such as "post_type" or "taxonomy." |
722
|
|
|
* - type_label: The singular label used to describe this type of menu item. |
723
|
|
|
* - url: The URL to which this menu item points. |
724
|
|
|
* - xfn: The XFN relationship expressed in the link of this menu item. |
725
|
|
|
* - _invalid: Whether the menu item represents an object that no longer exists. |
726
|
|
|
* |
727
|
|
|
* @since 3.0.0 |
728
|
|
|
* |
729
|
|
|
* @param object $menu_item The menu item to modify. |
730
|
|
|
* @return object $menu_item The menu item with standard menu item properties. |
731
|
|
|
*/ |
732
|
|
|
function wp_setup_nav_menu_item( $menu_item ) { |
733
|
|
|
if ( isset( $menu_item->post_type ) ) { |
734
|
|
|
if ( 'nav_menu_item' == $menu_item->post_type ) { |
735
|
|
|
$menu_item->db_id = (int) $menu_item->ID; |
736
|
|
|
$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; |
737
|
|
|
$menu_item->object_id = ! isset( $menu_item->object_id ) ? get_post_meta( $menu_item->ID, '_menu_item_object_id', true ) : $menu_item->object_id; |
738
|
|
|
$menu_item->object = ! isset( $menu_item->object ) ? get_post_meta( $menu_item->ID, '_menu_item_object', true ) : $menu_item->object; |
739
|
|
|
$menu_item->type = ! isset( $menu_item->type ) ? get_post_meta( $menu_item->ID, '_menu_item_type', true ) : $menu_item->type; |
740
|
|
|
|
741
|
|
|
if ( 'post_type' == $menu_item->type ) { |
742
|
|
|
$object = get_post_type_object( $menu_item->object ); |
743
|
|
View Code Duplication |
if ( $object ) { |
744
|
|
|
$menu_item->type_label = $object->labels->singular_name; |
745
|
|
|
} else { |
746
|
|
|
$menu_item->type_label = $menu_item->object; |
747
|
|
|
$menu_item->_invalid = true; |
748
|
|
|
} |
749
|
|
|
|
750
|
|
|
$menu_item->url = get_permalink( $menu_item->object_id ); |
751
|
|
|
|
752
|
|
|
$original_object = get_post( $menu_item->object_id ); |
753
|
|
|
/** This filter is documented in wp-includes/post-template.php */ |
754
|
|
|
$original_title = apply_filters( 'the_title', $original_object->post_title, $original_object->ID ); |
755
|
|
|
|
756
|
|
|
if ( '' === $original_title ) { |
757
|
|
|
/* translators: %d: ID of a post */ |
758
|
|
|
$original_title = sprintf( __( '#%d (no title)' ), $original_object->ID ); |
759
|
|
|
} |
760
|
|
|
|
761
|
|
|
$menu_item->title = '' == $menu_item->post_title ? $original_title : $menu_item->post_title; |
762
|
|
|
|
763
|
|
|
} elseif ( 'post_type_archive' == $menu_item->type ) { |
764
|
|
|
$object = get_post_type_object( $menu_item->object ); |
765
|
|
|
if ( $object ) { |
766
|
|
|
$menu_item->title = '' == $menu_item->post_title ? $object->labels->archives : $menu_item->post_title; |
767
|
|
|
$post_type_description = $object->description; |
768
|
|
|
} else { |
769
|
|
|
$menu_item->_invalid = true; |
770
|
|
|
$post_type_description = ''; |
771
|
|
|
} |
772
|
|
|
|
773
|
|
|
$menu_item->type_label = __( 'Post Type Archive' ); |
774
|
|
|
$post_content = wp_trim_words( $menu_item->post_content, 200 ); |
775
|
|
|
$post_type_description = '' == $post_content ? $post_type_description : $post_content; |
|
|
|
|
776
|
|
|
$menu_item->url = get_post_type_archive_link( $menu_item->object ); |
777
|
|
|
} elseif ( 'taxonomy' == $menu_item->type ) { |
778
|
|
|
$object = get_taxonomy( $menu_item->object ); |
779
|
|
View Code Duplication |
if ( $object ) { |
780
|
|
|
$menu_item->type_label = $object->labels->singular_name; |
781
|
|
|
} else { |
782
|
|
|
$menu_item->type_label = $menu_item->object; |
783
|
|
|
$menu_item->_invalid = true; |
784
|
|
|
} |
785
|
|
|
|
786
|
|
|
$term_url = get_term_link( (int) $menu_item->object_id, $menu_item->object ); |
787
|
|
|
$menu_item->url = !is_wp_error( $term_url ) ? $term_url : ''; |
788
|
|
|
|
789
|
|
|
$original_title = get_term_field( 'name', $menu_item->object_id, $menu_item->object, 'raw' ); |
790
|
|
|
if ( is_wp_error( $original_title ) ) |
791
|
|
|
$original_title = false; |
792
|
|
|
$menu_item->title = '' == $menu_item->post_title ? $original_title : $menu_item->post_title; |
793
|
|
|
|
794
|
|
|
} else { |
795
|
|
|
$menu_item->type_label = __('Custom Link'); |
796
|
|
|
$menu_item->title = $menu_item->post_title; |
797
|
|
|
$menu_item->url = ! isset( $menu_item->url ) ? get_post_meta( $menu_item->ID, '_menu_item_url', true ) : $menu_item->url; |
798
|
|
|
} |
799
|
|
|
|
800
|
|
|
$menu_item->target = ! isset( $menu_item->target ) ? get_post_meta( $menu_item->ID, '_menu_item_target', true ) : $menu_item->target; |
801
|
|
|
|
802
|
|
|
/** |
803
|
|
|
* Filters a navigation menu item's title attribute. |
804
|
|
|
* |
805
|
|
|
* @since 3.0.0 |
806
|
|
|
* |
807
|
|
|
* @param string $item_title The menu item title attribute. |
808
|
|
|
*/ |
809
|
|
|
$menu_item->attr_title = ! isset( $menu_item->attr_title ) ? apply_filters( 'nav_menu_attr_title', $menu_item->post_excerpt ) : $menu_item->attr_title; |
810
|
|
|
|
811
|
|
|
if ( ! isset( $menu_item->description ) ) { |
812
|
|
|
/** |
813
|
|
|
* Filters a navigation menu item's description. |
814
|
|
|
* |
815
|
|
|
* @since 3.0.0 |
816
|
|
|
* |
817
|
|
|
* @param string $description The menu item description. |
818
|
|
|
*/ |
819
|
|
|
$menu_item->description = apply_filters( 'nav_menu_description', wp_trim_words( $menu_item->post_content, 200 ) ); |
820
|
|
|
} |
821
|
|
|
|
822
|
|
|
$menu_item->classes = ! isset( $menu_item->classes ) ? (array) get_post_meta( $menu_item->ID, '_menu_item_classes', true ) : $menu_item->classes; |
823
|
|
|
$menu_item->xfn = ! isset( $menu_item->xfn ) ? get_post_meta( $menu_item->ID, '_menu_item_xfn', true ) : $menu_item->xfn; |
824
|
|
|
} else { |
825
|
|
|
$menu_item->db_id = 0; |
826
|
|
|
$menu_item->menu_item_parent = 0; |
827
|
|
|
$menu_item->object_id = (int) $menu_item->ID; |
828
|
|
|
$menu_item->type = 'post_type'; |
829
|
|
|
|
830
|
|
|
$object = get_post_type_object( $menu_item->post_type ); |
831
|
|
|
$menu_item->object = $object->name; |
832
|
|
|
$menu_item->type_label = $object->labels->singular_name; |
833
|
|
|
|
834
|
|
|
if ( '' === $menu_item->post_title ) { |
835
|
|
|
/* translators: %d: ID of a post */ |
836
|
|
|
$menu_item->post_title = sprintf( __( '#%d (no title)' ), $menu_item->ID ); |
837
|
|
|
} |
838
|
|
|
|
839
|
|
|
$menu_item->title = $menu_item->post_title; |
840
|
|
|
$menu_item->url = get_permalink( $menu_item->ID ); |
841
|
|
|
$menu_item->target = ''; |
842
|
|
|
|
843
|
|
|
/** This filter is documented in wp-includes/nav-menu.php */ |
844
|
|
|
$menu_item->attr_title = apply_filters( 'nav_menu_attr_title', '' ); |
845
|
|
|
|
846
|
|
|
/** This filter is documented in wp-includes/nav-menu.php */ |
847
|
|
|
$menu_item->description = apply_filters( 'nav_menu_description', '' ); |
848
|
|
|
$menu_item->classes = array(); |
849
|
|
|
$menu_item->xfn = ''; |
850
|
|
|
} |
851
|
|
|
} elseif ( isset( $menu_item->taxonomy ) ) { |
852
|
|
|
$menu_item->ID = $menu_item->term_id; |
853
|
|
|
$menu_item->db_id = 0; |
854
|
|
|
$menu_item->menu_item_parent = 0; |
855
|
|
|
$menu_item->object_id = (int) $menu_item->term_id; |
856
|
|
|
$menu_item->post_parent = (int) $menu_item->parent; |
857
|
|
|
$menu_item->type = 'taxonomy'; |
858
|
|
|
|
859
|
|
|
$object = get_taxonomy( $menu_item->taxonomy ); |
860
|
|
|
$menu_item->object = $object->name; |
861
|
|
|
$menu_item->type_label = $object->labels->singular_name; |
862
|
|
|
|
863
|
|
|
$menu_item->title = $menu_item->name; |
864
|
|
|
$menu_item->url = get_term_link( $menu_item, $menu_item->taxonomy ); |
865
|
|
|
$menu_item->target = ''; |
866
|
|
|
$menu_item->attr_title = ''; |
867
|
|
|
$menu_item->description = get_term_field( 'description', $menu_item->term_id, $menu_item->taxonomy ); |
868
|
|
|
$menu_item->classes = array(); |
869
|
|
|
$menu_item->xfn = ''; |
870
|
|
|
|
871
|
|
|
} |
872
|
|
|
|
873
|
|
|
/** |
874
|
|
|
* Filters a navigation menu item object. |
875
|
|
|
* |
876
|
|
|
* @since 3.0.0 |
877
|
|
|
* |
878
|
|
|
* @param object $menu_item The menu item object. |
879
|
|
|
*/ |
880
|
|
|
return apply_filters( 'wp_setup_nav_menu_item', $menu_item ); |
881
|
|
|
} |
882
|
|
|
|
883
|
|
|
/** |
884
|
|
|
* Get the menu items associated with a particular object. |
885
|
|
|
* |
886
|
|
|
* @since 3.0.0 |
887
|
|
|
* |
888
|
|
|
* @param int $object_id The ID of the original object. |
889
|
|
|
* @param string $object_type The type of object, such as "taxonomy" or "post_type." |
890
|
|
|
* @param string $taxonomy If $object_type is "taxonomy", $taxonomy is the name of the tax that $object_id belongs to |
891
|
|
|
* @return array The array of menu item IDs; empty array if none; |
892
|
|
|
*/ |
893
|
|
|
function wp_get_associated_nav_menu_items( $object_id = 0, $object_type = 'post_type', $taxonomy = '' ) { |
894
|
|
|
$object_id = (int) $object_id; |
895
|
|
|
$menu_item_ids = array(); |
896
|
|
|
|
897
|
|
|
$query = new WP_Query; |
898
|
|
|
$menu_items = $query->query( |
899
|
|
|
array( |
|
|
|
|
900
|
|
|
'meta_key' => '_menu_item_object_id', |
901
|
|
|
'meta_value' => $object_id, |
902
|
|
|
'post_status' => 'any', |
903
|
|
|
'post_type' => 'nav_menu_item', |
904
|
|
|
'posts_per_page' => -1, |
905
|
|
|
) |
906
|
|
|
); |
907
|
|
|
foreach ( (array) $menu_items as $menu_item ) { |
908
|
|
|
if ( isset( $menu_item->ID ) && is_nav_menu_item( $menu_item->ID ) ) { |
909
|
|
|
$menu_item_type = get_post_meta( $menu_item->ID, '_menu_item_type', true ); |
910
|
|
|
if ( |
911
|
|
|
'post_type' == $object_type && |
912
|
|
|
'post_type' == $menu_item_type |
913
|
|
|
) { |
914
|
|
|
$menu_item_ids[] = (int) $menu_item->ID; |
915
|
|
|
} elseif ( |
916
|
|
|
'taxonomy' == $object_type && |
917
|
|
|
'taxonomy' == $menu_item_type && |
918
|
|
|
get_post_meta( $menu_item->ID, '_menu_item_object', true ) == $taxonomy |
919
|
|
|
) { |
920
|
|
|
$menu_item_ids[] = (int) $menu_item->ID; |
921
|
|
|
} |
922
|
|
|
} |
923
|
|
|
} |
924
|
|
|
|
925
|
|
|
return array_unique( $menu_item_ids ); |
926
|
|
|
} |
927
|
|
|
|
928
|
|
|
/** |
929
|
|
|
* Callback for handling a menu item when its original object is deleted. |
930
|
|
|
* |
931
|
|
|
* @since 3.0.0 |
932
|
|
|
* @access private |
933
|
|
|
* |
934
|
|
|
* @param int $object_id The ID of the original object being trashed. |
935
|
|
|
* |
936
|
|
|
*/ |
937
|
|
View Code Duplication |
function _wp_delete_post_menu_item( $object_id = 0 ) { |
|
|
|
|
938
|
|
|
$object_id = (int) $object_id; |
939
|
|
|
|
940
|
|
|
$menu_item_ids = wp_get_associated_nav_menu_items( $object_id, 'post_type' ); |
941
|
|
|
|
942
|
|
|
foreach ( (array) $menu_item_ids as $menu_item_id ) { |
943
|
|
|
wp_delete_post( $menu_item_id, true ); |
944
|
|
|
} |
945
|
|
|
} |
946
|
|
|
|
947
|
|
|
/** |
948
|
|
|
* Serves as a callback for handling a menu item when its original object is deleted. |
949
|
|
|
* |
950
|
|
|
* @since 3.0.0 |
951
|
|
|
* @access private |
952
|
|
|
* |
953
|
|
|
* @param int $object_id Optional. The ID of the original object being trashed. Default 0. |
954
|
|
|
* @param int $tt_id Term taxonomy ID. Unused. |
955
|
|
|
* @param string $taxonomy Taxonomy slug. |
956
|
|
|
*/ |
957
|
|
View Code Duplication |
function _wp_delete_tax_menu_item( $object_id = 0, $tt_id, $taxonomy ) { |
|
|
|
|
958
|
|
|
$object_id = (int) $object_id; |
959
|
|
|
|
960
|
|
|
$menu_item_ids = wp_get_associated_nav_menu_items( $object_id, 'taxonomy', $taxonomy ); |
961
|
|
|
|
962
|
|
|
foreach ( (array) $menu_item_ids as $menu_item_id ) { |
963
|
|
|
wp_delete_post( $menu_item_id, true ); |
964
|
|
|
} |
965
|
|
|
} |
966
|
|
|
|
967
|
|
|
/** |
968
|
|
|
* Automatically add newly published page objects to menus with that as an option. |
969
|
|
|
* |
970
|
|
|
* @since 3.0.0 |
971
|
|
|
* @access private |
972
|
|
|
* |
973
|
|
|
* @param string $new_status The new status of the post object. |
974
|
|
|
* @param string $old_status The old status of the post object. |
975
|
|
|
* @param object $post The post object being transitioned from one status to another. |
976
|
|
|
*/ |
977
|
|
|
function _wp_auto_add_pages_to_menu( $new_status, $old_status, $post ) { |
978
|
|
|
if ( 'publish' != $new_status || 'publish' == $old_status || 'page' != $post->post_type ) |
979
|
|
|
return; |
980
|
|
|
if ( ! empty( $post->post_parent ) ) |
981
|
|
|
return; |
982
|
|
|
$auto_add = get_option( 'nav_menu_options' ); |
983
|
|
|
if ( empty( $auto_add ) || ! is_array( $auto_add ) || ! isset( $auto_add['auto_add'] ) ) |
984
|
|
|
return; |
985
|
|
|
$auto_add = $auto_add['auto_add']; |
986
|
|
|
if ( empty( $auto_add ) || ! is_array( $auto_add ) ) |
987
|
|
|
return; |
988
|
|
|
|
989
|
|
|
$args = array( |
990
|
|
|
'menu-item-object-id' => $post->ID, |
991
|
|
|
'menu-item-object' => $post->post_type, |
992
|
|
|
'menu-item-type' => 'post_type', |
993
|
|
|
'menu-item-status' => 'publish', |
994
|
|
|
); |
995
|
|
|
|
996
|
|
|
foreach ( $auto_add as $menu_id ) { |
997
|
|
|
$items = wp_get_nav_menu_items( $menu_id, array( 'post_status' => 'publish,draft' ) ); |
998
|
|
|
if ( ! is_array( $items ) ) |
999
|
|
|
continue; |
1000
|
|
|
foreach ( $items as $item ) { |
1001
|
|
|
if ( $post->ID == $item->object_id ) |
1002
|
|
|
continue 2; |
1003
|
|
|
} |
1004
|
|
|
wp_update_nav_menu_item( $menu_id, 0, $args ); |
1005
|
|
|
} |
1006
|
|
|
} |
1007
|
|
|
|
There are different options of fixing this problem.
If you want to be on the safe side, you can add an additional type-check:
If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:
Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.