Completed
Push — master ( 0e4fe9...f5c78e )
by Fulvio
02:21
created

includes/wp-api-menus-v2.php (1 issue)

a file either defines symbols or has side-effects, but not both.

Coding Style Compatibility Minor

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 23 and the first side effect is on line 9.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

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