Completed
Pull Request — master (#27)
by
unknown
02:12
created

WP_REST_Menus::get_plugin_namespace()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 1
eloc 2
c 1
b 1
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
/**
3
 * WP REST 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_REST_Menus' ) ) :
13
14
15
    /**
16
     * WP REST Menus class.
17
     *
18
     * WP API Menus support for WP API v2.
19
     *
20
     * @package WP_API_Menus
21
     * @since 1.2.0
22
     */
23
    class WP_REST_Menus {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
24
25
26
	    /**
27
	     * Get WP API namespace.
28
	     *
29
	     * @since 1.2.0
30
	     * @return string
31
	     */
32
        public static function get_api_namespace() {
33
            return 'wp/v2';
34
        }
35
36
37
	    /**
38
	     * Get WP API Menus namespace.
39
	     *
40
	     * @since 1.2.1
41
	     * @return string
42
	     */
43
	    public static function get_plugin_namespace() {
44
		    return 'wp-api-menus/v2';
45
	    }
46
47
48
        /**
49
         * Register menu routes for WP API v2.
50
         *
51
         * @since  1.2.0
52
         * @return array
53
         */
54
        public function register_routes() {
55
56
            register_rest_route( self::get_plugin_namespace(), '/menus', array(
57
                array(
58
                    'methods'  => WP_REST_Server::READABLE,
59
                    'callback' => array( $this, 'get_menus' ),
60
                )
61
            ) );
62
63
            register_rest_route( self::get_plugin_namespace(), '/menu-html/(?P<menu_id>[a-zA-Z0-9_-]+)', array(
64
                array(
65
                    'methods'  => WP_REST_Server::READABLE,
66
                    'callback' => array( $this, 'get_menu_html' ),
67
                    'args'     => array(
68
                        'context' => array(
69
                        'default' => 'view',
70
                        ),
71
                    ),
72
                )
73
            ) );
74
75
            register_rest_route( self::get_plugin_namespace(), '/menu-html/(?P<id>\d+)', array(
76
                array(
77
                    'methods'  => WP_REST_Server::READABLE,
78
                    'callback' => array( $this, 'get_menu_html' ),
79
                    'args'     => array(
80
                        'context' => array(
81
                        'default' => 'view',
82
                        ),
83
                    ),
84
                )
85
            ) );
86
87
            register_rest_route( self::get_plugin_namespace(), '/menu-locations', array(
88
                array(
89
                    'methods'  => WP_REST_Server::READABLE,
90
                    'callback' => array( $this, 'get_menu_locations' ),
91
                )
92
            ) );
93
94
            register_rest_route( self::get_plugin_namespace(), '/menu-locations/(?P<location>[a-zA-Z0-9_-]+)', array(
95
                array(
96
                    'methods'  => WP_REST_Server::READABLE,
97
                    'callback' => array( $this, 'get_menu_location' ),
98
                )
99
            ) );
100
101
        }
102
103
104
        /**
105
         * Get menus.
106
         *
107
         * @since  1.2.0
108
         * @return array All registered menus
109
         */
110
        public static function get_menus() {
111
112
            $rest_url = trailingslashit( get_rest_url() . self::get_plugin_namespace() . '/menus/' );
113
            $rest_url_base = get_rest_url() . self::get_plugin_namespace();
114
            $wp_menus = wp_get_nav_menus();
115
116
            $i = 0;
117
            $rest_menus = array();
118 View Code Duplication
            foreach ( $wp_menus as $wp_menu ) :
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
119
120
                $menu = (array) $wp_menu;
121
122
                $rest_menus[ $i ]                = $menu;
123
                $rest_menus[ $i ]['ID']          = $menu['term_id'];
124
                $rest_menus[ $i ]['name']        = $menu['name'];
125
                $rest_menus[ $i ]['slug']        = $menu['slug'];
126
                $rest_menus[ $i ]['description'] = $menu['description'];
127
                $rest_menus[ $i ]['count']       = $menu['count'];
128
129
                $rest_menus[ $i ]['meta']['links']['collection'] = $rest_url;
130
                $rest_menus[ $i ]['meta']['links']['self']       = $rest_url . $menu['term_id'];
131
                $rest_menus[ $i ]['meta']['links']['html']       = $rest_url_base . '/menu-html/' . $menu['term_id'];
132
133
                $i ++;
134
            endforeach;
135
136
            return apply_filters( 'rest_menus_format_menus', $rest_menus );
137
        }
138
139
140
        /**
141
         * Get a menu.
142
         *
143
         * @since  1.2.0
144
         * @param  $request
145
         * @return array Menu data
146
         */
147
        public function get_menu( $request ) {
148
149
            $id             = (int) $request['id'];
150
            $rest_url       = get_rest_url() . self::get_plugin_namespace() . '/menus/';
151
            $wp_menu_object = $id ? wp_get_nav_menu_object( $id ) : array();
152
            $wp_menu_items  = $id ? wp_get_nav_menu_items( $id ) : array();
153
154
            $rest_menu = array();
155
156 View Code Duplication
            if ( $wp_menu_object ) :
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
157
158
                $menu = (array) $wp_menu_object;
159
                $rest_menu['ID']          = abs( $menu['term_id'] );
160
                $rest_menu['name']        = $menu['name'];
161
                $rest_menu['slug']        = $menu['slug'];
162
                $rest_menu['description'] = $menu['description'];
163
                $rest_menu['count']       = abs( $menu['count'] );
164
165
                $rest_menu_items = array();
166
                foreach ( $wp_menu_items as $item_object ) {
167
	                $rest_menu_items[] = $this->format_menu_item( $item_object );
168
                }
169
170
                $rest_menu_items = $this->nested_menu_items($rest_menu_items, 0);
171
172
                $rest_menu['items']                       = $rest_menu_items;
173
                $rest_menu['meta']['links']['collection'] = $rest_url;
174
                $rest_menu['meta']['links']['self']       = $rest_url . $id;
175
176
            endif;
177
178
            return apply_filters( 'rest_menus_format_menu', $rest_menu );
179
        }
180
		
181
		
182
183
       /**
184
         * Get a menu rendered in html.
185
         *
186
         * @since  1.2.0
187
         * @param  $request
188
         * @return array Menu data
189
         */
190
        public function get_menu_html( $request ) {
191
192
            $menu_id        = $request['menu_id'];
193
            $rest_url_base  = get_rest_url() . self::get_plugin_namespace();
194
            $wp_menu_object = $menu_id ? wp_get_nav_menu_object( $menu_id) : array();
195
            $wp_menu_items  = $menu_id ? wp_get_nav_menu_items( $menu_id ) : array();
0 ignored issues
show
Unused Code introduced by
$wp_menu_items is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
196
197
			$rest_menu = array();
198
199 View Code Duplication
            if ( $wp_menu_object ) :
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
200
201
                $menu = (array) $wp_menu_object;
202
                $rest_menu['ID']          = abs( $menu['term_id'] );
203
                $rest_menu['name']        = $menu['name'];
204
                $rest_menu['slug']        = $menu['slug'];
205
                $rest_menu['description'] = $menu['description'];
206
                $rest_menu['count']       = abs( $menu['count'] );
207
208
                ob_start();
209
           			wp_nav_menu( array( 'menu' => $menu_id ) );
210
           		$rest_menu['html']=ob_get_clean();
211
212
           		$rest_menu['meta']['links']['collection'] = $rest_url_base . '/menus/';
213
                $rest_menu['meta']['links']['self']       = $rest_url_base . '/menu-html/' . $menu_id;
214
215
            endif;
216
217
            return apply_filters( 'rest_menus_format_menu', $rest_menu );
218
        }
219
        
220
221
        /**
222
         * Handle nested menu items.
223
         *
224
         * Given a flat array of menu items, split them into parent/child items
225
         * and recurse over them to return children nested in their parent.
226
         *
227
         * @since  1.2.0
228
         * @param  $menu_items
229
         * @param  $parent
230
         * @return array
231
         */
232
        private function nested_menu_items( &$menu_items, $parent = null ) {
233
234
            $parents = array();
235
            $children = array();
236
237
            // Separate menu_items into parents & children.
238
            array_map( function( $i ) use ( $parent, &$children, &$parents ){
239
                if ( $i['id'] != $parent && $i['parent'] == $parent ) {
240
                    $parents[] = $i;
241
                } else {
242
                    $children[] = $i;
243
                }
244
            }, $menu_items );
245
246
            foreach ( $parents as &$parent ) {
247
248
                if ( $this->has_children( $children, $parent['id'] ) ) {
249
                    $parent['children'] = $this->nested_menu_items( $children, $parent['id'] );
250
                }
251
            }
252
253
            return $parents;
254
        }
255
256
257
        /**
258
         * Check if a collection of menu items contains an item that is the parent id of 'id'.
259
         *
260
         * @since  1.2.0
261
         * @param  array $items
262
         * @param  int $id
263
         * @return array
264
         */
265
        private function has_children( $items, $id ) {
266
            return array_filter( $items, function( $i ) use ( $id ) {
267
                return $i['parent'] == $id;
268
            } );
269
        }
270
271
272
        /**
273
         * Get menu locations.
274
         *
275
         * @since 1.2.0
276
         * @param  $request
277
         * @return array All registered menus locations
278
         */
279 View Code Duplication
        public static function get_menu_locations( $request ) {
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
280
281
            $locations        = get_nav_menu_locations();
282
            $registered_menus = get_registered_nav_menus();
283
	        $rest_url         = get_rest_url() . self::get_api_namespace() . '/menu-locations/';
284
            $rest_menus       = array();
285
286
            if ( $locations && $registered_menus ) :
287
288
                foreach ( $registered_menus as $slug => $label ) :
289
290
	                // Sanity check
291
	                if ( ! isset( $locations[ $slug ] ) ) {
292
		                continue;
293
	                }
294
295
	                $rest_menus[ $slug ]['ID']                          = $locations[ $slug ];
296
                    $rest_menus[ $slug ]['label']                       = $label;
297
                    $rest_menus[ $slug ]['meta']['links']['collection'] = $rest_url;
298
                    $rest_menus[ $slug ]['meta']['links']['self']       = $rest_url . $slug;
299
300
                endforeach;
301
302
            endif;
303
304
            return $rest_menus;
305
        }
306
307
308
        /**
309
         * Get menu for location.
310
         *
311
         * @since 1.2.0
312
         * @param  $request
313
         * @return array The menu for the corresponding location
314
         */
315
        public function get_menu_location( $request ) {
316
317
            $params     = $request->get_params();
318
            $location   = $params['location'];
319
            $locations  = get_nav_menu_locations();
320
321
            if ( ! isset( $locations[ $location ] ) ) {
322
	            return array();
323
            }
324
325
            $wp_menu = wp_get_nav_menu_object( $locations[ $location ] );
326
            $menu_items = wp_get_nav_menu_items( $wp_menu->term_id );
327
328
			/**
329
			 * wp_get_nav_menu_items() outputs a list that's already sequenced correctly.
330
			 * So the easiest thing to do is to reverse the list and then build our tree
331
			 * from the ground up
332
			 */
333
			$rev_items = array_reverse ( $menu_items );
334
			$rev_menu = array();
335
			$cache = array();
336
			foreach ( $rev_items as $item ) :
337
				$formatted = array(
338
					'ID'          => abs( $item->ID ),
339
					'order'       => (int) $item->menu_order,
340
					'parent'      => abs( $item->menu_item_parent ),
341
					'title'       => $item->title,
342
					'url'         => $item->url,
343
					'attr'        => $item->attr_title,
344
					'target'      => $item->target,
345
					'classes'     => implode( ' ', $item->classes ),
346
					'xfn'         => $item->xfn,
347
					'description' => $item->description,
348
					'object_id'   => abs( $item->object_id ),
349
					'object'      => $item->object,
350
					'type'        => $item->type,
351
					'type_label'  => $item->type_label,
352
					'children'    => array(),
353
				);
354
				// Pickup my children
355
				if ( array_key_exists ( $item->ID , $cache ) ) {
356
					$formatted['children'] = array_reverse ( $cache[ $item->ID ] );
357
				}
358
				
359
            	$formatted = apply_filters( 'rest_menus_format_menu_item', $formatted );
360
				
361
				if ( $item->menu_item_parent != 0 ) {
362
					// Wait for parent to pick me up
363
					if ( array_key_exists ( $item->menu_item_parent , $cache ) ) {
364
						array_push( $cache[ $item->menu_item_parent ], $formatted );
365
					} else {
366
						$cache[ $item->menu_item_parent ] = array( $formatted, );
367
					}
368
				} else {
369
					array_push( $rev_menu, $formatted );
370
				}
371
			endforeach;
372
			return array_reverse ( $rev_menu );
373
        }
374
375
376
        /**
377
         * Returns all child nav_menu_items under a specific parent.
378
         *
379
         * @since   1.2.0
380
         * @param int   $parent_id      The parent nav_menu_item ID
381
         * @param array $nav_menu_items Navigation menu items
382
         * @param bool  $depth          Gives all children or direct children only
383
         * @return  array   returns filtered array of nav_menu_items
384
         */
385 View Code Duplication
        public function get_nav_menu_item_children( $parent_id, $nav_menu_items, $depth = true ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
386
387
            $nav_menu_item_list = array();
388
389
            foreach ( (array) $nav_menu_items as $nav_menu_item ) :
390
391
                if ( $nav_menu_item->menu_item_parent == $parent_id ) :
392
393
                    $nav_menu_item_list[] = $this->format_menu_item( $nav_menu_item, true, $nav_menu_items );
394
395
                    if ( $depth ) {
396
                        if ( $children = $this->get_nav_menu_item_children( $nav_menu_item->ID, $nav_menu_items ) ) {
397
                            $nav_menu_item_list = array_merge( $nav_menu_item_list, $children );
398
                        }
399
                    }
400
401
                endif;
402
403
            endforeach;
404
405
            return $nav_menu_item_list;
406
        }
407
408
409
        /**
410
         * Format a menu item for REST API consumption.
411
         *
412
         * @since  1.2.0
413
         * @param  object|array $menu_item  The menu item
414
         * @param  bool         $children   Get menu item children (default false)
415
         * @param  array        $menu       The menu the item belongs to (used when $children is set to true)
416
         * @return array   a formatted menu item for REST
417
         */
418 View Code Duplication
        public function format_menu_item( $menu_item, $children = false, $menu = array() ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
419
420
            $item = (array) $menu_item;
421
422
            $menu_item = array(
423
                'id'          => abs( $item['ID'] ),
424
                'order'       => (int) $item['menu_order'],
425
                'parent'      => abs( $item['menu_item_parent'] ),
426
                'title'       => $item['title'],
427
                'url'         => $item['url'],
428
                'attr'        => $item['attr_title'],
429
                'target'      => $item['target'],
430
                'classes'     => implode( ' ', $item['classes'] ),
431
                'xfn'         => $item['xfn'],
432
                'description' => $item['description'],
433
                'object_id'   => abs( $item['object_id'] ),
434
                'object'      => $item['object'],
435
                'type'        => $item['type'],
436
                'type_label'  => $item['type_label'],
437
            );
438
439
            if ( $children === true && ! empty( $menu ) ) {
440
	            $menu_item['children'] = $this->get_nav_menu_item_children( $item['ID'], $menu );
441
            }
442
443
            return apply_filters( 'rest_menus_format_menu_item', $menu_item );
444
        }
445
446
447
    }
448
449
450
endif;
451