PluginProbe
Redirection / 5.1.2
Redirection v5.1.2
5.10.0 5.9.0 5.8.1 5.8.0 3.7.2 3.7.3 4.0 4.0.1 4.1 4.1.1 4.2 4.2.1 4.2.2 4.2.3 4.3 4.3.1 4.3.2 4.3.3 4.4 4.4.1 4.4.2 4.5 4.5.1 4.6.2 4.7.1 All 130 releases
redirection / api / api-redirect.php

api-redirect.php in Redirection 5.1.2, at api/api-redirect.php

405 lines 14.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * @api {get} /redirection/v1/redirect Get redirects
5 * @apiName GetRedirects
6 * @apiDescription Get a paged list of redirects based after applying a set of filters and result ordering.
7 * @apiGroup Redirect
8 *
9 * @apiUse RedirectQueryParams
10 *
11 * @apiUse RedirectList
12 * @apiUse 401Error
13 * @apiUse 404Error
14 */
15
16 /**
17 * @api {post} /redirection/v1/redirect Create redirect
18 * @apiName CreateRedirect
19 * @apiDescription Create a new redirect, and return a paged list of redirects.
20 * @apiGroup Redirect
21 *
22 * @apiUse RedirectItem
23 * @apiUse RedirectQueryParams
24 *
25 * @apiUse RedirectList
26 * @apiUse 401Error
27 * @apiUse 404Error
28 * @apiError (Error 400) redirect_create_failed Failed to create redirect
29 * @apiErrorExample {json} 404 Error Response:
30 * HTTP/1.1 400 Bad Request
31 * {
32 * "code": "redirect_create_failed",
33 * "message": "Failed to create redirect"
34 * }
35 */
36
37 /**
38 * @api {post} /redirection/v1/redirect/:id Update redirect
39 * @apiName UpdateRedirect
40 * @apiDescription Update an existing redirect.
41 * @apiGroup Redirect
42 *
43 * @apiParam (URL) {Integer} :id Redirect ID to update
44 *
45 * @apiUse RedirectItem
46 *
47 * @apiUse RedirectList
48 * @apiUse 401Error
49 * @apiUse 404Error
50 * @apiError (Error 400) redirect_update_failed Failed to update redirect
51 * @apiErrorExample {json} 404 Error Response:
52 * HTTP/1.1 400 Bad Request
53 * {
54 * "code": "redirect_update_failed",
55 * "message": "Failed to update redirect"
56 * }
57 */
58
59 /**
60 * @api {post} /redirection/v1/bulk/redirect/:type Bulk action
61 * @apiName BulkAction
62 * @apiDescription Enable, disable, and delete a set of redirects. The endpoint will return the next page of results after.
63 * performing the action, based on the supplied query parameters. This information can be used to refresh a list displayed to the client.
64 * @apiGroup Redirect
65 *
66 * @apiParam (URL) {String="delete","enable","disable","reset"} :type Type of bulk action that is applied to every item.
67 * @apiParam (Query Parameter) {String[]} [items] Array of redirect IDs to perform the action on
68 * @apiParam (Query Parameter) {Boolean=false} [global] Perform action globally using the filter parameters
69 * @apiUse RedirectQueryParams
70 *
71 * @apiUse RedirectList
72 * @apiUse 401Error
73 * @apiUse 404Error
74 * @apiUse 400MissingError
75 */
76
77 /**
78 * @apiDefine RedirectItem Redirect
79 * All data associated with a redirect
80 *
81 * @apiParam {String="enabled","disabled"} status Status of the redirect
82 * @apiParam {Integer} position Redirect position, used to determine order multiple redirects occur
83 * @apiParam {Object} match_data Additional match parameters
84 * @apiParam {Object} match_data.source Match against the source
85 * @apiParam {Boolean} match_data.source.flag_regex `true` for regular expression, `false` otherwise
86 * @apiParam {String="ignore","exact","pass"} match_data.source.flag_query Which query parameter matching to use
87 * @apiParam {Boolean} match_data.source.flag_case] `true` for case insensitive matches, `false` otherwise
88 * @apiParam {Boolean} match_data.source.flag_trailing] `true` to ignore trailing slashes, `false` otherwise
89 * @apiParam {Object} match_data.options Options for the redirect match
90 * @apiParam {Boolean} match_data.options.log_exclude `true` to exclude this from any logs, `false` otherwise (default)
91 * @apiParam {Boolean} regex True for regular expression, `false` otherwise
92 * @apiParam {String} url The source URL
93 * @apiParam {String="url","referrer","agent","login","header","custom","cookie","role","server","ip","page","language"} match_type What URL matching to use
94 * @apiParam {String} [title] A descriptive title for the redirect, or empty for no title
95 * @apiParam {Integer} group_id The group this redirect belongs to
96 * @apiParam {String} action_type What to do when the URL is matched
97 * @apiParam {Integer} action_code The HTTP code to return
98 * @apiParam {String} action_data Any data associated with the `action_type` and `match_type`. For example, the target URL
99 */
100
101 /**
102 * @apiDefine RedirectList A list of redirects
103 * A list of redirects
104 *
105 * @apiSuccess {Object[]} items Array of redirect objects
106 * @apiSuccess {Integer} items.id ID of redirect
107 * @apiSuccess {String} items.url Source URL to match
108 * @apiSuccess {String} items.match_url Match URL
109 * @apiSuccess {Object} items.match_data Match against the source
110 * @apiSuccess {String} items.match_type What URL matching to use
111 * @apiSuccess {String} items.action_type What to do when the URL is matched
112 * @apiSuccess {Integer} items.action_code The HTTP code to return
113 * @apiSuccess {String} items.action_data Any data associated with the action_type. For example, the target URL
114 * @apiSuccess {String} items.title Optional A descriptive title for the redirect, or empty for no title
115 * @apiSuccess {String} items.hits Number of hits this redirect has received
116 * @apiSuccess {String} items.regex True for regular expression, false otherwise
117 * @apiSuccess {String} items.group_id The group this redirect belongs to
118 * @apiSuccess {String} items.position Redirect position, used to determine order multiple redirects occur
119 * @apiSuccess {String} items.last_access The date this redirect was last hit
120 * @apiSuccess {String} items.status Status of the redirect
121 * @apiSuccess {Integer} total Number of items
122 *
123 * @apiSuccessExample {json} Success-Response:
124 * HTTP/1.1 200 OK
125 * {
126 * "items": [
127 * {
128 * id: 3,
129 * url: "/source",
130 * match_url: "/source",
131 * match_data: "",
132 * action_code: "",
133 * action_type: "",
134 * action_data: "",
135 * match_type: "url",
136 * title: "Redirect title",
137 * hits: 5,
138 * regex: true,
139 * group_id: 15,
140 * position: 1,
141 * last_access: "2019-01-01 01:01:01"
142 * status: "enabled"
143 * }
144 * ],
145 * "total": 1
146 * }
147 */
148
149 /**
150 * @apiDefine RedirectQueryParams
151 *
152 * @apiParam (Query Parameter) {String="enabled","disabled"} [filterBy[status]] Filter the results by the supplied status
153 * @apiParam (Query Parameter) {String} [filterBy[url]] Filter the results by the supplied URL
154 * @apiParam (Query Parameter) {String="regular","plain"} [filterBy[url-match]] Filter the results by `regular` expressions or non regular expressions
155 * @apiParam (Query Parameter) {String} [filterBy[match]] Filter the results by the supplied match type
156 * @apiParam (Query Parameter) {String} [filterBy[action]] Filter the results by the supplied action type
157 * @apiParam (Query Parameter) {Integer} [filterBy[http]] Filter the results by the supplied redirect HTTP code
158 * @apiParam (Query Parameter) {String="year","month","all"} [filterBy[access]] Filter the results by how long the redirect was last accessed
159 * @apiParam (Query Parameter) {String} [filterBy[target]] Filter the results by the supplied redirect target
160 * @apiParam (Query Parameter) {String} [filterBy[title]] Filter the results by the supplied redirect title
161 * @apiParam (Query Parameter) {Integer} [filterBy[group]] Filter the results by the supplied redirect group ID
162 * @apiParam (Query Parameter) {Integer} [filterBy[id]] Filter the results to the redirect ID
163 * @apiParam (Query Parameter) {Integer="1","2","3"} [filterBy[module]] Filter the results by the supplied module ID
164 * @apiParam (Query Parameter) {String="source","last_count","last_access","position","id"} [orderby=id] Order in which results are returned
165 * @apiParam (Query Parameter) {String="asc","desc"} [direction=desc] Direction to order the results by (ascending or descending)
166 * @apiParam (Query Parameter) {Integer{1...200}} [per_page=25] Number of results per request
167 * @apiParam (Query Parameter) {Integer} [page=0] Current page of results
168 */
169
170 /**
171 * Redirect API endpoint
172 */
173 class Redirection_Api_Redirect extends Redirection_Api_Filter_Route {
174 /**
175 * Redirect API endpoint constructor
176 *
177 * @param String $namespace Namespace.
178 */
179 public function __construct( $namespace ) {
180 $orders = [ 'source', 'last_count', 'last_access', 'position', 'id', '' ];
181 $filters = [ 'status', 'url-match', 'match', 'action', 'http', 'access', 'url', 'target', 'title', 'group', 'id' ];
182
183 register_rest_route( $namespace, '/redirect', array(
184 'args' => $this->get_filter_args( $orders, $filters ),
185 $this->get_route( WP_REST_Server::READABLE, 'route_list', [ $this, 'permission_callback_manage' ] ),
186 $this->get_route( WP_REST_Server::EDITABLE, 'route_create', [ $this, 'permission_callback_add' ] ),
187 ) );
188
189 register_rest_route( $namespace, '/redirect/(?P<id>[\d]+)', array(
190 $this->get_route( WP_REST_Server::EDITABLE, 'route_update', [ $this, 'permission_callback_add' ] ),
191 ) );
192
193 register_rest_route( $namespace, '/redirect/post', array(
194 $this->get_route( WP_REST_Server::READABLE, 'route_match_post', [ $this, 'permission_callback_manage' ] ),
195 'args' => [
196 'text' => [
197 'description' => 'Text to match',
198 'type' => 'string',
199 'required' => true,
200 ],
201 ],
202 ) );
203
204 register_rest_route( $namespace, '/bulk/redirect/(?P<bulk>delete|enable|disable|reset)', array(
205 $this->get_route( WP_REST_Server::EDITABLE, 'route_bulk', [ $this, 'permission_callback_bulk' ] ),
206 'args' => array_merge( $this->get_filter_args( $orders, $filters ), [
207 'global' => [
208 'description' => 'Apply bulk action globally, as per filters',
209 'type' => 'boolean',
210 ],
211 'items' => [
212 'description' => 'Array of IDs to perform action on',
213 'type' => 'array',
214 'items' => [
215 'description' => 'Item ID',
216 'type' => [ 'string', 'number' ],
217 ],
218 ],
219 ] ),
220 ) );
221 }
222
223 /**
224 * Checks a manage capability
225 *
226 * @param WP_REST_Request $request Request.
227 * @return Bool
228 */
229 public function permission_callback_manage( WP_REST_Request $request ) {
230 return Redirection_Capabilities::has_access( Redirection_Capabilities::CAP_REDIRECT_MANAGE );
231 }
232
233 /**
234 * Checks a bulk capability
235 *
236 * @param WP_REST_Request $request Request.
237 * @return Bool
238 */
239 public function permission_callback_bulk( WP_REST_Request $request ) {
240 if ( $request['bulk'] === 'delete' ) {
241 return Redirection_Capabilities::has_access( Redirection_Capabilities::CAP_REDIRECT_DELETE );
242 }
243
244 return $this->permission_callback_add( $request );
245 }
246
247 /**
248 * Checks a create capability
249 *
250 * @param WP_REST_Request $request Request.
251 * @return Bool
252 */
253 public function permission_callback_add( WP_REST_Request $request ) {
254 return Redirection_Capabilities::has_access( Redirection_Capabilities::CAP_REDIRECT_ADD );
255 }
256
257 /**
258 * Get redirect list
259 *
260 * @param WP_REST_Request $request The request.
261 * @return WP_Error|array Return an array of results, or a WP_Error
262 */
263 public function route_list( WP_REST_Request $request ) {
264 return Red_Item::get_filtered( $request->get_params() );
265 }
266
267 /**
268 * Get redirect list
269 *
270 * @param WP_REST_Request $request The request.
271 * @return WP_Error|array Return an array of results, or a WP_Error
272 */
273 public function route_create( WP_REST_Request $request ) {
274 $params = $request->get_params();
275 $urls = array();
276
277 if ( isset( $params['url'] ) ) {
278 $urls = array( $params['url'] );
279
280 if ( is_array( $params['url'] ) ) {
281 $urls = $params['url'];
282 }
283
284 // Remove duplicates
285 $unique = [];
286 foreach ( $urls as $url ) {
287 $unique[ $url ] = $url;
288 }
289
290 foreach ( $unique as $url ) {
291 $params['url'] = $url;
292 $redirect = Red_Item::create( $params );
293
294 if ( is_wp_error( $redirect ) ) {
295 return $this->add_error_details( $redirect, __LINE__ );
296 }
297 }
298 }
299
300 return $this->route_list( $request );
301 }
302
303 /**
304 * Update redirect
305 *
306 * @param WP_REST_Request $request The request.
307 * @return WP_Error|array Return an array of results, or a WP_Error
308 */
309 public function route_update( WP_REST_Request $request ) {
310 $params = $request->get_params();
311 $redirect = Red_Item::get_by_id( intval( $params['id'], 10 ) );
312
313 if ( $redirect ) {
314 $result = $redirect->update( $params );
315
316 if ( is_wp_error( $result ) ) {
317 return $this->add_error_details( $result, __LINE__ );
318 }
319
320 return [ 'item' => $redirect->to_json() ];
321 }
322
323 return $this->add_error_details( new WP_Error( 'redirect_update_failed', 'Invalid redirect details' ), __LINE__ );
324 }
325
326 /**
327 * Perform bulk action on redirects
328 *
329 * @param WP_REST_Request $request The request.
330 * @return WP_Error|array Return an array of results, or a WP_Error
331 */
332 public function route_bulk( WP_REST_Request $request ) {
333 $params = $request->get_params();
334 $action = $request['bulk'];
335
336 if ( isset( $params['items'] ) && is_array( $params['items'] ) ) {
337 $items = $params['items'];
338
339 foreach ( $items as $item ) {
340 $redirect = Red_Item::get_by_id( intval( $item, 10 ) );
341
342 if ( $redirect === false ) {
343 return $this->add_error_details( new WP_Error( 'redirect_bulk_failed', 'Invalid redirect' ), __LINE__ );
344 }
345
346 if ( $action === 'delete' ) {
347 $redirect->delete();
348 } elseif ( $action === 'disable' ) {
349 $redirect->disable();
350 } elseif ( $action === 'enable' ) {
351 $redirect->enable();
352 } elseif ( $action === 'reset' ) {
353 $redirect->reset();
354 }
355 }
356 } elseif ( isset( $params['global'] ) && $params['global'] ) {
357 if ( $action === 'delete' ) {
358 Red_Item::delete_all( $params );
359 } elseif ( $action === 'reset' ) {
360 Red_Item::reset_all( $params );
361 } elseif ( $action === 'enable' || $action === 'disable' ) {
362 Red_Item::set_status_all( $action, $params );
363 }
364 }
365
366 return $this->route_list( $request );
367 }
368
369 /**
370 * Search for a post
371 *
372 * @param WP_REST_Request $request The request.
373 * @return WP_Error|array Return an array of results, or a WP_Error
374 */
375 public function route_match_post( WP_REST_Request $request ) {
376 global $wpdb;
377
378 $params = $request->get_params();
379 $search = $params['text'];
380 $results = [];
381
382 $posts = $wpdb->get_results(
383 $wpdb->prepare(
384 "SELECT ID,post_title,post_name FROM $wpdb->posts WHERE post_status='publish' AND (post_title LIKE %s OR post_name LIKE %s) " .
385 "AND post_type IN ('post','page')",
386 '%' . $wpdb->esc_like( $search ) . '%', '%' . $wpdb->esc_like( $search ) . '%'
387 )
388 );
389
390 foreach ( (array) $posts as $post ) {
391 $title = $post->post_name;
392 if ( strpos( $post->post_title, $search ) ) {
393 $title = $post->post_title;
394 }
395
396 $results[] = [
397 'title' => $title,
398 'value' => get_permalink( $post->ID ),
399 ];
400 }
401
402 return $results;
403 }
404 }
405