PluginProbe
MainWP Dashboard: Self-hosted WordPress Management for Agencies / 6.1
MainWP Dashboard: Self-hosted WordPress Management for Agencies v6.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 5.2.2 5.3 All 153 releases
mainwp / pages / page-mainwp-extensions-handler.php

page-mainwp-extensions-handler.php in MainWP Dashboard: Self-hosted WordPress Management for Agencies 6.1, at pages/page-mainwp-extensions-handler.php

1,117 lines 40.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * MainWP Extensions Page Handler
4 *
5 * @package MainWP/Dashboard
6 */
7
8 namespace MainWP\Dashboard;
9
10 // Exit if accessed directly.
11 if ( ! defined( 'ABSPATH' ) ) {
12 exit;
13 }
14
15 /**
16 * Class MainWP_Extensions_Handler
17 */
18 class MainWP_Extensions_Handler { // phpcs:ignore Generic.Classes.OpeningBraceSameLine.ContentAfterBrace -- NOSONAR.
19
20 // phpcs:disable Generic.Metrics.CyclomaticComplexity -- complexity.
21
22 /**
23 * Method get_class_name()
24 *
25 * Get Class Name.
26 *
27 * @return object
28 */
29 public static function get_class_name() {
30 return __CLASS__;
31 }
32
33 /**
34 * All extensions.
35 *
36 * @var array $extensions
37 */
38 public static $extensions;
39
40 /**
41 * All disabled extensions.
42 *
43 * @var array $extensions
44 */
45 public static $extensions_disabled;
46
47 /**
48 * Get Extension Slug.
49 *
50 * @param mixed $slug Extension Slug.
51 *
52 * @return string Extensions Slug.
53 */
54 public static function get_extension_slug( $slug ) {
55 $currentExtensions = static::get_extensions();
56 if ( ! is_array( $currentExtensions ) || empty( $currentExtensions ) ) {
57 return $slug;
58 }
59
60 foreach ( $currentExtensions as $extension ) {
61 if ( isset( $extension['api'] ) && ( $extension['api'] === $slug ) ) {
62 return $extension['slug'];
63 }
64 }
65
66 return $slug;
67 }
68
69 /**
70 * Get all extension slugs.
71 *
72 * @return array am_slugs|slugs.
73 */
74 public static function get_slugs() {
75 $currentExtensions = static::get_extensions();
76
77 if ( empty( $currentExtensions ) ) {
78 return array(
79 'slugs' => '',
80 'am_slugs' => '',
81 );
82 }
83
84 $out = '';
85 $am_out = '';
86 foreach ( $currentExtensions as $extension ) {
87 if ( ! isset( $extension['api'] ) || '' === $extension['api'] ) {
88 continue;
89 }
90
91 if ( isset( $extension['apiManager'] ) && ! empty( $extension['apiManager'] ) && 'Activated' === $extension['activated_key'] ) {
92 if ( '' !== $am_out ) {
93 $am_out .= ',';
94 }
95 $am_out .= $extension['api'];
96 } else {
97 if ( '' !== $out ) {
98 $out .= ',';
99 }
100 $out .= $extension['api'];
101 }
102 }
103
104 return array(
105 'slugs' => $out,
106 'am_slugs' => $am_out,
107 );
108 }
109
110 /**
111 * Clean up MainWP Extention names.
112 *
113 * @param string $extension Array of MainWP Extentsions.
114 * @param bool $forced forced polish.
115 *
116 * @return string $menu_name Final Menu Name.
117 */
118 public static function polish_ext_name( $extension, $forced = false ) {
119 if ( $forced || ( isset( $extension['mainwp'] ) && $extension['mainwp'] ) ) {
120 $menu_name = static::polish_string_name( $extension['name'] );
121 } else {
122 $menu_name = $extension['name'];
123 }
124 return $menu_name;
125 }
126
127 /**
128 * Clean up MainWP Extention names.
129 *
130 * @param string $name Extention name string.
131 *
132 * @return string $menu_name Final Name.
133 */
134 public static function polish_string_name( $name ) {
135 if ( false !== stripos( $name, 'for Mainwp' ) ) {
136 return $name; // skip.
137 }
138 $new_name = str_replace(
139 array(
140 'Extensions',
141 'Mainwp',
142 'Extension',
143 'MainWP',
144 'Add-on',
145 ),
146 '',
147 $name
148 );
149 $new_name = trim( $new_name );
150 return $new_name;
151 }
152
153
154 /**
155 * Load MainWP Extensions.
156 *
157 * @param bool $forced Forced reload value.
158 *
159 * @return array Array of loaded Extensions.
160 */
161 public static function get_extensions( $forced = false ) {
162 if ( ! isset( static::$extensions ) || $forced ) {
163 static::$extensions = array();
164 $extensions = get_option( 'mainwp_extensions', array() );
165 foreach ( $extensions as $extension ) {
166 $slug = $extension['slug'];
167 if ( function_exists( '\mainwp_current_user_can' ) ) { // to fix later init, it's ok to check user have right.
168 if ( \mainwp_current_user_can( 'extension', dirname( $slug ) ) ) {
169 static::$extensions[] = $extension;
170 }
171 } else {
172 static::$extensions[] = $extension;
173 }
174 }
175 }
176 return static::$extensions;
177 }
178
179
180 /**
181 * Get disabled MainWP Extensions.
182 *
183 * @param bool $compatible_api_response To get compatible api response values.
184 *
185 * @return array Array of disabled Extensions.
186 */
187 public static function get_extensions_disabled( $compatible_api_response = false ) { // phpcs:ignore -- NOSONAR - complex.
188 if ( ! isset( static::$extensions_disabled ) || $compatible_api_response ) {
189 static::$extensions_disabled = array();
190 $all_available_extensions = MainWP_Extensions_View::get_available_extensions( 'all' );
191 $all_plugins = get_plugins();
192
193 $exts_disabled = array();
194
195 if ( $all_plugins ) {
196 foreach ( $all_plugins as $plugin => $plugin_data ) {
197 if ( is_plugin_active( $plugin ) ) {
198 continue;
199 }
200 $slug = dirname( $plugin );
201 if ( isset( $all_available_extensions[ $slug ] ) ) {
202
203 $ext = $all_available_extensions[ $slug ];
204
205 $extension = array();
206
207 $extension['name'] = $plugin_data['Name'];
208 $extension['slug'] = $plugin;
209 $extension['version'] = $plugin_data['Version'];
210 $extension['description'] = $plugin_data['Description'];
211 $extension['author'] = $plugin_data['Author'];
212 $extension['img'] = isset( $ext['img'] ) ? $ext['img'] : '';
213 $extension['iconURI'] = isset( $plugin_data['IconURI'] ) ? $plugin_data['IconURI'] : '';
214 $extension['SupportForumURI'] = '';
215 $extension['DocumentationURI'] = '';
216 $extension['page'] = 'Extensions-' . str_replace( ' ', '-', ucwords( str_replace( '-', ' ', dirname( $slug ) ) ) );
217
218 $extension['api_key'] = '';
219 $extension['activated_key'] = 'Deactivated';
220 $extension['deactivate_checkbox'] = 'off';
221 $extension['product_id'] = $ext['product_id'];
222 $extension['instance_id'] = '';
223 $extension['software_version'] = '';
224 $extension['product_item_id'] = '';
225 $extension['type'] = $ext['type'];
226
227 if ( $compatible_api_response ) {
228 $exts_disabled[ $ext['product_id'] ] = $extension;
229 } else {
230 $exts_disabled[] = $extension;
231 }
232 }
233 }
234 }
235
236 if ( $compatible_api_response ) {
237 return $exts_disabled;
238 } else {
239 static::$extensions_disabled = $exts_disabled;
240 }
241 }
242 return static::$extensions_disabled;
243 }
244
245 /**
246 * Get not installed MainWP Extensions.
247 *
248 * @return array Array of not installed Extensions.
249 */
250 public static function get_extensions_not_installed() {
251 $all_available_extensions = MainWP_Extensions_View::get_available_extensions( 'all' );
252
253 $all_plugins = get_plugins();
254
255 $installed_slugs = array();
256 foreach ( $all_plugins as $plugin => $plugin_data ) {
257 $slug = dirname( $plugin );
258 if ( ! isset( $installed_slugs[ $slug ] ) ) {
259 $installed_slugs[] = $slug;
260 }
261 }
262
263 $exts_not_installed = array();
264 foreach ( $all_available_extensions as $slug => $info ) {
265 if ( ! in_array( $slug, $installed_slugs ) ) {
266 $exts_not_installed[ $slug ] = array(
267 'name' => $info['title'],
268 'slug' => $info['slug'],
269 'link' => $info['link'],
270 'img' => isset( $info['img'] ) ? $info['img'] : '',
271 'description' => isset( $info['desc'] ) ? $info['desc'] : '',
272 );
273 }
274 }
275 return $exts_not_installed;
276 }
277
278 /**
279 * Get MainWP Extensions infor array.
280 *
281 * @param array $args Empty Array.
282 * @param bool $deactivated_license Get extensions that deactivated license or not.
283 *
284 * @return array Array of Extensions.
285 */
286 public static function get_indexed_extensions_infor( $args = array(), $deactivated_license = null ) { // phpcs:ignore -- NOSONAR - complex.
287 if ( ! is_array( $args ) ) {
288 $args = array();
289 }
290 $extensions = static::get_extensions();
291 $return = array();
292 foreach ( $extensions as $extension ) {
293 if ( ( isset( $args['activated'] ) && ! empty( $args['activated'] ) && isset( $extension['apiManager'] ) && $extension['apiManager'] ) && ( ! isset( $extension['activated_key'] ) || 'Activated' !== $extension['activated_key'] ) ) {
294 continue;
295 }
296 $apiManager = isset( $extension['apiManager'] ) && $extension['apiManager'] ? true : false;
297 $ext = array();
298 $ext['version'] = $extension['version'];
299 $ext['apiManager'] = $apiManager;
300 $ext['name'] = $extension['name'];
301 $ext['page'] = $extension['page'];
302 $ext['mainwp_version'] = isset( $extension['mainwp_version'] ) ? $extension['mainwp_version'] : '';
303
304 if ( isset( $extension['activated_key'] ) && 'Activated' === $extension['activated_key'] ) {
305 $ext['activated_key'] = 'Activated';
306 }
307
308 if ( null !== $deactivated_license && ( ( $deactivated_license && $apiManager && isset( $ext['activated_key'] ) && 'Activated' === $ext['activated_key'] ) || ( ! $deactivated_license && ( ! isset( $ext['activated_key'] ) || 'Activated' !== $ext['activated_key'] ) ) ) ) {
309 continue; // get deactivated license, skip activated license.
310 }
311
312 $return[ $extension['slug'] ] = $ext;
313 }
314 return $return;
315 }
316
317 /**
318 * Generate API Password.
319 *
320 * @param integer $length Lenght of password.
321 * @param bool $special_chars true|false, allow special characters.
322 * @param bool $extra_special_chars true|false, allow extra special characters.
323 *
324 * @return MainWP_Api_Manager_Password_Management::generate_password()
325 */
326 public static function gen_api_password( $length = 12, $special_chars = true, $extra_special_chars = false ) {
327 MainWP_Deprecated_Hooks::maybe_handle_deprecated_hook();
328 return MainWP_Api_Manager_Password_Management::generate_password( $length, $special_chars, $extra_special_chars );
329 }
330
331
332 /**
333 * Add Extension Menu.
334 *
335 * @param mixed $slug Extension slug.
336 *
337 * @return boolean true|false.
338 *
339 * @uses \MainWP\Dashboard\MainWP_Utility::update_option()
340 */
341 public static function add_extension_menu( $slug ) {
342 $snMenuExtensions = get_option( 'mainwp_extmenu' );
343 if ( ! is_array( $snMenuExtensions ) ) {
344 $snMenuExtensions = array();
345 }
346
347 $snMenuExtensions[] = $slug;
348
349 MainWP_Utility::update_option( 'mainwp_extmenu', $snMenuExtensions );
350
351 /**
352 * Adds Extension to the navigation menu
353 *
354 * Adds Extension instance to the Extensions located in the main MainWP navigation menu.
355 *
356 * @param string $slug Extension slug.
357 *
358 * @since 4.0
359 */
360 do_action( 'mainwp_added_extension_menu', $slug );
361
362 return true;
363 }
364
365 /**
366 * HTTP Request Reject Unsafe Urls.
367 *
368 * @param bool $args args.
369 *
370 * @return mixed args.
371 */
372 public static function http_request_reject_unsafe_urls( $args ) {
373 $args['reject_unsafe_urls'] = false;
374
375 return $args;
376 }
377
378 /**
379 * No SSL Filter Function.
380 *
381 * @param bool $args args.
382 *
383 * @return mixed args.
384 */
385 public static function no_ssl_filter_function( $args ) {
386 $args['sslverify'] = false;
387 return $args;
388 }
389
390 /**
391 * No SSL Filter Extention Upgrade.
392 *
393 * @param bool $r Results.
394 * @param mixed $url Upgrade Extension URL.
395 *
396 * @return mixed false|$r.
397 */
398 public static function no_ssl_filter_extension_upgrade( $r, $url ) {
399 if ( ( false !== strpos( $url, 'am_download_file=' ) ) && ( false !== strpos( $url, 'am_email=' ) ) ) {
400 $r['sslverify'] = false;
401 }
402
403 return $r;
404 }
405
406 /**
407 * Install MainWP Extension.
408 *
409 * @param mixed $url MainWP Extension update URL.
410 * @param bool $activatePlugin true|false Whether or not to activate extension.
411 *
412 * @return mixed $return
413 *
414 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_wp_file_system()
415 */
416 public static function install_plugin( $url, $activatePlugin = false ) { //phpcs:ignore -- NOSONAR - complex.
417
418 MainWP_System_Utility::get_wp_file_system();
419
420 /**
421 * WordPress files system object.
422 *
423 * @global object
424 */
425 global $wp_filesystem;
426
427 if ( file_exists( ABSPATH . '/wp-admin/includes/screen.php' ) ) {
428 include_once ABSPATH . '/wp-admin/includes/screen.php'; // NOSONAR - WP compatible.
429 }
430
431 include_once ABSPATH . '/wp-admin/includes/template.php'; // NOSONAR - WP compatible.
432 include_once ABSPATH . '/wp-admin/includes/misc.php'; // NOSONAR - WP compatible.
433 include_once ABSPATH . '/wp-admin/includes/class-wp-upgrader.php'; // NOSONAR - WP compatible.
434 include_once ABSPATH . '/wp-admin/includes/plugin.php'; // NOSONAR - WP compatible.
435
436 // To fix conflict.
437 if ( is_plugin_active( 'git-updater/git-updater.php' ) ) {
438 remove_all_filters( 'upgrader_source_selection' );
439 }
440
441 $installer = new \WP_Upgrader();
442 $ssl_verifyhost = get_option( 'mainwp_sslVerifyCertificate' );
443 $ssl_api_verifyhost = ( ( false === get_option( 'mainwp_api_sslVerifyCertificate' ) ) || ( 1 === (int) get_option( 'mainwp_api_sslVerifyCertificate' ) ) ) ? 1 : 0;
444
445 if ( empty( $ssl_api_verifyhost ) ) {
446 add_filter( 'http_request_args', array( static::get_class_name(), 'no_ssl_filter_function' ), 99, 2 );
447 }
448
449 add_filter( 'http_request_args', array( static::get_class_name(), 'http_request_reject_unsafe_urls' ), 99, 2 );
450
451 $result = $installer->run(
452 array(
453 'package' => $url,
454 'destination' => WP_PLUGIN_DIR,
455 'clear_destination' => false,
456 'clear_working' => true,
457 'hook_extra' => array(),
458 )
459 );
460
461 remove_filter( 'http_request_args', array( static::get_class_name(), 'http_request_reject_unsafe_urls' ), 99, 2 );
462
463 if ( '0' === $ssl_verifyhost ) {
464 remove_filter( 'http_request_args', array( static::get_class_name(), 'no_ssl_filter_function' ), 99 );
465 }
466
467 $error = null;
468 $output = null;
469 $plugin_slug = null;
470
471 if ( is_wp_error( $result ) ) {
472 $error_code = $result->get_error_code();
473 if ( $result->get_error_data() && is_string( $result->get_error_data() ) ) {
474 $error = $error_code . ' - ' . $result->get_error_data();
475 } else {
476 $error = $error_code;
477 }
478 } else {
479 $path = $result['destination'];
480
481 foreach ( $result['source_files'] as $srcFile ) {
482
483 if ( 'readme.txt' === $srcFile ) {
484 continue;
485 }
486
487 $thePlugin = get_plugin_data( $path . $srcFile );
488
489 if ( null !== $thePlugin && '' !== $thePlugin && '' !== $thePlugin['Name'] ) {
490 $the_name = static::polish_string_name( $thePlugin['Name'] );
491 $output .= esc_html( $the_name ) . ' ' . esc_html__( 'installed successfully. Do not forget to activate the extension API license.', 'mainwp' );
492 $plugin_slug = $result['destination_name'] . '/' . $srcFile;
493
494 if ( $activatePlugin ) {
495 activate_plugin( $path . $srcFile, '', false, true );
496
497 /**
498 * Extension API activation
499 *
500 * Activates the extension API license upon the extension installation.
501 *
502 * @since Unknown
503 * @ignore
504 */
505 do_action( 'mainwp_api_extension_activated', $path . $srcFile );
506 }
507
508 break;
509 }
510 }
511 }
512
513 if ( ! empty( $error ) ) {
514 $return['error'] = $error;
515 } else {
516 $return['result'] = 'SUCCESS';
517 $return['output'] = $output;
518 $return['slug'] = esc_html( $plugin_slug );
519 }
520
521 return $return;
522 }
523
524 /**
525 * Check if MainWP Extension is available.
526 *
527 * @param mixed $pAPI MainWP Extension API Key.
528 *
529 * @return boolean true|false.
530 */
531 public static function is_extension_available( $pAPI ) {
532
533 MainWP_Deprecated_Hooks::maybe_handle_deprecated_hook();
534
535 $extensions = static::get_extensions();
536 if ( isset( $extensions ) && is_array( $extensions ) ) {
537 foreach ( $extensions as $extension ) {
538 $slug = dirname( $extension['slug'] );
539 if ( $slug === $pAPI ) {
540 return true;
541 }
542 }
543 }
544 return false;
545 }
546
547 /**
548 * Check if MainWP Extension is enabled.
549 *
550 * @param mixed $pluginFile MainWP Extension to bo verified.
551 *
552 * @return array 'key' => md5( $pluginFile . '-SNNonceAdder').
553 */
554 public static function is_extension_enabled( $pluginFile ) {
555 MainWP_Deprecated_Hooks::maybe_handle_deprecated_hook();
556 return array( 'key' => md5( $pluginFile . '-SNNonceAdder' ) ); // NOSONAR - safe for sig file name.
557 }
558
559 /**
560 * Create Menu Extension Array.
561 *
562 * @param mixed $slug menu slug.
563 *
564 * @return array Menu Array.
565 */
566 public static function added_on_menu( $slug ) {
567 $snMenuExtensions = get_option( 'mainwp_extmenu' );
568 if ( ! is_array( $snMenuExtensions ) ) {
569 $snMenuExtensions = array();
570 }
571 return in_array( $slug, $snMenuExtensions );
572 }
573
574 /**
575 * Check if MainWP Extension is activated or not.
576 *
577 * @param mixed $plugin_slug MainWP Extension slug.
578 *
579 * @return boolean true|false.
580 */
581 public static function is_extension_activated( $plugin_slug ) {
582 $extensions = static::get_indexed_extensions_infor( array( 'activated' => true ) );
583 return isset( $extensions[ $plugin_slug ] ) ? true : false;
584 }
585
586 /**
587 * Verify MainWP Extension.
588 *
589 * @param mixed $pluginFile MainWP Extensoin to verify.
590 * @param mixed $key Child Site Key.
591 *
592 * @return mixed md5( $pluginFile . '-SNNonceAdder' ) === $key
593 */
594 public static function hook_verify( $pluginFile, $key ) {
595 return md5( $pluginFile . '-SNNonceAdder' ) === $key; // NOSONAR - safe for sig file name.
596 }
597
598 /**
599 * Get sql websites for current user.
600 *
601 * @param mixed $pluginFile Extension plugin file to verify.
602 * @param mixed $key PThe child-key.
603 *
604 * @return mixed null|sql query.
605 *
606 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_current_wpid()
607 */
608 public static function hook_get_dashboard_sites( $pluginFile, $key ) {
609 if ( ! static::hook_verify( $pluginFile, $key ) ) {
610 return null;
611 }
612
613 $current_wpid = MainWP_System_Utility::get_current_wpid();
614
615 if ( $current_wpid ) {
616 $sql = MainWP_DB::instance()->get_sql_website_by_id( $current_wpid );
617 } else {
618 $sql = MainWP_DB::instance()->get_sql_websites_for_current_user();
619 }
620
621 return MainWP_DB::instance()->query( $sql );
622 }
623
624 /**
625 * Fetch Authorized URLS.
626 *
627 * @param mixed $pluginFile Extension plugin file to verify.
628 * @param string $key The child key.
629 * @param object $dbwebsites The websites.
630 * @param string $what Action to perorm.
631 * @param mixed $params Request parameters.
632 * @param mixed $handle Request handle.
633 * @param mixed $output Request output.
634 *
635 * @uses MainWP_Connect::fetch_urls_authed()
636 *
637 * @return mixed false|MainWP_Connect::fetch_urls_authed()
638 */
639 public static function hook_fetch_urls_authed( $pluginFile, $key, $dbwebsites, $what, $params, $handle, $output ) {
640 if ( ! static::hook_verify( $pluginFile, $key ) ) {
641 return false;
642 }
643
644 return MainWP_Connect::fetch_urls_authed( $dbwebsites, $what, $params, $handle, $output );
645 }
646
647 /**
648 * Fetch Authorized URL.
649 *
650 * @throws MainWP_Exception On incorrect website.
651 * @param mixed $pluginFile Extension plugin file to verify.
652 * @param mixed $key The child-key.
653 * @param mixed $websiteId Child Site ID.
654 * @param mixed $what What.
655 * @param mixed $params Parameters.
656 * @param null $rawResponse Raw responce.
657 *
658 * @return mixed false|throw|error
659 *
660 * @uses \MainWP\Dashboard\MainWP_System_Utility::can_edit_website()
661 */
662 public static function hook_fetch_url_authed( $pluginFile, $key, $websiteId, $what, $params, $rawResponse = null ) {
663 if ( ! static::hook_verify( $pluginFile, $key ) ) {
664 return false;
665 }
666
667 $website = MainWP_DB::instance()->get_website_by_id( $websiteId );
668
669 if ( $website && $website->suspended && ( ! defined( 'DOING_CRON' ) || true !== DOING_CRON ) && ( ! defined( 'WP_CLI' ) || true !== WP_CLI ) ) {
670 return array(
671 'error' => esc_html__( 'Suspended site.', 'mainwp' ),
672 'errorCode' => 'SUSPENDED_SITE',
673 );
674 }
675
676 return static::fetch_url_authed( $websiteId, $what, $params, $rawResponse );
677 }
678
679 /**
680 * Fetch Authorized URL.
681 *
682 * @throws MainWP_Exception On incorrect website.
683 * @param mixed $websiteId Child Site ID.
684 * @param mixed $what What.
685 * @param mixed $params Parameters.
686 * @param null $rawResponse Raw responce.
687 *
688 * @return mixed false|throw|error
689 *
690 * @uses \MainWP\Dashboard\MainWP_System_Utility::can_edit_website()
691 */
692 public static function fetch_url_authed( $websiteId, $what, $params, $rawResponse = null ) {
693 try {
694 $website = MainWP_DB::instance()->get_website_by_id( $websiteId );
695 if ( ! MainWP_System_Utility::can_edit_website( $website ) ) {
696 throw new MainWP_Exception( 'You can not edit this website.' );
697 }
698
699 return MainWP_Connect::fetch_url_authed( $website, $what, $params, false, false, true, $rawResponse );
700 } catch ( MainWP_Exception $e ) {
701 return array(
702 'error' => MainWP_Error_Helper::get_error_message( $e ),
703 'errorCode' => 'excep_fetch_url_authed',
704 );
705 }
706 }
707
708 /**
709 * Retrieves database sites based on provided parameters.
710 *
711 * This method verifies the hook using the plugin file and key, then retrieves
712 * sites from the database according to the specified criteria.
713 *
714 * @param string $pluginFile The path to the plugin file for verification.
715 * @param string $key The key used for hook verification.
716 * @param array|string $sites Site IDs to retrieve. Can be an array of IDs or a comma-separated string.
717 * @param array|string $groups Optional. Group IDs to filter sites by. Can be an array or comma-separated string.
718 * Default is empty string.
719 * @param array|bool $options Optional. Fields to return or additional query options.
720 * Set to false to return all fields. Default is false.
721 * @param array|string $clients Optional. Client IDs to filter sites by. Can be an array or comma-separated string.
722 * Default is empty string.
723 *
724 * @return array|bool Array of site objects on success, or false if hook verification fails.
725 *
726 * @uses \MainWP\Dashboard\MainWP_Utility::ctype_digit()
727 * @uses \MainWP\Dashboard\MainWP_Utility::map_site()
728 */
729 public static function hook_get_db_sites( $pluginFile, $key, $sites, $groups = '', $options = false, $clients = '' ) {
730 if ( ! static::hook_verify( $pluginFile, $key ) ) {
731 return false;
732 }
733
734 MainWP_Deprecated_Hooks::maybe_handle_deprecated_hook();
735 $params = array(
736 'fields' => $options,
737 'sites' => $sites,
738 'groups' => $groups,
739 'clients' => $clients,
740 );
741 return MainWP_DB::instance()->get_db_sites( $params );
742 }
743
744 /**
745 * Get DB Sites.
746 *
747 * @since 4.4.2
748 *
749 * @param mixed $pluginFile Extension plugin file to verify.
750 * @param mixed $key The child-key.
751 * @param mixed $params params.
752 *
753 * @return array $dbwebsites.
754 */
755 public static function hook_get_db_websites( $pluginFile, $key, $params = array() ) {
756 if ( ! static::hook_verify( $pluginFile, $key ) ) {
757 return false;
758 }
759
760 if ( empty( $params ) || ! is_array( $params ) ) {
761 return false;
762 }
763 return MainWP_DB::instance()->get_db_sites( $params );
764 }
765
766
767 /**
768 * Get Sites.
769 *
770 * @param string $pluginFile Extension plugin file to verify.
771 * @param string $key The child-key.
772 * @param int $websiteid The id of the child site you wish to retrieve.
773 * @param bool $for_manager Check Team Control.
774 * @param array $others Array of others.
775 *
776 * @return array $output Array of content to output.
777 *
778 * @uses \MainWP\Dashboard\MainWP_System_Utility::can_edit_website()
779 * @uses \MainWP\Dashboard\MainWP_Utility::get_nice_url()
780 */
781 public static function hook_get_sites( $pluginFile, $key, $websiteid = null, $for_manager = false, $others = array() ) { // phpcs:ignore -- NOSONAR - not quite complex function.
782 if ( ! static::hook_verify( $pluginFile, $key ) ) {
783 return false;
784 }
785
786 if ( $for_manager && ( ! defined( 'MWP_TEAMCONTROL_PLUGIN_SLUG' ) || ! \mainwp_current_user_can( 'extension', dirname( MWP_TEAMCONTROL_PLUGIN_SLUG ) ) ) ) {
787 return false;
788 }
789 MainWP_Deprecated_Hooks::maybe_handle_deprecated_hook();
790
791 return MainWP_DB::instance()->get_sites( $websiteid, $for_manager, $others );
792 }
793
794 /**
795 * Method hook_get_groups()
796 *
797 * Get Child Sites within groups & store them in an array.
798 *
799 * @param string $pluginFile Extension plugin file to verify.
800 * @param string $key The child-key.
801 * @param int $groupid The id of the group you wish to retrieve.
802 * @param bool $for_manager Check Team Control.
803 *
804 * @return array|bool $output|false An array of arrays, the inner-array contains the id/name/array of site ids for the supplied groupid/all groups. False when something goes wrong.
805 */
806 public static function hook_get_groups( $pluginFile, $key, $groupid, $for_manager = false ) {
807 if ( ! static::hook_verify( $pluginFile, $key ) ) {
808 return false;
809 }
810
811 if ( $for_manager && ( ! defined( 'MWP_TEAMCONTROL_PLUGIN_SLUG' ) || ! \mainwp_current_user_can( 'extension', dirname( MWP_TEAMCONTROL_PLUGIN_SLUG ) ) ) ) {
812 return false;
813 }
814
815 MainWP_Deprecated_Hooks::maybe_handle_deprecated_hook();
816
817 if ( isset( $groupid ) ) {
818 $group = MainWP_DB_Common::instance()->get_group_by_id( $groupid );
819 if ( empty( $group ) ) {
820 return false;
821 }
822
823 $websites = MainWP_DB::instance()->get_websites_by_group_id( $group->id );
824 $websitesOut = array();
825 foreach ( $websites as $website ) {
826 $websitesOut[] = $website->id;
827 }
828
829 return array(
830 array(
831 'id' => $groupid,
832 'name' => $group->name,
833 'websites' => $websitesOut,
834 ),
835 );
836 }
837
838 $groups = MainWP_DB_Common::instance()->get_groups_and_count( null, $for_manager );
839 $output = array();
840 foreach ( $groups as $group ) {
841 $websites = MainWP_DB::instance()->get_websites_by_group_id( $group->id );
842 $websitesOut = array();
843 foreach ( $websites as $website ) {
844 if ( in_array( $website->id, $websitesOut ) ) {
845 continue;
846 }
847 $websitesOut[] = $website->id;
848 }
849 $output[] = array(
850 'id' => $group->id,
851 'name' => $group->name,
852 'websites' => $websitesOut,
853 );
854 }
855
856 return $output;
857 }
858
859
860 /**
861 * Get all loaded extensions.
862 *
863 * @return mainwp_extensions value.
864 */
865 public static function hook_get_all_extensions() {
866 MainWP_Deprecated_Hooks::maybe_handle_deprecated_hook();
867 return get_option( 'mainwp_extensions' );
868 }
869
870 /**
871 * Clone Site.
872 *
873 * @param mixed $pluginFile Extension plugin file to verify.
874 * @param mixed $key The child-key.
875 * @param mixed $websiteid Child Site ID.
876 * @param mixed $cloneID Clone ID.
877 * @param mixed $clone_url URL to CLone to.
878 * @param bool $force_update true|false, force an update.
879 *
880 * @return mixed false|$ret
881 *
882 * @uses \MainWP\Dashboard\MainWP_Sync::sync_site()
883 * @uses \MainWP\Dashboard\MainWP_System_Utility::can_edit_website()
884 * @uses \MainWP\Dashboard\MainWP_Utility::remove_http_www_prefix()
885 */
886 public static function hook_clone_site( $pluginFile, $key, $websiteid, $cloneID, $clone_url, $force_update = false ) { //phpcs:ignore -- NOSONAR - complex.
887 if ( ! static::hook_verify( $pluginFile, $key ) ) {
888 return false;
889 }
890
891 if ( ! empty( $websiteid ) && ! empty( $cloneID ) ) {
892
893 $sql = MainWP_DB::instance()->get_sql_website_by_id( $websiteid );
894 $websites = MainWP_DB::instance()->query( $sql );
895 $website = MainWP_DB::fetch_object( $websites );
896
897 if ( empty( $website ) ) {
898 return array( 'error' => esc_html__( 'Website not found.', 'mainwp' ) );
899 }
900
901 $ret = array();
902
903 if ( '/' !== substr( $clone_url, - 1 ) ) {
904 $clone_url .= '/';
905 }
906
907 $tmp1 = MainWP_Utility::remove_http_www_prefix( $website->url );
908 $tmp2 = MainWP_Utility::remove_http_www_prefix( $clone_url );
909
910 if ( false === strpos( $tmp2, $tmp1 ) ) {
911 return false;
912 }
913
914 $clone_sites = MainWP_DB::instance()->get_websites_by_url( $clone_url );
915 if ( $clone_sites ) {
916 $clone_site = current( $clone_sites );
917 if ( $clone_site && $clone_site->is_staging ) {
918
919 // try to decrypt priv key.
920 $de_privkey = MainWP_Encrypt_Data_Lib::instance()->decrypt_privkey( base64_decode( $website->privkey ), $website->id ); // phpcs:ignore -- NOSONAR - base64_encode trust.
921 if ( ! empty( $de_privkey ) ) {
922 $en_privkey = MainWP_Encrypt_Data_Lib::instance()->encrypt_privkey( $de_privkey, $clone_site->id, true ); // create encrypt priv key for clone site.
923 } else {
924 $en_privkey = base64_decode( $website->privkey ); // phpcs:ignore -- NOSONAR -trust - compatible.
925 }
926
927 if ( $force_update ) {
928 MainWP_DB::instance()->update_website_values(
929 $clone_site->id,
930 array(
931 'adminname' => $website->adminname,
932 'pubkey' => $website->pubkey,
933 'privkey' => is_array( $en_privkey ) ? base64_encode( json_encode( $en_privkey ) ) : base64_encode( $en_privkey ), //phpcs:ignore -- NOSONAR -ok.
934 'verify_certificate' => $website->verify_certificate,
935 'uniqueId' => ( null !== $website->uniqueId ? $website->uniqueId : '' ),
936 // MWP-1548: decrypt the source's credentials and let
937 // update_website_values re-encrypt under a fresh keyfile,
938 // so the cloned site doesn't share the source row's file_key.
939 'http_user' => MainWP_Credential_Storage::decrypt_credential( $website->http_user ),
940 'http_pass' => MainWP_Credential_Storage::decrypt_credential( $website->http_pass ),
941 'ssl_version' => $website->ssl_version,
942 )
943 );
944 }
945 $ret['siteid'] = $clone_site->id;
946 $ret['response'] = esc_html__( 'Site updated.', 'mainwp' );
947 }
948 return $ret;
949 }
950 $clone_name = $website->name . ' - ' . $cloneID;
951
952 /**
953 * Current user global.
954 *
955 * @global string
956 */
957 global $current_user;
958
959 $others = array(
960 'groupids' => array(),
961 'groupnames' => array(),
962 'verifyCertificate' => $website->verify_certificate,
963 'addUniqueId' => ( null !== $website->uniqueId ? $website->uniqueId : '' ),
964 // MWP-1548: same pattern as the force_update branch above --
965 // decrypt the source's credentials, let add_website re-encrypt
966 // for the new clone with a fresh keyfile.
967 'http_user' => MainWP_Credential_Storage::decrypt_credential( $website->http_user ),
968 'http_pass' => MainWP_Credential_Storage::decrypt_credential( $website->http_pass ),
969 'sslVersion' => $website->ssl_version,
970 'wpe' => $website->wpe,
971 'isStaging' => 1,
972 );
973
974 $de_privkey = base64_decode( $website->privkey ); //phpcs:ignore -- NOSONAR -trust - compatible.
975 $de_privkey = MainWP_Encrypt_Data_Lib::instance()->decrypt_privkey( $de_privkey, $site_id );
976
977 if ( ! empty( $de_privkey ) ) {
978 $de_privkey = base64_encode( $de_privkey ); //phpcs:ignore -- NOSONAR -ok.
979 } else {
980 $de_privkey = $website->privkey; // compatible - encoded.
981 }
982
983 $id = MainWP_DB::instance()->add_website( $current_user->ID, $clone_name, $clone_url, $website->adminname, $website->pubkey, $de_privkey, $others );
984
985 /** This action is documented in class\class-mainwp-manage-sites-view.php */
986 do_action( 'mainwp_added_new_site', $id, $website );
987
988 if ( $id ) {
989 $group_id = get_option( 'mainwp_stagingsites_group_id' );
990 if ( $group_id ) {
991 $website = MainWP_DB::instance()->get_website_by_id( $id );
992 if ( MainWP_System_Utility::can_edit_website( $website ) ) {
993 MainWP_Sync::sync_site( $website, false, false );
994 $group = MainWP_DB_Common::instance()->get_group_by_id( $group_id );
995 if ( ! empty( $group ) ) {
996 MainWP_DB_Common::instance()->update_group_site( $group->id, $id );
997 }
998 }
999 }
1000 $ret['response'] = esc_html__( 'Site successfully added.', 'mainwp' );
1001 $ret['siteid'] = $id;
1002 }
1003 return $ret;
1004 }
1005
1006 return false;
1007 }
1008
1009 /**
1010 * Delete Clones Site.
1011 *
1012 * @param mixed $pluginFile Extension plugin file to verify.
1013 * @param mixed $key The child-key.
1014 * @param mixed $clone_url URL to Clone to.
1015 * @param bool $clone_site_id Cloned Site ID.
1016 *
1017 * @return mixed false|array Array => "Success".
1018 *
1019 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_wp_file_system()
1020 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_icons_dir()
1021 */
1022 public static function hook_delete_clone_site( $pluginFile, $key, $clone_url = '', $clone_site_id = false ) { //phpcs:ignore -- NOSONAR - complex.
1023 if ( ! static::hook_verify( $pluginFile, $key ) ) {
1024 return false;
1025 }
1026
1027 if ( empty( $clone_url ) && empty( $clone_site_id ) ) {
1028 return false;
1029 }
1030
1031 $clone_site = null;
1032 if ( ! empty( $clone_url ) ) {
1033 if ( '/' !== substr( $clone_url, - 1 ) ) {
1034 $clone_url .= '/';
1035 }
1036 $clone_sites = MainWP_DB::instance()->get_websites_by_url( $clone_url );
1037 if ( ! empty( $clone_sites ) ) {
1038 $clone_site = current( $clone_sites );
1039
1040 }
1041 } elseif ( ! empty( $clone_site_id ) ) {
1042 $sql = MainWP_DB::instance()->get_sql_website_by_id( $clone_site_id );
1043 $websites = MainWP_DB::instance()->query( $sql );
1044 $clone_site = MainWP_DB::fetch_object( $websites );
1045 }
1046
1047 if ( empty( $clone_site ) ) {
1048 return array( 'error' => esc_html__( 'Not found the clone website', 'mainwp' ) );
1049 }
1050
1051 if ( $clone_site ) {
1052 if ( empty( $clone_site->is_staging ) ) {
1053 return false;
1054 }
1055
1056 MainWP_System_Utility::get_wp_file_system();
1057
1058 /**
1059 * WordPress files system object.
1060 *
1061 * @global object
1062 */
1063 global $wp_filesystem;
1064
1065 $favi = MainWP_DB::instance()->get_website_option( $clone_site, 'favi_icon', '' );
1066 if ( ! empty( $favi ) && ( false !== strpos( $favi, 'favi-' . $clone_site->id . '-' ) ) ) {
1067 $dirs = MainWP_System_Utility::get_icons_dir();
1068 if ( $wp_filesystem->exists( $dirs[0] . $favi ) ) {
1069 $wp_filesystem->delete( $dirs[0] . $favi );
1070 }
1071 }
1072
1073 MainWP_DB::instance()->remove_website( $clone_site->id );
1074
1075 /** This action is documented in pages\page-mainwp-manage-sites-handler.php */
1076 do_action( 'mainwp_delete_site', $clone_site );
1077 return array( 'result' => 'SUCCESS' );
1078 }
1079
1080 return false;
1081 }
1082
1083 /**
1084 * Add Groups.
1085 *
1086 * @param mixed $pluginFile Extension plugin file to verify.
1087 * @param mixed $key The child-key.
1088 * @param mixed $newName Name that you want to give the group.
1089 *
1090 * @return mixed false|$groupId
1091 *
1092 * @uses \MainWP\Dashboard\MainWP_Manage_Groups::check_group_name()
1093 */
1094 public static function hook_add_group( $pluginFile, $key, $newName ) {
1095
1096 if ( ! static::hook_verify( $pluginFile, $key ) ) {
1097 return false;
1098 }
1099
1100 /**
1101 * Current user global.
1102 *
1103 * @global string
1104 */
1105 global $current_user;
1106
1107 if ( ! empty( $newName ) ) {
1108 $groupId = MainWP_DB_Common::instance()->add_group( $current_user->ID, MainWP_Manage_Groups::check_group_name( $newName ) );
1109
1110 /** This action is documented in pages\page-mainwp-manage-groups.php */
1111 do_action( 'mainwp_added_new_group', $groupId );
1112 return $groupId;
1113 }
1114 return false;
1115 }
1116 }
1117