Completed
Push — try/unified-nav ( 0ea6b5 )
by
unknown
21:19
created

WPCOM_REST_API_V2_Endpoint_Admin_Menu   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 223
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 0

Importance

Changes 0
Metric Value
dl 0
loc 223
rs 10
c 0
b 0
f 0
wmc 29
lcom 2
cbo 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A register_routes() 0 12 1
A get_item_permissions_check() 0 3 1
A get_item() 0 8 1
A prepare_item_for_response() 0 22 3
A prepare_menu_item() 0 27 4
A prepare_submenu_item() 0 15 2
A prepare_menu_item_icon() 0 17 6
B prepare_menu_item_url() 0 27 10
1
<?php
2
/**
3
 * REST API endpoint for the admin menu json.
4
 *
5
 * @package A8C
6
 */
7
8
/**
9
 * Class WPCOM_REST_API_V2_Endpoint_Admin_Menu
10
 */
11
class WPCOM_REST_API_V2_Endpoint_Admin_Menu extends WP_REST_Controller {
12
	/**
13
	 * Whether this is a wpcom-specific endpoint.
14
	 *
15
	 * @var bool
16
	 */
17
	public $wpcom_is_wpcom_only_endpoint = true;
18
19
	/**
20
	 * Whether this is a site-specific endpoint.
21
	 *
22
	 * @var bool
23
	 */
24
	public $wpcom_is_site_specific_endpoint = true;
25
26
	/**
27
	 * Namespace prefix.
28
	 *
29
	 * @var string
30
	 */
31
	public $namespace = 'wpcom/v2';
32
33
	/**
34
	 * Endpoint base route.
35
	 *
36
	 * @var string
37
	 */
38
	public $rest_base = 'admin-menu';
39
40
	/**
41
	 * WPCOM_REST_API_V2_Endpoint_Admin_Menu constructor.
42
	 */
43
	public function __construct() {
44
		add_action( 'rest_api_init', array( $this, 'register_routes' ) );
45
	}
46
47
	/**
48
	 * Register routes.
49
	 */
50
	public function register_routes() {
51
		register_rest_route(
52
			$this->namespace,
53
			$this->rest_base . '/',
54
			array(
55
				'show_in_index'       => false,
56
				'methods'             => WP_REST_Server::READABLE,
57
				'callback'            => array( $this, 'get_item' ),
58
				'permission_callback' => array( $this, 'get_item_permissions_check' ),
59
			)
60
		);
61
	}
62
63
	/**
64
	 * Checks if a given request has access to get a specific item.
65
	 *
66
	 * @param WP_REST_Request $request Full details about the request.
67
	 * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise.
68
	 */
69
	public function get_item_permissions_check( $request ) {  // phpcs:ignore
70
		return current_user_can( 'read' );
71
	}
72
73
	/**
74
	 * Retrieves one item from the collection.
75
	 *
76
	 * @param WP_REST_Request $request Full details about the request.
77
	 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
78
	 */
79
	public function get_item( $request ) {
80
		// Both globals need to be declared for menu items to properly register.
81
		global $menu, $submenu; // phpcs:ignore
82
83
		require_once ABSPATH . 'wp-admin/menu.php';
84
85
		return rest_ensure_response( $this->prepare_item_for_response( $menu, $request ) );
86
	}
87
88
	/**
89
	 * Prepares the item for the REST response.
90
	 *
91
	 * @param array           $menu    Admin menu.
92
	 * @param WP_REST_Request $request Request object.
93
	 * @return array Admin menu
94
	 */
95
	public function prepare_item_for_response( $menu, $request ) { // phpcs:ignore
96
		global $submenu;
97
98
		$data = array();
99
100
		foreach ( $menu as $menu_item ) {
101
			$item = $this->prepare_menu_item( $menu_item );
102
103
			if ( ! empty( $submenu[ $menu_item[2] ] ) ) {
104
				$item['children'] = array_map(
105
					function ( $submenu_item ) use ( $menu_item ) {
106
						return $this->prepare_submenu_item( $submenu_item, $menu_item );
107
					},
108
					$submenu[ $menu_item[2] ]
109
				);
110
			}
111
112
			$data[] = $item;
113
		}
114
115
		return array_filter( $data );
116
	}
117
118
	/**
119
	 * Sets up a menu item for consumption by Calypso.
120
	 *
121
	 * @param array $menu_item Menu item.
122
	 * @return array Prepared menu item.
123
	 */
124
	private function prepare_menu_item( $menu_item ) {
125
		if ( ! current_user_can( $menu_item[1] ) ) {
126
			return array();
127
		}
128
129
		if ( false !== strpos( $menu_item[4], 'wp-menu-separator' ) ) {
130
			return array(
131
				'type' => 'separator',
132
			);
133
		}
134
135
		$item = array(
136
			'icon'  => $this->prepare_menu_item_icon( $menu_item[6] ),
137
			'slug'  => sanitize_title_with_dashes( $menu_item[2] ),
138
			'title' => wptexturize( $menu_item[0] ),
139
			'type'  => 'menu-item',
140
			'url'   => $this->prepare_menu_item_url( $menu_item[2] ),
141
		);
142
143
		if ( false !== strpos( $menu_item[0], 'count-' ) ) {
144
			preg_match( '/class="(.+\s)?count-(\d*)/', $menu_item[0], $matches );
145
			$item['count'] = absint( $matches[2] );
146
			$item['title'] = wptexturize( trim( substr( $menu_item[0], 0, strpos( $menu_item[0], '<' ) ) ) );
147
		}
148
149
		return $item;
150
	}
151
152
	/**
153
	 * Sets up a submenu item for consumption by Calypso.
154
	 *
155
	 * @param array $submenu_item Submenu item.
156
	 * @param array $menu_item    Menu item.
157
	 * @return array Prepared submenu item.
158
	 */
159
	private function prepare_submenu_item( $submenu_item, $menu_item ) {
160
		$item = array();
161
162
		if ( current_user_can( $submenu_item[1] ) ) {
163
			$item = array(
164
				'parent' => $menu_item[2],
165
				'slug'   => sanitize_title_with_dashes( $submenu_item[2] ),
166
				'title'  => wptexturize( $submenu_item[0] ),
167
				'type'   => 'submenu-item',
168
				'url'    => $this->prepare_menu_item_url( $submenu_item[2], $menu_item[2] ),
169
			);
170
		}
171
172
		return $item;
173
	}
174
175
	/**
176
	 * Prepares a menu icon for consumption by Calypso.
177
	 *
178
	 * @param string $icon Menu icon.
179
	 * @return string
180
	 */
181
	private function prepare_menu_item_icon( $icon ) {
182
		$img = '';
183
184
		if ( ! empty( $icon ) ) {
185
			$img = '<img src="' . esc_attr( $icon ) . '" alt="" />';
186
187
			if ( 'none' === $icon || 'div' === $icon ) {
188
				$img = '';
189
			} elseif ( 0 === strpos( $icon, 'data:image/svg+xml,' ) ) {
190
				$img = $icon;
191
			} elseif ( 0 === strpos( $icon, 'dashicons-' ) ) {
192
				$img = sanitize_html_class( $icon );
193
			}
194
		}
195
196
		return $img;
197
	}
198
199
	/**
200
	 * Prepares a menu icon for consumption by Calypso.
201
	 *
202
	 * @param string $url         Menu slug.
203
	 * @param string $parent_slug Parent menu item slug.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $parent_slug not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
204
	 * @return string
205
	 */
206
	private function prepare_menu_item_url( $url, $parent_slug = null ) {
207
		if ( 0 === strpos( $url, 'http' ) ) {
208
			$url = str_replace( 'https://wordpress.com', '', $url );
209
		} else {
210
			$menu_hook = get_plugin_page_hook( $url, 'admin.php' );
211
			$menu_file = wp_parse_url( $url, PHP_URL_PATH );
0 ignored issues
show
Unused Code introduced by
The call to wp_parse_url() has too many arguments starting with PHP_URL_PATH.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
212
213
			if (
214
				! empty( $menu_hook ) ||
215
				(
216
					'index.php' !== $url &&
217
					file_exists( WP_PLUGIN_DIR . "/$menu_file" ) &&
218
					! file_exists( ABSPATH . "/wp-admin/$menu_file" )
219
				)
220
			) {
221
				if ( ( 'admin.php' !== $parent_slug && file_exists( WP_PLUGIN_DIR . "/$parent_slug" ) && ! is_dir( WP_PLUGIN_DIR . "/$parent_slug" ) ) || file_exists( ABSPATH . "/wp-admin/$parent_slug" ) ) {
222
					$url = add_query_arg( array( 'page' => $url ), admin_url( $parent_slug ) );
223
				} else {
224
					$url = add_query_arg( array( 'page' => $url ), admin_url( 'admin.php' ) );
225
				}
226
			} else {
227
				$url = admin_url( $url );
228
			}
229
		}
230
231
		return esc_url( $url );
232
	}
233
}
234
235
wpcom_rest_api_v2_load_plugin( 'WPCOM_REST_API_V2_Endpoint_Admin_Menu' );
236