Completed
Push — master ( 929199...154e92 )
by Claudio
17s queued 11s
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.3
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_term($item->object_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

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