PluginProbe
MainWP Dashboard: Self-hosted WordPress Management for Agencies / 5.0.3.2
MainWP Dashboard: Self-hosted WordPress Management for Agencies v5.0.3.2
6.2.2 6.2.1 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 All 155 releases
mainwp / pages / page-mainwp-install-bulk.php

page-mainwp-install-bulk.php in MainWP Dashboard: Self-hosted WordPress Management for Agencies 5.0.3.2, at pages/page-mainwp-install-bulk.php

738 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 file handles all of the Bulk Installation Methods
4 * for Plugins & Themes.
5 *
6 * @package MainWP/Dashboard
7 */
8
9 namespace MainWP\Dashboard;
10
11 /**
12 * Class MainWP_Install_Bulk
13 *
14 * @used-by MainWP_Plugins::InstallPlugins
15 * @used-by MainWP_Themes::InstallThemes
16 */
17 class MainWP_Install_Bulk {
18
19 /**
20 * Get Class Name
21 *
22 * @return string __CLASS__
23 *
24 * @uses self::init()
25 */
26 public static function get_class_name() {
27 return __CLASS__;
28 }
29
30 /**
31 * Method init()
32 *
33 * Instantiate the main page
34 *
35 * Has to be called in System constructor,
36 * adds handling for the main page.
37 */
38 public static function init() {
39 add_action( 'admin_init', array( self::get_class_name(), 'admin_init' ) );
40 }
41
42 /**
43 * Method admin_init()
44 *
45 * Handles the uploading of a file.
46 *
47 * @uses \MainWP\Dashboard\MainWP_QQ2_File_Uploader
48 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_mainwp_specific_dir()
49 */
50 public static function admin_init() {
51 if ( isset( $_REQUEST['mainwp_do'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
52 if ( isset( $_REQUEST['qq_nonce'] ) && 'MainWP_Install_Bulk-uploadfile' === $_REQUEST['mainwp_do'] ) { // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
53 do_action( 'mainwp_secure_request', 'qq_nonce', 'qq_nonce' );
54 $allowedExtensions = array( 'zip' ); // Only zip allowed.
55 // max file size in bytes.
56 $sizeLimit = 2 * 1024 * 1024; // 2MB = max allowed.
57
58 $uploader = new MainWP_QQ2_File_Uploader( $allowedExtensions, $sizeLimit );
59 $path = MainWP_System_Utility::get_mainwp_specific_dir( 'bulk' );
60
61 $result = $uploader->handle_upload( $path, true );
62 // to pass data through iframe you will need to encode all html tags.
63 die( htmlspecialchars( wp_json_encode( $result ), ENT_NOQUOTES ) ); // phpcs:ignore WordPress.Security.EscapeOutput
64 }
65 }
66 }
67
68
69 /**
70 * Method render_upload()
71 *
72 * Renders the upload sub part.
73 *
74 * @param string $type Plugin|Theme Type of upload.
75 */
76 public static function render_upload( $type ) {
77 $title = ( 'plugin' === $type ) ? 'Plugins' : 'Themes';
78 $favorites_enabled = is_plugin_active( 'mainwp-favorites-extension/mainwp-favorites-extension.php' );
79 $cls = $favorites_enabled ? 'favorites-extension-enabled ' : '';
80 $cls .= ( 'plugin' === $type ) ? 'qq-upload-plugins' : '';
81
82 $disabled_upload = false;
83 $disabled_functions = ini_get( 'disable_functions' );
84 if ( ! empty( $disable_functions ) ) {
85 $disabled_functions_array = explode( ',', $disabled_functions );
86 if ( is_array( $disabled_functions_array ) && in_array( 'tmpfile', $disabled_functions_array ) ) {
87 $disabled_upload = true;
88 }
89 }
90
91 if ( $disabled_upload ) {
92 ?>
93 <div class="ui red message">
94 <div><?php esc_html_e( 'MainWP has detected that the tmpfile() PHP function is disabled on your server. This function is essential for uploading and installing zip files for plugins and themes. Please enable the tmpfile() function on your server to proceed. Contact your hosting provider for assistance if needed.', 'mainwp' ); ?></div>
95 </div>
96
97 <div class="ui secondary center aligned padded segment">
98 <h2 class="ui icon header">
99 <i class="file archive outline icon" style="color: #ddd"></i>
100 <div class="content" style="color: #ddd">
101 <?php esc_html_e( 'Upload .zip File', 'mainwp' ); ?>
102 <div class="sub header" style="color: #ddd"><?php esc_html_e( 'If you have', 'mainwp' ); ?> <?php echo esc_html( strtolower( $title ) ); ?> <?php esc_html_e( 'in a .zip format, you may install it by uploading it here.', 'mainwp' ); ?></div>
103 </div>
104 </h2>
105
106 <div class="ui hidden divider"></div>
107
108 <div class="ui center aligned segment">
109 <div class="ui labeled icon massive green button disabled">
110 <i class="upload icon"></i>
111 <?php esc_html_e( 'Upload Now', 'mainwp' ); ?>
112 </div>
113 </div>
114
115 </div>
116 <?php
117 } else {
118 ?>
119 <div class="ui secondary center aligned padded segment">
120 <h2 class="ui icon header">
121 <i class="file archive outline icon"></i>
122 <div class="content">
123 <?php esc_html_e( 'Upload .zip File', 'mainwp' ); ?>
124 <div class="sub header"><?php esc_html_e( 'If you have', 'mainwp' ); ?> <?php echo esc_html( strtolower( $title ) ); ?> <?php esc_html_e( 'in a .zip format, you may install it by uploading it here.', 'mainwp' ); ?></div>
125 </div>
126 </h2>
127
128 <div class="ui hidden divider"></div>
129
130 <div id="mainwp-file-uploader" class="<?php echo esc_attr( $cls ); ?>" >
131 <noscript>
132 <div class="ui message red"><?php esc_html_e( 'Please enable JavaScript to use file uploader.', 'mainwp' ); ?></div>
133 </noscript>
134 </div>
135
136 <script>
137 function createUploader() {
138 var uploader = new qq.FileUploader( {
139 element: document.getElementById( 'mainwp-file-uploader' ),
140 action: location.href,
141 <?php
142 /**
143 * Uploader options
144 *
145 * Adds extra options to the bulk upload process as a support for the Favorites extension.
146 *
147 * @param string $type Determines if plugins or themes are being installed.
148 *
149 * @since Unknown
150 */
151 $extraOptions = apply_filters( 'mainwp_uploadbulk_uploader_options', '', $type );
152 $extraOptions = trim( $extraOptions );
153 $extraOptions = trim( trim( $extraOptions, ',' ) );
154 if ( '' !== $extraOptions ) {
155 echo wp_strip_all_tags( $extraOptions ) . ','; // phpcs:ignore WordPress.Security.EscapeOutput
156 }
157 ?>
158 params: {mainwp_do: 'MainWP_Install_Bulk-uploadfile', qq_nonce: '<?php echo esc_js( wp_create_nonce( 'qq_nonce' ) ); ?>' }
159 } );
160 }
161
162 // in your app create uploader as soon as the DOM is ready.
163 // don't wait for the window to load.
164 createUploader();
165 </script>
166 </div>
167 <?php
168 }
169 }
170
171 /**
172 * Method prepare_install()
173 *
174 * Prepare for the installation.
175 *
176 * Grab all the necessary data to make the upload and prepare json response.
177 *
178 * @uses \MainWP\Dashboard\MainWP_DB::query()
179 * @uses \MainWP\Dashboard\MainWP_DB::get_website_by_id()
180 * @uses \MainWP\Dashboard\MainWP_DB::get_sql_websites_by_group_id()
181 * @uses \MainWP\Dashboard\MainWP_DB::fetch_object()
182 * @uses \MainWP\Dashboard\MainWP_DB::free_result()
183 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_mainwp_dir()
184 * @uses \MainWP\Dashboard\MainWP_Utility::ctype_digit()
185 * @uses \MainWP\Dashboard\MainWP_Utility::map_site()
186 */
187 public static function prepare_install() { // phpcs:ignore -- Current complexity is the only way to achieve desired results, pull request solutions appreciated.
188 include_once ABSPATH . '/wp-admin/includes/plugin-install.php';
189 // phpcs:disable WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
190
191 $type = 'theme';
192 if ( isset( $_POST['type'] ) && 'plugin' === $_POST['type'] ) {
193 $type = 'plugin';
194 }
195 if ( ! isset( $_POST['url'] ) ) {
196 $api = MainWP_System_Utility::get_plugin_theme_info(
197 $type,
198 array(
199 'slug' => isset( $_POST['slug'] ) ? wp_unslash( $_POST['slug'] ) : '',
200 'fields' => array( 'sections' => false ),
201 )
202 ); // Save on a bit of bandwidth.
203
204 $url = $api->download_link;
205 $url = apply_filters( 'mainwp_prepare_install_download_url', $url, $_POST );
206 } else {
207 $url = isset( $_POST['url'] ) ? wp_unslash( $_POST['url'] ) : '';
208
209 $mwpDir = MainWP_System_Utility::get_mainwp_dir();
210 $mwpUrl = $mwpDir[1];
211 if ( stristr( $url, $mwpUrl ) ) {
212 $fullFile = $mwpDir[0] . str_replace( $mwpUrl, '', $url );
213 $url = admin_url( '?sig=' . MainWP_System_Utility::get_download_sig( $fullFile ) . '&mwpdl=' . rawurlencode( str_replace( $mwpDir[0], '', $fullFile ) ) );
214 }
215 }
216
217 $output = array();
218 $output['url'] = $url;
219 $output['slug'] = isset( $_POST['slug'] ) ? sanitize_text_field( wp_unslash( $_POST['slug'] ) ) : '';
220 $output['name'] = isset( $_POST['name'] ) ? sanitize_text_field( wp_unslash( $_POST['name'] ) ) : '';
221 $output['sites'] = array();
222
223 $data_fields = array(
224 'id',
225 'url',
226 'name',
227 'sync_errors',
228 );
229
230 if ( isset( $_POST['selected_by'] ) && 'site' === $_POST['selected_by'] ) {
231 $selected_sites = isset( $_POST['selected_sites'] ) && is_array( $_POST['selected_sites'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['selected_sites'] ) ) : array();
232 // Get sites.
233 foreach ( $selected_sites as $enc_id ) {
234 $websiteid = $enc_id;
235 if ( MainWP_Utility::ctype_digit( $websiteid ) ) {
236 $website = MainWP_DB::instance()->get_website_by_id( $websiteid );
237 $output['sites'][ $website->id ] = MainWP_Utility::map_site(
238 $website,
239 array(
240 'id',
241 'url',
242 'name',
243 )
244 );
245 }
246 }
247 } elseif ( isset( $_POST['selected_by'] ) && 'client' === $_POST['selected_by'] ) {
248 $selected_clients = isset( $_POST['selected_clients'] ) && is_array( $_POST['selected_clients'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['selected_clients'] ) ) : array();
249 $websites = MainWP_DB_Client::instance()->get_websites_by_client_ids(
250 $selected_clients,
251 array(
252 'select_data' => $data_fields,
253 )
254 );
255 // Get sites.
256 if ( $websites ) {
257 foreach ( $websites as $website ) {
258 if ( '' !== $website->sync_errors || MainWP_System_Utility::is_suspended_site( $website ) ) {
259 continue;
260 }
261 $output['sites'][ $website->id ] = MainWP_Utility::map_site(
262 $website,
263 array(
264 'id',
265 'url',
266 'name',
267 )
268 );
269 }
270 }
271 } else {
272 $selected_groups = ( isset( $_POST['selected_groups'] ) && is_array( $_POST['selected_groups'] ) ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['selected_groups'] ) ) : array();
273 // Get sites from group.
274 foreach ( $selected_groups as $enc_id ) {
275 $groupid = $enc_id;
276 if ( MainWP_Utility::ctype_digit( $groupid ) ) {
277 $websites = MainWP_DB::instance()->query( MainWP_DB::instance()->get_sql_websites_by_group_id( $groupid ) );
278 while ( $websites && ( $website = MainWP_DB::fetch_object( $websites ) ) ) {
279 if ( '' !== $website->sync_errors || MainWP_System_Utility::is_suspended_site( $website ) ) {
280 continue;
281 }
282 $output['sites'][ $website->id ] = MainWP_Utility::map_site(
283 $website,
284 array(
285 'id',
286 'url',
287 'name',
288 )
289 );
290 }
291 MainWP_DB::free_result( $websites );
292 }
293 }
294 }
295 // phpcs:enable
296
297 /**
298 * Filter: mainwp_bulk_prepare_install_result
299 *
300 * Fires after plugin/theme prepare install.
301 *
302 * @since 4.6
303 */
304 $output = apply_filters( 'mainwp_bulk_prepare_install_result', $output, $type );
305 mainwp_send_json_output( $output );
306 }
307
308
309 /**
310 * Method addition_post_data()
311 *
312 * Grab Post addition data.
313 *
314 * @param array $post_data Data for post.
315 *
316 * @return mixed $post_data Bulk post addition data.
317 */
318 public static function addition_post_data( &$post_data = array() ) {
319
320 /**
321 * Clean and Lock extension options
322 *
323 * Adds additional options related to Clean and Lock options in order to avoid conflicts when HTTP Basic auth is set.
324 *
325 * @since Unknown
326 */
327 $clear_and_lock_opts = apply_filters( 'mainwp_clear_and_lock_options', array() );
328 if ( isset( $post_data['url'] ) && false !== strpos( $post_data['url'], 'mwpdl' ) && false !== strpos( $post_data['url'], 'sig' ) ) {
329 if ( is_array( $clear_and_lock_opts ) && isset( $clear_and_lock_opts['wpadmin_user'] ) && ! empty( $clear_and_lock_opts['wpadmin_user'] ) && isset( $clear_and_lock_opts['wpadmin_passwd'] ) && ! empty( $clear_and_lock_opts['wpadmin_passwd'] ) ) {
330 $post_data['wpadmin_user'] = $clear_and_lock_opts['wpadmin_user'];
331 $post_data['wpadmin_passwd'] = $clear_and_lock_opts['wpadmin_passwd'];
332 }
333 }
334 return $post_data;
335 }
336
337 /**
338 * Perform Install.
339 *
340 * @uses \MainWP\Dashboard\MainWP_Connect::fetch_url_authed()
341 * @uses \MainWP\Dashboard\MainWP_DB::get_website_by_id()
342 * @uses \MainWP\Dashboard\MainWP_Utility::end_session()
343 */
344 public static function perform_install() {
345 MainWP_Utility::end_session();
346
347 // phpcs:disable WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
348 // Fetch info.
349 $type = isset( $_POST['type'] ) ? sanitize_text_field( wp_unslash( $_POST['type'] ) ) : '';
350 $post_data = array(
351 'type' => $type,
352 );
353 if ( isset( $_POST['activatePlugin'] ) && 'true' === $_POST['activatePlugin'] ) {
354 $post_data['activatePlugin'] = 'yes';
355 }
356 if ( isset( $_POST['overwrite'] ) && 'true' === $_POST['overwrite'] ) {
357 $post_data['overwrite'] = true;
358 }
359
360 /**
361 * Addition Post Data.
362 *
363 * @param $post_data The post data.
364 * @deprecated From.
365 * @since 3.5.6.
366 */
367 self::addition_post_data( $post_data );
368
369 $site_id = isset( $_POST['siteId'] ) ? intval( $_POST['siteId'] ) : 0;
370 $website = MainWP_DB::instance()->get_website_by_id( $site_id );
371
372 // to support demo data.
373 if ( MainWP_Demo_Handle::get_instance()->is_demo_website( $website ) ) {
374 return MainWP_Demo_Handle::get_instance()->handle_action_demo( $website, 'perform_install' );
375 }
376
377 $websites = array( $website );
378
379 /**
380 * Perform insatallation additional data
381 *
382 * Adds support for additional data such as HTTP User and HTTP Password.
383 *
384 * @param array $post_data Array containg the post data.
385 *
386 * @since Unknown
387 */
388 $post_data = apply_filters( 'mainwp_perform_install_data', $post_data );
389
390 $post_data['url'] = isset( $_POST['url'] ) ? wp_json_encode( wp_unslash( $_POST['url'] ) ) : '';
391
392 $output = new \stdClass();
393 $output->ok = array();
394 $output->errors = array();
395 $output->results = array();
396 $output->other_data = array();
397
398 // phpcs:enable
399 /**
400 * Action: mainwp_before_plugin_theme_install
401 *
402 * Fires before plugin/theme install.
403 *
404 * @since 4.1
405 */
406 do_action( 'mainwp_before_plugin_theme_install', $post_data, $websites );
407
408 MainWP_Connect::fetch_urls_authed(
409 $websites,
410 'installplugintheme',
411 $post_data,
412 array(
413 self::get_class_name(),
414 'install_plugin_theme_handler',
415 ),
416 $output,
417 null,
418 array( 'upgrade' => true )
419 );
420
421 $output_obj = $output;
422
423 mainwp_get_actions_handler_instance()->do_action_mainwp_install_actions( $websites, 'install', $output_obj, $type, $post_data );
424
425 /**
426 * Action: mainwp_after_plugin_theme_install
427 *
428 * Fires after plugin/theme install.
429 *
430 * @since 4.1
431 */
432 do_action( 'mainwp_after_plugin_theme_install', $output, $post_data, $websites );
433
434 wp_send_json( $output );
435 }
436
437 /**
438 * Method prepare_upload()
439 *
440 * Prepare the upload.
441 *
442 * @uses \MainWP\Dashboard\MainWP_DB::query()
443 * @uses \MainWP\Dashboard\MainWP_DB::get_website_by_id()
444 * @uses \MainWP\Dashboard\MainWP_DB::fetch_object()
445 * @uses \MainWP\Dashboard\MainWP_DB::free_result()
446 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_download_url()
447 * @uses \MainWP\Dashboard\MainWP_Utility::ctype_digit()
448 * @uses \MainWP\Dashboard\MainWP_Utility::map_site()
449 */
450 public static function prepare_upload() { // phpcs:ignore -- comlex function. Current complexity is the only way to achieve desired results, pull request solutions appreciated.
451 include_once ABSPATH . '/wp-admin/includes/plugin-install.php';
452
453 $output = array();
454 $output['sites'] = array();
455
456 $data_fields = array(
457 'id',
458 'url',
459 'name',
460 'sync_errors',
461 );
462 // phpcs:disable WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
463 if ( isset( $_POST['selected_by'] ) && 'site' === $_POST['selected_by'] ) {
464 $selected_sites = isset( $_POST['selected_sites'] ) && is_array( $_POST['selected_sites'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['selected_sites'] ) ) : array();
465 // Get sites.
466 foreach ( $selected_sites as $enc_id ) {
467 $websiteid = $enc_id;
468 if ( MainWP_Utility::ctype_digit( $websiteid ) ) {
469 $website = MainWP_DB::instance()->get_website_by_id( $websiteid );
470 $output['sites'][ $website->id ] = MainWP_Utility::map_site(
471 $website,
472 array(
473 'id',
474 'url',
475 'name',
476 )
477 );
478 }
479 }
480 } elseif ( isset( $_POST['selected_by'] ) && 'client' === $_POST['selected_by'] ) {
481 $selected_clients = isset( $_POST['selected_clients'] ) && is_array( $_POST['selected_clients'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['selected_clients'] ) ) : array();
482 $websites = MainWP_DB_Client::instance()->get_websites_by_client_ids(
483 $selected_clients,
484 array(
485 'select_data' => $data_fields,
486 )
487 );
488 // Get sites.
489 if ( $websites ) {
490 foreach ( $websites as $website ) {
491 if ( '' !== $website->sync_errors || MainWP_System_Utility::is_suspended_site( $website ) ) {
492 continue;
493 }
494 $output['sites'][ $website->id ] = MainWP_Utility::map_site(
495 $website,
496 array(
497 'id',
498 'url',
499 'name',
500 )
501 );
502 }
503 }
504 } else {
505 $selected_groups = ( isset( $_POST['selected_groups'] ) && is_array( $_POST['selected_groups'] ) ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['selected_groups'] ) ) : array();
506 // Get sites from group.
507 foreach ( $selected_groups as $enc_id ) {
508 $groupid = $enc_id;
509 if ( MainWP_Utility::ctype_digit( $groupid ) ) {
510 $websites = MainWP_DB::instance()->query( MainWP_DB::instance()->get_sql_websites_by_group_id( $groupid ) );
511 while ( $websites && ( $website = MainWP_DB::fetch_object( $websites ) ) ) {
512 if ( '' !== $website->sync_errors || MainWP_System_Utility::is_suspended_site( $website ) ) {
513 continue;
514 }
515 $output['sites'][ $website->id ] = MainWP_Utility::map_site(
516 $website,
517 array(
518 'id',
519 'url',
520 'name',
521 )
522 );
523 }
524 MainWP_DB::free_result( $websites );
525 }
526 }
527 }
528
529 $output['urls'] = array();
530 $files = isset( $_POST['files'] ) && is_array( $_POST['files'] ) ? wp_unslash( $_POST['files'] ) : array();
531 foreach ( $files as $file ) {
532 $output['urls'][] = MainWP_System_Utility::get_download_url( 'bulk', $file );
533 }
534 $output['urls'] = implode( '||', $output['urls'] );
535 // phpcs:enable
536
537 /**
538 * Prepare upload
539 *
540 * Prepares upload URLs for the bulk install process.
541 *
542 * @since Unknown
543 */
544 $output['urls'] = apply_filters( 'mainwp_installbulk_prepareupload', $output['urls'] );
545
546 wp_send_json( $output );
547 }
548
549 /**
550 * Method perform_upload()
551 *
552 * Perform the upload.
553 *
554 * @uses \MainWP\Dashboard\MainWP_Connect::fetch_url_authed()
555 * @uses \MainWP\Dashboard\MainWP_DB::get_website_by_id()
556 * @uses \MainWP\Dashboard\MainWP_Utility::end_session()
557 */
558 public static function perform_upload() {
559 MainWP_Utility::end_session();
560 // phpcs:disable WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
561 $type = isset( $_POST['type'] ) ? sanitize_text_field( wp_unslash( $_POST['type'] ) ) : '';
562 // Fetch info.
563 $post_data = array(
564 'type' => $type,
565 );
566 if ( isset( $_POST['activatePlugin'] ) && 'true' === $_POST['activatePlugin'] ) {
567 $post_data['activatePlugin'] = 'yes';
568 }
569 if ( isset( $_POST['overwrite'] ) && 'true' === $_POST['overwrite'] ) {
570 $post_data['overwrite'] = true;
571 }
572
573 // deprecated from 3.5.6.
574 self::addition_post_data( $post_data );
575
576 /** This filter is documented in pages/page-mainwp-install-bulk.php */
577 $post_data = apply_filters( 'mainwp_perform_install_data', $post_data );
578
579 $urls = isset( $_POST['urls'] ) ? esc_url_raw( wp_unslash( $_POST['urls'] ) ) : '';
580 $post_data['url'] = wp_json_encode( explode( '||', $urls ) );
581 $site_id = isset( $_POST['siteId'] ) ? intval( $_POST['siteId'] ) : 0;
582 $website = MainWP_DB::instance()->get_website_by_id( $site_id );
583
584 // phpcs:enable
585
586 // to support demo data.
587 if ( MainWP_Demo_Handle::get_instance()->is_demo_website( $website ) ) {
588 return MainWP_Demo_Handle::get_instance()->handle_action_demo( $website, 'perform_upload' );
589 }
590
591 $output = new \stdClass();
592 $output->ok = array();
593 $output->errors = array();
594 $output->results = array();
595 $output->other_data = array();
596 $websites = array( $website );
597
598 /**
599 * Action: mainwp_before_plugin_theme_install
600 *
601 * Fires before plugin/theme install.
602 *
603 * @since 4.1
604 */
605 do_action( 'mainwp_before_plugin_theme_install', $post_data, $websites );
606
607 MainWP_Connect::fetch_urls_authed(
608 $websites,
609 'installplugintheme',
610 $post_data,
611 array(
612 self::get_class_name(),
613 'install_plugin_theme_handler',
614 ),
615 $output,
616 null,
617 array( 'upgrade' => true )
618 );
619 $output_obj = $output;
620 mainwp_get_actions_handler_instance()->do_action_mainwp_install_actions( $websites, 'install', $output_obj, $type, $post_data, true );
621
622 /**
623 * Action: mainwp_after_plugin_theme_install
624 *
625 * Fires after plugin/theme install.
626 *
627 * @since 4.1
628 */
629 do_action( 'mainwp_after_plugin_theme_install', $output, $post_data, $websites, $type );
630
631 /**
632 * Filter: mainwp_bulk_upload_install_result
633 *
634 * Fires after plugin/theme install.
635 *
636 * @since 4.6
637 */
638 $output = apply_filters( 'mainwp_bulk_upload_install_result', $output, $type, $post_data, $websites );
639
640 wp_send_json( $output );
641 }
642
643 /**
644 * Clean the upload
645 *
646 * Do file structure maintenance and tmp file removals.
647 *
648 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_wp_file_system()
649 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_mainwp_specific_dir()
650 */
651 public static function clean_upload() {
652 $hasWPFileSystem = MainWP_System_Utility::get_wp_file_system();
653
654 /**
655 * WordPress files system object.
656 *
657 * @global object
658 */
659 global $wp_filesystem;
660
661 $path = MainWP_System_Utility::get_mainwp_specific_dir( 'bulk' );
662 if ( $wp_filesystem->exists( $path ) ) {
663 $dh = opendir( $path );
664 if ( $dh ) {
665 while ( false !== ( $file = readdir( $dh ) ) ) {
666 if ( '.' !== $file && '..' !== $file ) {
667 $wp_filesystem->delete( $path . $file );
668 }
669 }
670 closedir( $dh );
671 }
672 }
673
674 die( wp_json_encode( array( 'ok' => true ) ) );
675 }
676
677 /**
678 * Plugin & Theme upload handler.
679 *
680 * @param mixed $data Processing data.
681 * @param object $website The website object.
682 * @param mixed $output Function output.
683 * @param mixed $post_data Post data.
684 *
685 * @return mixed $output->ok[ $website->id ] = array( $website->name )|Error,
686 * Already installed,
687 * Undefined error! Please reinstall the MainWP Child plugin on the child site,
688 * Error while installing.
689 *
690 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_child_response()
691 */
692 public static function install_plugin_theme_handler( $data, $website, &$output, $post_data = array() ) {
693 if ( MainWP_Demo_Handle::get_instance()->is_demo_website( $website ) ) {
694 return;
695 }
696 if ( preg_match( '/<mainwp>(.*)<\/mainwp>/', $data, $results ) > 0 ) {
697
698 $result = $results[1];
699 // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode used for http encoding compatible.
700 $information = MainWP_System_Utility::get_child_response( base64_decode( $result ) );
701 if ( is_array( $information ) ) {
702 if ( isset( $information['other_data']['install_items'] ) ) {
703 $output->other_data[ $website->id ] = $information['other_data']; // content: install_items themes/plugins.
704 }
705 }
706
707 if ( isset( $information['installation'] ) && 'SUCCESS' === $information['installation'] ) {
708 $output->ok[ $website->id ] = array( $website->name );
709 $output->results[ $website->id ] = isset( $information['install_results'] ) ? $information['install_results'] : array();
710 } elseif ( isset( $information['error'] ) ) {
711 $error = esc_html( $information['error'] );
712 if ( isset( $information['error_code'] ) && 'folder_exists' === $information['error_code'] ) {
713 $error = esc_html__( 'Already installed', 'mainwp' );
714 }
715
716 if ( 'not found' === strtolower( $error ) ) {
717 if ( is_array( $post_data ) && isset( $post_data['type'] ) ) {
718 if ( 'plugin' === $post_data['type'] ) {
719 $error = esc_html__( 'Plugin file not found. Make sure security plugins or server-side security rules are not blocking requests from your child sites.', 'mainwp' );
720 } elseif ( 'theme' === $post_data['type'] ) {
721 $error = esc_html__( 'Theme file not found. Make sure security plugins or server-side security rules are not blocking requests from your child sites.', 'mainwp' );
722 }
723 }
724 }
725
726 $output->errors[ $website->id ] = array( $website->name, $error );
727 } else {
728 $output->errors[ $website->id ] = array(
729 $website->name,
730 __( 'Undefined error! Please reinstall the MainWP Child plugin on the child site', 'mainwp' ),
731 );
732 }
733 } else {
734 $output->errors[ $website->id ] = array( $website->name, 'Error while installing' );
735 }
736 }
737 }
738