1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* WP JSON API Menu routes |
4
|
|
|
* |
5
|
|
|
* @package WP_API_Menus |
6
|
|
|
*/ |
7
|
|
|
|
8
|
|
|
if ( ! defined( 'ABSPATH' ) ) { |
9
|
|
|
exit; // Exit if accessed directly |
10
|
|
|
} |
11
|
|
|
|
12
|
|
|
if ( ! class_exists( 'WP_JSON_Menus' ) ) : |
13
|
|
|
|
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* WP JSON Menus class. |
17
|
|
|
* |
18
|
|
|
* WP API Menus support for WP API v1. |
19
|
|
|
* |
20
|
|
|
* @package WP_API_Menus |
21
|
|
|
* @since 1.0.0 |
22
|
|
|
*/ |
23
|
|
|
class WP_JSON_Menus { |
24
|
|
|
|
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* Register menu routes for WP API. |
28
|
|
|
* |
29
|
|
|
* @since 1.0.0 |
30
|
|
|
* @param array $routes Existing routes |
31
|
|
|
* @return array Modified routes |
32
|
|
|
*/ |
33
|
|
|
public function register_routes( $routes ) { |
34
|
|
|
|
35
|
|
|
// all registered menus |
36
|
|
|
$routes['/menus'] = array( |
37
|
|
|
array( array( $this, 'get_menus' ), WP_JSON_Server::READABLE ), |
38
|
|
|
); |
39
|
|
|
// a specific menu |
40
|
|
|
$routes['/menus/(?P<id>\d+)'] = array( |
41
|
|
|
array( array( $this, 'get_menu' ), WP_JSON_Server::READABLE ), |
42
|
|
|
); |
43
|
|
|
// a specific menu rendered in html |
44
|
|
|
$routes['/menu-html/(?P<id>[a-zA-Z0-9_-]+)'] = array( |
45
|
|
|
array( array( $this, 'get_menu_html' ), WP_JSON_Server::READABLE ), |
46
|
|
|
); |
47
|
|
|
// all registered menu locations |
48
|
|
|
$routes['/menu-locations'] = array( |
49
|
|
|
array( array( $this, 'get_menu_locations' ), WP_JSON_Server::READABLE ), |
50
|
|
|
); |
51
|
|
|
// menu for given location |
52
|
|
|
$routes['/menu-locations/(?P<location>[a-zA-Z0-9_-]+)'] = array( |
53
|
|
|
array( array( $this, 'get_menu_location' ), WP_JSON_Server::READABLE ), |
54
|
|
|
); |
55
|
|
|
// menu for given location rendered in html |
56
|
|
|
$routes['/menu-html-location/(?P<location>[a-zA-Z0-9_-]+)'] = array( |
57
|
|
|
array( array( $this, 'get_menu_html_location' ), WP_JSON_Server::READABLE ), |
58
|
|
|
); |
59
|
|
|
|
60
|
|
|
return $routes; |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* Get menus. |
66
|
|
|
* |
67
|
|
|
* @since 1.0.0 |
68
|
|
|
* @return array All registered menus |
69
|
|
|
*/ |
70
|
|
|
public static function get_menus() { |
71
|
|
|
|
72
|
|
|
$json_url = get_json_url() . '/menus/'; |
73
|
|
|
$json_url_base = get_json_url(); |
74
|
|
|
$wp_menus = wp_get_nav_menus(); |
75
|
|
|
|
76
|
|
|
$i = 0; |
77
|
|
|
$json_menus = array(); |
78
|
|
View Code Duplication |
foreach ( $wp_menus as $wp_menu ) : |
|
|
|
|
79
|
|
|
|
80
|
|
|
$menu = (array) $wp_menu; |
81
|
|
|
|
82
|
|
|
$json_menus[ $i ] = $menu; |
83
|
|
|
$json_menus[ $i ]['ID'] = $menu['term_id']; |
84
|
|
|
$json_menus[ $i ]['name'] = $menu['name']; |
85
|
|
|
$json_menus[ $i ]['slug'] = $menu['slug']; |
86
|
|
|
$json_menus[ $i ]['description'] = $menu['description']; |
87
|
|
|
$json_menus[ $i ]['count'] = $menu['count']; |
88
|
|
|
|
89
|
|
|
$json_menus[ $i ]['meta']['links']['collection'] = $json_url; |
90
|
|
|
$json_menus[ $i ]['meta']['links']['self'] = $json_url . $menu['term_id']; |
91
|
|
|
$json_menus[ $i ]['meta']['links']['self'] = $json_url_base . '/menu-html/' . $menu['term_id']; |
92
|
|
|
|
93
|
|
|
$i ++; |
94
|
|
|
endforeach; |
95
|
|
|
|
96
|
|
|
return $json_menus; |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* Get a menu. |
102
|
|
|
* |
103
|
|
|
* @since 1.0.0 |
104
|
|
|
* @param int $id ID of the menu |
105
|
|
|
* @return array Menu data |
106
|
|
|
*/ |
107
|
|
|
public function get_menu( $id ) { |
108
|
|
|
|
109
|
|
|
$json_url = get_json_url() . '/menus/'; |
110
|
|
|
$wp_menu_object = $id ? wp_get_nav_menu_object( $id ) : array(); |
111
|
|
|
$wp_menu_items = $id ? wp_get_nav_menu_items( $id ) : array(); |
112
|
|
|
|
113
|
|
|
$json_menu = array(); |
114
|
|
|
|
115
|
|
View Code Duplication |
if ( $wp_menu_object ) : |
|
|
|
|
116
|
|
|
|
117
|
|
|
$menu = (array) $wp_menu_object; |
118
|
|
|
$json_menu['ID'] = abs( $menu['term_id'] ); |
119
|
|
|
$json_menu['name'] = $menu['name']; |
120
|
|
|
$json_menu['slug'] = $menu['slug']; |
121
|
|
|
$json_menu['description'] = $menu['description']; |
122
|
|
|
$json_menu['count'] = abs( $menu['count'] ); |
123
|
|
|
|
124
|
|
|
$json_menu_items = array(); |
125
|
|
|
foreach ( $wp_menu_items as $item_object ) { |
126
|
|
|
$json_menu_items[] = $this->format_menu_item( $item_object ); |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
$json_menu['items'] = $json_menu_items; |
130
|
|
|
$json_menu['meta']['links']['collection'] = $json_url; |
131
|
|
|
$json_menu['meta']['links']['self'] = $json_url . $id; |
132
|
|
|
|
133
|
|
|
endif; |
134
|
|
|
|
135
|
|
|
return $json_menu; |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
|
139
|
|
|
/** |
140
|
|
|
* Get a menu rendered in html. |
141
|
|
|
* |
142
|
|
|
* @since 1.0.0 |
143
|
|
|
* @param int $id ID of the menu |
|
|
|
|
144
|
|
|
* @return array Menu data |
145
|
|
|
*/ |
146
|
|
|
public function get_menu_html( $menu_id ) { |
147
|
|
|
|
148
|
|
|
$json_url_base = get_json_url(); |
149
|
|
|
$wp_menu_object = $menu_id ? wp_get_nav_menu_object( $menu_id ) : array(); |
150
|
|
|
$wp_menu_items = $menu_id ? wp_get_nav_menu_items( $menu_id ) : array(); |
|
|
|
|
151
|
|
|
|
152
|
|
|
$json_menu = array(); |
153
|
|
|
|
154
|
|
View Code Duplication |
if ( $wp_menu_object ) : |
|
|
|
|
155
|
|
|
|
156
|
|
|
$menu = (array) $wp_menu_object; |
157
|
|
|
$json_menu['ID'] = abs( $menu['term_id'] ); |
158
|
|
|
$json_menu['name'] = $menu['name']; |
159
|
|
|
$json_menu['slug'] = $menu['slug']; |
160
|
|
|
$json_menu['description'] = $menu['description']; |
161
|
|
|
$json_menu['count'] = abs( $menu['count'] ); |
162
|
|
|
|
163
|
|
|
ob_start(); |
164
|
|
|
wp_nav_menu( array( 'menu' => $menu_id ) ); |
165
|
|
|
$json_menu['html']=ob_get_clean(); |
166
|
|
|
|
167
|
|
|
$json_menu['meta']['links']['collection'] = $json_url_base . '/menus/'; |
168
|
|
|
$json_menu['meta']['links']['self'] = $json_url_base . '/menu-html/' . $menu_id; |
169
|
|
|
|
170
|
|
|
endif; |
171
|
|
|
|
172
|
|
|
return $json_menu; |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
|
176
|
|
|
/** |
177
|
|
|
* Get menu locations. |
178
|
|
|
* |
179
|
|
|
* @since 1.0.0 |
180
|
|
|
* @return array All registered menus locations |
181
|
|
|
*/ |
182
|
|
|
public static function get_menu_locations() { |
183
|
|
|
|
184
|
|
|
$locations = get_nav_menu_locations(); |
185
|
|
|
$registered_menus = get_registered_nav_menus(); |
186
|
|
|
$json_url = get_json_url() . '/menu-locations/'; |
187
|
|
|
$json_url_base = get_json_url(); |
188
|
|
|
$json_menus = array(); |
189
|
|
|
|
190
|
|
View Code Duplication |
if ( $locations && $registered_menus ) : |
|
|
|
|
191
|
|
|
|
192
|
|
|
foreach ( $registered_menus as $slug => $label ) : |
193
|
|
|
|
194
|
|
|
// Sanity check |
195
|
|
|
if ( ! isset( $locations[ $slug ] ) ) { |
196
|
|
|
continue; |
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
$json_menus[ $slug ]['ID'] = $locations[ $slug ]; |
200
|
|
|
$json_menus[ $slug ]['label'] = $label; |
201
|
|
|
$json_menus[ $slug ]['meta']['links']['collection'] = $json_url; |
202
|
|
|
$json_menus[ $slug ]['meta']['links']['self'] = $json_url . $slug; |
203
|
|
|
$json_menus[ $slug ]['meta']['links']['html'] = $json_url_base . '/menu-html-location/' . $slug; |
204
|
|
|
|
205
|
|
|
endforeach; |
206
|
|
|
|
207
|
|
|
endif; |
208
|
|
|
|
209
|
|
|
return $json_menus; |
210
|
|
|
} |
211
|
|
|
|
212
|
|
|
|
213
|
|
|
/** |
214
|
|
|
* Get menu for location. |
215
|
|
|
* |
216
|
|
|
* @since 1.0.0 |
217
|
|
|
* @param string $location The theme location menu name |
218
|
|
|
* @return array The menu for the corresponding location |
219
|
|
|
*/ |
220
|
|
|
public function get_menu_location( $location ) { |
221
|
|
|
|
222
|
|
|
$locations = get_nav_menu_locations(); |
223
|
|
|
if ( ! isset( $locations[ $location ] ) ) { |
224
|
|
|
return array(); |
225
|
|
|
} |
226
|
|
|
|
227
|
|
|
$wp_menu = wp_get_nav_menu_object( $locations[ $location ] ); |
228
|
|
|
$menu_items = wp_get_nav_menu_items( $wp_menu->term_id ); |
229
|
|
|
|
230
|
|
|
$sorted_menu_items = $top_level_menu_items = $menu_items_with_children = array(); |
231
|
|
|
|
232
|
|
|
foreach ( (array) $menu_items as $menu_item ) { |
233
|
|
|
$sorted_menu_items[ $menu_item->menu_order ] = $menu_item; |
234
|
|
|
} |
235
|
|
|
foreach ( $sorted_menu_items as $menu_item ) { |
236
|
|
|
if ( (int) $menu_item->menu_item_parent !== 0 ) { |
237
|
|
|
$menu_items_with_children[ $menu_item->menu_item_parent ] = true; |
238
|
|
|
} else { |
239
|
|
|
$top_level_menu_items[] = $menu_item; |
240
|
|
|
} |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
$menu = array(); |
244
|
|
|
while ( $sorted_menu_items ) : |
|
|
|
|
245
|
|
|
|
246
|
|
|
$i = 0; |
247
|
|
|
foreach ( $top_level_menu_items as $top_item ) : |
248
|
|
|
|
249
|
|
|
$menu[ $i ] = $this->format_menu_item( $top_item, false ); |
250
|
|
|
if ( isset( $menu_items_with_children[ $top_item->ID ] ) ) { |
251
|
|
|
$menu[ $i ]['children'] = $this->get_nav_menu_item_children( $top_item->ID, $menu_items, false ); |
252
|
|
|
} else { |
253
|
|
|
$menu[ $i ]['children'] = array(); |
254
|
|
|
} |
255
|
|
|
|
256
|
|
|
$i++; |
257
|
|
|
endforeach; |
258
|
|
|
|
259
|
|
|
break; |
260
|
|
|
|
261
|
|
|
endwhile; |
262
|
|
|
|
263
|
|
|
return $menu; |
264
|
|
|
} |
265
|
|
|
|
266
|
|
|
/** |
267
|
|
|
* Get menu rendered in html for location. |
268
|
|
|
* |
269
|
|
|
* @since 1.x.0 |
270
|
|
|
* @param string $location The theme location menu name |
271
|
|
|
* @return array The menu for the corresponding location |
272
|
|
|
*/ |
273
|
|
|
public static function get_menu_html_location( $location ) { |
274
|
|
|
|
275
|
|
|
$locations = get_nav_menu_locations(); |
276
|
|
|
if ( ! isset( $locations[ $location ] ) ) { |
277
|
|
|
return array(); |
278
|
|
|
} |
279
|
|
|
|
280
|
|
|
$wp_menu_object = get_term( $locations[$location], 'nav_menu' ); |
281
|
|
|
$json_url_base = get_json_url(); |
282
|
|
|
|
283
|
|
|
$json_menu = array(); |
284
|
|
|
|
285
|
|
View Code Duplication |
if ( $wp_menu_object ) : |
|
|
|
|
286
|
|
|
|
287
|
|
|
$menu = (array) $wp_menu_object; |
288
|
|
|
$json_menu['ID'] = abs( $menu['term_id'] ); |
289
|
|
|
$json_menu['name'] = $menu['name']; |
290
|
|
|
$json_menu['slug'] = $menu['slug']; |
291
|
|
|
$json_menu['location_slug'] = $location; |
292
|
|
|
$json_menu['description'] = $menu['description']; |
293
|
|
|
$json_menu['count'] = abs( $menu['count'] ); |
294
|
|
|
|
295
|
|
|
ob_start(); |
296
|
|
|
wp_nav_menu( array( 'menu' => $location ) ); |
297
|
|
|
$json_menu['html']=ob_get_clean(); |
298
|
|
|
|
299
|
|
|
$json_menu['meta']['links']['collection'] = $json_url_base . '/menu-locations/'; |
300
|
|
|
$json_menu['meta']['links']['self'] = $json_url_base . '/menu-html-location/' . $location; |
301
|
|
|
|
302
|
|
|
endif; |
303
|
|
|
|
304
|
|
|
return $json_menu; |
305
|
|
|
} |
306
|
|
|
|
307
|
|
|
|
308
|
|
|
/** |
309
|
|
|
* Returns all child nav_menu_items under a specific parent. |
310
|
|
|
* |
311
|
|
|
* @since 1.1.0 |
312
|
|
|
* @param int $parent_id the parent nav_menu_item ID |
313
|
|
|
* @param array $nav_menu_items navigation menu items |
314
|
|
|
* @param bool $depth gives all children or direct children only |
315
|
|
|
* @return array returns filtered array of nav_menu_items |
316
|
|
|
*/ |
317
|
|
View Code Duplication |
public function get_nav_menu_item_children( $parent_id, $nav_menu_items, $depth = true ) { |
|
|
|
|
318
|
|
|
|
319
|
|
|
$nav_menu_item_list = array(); |
320
|
|
|
|
321
|
|
|
foreach ( (array) $nav_menu_items as $nav_menu_item ) : |
322
|
|
|
|
323
|
|
|
if ( $nav_menu_item->menu_item_parent == $parent_id ) : |
324
|
|
|
|
325
|
|
|
$nav_menu_item_list[] = $this->format_menu_item( $nav_menu_item, true, $nav_menu_items ); |
326
|
|
|
|
327
|
|
|
if ( $depth ) { |
328
|
|
|
if ( $children = $this->get_nav_menu_item_children( $nav_menu_item->ID, $nav_menu_items ) ) { |
329
|
|
|
$nav_menu_item_list = array_merge( $nav_menu_item_list, $children ); |
330
|
|
|
} |
331
|
|
|
} |
332
|
|
|
|
333
|
|
|
endif; |
334
|
|
|
|
335
|
|
|
endforeach; |
336
|
|
|
|
337
|
|
|
return $nav_menu_item_list; |
338
|
|
|
} |
339
|
|
|
|
340
|
|
|
|
341
|
|
|
/** |
342
|
|
|
* Format a menu item for JSON API consumption. |
343
|
|
|
* |
344
|
|
|
* @since 1.1.0 |
345
|
|
|
* @param object|array $menu_item the menu item |
346
|
|
|
* @param bool $children get menu item children (default false) |
347
|
|
|
* @param array $menu the menu the item belongs to (used when $children is set to true) |
348
|
|
|
* @return array a formatted menu item for JSON |
349
|
|
|
*/ |
350
|
|
View Code Duplication |
public function format_menu_item( $menu_item, $children = false, $menu = array() ) { |
|
|
|
|
351
|
|
|
|
352
|
|
|
$item = (array) $menu_item; |
353
|
|
|
|
354
|
|
|
$menu_item = array( |
355
|
|
|
'ID' => abs( $item['ID'] ), |
356
|
|
|
'order' => (int) $item['menu_order'], |
357
|
|
|
'parent' => abs( $item['menu_item_parent'] ), |
358
|
|
|
'title' => $item['title'], |
359
|
|
|
'url' => $item['url'], |
360
|
|
|
'attr' => $item['attr_title'], |
361
|
|
|
'target' => $item['target'], |
362
|
|
|
'classes' => implode( ' ', $item['classes'] ), |
363
|
|
|
'xfn' => $item['xfn'], |
364
|
|
|
'description' => $item['description'], |
365
|
|
|
'object_id' => abs( $item['object_id'] ), |
366
|
|
|
'object' => $item['object'], |
367
|
|
|
'type' => $item['type'], |
368
|
|
|
'type_label' => $item['type_label'], |
369
|
|
|
); |
370
|
|
|
|
371
|
|
|
if ( $children === true && ! empty( $menu ) ) { |
372
|
|
|
$menu_item['children'] = $this->get_nav_menu_item_children( $item['ID'], $menu ); |
373
|
|
|
} |
374
|
|
|
|
375
|
|
|
return apply_filters( 'json_menus_format_menu_item', $menu_item ); |
376
|
|
|
} |
377
|
|
|
|
378
|
|
|
|
379
|
|
|
} |
380
|
|
|
|
381
|
|
|
|
382
|
|
|
endif; |
383
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.