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

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

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