Passed
Push — master ( e3e9d1...f6667d )
by Claudio
02:21 queued 01:09
created

wp-rest-api-v2-menus.php (21 issues)

1
<?php
2
/*
3
Plugin Name: WP-REST-API V2 Menus
4
Version: 0.7.1
5
Description: Adding menus endpoints on WP REST API v2
6
Author: Claudio La Barbera
7
Author URI: https://thebatclaud.io
8
*/
9
10
/**
11
 * Get all registered menus
12
 * @return array List of menus with slug and description
13
 */
14
function wp_api_v2_menus_get_all_menus() {
15
	$menus = get_terms( 'nav_menu', array( 'hide_empty' => true ) );
0 ignored issues
show
The function get_terms was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

15
	$menus = /** @scrutinizer ignore-call */ get_terms( 'nav_menu', array( 'hide_empty' => true ) );
Loading history...
16
17
	foreach ( $menus as $key => $menu ) {
18
		// check if there is acf installed
19
		if ( class_exists( 'acf' ) ) {
20
			$fields = get_fields( $menu );
0 ignored issues
show
The function get_fields was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

20
			$fields = /** @scrutinizer ignore-call */ get_fields( $menu );
Loading history...
21
			if ( ! empty( $fields ) ) {
22
				foreach ( $fields as $field_key => $item ) {
23
					// add all acf custom fields
24
					$menus[ $key ]->$field_key = $item;
25
				}
26
			}
27
		}
28
	}
29
30
	return $menus;
31
}
32
33
/**
34
 * Get all locations
35
 * @return array List of locations
36
 **/
37
38
function wp_api_v2_menu_get_all_locations() {
39
	$nav_menu_locations = get_nav_menu_locations();
0 ignored issues
show
The function get_nav_menu_locations was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

39
	$nav_menu_locations = /** @scrutinizer ignore-call */ get_nav_menu_locations();
Loading history...
40
	$locations          = new stdClass;
41
	foreach ( $nav_menu_locations as $location_slug => $menu_id ) {
42
		if ( get_term( $location_slug ) !== null ) {
0 ignored issues
show
The function get_term was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

42
		if ( /** @scrutinizer ignore-call */ get_term( $location_slug ) !== null ) {
Loading history...
43
			$locations->{$location_slug} = get_term( $location_slug );
44
		} else {
45
			$locations->{$location_slug} = new stdClass;
46
		}
47
		$locations->{$location_slug}->slug = $location_slug;
48
		$locations->{$location_slug}->menu = get_term( $menu_id );
49
	}
50
51
	return $locations;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $locations returns the type stdClass which is incompatible with the documented return type array.
Loading history...
52
}
53
54
/**
55
 * Get menu's data from his id
56
 *
57
 * @param array $data WP REST API data variable
58
 *
59
 * @return object Menu's data with his items
60
 */
61
function wp_api_v2_locations_get_menu_data( $data ) {
62
	// Create default empty object
63
	$menu = new stdClass;
0 ignored issues
show
The assignment to $menu is dead and can be removed.
Loading history...
64
65
	// this could be replaced with `if (has_nav_menu($data['id']))`
66
	if ( ( $locations = get_nav_menu_locations() ) && isset( $locations[ $data['id'] ] ) ) {
0 ignored issues
show
The function get_nav_menu_locations was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

66
	if ( ( $locations = /** @scrutinizer ignore-call */ get_nav_menu_locations() ) && isset( $locations[ $data['id'] ] ) ) {
Loading history...
67
		// Replace default empty object with the location object
68
		$menu        = get_term( $locations[ $data['id'] ] );
0 ignored issues
show
The function get_term was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

68
		$menu        = /** @scrutinizer ignore-call */ get_term( $locations[ $data['id'] ] );
Loading history...
69
		$menu->items = wp_api_v2_menus_get_menu_items( $locations[ $data['id'] ] );
70
	} else {
71
		return new WP_Error( 'not_found', 'No location has been found with this id or slug: `' . $data['id'] . '`. Please ensure you passed an existing location ID or location slug.', array( 'status' => 404 ) );
0 ignored issues
show
The type WP_Error was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
72
	}
73
74
	// check if there is acf installed
75
	if ( class_exists( 'acf' ) ) {
76
		$fields = get_fields( $menu );
0 ignored issues
show
The function get_fields was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

76
		$fields = /** @scrutinizer ignore-call */ get_fields( $menu );
Loading history...
77
		if ( ! empty( $fields ) ) {
78
			foreach ( $fields as $field_key => $item ) {
79
				// add all acf custom fields
80
				$menu->$field_key = $item;
81
			}
82
		}
83
	}
84
85
	return $menu;
86
}
87
88
/**
89
 * Check if a menu item is child of one of the menu's element passed as reference
90
 *
91
 * @param $parents Menu's items
0 ignored issues
show
Documentation Bug introduced by
The doc comment Menu's at position 0 could not be parsed: Unknown type name 'Menu's' at position 0 in Menu's.
Loading history...
92
 * @param $child Menu's item to check
93
 *
94
 * @return bool True if the parent is found, false otherwise
95
 */
96
function wp_api_v2_menus_dna_test( &$parents, $child ) {
97
	foreach ( $parents as $key => $item ) {
98
		if ( $child->menu_item_parent == $item->ID ) {
99
			if ( ! $item->child_items ) {
100
				$item->child_items = [];
101
			}
102
			array_push( $item->child_items, $child );
103
			return true;
104
		}
105
106
		if($item->child_items) {
107
			if(wp_api_v2_menus_dna_test($item->child_items, $child)) {
108
				return true;
109
			}
110
		}
111
	}
112
113
	return false;
114
}
115
116
/**
117
 * Retrieve items for a specific menu
118
 *
119
 * @param $id Menu id
0 ignored issues
show
The type Menu was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
120
 *
121
 * @return array List of menu items
122
 */
123
function wp_api_v2_menus_get_menu_items( $id ) {
124
	$menu_items = wp_get_nav_menu_items( $id );
0 ignored issues
show
The function wp_get_nav_menu_items was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

124
	$menu_items = /** @scrutinizer ignore-call */ wp_get_nav_menu_items( $id );
Loading history...
125
126
	// check if there is acf installed
127
	if ( class_exists( 'acf' ) ) {
128
		foreach ( $menu_items as $menu_key => $menu_item ) {
129
			$fields = get_fields( $menu_item->ID );
0 ignored issues
show
The function get_fields was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

129
			$fields = /** @scrutinizer ignore-call */ get_fields( $menu_item->ID );
Loading history...
130
			if ( ! empty( $fields ) ) {
131
				foreach ( $fields as $field_key => $item ) {
132
					// add all acf custom fields
133
					$menu_items[ $menu_key ]->$field_key = $item;
134
				}
135
			}
136
		}
137
	}
138
139
	// wordpress does not group child menu items with parent menu items
140
	$child_items = [];
141
	// pull all child menu items into separate object
142
	foreach ( $menu_items as $key => $item ) {
143
		if ( $item->menu_item_parent ) {
144
			array_push( $child_items, $item );
145
			unset( $menu_items[ $key ] );
146
		}
147
	}
148
149
	// push child items into their parent item in the original object
150
	do {
151
		foreach($child_items as $key => $child_item) {
152
			if(wp_api_v2_menus_dna_test($menu_items, $child_item)) {
153
				unset($child_items[$key]);
154
			}
155
		}
156
	} while(count($child_items));
157
158
	return array_values($menu_items);
159
}
160
161
/**
162
 * Get menu's data from his id.
163
 *    It ensures compatibility for previous versions when this endpoint
164
 *    was allowing locations id in place of menus id)
165
 *
166
 * @param array $data WP REST API data variable
167
 *
168
 * @return object Menu's data with his items
169
 */
170
function wp_api_v2_menus_get_menu_data( $data ) {
171
	// This ensure retro compatibility with versions `<= 0.5` when this endpoint
172
	//   was allowing locations id in place of menus id
173
	if ( has_nav_menu( $data['id'] ) ) {
0 ignored issues
show
The function has_nav_menu was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

173
	if ( /** @scrutinizer ignore-call */ has_nav_menu( $data['id'] ) ) {
Loading history...
174
		$menu = wp_api_v2_locations_get_menu_data( $data );
175
	} else if ( is_nav_menu( $data['id'] ) ) {
0 ignored issues
show
The function is_nav_menu was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

175
	} else if ( /** @scrutinizer ignore-call */ is_nav_menu( $data['id'] ) ) {
Loading history...
176
		if ( is_int( $data['id'] ) ) {
177
			$id = $data['id'];
178
		} else {
179
			$id = wp_get_nav_menu_object( $data['id'] );
0 ignored issues
show
The function wp_get_nav_menu_object was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

179
			$id = /** @scrutinizer ignore-call */ wp_get_nav_menu_object( $data['id'] );
Loading history...
180
		}
181
		$menu        = get_term( $id );
0 ignored issues
show
The function get_term was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

181
		$menu        = /** @scrutinizer ignore-call */ get_term( $id );
Loading history...
182
		$menu->items = wp_api_v2_menus_get_menu_items( $id );
183
	} else {
184
		return new WP_Error( 'not_found', 'No menu has been found with this id or slug: `' . $data['id'] . '`. Please ensure you passed an existing menu ID, menu slug, location ID or location slug.', array( 'status' => 404 ) );
185
	}
186
187
	// check if there is acf installed
188
	if ( class_exists( 'acf' ) ) {
189
		$fields = get_fields( $menu );
0 ignored issues
show
The function get_fields was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

189
		$fields = /** @scrutinizer ignore-call */ get_fields( $menu );
Loading history...
190
		if ( ! empty( $fields ) ) {
191
			foreach ( $fields as $field_key => $item ) {
192
				// add all acf custom fields
193
				$menu->$field_key = $item;
194
			}
195
		}
196
	}
197
198
	return $menu;
199
}
200
201
add_action( 'rest_api_init', function () {
0 ignored issues
show
The function add_action was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

201
/** @scrutinizer ignore-call */ 
202
add_action( 'rest_api_init', function () {
Loading history...
202
	register_rest_route( 'menus/v1', '/menus', array(
0 ignored issues
show
The function register_rest_route was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

202
	/** @scrutinizer ignore-call */ 
203
 register_rest_route( 'menus/v1', '/menus', array(
Loading history...
203
		'methods'  => 'GET',
204
		'callback' => 'wp_api_v2_menus_get_all_menus',
205
	) );
206
207
	register_rest_route( 'menus/v1', '/menus/(?P<id>[a-zA-Z0-9_-]+)', array(
208
		'methods'  => 'GET',
209
		'callback' => 'wp_api_v2_menus_get_menu_data',
210
	) );
211
212
	register_rest_route( 'menus/v1', '/locations/(?P<id>[a-zA-Z0-9_-]+)', array(
213
		'methods'  => 'GET',
214
		'callback' => 'wp_api_v2_locations_get_menu_data',
215
	) );
216
217
	register_rest_route( 'menus/v1', '/locations', array(
218
		'methods'  => 'GET',
219
		'callback' => 'wp_api_v2_menu_get_all_locations',
220
	) );
221
} );
222