Completed
Pull Request — master (#44)
by
unknown
01:25
created

WP_REST_Menus   B

Complexity

Total Complexity 37

Size/Duplication

Total Lines 389
Duplicated Lines 22.11 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 0
Metric Value
wmc 37
lcom 1
cbo 0
dl 86
loc 389
rs 8.6
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A get_api_namespace() 0 3 1
A get_plugin_namespace() 0 3 1
B register_routes() 0 35 1
B get_menus() 16 26 2
B get_menu() 21 33 5
B nested_menu_items() 0 23 5
A has_children() 0 5 1
B get_menu_locations() 27 27 5
B get_menu_location() 0 65 6
B get_nav_menu_item_children() 22 22 5
B format_menu_item() 0 28 3
A get_object_slug() 0 12 2

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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
         */
53
        public function register_routes() {
54
55
            register_rest_route( self::get_plugin_namespace(), '/menus', array(
56
                array(
57
                    'methods'  => WP_REST_Server::READABLE,
58
                    'callback' => array( $this, 'get_menus' ),
59
                )
60
            ) );
61
62
            register_rest_route( self::get_plugin_namespace(), '/menus/(?P<id>\d+)', array(
63
                array(
64
                    'methods'  => WP_REST_Server::READABLE,
65
                    'callback' => array( $this, 'get_menu' ),
66
                    'args'     => array(
67
                        'context' => array(
68
                        'default' => 'view',
69
                        ),
70
                    ),
71
                )
72
            ) );
73
74
            register_rest_route( self::get_plugin_namespace(), '/menu-locations', array(
75
                array(
76
                    'methods'  => WP_REST_Server::READABLE,
77
                    'callback' => array( $this, 'get_menu_locations' ),
78
                )
79
            ) );
80
81
            register_rest_route( self::get_plugin_namespace(), '/menu-locations/(?P<location>[a-zA-Z0-9_-]+)', array(
82
                array(
83
                    'methods'  => WP_REST_Server::READABLE,
84
                    'callback' => array( $this, 'get_menu_location' ),
85
                )
86
            ) );
87
        }
88
89
90
        /**
91
         * Get menus.
92
         *
93
         * @since  1.2.0
94
         * @return array All registered menus
95
         */
96
        public static function get_menus() {
97
98
            $rest_url = trailingslashit( get_rest_url() . self::get_plugin_namespace() . '/menus/' );
99
            $wp_menus = wp_get_nav_menus();
100
101
            $i = 0;
102
            $rest_menus = array();
103 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...
104
105
                $menu = (array) $wp_menu;
106
107
                $rest_menus[ $i ]                = $menu;
108
                $rest_menus[ $i ]['ID']          = $menu['term_id'];
109
                $rest_menus[ $i ]['name']        = $menu['name'];
110
                $rest_menus[ $i ]['slug']        = $menu['slug'];
111
                $rest_menus[ $i ]['description'] = $menu['description'];
112
                $rest_menus[ $i ]['count']       = $menu['count'];
113
114
                $rest_menus[ $i ]['meta']['links']['collection'] = $rest_url;
115
                $rest_menus[ $i ]['meta']['links']['self']       = $rest_url . $menu['term_id'];
116
117
                $i ++;
118
            endforeach;
119
120
            return apply_filters( 'rest_menus_format_menus', $rest_menus );
121
        }
122
123
124
        /**
125
         * Get a menu.
126
         *
127
         * @since  1.2.0
128
         * @param  $request
129
         * @return array Menu data
130
         */
131
        public function get_menu( $request ) {
132
133
            $id             = (int) $request['id'];
134
            $rest_url       = get_rest_url() . self::get_api_namespace() . '/menus/';
135
            $wp_menu_object = $id ? wp_get_nav_menu_object( $id ) : array();
136
            $wp_menu_items  = $id ? wp_get_nav_menu_items( $id ) : array();
137
138
            $rest_menu = array();
139
140 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...
141
142
                $menu = (array) $wp_menu_object;
143
                $rest_menu['ID']          = abs( $menu['term_id'] );
144
                $rest_menu['name']        = $menu['name'];
145
                $rest_menu['slug']        = $menu['slug'];
146
                $rest_menu['description'] = $menu['description'];
147
                $rest_menu['count']       = abs( $menu['count'] );
148
149
                $rest_menu_items = array();
150
                foreach ( $wp_menu_items as $item_object ) {
151
	                $rest_menu_items[] = $this->format_menu_item( $item_object );
152
                }
153
154
                $rest_menu_items = $this->nested_menu_items($rest_menu_items, 0);
155
156
                $rest_menu['items']                       = $rest_menu_items;
157
                $rest_menu['meta']['links']['collection'] = $rest_url;
158
                $rest_menu['meta']['links']['self']       = $rest_url . $id;
159
160
            endif;
161
162
            return apply_filters( 'rest_menus_format_menu', $rest_menu );
163
        }
164
165
166
        /**
167
         * Handle nested menu items.
168
         *
169
         * Given a flat array of menu items, split them into parent/child items
170
         * and recurse over them to return children nested in their parent.
171
         *
172
         * @since  1.2.0
173
         * @param  $menu_items
174
         * @param  $parent
175
         * @return array
176
         */
177
        private function nested_menu_items( &$menu_items, $parent = null ) {
178
179
            $parents = array();
180
            $children = array();
181
182
            // Separate menu_items into parents & children.
183
            array_map( function( $i ) use ( $parent, &$children, &$parents ){
184
                if ( $i['id'] != $parent && $i['parent'] == $parent ) {
185
                    $parents[] = $i;
186
                } else {
187
                    $children[] = $i;
188
                }
189
            }, $menu_items );
190
191
            foreach ( $parents as &$parent ) {
192
193
                if ( $this->has_children( $children, $parent['id'] ) ) {
194
                    $parent['children'] = $this->nested_menu_items( $children, $parent['id'] );
195
                }
196
            }
197
198
            return $parents;
199
        }
200
201
202
        /**
203
         * Check if a collection of menu items contains an item that is the parent id of 'id'.
204
         *
205
         * @since  1.2.0
206
         * @param  array $items
207
         * @param  int $id
208
         * @return array
209
         */
210
        private function has_children( $items, $id ) {
211
            return array_filter( $items, function( $i ) use ( $id ) {
212
                return $i['parent'] == $id;
213
            } );
214
        }
215
216
217
        /**
218
         * Get menu locations.
219
         *
220
         * @since 1.2.0
221
         * @param  $request
222
         * @return array All registered menus locations
223
         */
224 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...
225
226
            $locations        = get_nav_menu_locations();
227
            $registered_menus = get_registered_nav_menus();
228
	        $rest_url         = get_rest_url() . self::get_api_namespace() . '/menu-locations/';
229
            $rest_menus       = array();
230
231
            if ( $locations && $registered_menus ) :
232
233
                foreach ( $registered_menus as $slug => $label ) :
234
235
	                // Sanity check
236
	                if ( ! isset( $locations[ $slug ] ) ) {
237
		                continue;
238
	                }
239
240
	                $rest_menus[ $slug ]['ID']                          = $locations[ $slug ];
241
                    $rest_menus[ $slug ]['label']                       = $label;
242
                    $rest_menus[ $slug ]['meta']['links']['collection'] = $rest_url;
243
                    $rest_menus[ $slug ]['meta']['links']['self']       = $rest_url . $slug;
244
245
                endforeach;
246
247
            endif;
248
249
            return $rest_menus;
250
        }
251
252
253
        /**
254
         * Get menu for location.
255
         *
256
         * @since 1.2.0
257
         * @param  $request
258
         * @return array The menu for the corresponding location
259
         */
260
        public function get_menu_location( $request ) {
261
262
            $params     = $request->get_params();
263
            $location   = $params['location'];
264
            $locations  = get_nav_menu_locations();
265
266
            if ( ! isset( $locations[ $location ] ) ) {
267
	            return array();
268
            }
269
270
            $wp_menu = wp_get_nav_menu_object( $locations[ $location ] );
271
            $menu_items = wp_get_nav_menu_items( $wp_menu->term_id );
272
273
			/**
274
			 * wp_get_nav_menu_items() outputs a list that's already sequenced correctly.
275
			 * So the easiest thing to do is to reverse the list and then build our tree
276
			 * from the ground up
277
			 */
278
			$rev_items = array_reverse ( $menu_items );
279
			$rev_menu  = array();
280
			$cache     = array();
281
282
			foreach ( $rev_items as $item ) :
283
284
				$formatted = array(
285
					'ID'          => abs( $item->ID ),
286
					'order'       => (int) $item->menu_order,
287
					'parent'      => abs( $item->menu_item_parent ),
288
					'title'       => $item->title,
289
					'url'         => $item->url,
290
					'attr'        => $item->attr_title,
291
					'target'      => $item->target,
292
					'classes'     => implode( ' ', $item->classes ),
293
					'xfn'         => $item->xfn,
294
					'description' => $item->description,
295
					'object_id'   => abs( $item->object_id ),
296
					'object'      => $item->object,
297
					'type'        => $item->type,
298
					'type_label'  => $item->type_label,
299
					'children'    => array(),
300
				);
301
302
				if ( array_key_exists( $item->ID , $cache ) ) {
303
					$formatted['children'] = array_reverse( $cache[ $item->ID ] );
304
				}
305
306
            	$formatted = apply_filters( 'rest_menus_format_menu_item', $formatted );
307
308
				if ( $item->menu_item_parent != 0 ) {
309
310
					if ( array_key_exists( $item->menu_item_parent , $cache ) ) {
311
						array_push( $cache[ $item->menu_item_parent ], $formatted );
312
					} else {
313
						$cache[ $item->menu_item_parent ] = array( $formatted, );
314
					}
315
316
				} else {
317
318
					array_push( $rev_menu, $formatted );
319
				}
320
321
			endforeach;
322
323
			return array_reverse ( $rev_menu );
324
        }
325
326
327
        /**
328
         * Returns all child nav_menu_items under a specific parent.
329
         *
330
         * @since   1.2.0
331
         * @param int   $parent_id      The parent nav_menu_item ID
332
         * @param array $nav_menu_items Navigation menu items
333
         * @param bool  $depth          Gives all children or direct children only
334
         * @return array	returns filtered array of nav_menu_items
335
         */
336 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...
337
338
            $nav_menu_item_list = array();
339
340
            foreach ( (array) $nav_menu_items as $nav_menu_item ) :
341
342
                if ( $nav_menu_item->menu_item_parent == $parent_id ) :
343
344
                    $nav_menu_item_list[] = $this->format_menu_item( $nav_menu_item, true, $nav_menu_items );
345
346
                    if ( $depth ) {
347
                        if ( $children = $this->get_nav_menu_item_children( $nav_menu_item->ID, $nav_menu_items ) ) {
348
                            $nav_menu_item_list = array_merge( $nav_menu_item_list, $children );
349
                        }
350
                    }
351
352
                endif;
353
354
            endforeach;
355
356
            return $nav_menu_item_list;
357
        }
358
359
360
        /**
361
         * Format a menu item for REST API consumption.
362
         *
363
         * @since  1.2.0
364
         * @param  object|array $menu_item  The menu item
365
         * @param  bool         $children   Get menu item children (default false)
366
         * @param  array        $menu       The menu the item belongs to (used when $children is set to true)
367
         * @return array	a formatted menu item for REST
368
         */
369
        public function format_menu_item( $menu_item, $children = false, $menu = array() ) {
370
371
            $item = (array) $menu_item;
372
373
            $menu_item = array(
374
                'id'          => abs( $item['ID'] ),
375
                'order'       => (int) $item['menu_order'],
376
                'parent'      => abs( $item['menu_item_parent'] ),
377
                'title'       => $item['title'],
378
                'url'         => $item['url'],
379
                'attr'        => $item['attr_title'],
380
                'target'      => $item['target'],
381
                'classes'     => implode( ' ', $item['classes'] ),
382
                'xfn'         => $item['xfn'],
383
                'description' => $item['description'],
384
                'object_id'   => abs( $item['object_id'] ),
385
                'object'      => $item['object'],
386
                'object_slug' => $this->get_object_slug( $item ),
387
                'type'        => $item['type'],
388
                'type_label'  => $item['type_label'],
389
            );
390
391
            if ( $children === true && ! empty( $menu ) ) {
392
	            $menu_item['children'] = $this->get_nav_menu_item_children( $item['ID'], $menu );
393
            }
394
395
            return apply_filters( 'rest_menus_format_menu_item', $menu_item );
396
        }
397
398
        private function get_object_slug($item){
399
			$slug = '';
0 ignored issues
show
Unused Code introduced by
$slug 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...
400
			
401
			if($item['type'] == 'taxonomy'){
402
                $slug = get_term( $item['object_id'] )->slug;
403
            }
404
            else {
405
                $slug = get_post( $item['object_id'] )->post_name;
406
            }
407
			
408
			return $slug;
409
		}
410
411
    }
412
413
414
endif;
415