PluginProbe
Redirection / 5.8.1
Redirection v5.8.1
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-plugin.php

api-plugin.php in Redirection 5.8.1, at api/api-plugin.php

347 lines 9.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * 'Plugin' functions for Redirection
5 *
6 * @phpstan-import-type DatabaseStatus from Red_Database_Status
7 * @phpstan-import-type FixerJson from Red_Fixer
8 */
9 class Redirection_Api_Plugin extends Redirection_Api_Route {
10 /**
11 * Register REST routes for plugin actions
12 *
13 * @param non-falsy-string $api_namespace REST namespace.
14 * @return void
15 */
16 public function __construct( $api_namespace ) {
17 // GET/POST /plugin - Get plugin status or run fixer
18 register_rest_route(
19 $api_namespace,
20 '/plugin',
21 [
22 [
23 'methods' => WP_REST_Server::READABLE,
24 'callback' => [ $this, 'route_status' ],
25 'permission_callback' => [ $this, 'permission_callback_manage' ],
26 ],
27 [
28 'methods' => WP_REST_Server::EDITABLE,
29 'callback' => [ $this, 'route_fixit' ],
30 'permission_callback' => [ $this, 'permission_callback_manage' ],
31 'args' => [
32 'name' => [
33 'description' => 'Name',
34 'type' => 'string',
35 ],
36 'value' => [
37 'description' => 'Value',
38 'type' => 'string',
39 ],
40 ],
41 ],
42 ]
43 );
44
45 // POST /plugin/delete - Delete plugin data
46 register_rest_route(
47 $api_namespace,
48 '/plugin/delete',
49 [
50 [
51 'methods' => WP_REST_Server::EDITABLE,
52 'callback' => [ $this, 'route_delete' ],
53 'permission_callback' => [ $this, 'permission_callback_manage' ],
54 ],
55 ]
56 );
57
58 // ALL /plugin/test - Test endpoint
59 register_rest_route(
60 $api_namespace,
61 '/plugin/test',
62 [
63 [
64 'methods' => WP_REST_Server::ALLMETHODS,
65 'callback' => [ $this, 'route_test' ],
66 'permission_callback' => [ $this, 'permission_callback_setup' ],
67 ],
68 ]
69 );
70
71 // POST /plugin/data - Database upgrade/status
72 register_rest_route(
73 $api_namespace,
74 '/plugin/data',
75 [
76 [
77 'methods' => WP_REST_Server::EDITABLE,
78 'callback' => [ $this, 'route_database' ],
79 'permission_callback' => [ $this, 'permission_callback_setup' ],
80 'args' => [
81 'upgrade' => [
82 'description' => 'Upgrade parameter',
83 'type' => 'string',
84 'enum' => [
85 'stop',
86 'skip',
87 'retry',
88 ],
89 ],
90 ],
91 ],
92 ]
93 );
94
95 // POST /plugin/finish - Finish setup wizard
96 register_rest_route(
97 $api_namespace,
98 '/plugin/finish',
99 [
100 [
101 'methods' => WP_REST_Server::EDITABLE,
102 'callback' => [ $this, 'route_finish' ],
103 'permission_callback' => [ $this, 'permission_callback_setup' ],
104 ],
105 ]
106 );
107
108 // POST /plugin/fix - Fix database status
109 register_rest_route(
110 $api_namespace,
111 '/plugin/fix',
112 [
113 [
114 'methods' => WP_REST_Server::EDITABLE,
115 'callback' => [ $this, 'route_fix_status' ],
116 'permission_callback' => [ $this, 'permission_callback_setup' ],
117 'args' => [
118 'reason' => [
119 'description' => 'Reason for fix',
120 'type' => 'string',
121 'required' => true,
122 ],
123 'current' => [
124 'description' => 'Current version',
125 'type' => 'string',
126 'required' => true,
127 ],
128 ],
129 ],
130 ]
131 );
132 }
133
134 /**
135 * Permission callback for manage-level actions
136 *
137 * @param WP_REST_Request $request REST request.
138 * @phpstan-param WP_REST_Request<array<string, mixed>> $request
139 * @return bool
140 */
141 public function permission_callback_manage( WP_REST_Request $request ) {
142 return Redirection_Capabilities::has_access( Redirection_Capabilities::CAP_SUPPORT_MANAGE );
143 }
144
145 /**
146 * Permission callback for setup and database upgrade actions
147 *
148 * @param WP_REST_Request $request REST request.
149 * @phpstan-param WP_REST_Request<array<string, mixed>> $request
150 * @return bool
151 */
152 public function permission_callback_setup( WP_REST_Request $request ) {
153 return Redirection_Capabilities::has_access( Redirection_Capabilities::CAP_OPTION_MANAGE ) ||
154 $this->permission_callback_manage( $request );
155 }
156
157 /**
158 * Get fixer status/debug details
159 *
160 * @param WP_REST_Request $request REST request.
161 * @phpstan-param WP_REST_Request<array<string, mixed>> $request
162 * @return FixerJson
163 */
164 public function route_status( WP_REST_Request $request ) {
165 include_once dirname( REDIRECTION_FILE ) . '/models/fixer.php';
166
167 $fixer = new Red_Fixer();
168 return $fixer->get_json();
169 }
170
171 /**
172 * Run fixer or save a specific debug setting
173 *
174 * @param WP_REST_Request $request REST request.
175 * @phpstan-param WP_REST_Request<array<string, mixed>> $request
176 * @return FixerJson|WP_Error
177 */
178 public function route_fixit( WP_REST_Request $request ) {
179 include_once dirname( REDIRECTION_FILE ) . '/models/fixer.php';
180
181 $params = $request->get_params();
182 $fixer = new Red_Fixer();
183
184 if ( isset( $params['name'] ) && isset( $params['value'] ) ) {
185 global $wpdb;
186
187 $fixer->save_debug( sanitize_text_field( $params['name'] ), sanitize_text_field( $params['value'] ) );
188
189 $groups = intval( $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->prefix}redirection_groups" ), 10 );
190 if ( $groups === 0 ) {
191 $group = Red_Group::create( __( 'Redirections', 'redirection' ), 1 );
192
193 if ( $group === false ) {
194 return $this->add_error_details( new WP_Error( 'redirect_group_create_failed', 'Unable to create group' ), __LINE__ );
195 }
196 }
197 } else {
198 $result = $fixer->fix( $fixer->get_status() );
199
200 if ( is_wp_error( $result ) ) {
201 return $this->add_error_details( $result, __LINE__ );
202 }
203 }
204
205 return $fixer->get_json();
206 }
207
208 /**
209 * Delete plugin (single-site only) and redirect back to plugins page
210 *
211 * @return array{location: string}|WP_Error
212 */
213 public function route_delete() {
214 if ( is_multisite() ) {
215 return new WP_Error( 'redirect_delete_multi', 'Multisite installations must delete the plugin from the network admin' );
216 }
217
218 Redirection_Admin::plugin_uninstall();
219
220 $current = get_option( 'active_plugins' );
221 $plugin_position = array_search( basename( dirname( REDIRECTION_FILE ) ) . '/' . basename( REDIRECTION_FILE ), $current, true );
222 if ( $plugin_position !== false ) {
223 array_splice( $current, (int) $plugin_position, 1 );
224 update_option( 'active_plugins', $current );
225 }
226
227 return array( 'location' => admin_url() . 'plugins.php' );
228 }
229
230 /**
231 * Simple plugin test endpoint
232 *
233 * @param WP_REST_Request $request REST request.
234 * @phpstan-param WP_REST_Request<array<string, mixed>> $request
235 * @return array{success: true}
236 */
237 public function route_test( WP_REST_Request $request ) {
238 return array(
239 'success' => true,
240 );
241 }
242
243 /**
244 * Database status/upgrade orchestration
245 *
246 * @param WP_REST_Request $request REST request.
247 * @phpstan-param WP_REST_Request<array<string, mixed>> $request
248 * @return DatabaseStatus
249 */
250 public function route_database( WP_REST_Request $request ) {
251 $params = $request->get_params();
252 $status = new Red_Database_Status();
253 /** @var string|false $upgrade */
254 $upgrade = false;
255
256 if ( isset( $params['upgrade'] ) && in_array( $params['upgrade'], [ 'stop', 'skip' ], true ) ) {
257 $upgrade = sanitize_text_field( $params['upgrade'] );
258 }
259
260 // Check upgrade
261 if ( ! $status->needs_updating() && ! $status->needs_installing() ) {
262 /* translators: version number */
263 $status->set_error( sprintf( __( 'Your database does not need updating to %s.', 'redirection' ), REDIRECTION_DB_VERSION ) );
264
265 return $status->get_json();
266 }
267
268 if ( $upgrade === 'stop' ) {
269 $status->stop_update();
270 } elseif ( $upgrade === 'skip' ) {
271 $status->set_next_stage();
272 }
273
274 $should_upgrade = $upgrade === false || $status->get_current_stage() !== false;
275 if ( $should_upgrade ) {
276 $database = new Red_Database();
277 $database->apply_upgrade( $status );
278 }
279
280 return $status->get_json();
281 }
282
283 /**
284 * Finish setup wizard
285 *
286 * @return array{success: true}
287 */
288 public function route_finish() {
289 $status = new Red_Database_Status();
290 $status->finish();
291
292 return array( 'success' => true );
293 }
294
295 /**
296 * Fix database status after manual upgrade
297 *
298 * @param WP_REST_Request $request REST request.
299 * @phpstan-param WP_REST_Request<array<string, mixed>> $request
300 * @return array{success: true, database: DatabaseStatus}|WP_Error
301 */
302 public function route_fix_status( WP_REST_Request $request ) {
303 global $wpdb;
304
305 $params = $request->get_params();
306 $reason = isset( $params['reason'] ) ? sanitize_text_field( $params['reason'] ) : '';
307 $current = isset( $params['current'] ) ? sanitize_text_field( $params['current'] ) : '';
308
309 // Validate required parameters
310 if ( $reason === '' ) {
311 return $this->add_error_details(
312 new WP_Error( 'redirection_invalid_reason', 'Missing or invalid reason parameter' ),
313 __LINE__
314 );
315 }
316
317 if ( $current === '' ) {
318 return $this->add_error_details(
319 new WP_Error( 'redirection_invalid_version', 'Missing or invalid current version parameter' ),
320 __LINE__
321 );
322 }
323
324 $status = new Red_Database_Status();
325
326 if ( $reason === 'database' ) {
327 $status->save_db_version( $current );
328
329 // After manual database install, ensure default groups are created
330 $latest = Red_Database::get_latest_database();
331 $latest->create_groups( $wpdb, true );
332
333 $status->finish();
334 } else {
335 return $this->add_error_details(
336 new WP_Error( 'redirection_unsupported_reason', "Unsupported reason: $reason" ),
337 __LINE__
338 );
339 }
340
341 return array(
342 'success' => true,
343 'database' => $status->get_json(),
344 );
345 }
346 }
347