PluginProbe
MainWP Dashboard: Self-hosted WordPress Management for Agencies / 6.2.1
MainWP Dashboard: Self-hosted WordPress Management for Agencies v6.2.1
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 / class / class-mainwp-system.php

class-mainwp-system.php in MainWP Dashboard: Self-hosted WordPress Management for Agencies 6.2.1, at class/class-mainwp-system.php

2,238 lines 89.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * MainWP System.
4 *
5 * @package MainWP/Dashboard
6 */
7
8 namespace MainWP\Dashboard;
9
10 use MainWP\Dashboard\Module\Log\Log_Manage_Insights_Events_Page;
11
12 // Exit if accessed directly.
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit;
15 }
16
17 // phpcs:disable Generic.Metrics.CyclomaticComplexity -- complexity.
18 // phpcs:disable plugin_updater_detected -- not a self-updater; injects update data exclusively for licensed MainWP premium extensions hosted on mainwp.com.
19
20 const MAINWP_VIEW_PER_SITE = 1;
21 const MAINWP_VIEW_PER_PLUGIN_THEME = 0;
22 const MAINWP_VIEW_PER_GROUP = 2;
23
24 // phpcs:disable WordPress.WP.AlternativeFunctions -- for custom read/write file.
25
26 /**
27 * Class MainWP_System
28 *
29 * @package MainWP\Dashboard
30 */
31 class MainWP_System { // phpcs:ignore Generic.Classes.OpeningBraceSameLine.ContentAfterBrace -- NOSONAR.
32
33 /**
34 * Public static variable to hold the current plugin version.
35 *
36 * @var string Current plugin version.
37 */
38 public static $version = '6.2.1'; // NOSONAR.
39
40 /**
41 * Private static variable to hold the single instance of the class.
42 *
43 * @var mixed Default null
44 */
45 private static $instance = null;
46
47 /**
48 * Public variable to hold the Metaboxes instance.
49 *
50 * @var object Metaboxes.
51 */
52 public $metaboxes;
53
54 /**
55 * Private variable to hold the current version.
56 *
57 * @var string The plugin current version.
58 */
59 private $current_version = null;
60
61
62 /**
63 * Private variable to hold the check update version number.
64 *
65 * @var string The plugin current update version.
66 */
67 private $check_ver_update = '0.0.8';
68
69 /**
70 * Private variable to hold the plugin slug (mainwp/mainwp.php)
71 *
72 * @var string Plugin slug.
73 */
74 private $plugin_slug;
75
76
77 /**
78 * Private variable to hold the defer js handle.
79 *
80 * @var array Defer js handle.
81 */
82 private static $defer_js_handle = array();
83
84
85 /**
86 * Method instance()
87 *
88 * Create a public static instance.
89 *
90 * @static
91 * @return MainWP_System
92 */
93 public static function instance() {
94 return static::$instance;
95 }
96
97 /**
98 * MainWP_System constructor.
99 *
100 * Runs any time class is called.
101 *
102 * @param string $mainwp_plugin_file Plugn slug.
103 *
104 * @uses \MainWP\Dashboard\MainWP_Bulk_Post
105 * @uses \MainWP\Dashboard\MainWP_Hooks
106 * @uses \MainWP\Dashboard\MainWP_Menu::get_class_name()
107 * @uses \MainWP\Dashboard\MainWP_Menu
108 * @uses \MainWP\Dashboard\MainWP_Meta_Boxes
109 * @uses \MainWP\Dashboard\MainWP_System_Cron_Jobs::init_cron_jobs()
110 * @uses \MainWP\Dashboard\MainWP_System_Cron_Jobs
111 * @uses \MainWP\Dashboard\MainWP_System_Handler
112 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_class_name()
113 * @uses \MainWP\Dashboard\MainWP_System_View::get_class_name()
114 * @uses \MainWP\Dashboard\MainWP_UI::get_class_name()
115 * @uses \MainWP\Dashboard\MainWP_WP_CLI_Command::init()
116 * @uses \MainWP\Dashboard\MainWP_Updates_Overview::init()
117 * @uses \MainWP\Dashboard\MainWP_Extensions::init()
118 * @uses \MainWP\Dashboard\MainWP_Extensions_Handler::get_class_name()
119 * @uses \MainWP\Dashboard\MainWP_Install_Bulk::init()
120 * @uses \MainWP\Dashboard\MainWP_Manage_Backups::init()
121 * @uses \MainWP\Dashboard\MainWP_Manage_Sites::init()
122 * @uses \MainWP\Dashboard\MainWP_Overview::get()
123 * @uses \MainWP\Dashboard\MainWP_Page::init()
124 * @uses \MainWP\Dashboard\MainWP_Plugins::init()
125 * @uses \MainWP\Dashboard\MainWP_Post::init()
126 * @uses \MainWP\Dashboard\MainWP_Settings::init()
127 * @uses \MainWP\Dashboard\MainWP_Themes::init()
128 * @uses \MainWP\Dashboard\MainWP_Updates::init()
129 * @uses \MainWP\Dashboard\MainWP_User::init()
130 * @uses \MainWP\Dashboard\MainWP_Updates::init()
131 * @uses \MainWP\Dashboard\MainWP_Utility::update_option()
132 */
133 public function __construct( $mainwp_plugin_file ) { //phpcs:ignore -- NOSONAR - complex.
134 static::$instance = $this;
135
136 MainWP_Execution_Helper::instance()->init_exec_time();
137
138 $includer = new MainWP_Includes();
139 $includer->includes();
140
141 MainWP_Keys_Manager::auto_load_files();
142 MainWP_Keys_Manager::register_migration_hooks();
143
144 $this->load_all_options();
145
146 $this->update_install();
147 $this->plugin_slug = plugin_basename( $mainwp_plugin_file );
148
149 add_action( 'shutdown', array( $this, 'hook_wp_shutdown' ) );
150
151 do_action( 'mainwp_system_init' );
152
153 if ( is_admin() ) {
154 include_once ABSPATH . 'wp-admin' . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'plugin.php'; // NOSONAR - WP compatible.
155 $pluginData = get_plugin_data( $mainwp_plugin_file, true, false ); // to fix issue of user language setting.
156 $this->current_version = $pluginData['Version'];
157 $currentVersion = get_option( 'mainwp_plugin_version' );
158
159 if ( ! empty( $currentVersion ) && version_compare( $currentVersion, '4.0', '<' ) && version_compare( $this->current_version, '4.0', '>=' ) ) {
160 add_action( 'mainwp_after_header', array( MainWP_System_View::get_class_name(), 'mainwp_4_update_notice' ) );
161 }
162
163 if ( ! empty( $currentVersion ) && version_compare( $currentVersion, '5.0', '<' ) && version_compare( $this->current_version, '5.0', '>=' ) ) {
164 add_action( 'mainwp_after_header', array( MainWP_System_View::get_class_name(), 'mainwp_ver5_update_notice' ) );
165 }
166
167 if ( ! empty( $currentVersion ) && version_compare( $currentVersion, '5.0.2', '<' ) && version_compare( $this->current_version, '5.0.2', '>=' ) ) {
168 add_action( 'mainwp_after_header', array( MainWP_System_View::get_class_name(), 'mainwp_ver502_update_notice' ) );
169 }
170
171 // Use 6.0.12 as the lower bound so 6.1-er.x builds trigger this notice.
172 if ( ! empty( $currentVersion ) && version_compare( $currentVersion, '6.1', '<' ) && version_compare( $currentVersion, '6.0.12', '>' ) ) {
173 add_action( 'mainwp_after_header', array( MainWP_System_View::get_class_name(), 'mainwp_ver61_update_notice' ) );
174 }
175
176 MainWP_Utility::update_option( 'mainwp_plugin_version', $this->current_version );
177 }
178
179 if ( ! defined( 'MAINWP_VERSION' ) ) {
180
181 /**
182 * Defines MainWP Version.
183 *
184 * @const ( string )
185 * @source https://code-reference.mainwp.com/classes/MainWP.Dashboard.MainWP_System.html
186 */
187 define( 'MAINWP_VERSION', $this->current_version );
188 }
189
190 if ( get_option( 'mainwp_setting_demo_mode_enabled' ) && ! defined( 'MAINWP_DEMO_MODE' ) ) {
191 define( 'MAINWP_DEMO_MODE', true );
192 }
193
194 $ssl_api_verifyhost = ( ( get_option( 'mainwp_api_sslVerifyCertificate' ) === false ) || ( 1 === (int) get_option( 'mainwp_api_sslVerifyCertificate' ) ) ) ? 1 : 0;
195 if ( empty( $ssl_api_verifyhost ) ) {
196 add_filter(
197 'http_request_args',
198 array(
199 MainWP_Extensions_Handler::get_class_name(),
200 'no_ssl_filter_extension_upgrade',
201 ),
202 99,
203 2
204 );
205 }
206
207 MainWP_Extensions::init();
208 MainWP_Extensions_Groups::init();
209
210 $systemHandler = MainWP_System_Handler::instance();
211
212 add_action( 'init', array( &$this, 'localization' ) );
213 add_filter( 'site_transient_update_plugins', array( $systemHandler, 'check_update_custom' ) ); // phpcs:ignore PluginCheck.CodeAnalysis.Sniffs.UpdatingPluginTransientFound -- not a self-updater; injects update data exclusively for licensed MainWP premium extensions (hosted on mainwp.com), not for the Dashboard plugin itself.
214 add_filter( 'pre_set_site_transient_update_plugins', array( $systemHandler, 'pre_check_update_custom' ) ); // phpcs:ignore PluginCheck.CodeAnalysis.Sniffs.UpdatingPluginTransientFound -- same as above; pre-populates update info for MainWP premium extensions before WordPress saves the transient.
215 add_filter( 'plugins_api', array( $systemHandler, 'plugins_api_extension_info' ), 10, 3 );
216 add_filter( 'plugins_api_result', array( $systemHandler, 'plugins_api_wp_plugins_api_result' ), 10, 3 );
217 add_filter( 'upgrader_pre_download', array( $systemHandler, 'hook_refresh_trusted_extension_package_url' ), 10, 4 );
218
219 $this->metaboxes = new MainWP_Meta_Boxes();
220
221 MainWP_Overview::get();
222 MainWP_Client_Overview::instance();
223
224 MainWP_Manage_Sites::init();
225 MainWP_Uptime_Monitoring_Handle::instance();
226
227 MainWP_Hooks::get_instance();
228 MainWP_Menu::get_instance();
229
230 add_action( 'plugins_loaded', array( $this, 'plugins_loaded' ), 9 );
231 add_action( 'admin_menu', array( MainWP_Menu::get_class_name(), 'init_mainwp_menus' ) );
232 add_filter( 'admin_footer', array( &$this, 'admin_footer' ), 15 );
233 add_action( 'admin_head', array( MainWP_System_View::get_class_name(), 'admin_head' ) );
234 add_action( 'admin_enqueue_scripts', array( &$this, 'admin_enqueue_styles' ) );
235 add_action( 'admin_enqueue_scripts', array( &$this, 'admin_enqueue_scripts' ) );
236 add_action( 'admin_enqueue_scripts', array( &$this, 'admin_enqueue_scripts_fix_conflict' ), 9 );
237 add_action( 'admin_body_class', array( MainWP_System_View::get_class_name(), 'admin_body_class' ) );
238
239 MainWP_Bulk_Post::get_instance();
240
241 add_action( 'admin_init', array( &$this, 'admin_init' ), 20 );
242 add_action( 'admin_init', array( $this, 'hook_admin_update_check' ) );
243 add_action( 'admin_init', array( $this, 'admin_init_update' ) );
244 add_action( 'after_setup_theme', array( &$this, 'after_setup_theme' ) );
245
246 add_action( 'init', array( &$this, 'parse_init' ) );
247 add_action( 'init', array( &$this, 'init_jobs' ) );
248 add_action( 'init', array( &$this, 'init' ), 9999 );
249
250 add_action( 'admin_init', array( $this, 'admin_redirects' ) );
251 add_action( 'current_screen', array( &$this, 'current_screen_redirects' ), 15 );
252 add_filter( 'plugin_action_links', array( $this, 'hook_plugin_action_links' ), 10, 4 );
253 add_action( 'admin_menu', array( &$this, 'admin_menu' ) );
254 add_action( 'admin_print_styles', array( MainWP_System_View::get_class_name(), 'admin_print_styles' ) );
255
256 add_action( 'wp_logout', array( &$this, 'clear_sessions' ) );
257
258 MainWP_Install_Bulk::init();
259
260 add_action( 'mainwp_after_header', array( MainWP_System_View::get_class_name(), 'admin_notices' ) );
261 add_action( 'admin_notices', array( MainWP_System_View::get_class_name(), 'wp_admin_notices' ) );
262 add_action( 'wp_mail_failed', array( &$this, 'wp_mail_failed' ) );
263
264 add_action( 'after_plugin_row', array( MainWP_System_View::get_class_name(), 'after_extensions_plugin_row' ), 10, 3 );
265
266 add_filter( 'mainwp-activated-check', array( &$this, 'activated_check' ) ); // @deprecated Use 'mainwp_activated_check' instead.
267 add_filter( 'mainwp_activated_check', array( &$this, 'activated_check' ) );
268
269 do_action_deprecated( 'mainwp-activated', array(), '4.0.7.2', 'mainwp_activated' ); // @deprecated Use 'mainwp_activated' instead. NOSONAR - not IP.
270
271 /**
272 * Action: mainwp_activated
273 *
274 * Fires upon MainWP plugin activation.
275 *
276 * @since Unknown
277 */
278 do_action( 'mainwp_activated' );
279
280 MainWP_Updates::init();
281 MainWP_Post::init();
282 MainWP_Settings::init();
283 if ( get_option( 'mainwp_enableLegacyBackupFeature' ) ) {
284 MainWP_Manage_Backups::init();
285 }
286 MainWP_Manage_Groups::init();
287 MainWP_User::init();
288 MainWP_Password_Policy_Settings::init();
289 MainWP_Page::init();
290 MainWP_Themes::init();
291 MainWP_Plugins::init();
292 MainWP_Updates_Overview::init();
293 MainWP_Client::init();
294 MainWP_Rest_Api_Page::init();
295 MainWP_Logger::instance();
296
297 if ( class_exists( '\MainWP\Dashboard\Module\Log\Log_Manage_Insights_Events_Page' ) ) {
298 Log_Manage_Insights_Events_Page::instance();
299 }
300
301 MainWP_Uptime_Monitoring_Schedule::instance();
302
303 if ( defined( 'WP_CLI' ) && WP_CLI ) {
304 MainWP_WP_CLI_Command::init();
305 }
306 MainWP_Unhooks_Helper::instance();
307 MainWP_Cache_Warm_Helper::instance();
308 MainWP_System_Utility::instance();
309
310 add_action(
311 'wp_ajax_nopriv_mainwp_self_connect',
312 array( MainWP_Post_Handler::instance(), 'ajax_self_connect' )
313 );
314 }
315
316 /**
317 * Method get_dashboard_version()
318 *
319 * Get dashboard version.
320 *
321 * @return string $version Version.
322 */
323 public function get_dashboard_version() {
324 return static::$version;
325 }
326
327 /**
328 * Method get_mainwp_version()
329 *
330 * Get dashboard version.
331 *
332 * @return string $version Version.
333 */
334 public static function get_mainwp_version() { //phpcs:ignore -- NOSONAR same function body.
335 return static::$version;
336 }
337
338 /**
339 * Method load_all_options()
340 *
341 * Load all wp_options data.
342 *
343 * @return array $alloptions Array of all options.
344 */
345 public function load_all_options() { //phpcs:ignore -- NOSONAR - complex.
346
347 /**
348 * WordPress Database instance.
349 *
350 * @global object $wpdb
351 */
352 global $wpdb;
353
354 if ( ! defined( 'WP_INSTALLING' ) || ! is_multisite() ) {
355 $alloptions = wp_cache_get( 'alloptions', 'options' );
356 } else {
357 $alloptions = false;
358 }
359
360 if ( ! defined( 'WP_INSTALLING' ) || ! is_multisite() ) {
361 $notoptions = wp_cache_get( 'notoptions', 'options' );
362 } else {
363 $notoptions = false;
364 }
365
366 if ( ! isset( $alloptions['mainwp_db_version'] ) ) {
367 $suppress = $wpdb->suppress_errors();
368 $options = array(
369 'mainwp_db_version',
370 'mainwp_plugin_version',
371 'mainwp_upgradeVersionInfo',
372 'mainwp_extensions',
373 'mainwp_activated',
374 'mainwp_api_sslVerifyCertificate',
375 'mainwp_automaticDailyUpdate',
376 'mainwp_pluginAutomaticDailyUpdate',
377 'mainwp_themeAutomaticDailyUpdate',
378 'mainwp_backup_before_upgrade',
379 'mainwp_enableLegacyBackupFeature',
380 'mainwp_maximumInstallUpdateRequests',
381 'mainwp_maximumSyncRequests',
382 'mainwp_primaryBackup',
383 'mainwp_use_favicon',
384 'mainwp_wp_cron',
385 'mainwp_timeDailyUpdate',
386 'mainwp_frequencyDailyUpdate',
387 'mainwp_delay_autoupdate',
388 'mainwp_wpcreport_extension',
389 'mainwp_daily_digest_plain_text',
390 'mainwp_hide_update_everything',
391 'mainwp_disable_update_confirmations',
392 'mainwp_settings_show_widgets',
393 'mainwp_clients_show_widgets',
394 'mainwp_settings_show_manage_sites_columns',
395 'mainwp_individual_uptime_monitoring_schedule_enabled',
396 'mainwp_disableSitesHealthMonitoring',
397 'mainwp_sitehealthThreshold',
398 'mainwp_check_http_response',
399 'mainwp_extmenu',
400 'mainwp_opensslLibLocation',
401 'mainwp_notice_wp_mail_failed',
402 'mainwp_show_language_updates',
403 'mainwp_logger_check_daily',
404 'mainwp_site_actions_notification_enable',
405 'mainwp_update_check_version',
406 'mainwp_admin_init_update_data',
407 'mainwp_setting_demo_mode_enabled',
408 'mainwp_log_wait_lasttime',
409 'mainwp_cron_license_deactivated_alert_lasttime',
410 'mainwp_updatescheck_is_running',
411 'mainwp_automatic_updates_is_running',
412 'mainwp_frequency_AutoUpdate',
413 'mainwp_batch_updates_is_running',
414 'mainwp_batch_individual_updates_is_running',
415 'mainwp_maximum_uptime_monitoring_requests',
416 'mainwp_actionlogs',
417 'mainwp_process_uptime_notification_run_status',
418 'mainwp_warm_cache_pages_ttl',
419 'mainwp_module_log_settings_logs_selection_data',
420 );
421
422 $options = apply_filters( 'mainwp_init_load_all_options', $options );
423
424 $query = "SELECT option_name, option_value FROM $wpdb->options WHERE option_name in (";
425 foreach ( $options as $option ) {
426 $query .= "'" . $option . "', ";
427 }
428 $query = substr( $query, 0, strlen( $query ) - 2 );
429 $query .= ")"; // phpcs:ignore -- ignore double quotes auto-correction.
430 $alloptions_db = $wpdb->get_results( $query ); // phpcs:ignore -- unprepared SQL ok.
431 $wpdb->suppress_errors( $suppress );
432 if ( ! is_array( $alloptions ) ) {
433 $alloptions = array();
434 }
435 if ( is_array( $alloptions_db ) ) {
436 foreach ( (array) $alloptions_db as $o ) {
437 $alloptions[ $o->option_name ] = $o->option_value;
438 unset( $options[ array_search( $o->option_name, $options ) ] );
439 }
440 if ( ! is_array( $notoptions ) ) {
441 $notoptions = array();
442 }
443 foreach ( $options as $option ) {
444 $notoptions[ $option ] = true;
445 }
446 if ( ! defined( 'WP_INSTALLING' ) || ! is_multisite() ) {
447 wp_cache_set( 'alloptions', $alloptions, 'options' );
448 wp_cache_set( 'notoptions', $notoptions, 'options' );
449 }
450 }
451 }
452
453 return $alloptions;
454 }
455
456 /**
457 * Method localization()
458 *
459 * Loads plugin language files.
460 */
461 public function localization() {
462 $load = apply_filters( 'mainwp_load_text_domain', true );
463 if ( $load ) {
464 load_plugin_textdomain( 'mainwp', false, dirname( dirname( plugin_basename( __FILE__ ) ) ) . '/languages/' ); // phpcs:ignore PluginCheck.CodeAnalysis.DiscouragedFunctions.load_plugin_textdomainFound -- kept for older WP versions (<4.6) and to support local/custom translation files loaded from the plugin's languages directory.
465 }
466 }
467
468
469 /**
470 * Method wp_mail_failed()
471 *
472 * Check if there has been a wp mail failer.
473 *
474 * @param string $error Array of error messages.
475 *
476 * @uses \MainWP\Dashboard\MainWP_Logger::debug()
477 * @uses \MainWP\Dashboard\MainWP_Utility::update_option()
478 */
479 public function wp_mail_failed( $error ) {
480 $mail_failed = get_option( 'mainwp_notice_wp_mail_failed' );
481 if ( is_object( $error ) && empty( $mail_failed ) ) {
482 MainWP_Utility::update_option( 'mainwp_notice_wp_mail_failed', 'yes' );
483 $er = $error->get_error_message();
484 if ( ! empty( $er ) ) {
485 MainWP_Logger::instance()->debug( 'Error :: wp_mail :: [error=' . $er . ']' );
486 }
487 }
488 }
489
490 /**
491 * Method get_version()
492 *
493 * Get current plugin version.
494 *
495 * @return string Current plugin version.
496 */
497 public function get_version() {
498 return $this->current_version;
499 }
500
501 /**
502 * Method mainwp_cronpingchilds_action()
503 *
504 * Run cron ping child's action.
505 *
506 * @uses \MainWP\Dashboard\MainWP_System_Cron_Jobs::cron_ping_childs()
507 */
508 public function mainwp_cronpingchilds_action() {
509 MainWP_System_Cron_Jobs::instance()->cron_ping_childs();
510 }
511
512 /**
513 * Method mainwp_cronbackups_continue_action()
514 *
515 * Run cron backups continue action.
516 *
517 * @uses \MainWP\Dashboard\MainWP_System_Cron_Jobs::cron_backups_continue()
518 */
519 public function mainwp_cronbackups_continue_action() {
520 MainWP_System_Cron_Jobs::instance()->cron_backups_continue();
521 }
522
523 /**
524 * Method mainwp_cronbackups_action()
525 *
526 * Run cron backups action.
527 *
528 * @uses \MainWP\Dashboard\MainWP_System_Cron_Jobs::cron_backups()
529 */
530 public function mainwp_cronbackups_action() {
531 MainWP_System_Cron_Jobs::instance()->cron_backups();
532 }
533
534 /**
535 * Method mainwp_cronreconnect_action()
536 *
537 * Run cron stats action.
538 *
539 * @uses \MainWP\Dashboard\MainWP_System_Cron_Jobs::cron_reconnect()
540 */
541 public function mainwp_cronreconnect_action() {
542 MainWP_System_Cron_Jobs::instance()->cron_reconnect();
543 }
544
545 /**
546 * Method mainwp_cronupdatescheck_action()
547 *
548 * Run cron updates check action.
549 *
550 * @uses \MainWP\Dashboard\MainWP_System_Cron_Jobs::cron_updates_check()
551 */
552 public function mainwp_cronupdatescheck_action() {
553 MainWP_System_Cron_Jobs::instance()->cron_updates_check();
554 }
555
556 /**
557 * Method mainwp_cron_uptime_monitoring_check_action()
558 *
559 * Run cron uptime monitoring check action.
560 */
561 public function mainwp_cron_uptime_monitoring_check_action() {
562 MainWP_Uptime_Monitoring_Schedule::instance()->cron_uptime_check();
563 }
564
565 /**
566 * Method mainwp_cron_perform_general_schedules_action()
567 *
568 * Run cron uptime monitoring check action.
569 */
570 public function mainwp_cron_perform_general_schedules_action() {
571 MainWP_System_Cron_Jobs::instance()->cron_perform_general_process();
572 }
573
574
575 /**
576 * Method mainwp_crondeactivatedlicensesalert_action()
577 *
578 * Run cron activated licenses alert action.
579 */
580 public function mainwp_crondeactivatedlicensesalert_action() {
581 MainWP_System_Cron_Jobs::instance()->cron_deactivated_licenses_alert();
582 }
583
584 /**
585 * Method mainwp_cronchecksitehealth_action()
586 *
587 * Run cron check sites health action.
588 *
589 * @uses \MainWP\Dashboard\MainWP_System_Cron_Jobs::cron_check_websites_health()
590 */
591 public function mainwp_cronchecksitehealth_action() {
592 MainWP_System_Cron_Jobs::instance()->cron_check_websites_health();
593 }
594
595 /**
596 * Method is_mainwp_pages()
597 *
598 * Get the current page and check it for "mainwp_".
599 *
600 * @return boolean ture|false.
601 */
602 public static function is_mainwp_pages() {
603 $screen = get_current_screen();
604 if ( $screen && strpos( $screen->base, 'mainwp_' ) !== false && strpos( $screen->base, 'mainwp_child_tab' ) === false ) {
605 return true;
606 }
607
608 return false;
609 }
610
611 /**
612 * Method is_mainwp_site_page()
613 *
614 * Checks if the current page is under the site mode.
615 *
616 * @return boolean ture|false.
617 */
618 public static function is_mainwp_site_page() {
619 $is_page = false;
620 //phpcs:disable WordPress.Security.NonceVerification.Recommended
621 if ( isset( $_GET['page'] ) && 'CostTrackerAdd' !== $_GET['page'] && ( ( ( isset( $_GET['id'] ) && ! empty( $_GET['id'] ) ) || ( isset( $_GET['dashboard'] ) && ! empty( $_GET['dashboard'] ) ) || ( isset( $_GET['updateid'] ) && ! empty( $_GET['updateid'] ) ) || ( isset( $_GET['monitor_wpid'] ) && ! empty( $_GET['monitor_wpid'] ) ) || ( isset( $_GET['emailsettingsid'] ) && ! empty( $_GET['emailsettingsid'] ) ) || ( isset( $_GET['scanid'] ) && ! empty( $_GET['scanid'] ) ) ) || ( 'ServerInformation' === $_GET['page'] || 'ServerInformationCron' === $_GET['page'] || 'ErrorLog' === $_GET['page'] || 'ActionLogs' === $_GET['page'] || 'PluginPrivacy' === $_GET['page'] || 'Settings' === $_GET['page'] || 'SettingsAdvanced' === $_GET['page'] || 'SettingsEmail' === $_GET['page'] || 'PremiumUpdates' === $_GET['page'] || 'MainWPTools' === $_GET['page'] || 'SettingsInsights' === $_GET['page'] || 'SettingsApiBackups' === $_GET['page'] || 'MonitoringSettings' === $_GET['page'] ) ) ) {
622 $is_page = true;
623 }
624 //phpcs:enable
625
626 /**
627 * Hook mainwp_is_mainwp_site_page.
628 *
629 * @since 5.4.1
630 */
631 return apply_filters( 'mainwp_is_mainwp_site_page', $is_page );
632 }
633
634
635 /**
636 * Method plugins_loaded()
637 *
638 * Load plugin text domain.
639 */
640 public function plugins_loaded() { // phpcs:ignore -- NOSONAR - complex.
641 /**
642 * Action: mainwp_system_plugins_loaded
643 *
644 * Fires after all plugins are loaded.
645 *
646 * @since 6.1.0
647 */
648 do_action( 'mainwp_system_plugins_loaded' );
649
650 if ( ! function_exists( 'MainWP\Dashboard\mainwp_current_user_have_right' ) ) {
651
652 /**
653 * Method \mainwp_current_user_can()
654 *
655 * Check permission level by hook mainwp_currentusercan of Team Control extension.
656 *
657 * @param string $cap_type group or type of capabilities.
658 * @param string $cap capabilities for current user.
659 *
660 * @return bool true|false
661 *
662 * @uses \MainWP\Dashboard\MainWP_System_Handler::handle_settings_post()
663 */
664 function mainwp_current_user_have_right( $cap_type = '', $cap = '' ) {
665
666 /**
667 * Current user global.
668 *
669 * @global string
670 */
671 global $current_user;
672
673 if ( defined( 'DOING_CRON' ) && DOING_CRON ) {
674 return true;
675 }
676
677 if ( defined( 'WP_CLI' ) && WP_CLI ) {
678 return true;
679 }
680
681 if ( defined( 'MAINWP_REST_API_DOING' ) && MAINWP_REST_API_DOING ) {
682 return true;
683 }
684
685 if ( empty( $current_user ) && ! function_exists( 'wp_get_current_user' ) ) {
686 require_once ABSPATH . WPINC . '/pluggable.php'; // NOSONAR - WP compatible.
687 }
688
689 return apply_filters( 'mainwp_currentusercan', true, $cap_type, $cap );
690 }
691 }
692 }
693
694 /**
695 * Method init()
696 *
697 * Instantiate Plugin.
698 */
699 public function init() { //phpcs:ignore -- NOSONAR - complex.
700
701 /**
702 * MainWP disabled menu items array.
703 *
704 * @global object $_mainwp_disable_menus_items
705 */
706 global $_mainwp_disable_menus_items;
707
708 $_mainwp_disable_menus_items = apply_filters( 'mainwp_disablemenuitems', $_mainwp_disable_menus_items );
709
710 /**
711 * Filter: mainwp_main_menu_disable_menu_items
712 *
713 * Filters disabled MainWP navigation items.
714 *
715 * @since Unknown
716 */
717 $_mainwp_disable_menus_items = apply_filters( 'mainwp_main_menu_disable_menu_items', $_mainwp_disable_menus_items );
718
719 MainWP_System_Handler::instance()->handle_settings_post();
720 }
721
722 /**
723 * Method parse_init()
724 *
725 * Initiate plugin installation & then run the Quick Setup Wizard.
726 *
727 * @uses \MainWP\Dashboard\MainWP_System_Handler::upload_file()
728 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_mainwp_dir()
729 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_wp_file_system()
730 * @uses \MainWP\Dashboard\MainWP_System_Utility::is_admin()
731 * @uses \MainWP\Dashboard\MainWP_Setup_Wizard()
732 */
733 public function parse_init() {
734 // phpcs:disable WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
735 if ( isset( $_GET['mwpdl'] ) && isset( $_GET['sig'] ) ) {
736 $mwpDir = MainWP_System_Utility::get_mainwp_dir();
737 $mwpDir = $mwpDir[0];
738 $mwpdl = isset( $_REQUEST['mwpdl'] ) ? wp_unslash( $_REQUEST['mwpdl'] ) : '';
739 $file = trailingslashit( $mwpDir ) . rawurldecode( $mwpdl );
740
741 if ( stristr( rawurldecode( $mwpdl ), '..' ) ) {
742 return;
743 }
744
745 $hasWPFileSystem = MainWP_System_Utility::get_wp_file_system();
746
747 /**
748 * WordPress files system object.
749 *
750 * @global object
751 */
752 global $wp_filesystem;
753 $sig_value = wp_unslash( $_GET['sig'] );
754 $valid_sig = MainWP_System_Utility::valid_download_sig( $file, $sig_value );
755
756 if ( ! $valid_sig ) {
757 MainWP_Logger::instance()->debug( ' :: download :: invalid sig :: ' . base64_decode( $sig_value ) ); // phpcs:ignore -- for debug logging.
758 }
759
760 if ( $hasWPFileSystem && $wp_filesystem->exists( $file ) && $valid_sig ) {
761 MainWP_System_Handler::instance()->upload_file( $file );
762 exit();
763 }
764 } elseif ( isset( $_GET['page'] ) ) {
765 if ( MainWP_System_Utility::is_admin() && 'mainwp-setup' === $_GET['page'] ) {
766 MainWP_Setup_Wizard::get_instance();
767 }
768 }
769 // phpcs:enable
770 }
771
772 /**
773 * Method init_jobs()
774 *
775 * Initiate mainwp schedule jobs.
776 */
777 public function init_jobs() {
778 MainWP_System_Cron_Jobs::instance()->init_cron_jobs();
779 }
780
781
782 /**
783 * Method after_setup_theme()
784 *
785 * After setup theme hook, to support post thumbnails.
786 */
787 public function after_setup_theme() {
788 add_theme_support( 'post-thumbnails' );
789 }
790
791
792 /**
793 * Method hook_admin_update_check()
794 */
795 public function hook_admin_update_check() {
796 $current_ver = $this->check_ver_update;
797 $saved_ver = get_option( 'mainwp_update_check_version', '' );
798
799 if ( version_compare( $saved_ver, $current_ver, '=' ) ) {
800 return;
801 }
802
803 if ( ! empty( $saved_ver ) && version_compare( $saved_ver, '0.0.4', '<' ) ) {
804 $sched = wp_next_scheduled( 'mainwp_cronstats_action' );
805 if ( ! empty( $sched ) ) {
806 wp_unschedule_event( $sched, 'mainwp_cronstats_action' );
807 }
808 global $wpdb;
809 $wpdb->query( 'DELETE FROM ' . $wpdb->usermeta . ' WHERE meta_key = "mainwp_widgets_sorted_toplevel_page_mainwp_tab" OR meta_key="mainwp_settings_show_widgets"' );//phpcs:ignore -- safe.
810 }
811
812 if ( ! empty( $saved_ver ) && version_compare( $saved_ver, '0.0.5', '<' ) ) {
813 $all_ext = MainWP_Extensions_View::get_available_extensions();
814 foreach ( $all_ext as $slug => $info ) {
815 $data = MainWP_Api_Manager::instance()->get_activation_info( $slug );
816 if ( is_array( $data ) && isset( $data['api_key'] ) ) {
817 $data['api_key'] = '';
818 $data['activated_key'] = 'Deactivated';
819 MainWP_Api_Manager::instance()->set_activation_info( $slug, $data );
820 }
821 }
822 update_option( 'mainwp_extensions_all_activation_cached', '' );
823 }
824
825 if ( version_compare( $saved_ver, '0.0.8', '<' ) ) {
826 static::handle_admin_perform_update( 'attempted_repair_primary_monitors' ); // init attempted repair.
827 }
828
829 MainWP_Utility::update_option( 'mainwp_update_check_version', $current_ver );
830 }
831
832
833 /**
834 * Method admin_init_update()
835 */
836 public function admin_init_update() {
837 static::handle_admin_perform_update();
838 }
839
840
841 /**
842 * Method handle_admin_perform_update()
843 *
844 * @param string $action Init action.
845 */
846 public function handle_admin_perform_update( $action = '' ) {
847
848 $update_actions = get_option( 'mainwp_admin_init_update_data' );
849
850 /**
851 * Filters the update actions.
852 *
853 * @param array $update_actions The available update actions.
854 * @param string $action The current update action.
855 *
856 * @since 6.2.1
857 *
858 * @return array The filtered update actions.
859 */
860 $update_actions = apply_filters( 'mainwp_admin_init_update_data', $update_actions, $action );
861
862 if ( ! empty( $action ) ) {
863 if ( ! is_array( $update_actions ) ) {
864 $update_actions = array();
865 }
866 if ( 'attempted_repair_primary_monitors' === $action ) {
867 $update_actions['attempted_repair_primary_monitors'] = 0;
868 }
869 }
870
871 if ( is_array( $update_actions ) ) {
872 $update = false;
873 if ( isset( $update_actions['attempted_repair_primary_monitors'] ) ) {
874 $result = MainWP_DB_Uptime_Monitoring::instance()->repair_missing_primary_monitors( $update_actions['attempted_repair_primary_monitors'] );
875 if ( is_array( $result ) && ! empty( $result['attempted'] ) ) {
876 $update_actions['attempted_repair_primary_monitors'] = $result['attempted'];
877 } else {
878 unset( $update_actions['attempted_repair_primary_monitors'] );
879 }
880 $update = true;
881 }
882
883 if ( $update ) {
884 MainWP_Utility::update_option( 'mainwp_admin_init_update_data', $update_actions );
885 }
886 }
887 }
888
889 /**
890 * Method admin_init()
891 *
892 * Do nothing if current user is not an Admin else display the page.
893 *
894 * @uses \MainWP\Dashboard\MainWP_Post_Backup_Handler::init()
895 * @uses \MainWP\Dashboard\MainWP_Post_Extension_Handler::init()
896 * @uses \MainWP\Dashboard\MainWP_Post_Handler::init()
897 * @uses \MainWP\Dashboard\MainWP_Post_Plugin_Theme_Handler::init()
898 * @uses \MainWP\Dashboard\MainWP_Post_Site_Handler::init()
899 * @uses \MainWP\Dashboard\MainWP_System_Handler::activate_extension()
900 * @uses \MainWP\Dashboard\MainWP_System_Utility::is_admin()
901 * @uses \MainWP\Dashboard\MainWP_System_View::get_class_name()
902 * @uses \MainWP\Dashboard\MainWP_System_View::get_mainwp_translations()
903 */
904 public function admin_init() { // phpcs:ignore -- NOSONAR - complex function.
905
906 if ( ! MainWP_System_Utility::is_admin() ) {
907 return;
908 }
909
910 add_action( 'mainwp_activate_extention', array( MainWP_System_Handler::instance(), 'activate_extension' ), 10, 2 ); // @deprecated Use 'mainwp_activate_extension' instead.
911 add_action( 'mainwp_deactivate_extention', array( MainWP_System_Handler::instance(), 'deactivate_extension' ), 10, 3 ); // @deprecated Use 'mainwp_deactivate_extension' instead.
912
913 add_action( 'mainwp_activate_extension', array( MainWP_System_Handler::instance(), 'activate_extension' ), 10, 2 );
914 add_action( 'mainwp_deactivate_extension', array( MainWP_System_Handler::instance(), 'deactivate_extension' ), 10, 3 );
915
916 /**
917 * MainWP use external primary backup method.
918 *
919 * @global string
920 */
921 global $mainwpUseExternalPrimaryBackupsMethod;
922
923 if ( null === $mainwpUseExternalPrimaryBackupsMethod ) {
924 $return = '';
925
926 /*
927 * @deprecated Use 'mainwp_getprimarybackup_activated' instead.
928 *
929 */
930 $return = apply_filters_deprecated( 'mainwp-getprimarybackup-activated', array( $return ), '4.0.7.2', 'mainwp_getprimarybackup_activated' ); // NOSONAR - not IP.
931 $mainwpUseExternalPrimaryBackupsMethod = apply_filters( 'mainwp_getprimarybackup_activated', $return );
932 }
933
934 add_action( 'mainwp_after_header', array( MainWP_System_View::get_class_name(), 'mainwp_warning_notice' ) );
935
936 MainWP_Post_Handler::instance()->init();
937 MainWP_Post_Site_Handler::instance()->init();
938 MainWP_Post_Plugin_Theme_Handler::instance()->init();
939 MainWP_Post_Extension_Handler::instance()->init();
940 MainWP_Post_Backup_Handler::instance()->init();
941 MainWP_Manage_Sites_Filter_Segment::get_instance()->admin_init();
942 MainWP_Ui_Manage_Widgets_Layout::get_instance()->admin_init();
943
944 /**
945 * Filter: mainwp_ui_use_wp_calendar
946 *
947 * Filters whether default jQuery datepicker should be used to avoid potential problems with Senatic UI Calendar library.
948 *
949 * @since 4.0.5
950 */
951 $use_wp_datepicker = apply_filters( 'mainwp_ui_use_wp_calendar', false );
952 if ( $use_wp_datepicker ) {
953 wp_enqueue_script( 'jquery-ui-datepicker' );
954 }
955 wp_enqueue_script( 'jquery-ui-dialog' );
956 $en_params = array( 'jquery-ui-dialog' );
957 if ( $use_wp_datepicker ) {
958 $en_params[] = 'jquery-ui-datepicker';
959 }
960
961 static::$defer_js_handle = array_merge( static::$defer_js_handle, array( 'mainwp' ) );
962
963 wp_enqueue_script( 'mainwp', MAINWP_PLUGIN_URL . 'assets/js/mainwp.js', $en_params, $this->current_version, true );
964 wp_enqueue_script( 'mainwp-cache-warm', MAINWP_PLUGIN_URL . 'assets/js/mainwp-cache-warm.js', array(), $this->current_version, true );
965
966 $disable_backup_checking = true; // removed option.
967 $mainwpParams = array(
968 'image_url' => MAINWP_PLUGIN_URL . 'assets/images/',
969 'backup_before_upgrade' => 1 === (int) get_option( 'mainwp_backup_before_upgrade' ),
970 'disable_checkBackupBeforeUpgrade' => $disable_backup_checking,
971 'admin_url' => admin_url(),
972 'use_wp_datepicker' => $use_wp_datepicker ? 1 : 0,
973 'date_format' => get_option( 'date_format' ),
974 'time_format' => get_option( 'time_format' ),
975 'installedBulkSettingsManager' => is_plugin_active( 'mainwp-bulk-settings-manager/mainwp-bulk-settings-manager.php' ) ? 1 : 0,
976 'maximumSyncRequests' => ( get_option( 'mainwp_maximumSyncRequests' ) === false ) ? 8 : get_option( 'mainwp_maximumSyncRequests' ),
977 'maximumInstallUpdateRequests' => ( get_option( 'mainwp_maximumInstallUpdateRequests' ) === false ) ? 3 : get_option( 'mainwp_maximumInstallUpdateRequests' ),
978 'maximumUptimeMonitoringRequests' => (int) get_option( 'mainwp_maximum_uptime_monitoring_requests', 10 ),
979 '_wpnonce' => wp_create_nonce( 'mainwp-admin-nonce' ),
980 'quickThemeChangeNonce' => wp_create_nonce( 'mainwp_quick_theme_change' ),
981 'demoMode' => MainWP_Demo_Handle::is_demo_mode() ? 1 : 0,
982 'roll_ui_icon' => MainWP_Updates_Helper::get_roll_icon( '', true ),
983 'admin_url_base' => admin_url(),
984 'mainwpVersion' => static::$version,
985 );
986 wp_localize_script( 'mainwp', 'mainwpParams', $mainwpParams );
987
988 $mainwpTranslations = MainWP_System_View::get_mainwp_translations();
989
990 wp_localize_script( 'mainwp', 'mainwpTranslations', $mainwpTranslations );
991
992 $security_nonces = MainWP_Post_Handler::instance()->create_security_nonces(); // to fix conflict with Post S M T P plugin.
993 $nonces_filter = apply_filters( 'mainwp_security_nonces', array() );
994 if ( is_array( $nonces_filter ) && ! empty( $nonces_filter ) ) {
995 $security_nonces = array_merge( $security_nonces, $nonces_filter );
996 }
997 wp_localize_script( 'mainwp', 'security_nonces', $security_nonces );
998
999 wp_enqueue_script( 'thickbox' );
1000 wp_enqueue_script( 'user-profile' );
1001 wp_enqueue_style( 'thickbox' );
1002
1003 $load_gridstack = false;
1004
1005 // phpcs:disable WordPress.Security.NonceVerification
1006 if ( ( isset( $_GET['page'] ) && ( 'mainwp_tab' === $_GET['page'] || ( 'managesites' === $_GET['page'] && isset( $_GET['dashboard'] ) ) ) ) || ( isset( $_GET['page'] ) && 'ManageClients' === $_GET['page'] && isset( $_GET['client_id'] ) ) || ( isset( $_GET['page'] ) && 0 === strpos( wp_unslash( $_GET['page'] ), 'ManageSites' ) ) ) { //phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- individual page.
1007 $load_gridstack = true;
1008 }
1009
1010 // compatible filter.
1011 $load_gridstack = apply_filters( 'mainwp_enqueue_script_gridster', $load_gridstack );
1012
1013 if ( $load_gridstack ) {
1014 static::$defer_js_handle[] = 'mainwp_gridstack';
1015 wp_enqueue_script( 'mainwp_gridstack', MAINWP_PLUGIN_URL . 'assets/js/gridstack/gridstack-all.js', array( 'jquery' ), $this->current_version, true );
1016 wp_enqueue_style( 'mainwp_gridstack', MAINWP_PLUGIN_URL . 'assets/js/gridstack/gridstack.min.css', array(), $this->current_version );
1017 }
1018
1019 if ( isset( $_GET['page'] ) && ( 'managesites' === $_GET['page'] || 'MonitoringSites' === $_GET['page'] || 'ManageGroups' === $_GET['page'] ) ) { //phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
1020 wp_enqueue_script( 'preview', MAINWP_PLUGIN_URL . 'assets/js/preview.js', array(), $this->current_version, true );
1021 wp_enqueue_style( 'preview', MAINWP_PLUGIN_URL . 'assets/css/preview.css', array(), $this->current_version );
1022 }
1023 // phpcs:enable
1024
1025 wp_enqueue_style( 'wp-color-picker' );
1026 wp_enqueue_script( 'wp-color-picker' );
1027
1028 $this->init_session();
1029
1030 if ( ! current_user_can( 'update_core' ) ) {
1031 remove_action( 'admin_notices', 'update_nag', 3 );
1032 }
1033 }
1034
1035
1036 /**
1037 * Method hook_wp_shutdown()
1038 */
1039 public function hook_wp_shutdown() {
1040 if ( MainWP_Logger::DISABLED !== (int) get_option( 'mainwp_actionlogs' ) ) {
1041 $error = error_get_last();
1042 if ( is_array( $error ) && isset( $error['type'] ) && ( E_ERROR === $error['type'] || E_CORE_ERROR === $error['type'] || E_COMPILE_ERROR === $error['type'] || E_PARSE === $error['type'] ) ) {
1043 MainWP_Logger::instance()->log_action( '[Fatal ERROR detected=' . print_r( $error, true ) . ']', false, MainWP_Logger::WARNING_COLOR, true ); //phpcs:ignore -- NOSONAR.
1044 }
1045 }
1046 MainWP_Cache_Helper::log_metrics();
1047
1048 /**
1049 * MainWP shutdown.
1050 *
1051 * @since 5.5.
1052 */
1053 do_action( 'mainwp_shutdown' );
1054
1055 $exctime = MainWP_Execution_Helper::get_run_time();
1056 MainWP_Logger::instance()->log_events( 'execution-time', 'Shutdown :: ' . $exctime );
1057 MainWP_Logger::instance()->log_execution_sync( 'end' );
1058 }
1059
1060 /**
1061 * Method hook_plugin_action_links()
1062 *
1063 * @param string[] $actions An array of plugin action links. By default this can include
1064 * 'activate', 'deactivate', and 'delete'. With Multisite active
1065 * this can also include 'network_active' and 'network_only' items.
1066 * @param string $plugin_file Path to the plugin file relative to the plugins directory.
1067 * @param array $plugin_data An array of plugin data. See get_plugin_data()
1068 * and the {@see 'plugin_row_meta'} filter for the list
1069 * of possible values.
1070 */
1071 public function hook_plugin_action_links( $actions, $plugin_file, $plugin_data ) {
1072 unset( $plugin_file ); // not use, compatible.
1073 if ( is_array( $plugin_data ) && ! empty( $plugin_data['slug'] ) && ! empty( $plugin_data['plugin'] ) && 'mainwp' === $plugin_data['slug'] && 'mainwp/mainwp.php' === $plugin_data['plugin'] ) {
1074 $tmp = array(
1075 'mainwp-setup' => '<a href="admin.php?page=mainwp-setup" id="mainwp-setup" aria-label="' . esc_html__( 'MainWP Dashboard Setup Wizard', 'mainwp' ) . '">' . esc_html__( 'Setup Wizard', 'mainwp' ) . '</a>',
1076 );
1077 if ( is_array( $actions ) ) {
1078 foreach ( $actions as $key => $val ) {
1079 $tmp[ $key ] = $val;
1080
1081 }
1082 }
1083 return $tmp;
1084 }
1085 return $actions;
1086 }
1087
1088 /**
1089 * Method current_screen_redirects()
1090 *
1091 * MainWP current screen redirects.
1092 */
1093 public function current_screen_redirects() {
1094
1095 if ( ( defined( 'DOING_CRON' ) && DOING_CRON ) || defined( 'DOING_AJAX' ) ) {
1096 return;
1097 }
1098 if ( static::is_mainwp_pages() ) {
1099 $quick_setup = get_option( 'mainwp_run_quick_setup', false );
1100 if ( 'yes' === $quick_setup ) {
1101 delete_option( 'mainwp_run_quick_setup' );
1102 wp_safe_redirect( admin_url( 'admin.php?page=mainwp-setup' ) );
1103 exit;
1104 }
1105 }
1106
1107 if ( ! empty( $_GET['page'] ) && in_array( $_GET['page'], array( 'mainwp-setup' ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
1108 return;
1109 }
1110
1111 if ( static::is_mainwp_pages() && 'yes' === get_option( 'mainwp_activated' ) ) {
1112 delete_option( 'mainwp_activated' );
1113 wp_cache_delete( 'mainwp_activated', 'options' );
1114 wp_cache_delete( 'alloptions', 'options' );
1115 wp_safe_redirect( admin_url( 'admin.php?page=mainwp_tab' ) );
1116 exit;
1117 }
1118 }
1119
1120 /**
1121 * Method admin_redirects()
1122 *
1123 * MainWP admin redirects.
1124 */
1125 public function admin_redirects() {
1126 if ( ( defined( 'DOING_CRON' ) && DOING_CRON ) || defined( 'DOING_AJAX' ) ) {
1127 return;
1128 }
1129
1130 if ( ! empty( $_GET['page'] ) && in_array( $_GET['page'], array( 'mainwp-setup' ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
1131 return;
1132 }
1133
1134 $quick_setup = get_option( 'mainwp_run_quick_setup', false );
1135 if ( 'yes' === $quick_setup ) {
1136 wp_safe_redirect( admin_url( 'admin.php?page=mainwp-setup' ) );
1137 exit;
1138 }
1139
1140 $request_uri = isset( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
1141 $_pos = strlen( $request_uri ) - strlen( '/wp-admin/' );
1142 if ( ! empty( $request_uri ) && strpos( $request_uri, '/wp-admin/' ) !== false && strpos( $request_uri, '/wp-admin/' ) === $_pos ) {
1143 $referer = wp_get_referer();
1144 if ( ! empty( $referer ) && strpos( $referer, 'wp-login.php?redirect_to' ) !== false && strpos( $referer, '&reauth=1' ) !== false && \mainwp_current_user_can( 'dashboard', 'access_global_dashboard' ) ) {
1145 wp_safe_redirect( admin_url( 'admin.php?page=mainwp_tab' ) );
1146 die();
1147 }
1148 }
1149
1150 MainWP_Logger::instance()->check_log_daily();
1151 }
1152
1153 /**
1154 * Method init_session()
1155 *
1156 * Check current page & initiate a session.
1157 *
1158 * @uses \MainWP\Dashboard\MainWP_Cache::init_session()
1159 */
1160 public function init_session() {
1161 $page = isset( $_GET['page'] ) ? wp_unslash( $_GET['page'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
1162 if ( ! empty( $page ) && in_array(
1163 $page,
1164 array(
1165 'PostBulkManage',
1166 'PageBulkManage',
1167 'PluginsManage',
1168 'PluginsAutoUpdate',
1169 'ThemesManage',
1170 'ThemesAutoUpdate',
1171 'UserBulkManage',
1172 )
1173 )
1174 ) {
1175 MainWP_Cache::init_session();
1176 }
1177 }
1178
1179 /**
1180 * Method clear_sessions()
1181 *
1182 * When logout clear the sessions to reset.
1183 */
1184 public function clear_sessions() {
1185 MainWP_Cache::init_session();
1186 $clear_cached = array(
1187 'Post',
1188 'Page',
1189 );
1190 foreach ( $clear_cached as $ca ) {
1191 MainWP_Cache::init_cache( $ca ); // to re-set cache.
1192 }
1193 }
1194
1195
1196 /**
1197 * Method admin_enqueue_scripts()
1198 *
1199 * Enqueue all Mainwp Admin Scripts.
1200 */
1201 public function admin_enqueue_scripts() { // phpcs:ignore -- NOSONAR - complex function.
1202
1203 $load_cust_scripts = false;
1204
1205 /**
1206 * Current pagenow.
1207 *
1208 * @global string
1209 */
1210 global $pagenow;
1211
1212 if ( is_plugin_active( 'mainwp-custom-post-types/mainwp-custom-post-types.php' ) && ( 'post-new.php' === $pagenow || 'post.php' === $pagenow ) ) {
1213 $load_cust_scripts = true;
1214 }
1215
1216 if ( static::is_mainwp_pages() ) {
1217 wp_enqueue_script( 'jquery-migrate' );
1218 wp_enqueue_script( 'mainwp-updates', MAINWP_PLUGIN_URL . 'assets/js/mainwp-updates.js', array(), $this->current_version, true );
1219 wp_enqueue_script( 'mainwp-managesites-action', MAINWP_PLUGIN_URL . 'assets/js/mainwp-managesites-action.js', array(), $this->current_version, true );
1220 wp_enqueue_script( 'mainwp-managesites-update', MAINWP_PLUGIN_URL . 'assets/js/mainwp-managesites-update.js', array(), $this->current_version, true );
1221 wp_enqueue_script( 'mainwp-managesites-import', MAINWP_PLUGIN_URL . 'assets/js/mainwp-managesites-import.js', array(), $this->current_version, true );
1222 wp_enqueue_script( 'mainwp-plugins-themes', MAINWP_PLUGIN_URL . 'assets/js/mainwp-plugins-themes.js', array(), $this->current_version, true );
1223 wp_enqueue_script( 'mainwp-backups', MAINWP_PLUGIN_URL . 'assets/js/mainwp-backups.js', array(), $this->current_version, true );
1224 wp_enqueue_script( 'mainwp-posts', MAINWP_PLUGIN_URL . 'assets/js/mainwp-posts.js', array(), $this->current_version, true );
1225 wp_enqueue_script( 'mainwp-users', MAINWP_PLUGIN_URL . 'assets/js/mainwp-users.js', array(), $this->current_version, true );
1226 wp_enqueue_script( 'mainwp-clients', MAINWP_PLUGIN_URL . 'assets/js/mainwp-clients.js', array(), $this->current_version, true );
1227 wp_enqueue_script( 'mainwp-extensions', MAINWP_PLUGIN_URL . 'assets/js/mainwp-extensions.js', array(), $this->current_version, true );
1228 wp_enqueue_script( 'moment' );
1229 wp_enqueue_script( 'fomantic-ui', MAINWP_PLUGIN_URL . 'assets/js/fomantic-ui/fomantic-ui.js', array( 'jquery' ), $this->current_version, false );
1230
1231 wp_enqueue_script( 'datatables', MAINWP_PLUGIN_URL . 'assets/js/datatables/datatables.min.js', array( 'jquery' ), $this->current_version, false );
1232 wp_enqueue_script( 'datatables-semanticui', MAINWP_PLUGIN_URL . 'assets/js/datatables/dataTables.semanticui.min.js', array( 'datatables' ), $this->current_version, false );
1233 wp_enqueue_script( 'datatables-select', MAINWP_PLUGIN_URL . 'assets/js/datatables/dataTables.select.min.js', array( 'datatables' ), $this->current_version, false );
1234 wp_enqueue_script( 'datatables-add-ons', MAINWP_PLUGIN_URL . 'assets/js/datatables/add-ons.datatables.min.js', array( 'datatables' ), $this->current_version, false );
1235
1236 wp_enqueue_script( 'datatables-natural-sorting', MAINWP_PLUGIN_URL . 'assets/js/sorting/natural.min.js', array( 'jquery', 'datatables' ), $this->current_version, true );
1237
1238 wp_enqueue_script( 'clipboard' );
1239 wp_enqueue_script( 'mainwp-rest-api', MAINWP_PLUGIN_URL . 'assets/js/mainwp-rest-api.js', array(), time(), true );
1240
1241 if ( isset( $_GET['page'] ) && 'ManageGroups' === $_GET['page'] ) { // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
1242 wp_enqueue_script( 'mainwp-groups', MAINWP_PLUGIN_URL . 'assets/js/mainwp-groups.js', array(), $this->current_version, true );
1243 }
1244 $enqueue_scripts = apply_filters( 'mainwp_admin_enqueue_scripts', array() );
1245 if ( is_array( $enqueue_scripts ) && ! empty( $enqueue_scripts['apexcharts'] ) ) {
1246 wp_enqueue_script(
1247 'mainwp-apexcharts',
1248 MAINWP_PLUGIN_URL . 'assets/js/apexcharts/apexcharts.min.js',
1249 array(
1250 'jquery',
1251 'mainwp',
1252 ),
1253 $this->current_version,
1254 true
1255 );
1256 static::$defer_js_handle[] = 'mainwp-apexcharts';
1257 }
1258 wp_enqueue_script( 'mainwp-dropzone', MAINWP_PLUGIN_URL . 'assets/js/dropzone/dropzone.min.js', array(), $this->current_version, true );
1259 wp_enqueue_script( 'mainwp-uptime', MAINWP_PLUGIN_URL . 'assets/js/mainwp-uptime.js', array( 'jquery', 'fomantic-ui' ), $this->current_version, true );
1260 static::$defer_js_handle = array_merge( static::$defer_js_handle, array( 'mainwp-updates', 'mainwp-managesites-action', 'mainwp-managesites-update', 'mainwp-managesites-import', 'mainwp-plugins-themes', 'mainwp-managesites-import', 'mainwp-plugins-themes', 'mainwp-backups', 'mainwp-posts', 'mainwp-users', 'mainwp-clients', 'fomantic-ui', 'datatables', 'datatables-semanticui', 'datatables-select', 'datatables-add-ons', 'mainwp-dropzone', 'mainwp-uptime' ) );
1261
1262 }
1263
1264 if ( $load_cust_scripts ) {
1265 static::$defer_js_handle[] = 'fomantic-ui';
1266 wp_enqueue_script( 'fomantic-ui', MAINWP_PLUGIN_URL . 'assets/js/fomantic-ui/fomantic-ui.js', array( 'jquery' ), $this->current_version, true );
1267 }
1268
1269 wp_enqueue_script( 'mainwp-ui', MAINWP_PLUGIN_URL . 'assets/js/mainwp-ui.js', array(), $this->current_version, true );
1270 wp_localize_script(
1271 'mainwp-ui',
1272 'mainwpWidgetLayout',
1273 array(
1274 'openNonce' => wp_create_nonce( 'mainwp-admin-nonce' ),
1275 )
1276 );
1277 wp_enqueue_script( 'mainwp-js-popup', MAINWP_PLUGIN_URL . 'assets/js/mainwp-popup.js', array(), $this->current_version, true );
1278 // to support extension uploader.
1279 wp_enqueue_script( 'mainwp-fileuploader', MAINWP_PLUGIN_URL . 'assets/js/fileuploader.js', array(), $this->current_version ); // phpcs:ignore -- fileuploader scripts need to load at header.
1280 wp_enqueue_script( 'mainwp-filesaver', MAINWP_PLUGIN_URL . 'assets/js/FileSaver.js', array(), $this->current_version, true );
1281
1282 static::$defer_js_handle[] = 'mainwp-ui';
1283
1284 if ( is_array( static::$defer_js_handle ) ) {
1285 $defer_handle = array_filter( array_unique( static::$defer_js_handle ) );
1286 foreach ( $defer_handle as $h ) {
1287 if ( wp_script_is( $h, 'enqueued' ) || wp_script_is( $h, 'registered' ) ) {
1288 wp_script_add_data( $h, 'strategy', 'defer' ); // adds defer to <script> tag.
1289 }
1290 }
1291 }
1292
1293 $this->enqueue_command_palette_script();
1294 }
1295
1296 /**
1297 * Enqueue the MainWP command palette integration.
1298 */
1299 private function enqueue_command_palette_script() {
1300
1301 if ( ! wp_script_is( 'wp-core-commands', 'enqueued' ) ) {
1302 return;
1303 }
1304
1305 $palette_data = $this->get_command_palette_data();
1306
1307 if ( empty( $palette_data['commands'] ) && empty( $palette_data['unregister'] ) ) {
1308 return;
1309 }
1310
1311 wp_enqueue_script(
1312 'mainwp-command-palette',
1313 MAINWP_PLUGIN_URL . 'assets/js/mainwp-command-palette.js',
1314 array( 'wp-core-commands', 'wp-data' ),
1315 $this->current_version,
1316 true
1317 );
1318
1319 wp_add_inline_script(
1320 'mainwp-command-palette',
1321 'window.mainwpCommandPalette = ' . wp_json_encode( $palette_data, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) . ';',
1322 'before'
1323 );
1324 }
1325
1326 /**
1327 * Build the MainWP command palette configuration.
1328 *
1329 * @return array<string, array<int, mixed>> Command palette configuration.
1330 */
1331 private function get_command_palette_data() {
1332 $registered_pages = $this->get_command_palette_registered_pages();
1333 $registered_page_urls = array();
1334
1335 foreach ( $registered_pages as $slug => $page_data ) {
1336 $registered_page_urls[ $slug ] = $page_data['url'];
1337 }
1338
1339 $commands = $this->get_command_palette_menu_commands( $registered_pages );
1340
1341 if ( empty( $commands ) ) {
1342 return array(
1343 'commands' => array(),
1344 'unregister' => array(),
1345 );
1346 }
1347
1348 $commands = apply_filters( 'mainwp_command_palette_commands', $commands, $registered_page_urls );
1349
1350 $unregister = array( 'mainwp_tab' );
1351 foreach ( array_keys( $registered_pages ) as $slug ) {
1352 $unregister[] = 'mainwp_tab-' . $slug;
1353 }
1354
1355 $unregister = apply_filters( 'mainwp_command_palette_unregister', array_values( array_unique( $unregister ) ), $registered_page_urls );
1356
1357 return array(
1358 'commands' => array_values( array_filter( $commands ) ),
1359 'unregister' => array_values( array_filter( $unregister ) ),
1360 );
1361 }
1362
1363 /**
1364 * Get registered MainWP submenu pages that can be opened from the palette.
1365 *
1366 * @return array<string, array<string, mixed>> Registered page map.
1367 */
1368 private function get_command_palette_registered_pages() {
1369 global $submenu;
1370
1371 if ( empty( $submenu['mainwp_tab'] ) || ! is_array( $submenu['mainwp_tab'] ) ) {
1372 return array();
1373 }
1374
1375 $registered_pages = array();
1376
1377 foreach ( $submenu['mainwp_tab'] as $submenu_item ) {
1378 if ( empty( $submenu_item[2] ) || ( ! empty( $submenu_item[1] ) && ! current_user_can( $submenu_item[1] ) ) ) {
1379 continue;
1380 }
1381
1382 $menu_slug = (string) $submenu_item[2];
1383 $menu_url = '';
1384
1385 if ( preg_match( '/\.php($|\?)/', $menu_slug ) || $this->is_command_palette_absolute_url( $menu_slug ) ) {
1386 $menu_url = $menu_slug;
1387 } elseif ( ! empty( menu_page_url( $menu_slug, false ) ) ) {
1388 $menu_url = wp_specialchars_decode( menu_page_url( $menu_slug, false ), ENT_QUOTES );
1389 }
1390
1391 if ( empty( $menu_url ) ) {
1392 continue;
1393 }
1394
1395 $raw_label = isset( $submenu_item[0] ) ? (string) $submenu_item[0] : '';
1396
1397 $registered_pages[ $menu_slug ] = array(
1398 'label' => $this->clean_command_palette_label( $raw_label ),
1399 'url' => $menu_url,
1400 'hidden' => false !== strpos( $raw_label, 'mainwp-hidden' ),
1401 );
1402 }
1403
1404 return $registered_pages;
1405 }
1406
1407 /**
1408 * Build MainWP command-palette commands from runtime menu data.
1409 *
1410 * @param array<string, array<string, mixed>> $registered_pages Registered MainWP pages.
1411 *
1412 * @return array<int, array<string, mixed>> Command list.
1413 */
1414 private function get_command_palette_menu_commands( $registered_pages ) {
1415 $menu_nodes = $this->get_command_palette_menu_nodes();
1416
1417 if ( empty( $menu_nodes ) ) {
1418 $menu_nodes = array();
1419 }
1420
1421 $nodes_by_id = array();
1422 $nodes_by_slug = array();
1423
1424 foreach ( $menu_nodes as $node ) {
1425 $nodes_by_id[ $node['id'] ] = $node;
1426
1427 if ( ! empty( $node['slug_key'] ) && ! isset( $nodes_by_slug[ $node['slug_key'] ] ) ) {
1428 $nodes_by_slug[ $node['slug_key'] ] = $node['id'];
1429 }
1430 }
1431
1432 $commands_by_url = array();
1433 $command_page_slugs = array();
1434
1435 foreach ( $menu_nodes as $node ) {
1436 $path_titles = $this->get_command_palette_menu_path_titles( $node, $nodes_by_id, $nodes_by_slug );
1437
1438 if ( empty( $path_titles ) ) {
1439 continue;
1440 }
1441
1442 $label = sprintf( __( 'Go to: MainWP > %s', 'mainwp' ), implode( ' > ', $path_titles ) );
1443
1444 $command_name = ! empty( $node['page_slug'] ) && isset( $registered_pages[ $node['page_slug'] ] )
1445 ? 'mainwp_tab-' . $node['page_slug']
1446 : 'mainwp-command-' . sanitize_key( ! empty( $node['page_slug'] ) ? $node['page_slug'] : md5( $node['url'] ) );
1447
1448 $command = array(
1449 'name' => $command_name,
1450 'label' => $label,
1451 'url' => $node['url'],
1452 'keywords' => $this->get_command_palette_keywords( $path_titles, $node['page_slug'] ),
1453 'searchLabel' => $label,
1454 '_depth' => count( $path_titles ),
1455 );
1456
1457 if ( ! isset( $commands_by_url[ $node['url'] ] ) || $command['_depth'] > $commands_by_url[ $node['url'] ]['_depth'] ) {
1458 $commands_by_url[ $node['url'] ] = $command;
1459 }
1460
1461 if ( ! empty( $node['page_slug'] ) ) {
1462 $command_page_slugs[ $node['page_slug'] ] = true;
1463 }
1464 }
1465
1466 foreach ( $this->get_command_palette_utility_commands( $registered_pages ) as $command ) {
1467 if ( empty( $command['url'] ) || empty( $command['label'] ) ) {
1468 continue;
1469 }
1470
1471 $command['_depth'] = isset( $command['_depth'] ) ? (int) $command['_depth'] : 1;
1472
1473 if (
1474 ! isset( $commands_by_url[ $command['url'] ] ) ||
1475 $command['_depth'] >= $commands_by_url[ $command['url'] ]['_depth']
1476 ) {
1477 $commands_by_url[ $command['url'] ] = $command;
1478 }
1479
1480 if ( ! empty( $command['_page_slug'] ) ) {
1481 $command_page_slugs[ $command['_page_slug'] ] = true;
1482 }
1483 }
1484
1485 foreach ( $registered_pages as $page_slug => $page_data ) {
1486 if (
1487 isset( $command_page_slugs[ $page_slug ] ) ||
1488 empty( $page_data['label'] ) ||
1489 empty( $page_data['url'] ) ||
1490 ! empty( $page_data['hidden'] )
1491 ) {
1492 continue;
1493 }
1494
1495 if ( isset( $commands_by_url[ $page_data['url'] ] ) ) {
1496 continue;
1497 }
1498
1499 $label = sprintf( __( 'Go to: MainWP > %s', 'mainwp' ), $page_data['label'] );
1500
1501 $commands_by_url[ $page_data['url'] ] = array(
1502 'name' => 'mainwp_tab-' . $page_slug,
1503 'label' => $label,
1504 'url' => $page_data['url'],
1505 'keywords' => $this->get_command_palette_keywords( array( $page_data['label'] ), $page_slug ),
1506 'searchLabel' => $label,
1507 '_depth' => 1,
1508 );
1509 }
1510
1511 foreach ( $commands_by_url as &$command ) {
1512 unset( $command['_depth'], $command['_page_slug'] );
1513 }
1514 unset( $command );
1515
1516 return array_values( $commands_by_url );
1517 }
1518
1519 /**
1520 * Build command-palette commands for MainWP pages that do not reliably exist in the global sidebar tree.
1521 *
1522 * @param array<string, array<string, mixed>> $registered_pages Registered MainWP pages.
1523 *
1524 * @return array<int, array<string, mixed>> Command list.
1525 */
1526 private function get_command_palette_utility_commands( $registered_pages ) {
1527 return array_merge(
1528 $this->get_command_palette_settings_commands( $registered_pages ),
1529 $this->get_command_palette_info_commands( $registered_pages )
1530 );
1531 }
1532
1533 /**
1534 * Build Settings-section command palette commands.
1535 *
1536 * @param array<string, array<string, mixed>> $registered_pages Registered MainWP pages.
1537 *
1538 * @return array<int, array<string, mixed>> Command list.
1539 */
1540 private function get_command_palette_settings_commands( $registered_pages ) {
1541 $commands = array();
1542
1543 foreach ( MainWP_Settings::get_command_palette_items() as $item ) {
1544 if ( empty( $item['slug'] ) || empty( $item['path_titles'] ) ) {
1545 continue;
1546 }
1547
1548 $commands[] = $this->build_command_palette_registered_command(
1549 $registered_pages,
1550 $item['slug'],
1551 $item['path_titles'],
1552 array( 'mainwp settings' ),
1553 isset( $item['href'] ) ? $item['href'] : ''
1554 );
1555 }
1556
1557 return array_values( array_filter( $commands ) );
1558 }
1559
1560 /**
1561 * Build System Info and profile utility command palette commands.
1562 *
1563 * @param array<string, array<string, mixed>> $registered_pages Registered MainWP pages.
1564 *
1565 * @return array<int, array<string, mixed>> Command list.
1566 */
1567 private function get_command_palette_info_commands( $registered_pages ) {
1568 $commands = array();
1569
1570 foreach ( MainWP_Server_Information::get_command_palette_items() as $item ) {
1571 if ( empty( $item['slug'] ) || empty( $item['path_titles'] ) ) {
1572 continue;
1573 }
1574
1575 $commands[] = $this->build_command_palette_registered_command(
1576 $registered_pages,
1577 $item['slug'],
1578 $item['path_titles'],
1579 array( 'system info', 'server info' ),
1580 isset( $item['href'] ) ? $item['href'] : ''
1581 );
1582 }
1583
1584 return array_values( array_filter( $commands ) );
1585 }
1586
1587 /**
1588 * Build a command palette command for a registered page.
1589 *
1590 * @param array<string, array<string, mixed>> $registered_pages Registered MainWP pages.
1591 * @param string $page_slug Registered page slug.
1592 * @param array<int, string> $path_titles Breadcrumb path labels.
1593 * @param array<int, string> $extra_keywords Additional search keywords.
1594 * @param string $href Optional command href override.
1595 *
1596 * @return array<string, mixed>|null Command configuration.
1597 */
1598 private function build_command_palette_registered_command( $registered_pages, $page_slug, $path_titles, $extra_keywords = array(), $href = '' ) {
1599 if ( empty( $registered_pages[ $page_slug ]['url'] ) ) {
1600 return null;
1601 }
1602
1603 $path_titles = array_values(
1604 array_filter(
1605 array_map(
1606 array( $this, 'clean_command_palette_label' ),
1607 is_array( $path_titles ) ? $path_titles : array()
1608 )
1609 )
1610 );
1611
1612 if ( empty( $path_titles ) ) {
1613 return null;
1614 }
1615
1616 $keywords = $this->get_command_palette_keywords( $path_titles, $page_slug );
1617
1618 foreach ( $extra_keywords as $keyword ) {
1619 $keyword = strtolower( $this->clean_command_palette_label( $keyword ) );
1620
1621 if ( ! empty( $keyword ) ) {
1622 $keywords[] = $keyword;
1623 }
1624 }
1625
1626 $label = sprintf( __( 'Go to: MainWP > %s', 'mainwp' ), implode( ' > ', $path_titles ) );
1627 $url = ! empty( $href ) ? $this->normalize_command_palette_url( $href, $page_slug ) : $registered_pages[ $page_slug ]['url'];
1628
1629 if ( empty( $url ) ) {
1630 return null;
1631 }
1632
1633 return array(
1634 'name' => 'mainwp_tab-' . $page_slug,
1635 'label' => $label,
1636 'url' => $url,
1637 'keywords' => array_values( array_unique( array_filter( $keywords ) ) ),
1638 'searchLabel' => $label,
1639 '_depth' => count( $path_titles ),
1640 '_page_slug' => $page_slug,
1641 );
1642 }
1643
1644 /**
1645 * Collect MainWP menu nodes from the runtime left-menu structures.
1646 *
1647 * @return array<int, array<string, string>> Menu nodes.
1648 */
1649 private function get_command_palette_menu_nodes() {
1650 global $mainwp_leftmenu, $mainwp_sub_leftmenu;
1651
1652 $left_menu = apply_filters( 'mainwp_main_menu', is_array( $mainwp_leftmenu ) ? $mainwp_leftmenu : array() );
1653 $sub_left_menu = apply_filters( 'mainwp_main_menu_submenu', is_array( $mainwp_sub_leftmenu ) ? $mainwp_sub_leftmenu : array() );
1654 $menu_nodes = array();
1655
1656 if ( ! empty( $left_menu['leftbar'] ) && is_array( $left_menu['leftbar'] ) ) {
1657 foreach ( $left_menu['leftbar'] as $item ) {
1658 $this->add_command_palette_menu_node(
1659 $menu_nodes,
1660 isset( $item[0] ) ? $item[0] : '',
1661 isset( $item[2] ) ? $item[2] : '',
1662 isset( $item[1] ) ? $item[1] : '',
1663 'mainwp_tab'
1664 );
1665 }
1666 }
1667
1668 foreach ( $left_menu as $parent_key => $items ) {
1669 if ( 'leftbar' === $parent_key || ! is_array( $items ) ) {
1670 continue;
1671 }
1672
1673 foreach ( $items as $item ) {
1674 $this->add_command_palette_menu_node(
1675 $menu_nodes,
1676 isset( $item[0] ) ? $item[0] : '',
1677 isset( $item[2] ) ? $item[2] : '',
1678 isset( $item[1] ) ? $item[1] : '',
1679 $parent_key
1680 );
1681 }
1682 }
1683
1684 if ( ! empty( $sub_left_menu['leftbar'] ) && is_array( $sub_left_menu['leftbar'] ) ) {
1685 foreach ( $sub_left_menu['leftbar'] as $parent_key => $items ) {
1686 if ( ! is_array( $items ) ) {
1687 continue;
1688 }
1689
1690 foreach ( $items as $item ) {
1691 $this->add_command_palette_menu_node(
1692 $menu_nodes,
1693 isset( $item[0] ) ? $item[0] : '',
1694 isset( $item[2] ) ? $item[2] : '',
1695 isset( $item[1] ) ? $item[1] : '',
1696 $parent_key
1697 );
1698 }
1699 }
1700 }
1701
1702 foreach ( $sub_left_menu as $parent_key => $items ) {
1703 if ( 'leftbar' === $parent_key || ! is_array( $items ) ) {
1704 continue;
1705 }
1706
1707 foreach ( $items as $item ) {
1708 $this->add_command_palette_menu_node(
1709 $menu_nodes,
1710 isset( $item[0] ) ? $item[0] : '',
1711 isset( $item[1] ) ? $item[1] : '',
1712 isset( $item[4] ) ? $item[4] : '',
1713 $parent_key
1714 );
1715 }
1716 }
1717
1718 return $menu_nodes;
1719 }
1720
1721 /**
1722 * Add a single node to the command palette source list.
1723 *
1724 * @param array<int, array<string, string>> $menu_nodes Menu nodes.
1725 * @param string $title Menu title.
1726 * @param string $href Menu href.
1727 * @param string $slug Menu slug.
1728 * @param string $parent_key Parent menu slug.
1729 */
1730 private function add_command_palette_menu_node( &$menu_nodes, $title, $href, $slug, $parent_key ) {
1731 $title = $this->clean_command_palette_label( $title );
1732 $url = $this->normalize_command_palette_url( $href, $slug );
1733
1734 if ( empty( $title ) || empty( $url ) ) {
1735 return;
1736 }
1737
1738 $page_slug = $this->get_command_palette_page_slug_from_url( $url );
1739 $slug_key = ! empty( $slug ) ? (string) $slug : $page_slug;
1740
1741 $menu_nodes[] = array(
1742 'id' => md5( $parent_key . '|' . $slug_key . '|' . $url . '|' . $title ),
1743 'parent' => (string) $parent_key,
1744 'page_slug' => $page_slug,
1745 'slug_key' => $slug_key,
1746 'title' => $title,
1747 'url' => $url,
1748 );
1749 }
1750
1751 /**
1752 * Build a node breadcrumb from the MainWP menu tree.
1753 *
1754 * @param array<string, string> $node Menu node.
1755 * @param array<string, array<string, string>> $nodes_by_id Menu nodes indexed by id.
1756 * @param array<string, string> $nodes_by_slug Menu nodes indexed by slug.
1757 *
1758 * @return array<int, string> Path titles.
1759 */
1760 private function get_command_palette_menu_path_titles( $node, $nodes_by_id, $nodes_by_slug ) {
1761 $titles = array();
1762 $current = $node;
1763 $seen_nodes = array();
1764
1765 while ( is_array( $current ) && ! empty( $current['id'] ) && ! isset( $seen_nodes[ $current['id'] ] ) ) {
1766 $seen_nodes[ $current['id'] ] = true;
1767
1768 if ( ! empty( $current['title'] ) ) {
1769 array_unshift( $titles, $current['title'] );
1770 }
1771
1772 if ( empty( $current['parent'] ) || 'mainwp_tab' === $current['parent'] || ! isset( $nodes_by_slug[ $current['parent'] ] ) ) {
1773 break;
1774 }
1775
1776 $parent_id = $nodes_by_slug[ $current['parent'] ];
1777 $current = isset( $nodes_by_id[ $parent_id ] ) ? $nodes_by_id[ $parent_id ] : array();
1778 }
1779
1780 return $titles;
1781 }
1782
1783 /**
1784 * Build search keywords for a MainWP command.
1785 *
1786 * @param array<int, string> $path_titles Path titles.
1787 * @param string $page_slug Page slug.
1788 *
1789 * @return array<int, string> Search keywords.
1790 */
1791 private function get_command_palette_keywords( $path_titles, $page_slug = '' ) {
1792 $keywords = array( 'mainwp' );
1793
1794 foreach ( $path_titles as $title ) {
1795 $keywords[] = strtolower( $title );
1796 }
1797
1798 if ( ! empty( $page_slug ) ) {
1799 $keywords[] = strtolower( str_replace( array( '-', '_' ), ' ', $page_slug ) );
1800 }
1801
1802 return array_values( array_unique( array_filter( $keywords ) ) );
1803 }
1804
1805 /**
1806 * Normalize menu text into readable plain text.
1807 *
1808 * @param string $label Raw menu label.
1809 *
1810 * @return string Plain-text label.
1811 */
1812 private function clean_command_palette_label( $label ) {
1813 $label = wp_specialchars_decode( wp_strip_all_tags( (string) $label ), ENT_QUOTES );
1814 $label = preg_replace( '/\s+/', ' ', $label );
1815
1816 return trim( (string) $label );
1817 }
1818
1819 /**
1820 * Check whether a command-palette URL is already absolute.
1821 *
1822 * @param string $url URL to check.
1823 *
1824 * @return bool True when the URL is an absolute HTTP(S) URL.
1825 */
1826 private function is_command_palette_absolute_url( $url ) {
1827 return 1 === preg_match( '/^https?:\/\//i', trim( (string) $url ) );
1828 }
1829
1830 /**
1831 * Normalize a MainWP menu href into a usable URL.
1832 *
1833 * @param string $href Menu href.
1834 * @param string $slug Menu slug.
1835 *
1836 * @return string Normalized URL.
1837 */
1838 private function normalize_command_palette_url( $href, $slug = '' ) {
1839 $href = trim( wp_specialchars_decode( (string) $href, ENT_QUOTES ) );
1840 $slug = trim( (string) $slug );
1841
1842 if ( empty( $href ) || '#' === $href || 0 === strpos( $href, 'javascript:' ) ) {
1843 if ( empty( $slug ) || preg_match( '/\.php($|\?)/', $slug ) || $this->is_command_palette_absolute_url( $slug ) ) {
1844 return '';
1845 }
1846
1847 return admin_url( 'admin.php?page=' . $slug );
1848 }
1849
1850 if ( $this->is_command_palette_absolute_url( $href ) ) {
1851 return $href;
1852 }
1853
1854 return admin_url( ltrim( $href, '/' ) );
1855 }
1856
1857 /**
1858 * Extract a page slug from a menu URL when one exists.
1859 *
1860 * @param string $url Menu URL.
1861 *
1862 * @return string Page slug.
1863 */
1864 private function get_command_palette_page_slug_from_url( $url ) {
1865 $query = wp_parse_url( $url, PHP_URL_QUERY );
1866
1867 if ( empty( $query ) ) {
1868 return '';
1869 }
1870
1871 parse_str( $query, $query_args );
1872
1873 if ( ! isset( $query_args['page'] ) ) {
1874 return '';
1875 }
1876
1877 return preg_replace( '/[^A-Za-z0-9_-]/', '', (string) $query_args['page'] );
1878 }
1879
1880 /**
1881 * Method admin_enqueue_scripts_fix_conflict()
1882 *
1883 * Enqueue Admin Scripts fix conflict.
1884 */
1885 public function admin_enqueue_scripts_fix_conflict() {
1886 if ( static::is_mainwp_pages() ) {
1887 // to fix conflict with the SVG Support plugin.
1888 remove_action( 'admin_enqueue_scripts', 'bodhi_svgs_admin_multiselect' );
1889 }
1890 }
1891
1892 /**
1893 * Method admin_enqueue_styles()
1894 *
1895 * Enqueue all Mainwp Admin Styles.
1896 */
1897 public function admin_enqueue_styles() { //phpcs:ignore -- NOSONAR - complex.
1898
1899 wp_enqueue_style( 'mainwp', MAINWP_PLUGIN_URL . 'assets/css/mainwp.css', array(), $this->current_version );
1900 wp_enqueue_style( 'mainwp-responsive-layouts', MAINWP_PLUGIN_URL . 'assets/css/mainwp-responsive-layouts.css', array(), $this->current_version );
1901
1902 if ( isset( $_GET['hideall'] ) && 1 === (int) $_GET['hideall'] ) { // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
1903 remove_action( 'admin_footer', 'wp_admin_bar_render', 1000 );
1904 }
1905
1906 /**
1907 * Current pagenow.
1908 *
1909 * @global string
1910 */
1911 global $pagenow;
1912
1913 $load_cust_scripts = false;
1914 if ( is_plugin_active( 'mainwp-custom-post-types/mainwp-custom-post-types.php' ) && ( 'post-new.php' === $pagenow || 'post.php' === $pagenow ) ) {
1915 $load_cust_scripts = true;
1916 }
1917
1918 if ( static::is_mainwp_pages() ) {
1919 wp_enqueue_style( 'mainwp-fonts', MAINWP_PLUGIN_URL . 'assets/css/mainwp-fonts.css', array(), $this->current_version );
1920 wp_enqueue_style( 'fomantic-ui', MAINWP_PLUGIN_URL . 'assets/js/fomantic-ui/fomantic-ui.css', array(), $this->current_version );
1921 wp_enqueue_style( 'mainwp-fomantic', MAINWP_PLUGIN_URL . 'assets/css/mainwp-fomantic.css', array(), $this->current_version );
1922
1923 wp_enqueue_style( 'datatables', MAINWP_PLUGIN_URL . 'assets/js/datatables/dataTables.dataTables.min.css', array(), $this->current_version );
1924 wp_enqueue_style( 'datatables-semanticui', MAINWP_PLUGIN_URL . 'assets/js/datatables/dataTables.semanticui.min.css', array(), $this->current_version );
1925 wp_enqueue_style( 'datatables-select', MAINWP_PLUGIN_URL . 'assets/js/datatables/select.semanticui.min.css', array(), $this->current_version );
1926 wp_enqueue_style( 'datatables-add-ons', MAINWP_PLUGIN_URL . 'assets/js/datatables/add-ons.datatables.min.css', array(), $this->current_version );
1927 // to fix conflict layout.
1928 wp_enqueue_style( 'jquery-ui-style', MAINWP_PLUGIN_URL . 'assets/css/1.11.1/jquery-ui.min.css', array(), '1.11.1' );
1929
1930 // load custom MainWP theme.
1931 $selected_theme = MainWP_Settings::get_instance()->get_selected_theme();
1932 if ( ! empty( $selected_theme ) ) {
1933 if ( 'dark' === $selected_theme ) {
1934 wp_enqueue_style( 'mainwp-custom-dashboard-extension-dark-theme', MAINWP_PLUGIN_URL . 'assets/css/themes/mainwp-dark-theme.css', array(), $this->current_version );
1935 } elseif ( 'wpadmin' === $selected_theme ) {
1936 wp_enqueue_style( 'mainwp-custom-dashboard-extension-wp-admin-theme', MAINWP_PLUGIN_URL . 'assets/css/themes/mainwp-wpadmin-theme.css', array(), $this->current_version );
1937 } elseif ( 'minimalistic' === $selected_theme ) {
1938 wp_enqueue_style( 'mainwp-custom-dashboard-extension-minimalistic-theme', MAINWP_PLUGIN_URL . 'assets/css/themes/mainwp-minimalistic-theme.css', array(), $this->current_version );
1939 } elseif ( 'default-2024' === $selected_theme ) {
1940 wp_enqueue_style( 'mainwp-custom-dashboard-extension-default-2024-theme', MAINWP_PLUGIN_URL . 'assets/css/themes/mainwp-default-2024-theme.css', array(), $this->current_version );
1941 } elseif ( 'default' === $selected_theme ) {
1942 wp_enqueue_style( 'mainwp-custom-dashboard-extension-default-theme', MAINWP_PLUGIN_URL . 'assets/css/themes/mainwp-default-theme.css', array(), $this->current_version );
1943 } elseif ( 'default-dark' === $selected_theme ) {
1944 wp_enqueue_style( 'mainwp-custom-dashboard-extension-default-dark-theme', MAINWP_PLUGIN_URL . 'assets/css/themes/mainwp-default-dark-theme.css', array(), $this->current_version );
1945 } else {
1946 $dirs = MainWP_Settings::get_instance()->get_custom_theme_folder();
1947 $custom_theme_url = $dirs[1];
1948 wp_enqueue_style( 'mainwp-custom-dashboard-theme', $custom_theme_url . $selected_theme, array(), $this->current_version );
1949 }
1950 }
1951 }
1952
1953 if ( $load_cust_scripts ) {
1954 wp_enqueue_style( 'mainwp-fonts', MAINWP_PLUGIN_URL . 'assets/css/mainwp-fonts.css', array(), $this->current_version );
1955 wp_enqueue_style( 'fomantic-ui', MAINWP_PLUGIN_URL . 'assets/js/fomantic-ui/fomantic-ui.css', array(), $this->current_version );
1956 }
1957 }
1958
1959 /**
1960 * Method admin_menu()
1961 *
1962 * Add Bulk Post/Pages menue.
1963 */
1964 public function admin_menu() {
1965
1966 /**
1967 * Admin menu array.
1968 *
1969 * @global object
1970 */
1971 global $menu;
1972
1973 foreach ( $menu as $k => $item ) {
1974 if ( 'edit.php?post_type=bulkpost' === $item[2] || 'edit.php?post_type=bulkpage' === $item[2] ) {
1975 unset( $menu[ $k ] );
1976 }
1977 }
1978 }
1979
1980 /**
1981 * Method enqueue_postbox_scripts()
1982 *
1983 * Enqueue postbox scripts.
1984 */
1985 public static function enqueue_postbox_scripts() {
1986 wp_enqueue_script( 'common' );
1987 wp_enqueue_script( 'wp-lists' );
1988 wp_enqueue_script( 'postbox' );
1989 }
1990
1991 /**
1992 * Method admin_footer()
1993 *
1994 * Create MainWP admin footer.
1995 *
1996 * @uses \MainWP\Dashboard\MainWP_DB::get_website_by_id()
1997 * @uses \MainWP\Dashboard\MainWP_DB::query()
1998 * @uses \MainWP\Dashboard\MainWP_DB::get_sql_websites_for_current_user()
1999 * @uses \MainWP\Dashboard\MainWP_DB::free_result()
2000 * @uses \MainWP\Dashboard\MainWP_Menu::init_subpages_menu()
2001 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_current_wpid()
2002 * @uses \MainWP\Dashboard\MainWP_System_View::render_footer_content()
2003 * @uses \MainWP\Dashboard\MainWP_System_View::admin_footer()
2004 */
2005 public function admin_footer() { //phpcs:ignore -- NOSONAR - complex.
2006 if ( ! static::is_mainwp_pages() ) {
2007 $sites_count = MainWP_DB::instance()->get_websites_count();
2008 if ( empty( $sites_count ) ) {
2009 ?>
2010 <script type="text/javascript">
2011 jQuery( function($){
2012 $( 'li#toplevel_page_mainwp_tab .wp-submenu-wrap .wp-submenu-head' ).after('<li style="background: #FFD300 !important;" class="wp-first-item"><a href="admin.php?page=mainwp-setup" style="color: #000 !important;" class="wp-first-item"><?php esc_html_e( 'Quick Setup', 'mainwp' ); ?></a></li>');
2013 });
2014 </script>
2015 <?php
2016 }
2017 return;
2018 }
2019
2020 ?>
2021 <div class="ui large modal" id="mainwp-response-data-modal">
2022 <i class="close icon"></i>
2023 <div class="header"><?php esc_html_e( 'Child Site Response', 'mainwp' ); ?></div>
2024 <div class="content">
2025 <div class="ui info message"><?php esc_html_e( 'To see the response in a more readable way, you can copy it and paste it into some HTML render tool, such as Codepen.io.', 'mainwp' ); ?>
2026 </div>
2027 </div>
2028 <div class="scrolling content content-response" contenteditable="true"></div>
2029 <div class="actions">
2030 <button class="ui green button mainwp-response-copy-button"><?php esc_html_e( 'Copy Response', 'mainwp' ); ?></button>
2031 </div>
2032 </div>
2033 <div id="mainwp-response-data-container" resp-data=""></div>
2034 <?php
2035
2036 if ( isset( $_GET['hideall'] ) && 1 === (int) $_GET['hideall'] ) { // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
2037 return;
2038 }
2039 $current_wpid = MainWP_System_Utility::get_current_wpid();
2040 if ( $current_wpid ) {
2041 $website = MainWP_DB::instance()->get_website_by_id( $current_wpid );
2042 $websites = array( $website );
2043 } else {
2044 $is_staging = 'no';
2045 if ( isset( $_GET['page'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
2046 if ( ( 'managesites' === $_GET['page'] ) && ! isset( $_GET['id'] ) && ! isset( $_GET['do'] ) && ! isset( $_GET['dashboard'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
2047 $group_ids = get_user_option( 'mainwp_managesites_filter_group' );
2048 if ( ! empty( $group_ids ) ) {
2049 $group_ids = explode( ',', $group_ids ); // convert to array.
2050 }
2051 } elseif ( 'UpdatesManage' === $_GET['page'] || 'mainwp_tab' === $_GET['page'] ) { // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
2052 $staging_enabled = is_plugin_active( 'mainwp-staging-extension/mainwp-staging-extension.php' ) ? true : false;
2053 if ( $staging_enabled ) {
2054 $staging_view = MainWP_System_Utility::get_select_staging_view_sites();
2055 if ( 'staging' === $staging_view ) {
2056 $is_staging = 'yes';
2057 }
2058 }
2059 }
2060 }
2061 $websites = MainWP_DB::instance()->query( MainWP_DB::instance()->get_sql_websites_for_current_user( false, null, 'wp_sync.dtsSync DESC, wp.url ASC', false, false, null, false, array(), $is_staging ) );
2062 }
2063
2064 MainWP_System_View::render_footer_content( $websites, $current_wpid );
2065 if ( empty( $current_wpid ) ) {
2066 MainWP_DB::free_result( $websites );
2067 }
2068
2069 MainWP_System_View::admin_footer();
2070 MainWP_System_View::render_plugins_install_check();
2071
2072 /**
2073 * MainWP disabled menu items array.
2074 *
2075 * @global object
2076 */
2077 global $_mainwp_disable_menus_items;
2078
2079 $_mainwp_disable_menus_items = apply_filters( 'mainwp_all_disablemenuitems', $_mainwp_disable_menus_items );
2080 }
2081
2082 /**
2083 * Method activated_check()
2084 *
2085 * Activated check.
2086 *
2087 * @uses \MainWP\Dashboard\MainWP_Deprecated_Hooks::maybe_handle_deprecated_hook()
2088 */
2089 public function activated_check() {
2090 MainWP_Deprecated_Hooks::maybe_handle_deprecated_hook();
2091 return $this->get_version();
2092 }
2093
2094 /**
2095 * Method activation()
2096 *
2097 * Activate MainWP.
2098 *
2099 * @uses \MainWP\Dashboard\MainWP_Install::install()
2100 * @uses \MainWP\Dashboard\MainWP_Utility::update_option()
2101 */
2102 public function activation() {
2103 $this->update_install();
2104 MainWP_Utility::update_option( 'mainwp_activated', 'yes' );
2105 }
2106
2107 /**
2108 * Method deactivation()
2109 *
2110 * Deactivate MainWP.
2111 */
2112 public function deactivation() {
2113 update_option( 'mainwp_extensions_all_activation_cached', '' );
2114 $useWPCron = ( get_option( 'mainwp_wp_cron' ) === false ) || ( (int) get_option( 'mainwp_wp_cron' ) === 1 );
2115 if ( $useWPCron ) {
2116 $jobs = MainWP_System_Cron_Jobs::instance()->get_cron_jobs();
2117 if ( $jobs ) {
2118 foreach ( $jobs as $job => $recu ) {
2119 wp_clear_scheduled_hook( $job );
2120 }
2121 }
2122 }
2123 }
2124
2125 /**
2126 * Method update_install()
2127 *
2128 * Update MainWP.
2129 *
2130 * @uses \MainWP\Dashboard\MainWP_Install::install()
2131 */
2132 public function update_install() {
2133 MainWP_DB_Client::instance();
2134 MainWP_DB_Site_Actions::instance();
2135 MainWP_Install::instance()->install();
2136 $this->check_to_updates();
2137 }
2138
2139
2140 /**
2141 * Method check_to_updates()
2142 *
2143 * To check updates options.
2144 */
2145 public function check_to_updates() {
2146 $update_ver = get_option( 'mainwp_update_check_version', false );
2147 $current_ver = $this->check_ver_update;
2148
2149 if ( false === $update_ver && version_compare( $current_ver, '0.0.1', '=' ) ) {
2150 // to update new saving format.
2151 MainWP_Api_Manager_Key::instance()->get_decrypt_master_api_key();
2152 MainWP_Utility::update_option( 'mainwp_update_check_version', $current_ver );
2153 }
2154 }
2155
2156 /**
2157 * Method is_single_user()
2158 *
2159 * Check if single user environment.
2160 *
2161 * @return boolean true|false.
2162 */
2163 public function is_single_user() {
2164 return true;
2165 }
2166
2167 /**
2168 * Method is_multi_user()
2169 *
2170 * Check if multi user environment.
2171 *
2172 * @return boolean true|false.
2173 */
2174 public function is_multi_user() {
2175 return ! $this->is_single_user();
2176 }
2177
2178 /**
2179 * Method get_plugin_slug()
2180 *
2181 * Get MainWP Plugin Slug.
2182 */
2183 public function get_plugin_slug() {
2184 return $this->plugin_slug;
2185 }
2186
2187 /**
2188 * Method get_selected_sites_with_allowed_sites.
2189 *
2190 * @param array $selected_ids Selected sites IDs.
2191 * @param array $current_sites Current sites IDs.
2192 * @return array Not selected but in not allowed sites in current sites ids, and selected sites ids.
2193 */
2194 public static function get_selected_sites_with_allowed_sites( $selected_ids, $current_sites_ids = array() ) {
2195
2196 $allowed_sites = apply_filters( 'mainwp_currentuserallowedaccesssites', 'all' );
2197 if ( 'all' === $allowed_sites ) {
2198 return $selected_ids;
2199 }
2200
2201 if ( ! is_array( $selected_ids ) ) {
2202 $selected_ids = array();
2203 }
2204
2205 if ( ! is_array( $current_sites_ids ) ) {
2206 $current_sites_ids = array();
2207 }
2208
2209 $allowed_sites = MainWP_DB::instance()->get_websites_for_current_user();
2210 if ( empty( $allowed_sites ) ) {
2211 return array();
2212 }
2213
2214 $allowed_ids = array_values(
2215 array_map(
2216 function ( $item ) {
2217 return $item->id;
2218 },
2219 $allowed_sites
2220 )
2221 );
2222
2223 $client_site_ids = array();
2224 foreach ( $selected_ids as $id ) {
2225 if ( in_array( $id, $allowed_ids ) ) {
2226 $client_site_ids[] = $id;
2227 }
2228 }
2229
2230 foreach ( $current_sites_ids as $id ) {
2231 if ( ! in_array( $id, $selected_ids ) && ! in_array( $id, $allowed_ids ) ) { // If it’s not in the allowed site IDs, the user is not permitted to change it.
2232 $client_site_ids[] = $id; // keep this site ids.
2233 }
2234 }
2235 return $client_site_ids;
2236 }
2237 }
2238