Passed
Pull Request — master (#19)
by
unknown
01:50
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.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 ) );
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
		// add slug to menu items
144
		$slug = basename( get_permalink($item->object_id) );
0 ignored issues
show
The function get_permalink 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

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