Passed
Push — master ( 7eda45...1783df )
by Claudio
01:41
created

wp-rest-api-v2-menus.php (1 issue)

Labels
Severity
1
<?php
2
/*
3
Plugin Name: WP-REST-API V2 Menus
4
Version: 0.7.2
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 ) );
16
17
	foreach ( $menus as $key => $menu ) {
18
		// check if there is acf installed
19
		if ( class_exists( 'acf' ) ) {
20
			$fields = get_fields( $menu );
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();
40
	$locations          = new stdClass;
41
	foreach ( $nav_menu_locations as $location_slug => $menu_id ) {
42
		if ( get_term( $location_slug ) !== null ) {
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;
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;
64
65
	// this could be replaced with `if (has_nav_menu($data['id']))`
66
	if ( ( $locations = get_nav_menu_locations() ) && isset( $locations[ $data['id'] ] ) ) {
67
		// Replace default empty object with the location object
68
		$menu        = get_term( $locations[ $data['id'] ] );
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 ) );
72
	}
73
74
	// check if there is acf installed
75
	if ( class_exists( 'acf' ) ) {
76
		$fields = get_fields( $menu );
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
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
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 );
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 );
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
144
		if($item->type == 'post_type') {
145
			// add slug to menu items
146
			$slug = basename( get_permalink($item->object_id) );
147
			$item->slug = $slug;
148
		} else if($item->type == 'taxonomy') {
149
			$cat = get_category($item->object_id);
0 ignored issues
show
The function get_category 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

149
			$cat = /** @scrutinizer ignore-call */ get_category($item->object_id);
Loading history...
150
			$item->slug = $cat->slug;
151
		}
152
153
		if ( $item->menu_item_parent ) {
154
			array_push( $child_items, $item );
155
			unset( $menu_items[ $key ] );
156
		}
157
	}
158
159
	// push child items into their parent item in the original object
160
	do {
161
		foreach($child_items as $key => $child_item) {
162
			if(wp_api_v2_menus_dna_test($menu_items, $child_item)) {
163
				unset($child_items[$key]);
164
			}
165
		}
166
	} while(count($child_items));
167
168
	return array_values($menu_items);
169
}
170
171
/**
172
 * Get menu's data from his id.
173
 *    It ensures compatibility for previous versions when this endpoint
174
 *    was allowing locations id in place of menus id)
175
 *
176
 * @param array $data WP REST API data variable
177
 *
178
 * @return object Menu's data with his items
179
 */
180
function wp_api_v2_menus_get_menu_data( $data ) {
181
	// This ensure retro compatibility with versions `<= 0.5` when this endpoint
182
	//   was allowing locations id in place of menus id
183
	if ( has_nav_menu( $data['id'] ) ) {
184
		$menu = wp_api_v2_locations_get_menu_data( $data );
185
	} else if ( is_nav_menu( $data['id'] ) ) {
186
		if ( is_int( $data['id'] ) ) {
187
			$id = $data['id'];
188
		} else {
189
			$id = wp_get_nav_menu_object( $data['id'] );
190
		}
191
		$menu        = get_term( $id );
192
		$menu->items = wp_api_v2_menus_get_menu_items( $id );
193
	} else {
194
		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 ) );
195
	}
196
197
	// check if there is acf installed
198
	if ( class_exists( 'acf' ) ) {
199
		$fields = get_fields( $menu );
200
		if ( ! empty( $fields ) ) {
201
			foreach ( $fields as $field_key => $item ) {
202
				// add all acf custom fields
203
				$menu->$field_key = $item;
204
			}
205
		}
206
	}
207
208
	return $menu;
209
}
210
211
add_action( 'rest_api_init', function () {
212
	register_rest_route( 'menus/v1', '/menus', array(
213
		'methods'  => 'GET',
214
		'callback' => 'wp_api_v2_menus_get_all_menus',
215
	) );
216
217
	register_rest_route( 'menus/v1', '/menus/(?P<id>[a-zA-Z0-9_-]+)', array(
218
		'methods'  => 'GET',
219
		'callback' => 'wp_api_v2_menus_get_menu_data',
220
	) );
221
222
	register_rest_route( 'menus/v1', '/locations/(?P<id>[a-zA-Z0-9_-]+)', array(
223
		'methods'  => 'GET',
224
		'callback' => 'wp_api_v2_locations_get_menu_data',
225
	) );
226
227
	register_rest_route( 'menus/v1', '/locations', array(
228
		'methods'  => 'GET',
229
		'callback' => 'wp_api_v2_menu_get_all_locations',
230
	) );
231
} );
232