PluginProbe
MainWP Dashboard: Self-hosted WordPress Management for Agencies / trunk
MainWP Dashboard: Self-hosted WordPress Management for Agencies vtrunk
6.2 6.1.8 6.1.7 6.1.6 6.1.5 6.1.4 6.1.3 6.1.2 6.1.1 6.1 6.0.12 6.0.11 4.6.0.1 5.0 5.0.1 5.0.2 5.0.3 5.0.3.1 5.0.3.2 5.1 5.1.1 5.2 5.2.1 5.2.2 5.3 All 153 releases
mainwp / class / class-mainwp-post-extension-handler.php

class-mainwp-post-extension-handler.php in MainWP Dashboard: Self-hosted WordPress Management for Agencies trunk, at class/class-mainwp-post-extension-handler.php

550 lines 24.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * This class extends the MainWP Post Base Handler class
4 * to add support for MainWP Extensions.
5 *
6 * @package MainWP/Dashboard
7 */
8
9 namespace MainWP\Dashboard;
10
11 // Exit if accessed directly.
12 if ( ! defined( 'ABSPATH' ) ) {
13 exit;
14 }
15
16 /**
17 * Class MainWP_Post_Extension_Handler
18 *
19 * @package MainWP\Dashboard
20 *
21 * @uses \MainWP\Dashboard\MainWP_Post_Base_Handler
22 */
23 class MainWP_Post_Extension_Handler extends MainWP_Post_Base_Handler { // phpcs:ignore Generic.Classes.OpeningBraceSameLine.ContentAfterBrace -- NOSONAR.
24
25 /**
26 * Public static varibale to hold the instance.
27 *
28 * @var null Default value.
29 */
30 private static $instance = null;
31
32 /**
33 * Method instance()
34 *
35 * Create public static instance.
36 *
37 * @return self $instance.
38 */
39 public static function instance() {
40 if ( null === static::$instance ) {
41 static::$instance = new self();
42 }
43 return static::$instance;
44 }
45
46 /**
47 * Init extensions actions
48 *
49 * @uses \MainWP\Dashboard\MainWP_Extensions::get_class_name()
50 */
51 public function init() {
52
53 $this->add_action( 'mainwp_extension_add_menu', array( &$this, 'add_extension_menu' ) );
54 $this->add_action( 'mainwp_extension_remove_menu', array( &$this, 'remove_extension_menu_from_mainwp_menu' ) );
55
56 $this->add_action( 'mainwp_extension_api_activate', array( &$this, 'activate_api_extension' ) );
57 $this->add_action( 'mainwp_extension_deactivate', array( &$this, 'deactivate_extension' ) );
58 $this->add_action( 'mainwp_extension_testextensionapilogin', array( &$this, 'test_extensions_api_login' ) );
59
60 $this->add_action( 'mainwp_extension_plugin_action', array( &$this, 'ajax_extension_plugin_action' ) );
61
62 if ( \mainwp_current_user_can( 'dashboard', 'manage_extensions' ) ) {
63 $this->add_action( 'mainwp_extension_update_check_retry', array( &$this, 'retry_extension_update_check' ) );
64 }
65
66 if ( \mainwp_current_user_can( 'dashboard', 'bulk_install_and_activate_extensions' ) ) {
67 $this->add_action( 'mainwp_extension_grabapikey', array( &$this, 'grab_extension_api_key' ) );
68 $this->add_action( 'mainwp_extension_saveextensionapilogin', array( &$this, 'save_extensions_api_login' ) );
69 $this->add_action( 'mainwp_extension_getpurchased', array( MainWP_Extensions::get_class_name(), 'ajax_get_purchased_extensions' ) );
70 $this->add_action( 'mainwp_extension_downloadandinstall', array( &$this, 'download_and_install' ) );
71 $this->add_action( 'mainwp_extension_bulk_activate', array( &$this, 'bulk_activate' ) );
72 $this->add_action( 'mainwp_extension_apisslverifycertificate', array( &$this, 'save_api_ssl_verify' ) );
73 }
74
75 // Page: ManageSites.
76 $this->add_action( 'mainwp_ext_applypluginsettings', array( &$this, 'mainwp_ext_applypluginsettings' ) );
77 }
78
79 /**
80 * Retry Add-on update checks.
81 */
82 public function retry_extension_update_check() {
83 $this->check_security( 'mainwp_extension_update_check_retry' );
84
85 if ( ! \mainwp_current_user_can( 'dashboard', 'manage_extensions' ) ) {
86 wp_send_json( array( 'error' => esc_html__( 'You are not allowed to manage Add-ons.', 'mainwp' ) ) );
87 }
88
89 if ( MainWP_System_Handler::instance()->retry_extension_update_check() ) {
90 wp_send_json( array( 'result' => 'SUCCESS' ) );
91 }
92
93 wp_send_json( array( 'error' => esc_html__( 'The update check is still failing. Make sure your MainWP Dashboard can connect to mainwp.com, then try again.', 'mainwp' ) ) );
94 }
95
96 /**
97 * Apply plugin settings.
98 *
99 * @return mixed success|error.
100 *
101 * @uses \MainWP\Dashboard\MainWP_Manage_Sites_Handler::apply_plugin_settings()
102 */
103 public function mainwp_ext_applypluginsettings() {
104 $this->check_security( 'mainwp_ext_applypluginsettings' );
105 MainWP_Manage_Sites_Handler::apply_plugin_settings();
106 }
107
108 /**
109 * Ajax add extension menu.
110 *
111 * @return void
112 *
113 * @uses \MainWP\Dashboard\MainWP_Extensions_Handler::add_extension_menu()
114 */
115 public function add_extension_menu() {
116 $this->check_security( 'mainwp_extension_add_menu' );
117 $slug = isset( $_POST['slug'] ) ? wp_unslash( $_POST['slug'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
118 MainWP_Extensions_Handler::add_extension_menu( $slug );
119 die( wp_json_encode( array( 'result' => 'SUCCESS' ) ) );
120 }
121
122 /**
123 * Activate MainWP Extension.
124 *
125 * @return void
126 *
127 * @uses \MainWP\Dashboard\MainWP_Api_Manager::license_key_activation()
128 * @uses \MainWP\Dashboard\MainWP_Deprecated_Hooks::maybe_handle_deprecated_hook()
129 */
130 public function activate_api_extension() {
131 $this->check_security( 'mainwp_extension_api_activate' );
132 MainWP_Deprecated_Hooks::maybe_handle_deprecated_hook();
133 $api_slug = isset( $_POST['slug'] ) ? dirname( wp_unslash( $_POST['slug'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
134 $api_key = isset( $_POST['key'] ) ? sanitize_text_field( wp_unslash( $_POST['key'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
135 $result = MainWP_Api_Manager::instance()->license_key_activation( $api_slug, $api_key );
136 wp_send_json( $result );
137 }
138
139
140 /**
141 * Handle MainWP Extension plugin actions.
142 *
143 * @return void
144 */
145 public function ajax_extension_plugin_action() {
146 $this->check_security( 'mainwp_extension_plugin_action' );
147 $plugin_slug = isset( $_POST['slug'] ) ? sanitize_text_field( wp_unslash( $_POST['slug'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
148 $action = isset( $_POST['what'] ) ? sanitize_text_field( wp_unslash( $_POST['what'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
149 if ( ! empty( $plugin_slug ) && in_array( $action, array( 'active', 'disable', 'remove' ) ) ) {
150 $this->invalidate_warm_cache();
151 if ( 'disable' === $action ) {
152 if ( is_plugin_active( $plugin_slug ) ) {
153 deactivate_plugins( $plugin_slug, false );
154 }
155 wp_send_json( array( 'result' => 'SUCCESS' ) );
156 } elseif ( 'active' === $action ) {
157 if ( ! is_plugin_active( $plugin_slug ) ) {
158 activate_plugin( $plugin_slug, '', false, false );
159 }
160 wp_send_json( array( 'result' => 'SUCCESS' ) );
161
162 } elseif ( 'remove' === $action ) {
163 $status = $this->delete_extension_plugin( $plugin_slug );
164 wp_send_json( $status );
165 }
166 }
167 wp_send_json( array( 'error' => esc_html__( 'Invalid data provided.', 'mainwp' ) ) );
168 }
169
170
171 /**
172 * Method invalidate_warm_cache()
173 */
174 public function invalidate_warm_cache() {
175 MainWP_Cache_Warm_Helper::invalidate_manage_pages( array( 'Extensions' ) );
176 }
177
178 /**
179 * Delete MainWP Extension plugin.
180 *
181 * @param string $plugin_slug plugin slug.
182 *
183 * @return array $status Status result.
184 */
185 public function delete_extension_plugin( $plugin_slug ) {
186
187 $status = array();
188 if ( ! empty( $plugin_slug ) ) {
189 // Check filesystem credentials.
190 $url = wp_nonce_url( 'plugins.php?action=delete-selected&verify-delete=1&checked[]=' . $plugin_slug, 'bulk-plugins' );
191 ob_start();
192 $credentials = request_filesystem_credentials( $url );
193 ob_end_clean();
194
195 if ( false === $credentials || ! WP_Filesystem( $credentials ) ) {
196 global $wp_filesystem;
197 $status['error'] = esc_html__( 'Unable to connect to the filesystem. Please confirm your credentials.', 'mainwp' );
198 // Pass through the error from WP_Filesystem if one was raised.
199 if ( $wp_filesystem instanceof WP_Filesystem_Base && is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->has_errors() ) {
200 $status['error'] = esc_html( $wp_filesystem->errors->get_error_message() );
201 }
202 return $status;
203 }
204
205 $result = delete_plugins( array( $plugin_slug ) );
206
207 if ( is_wp_error( $result ) ) {
208 $status['error'] = $result->get_error_message();
209 return $status;
210 } elseif ( false === $result ) {
211 $status['error'] = esc_html__( 'Plugin could not be deleted.', 'mainwp' );
212 return $status;
213 }
214 $status['result'] = 'SUCCESS';
215
216 return $status;
217 }
218 return $status;
219 }
220
221
222 /**
223 * Deactivate MainWP Extension.
224 *
225 * @return void
226 *
227 * @uses \MainWP\Dashboard\MainWP_Api_Manager::license_key_deactivation()
228 * @uses \MainWP\Dashboard\MainWP_Deprecated_Hooks::maybe_handle_deprecated_hook()
229 */
230 public function deactivate_extension() {
231 $this->check_security( 'mainwp_extension_deactivate' );
232 $api_slug = isset( $_POST['slug'] ) ? dirname( wp_unslash( $_POST['slug'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
233 $api_key = isset( $_POST['api_key'] ) ? wp_unslash( $_POST['api_key'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
234 // MWP-1546: the hidden input on the Extensions card now renders the
235 // sentinel placeholder instead of the plaintext per-extension license
236 // key. Resolve the sentinel server-side using the slug so the
237 // deactivation request gets the real key from the (now-encrypted)
238 // per-slug option rather than forwarding the placeholder.
239 //
240 // CR follow-up: if the stored key cannot be recovered (option
241 // missing, decrypt failed, etc.), bail with an error rather
242 // than forwarding an empty key. license_key_deactivation()
243 // takes its local-clear fast path on empty $api_key and
244 // returns SUCCESS without ever calling the licensing API,
245 // which would silently leave the activation slot allocated
246 // upstream while telling the operator everything is fine.
247 if ( MainWP_Credential_Render::is_sentinel( $api_key ) ) {
248 $info = MainWP_Api_Manager::instance()->get_activation_info( $api_slug );
249 if ( ! is_array( $info ) || empty( $info['api_key'] ) || ! is_string( $info['api_key'] ) ) {
250 wp_send_json(
251 array(
252 'error' => esc_html__( 'The stored license key could not be recovered. Please re-enter it before deactivating.', 'mainwp' ),
253 )
254 );
255 return;
256 }
257 $api_key = $info['api_key'];
258 }
259 // MWP-1546 follow-up: reject empty / non-string submissions outside
260 // the sentinel path. Without this guard a direct API hit with an
261 // empty api_key would fall through to license_key_deactivation, which
262 // takes its local-clear fast path and returns SUCCESS without ever
263 // contacting the licensing API -- silently leaving the activation
264 // slot allocated upstream. Same failure mode the sentinel-recovery
265 // branch above closes; close it here too.
266 if ( ! is_string( $api_key ) || '' === $api_key ) {
267 wp_send_json(
268 array(
269 'error' => esc_html__( 'A license key is required to deactivate.', 'mainwp' ),
270 )
271 );
272 return;
273 }
274 $result = MainWP_Api_Manager::instance()->license_key_deactivation( $api_slug, $api_key );
275 wp_send_json( $result );
276 }
277
278 /**
279 * Grab MainWP Extension API Key.
280 *
281 * @return void
282 *
283 * @uses \MainWP\Dashboard\MainWP_Api_Manager::grab_license_key()
284 */
285 public function grab_extension_api_key() {
286 $this->check_security( 'mainwp_extension_grabapikey' );
287 $api_slug = isset( $_POST['slug'] ) ? dirname( wp_unslash( $_POST['slug'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
288 $master_api_key = isset( $_POST['master_api_key'] ) ? wp_unslash( $_POST['master_api_key'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
289 // MWP-1547: the Extensions page renders the sentinel placeholder
290 // when a master key is already stored. The browser-side AJAX call
291 // reads #mainwp_com_api_key and submits whatever is there, so a
292 // remembered-license dashboard sends the sentinel here. Resolve to
293 // the stored decrypted master key server-side instead of forwarding
294 // the placeholder to mainwp.com.
295 if ( MainWP_Credential_Render::is_sentinel( $master_api_key ) ) {
296 $master_api_key = MainWP_Api_Manager_Key::instance()->get_decrypt_master_api_key();
297 }
298 $result = MainWP_Api_Manager::instance()->grab_license_key( $api_slug, $master_api_key );
299 wp_send_json( $result );
300 }
301
302 /**
303 * Save MainWP Extensions API Login details for future logins.
304 *
305 * @return void
306 *
307 * @uses \MainWP\Dashboard\MainWP_Api_Manager::verify_mainwp_api()
308 * @uses \MainWP\Dashboard\MainWP_Api_Manager_Password_Management::encrypt_string()
309 * @uses \MainWP\Dashboard\MainWP_Utility::update_option()
310 */
311 public function save_extensions_api_login() { // phpcs:ignore -- NOSONAR -Current complexity is the only way to achieve desired results, pull request solutions appreciated.
312 $this->check_security( 'mainwp_extension_saveextensionapilogin' );
313 $api_login_history = isset( $_SESSION['api_login_history'] ) ? $_SESSION['api_login_history'] : array(); //phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- ok.
314
315 $new_api_login_history = array();
316 $requests = 0;
317
318 foreach ( $api_login_history as $api_login ) {
319 if ( $api_login['time'] > ( time() - 1 * 60 ) ) {
320 $new_api_login_history[] = $api_login;
321 ++$requests;
322 }
323 }
324
325 if ( 4 < $requests ) {
326 $_SESSION['api_login_history'] = $new_api_login_history;
327 die( wp_json_encode( array( 'error' => esc_html__( 'Too many requests', 'mainwp' ) ) ) );
328 } else {
329 $new_api_login_history[] = array( 'time' => time() );
330 $_SESSION['api_login_history'] = $new_api_login_history;
331 }
332
333 $api_key = isset( $_POST['api_key'] ) ? trim( wp_unslash( $_POST['api_key'] ) ) : false; // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
334
335 // MWP-1547: the Extensions page now renders the sentinel placeholder
336 // ('••••••••') in the license-key input when a value is already
337 // stored. A submission that returns the sentinel unchanged means
338 // "leave the existing key alone" -- short-circuit before contacting
339 // mainwp.com for verification (the sentinel is not a real key, so
340 // the verify call would otherwise produce a misleading error).
341 //
342 // CR follow-up: the unchecked-"Remember API Key" flow normally
343 // reaches the trailing block at the end of this method which clears
344 // mainwp_extensions_api_save_login + mainwp_extensions_plan_info.
345 // The sentinel short-circuit must mirror that behaviour so a user
346 // who unchecks the box (without changing the input) still has the
347 // flag cleared. The trailing block deliberately does NOT clear the
348 // master key itself, so the sentinel branch matches that semantic
349 // -- the only way to delete the stored master key is to submit an
350 // empty input, which the next branch handles.
351 if ( MainWP_Credential_Render::is_sentinel( $api_key ) ) {
352 $save_login = ( isset( $_POST['saveLogin'] ) && ( 1 === (int) $_POST['saveLogin'] ) ) ? true : false; // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
353 if ( ! $save_login ) {
354 MainWP_Utility::update_option( 'mainwp_extensions_api_save_login', '' );
355 MainWP_Utility::update_option( 'mainwp_extensions_plan_info', '' );
356 }
357 die(
358 wp_json_encode(
359 array(
360 'saved' => 1,
361 'result' => 'SUCCESS',
362 )
363 )
364 );
365 }
366
367 if ( '' === $api_key && false !== $api_key ) {
368 MainWP_Keys_Manager::instance()->update_key_value( 'mainwp_extensions_master_api_key', false );
369 }
370
371 if ( empty( $api_key ) ) {
372 die( wp_json_encode( array( 'saved' => 1 ) ) );
373 }
374
375 $result = array();
376 try {
377 $test = MainWP_Api_Manager::instance()->verify_mainwp_api( $api_key );
378 } catch ( \Exception $e ) {
379 $return['error'] = $e->getMessage();
380 die( wp_json_encode( $return ) );
381 }
382
383 if ( is_array( $test ) && isset( $test['retry_action'] ) ) {
384 wp_send_json( $test );
385 }
386
387 $result = json_decode( $test, true );
388 $save_login = ( isset( $_POST['saveLogin'] ) && ( 1 === (int) $_POST['saveLogin'] ) ) ? true : false; // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
389 $return = array();
390 if ( is_array( $result ) ) {
391 if ( isset( $result['success'] ) && $result['success'] ) {
392 if ( $save_login ) {
393 if ( empty( $api_key ) && isset( $result['master_api_key'] ) ) {
394 $api_key = $result['master_api_key'];
395 }
396 MainWP_Keys_Manager::instance()->update_key_value( 'mainwp_extensions_master_api_key', $api_key );
397 MainWP_Utility::update_option( 'mainwp_extensions_api_save_login', true );
398 $plan_info = isset( $result['plan_info'] ) ? wp_json_encode( $result['plan_info'] ) : '';
399 MainWP_Utility::update_option( 'mainwp_extensions_plan_info', $plan_info );
400 }
401 $return['result'] = 'SUCCESS';
402 } elseif ( isset( $result['error'] ) ) {
403 $return['error'] = $result['error'];
404 }
405 }
406
407 if ( ! $save_login ) {
408 MainWP_Utility::update_option( 'mainwp_extensions_api_save_login', '' );
409 MainWP_Utility::update_option( 'mainwp_extensions_plan_info', '' );
410 }
411
412 die( wp_json_encode( $return ) );
413 }
414
415 /**
416 * Save whenther or not to verify MainWP API SSL certificate.
417 *
418 * @return void
419 *
420 * @uses \MainWP\Dashboard\MainWP_Utility::update_option()
421 */
422 public function save_api_ssl_verify() {
423 $this->check_security( 'mainwp_extension_apisslverifycertificate' );
424 MainWP_Utility::update_option( 'mainwp_api_sslVerifyCertificate', isset( $_POST['api_sslverify'] ) ? intval( $_POST['api_sslverify'] ) : 0 ); // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
425 die( wp_json_encode( array( 'saved' => 1 ) ) );
426 }
427
428 /**
429 * Test Extension page MainWP.com login details.
430 *
431 * @return void
432 *
433 * @uses \MainWP\Dashboard\MainWP_Api_Manager::verify_mainwp_api()
434 * @uses \MainWP\Dashboard\MainWP_Utility::update_option()
435 */
436 public function test_extensions_api_login() {
437 $this->check_security( 'mainwp_extension_testextensionapilogin' );
438 $api_key = MainWP_Api_Manager_Key::instance()->get_decrypt_master_api_key();
439 $result = array();
440 try {
441 $test = MainWP_Api_Manager::instance()->verify_mainwp_api( $api_key );
442 } catch ( \Exception $e ) {
443 $return['error'] = $e->getMessage();
444 die( wp_json_encode( $return ) );
445 }
446
447 if ( is_array( $test ) && isset( $test['retry_action'] ) ) {
448 wp_send_json( $test );
449 }
450
451 $result = json_decode( $test, true );
452 $return = array();
453 if ( is_array( $result ) ) {
454 if ( isset( $result['success'] ) && $result['success'] ) {
455 $return['result'] = 'SUCCESS';
456 } elseif ( isset( $result['error'] ) ) {
457 $return['error'] = $result['error'];
458 }
459 } else {
460 $apisslverify = get_option( 'mainwp_api_sslVerifyCertificate' );
461 if ( 1 === (int) $apisslverify ) {
462 MainWP_Utility::update_option( 'mainwp_api_sslVerifyCertificate', 0 );
463 $return['retry_action'] = 1;
464 }
465 }
466 wp_send_json( $return );
467 }
468
469 /**
470 * Download & Install MainWP Extension.
471 *
472 * @return void
473 *
474 * @uses \MainWP\Dashboard\MainWP_Extensions_Handler::install_plugin()
475 */
476 public function download_and_install() {
477 $this->check_security( 'mainwp_extension_downloadandinstall' );
478 // phpcs:ignore -- custom setting to install plugin.
479 ini_set( 'zlib.output_compression', 'Off' );
480 $download_link = isset( $_POST['download_link'] ) ? wp_unslash( $_POST['download_link'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
481 $plugin_slug = isset( $_POST['plugin_slug'] ) ? wp_unslash( $_POST['plugin_slug'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
482
483 $return = array( 'error' => esc_html__( 'Empty or Invalid request data, please try again.', 'mainwp' ) );
484
485 if ( ! empty( $download_link ) ) {
486 $return = MainWP_Extensions_Handler::install_plugin( $download_link );
487 } elseif ( ! empty( $plugin_slug ) ) {
488 include_once ABSPATH . '/wp-admin/includes/plugin-install.php'; // NOSONAR - WP compatible.
489 $api = MainWP_System_Utility::get_plugin_theme_info(
490 'plugin',
491 array(
492 'slug' => dirname( $plugin_slug ),
493 'fields' => array( 'sections' => false ),
494 'timeout' => 60,
495 )
496 );
497
498 if ( is_object( $api ) && property_exists( $api, 'download_link' ) ) {
499 $download_link = $api->download_link;
500 $return = MainWP_Extensions_Handler::install_plugin( $download_link );
501 } else {
502 $return = array( 'error' => esc_html__( 'No response from the WordPress update server.', 'mainwp' ) );
503 }
504 }
505
506 die( '<mainwp>' . wp_json_encode( $return ) . '</mainwp>' );
507 }
508
509 /**
510 * MainWP Extension Bulck Activation.
511 *
512 * @return void
513 */
514 public function bulk_activate() {
515 $this->check_security( 'mainwp_extension_bulk_activate' );
516 $plugins = isset( $_POST['plugins'] ) ? wp_unslash( $_POST['plugins'] ) : false; // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
517 if ( is_array( $plugins ) && ! empty( $plugins ) && current_user_can( 'activate_plugins' ) ) {
518 activate_plugins( $plugins );
519 die( 'SUCCESS' );
520 }
521 die( 'FAILED' );
522 }
523
524 /**
525 * Remove Extensions menu from MainWP Menu.
526 *
527 * @return void
528 *
529 * @uses \MainWP\Dashboard\MainWP_Utility::update_option()
530 */
531 public function remove_extension_menu_from_mainwp_menu() {
532 $this->check_security( 'mainwp_extension_remove_menu' );
533 $snMenuExtensions = get_option( 'mainwp_extmenu' );
534 if ( ! is_array( $snMenuExtensions ) ) {
535 $snMenuExtensions = array();
536 }
537
538 $key = isset( $_POST['slug'] ) ? sanitize_text_field( wp_unslash( $_POST['slug'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
539
540 if ( ! empty( $key ) && isset( $snMenuExtensions[ $key ] ) ) {
541 unset( $snMenuExtensions[ $key ] );
542 MainWP_Utility::update_option( 'mainwp_extmenu', $snMenuExtensions );
543 do_action( 'mainwp_removed_extension_menu', $key );
544 die( wp_json_encode( array( 'result' => 'SUCCESS' ) ) );
545 }
546
547 die( - 1 );
548 }
549 }
550