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 / pages / page-mainwp-settings.php

page-mainwp-settings.php in MainWP Dashboard: Self-hosted WordPress Management for Agencies 6.2.1, at pages/page-mainwp-settings.php

2,841 lines 169.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * MainWP Settings page
4 *
5 * This Class handles building/Managing the
6 * Settings MainWP DashboardPage & all SubPages.
7 *
8 * @package MainWP/Settings
9 */
10
11 namespace MainWP\Dashboard;
12
13 use MainWP\Dashboard\Module\CostTracker\Cost_Tracker_Settings;
14
15 // Exit if accessed directly.
16 if ( ! defined( 'ABSPATH' ) ) {
17 exit;
18 }
19
20 /**
21 * Class MainWP_Settings
22 *
23 * @package MainWP\Dashboard
24 */
25 class MainWP_Settings { // phpcs:ignore Generic.Classes.OpeningBraceSameLine.ContentAfterBrace -- NOSONAR.
26
27 // phpcs:disable Generic.Metrics.CyclomaticComplexity -- complexity.
28
29 /**
30 * Protected static variable to hold the single instance of the class.
31 *
32 * @var mixed Default null
33 */
34 protected static $instance = null;
35
36 /**
37 * Public static varable to hold Subpages information.
38 *
39 * @var array $subPages
40 */
41 public static $subPages;
42
43 /**
44 * Get Class Name
45 *
46 * @return __CLASS__
47 */
48 public static function get_class_name() {
49 return __CLASS__;
50 }
51
52 /**
53 * Return the single instance of the class.
54 *
55 * @return mixed $instance The single instance of the class.
56 */
57 public static function get_instance() {
58 if ( is_null( static::$instance ) ) {
59 static::$instance = new self();
60 }
61 return static::$instance;
62 }
63
64 /** Instantiate Hooks for the Settings Page. */
65 public static function init() {
66 /**
67 * This hook allows you to render the Settings page header via the 'mainwp_pageheader_settings' action.
68 *
69 * This hook is normally used in the same context of 'mainwp_getsubpages_settings'
70 *
71 * @see \MainWP_Settings::render_header
72 */
73 add_action( 'mainwp-pageheader-settings', array( static::get_class_name(), 'render_header' ) ); // deprecated, use mainwp_pageheader_settings.
74
75 add_action( 'mainwp_pageheader_settings', array( static::get_class_name(), 'render_header' ) );
76
77 /**
78 * This hook allows you to render the Settings page footer via the 'mainwp-pagefooter-settings' action.
79 *
80 * This hook is normally used in the same context of 'mainwp-getsubpages-settings'
81 *
82 * @see \MainWP_Settings::render_footer
83 */
84 add_action( 'mainwp-pagefooter-settings', array( static::get_class_name(), 'render_footer' ) ); // deprecated, use mainwp_pagefooter_settings.
85
86 add_action( 'mainwp_pagefooter_settings', array( static::get_class_name(), 'render_footer' ) );
87
88 add_action( 'admin_init', array( static::get_class_name(), 'admin_init' ) );
89
90 add_action( 'mainwp_help_sidebar_content', array( static::get_class_name(), 'mainwp_help_content' ) );
91 }
92
93 /**
94 * Get the registered Settings subpages.
95 *
96 * @return array<int, array<string, mixed>> Settings subpages.
97 */
98 private static function get_subpages() {
99 if ( isset( static::$subPages ) && is_array( static::$subPages ) ) {
100 return static::$subPages;
101 }
102
103 /**
104 * Settings Subpages
105 *
106 * Filters subpages for the Settings page.
107 *
108 * @since Unknown
109 */
110 $sub_pages = apply_filters_deprecated( 'mainwp-getsubpages-settings', array( array() ), '4.0.7.2', 'mainwp_getsubpages_settings' ); // @deprecated Use 'mainwp_getsubpages_settings' instead. NOSONAR - not IP.
111 static::$subPages = apply_filters( 'mainwp_getsubpages_settings', $sub_pages );
112
113 return is_array( static::$subPages ) ? static::$subPages : array();
114 }
115
116 /**
117 * Get the built-in Settings pages used across menu registration and navigation rendering.
118 *
119 * @return array<int, array<string, mixed>> Settings page definitions.
120 */
121 private static function get_core_pages() {
122 $pages = array(
123 array(
124 'slug' => 'Settings',
125 'page_title' => __( 'Settings Global options', 'mainwp' ),
126 'menu_title' => ' <span id="mainwp-Settings">' . esc_html__( 'Settings', 'mainwp' ) . '</span>',
127 'nav_title' => esc_html__( 'General Settings', 'mainwp' ),
128 'callback' => array( static::get_class_name(), 'render' ),
129 'active_keys' => array( '', 'Settings' ),
130 ),
131 array(
132 'slug' => 'MainWPTools',
133 'page_title' => __( 'Tools', 'mainwp' ),
134 'menu_title' => ' <div class="mainwp-hidden">' . esc_html__( 'Tools', 'mainwp' ) . '</div>',
135 'nav_title' => esc_html__( 'Tools', 'mainwp' ),
136 'callback' => array( static::get_class_name(), 'render_mainwp_tools' ),
137 'active_keys' => array( 'MainWPTools' ),
138 ),
139 array(
140 'slug' => 'CostTrackerSettings',
141 'page_title' => esc_html__( 'Cost Tracker Settings', 'mainwp' ),
142 'menu_title' => '<div class="mainwp-hidden">' . esc_html__( 'Cost Tracker', 'mainwp' ) . '</div>',
143 'nav_title' => esc_html__( 'Cost Tracker Settings', 'mainwp' ),
144 'callback' => array( Cost_Tracker_Settings::get_instance(), 'render_settings_page' ),
145 'active_keys' => array( 'CostTrackerSettings' ),
146 ),
147 array(
148 'slug' => 'SettingsAdvanced',
149 'page_title' => __( 'Advanced Options', 'mainwp' ),
150 'menu_title' => ' <div class="mainwp-hidden">' . esc_html__( 'Advanced Options', 'mainwp' ) . '</div>',
151 'nav_title' => esc_html__( 'Advanced Settings', 'mainwp' ),
152 'callback' => array( static::get_class_name(), 'render_advanced' ),
153 'active_keys' => array( 'Advanced', 'SettingsAdvanced' ),
154 ),
155 array(
156 'slug' => 'MonitoringSettings',
157 'page_title' => __( 'Monitoring Options', 'mainwp' ),
158 'menu_title' => ' <div class="mainwp-hidden">' . esc_html__( 'Monitoring Options', 'mainwp' ) . '</div>',
159 'nav_title' => esc_html__( 'Monitoring Settings', 'mainwp' ),
160 'callback' => array( static::get_class_name(), 'render_monitoring' ),
161 'active_keys' => array( 'Monitoring', 'MonitoringSettings' ),
162 ),
163 array(
164 'slug' => 'SettingsEmail',
165 'page_title' => __( 'Email Settings', 'mainwp' ),
166 'menu_title' => ' <div class="mainwp-hidden">' . esc_html__( 'Email Settings', 'mainwp' ) . '</div>',
167 'nav_title' => esc_html__( 'Email Settings', 'mainwp' ),
168 'callback' => array( static::get_class_name(), 'render_email_settings' ),
169 'active_keys' => array( 'Emails', 'SettingsEmail' ),
170 ),
171 array(
172 'slug' => 'PremiumUpdates',
173 'page_title' => __( 'Premium Updates', 'mainwp' ),
174 'menu_title' => ' <div class="mainwp-hidden">' . esc_html__( 'Premium Updates', 'mainwp' ) . '</div>',
175 'nav_title' => esc_html__( 'Premium Updates', 'mainwp' ),
176 'callback' => array( MainWP_Settings_Premium_Updates::get_class_name(), 'render' ),
177 'active_keys' => array( 'Premium', 'PremiumUpdates' ),
178 ),
179 );
180
181 $visible_pages = array();
182
183 foreach ( $pages as $page ) {
184 if ( 'Settings' !== $page['slug'] && MainWP_Menu::is_disable_menu_item( 3, $page['slug'] ) ) {
185 continue;
186 }
187
188 $visible_pages[] = $page;
189 }
190
191 return $visible_pages;
192 }
193
194 /**
195 * Convert a navigation href into a usable URL.
196 *
197 * @param string $href Navigation href.
198 *
199 * @return string Navigation URL.
200 */
201 private static function get_navigation_item_url( $href ) {
202 $href = trim( wp_specialchars_decode( (string) $href, ENT_QUOTES ) );
203
204 if ( empty( $href ) ) {
205 return '';
206 }
207
208 if ( preg_match( '/^https?:\/\//i', $href ) ) {
209 return $href;
210 }
211
212 return admin_url( ltrim( $href, '/' ) );
213 }
214
215 /**
216 * Get dynamic Settings subpage items using the legacy left-menu normalization path.
217 *
218 * @return array<int, array<string, mixed>> Settings navigation items.
219 */
220 private static function get_filtered_subpage_navigation_items() {
221 $menu_items = array();
222 $core_slugs = array();
223
224 foreach ( static::get_navigation_items( 'left_menu_core' ) as $item ) {
225 $core_slugs[ $item['slug'] ] = true;
226 $menu_items[] = array(
227 'title' => $item['title'],
228 'parent_key' => 'Settings',
229 'href' => $item['href'],
230 'slug' => $item['slug'],
231 'right' => '',
232 'before_title' => isset( $item['before_title'] ) ? $item['before_title'] : '',
233 );
234 }
235
236 MainWP_Menu::init_subpages_left_menu( static::get_subpages(), $menu_items, 'Settings', 'Settings' );
237
238 $items = array();
239
240 foreach ( $menu_items as $menu_item ) {
241 if ( empty( $menu_item['slug'] ) || empty( $menu_item['title'] ) || empty( $menu_item['href'] ) ) {
242 continue;
243 }
244
245 if ( isset( $core_slugs[ $menu_item['slug'] ] ) ) {
246 continue;
247 }
248
249 if ( isset( $menu_item['item_slug'] ) ) {
250 if ( MainWP_Menu::is_disable_menu_item( 3, $menu_item['item_slug'] ) ) {
251 continue;
252 }
253 } elseif ( MainWP_Menu::is_disable_menu_item( 3, $menu_item['slug'] ) ) {
254 continue;
255 }
256
257 $active_slug = 0 === strpos( $menu_item['slug'], 'Settings' ) ? substr( $menu_item['slug'], strlen( 'Settings' ) ) : $menu_item['slug'];
258 $item = array(
259 'slug' => $menu_item['slug'],
260 'title' => $menu_item['title'],
261 'href' => $menu_item['href'],
262 'active_keys' => array( $active_slug, $menu_item['slug'] ),
263 'menu_hidden' => false,
264 );
265
266 if ( ! empty( $menu_item['before_title'] ) ) {
267 $item['before_title'] = $menu_item['before_title'];
268 }
269
270 if ( isset( $menu_item['item_slug'] ) ) {
271 $item['item_slug'] = $menu_item['item_slug'];
272 }
273
274 $items[] = $item;
275 }
276
277 return $items;
278 }
279
280 /**
281 * Get the Settings navigation items.
282 *
283 * @return array<int, array<string, mixed>> Settings navigation items.
284 */
285 public static function get_navigation_items( $context = 'default' ) {
286 $core_items = array();
287 $dynamic_items = array();
288 $items = array();
289
290 foreach ( static::get_core_pages() as $page ) {
291 $core_items[ $page['slug'] ] = array(
292 'slug' => $page['slug'],
293 'title' => $page['nav_title'],
294 'href' => 'admin.php?page=' . $page['slug'],
295 'active_keys' => $page['active_keys'],
296 'menu_hidden' => false,
297 );
298 }
299
300 if ( 'command_palette' === $context ) {
301 $dynamic_items = static::get_filtered_subpage_navigation_items();
302 } else {
303 foreach ( static::get_subpages() as $subPage ) {
304 if ( empty( $subPage['slug'] ) || MainWP_Menu::is_disable_menu_item( 3, 'Settings' . $subPage['slug'] ) ) {
305 continue;
306 }
307
308 $item = array(
309 'slug' => 'Settings' . $subPage['slug'],
310 'title' => $subPage['title'],
311 'href' => ! empty( $subPage['href'] ) ? $subPage['href'] : 'admin.php?page=Settings' . $subPage['slug'],
312 'active_keys' => array( $subPage['slug'], 'Settings' . $subPage['slug'] ),
313 'menu_hidden' => ! empty( $subPage['menu_hidden'] ),
314 );
315
316 if ( ! empty( $subPage['before_title'] ) ) {
317 $item['before_title'] = $subPage['before_title'];
318 }
319
320 if ( isset( $subPage['class'] ) ) {
321 $item['class'] = $subPage['class'];
322 }
323
324 if ( isset( $subPage['item_slug'] ) ) {
325 $item['item_slug'] = $subPage['item_slug'];
326 }
327
328 $dynamic_items[] = $item;
329 }
330 }
331
332 $base_order = array( 'Settings', 'SettingsAdvanced', 'MonitoringSettings', 'SettingsEmail', 'PremiumUpdates' );
333
334 if ( in_array( $context, array( 'left_menu', 'left_menu_core' ), true ) ) {
335 $base_order[] = 'MainWPTools';
336 $base_order[] = 'CostTrackerSettings';
337 } else {
338 $base_order[] = 'CostTrackerSettings';
339 }
340
341 foreach ( $base_order as $slug ) {
342 if ( isset( $core_items[ $slug ] ) ) {
343 $items[] = $core_items[ $slug ];
344 }
345 }
346
347 if ( 'left_menu_core' !== $context ) {
348 $items = array_merge( $items, $dynamic_items );
349 }
350
351 if ( ! in_array( $context, array( 'left_menu', 'left_menu_core' ), true ) && isset( $core_items['MainWPTools'] ) ) {
352 $items[] = $core_items['MainWPTools'];
353 }
354
355 return $items;
356 }
357
358 /**
359 * Get the Settings command palette items.
360 *
361 * @return array<int, array<string, mixed>> Command palette item definitions.
362 */
363 public static function get_command_palette_items() {
364 $items = array();
365
366 foreach ( static::get_navigation_items( 'command_palette' ) as $item ) {
367 if ( ! empty( $item['menu_hidden'] ) ) {
368 continue;
369 }
370
371 $path_title = $item['title'];
372 $path_titles = array( esc_html__( 'Settings', 'mainwp' ), $path_title );
373
374 if ( ! empty( $item['before_title'] ) ) {
375 $path_title = trim( wp_strip_all_tags( $item['before_title'] ) . ' ' . $item['title'] );
376 $path_titles[1] = $path_title;
377 }
378
379 if ( 'Settings' === $item['slug'] ) {
380 $path_titles[1] = esc_html__( 'General Settings', 'mainwp' );
381 }
382
383 $items[] = array(
384 'slug' => $item['slug'],
385 'href' => $item['href'],
386 'path_titles' => $path_titles,
387 );
388 }
389
390 return $items;
391 }
392
393 /** Run the export_sites method that exports the Child Sites .csv file */
394 public static function admin_init() { // phpcs:ignore -- NOSONAR - complex.
395 static::export_sites();
396 if ( isset( $_GET['clearActivationData'] ) && isset( $_GET['_wpnonce'] ) && wp_verify_nonce( sanitize_key( $_GET['_wpnonce'] ), 'clear_activation_data' ) ) { // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
397 delete_option( 'mainwp_extensions_api_username' );
398 delete_option( 'mainwp_extensions_api_password' );
399 delete_option( 'mainwp_extensions_api_save_login' );
400 delete_option( 'mainwp_extensions_plan_info' );
401 MainWP_Keys_Manager::instance()->update_key_value( 'mainwp_extensions_master_api_key', false );
402
403 $new_extensions = array();
404 $extensions = get_option( 'mainwp_extensions', array() );
405
406 if ( is_array( $extensions ) ) {
407 foreach ( $extensions as $ext ) {
408 if ( isset( $ext['api'] ) && isset( $ext['apiManager'] ) && ! empty( $ext['apiManager'] ) ) {
409 if ( isset( $ext['api_key'] ) ) {
410 $ext['api_key'] = '';
411 }
412 if ( isset( $ext['activation_email'] ) ) {
413 $ext['activation_email'] = '';
414 }
415 if ( isset( $ext['activated_key'] ) ) {
416 $ext['activated_key'] = 'Deactivated';
417 }
418
419 $act_info = MainWP_Api_Manager::instance()->get_activation_info( $ext['api'] );
420 if ( isset( $act_info['api_key'] ) ) {
421 $act_info['api_key'] = '';
422 }
423 if ( isset( $act_info['activation_email'] ) ) {
424 $act_info['activation_email'] = '';
425 }
426 if ( isset( $act_info['activated_key'] ) ) {
427 $act_info['activated_key'] = 'Deactivated';
428 }
429 MainWP_Api_Manager::instance()->set_activation_info( $ext['api'], $act_info );
430 }
431 $new_extensions[] = $ext;
432 }
433 }
434
435 MainWP_Utility::update_option( 'mainwp_extensions', $new_extensions );
436 update_option( 'mainwp_extensions_all_activation_cached', '' );
437 wp_safe_redirect( esc_url( admin_url( 'admin.php?page=MainWPTools' ) ) );
438 die();
439 }
440 }
441
442 /**
443 * Instantiate the Settings Menu.
444 *
445 * @uses \MainWP\Dashboard\MainWP_Menu::is_disable_menu_item()
446 */
447 public static function init_menu() {
448 foreach ( static::get_core_pages() as $page ) {
449 add_submenu_page(
450 'mainwp_tab',
451 $page['page_title'],
452 $page['menu_title'],
453 'read',
454 $page['slug'],
455 $page['callback']
456 );
457 }
458
459 foreach ( static::get_subpages() as $subPage ) {
460 if ( empty( $subPage['slug'] ) || MainWP_Menu::is_disable_menu_item( 3, 'Settings' . $subPage['slug'] ) ) {
461 continue;
462 }
463
464 add_submenu_page( 'mainwp_tab', $subPage['title'], '<div class="mainwp-hidden">' . $subPage['title'] . '</div>', 'read', 'Settings' . $subPage['slug'], $subPage['callback'] );
465 }
466 }
467
468 /**
469 * Instantiate Settings SubPages Menu.
470 *
471 * @uses \MainWP\Dashboard\MainWP_Menu::is_disable_menu_item()
472 */
473 public static function init_subpages_menu() {
474 ?>
475 <div id="menu-mainwp-Settings" class="mainwp-submenu-wrapper">
476 <div class="wp-submenu sub-open" style="">
477 <div class="mainwp_boxout">
478 <div class="mainwp_boxoutin"></div>
479 <?php foreach ( static::get_navigation_items() as $item ) { ?>
480 <a href="<?php echo esc_url( static::get_navigation_item_url( $item['href'] ) ); ?>" class="mainwp-submenu"><?php echo isset( $item['before_title'] ) ? $item['before_title'] . ' ' : ''; // phpcs:ignore WordPress.Security.EscapeOutput ?><?php echo esc_html( $item['title'] ); ?></a>
481 <?php } ?>
482 </div>
483 </div>
484 </div>
485 <?php
486 }
487
488 /**
489 * Instantiate left menu
490 *
491 * Settings Page & SubPage link data.
492 *
493 * @param array $subPages SubPages Array.
494 *
495 * @uses \MainWP\Dashboard\MainWP_Menu::add_left_menu()
496 * @uses \MainWP\Dashboard\MainWP_Menu::init_subpages_left_menu()
497 * @uses \MainWP\Dashboard\MainWP_Menu::is_disable_menu_item()
498 */
499 public static function init_left_menu( $subPages = array() ) {
500 MainWP_Menu::add_left_menu(
501 array(
502 'title' => esc_html__( 'Settings', 'mainwp' ),
503 'parent_key' => 'mainwp_tab',
504 'slug' => 'Settings',
505 'href' => 'admin.php?page=Settings',
506 'icon' => '<i class="cog icon"></i>',
507 ),
508 0
509 );
510
511 $init_sub_subleftmenu = array();
512
513 foreach ( static::get_navigation_items( 'left_menu_core' ) as $item ) {
514 $init_sub_subleftmenu[] = array(
515 'title' => $item['title'],
516 'parent_key' => 'Settings',
517 'href' => $item['href'],
518 'slug' => $item['slug'],
519 'right' => '',
520 'before_title' => isset( $item['before_title'] ) ? $item['before_title'] : '',
521 );
522 }
523
524 if ( empty( $subPages ) ) {
525 $subPages = static::get_subpages();
526 }
527
528 MainWP_Menu::init_subpages_left_menu( $subPages, $init_sub_subleftmenu, 'Settings', 'Settings' );
529
530 foreach ( $init_sub_subleftmenu as $item ) {
531 if ( isset( $item['item_slug'] ) ) {
532 if ( MainWP_Menu::is_disable_menu_item( 3, $item['item_slug'] ) ) {
533 continue;
534 }
535 } elseif ( MainWP_Menu::is_disable_menu_item( 3, $item['slug'] ) ) {
536 continue;
537 }
538
539 MainWP_Menu::add_left_menu( $item, 2 );
540 }
541 }
542
543 /**
544 * Render Page Header.
545 *
546 * @param string $shownPage The page slug shown at this moment.
547 *
548 * @uses \MainWP\Dashboard\MainWP_Menu::is_disable_menu_item()
549 * @uses \MainWP\Dashboard\MainWP_UI::render_top_header()
550 * @uses \MainWP\Dashboard\MainWP_UI::render_page_navigation()
551 */
552 public static function render_header( $shownPage = '' ) { // phpcs:ignore -- NOSONAR - complex.
553
554 $params = array(
555 'title' => esc_html__( 'MainWP Settings', 'mainwp' ),
556 );
557
558 MainWP_UI::render_top_header( $params );
559
560 $renderItems = array();
561
562 foreach ( static::get_navigation_items() as $item ) {
563 $render_item = array(
564 'title' => $item['title'],
565 'href' => $item['href'],
566 'active' => in_array( $shownPage, $item['active_keys'], true ),
567 );
568
569 if ( ! empty( $item['before_title'] ) ) {
570 $render_item['before_title'] = $item['before_title'];
571 }
572
573 if ( isset( $item['class'] ) ) {
574 $render_item['class'] = $item['class'];
575 }
576
577 $renderItems[] = $render_item;
578 }
579
580 MainWP_UI::render_page_navigation( $renderItems, 'nav_mainwp_settings' );
581 }
582
583 /**
584 * Close the HTML container.
585 */
586 public static function render_footer() {
587 echo '</div>';
588 }
589
590 /**
591 * Method handle_settings_post().
592 *
593 * This class handles the $_POST of Settings Options.
594 *
595 * @uses MainWP_DB::instance()
596 * @uses MainWP_Utility::update_option()
597 *
598 * @return boolean True|False Posts On True.
599 *
600 * @uses \MainWP\Dashboard\MainWP_DB_Common::get_user_extension()
601 * @uses \MainWP\Dashboard\MainWP_DB_Common::update_user_extension()
602 * @uses \MainWP\Dashboard\MainWP_System_Utility::is_admin()
603 * @uses \MainWP\Dashboard\MainWP_Utility::update_option()
604 */
605 public static function handle_settings_post() { // phpcs:ignore -- NOSONAR - complex.
606 if ( isset( $_POST['submit'] ) && isset( $_POST['wp_nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['wp_nonce'] ), 'Settings' ) ) {
607 $userExtension = MainWP_DB_Common::instance()->get_user_extension();
608 $userExtension->pluginDir = '';
609
610 MainWP_DB_Common::instance()->update_user_extension( $userExtension );
611 if ( MainWP_System_Utility::is_admin() ) {
612
613 $old_settings = self::get_all_settings_values();
614
615 /**
616 * Action: mainwp_before_save_general_settings
617 *
618 * Fires before general settings save.
619 *
620 * @since 4.1
621 */
622 do_action( 'mainwp_before_save_general_settings', $_POST );
623
624 $val = ( ! isset( $_POST['mainwp_pluginAutomaticDailyUpdate'] ) ? 0 : intval( $_POST['mainwp_pluginAutomaticDailyUpdate'] ) );
625 MainWP_Utility::update_option( 'mainwp_pluginAutomaticDailyUpdate', $val );
626 $val = ( ! isset( $_POST['mainwp_themeAutomaticDailyUpdate'] ) ? 0 : intval( $_POST['mainwp_themeAutomaticDailyUpdate'] ) );
627 MainWP_Utility::update_option( 'mainwp_themeAutomaticDailyUpdate', $val );
628 $val = ( ! isset( $_POST['mainwp_transAutomaticDailyUpdate'] ) ? 0 : intval( $_POST['mainwp_transAutomaticDailyUpdate'] ) );
629 MainWP_Utility::update_option( 'mainwp_transAutomaticDailyUpdate', $val );
630 $val = ( ! isset( $_POST['mainwp_automaticDailyUpdate'] ) ? 0 : intval( $_POST['mainwp_automaticDailyUpdate'] ) );
631 MainWP_Utility::update_option( 'mainwp_automaticDailyUpdate', $val );
632 $val = ( ! isset( $_POST['mainwp_show_language_updates'] ) ? 0 : 1 );
633 MainWP_Utility::update_option( 'mainwp_show_language_updates', $val );
634 $val = ( ! isset( $_POST['mainwp_disable_update_confirmations'] ) ? 0 : intval( $_POST['mainwp_disable_update_confirmations'] ) );
635 MainWP_Utility::update_option( 'mainwp_disable_update_confirmations', $val );
636 $val = ( ! isset( $_POST['mainwp_backup_before_upgrade'] ) ? 0 : 1 );
637 MainWP_Utility::update_option( 'mainwp_backup_before_upgrade', $val );
638 $val = ( ! isset( $_POST['mainwp_backup_before_upgrade_days'] ) ? 7 : intval( $_POST['mainwp_backup_before_upgrade_days'] ) );
639 MainWP_Utility::update_option( 'mainwp_backup_before_upgrade_days', $val );
640
641 if ( is_plugin_active( 'mainwp-comments-extension/mainwp-comments-extension.php' ) ) {
642 MainWP_Utility::update_option( 'mainwp_maximumComments', isset( $_POST['mainwp_maximumComments'] ) ? intval( $_POST['mainwp_maximumComments'] ) : 50 );
643 }
644
645 $current_timeDailyUpdate = get_option( 'mainwp_timeDailyUpdate' );
646 $new_timeDailyUpdate = isset( $_POST['mainwp_timeDailyUpdate'] ) ? sanitize_text_field( wp_unslash( $_POST['mainwp_timeDailyUpdate'] ) ) : '';
647
648 if ( $current_timeDailyUpdate !== $new_timeDailyUpdate ) {
649 MainWP_Utility::update_option( 'mainwp_timeDailyUpdate', $new_timeDailyUpdate );
650 }
651
652 $old_freq = (int) get_option( 'mainwp_frequencyDailyUpdate', 2 );
653 $new_freq = ( isset( $_POST['mainwp_frequencyDailyUpdate'] ) ? intval( $_POST['mainwp_frequencyDailyUpdate'] ) : 2 );
654 if ( $old_freq !== $new_freq ) {
655 MainWP_Utility::update_option( 'mainwp_frequencyDailyUpdate', $new_freq );
656 MainWP_Logger::instance()->log_update_check( 'New frequency daily :: ' . $new_freq );
657 }
658
659 $curr_frequency_updates = get_option( 'mainwp_frequency_AutoUpdate', 'daily' );
660 $new_frequency_updates = isset( $_POST['mainwp_frequency_AutoUpdate'] ) ? sanitize_text_field( wp_unslash( $_POST['mainwp_frequency_AutoUpdate'] ) ) : 'daily';
661 if ( $new_frequency_updates !== $curr_frequency_updates ) {
662 MainWP_Utility::update_option( 'mainwp_frequency_AutoUpdate', $new_frequency_updates );
663 }
664
665 $curr_day_updates = (int) get_option( 'mainwp_dayinweek_AutoUpdate', 0 );
666 $new_day_updates = isset( $_POST['mainwp_dayinweek_AutoUpdate'] ) ? intval( wp_unslash( $_POST['mainwp_dayinweek_AutoUpdate'] ) ) : 0;
667 if ( $new_day_updates !== $curr_day_updates ) {
668 MainWP_Utility::update_option( 'mainwp_dayinweek_AutoUpdate', $new_day_updates );
669 }
670
671 $curr_dayinmonth_updates = (int) get_option( 'mainwp_dayinmonth_AutoUpdate', 1 );
672 $new_dayinmonth_updates = isset( $_POST['mainwp_dayinmonth_AutoUpdate'] ) ? intval( wp_unslash( $_POST['mainwp_dayinmonth_AutoUpdate'] ) ) : 1;
673 if ( $new_dayinmonth_updates !== $curr_dayinmonth_updates ) {
674 MainWP_Utility::update_option( 'mainwp_dayinmonth_AutoUpdate', $new_dayinmonth_updates );
675 }
676
677 $curr_time_updates = get_option( 'mainwp_time_AutoUpdate', '00:00' );
678 $new_time_updates = isset( $_POST['mainwp_time_AutoUpdate'] ) ? sanitize_text_field( wp_unslash( $_POST['mainwp_time_AutoUpdate'] ) ) : '00:00';
679 if ( $new_time_updates !== $curr_time_updates ) {
680 MainWP_Utility::update_option( 'mainwp_time_AutoUpdate', $new_time_updates );
681 }
682
683 MainWP_Cron_Jobs_Auto_Updates::set_next_auto_updates_time();
684
685 $new_delay = ( isset( $_POST['mainwp_delay_autoupdate'] ) ? intval( $_POST['mainwp_delay_autoupdate'] ) : 1 );
686 MainWP_Utility::update_option( 'mainwp_delay_autoupdate', $new_delay );
687
688 $val = ( isset( $_POST['mainwp_sidebarPosition'] ) ? intval( $_POST['mainwp_sidebarPosition'] ) : 1 );
689 $user = wp_get_current_user();
690 if ( $user ) {
691 update_user_option( $user->ID, 'mainwp_sidebarPosition', $val, true );
692 }
693
694 MainWP_Utility::update_option( 'mainwp_numberdays_Outdate_Plugin_Theme', ! empty( $_POST['mainwp_numberdays_Outdate_Plugin_Theme'] ) ? intval( $_POST['mainwp_numberdays_Outdate_Plugin_Theme'] ) : 365 );
695
696 $actions_notification_enable = ( isset( $_POST['mainwp_site_actions_notification_enable'] ) ? 1 : 0 );
697 MainWP_Utility::update_option( 'mainwp_site_actions_notification_enable', $actions_notification_enable );
698
699 //phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
700 // Handle custom date/time formats.
701 if ( ! empty( $_POST['date_format'] ) && isset( $_POST['date_format_custom'] )
702 && '\c\u\s\t\o\m' === wp_unslash( $_POST['date_format'] )
703 ) {
704 $_POST['date_format'] = wp_unslash( $_POST['date_format_custom'] );
705 }
706
707 if ( ! empty( $_POST['time_format'] ) && isset( $_POST['time_format_custom'] )
708 && '\c\u\s\t\o\m' === wp_unslash( $_POST['time_format'] )
709 ) {
710 $_POST['time_format'] = wp_unslash( $_POST['time_format_custom'] );
711 }
712
713 if ( isset( $_POST['timezone_string'] ) ) {
714 // Map UTC+- timezones to gmt_offsets and set timezone_string to empty.
715 if ( ! empty( $_POST['timezone_string'] ) && preg_match( '/^UTC[+-]/', wp_unslash( $_POST['timezone_string'] ) ) ) {
716 $_POST['gmt_offset'] = wp_unslash( $_POST['timezone_string'] );
717 $_POST['gmt_offset'] = preg_replace( '/UTC\+?/', '', wp_unslash( $_POST['gmt_offset'] ) ); //phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated
718 $_POST['timezone_string'] = '';
719 }
720
721 $options = array(
722 'gmt_offset',
723 'date_format',
724 'time_format',
725 'timezone_string',
726 );
727
728 foreach ( $options as $option ) {
729 $value = null;
730 if ( isset( $_POST[ $option ] ) ) {
731 $value = wp_unslash( $_POST[ $option ] );
732 if ( ! is_array( $value ) ) {
733 $value = trim( $value );
734 }
735 }
736 update_option( $option, $value );
737 }
738 }
739 //phpcs:enable
740
741 MainWP_Utility::update_option( 'mainwp_use_favicon', 1 );
742 /**
743 * Action: mainwp_after_save_general_settings
744 *
745 * Fires after save general settings.
746 *
747 * @since 4.1
748 */
749 do_action( 'mainwp_after_save_general_settings', $_POST );
750
751 $new_settings = self::get_all_settings_values();
752
753 /**
754 * Action: mainwp_after_save_settings
755 *
756 * Fires after save settings.
757 *
758 * @since 6.0
759 *
760 * @param array $new_settings The new settings.
761 * @param array $old_settings The old settings.
762 */
763 do_action( 'mainwp_after_save_settings', $new_settings, $old_settings );
764
765 }
766
767 return true;
768 }
769
770 return false;
771 }
772
773 /**
774 * Method get_all_settings_values().
775 *
776 * @param mixed $keys_only True if get Keys only.
777 *
778 * @return array All Settings Fields.
779 */
780 public static function get_all_settings_values( $keys_only = false ) {
781 $keys = array(
782 'mainwp_hide_update_everything',
783 'mainwp_pluginAutomaticDailyUpdate',
784 'mainwp_themeAutomaticDailyUpdate',
785 'mainwp_transAutomaticDailyUpdate',
786 'mainwp_automaticDailyUpdate',
787 'mainwp_show_language_updates',
788 'mainwp_disable_update_confirmations',
789 'mainwp_backup_before_upgrade',
790 'mainwp_backup_before_upgrade_days',
791 'mainwp_maximumComments',
792 'mainwp_automatic_update_next_run_timestamp',
793 'mainwp_delay_autoupdate',
794 'mainwp_numberdays_Outdate_Plugin_Theme',
795 'mainwp_check_http_response',
796 'mainwp_check_http_response_method',
797 'mainwp_site_actions_notification_enable',
798 'mainwp_use_favicon',
799 'mainwp_backupsOnServer',
800 'mainwp_maximumFileDescriptors',
801 'mainwp_maximumFileDescriptorsAuto',
802 'mainwp_backupOnExternalSources',
803 'mainwp_archiveFormat',
804 'mainwp_notificationOnBackupFail',
805 'mainwp_notificationOnBackupStart',
806 'mainwp_chunkedBackupTasks',
807 'mainwp_primaryBackup',
808 'mainwp_enableLegacyBackupFeature',
809 'mainwp_global_uptime_monitoring_settings',
810 'mainwp_disableSitesHealthMonitoring',
811 'mainwp_sitehealthThreshold',
812 'mainwp_maximumRequests',
813 'mainwp_minimumDelay',
814 'mainwp_maximumIPRequests',
815 'mainwp_minimumIPDelay',
816 'mainwp_maximumSyncRequests',
817 'mainwp_maximumInstallUpdateRequests',
818 'mainwp_sslVerifyCertificate',
819 'mainwp_connect_signature_algo',
820 'mainwp_verify_connection_method',
821 'mainwp_forceUseIPv4',
822 'mainwp_wp_cron',
823 'mainwp_warm_cache_pages_ttl',
824 'mainwp_optimize',
825 'mainwp_maximum_uptime_monitoring_requests',
826 'mainwp_chunksitesnumber',
827 'mainwp_chunksleepinterval',
828 'mainwp_settings_sync_data',
829 'mainwp_module_log_settings',
830 'mainwp_module_log_settings_logs_selection_data',
831 'mainwp_uptimecheck_running',
832 'mainwp_uptimecheck_auto_main_counter_lasttime_started',
833 'mainwp_enable_guided_tours',
834 'mainwp_enable_guided_chatbase',
835 'mainwp_enable_guided_video',
836 'mainwp_enable_cloudways_api',
837 'mainwp_enable_gridpane_api',
838 'mainwp_enable_vultr_api',
839 'mainwp_enable_linode_api',
840 'mainwp_enable_digitalocean_api',
841 'mainwp_enable_cpanel_api',
842 'mainwp_enable_plesk_api',
843 'mainwp_enable_kinsta_api',
844 );
845
846 if ( $keys_only ) {
847 return $keys;
848 }
849
850 $values = array();
851 foreach ( $keys as $key ) {
852 $values[ $key ] = get_option( $key );
853 }
854 return $values;
855 }
856
857 /**
858 * Render the MainWP Settings Page.
859 *
860 * @uses \MainWP\Dashboard\MainWP_Monitoring_View
861 * @uses \MainWP\Dashboard\MainWP_Manage_Backups::render_settings()
862 * @uses \MainWP\Dashboard\MainWP_Utility::get_http_codes()
863 */
864 public static function render() { //phpcs:ignore -- NOSONAR - complex method.
865 if ( ! \mainwp_current_user_can( 'dashboard', 'manage_dashboard_settings' ) ) {
866 \mainwp_do_not_have_permissions( esc_html__( 'manage dashboard settings', 'mainwp' ) );
867 return;
868 }
869
870 static::render_header( '' );
871 ?>
872 <div id="mainwp-general-settings" class="ui padded segment">
873
874 <?php if ( isset( $_GET['message'] ) && 'saved' === $_GET['message'] ) : // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized ?>
875 <div class="ui green message"><i class="close icon"></i><?php esc_html_e( 'Settings have been saved successfully!', 'mainwp' ); ?></div>
876 <?php endif; ?>
877 <div class="ui form">
878 <form method="POST" action="admin.php?page=Settings" id="mainwp-settings-page-form">
879 <?php MainWP_UI::generate_wp_nonce( 'mainwp-admin-nonce' ); ?>
880 <input type="hidden" name="wp_nonce" value="<?php echo esc_attr( wp_create_nonce( 'Settings' ) ); ?>" />
881 <?php
882 /**
883 * Action: mainwp_settings_form_top
884 *
885 * Fires at the top of settings form.
886 *
887 * @since 4.1
888 */
889 do_action( 'mainwp_settings_form_top' );
890 ?>
891 <h3 class="ui dividing header">
892 <?php MainWP_Settings_Indicator::render_indicator( 'header', 'settings-field-indicator-general' ); ?>
893 <?php esc_html_e( 'General Settings', 'mainwp' ); ?></h3>
894 <?php
895 $timeDailyUpdate = get_option( 'mainwp_timeDailyUpdate' );
896 $frequencyDailyUpdate = (int) get_option( 'mainwp_frequencyDailyUpdate', 2 );
897 $run_timestamp = MainWP_System_Cron_Jobs::get_timestamp_from_hh_mm( $timeDailyUpdate );
898 $delay_autoupdate = (int) get_option( 'mainwp_delay_autoupdate', 1 );
899
900 ?>
901 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-general">
902 <label class="six wide column middle aligned">
903 <?php
904 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_timeDailyUpdate', $timeDailyUpdate );
905 esc_html_e( 'Daily sync time', 'mainwp' );
906 ?>
907 </label>
908 <div class="ten wide column" data-tooltip="<?php esc_attr_e( 'Choose a specific time to initiate the first daily synchronization process.', 'mainwp' ); ?>" data-inverted="" data-position="top left">
909 <div class="time-selector">
910 <div class="ui input left icon">
911 <i class="clock icon"></i>
912 <input type="text" class="settings-field-value-change-handler" current-utc-datetime="<?php echo esc_attr( gmdate( 'Y-m-d H:i:s' ) ); ?>" sync-time-local-datetime="<?php echo esc_attr( gmdate( 'Y-m-d H:i:s', $run_timestamp ) ); ?>" local-datetime="<?php echo esc_attr( gmdate( 'Y-m-d H:i:s', MainWP_Utility::get_timestamp() ) ); // phpcs:ignore -- to get local time. ?>" name="mainwp_timeDailyUpdate" id="mainwp_timeDailyUpdate" value="<?php echo esc_attr( $timeDailyUpdate ); ?>" />
913 </div>
914 </div>
915 </div>
916 </div>
917 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-general" default-indi-value="2">
918 <label class="six wide column middle aligned">
919 <?php
920 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_frequencyDailyUpdate', $frequencyDailyUpdate );
921 esc_html_e( 'Frequency of auto sync', 'mainwp' );
922 ?>
923 </label>
924 <div class="ten wide column" data-tooltip="<?php esc_attr_e( 'Set the frequency for automatic synchronization throughout the day.', 'mainwp' ); ?>" data-inverted="" data-position="top left" >
925 <select name="mainwp_frequencyDailyUpdate" id="mainwp_frequencyDailyUpdate" class="ui dropdown settings-field-value-change-handler">
926 <option value="1" <?php echo 1 === $frequencyDailyUpdate ? 'selected' : ''; ?>><?php esc_html_e( 'Once per day', 'mainwp' ); ?></option>
927 <option value="2" <?php echo 2 === $frequencyDailyUpdate ? 'selected' : ''; ?>><?php esc_html_e( 'Twice per day', 'mainwp' ); ?></option>
928 <option value="3" <?php echo 3 === $frequencyDailyUpdate ? 'selected' : ''; ?>><?php esc_html_e( 'Three times per day', 'mainwp' ); ?></option>
929 <option value="4" <?php echo 4 === $frequencyDailyUpdate ? 'selected' : ''; ?>><?php esc_html_e( 'Four times per day', 'mainwp' ); ?></option>
930 <option value="5" <?php echo 5 === $frequencyDailyUpdate ? 'selected' : ''; ?>><?php esc_html_e( 'Five times per day', 'mainwp' ); ?></option>
931 <option value="6" <?php echo 6 === $frequencyDailyUpdate ? 'selected' : ''; ?>><?php esc_html_e( 'Six times per day', 'mainwp' ); ?></option>
932 <option value="7" <?php echo 7 === $frequencyDailyUpdate ? 'selected' : ''; ?>><?php esc_html_e( 'Seven times per day', 'mainwp' ); ?></option>
933 <option value="8" <?php echo 8 === $frequencyDailyUpdate ? 'selected' : ''; ?>><?php esc_html_e( 'Eight times per day', 'mainwp' ); ?></option>
934 <option value="9" <?php echo 9 === $frequencyDailyUpdate ? 'selected' : ''; ?>><?php esc_html_e( 'Nine times per day', 'mainwp' ); ?></option>
935 <option value="10" <?php echo 10 === $frequencyDailyUpdate ? 'selected' : ''; ?>><?php esc_html_e( 'Ten times per day', 'mainwp' ); ?></option>
936 <option value="11" <?php echo 11 === $frequencyDailyUpdate ? 'selected' : ''; ?>><?php esc_html_e( 'Eleven times per day', 'mainwp' ); ?></option>
937 <option value="12" <?php echo 12 === $frequencyDailyUpdate ? 'selected' : ''; ?>><?php esc_html_e( 'Twelve times per day', 'mainwp' ); ?></option>
938 </select>
939 </div>
940 </div>
941 <script type="text/javascript">
942 jQuery( document ).ready( function() {
943 jQuery( '.time-selector' ).calendar( {
944 type: 'time',
945 ampm: false,
946 formatter: {
947 time: 'H:mm',
948 cellTime: 'H:mm'
949 }
950 } );
951 } );
952 </script>
953
954 <?php
955
956 static::render_timezone_settings();
957 static::render_datetime_settings();
958
959 $sidebarPosition = get_user_option( 'mainwp_sidebarPosition' );
960 if ( false === $sidebarPosition ) {
961 $sidebarPosition = 1;
962 }
963
964 ?>
965 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-general" default-indi-value="1">
966 <label class="six wide column middle aligned">
967 <?php
968 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_sidebarPosition', (int) $sidebarPosition );
969 esc_html_e( 'Sidebar position', 'mainwp' );
970 ?>
971 </label>
972 <div class="ten wide column" data-tooltip="<?php esc_attr_e( 'Select if you want to show sidebar with option on left or right.', 'mainwp' ); ?>" data-inverted="" data-position="bottom left">
973 <select name="mainwp_sidebarPosition" id="mainwp_sidebarPosition" class="ui dropdown settings-field-value-change-handler">
974 <option value="1" <?php echo 1 === (int) $sidebarPosition ? 'selected' : ''; ?>><?php esc_html_e( 'Right (default)', 'mainwp' ); ?></option>
975 <option value="0" <?php echo 0 === (int) $sidebarPosition ? 'selected' : ''; ?>><?php esc_html_e( 'Left', 'mainwp' ); ?></option>
976 </select>
977 </div>
978 </div>
979 <?php MainWP_UI::render_screen_options(); ?>
980
981 <h3 class="ui dividing header">
982 <?php MainWP_Settings_Indicator::render_indicator( 'header', 'settings-field-indicator-updates' ); ?>
983 <?php esc_html_e( 'Updates Settings', 'mainwp' ); ?></h3>
984 <?php
985 $snAutomaticDailyUpdate = (int) get_option( 'mainwp_automaticDailyUpdate', 0 );
986 $snPluginAutomaticDailyUpdate = (int) get_option( 'mainwp_pluginAutomaticDailyUpdate', 0 );
987 $snThemeAutomaticDailyUpdate = (int) get_option( 'mainwp_themeAutomaticDailyUpdate', 0 );
988 $snTransAutomaticUpdate = (int) get_option( 'mainwp_transAutomaticDailyUpdate', 0 );
989
990 $backup_before_upgrade = get_option( 'mainwp_backup_before_upgrade' );
991 $mainwp_backup_before_upgrade_days = get_option( 'mainwp_backup_before_upgrade_days' );
992 if ( empty( $mainwp_backup_before_upgrade_days ) || ! ctype_digit( $mainwp_backup_before_upgrade_days ) ) {
993 $mainwp_backup_before_upgrade_days = 7;
994 }
995 $mainwp_show_language_updates = get_option( 'mainwp_show_language_updates', 1 );
996 $enableLegacyBackupFeature = get_option( 'mainwp_enableLegacyBackupFeature' );
997 $primaryBackup = get_option( 'mainwp_primaryBackup' );
998 $disableUpdateConfirmations = (int) get_option( 'mainwp_disable_update_confirmations', 0 );
999 ?>
1000 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-updates">
1001 <label class="six wide column middle aligned">
1002 <?php
1003 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_pluginAutomaticDailyUpdate', $snPluginAutomaticDailyUpdate );
1004 esc_html_e( 'Plugin advanced automatic updates', 'mainwp' );
1005 ?>
1006 </label>
1007 <div class="ten wide column" data-tooltip="<?php esc_attr_e( 'Enable or disable automatic plugin updates. If enabled, MainWP will update only plugins that you have marked as Trusted.', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1008 <select name="mainwp_pluginAutomaticDailyUpdate" id="mainwp_pluginAutomaticDailyUpdate" class="ui dropdown settings-field-value-change-handler">
1009 <option value="1" <?php echo 1 === $snPluginAutomaticDailyUpdate ? 'selected' : ''; ?>><?php esc_html_e( 'Install Trusted Updates', 'mainwp' ); ?></option>
1010 <option value="0" <?php echo 0 === $snPluginAutomaticDailyUpdate || 2 === $snPluginAutomaticDailyUpdate ? 'selected' : ''; ?>><?php esc_html_e( 'Disabled', 'mainwp' ); ?></option>
1011 </select>
1012 </div>
1013 </div>
1014 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-updates">
1015 <label class="six wide column middle aligned">
1016 <?php
1017 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_themeAutomaticDailyUpdate', $snThemeAutomaticDailyUpdate );
1018 esc_html_e( 'Theme advanced automatic updates', 'mainwp' );
1019 ?>
1020 </label>
1021 <div class="ten wide column" data-tooltip="<?php esc_attr_e( 'Enable or disable automatic theme updates. If enabled, MainWP will update only themes that you have marked as Trusted.', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1022 <select name="mainwp_themeAutomaticDailyUpdate" id="mainwp_themeAutomaticDailyUpdate" class="ui dropdown settings-field-value-change-handler">
1023 <option value="1" <?php echo 1 === $snThemeAutomaticDailyUpdate ? 'selected' : ''; ?>><?php esc_html_e( 'Install Trusted Updates', 'mainwp' ); ?></option>
1024 <option value="0" <?php echo 0 === $snThemeAutomaticDailyUpdate || 2 === $snThemeAutomaticDailyUpdate ? 'selected' : ''; ?>><?php esc_html_e( 'Disabled', 'mainwp' ); ?></option>
1025 </select>
1026 </div>
1027 </div>
1028 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-updates">
1029 <label class="six wide column middle aligned">
1030 <?php
1031 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_stransAutomaticUpdate', $snTransAutomaticUpdate );
1032 esc_html_e( 'Translation advanced automatic updates', 'mainwp' );
1033 ?>
1034 </label>
1035 <div class="ten wide column" data-tooltip="<?php esc_attr_e( 'Enable or disable automatic Translation updates.', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1036 <select name="mainwp_transAutomaticDailyUpdate" id="mainwp_transAutomaticDailyUpdate" class="ui dropdown settings-field-value-change-handler">
1037 <option value="1" <?php echo 1 === $snTransAutomaticUpdate ? 'selected' : ''; ?>><?php esc_html_e( 'Install Trusted Updates', 'mainwp' ); ?></option>
1038 <option value="0" <?php echo 0 === $snTransAutomaticUpdate || 2 === (int) $snTransAutomaticUpdate ? 'selected' : ''; ?>><?php esc_html_e( 'Disabled', 'mainwp' ); ?></option>
1039 </select>
1040 </div>
1041 </div>
1042 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-updates">
1043 <label class="six wide column middle aligned">
1044 <?php
1045 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_automaticDailyUpdate', $snAutomaticDailyUpdate );
1046 esc_html_e( 'WP Core advanced automatic updates', 'mainwp' );
1047 ?>
1048 </label>
1049 <div class="ten wide column" data-tooltip="<?php esc_attr_e( 'Enable or disable automatic WordPress core updates.', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1050 <select name="mainwp_automaticDailyUpdate" id="mainwp_automaticDailyUpdate" class="ui dropdown settings-field-value-change-handler">
1051 <option value="1" <?php echo 1 === $snAutomaticDailyUpdate ? 'selected' : ''; ?>><?php esc_html_e( 'Install Trusted Updates', 'mainwp' ); ?></option>
1052 <option value="0" <?php echo 0 === $snAutomaticDailyUpdate || 2 === (int) $snAutomaticDailyUpdate ? 'selected' : ''; ?>><?php esc_html_e( 'Disabled', 'mainwp' ); ?></option>
1053 </select>
1054 </div>
1055 </div>
1056 <?php static::render_auto_updates_settings(); ?>
1057 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-updates" default-indi-value="1">
1058 <label class="six wide column middle aligned">
1059 <?php
1060 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_delay_autoupdate', $delay_autoupdate );
1061 esc_html_e( 'Advanced automatic updates delay', 'mainwp' );
1062 ?>
1063 </label>
1064 <div class="ten wide column ui input" data-tooltip="<?php esc_attr_e( 'Set the number of days to delay automatic updates.', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1065 <select name="mainwp_delay_autoupdate" id="mainwp_delay_autoupdate" class="ui dropdown settings-field-value-change-handler">
1066 <option value="0" <?php echo 0 === $delay_autoupdate ? 'selected' : ''; ?>><?php esc_html_e( 'Delay off', 'mainwp' ); ?></option>
1067 <option value="1" <?php echo 1 === $delay_autoupdate ? 'selected' : ''; ?>><?php esc_html_e( '1 day', 'mainwp' ); ?></option>
1068 <option value="2" <?php echo 2 === $delay_autoupdate ? 'selected' : ''; ?>><?php esc_html_e( '2 days', 'mainwp' ); ?></option>
1069 <option value="3" <?php echo 3 === $delay_autoupdate ? 'selected' : ''; ?>><?php esc_html_e( '3 days', 'mainwp' ); ?></option>
1070 <option value="4" <?php echo 4 === $delay_autoupdate ? 'selected' : ''; ?>><?php esc_html_e( '4 days', 'mainwp' ); ?></option>
1071 <option value="5" <?php echo 5 === $delay_autoupdate ? 'selected' : ''; ?>><?php esc_html_e( '5 days', 'mainwp' ); ?></option>
1072 <option value="6" <?php echo 6 === $delay_autoupdate ? 'selected' : ''; ?>><?php esc_html_e( '6 days', 'mainwp' ); ?></option>
1073 <option value="7" <?php echo 7 === $delay_autoupdate ? 'selected' : ''; ?>><?php esc_html_e( '7 days', 'mainwp' ); ?></option>
1074 <option value="14" <?php echo 14 === $delay_autoupdate ? 'selected' : ''; ?>><?php esc_html_e( '14 days', 'mainwp' ); ?></option>
1075 <option value="30" <?php echo 30 === $delay_autoupdate ? 'selected' : ''; ?>><?php esc_html_e( '30 days', 'mainwp' ); ?></option>
1076 </select>
1077 </div>
1078 </div>
1079 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-updates" default-indi-value="1">
1080 <label class="six wide column middle aligned">
1081 <?php
1082 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_show_language_updates', $mainwp_show_language_updates );
1083 esc_html_e( 'Show WordPress language updates', 'mainwp' );
1084 ?>
1085 </label>
1086 <div class="ten wide column ui toggle checkbox" data-tooltip="<?php esc_attr_e( 'Enable if you want to manage Translation updates', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1087 <input type="checkbox" name="mainwp_show_language_updates" class="settings-field-value-change-handler" id="mainwp_show_language_updates" <?php echo 1 === (int) $mainwp_show_language_updates ? 'checked="true"' : ''; ?>/>
1088 </div>
1089 </div>
1090 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-updates">
1091 <label class="six wide column middle aligned">
1092 <?php
1093 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_disable_update_confirmations', $disableUpdateConfirmations );
1094 esc_html_e( 'Update confirmations', 'mainwp' );
1095 ?>
1096 </label>
1097 <div class="ten wide column ui toggle checkbox" data-tooltip="<?php esc_attr_e( 'Choose if you want to disable the popup confirmations when performing updates.', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1098 <select name="mainwp_disable_update_confirmations" id="mainwp_disable_update_confirmations" class="ui dropdown settings-field-value-change-handler">
1099 <option value="0" <?php echo 0 === $disableUpdateConfirmations ? 'selected' : ''; ?>><?php esc_html_e( 'Enable', 'mainwp' ); ?></option>
1100 <option value="2" <?php echo 2 === $disableUpdateConfirmations ? 'selected' : ''; ?>><?php esc_html_e( 'Disable', 'mainwp' ); ?></option>
1101 <option value="1" <?php echo 1 === $disableUpdateConfirmations ? 'selected' : ''; ?>><?php esc_html_e( 'Disable for single updates', 'mainwp' ); ?></option>
1102 </select>
1103 </div>
1104 </div>
1105 <?php if ( ( $enableLegacyBackupFeature && empty( $primaryBackup ) ) || ( empty( $enableLegacyBackupFeature ) && ! empty( $primaryBackup ) ) ) { ?>
1106 <div class="ui grid field mainwp-parent-toggle settings-field-indicator-wrapper settings-field-indicator-updates">
1107 <label class="six wide column middle aligned">
1108 <?php
1109 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_backup_before_upgrade', (int) $backup_before_upgrade );
1110 esc_html_e( 'Require a backup before an update', 'mainwp' );
1111 ?>
1112 </label>
1113 <div class="ten wide column ui toggle checkbox" data-tooltip="<?php esc_attr_e( 'If enabled, your MainWP Dashboard will check if full backups exists before updating.', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1114 <input type="checkbox" class="settings-field-value-change-handler" name="mainwp_backup_before_upgrade" id="mainwp_backup_before_upgrade" <?php echo 1 === (int) $backup_before_upgrade ? 'checked="true"' : ''; ?>/>
1115 </div>
1116 </div>
1117 <div class="ui grid field mainwp-child-field settings-field-indicator-wrapper settings-field-indicator-updates" default-indi-value="7" <?php echo 1 === (int) $backup_before_upgrade ? '' : 'style="display:none"'; ?> >
1118 <label class="six wide column middle aligned">
1119 <?php
1120 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_backup_before_upgrade_days', (int) $mainwp_backup_before_upgrade_days );
1121 esc_html_e( 'Days without of a full backup tolerance', 'mainwp' );
1122 ?>
1123 </label>
1124 <div class="ten wide column" data-tooltip="<?php esc_attr_e( 'Set the number of days without of backup tolerance.', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1125 <input type="text" class="settings-field-value-change-handler" name="mainwp_backup_before_upgrade_days" id="mainwp_backup_before_upgrade_days" value="<?php echo esc_attr( $mainwp_backup_before_upgrade_days ); ?>" />
1126 </div>
1127 </div>
1128 <?php } ?>
1129
1130 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-updates" default-indi-value="365">
1131 <label class="six wide column middle aligned">
1132 <?php
1133 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_numberdays_Outdate_Plugin_Theme', (int) get_option( 'mainwp_numberdays_Outdate_Plugin_Theme', 365 ) );
1134
1135 esc_html_e( 'Abandoned plugins/themes tolerance', 'mainwp' );
1136 ?>
1137 </label>
1138 <div class="ten wide column" data-tooltip="<?php esc_attr_e( 'Set how many days without an update before plugin or theme will be considered as abandoned.', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1139 <input type="text" class="settings-field-value-change-handler" name="mainwp_numberdays_Outdate_Plugin_Theme" id="mainwp_numberdays_Outdate_Plugin_Theme" value="<?php echo false === get_option( 'mainwp_numberdays_Outdate_Plugin_Theme' ) ? 365 : intval( get_option( 'mainwp_numberdays_Outdate_Plugin_Theme' ) ); ?>"/>
1140 </div>
1141 </div>
1142
1143 <?php MainWP_Manage_Backups::render_settings(); ?>
1144 <?php
1145 /**
1146 * Action: mainwp_settings_form_bottom
1147 *
1148 * Fires at the bottom of settings form.
1149 *
1150 * @since 4.1
1151 */
1152 do_action( 'mainwp_settings_form_bottom' );
1153 ?>
1154 <div class="ui divider"></div>
1155 <input type="submit" name="submit" id="submit" class="ui button green big" value="<?php esc_attr_e( 'Save Settings', 'mainwp' ); ?>"/>
1156 <div style="clear:both"></div>
1157 </form>
1158 </div>
1159 </div>
1160 <?php
1161 static::render_footer( '' );
1162 }
1163
1164 /**
1165 * Method render_auto_updates_settings().
1166 */
1167 public static function render_auto_updates_settings() { // phpcs:ignore -- NOSONAR - complex.
1168
1169 $time_AutoUpdate = get_option( 'mainwp_time_AutoUpdate' );
1170 $dayinweek_AutoUpdate = (int) get_option( 'mainwp_dayinweek_AutoUpdate', 0 );
1171 $dayinmonth_AutoUpdate = (int) get_option( 'mainwp_dayinmonth_AutoUpdate', 1 );
1172 $frequency_AutoUpdate = get_option( 'mainwp_frequency_AutoUpdate', 'daily' );
1173
1174 if ( empty( $time_AutoUpdate ) ) {
1175 $time_AutoUpdate = '00:00';
1176 }
1177
1178 if ( ! in_array( $frequency_AutoUpdate, array( 'daily', 'weekly', 'monthly' ) ) ) {
1179 $frequency_AutoUpdate = 'daily';
1180 }
1181
1182 ?>
1183 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-general" default-indi-value="daily">
1184 <label class="six wide column middle aligned">
1185 <?php
1186 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_frequency_AutoUpdate', $frequency_AutoUpdate );
1187 esc_html_e( 'Frequency of automatic updates', 'mainwp' );
1188 ?>
1189 </label>
1190 <div class="ten wide column" data-tooltip="<?php esc_attr_e( 'Set the frequency for automatic updates process.', 'mainwp' ); ?>" data-inverted="" data-position="top left" >
1191 <select name="mainwp_frequency_AutoUpdate" id="mainwp_frequency_AutoUpdate" class="ui dropdown settings-field-value-change-handler">
1192 <option value="daily" <?php echo 'daily' === $frequency_AutoUpdate ? 'selected' : ''; ?>><?php esc_html_e( 'Daily', 'mainwp' ); ?></option>
1193 <option value="weekly" <?php echo 'weekly' === $frequency_AutoUpdate ? 'selected' : ''; ?>><?php esc_html_e( 'Weekly', 'mainwp' ); ?></option>
1194 <option value="monthly" <?php echo 'monthly' === $frequency_AutoUpdate ? 'selected' : ''; ?>><?php esc_html_e( 'Monthly', 'mainwp' ); ?></option>
1195 </select>
1196 </div>
1197 </div>
1198
1199 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-general" id="mainwp-dayinmonth-autoupdate-wrapper" <?php echo in_array( $frequency_AutoUpdate, array( 'monthly' ) ) ? '' : 'style="display:none;"'; ?>>
1200 <label class="six wide column middle aligned">
1201 <?php
1202 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_dayinmonth_AutoUpdate', $dayinmonth_AutoUpdate );
1203 esc_html_e( 'Select day', 'mainwp' );
1204 ?>
1205 </label>
1206 <div class="ten wide column" data-tooltip="<?php esc_attr_e( 'Choose a specific day in month to initiate automatic updates process.', 'mainwp' ); ?>" data-inverted="" data-position="top left" >
1207 <select name="mainwp_dayinmonth_AutoUpdate" id="mainwp_dayinmonth_AutoUpdate" class="ui dropdown settings-field-value-change-handler">
1208 <?php
1209 $day_suffix = array(
1210 1 => 'st',
1211 2 => 'nd',
1212 3 => 'rd',
1213 );
1214 for ( $x = 1; $x <= 31; $x++ ) {
1215 $_select = '';
1216 if ( $dayinmonth_AutoUpdate === $x ) {
1217 $_select = 'selected';
1218 }
1219 $remain = $x % 10;
1220 $day_sf = isset( $day_suffix[ $remain ] ) ? $day_suffix[ $remain ] : 'th';
1221 echo '<option value="' . intval( $x ) . '" ' . esc_html( $_select ) . '>' . esc_html( $x . $day_sf ) . ' of the month</option>';
1222 }
1223 ?>
1224 </select>
1225 </div>
1226 </div>
1227
1228 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-general" id="mainwp-dayinweek-autoupdate-wrapper" <?php echo in_array( $frequency_AutoUpdate, array( 'weekly' ) ) ? '' : 'style="display:none;"'; ?>>
1229 <label class="six wide column middle aligned">
1230 <?php
1231 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_dayinweek_AutoUpdate', $dayinweek_AutoUpdate );
1232 esc_html_e( 'Select day', 'mainwp' );
1233 ?>
1234 </label>
1235 <div class="ten wide column" data-tooltip="<?php esc_attr_e( 'Choose a specific day in week to initiate automatic updates process.', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1236 <select name="mainwp_dayinweek_AutoUpdate" id="mainwp_dayinweek_AutoUpdate" class="ui dropdown settings-field-value-change-handler">
1237 <option value="0" <?php echo 0 === $dayinweek_AutoUpdate ? 'selected' : ''; ?>><?php esc_html_e( 'Mon', 'mainwp' ); ?></option>
1238 <option value="1" <?php echo 1 === $dayinweek_AutoUpdate ? 'selected' : ''; ?>><?php esc_html_e( 'Tue', 'mainwp' ); ?></option>
1239 <option value="2" <?php echo 2 === $dayinweek_AutoUpdate ? 'selected' : ''; ?>><?php esc_html_e( 'Wed', 'mainwp' ); ?></option>
1240 <option value="3" <?php echo 3 === $dayinweek_AutoUpdate ? 'selected' : ''; ?>><?php esc_html_e( 'Thus', 'mainwp' ); ?></option>
1241 <option value="4" <?php echo 4 === $dayinweek_AutoUpdate ? 'selected' : ''; ?>><?php esc_html_e( 'Fri', 'mainwp' ); ?></option>
1242 <option value="5" <?php echo 5 === $dayinweek_AutoUpdate ? 'selected' : ''; ?>><?php esc_html_e( 'Sat', 'mainwp' ); ?></option>
1243 <option value="6" <?php echo 6 === $dayinweek_AutoUpdate ? 'selected' : ''; ?>><?php esc_html_e( 'Sun', 'mainwp' ); ?></option>
1244 </select>
1245 </div>
1246 </div>
1247 <div id="mainwp-time-autoupdate-wrapper" class="ui grid field settings-field-indicator-wrapper settings-field-indicator-general" default-indi-value="00:00">
1248 <label class="six wide column middle aligned">
1249 <?php
1250 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_time_AutoUpdate', $time_AutoUpdate );
1251 esc_html_e( 'Select time', 'mainwp' );
1252 $_last_start_auto_updates = get_option( 'mainwp_automatic_updates_start_lasttime', 0 );
1253 $_next_auto_updates = get_option( 'mainwp_automatic_update_next_run_timestamp', 0 );
1254 ?>
1255 </label>
1256 <div class="ten wide column" data-tooltip="<?php esc_attr_e( 'Choose a specific time to initiate automatic updates process.', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1257 <div class="time-selector">
1258 <div class="ui input left icon">
1259 <i class="clock icon"></i>
1260 <input type="text" class="settings-field-value-change-handler" current-utc-datetime="<?php echo date( 'Y-m-d H:i:s' ); ?>" auto-updates-last-start-time="<?php echo date( 'Y-m-d H:i:s', $_last_start_auto_updates ); ?>" auto-updates-next-time="<?php echo date( 'Y-m-d H:i:s', $_next_auto_updates ); ?>" local-datetime="<?php echo date( 'Y-m-d H:i:s', MainWP_Utility::get_timestamp() ); // phpcs:ignore -- to get local time. ?>" name="mainwp_time_AutoUpdate" id="mainwp_time_AutoUpdate" value="<?php echo esc_attr( $time_AutoUpdate ); ?>" />
1261 </div>
1262 </div>
1263 </div>
1264 </div>
1265 <script type="text/javascript">
1266 jQuery(document).on('change', '#mainwp_frequency_AutoUpdate', function () {
1267 if( jQuery(this).val() == 'monthly' ){
1268 jQuery('#mainwp-dayinweek-autoupdate-wrapper').hide();
1269 jQuery('#mainwp-dayinmonth-autoupdate-wrapper').show();
1270 } else if( jQuery(this).val() == 'weekly'){
1271 jQuery('#mainwp-dayinweek-autoupdate-wrapper').show();
1272 jQuery('#mainwp-dayinmonth-autoupdate-wrapper').hide();
1273 } else {
1274 jQuery('#mainwp-dayinweek-autoupdate-wrapper').hide();
1275 jQuery('#mainwp-dayinmonth-autoupdate-wrapper').hide();
1276 }
1277 });
1278 </script>
1279 <?php
1280 }
1281
1282 /**
1283 * Render Timezone settings.
1284 */
1285 public static function render_timezone_settings() { // phpcs:ignore -- NOSONAR - complex.
1286
1287 $current_offset = get_option( 'gmt_offset' );
1288 $tzstring = get_option( 'timezone_string' );
1289 $tzstring = MainWP_Utility::clean_wp_timezone_string( $tzstring );
1290
1291 $check_zone_info = true;
1292
1293 // Remove old Etc mappings. Fallback to gmt_offset.
1294 if ( false !== strpos( $tzstring, 'Etc/GMT' ) ) {
1295 $tzstring = '';
1296 }
1297
1298 if ( empty( $tzstring ) ) { // Create a UTC+- zone if no timezone string exists.
1299 $check_zone_info = false;
1300 if ( empty( $current_offset ) ) {
1301 $tzstring = 'UTC+0';
1302 } elseif ( $current_offset < 0 ) {
1303 $tzstring = 'UTC' . $current_offset;
1304 } else {
1305 $tzstring = 'UTC+' . $current_offset;
1306 }
1307 }
1308
1309 $timezone_format = _x( 'Y-m-d H:i:s', 'timezone date format', 'mainwp' );
1310
1311 ?>
1312 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-general">
1313 <label class="six wide column middle aligned"><?php esc_html_e( 'Timezone', 'mainwp' ); ?></label>
1314 <?php
1315 // translators: %s is the abbreviation "UTC".
1316 $timezone_tooltip = esc_attr__( 'Choose either a city in the same timezone as you or a %s (Coordinated Universal Time) time offset.', 'mainwp' );
1317 ?>
1318 <div class="ten wide column" data-tooltip="<?php echo $timezone_tooltip; // phpcs:ignore WordPress.Security.EscapeOutput ?>" data-inverted="" data-position="top left">
1319 <select id="timezone_string" class="ui dropdown" name="timezone_string" aria-describedby="timezone-description">
1320 <?php echo wp_timezone_choice( $tzstring, get_user_locale() ); // phpcs:ignore WordPress.Security.EscapeOutput ?>
1321 </select>
1322 <div class="ui hidden fitted divider"></div>
1323 <div class="ui secondary segment">
1324 <?php
1325 // translators: %s is the current UTC date and time.
1326 printf( esc_html__( 'Universal time is %s.', 'mainwp' ), '<code>' . esc_html( date_i18n( $timezone_format, false, true ) ) . '</code>' );
1327 ?>
1328 <div class="ui hidden fitted divider"></div>
1329 <?php if ( get_option( 'timezone_string' ) || ! empty( $current_offset ) ) : ?>
1330 <?php
1331 // translators: %s is the current local date and time.
1332 printf( esc_html__( 'Local time is %s.', 'mainwp' ), '<code>' . esc_html( date_i18n( $timezone_format ) ) . '</code>' );
1333 ?>
1334 <div class="ui hidden fitted divider"></div>
1335 <?php endif; ?>
1336 <?php if ( $check_zone_info && $tzstring ) : ?>
1337 <?php
1338 $now = new \DateTime( 'now', new \DateTimeZone( $tzstring ) );
1339 $dst = (bool) $now->format( 'I' );
1340
1341 if ( $dst ) {
1342 esc_html_e( 'This timezone is currently in daylight saving time.', 'mainwp' );
1343 } else {
1344 esc_html_e( 'This timezone is currently in standard time.', 'mainwp' );
1345 }
1346 ?>
1347 <div class="ui hidden fitted divider"></div>
1348 <?php
1349 if ( in_array( $tzstring, timezone_identifiers_list(), true ) ) {
1350 $transitions = timezone_transitions_get( timezone_open( $tzstring ), time() );
1351
1352 if ( ! empty( $transitions[1] ) ) {
1353 echo ' ';
1354 // translators: %s is the date and time when the timezone transition occurs.
1355 $message = $transitions[1]['isdst'] ? esc_html__( 'Daylight saving time begins on: %s.', 'mainwp' ) : esc_html__( 'Standard time begins on: %s.', 'mainwp' );
1356 printf( $message, '<code>' . wp_date( esc_html__( 'F j, Y', 'mainwp' ) . ' ' . esc_html__( 'g:i a', 'mainwp' ), esc_html( $transitions[1]['ts'] ) ) . '</code>' ); // phpcs:ignore WordPress.Security.EscapeOutput
1357 } else {
1358 esc_html_e( 'This timezone does not observe daylight saving time.', 'mainwp' );
1359 }
1360 }
1361 ?>
1362 <?php endif; ?>
1363 </div>
1364 </div>
1365 </div>
1366 <?php
1367 }
1368
1369 /**
1370 * Render Date/Time settings.
1371 */
1372 public static function render_datetime_settings() {
1373 ?>
1374 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-general" default-indi-value="F j, Y">
1375 <label class="six wide column middle aligned">
1376 <?php
1377 MainWP_Settings_Indicator::render_not_default_indicator( 'date_format', get_option( 'date_format' ) );
1378 esc_html_e( 'Date format', 'mainwp' );
1379 ?>
1380 </label>
1381 <div class="ten wide column fieldset-wrapper" data-tooltip="<?php esc_attr_e( 'Choose the display format for date.', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1382 <?php
1383 /**
1384 * Filters the default date formats.
1385 *
1386 * @since 2.7.0
1387 * @since 4.0.0 Added ISO date standard YYYY-MM-DD format.
1388 *
1389 * @param string[] $default_date_formats Array of default date formats.
1390 */
1391 $date_formats = array_unique( apply_filters( 'date_formats', array( esc_html__( 'F j, Y', 'mainwp' ), 'Y-m-d', 'm/d/Y', 'd/m/Y' ) ) );
1392
1393 $custom = true;
1394
1395 foreach ( $date_formats as $format ) {
1396 echo "\t<label><input type='radio' name='date_format' value='" . esc_attr( $format ) . "'";
1397 if ( get_option( 'date_format' ) === $format ) { // checked() uses "==" rather than "===".
1398 echo " checked='checked'";
1399 $custom = false;
1400 }
1401 echo ' /> <span class="date-time-text format-i18n">' . esc_html( date_i18n( $format ) ) . '</span><code>' . esc_html( $format ) . "</code></label><br />\n";
1402 }
1403 echo '<label><input type="radio" name="date_format" id="date_format_custom_radio" value="\c\u\s\t\o\m"';
1404 checked( $custom );
1405 echo '/> <span class="date-time-text date-time-custom-text">' . esc_html__( 'Custom:', 'mainwp' ) . '<span class="screen-reader-text"> ' . esc_html__( 'enter a custom date format in the following field', 'mainwp' ) . '</span></span></label>' .
1406 '<label for="date_format_custom" class="screen-reader-text">' . esc_html__( 'Custom date format:', 'mainwp' ) . '</label>' .
1407 '<input type="text" name="date_format_custom" id="date_format_custom" value="' . esc_attr( get_option( 'date_format' ) ) . '" class="small-text settings-field-value-change-handler" />' .
1408 '<br />' .
1409 '<em><strong>' . esc_html__( 'Preview:', 'mainwp' ) . '</strong> <span class="example">' . esc_html( date_i18n( get_option( 'date_format' ) ) ) . '</span>' .
1410 "<span class='spinner'></span>\n" . '</em>';
1411 ?>
1412 </div>
1413 </div>
1414
1415 <div class="ui grid field settings-field-indicator-wrapper" default-indi-value="g:i a">
1416 <label class="six wide column middle aligned">
1417 <?php
1418 MainWP_Settings_Indicator::render_not_default_indicator( 'time_format', get_option( 'time_format' ) );
1419 esc_html_e( 'Time format', 'mainwp' );
1420 ?>
1421 </label>
1422 <div class="ten wide column fieldset-wrapper" data-tooltip="<?php esc_attr_e( 'Choose the display format for time.', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1423 <?php
1424 /**
1425 * Filters the default time formats.
1426 *
1427 * @since 2.7.0
1428 *
1429 * @param string[] $default_time_formats Array of default time formats.
1430 */
1431 $time_formats = array_unique( apply_filters( 'time_formats', array( esc_html__( 'g:i a', 'mainwp' ), 'g:i A', 'H:i' ) ) );
1432
1433 $custom = true;
1434
1435 foreach ( $time_formats as $format ) {
1436 echo "\t<label><input type='radio' name='time_format' value='" . esc_attr( $format ) . "'";
1437 if ( get_option( 'time_format' ) === $format ) { // checked() uses "==" rather than "===".
1438 echo " checked='checked'";
1439 $custom = false;
1440 }
1441 echo ' /> <span class="date-time-text format-i18n">' . esc_html( date_i18n( $format ) ) . '</span><code>' . esc_html( $format ) . "</code></label><br />\n";
1442 }
1443 echo '<label><input type="radio" name="time_format" id="time_format_custom_radio" value="\c\u\s\t\o\m"';
1444 checked( $custom );
1445 echo '/> <span class="date-time-text date-time-custom-text">' . esc_html__( 'Custom:', 'mainwp' ) . '<span class="screen-reader-text"> ' . esc_html__( 'enter a custom time format in the following field', 'mainwp' ) . '</span></span></label>' .
1446 '<label for="time_format_custom" class="screen-reader-text">' . esc_html__( 'Custom time format:', 'mainwp' ) . '</label>' .
1447 '<input type="text" class="small-text settings-field-value-change-handler" name="time_format_custom" id="time_format_custom" value="' . esc_attr( get_option( 'time_format' ) ) . '" />' .
1448 '<br />' .
1449 '<em><strong>' . esc_html__( 'Preview:', 'mainwp' ) . '</strong> <span class="example">' . esc_html( date_i18n( get_option( 'time_format' ) ) ) . '</span>' .
1450 "<span class='spinner'></span>\n" . '</em>';
1451 ?>
1452 </div>
1453 </div>
1454 <script type="text/javascript">
1455 jQuery(function($) {
1456 $( 'input[name="date_format"]' ).on( 'click', function() {
1457 if ( 'date_format_custom_radio' !== $( this ).attr( 'id' ) ){
1458 $( 'input[name="date_format_custom"]' ).val( $( this ).val() ).closest( '.fieldset-wrapper' ).find( '.example' ).text( $( this ).parent( 'label' ).children( '.format-i18n' ).text() );
1459 $( 'input[name="date_format_custom"]' ).trigger("change"); // support indicator.
1460 }
1461 } );
1462
1463 $( 'input[name="date_format_custom"]' ).on( 'click input', function() {
1464 $( '#date_format_custom_radio' ).prop( 'checked', true );
1465 } );
1466
1467 $( 'input[name="time_format"]' ).on( 'click', function() {
1468 if ( 'time_format_custom_radio' !== $(this).attr( 'id' ) ){
1469 $( 'input[name="time_format_custom"]' ).val( $( this ).val() ).closest( '.fieldset-wrapper' ).find( '.example' ).text( $( this ).parent( 'label' ).children( '.format-i18n' ).text() );
1470 $( 'input[name="time_format_custom"]' ).trigger("change"); // support indicator.
1471 }
1472 } );
1473
1474 $( 'input[name="time_format_custom"]' ).on( 'click input', function() {
1475 $( '#time_format_custom_radio' ).prop( 'checked', true );
1476 } );
1477
1478 $( 'input[name="date_format_custom"], input[name="time_format_custom"]' ).on( 'input', function() {
1479 let format = $( this ),
1480 fieldset = format.closest( '.fieldset-wrapper' ),
1481 example = fieldset.find( '.example' ),
1482 spinner = fieldset.find( '.spinner' );
1483
1484 // Debounce the event callback while users are typing.
1485 clearTimeout( $.data( this, 'timer' ) );
1486 $( this ).data( 'timer', setTimeout( function() {
1487 // If custom date is not empty.
1488 if ( format.val() ) {
1489 spinner.addClass( 'is-active' );
1490
1491 $.post( ajaxurl, {
1492 action: 'date_format_custom' === format.attr( 'name' ) ? 'date_format' : 'time_format',
1493 date : format.val()
1494 }, function( d ) { spinner.removeClass( 'is-active' ); example.text( d ); } );
1495 }
1496 }, 500 ) );
1497 } );
1498 });
1499 </script>
1500 <?php
1501 }
1502
1503 /**
1504 * Method get_websites_automatic_update_time()
1505 *
1506 * Get websites automatic update time.
1507 *
1508 * @return mixed array
1509 *
1510 * @uses \MainWP\Dashboard\MainWP_Utility::format_timestamp()
1511 */
1512 public static function get_websites_automatic_update_time() {
1513 $lastAutomaticUpdate = MainWP_Auto_Updates_DB::instance()->get_websites_last_automatic_sync();
1514 $lasttimeAutomatic = get_option( 'mainwp_updatescheck_last_timestamp' );
1515 $lasttimeStartAutomatic = get_option( 'mainwp_updatescheck_start_last_timestamp' );
1516 $local_timestamp = MainWP_Utility::get_timestamp();
1517
1518 if ( empty( $lasttimeStartAutomatic ) && ! empty( $lasttimeAutomatic ) ) {
1519 $lasttimeStartAutomatic = $lasttimeAutomatic;
1520 }
1521
1522 if ( empty( $lastAutomaticUpdate ) ) {
1523 $nextAutomaticUpdate = esc_html__( 'Any minute', 'mainwp' );
1524 } elseif ( 0 < MainWP_Auto_Updates_DB::instance()->get_websites_check_updates_count( $lasttimeStartAutomatic ) ) {
1525 $nextAutomaticUpdate = esc_html__( 'Processing your websites.', 'mainwp' );
1526 } else {
1527 $next_time = MainWP_System_Cron_Jobs::get_next_time_automatic_update_to_show();
1528 if ( $next_time < $local_timestamp + 5 * MINUTE_IN_SECONDS ) {
1529 $nextAutomaticUpdate = esc_html__( 'Any minute', 'mainwp' );
1530 } else {
1531 $nextAutomaticUpdate = MainWP_Utility::format_timestamp( $next_time );
1532 }
1533 }
1534
1535 if ( empty( $lastAutomaticUpdate ) ) {
1536 $lastAutomaticUpdate = esc_html__( 'Never', 'mainwp' );
1537 } else {
1538 $lastAutomaticUpdate = MainWP_Utility::format_timestamp( $lastAutomaticUpdate );
1539 }
1540
1541 return array(
1542 'last' => $lastAutomaticUpdate,
1543 'next' => $nextAutomaticUpdate,
1544 );
1545 }
1546
1547 /**
1548 * Returns false or the location of the OpenSSL Lib File.
1549 *
1550 * @return mixed false|opensslLibLocation
1551 *
1552 * @uses \MainWP\Dashboard\MainWP_Server_Information_Handler::is_openssl_config_warning()
1553 */
1554 public static function show_openssl_lib_config() {
1555 return MainWP_Server_Information_Handler::is_openssl_config_warning() ? true : false;
1556 }
1557
1558 /**
1559 * Render Advanced Options Subpage.
1560 *
1561 * @uses \MainWP\Dashboard\MainWP_Utility::update_option()
1562 */
1563 public static function render_advanced() { //phpcs:ignore -- NOSONAR - complex method.
1564 if ( ! \mainwp_current_user_can( 'dashboard', 'manage_dashboard_settings' ) ) {
1565 \mainwp_do_not_have_permissions( esc_html__( 'manage dashboard settings', 'mainwp' ) );
1566 return;
1567 }
1568
1569 if ( isset( $_POST['submit'] ) && isset( $_POST['wp_nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['wp_nonce'] ), 'SettingsAdvanced' ) ) {
1570
1571 $old_settings = static::get_all_settings_values();
1572
1573 /**
1574 * Action: mainwp_before_save_advanced_settings
1575 *
1576 * Fires before save advanced settings.
1577 *
1578 * @since 4.1
1579 */
1580 do_action( 'mainwp_before_save_advanced_settings', $_POST );
1581
1582 MainWP_Utility::update_option( 'mainwp_maximumRequests', ! empty( $_POST['mainwp_maximumRequests'] ) ? intval( $_POST['mainwp_maximumRequests'] ) : 4 );
1583 MainWP_Utility::update_option( 'mainwp_minimumDelay', ! empty( $_POST['mainwp_minimumDelay'] ) ? intval( $_POST['mainwp_minimumDelay'] ) : 200 );
1584 MainWP_Utility::update_option( 'mainwp_maximumIPRequests', ! empty( $_POST['mainwp_maximumIPRequests'] ) ? intval( $_POST['mainwp_maximumIPRequests'] ) : 1 );
1585 MainWP_Utility::update_option( 'mainwp_minimumIPDelay', ! empty( $_POST['mainwp_minimumIPDelay'] ) ? intval( $_POST['mainwp_minimumIPDelay'] ) : 1000 );
1586 MainWP_Utility::update_option( 'mainwp_maximumSyncRequests', ! empty( $_POST['mainwp_maximumSyncRequests'] ) ? intval( $_POST['mainwp_maximumSyncRequests'] ) : 8 );
1587 MainWP_Utility::update_option( 'mainwp_maximumInstallUpdateRequests', ! empty( $_POST['mainwp_maximumInstallUpdateRequests'] ) ? intval( $_POST['mainwp_maximumInstallUpdateRequests'] ) : 3 );
1588 MainWP_Utility::update_option( 'mainwp_sslVerifyCertificate', isset( $_POST['mainwp_sslVerifyCertificate'] ) ? 1 : 0 );
1589 MainWP_Utility::update_option( 'mainwp_connect_signature_algo', isset( $_POST['mainwp_settings_openssl_alg'] ) ? sanitize_text_field( wp_unslash( $_POST['mainwp_settings_openssl_alg'] ) ) : 0 );
1590 MainWP_Utility::update_option( 'mainwp_verify_connection_method', isset( $_POST['mainwp_settings_verify_connection_method'] ) ? intval( $_POST['mainwp_settings_verify_connection_method'] ) : 0 );
1591 MainWP_Utility::update_option( 'mainwp_forceUseIPv4', isset( $_POST['mainwp_forceUseIPv4'] ) ? 1 : 0 );
1592 $use_wpcron = ! isset( $_POST['mainwp_options_wp_cron'] ) ? 0 : 1;
1593 MainWP_Utility::update_option( 'mainwp_wp_cron', $use_wpcron );
1594 MainWP_Utility::update_option( 'mainwp_warm_cache_pages_ttl', intval( $_POST['mainwp_warm_cache_pages_ttl'] ) );
1595
1596 MainWP_Utility::update_option( 'mainwp_optimize', ( ! isset( $_POST['mainwp_optimize'] ) ? 0 : 1 ) );
1597 MainWP_Utility::update_option( 'mainwp_auto_correct_site_url', ( ! isset( $_POST['mainwp_auto_correct_site_url'] ) ? 0 : 1 ) );
1598 MainWP_Utility::update_option( 'mainwp_maximum_uptime_monitoring_requests', ! empty( $_POST['mainwp_maximumUptimeMonitoringRequests'] ) ? intval( $_POST['mainwp_maximumUptimeMonitoringRequests'] ) : 10 );
1599 MainWP_Utility::update_option( 'mainwp_chunksitesnumber', isset( $_POST['mainwp_chunksitesnumber'] ) ? intval( $_POST['mainwp_chunksitesnumber'] ) : 10 );
1600 MainWP_Utility::update_option( 'mainwp_chunksleepinterval', isset( $_POST['mainwp_chunksleepinterval'] ) ? intval( $_POST['mainwp_chunksleepinterval'] ) : 5 );
1601
1602 $sync_data = array();
1603
1604 if ( isset( $_POST['mainwp_settings_sync_data'] ) && is_array( $_POST['mainwp_settings_sync_data'] ) ) {
1605 $selected_data = array_map( 'sanitize_text_field', wp_unslash( $_POST['mainwp_settings_sync_data'] ) );
1606 foreach ( $selected_data as $name ) {
1607 $sync_data[ $name ] = 1;
1608 }
1609 }
1610
1611 if ( isset( $_POST['mainwp_settings_sync_name'] ) && is_array( $_POST['mainwp_settings_sync_name'] ) ) {
1612 $name_data = array_map( 'sanitize_text_field', wp_unslash( $_POST['mainwp_settings_sync_name'] ) );
1613 foreach ( $name_data as $name ) {
1614 if ( ! isset( $sync_data[ $name ] ) ) {
1615 $sync_data[ $name ] = 0;
1616 }
1617 }
1618 }
1619
1620 MainWP_Utility::update_option( 'mainwp_settings_sync_data', wp_json_encode( $sync_data ) );
1621
1622 // required check.
1623 MainWP_Uptime_Monitoring_Schedule::instance()->check_to_disable_schedule_individual_uptime_monitoring(); // required a check to sync the settings.
1624
1625 if ( isset( $_POST['mainwp_openssl_lib_location'] ) ) {
1626 $openssl_loc = ! empty( $_POST['mainwp_openssl_lib_location'] ) ? sanitize_text_field( wp_unslash( $_POST['mainwp_openssl_lib_location'] ) ) : '';
1627 MainWP_Utility::update_option( 'mainwp_opensslLibLocation', $openssl_loc );
1628 }
1629 /**
1630 * Action: mainwp_after_save_advanced_settings
1631 *
1632 * Fires after advanced settings save.
1633 *
1634 * @since 4.1
1635 */
1636 do_action( 'mainwp_after_save_advanced_settings', $_POST );
1637
1638 $new_settings = self::get_all_settings_values();
1639
1640 /**
1641 * Action: mainwp_after_save_settings
1642 *
1643 * Fires after save settings.
1644 *
1645 * @since 6.0
1646 *
1647 * @param array $new_settings The new settings.
1648 * @param array $old_settings The old settings.
1649 */
1650 do_action( 'mainwp_after_save_settings', $new_settings, $old_settings );
1651
1652 }
1653 static::render_header( 'Advanced' );
1654 ?>
1655
1656 <div id="mainwp-advanced-settings" class="ui padded segment">
1657 <?php if ( MainWP_Utility::show_mainwp_message( 'notice', 'mainwp-advanced-settings-info-notice' ) ) : ?>
1658 <div class="ui info message">
1659 <i class="close icon mainwp-notice-dismiss" notice-id="mainwp-advanced-settings-info-notice"></i>
1660 <?php echo esc_html__( 'Set how many requests are performed at once and delay between requests in order to optimize your MainWP Dashboard performance. Both Cross IP and IP Settings handle the majority of work connecting to your Child sites, while the sync, update, and installation request have specialized options under the Frontend Requests Settings section.', 'mainwp' ); ?>
1661 </div>
1662 <?php endif; ?>
1663 <?php if ( isset( $_POST['submit'] ) && isset( $_POST['wp_nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['wp_nonce'] ), 'SettingsAdvanced' ) ) : ?>
1664 <div class="ui green message"><i class="close icon"></i><?php esc_html_e( 'Settings have been saved successfully!', 'mainwp' ); ?></div>
1665 <?php endif; ?>
1666 <div class="ui form">
1667 <form method="POST" action="">
1668 <?php MainWP_UI::generate_wp_nonce( 'mainwp-admin-nonce' ); ?>
1669 <input type="hidden" name="wp_nonce" value="<?php echo esc_attr( wp_create_nonce( 'SettingsAdvanced' ) ); ?>" />
1670 <?php
1671
1672 /**
1673 * Action: mainwp_advanced_settings_form_top
1674 *
1675 * Fires at the top of advanced settings form.
1676 *
1677 * @since 4.1
1678 */
1679 do_action( 'mainwp_advanced_settings_form_top' );
1680
1681 if ( static::show_openssl_lib_config() ) {
1682 $openssl_loc = MainWP_System_Utility::get_openssl_conf();
1683 ?>
1684 <h3 class="ui dividing header">
1685 <?php esc_html_e( 'OpenSSL Settings', 'mainwp' ); ?>
1686 <div class="sub header"><?php esc_html_e( 'Due to bug with PHP on some servers it is required to set the OpenSSL Library location so MainWP Dashboard can connect to your child sites.', 'mainwp' ); ?></div>
1687 </h3>
1688 <div class="ui grid field">
1689 <label class="six wide column middle aligned"><?php esc_html_e( 'OpenSSL.cnf location', 'mainwp' ); ?></label>
1690 <div class="ten wide column ui field">
1691 <input type="text" name="mainwp_openssl_lib_location" value="<?php echo esc_html( $openssl_loc ); ?>">
1692 <em><?php esc_html_e( 'If your openssl.cnf file is saved to a different path from what is entered please enter your exact path.', 'mainwp' ); ?>
1693 <?php
1694 // translators: 1: Opening anchor tag. 2: Closing anchor tag.
1695 printf( esc_html__( 'If you are not sure how to find the openssl.cnf location, please %1$scheck this help document%2$s.', 'mainwp' ), '<a href="https://docs.mainwp.com/troubleshooting/potential-issues#openssl-library-error-invalid-request" target="_blank">', '</a> <i class="external alternate icon"></i>' );
1696 ?>
1697 </em>
1698 <em><?php esc_html_e( 'If you have confirmed the placement of your openssl.cnf and are still receiving an error banner, click the "Error Fixed" button to dismiss it.', 'mainwp' ); ?></em>
1699 </div>
1700 </div>
1701 <?php } ?>
1702
1703 <h3 class="ui dividing header">
1704 <?php MainWP_Settings_Indicator::render_indicator( 'header', 'settings-field-indicator-cross-ip' ); ?>
1705 <?php esc_html_e( 'Rate Limiting & Concurrency Controls', 'mainwp' ); ?>
1706 <div class="sub header"><?php esc_html_e( 'Fine-tune how your system handles outgoing requests by managing both global and per-server concurrency limits.', 'mainwp' ); ?></div>
1707 </h3>
1708
1709 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-cross-ip" default-indi-value="4">
1710 <label class="six wide column middle aligned">
1711 <?php
1712 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_maximumRequests', (int) get_option( 'mainwp_maximumRequests', 4 ) );
1713 esc_html_e( 'Global request limit (Default: 4)', 'mainwp' );
1714 ?>
1715 </label>
1716 <div class="ten wide column" data-tooltip="<?php esc_attr_e( 'Defines the overall maximum number of simultaneous requests that can be active. Adjust this setting to balance system throughput with resource constraints (default is 4).', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1717 <div class="ui bottom aligned labeled slider" id="mainwp_maximumRequests_slider"></div>
1718 <div class="ui input">
1719 <input type="hidden" class="settings-field-value-change-handler" name="mainwp_maximumRequests" id="mainwp_maximumRequests" value="<?php echo false === get_option( 'mainwp_maximumRequests' ) ? 4 : esc_attr( get_option( 'mainwp_maximumRequests' ) ); ?>"/>
1720 </div>
1721 </div>
1722 </div>
1723
1724 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-cross-ip" default-indi-value="200">
1725 <label class="six wide column middle aligned">
1726 <?php
1727 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_minimumDelay', (int) get_option( 'mainwp_minimumDelay', 200 ) );
1728 esc_html_e( 'Minimum delay between requests in milliseconds (Default: 200ms)', 'mainwp' );
1729 ?>
1730 </label>
1731 <div class="ten wide column" data-tooltip="<?php esc_attr_e( 'This option allows you to control minimum time delay between two requests.', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1732 <div class="ui bottom aligned labeled slider" id="mainwp_minimumDelay_slider"></div>
1733 <div class="ui input">
1734 <input type="hidden" class="settings-field-value-change-handler" name="mainwp_minimumDelay" id="mainwp_minimumDelay" value="<?php echo false === get_option( 'mainwp_minimumDelay' ) ? 200 : esc_attr( get_option( 'mainwp_minimumDelay' ) ); ?>"/>
1735 </div>
1736 </div>
1737 </div>
1738
1739 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-per-ip" default-indi-value="1">
1740 <label class="six wide column middle aligned">
1741 <?php
1742 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_maximumIPRequests', (int) get_option( 'mainwp_maximumIPRequests', 1 ) );
1743 esc_html_e( 'Per-IP request limit (Default: 1)', 'mainwp' );
1744 ?>
1745 </label>
1746 <div class="ten wide column" data-tooltip="<?php esc_attr_e( 'Sets the maximum number of concurrent requests allowed for any individual website\'s IP address. This setting safeguards target servers from excessive load (default is 1).', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1747 <div class="ui bottom aligned labeled slider" id="mainwp_maximumIPRequests_slider"></div>
1748 <div class="ui input">
1749 <input type="hidden" class="settings-field-value-change-handler" name="mainwp_maximumIPRequests" id="mainwp_maximumIPRequests" value="<?php echo false === get_option( 'mainwp_maximumIPRequests' ) ? 1 : esc_attr( get_option( 'mainwp_maximumIPRequests' ) ); ?>"/>
1750 </div>
1751 </div>
1752 </div>
1753
1754 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-per-ip" default-indi-value="1000">
1755 <label class="six wide column middle aligned">
1756 <?php
1757 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_minimumIPDelay', (int) get_option( 'mainwp_minimumIPDelay', 1000 ) );
1758 esc_html_e( 'Minimum delay between requests to the same IP in milliseconds (Default: 1000ms)', 'mainwp' );
1759 ?>
1760 </label>
1761 <div class="ten wide column" data-tooltip="<?php esc_attr_e( 'This option allows you to control minimum time delay between two requests.', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1762 <div class="ui bottom aligned labeled slider" id="mainwp_minimumIPDelay_slider"></div>
1763 <div class="ui input">
1764 <input type="hidden" class="settings-field-value-change-handler" name="mainwp_minimumIPDelay" id="mainwp_minimumIPDelay" value="<?php echo false === get_option( 'mainwp_minimumIPDelay' ) ? 1000 : esc_attr( get_option( 'mainwp_minimumIPDelay' ) ); ?>"/>
1765 </div>
1766 </div>
1767 </div>
1768
1769 <h3 class="ui dividing header">
1770 <?php MainWP_Settings_Indicator::render_indicator( 'header', 'settings-field-indicator-chunk-site' ); ?>
1771 <?php esc_html_e( 'Batch Processing Settings', 'mainwp' ); ?>
1772 <div class="sub header"><?php esc_html_e( 'Configure how many websites are processed at once and the delay between each batch to optimize system performance and prevent server overload.', 'mainwp' ); ?></div>
1773 </h3>
1774
1775 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-cross-ip" default-indi-value="10">
1776 <label class="six wide column middle aligned">
1777 <?php
1778 MainWP_Settings_Indicator::render_not_default_indicator( 'none_preset_value', 10 === (int) get_option( 'mainwp_chunksitesnumber', 10 ) ? '' : 1 );
1779 esc_html_e( 'Maximum sites per batch (Default: 10)', 'mainwp' );
1780 ?>
1781 </label>
1782 <div class="ten wide column" data-tooltip="<?php esc_attr_e( 'The maximum number of websites processed concurrently. If too many requests are sent out, they will begin to time out.', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1783 <div class="ui bottom aligned labeled slider" id="mainwp_chunksitesnumber_slider"></div>
1784 <div class="ui input">
1785 <input type="hidden" class="settings-field-value-change-handler" name="mainwp_chunksitesnumber" id="mainwp_chunksitesnumber" value="<?php echo false === get_option( 'mainwp_chunksitesnumber' ) ? 10 : (int) get_option( 'mainwp_chunksitesnumber' ); ?>"/>
1786 </div>
1787 </div>
1788 </div>
1789
1790 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-cross-ip" default-indi-value="5">
1791 <label class="six wide column middle aligned">
1792 <?php
1793 MainWP_Settings_Indicator::render_not_default_indicator( 'none_preset_value', 5 === (int) get_option( 'mainwp_chunksleepinterval', 5 ) ? '' : 1 );
1794 esc_html_e( 'Delay between batches (Default: 5ms)', 'mainwp' );
1795 ?>
1796 </label>
1797 <div class="ten wide column" data-tooltip="<?php esc_attr_e( 'The pause duration between processing each batch of websites.', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1798 <div class="ui bottom aligned labeled slider" id="mainwp_chunksleepinterval_slider"></div>
1799 <div class="ui input">
1800 <input type="hidden" class="settings-field-value-change-handler" name="mainwp_chunksleepinterval" id="mainwp_chunksleepinterval" value="<?php echo false === get_option( 'mainwp_chunksleepinterval' ) ? 5 : (int) get_option( 'mainwp_chunksleepinterval' ); ?>"/>
1801 </div>
1802 </div>
1803 </div>
1804
1805 <h3 class="ui dividing header">
1806 <?php MainWP_Settings_Indicator::render_indicator( 'header', 'settings-field-indicator-frontend-request' ); ?>
1807 <?php esc_html_e( 'Frontend Request Settings', 'mainwp' ); ?>
1808 <div class="sub header"><?php esc_html_e( 'Configure limits for concurrent background tasks such as synchronization, installation/updating, and uptime monitoring, ensuring efficient resource use and system stability.', 'mainwp' ); ?></div>
1809 </h3>
1810
1811 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-frontend-request" default-indi-value="8">
1812 <label class="six wide column middle aligned">
1813 <?php
1814 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_maximumSyncRequests', (int) get_option( 'mainwp_maximumSyncRequests', 8 ) );
1815 esc_html_e( 'Maximum simultaneous sync requests (Default: 8)', 'mainwp' );
1816 ?>
1817 </label>
1818 <div class="ten wide column" data-tooltip="<?php esc_attr_e( 'This option allows you to control how many sites your MainWP Dashboard should sync at once.', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1819 <div class="ui bottom aligned labeled slider" id="mainwp_maximumSyncRequests_slider"></div>
1820 <div class="ui input">
1821 <input type="hidden" class="settings-field-value-change-handler" name="mainwp_maximumSyncRequests" id="mainwp_maximumSyncRequests" value="<?php echo false === get_option( 'mainwp_maximumSyncRequests' ) ? 8 : esc_attr( get_option( 'mainwp_maximumSyncRequests' ) ); ?>"/>
1822 </div>
1823 </div>
1824 </div>
1825
1826 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-frontend-request" default-indi-value="3">
1827 <label class="six wide column middle aligned">
1828 <?php
1829 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_maximumInstallUpdateRequests', (int) get_option( 'mainwp_maximumInstallUpdateRequests', 3 ) );
1830 esc_html_e( 'Maximum simultaneous install and update requests (Default: 3)', 'mainwp' );
1831 ?>
1832 </label>
1833 <div class="ten wide column" data-tooltip="<?php esc_attr_e( 'This option allows you to control how many update and install requests your MainWP Dashboard should process at once.', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1834 <div class="ui bottom aligned labeled slider" id="mainwp_maximumInstallUpdateRequests_slider"></div>
1835 <div class="ui input">
1836 <input type="hidden" class="settings-field-value-change-handler" name="mainwp_maximumInstallUpdateRequests" id="mainwp_maximumInstallUpdateRequests" value="<?php echo false === get_option( 'mainwp_maximumInstallUpdateRequests' ) ? 3 : esc_attr( get_option( 'mainwp_maximumInstallUpdateRequests' ) ); ?>"/>
1837 </div>
1838 </div>
1839 </div>
1840
1841 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-frontend-request" default-indi-value="10">
1842 <label class="six wide column middle aligned">
1843 <?php
1844 $maximum_monitoring_requests = (int) get_option( 'mainwp_maximum_uptime_monitoring_requests', 10 );
1845 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_maximum_uptime_monitoring_requests', $maximum_monitoring_requests );
1846 esc_html_e( 'Maximum simultaneous uptime monitoring requests (Default: 10)', 'mainwp' );
1847 ?>
1848 </label>
1849 <div class="ten wide column" data-tooltip="<?php esc_attr_e( 'This option allows you to control how many uptime monitoring requests your MainWP Dashboard should process at once.', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1850 <div class="ui bottom aligned labeled slider settings-field-value-change-handler" id="mainwp_maximumUptimeMonitoringRequests_slider"></div>
1851 <div class="ui input">
1852 <input type="hidden" class="settings-field-value-change-handler" name="mainwp_maximumUptimeMonitoringRequests" id="mainwp_maximumUptimeMonitoringRequests" value="<?php echo false === get_option( 'mainwp_maximum_uptime_monitoring_requests' ) ? 10 : esc_attr( get_option( 'mainwp_maximum_uptime_monitoring_requests' ) ); ?>"/>
1853 </div>
1854 </div>
1855 </div>
1856
1857 <h3 class="ui dividing header">
1858 <?php MainWP_Settings_Indicator::render_indicator( 'header', 'settings-field-indicator-miscellaneous' ); ?>
1859 <?php esc_html_e( 'Miscellaneous Settings', 'mainwp' ); ?></h3>
1860 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-miscellaneous" default-indi-value="1">
1861 <label class="six wide column middle aligned">
1862 <?php
1863 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_optimize', (int) get_option( 'mainwp_optimize', 1 ) );
1864 esc_html_e( 'Optimize data loading', 'mainwp' );
1865 ?>
1866 </label>
1867 <div class="ten wide column ui toggle checkbox" data-tooltip="<?php esc_attr_e( 'If enabled, your MainWP Dashboard will cache updates for faster loading.', 'mainwp' ); ?>" data-inverted="" data-position="bottom left">
1868 <input type="checkbox" class="settings-field-value-change-handler" name="mainwp_optimize" id="mainwp_optimize" <?php echo 1 === (int) get_option( 'mainwp_optimize', 1 ) ? 'checked="true"' : ''; ?> /><label><?php esc_html_e( 'Default: Enabled', 'mainwp' ); ?></label>
1869 </div>
1870 </div>
1871 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-miscellaneous" default-indi-value="1">
1872 <label class="six wide column middle aligned">
1873 <?php
1874 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_auto_correct_site_url', (int) get_option( 'mainwp_auto_correct_site_url', 1 ) );
1875 esc_html_e( 'Auto-correct site URLs', 'mainwp' );
1876 ?>
1877 </label>
1878 <div class="ten wide column ui toggle checkbox" data-tooltip="<?php esc_attr_e( 'If enabled, your MainWP Dashboard will automatically correct the stored site URL when the child site reports a different address. Only safe changes are applied (www variant and HTTP to HTTPS); the corrected URL is verified before saving, and sites with a locked URL are never changed.', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1879 <input type="checkbox" class="settings-field-value-change-handler" name="mainwp_auto_correct_site_url" id="mainwp_auto_correct_site_url" <?php echo 1 === (int) get_option( 'mainwp_auto_correct_site_url', 1 ) ? 'checked="true"' : ''; ?> /><label><?php esc_html_e( 'Default: Enabled', 'mainwp' ); ?></label>
1880 </div>
1881 </div>
1882 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-miscellaneous" default-indi-value="10">
1883 <label class="six wide column middle aligned">
1884 <?php
1885 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_warm_cache_pages_ttl', (int) get_option( 'mainwp_warm_cache_pages_ttl', 10 ) );
1886 esc_html_e( 'Browser cache expiration time', 'mainwp' );
1887 $browser_cache_ttl = (int) get_option( 'mainwp_warm_cache_pages_ttl', 10 );
1888 ?>
1889 </label>
1890 <div class="five wide column" data-tooltip="<?php esc_attr_e( 'Set how many minutes the browser cache should retain page content before it expires', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1891 <input type="number" class="settings-field-value-change-handler small-text" name="mainwp_warm_cache_pages_ttl" id="mainwp_warm_cache_pages_ttl" placeholder="" min="1" max="24" step="1" value="<?php echo intval( $browser_cache_ttl ); ?>">
1892 </div>
1893 </div>
1894 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-miscellaneous" default-indi-value="1">
1895 <label class="six wide column middle aligned">
1896 <?php
1897 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_wp_cron', (int) get_option( 'mainwp_wp_cron', 1 ) );
1898 esc_html_e( 'Use WP Cron', 'mainwp' );
1899 ?>
1900 </label>
1901 <div class="ten wide column ui toggle checkbox" data-tooltip="<?php esc_attr_e( 'Disabling this option will disable the WP Cron so all scheduled events will stop working.', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1902 <input type="checkbox" class="settings-field-value-change-handler" name="mainwp_options_wp_cron" id="mainwp_options_wp_cron" <?php echo 1 === (int) get_option( 'mainwp_wp_cron' ) || ( false === get_option( 'mainwp_wp_cron' ) ) ? 'checked="true"' : ''; ?>/><label><?php esc_html_e( 'Default: Enabled', 'mainwp' ); ?></label>
1903 </div>
1904 </div>
1905 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-miscellaneous" default-indi-value="1" >
1906 <label class="six wide column middle aligned">
1907 <?php
1908 $indi_val = (int) get_option( 'mainwp_sslVerifyCertificate', 1 );
1909 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_sslVerifyCertificate', $indi_val );
1910 esc_html_e( 'Verify SSL certificate', 'mainwp' );
1911 ?>
1912 </label>
1913 <div class="ten wide column ui toggle checkbox" data-tooltip="<?php esc_attr_e( 'If enabled, your MainWP Dashboard will verify the SSL Certificate on your Child Site (if exists) while connecting the Child Site.', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1914 <input type="checkbox" class="settings-field-value-change-handler" name="mainwp_sslVerifyCertificate" id="mainwp_sslVerifyCertificate" value="checked" <?php echo false === get_option( 'mainwp_sslVerifyCertificate' ) || 1 === (int) get_option( 'mainwp_sslVerifyCertificate' ) ? 'checked="checked"' : ''; ?>/><label><?php esc_html_e( 'Default: Enabled', 'mainwp' ); ?></label>
1915 </div>
1916 </div>
1917 <?php
1918 $general_verify_con = (int) get_option( 'mainwp_verify_connection_method', 1 );
1919 ?>
1920 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-miscellaneous" default-indi-value="1">
1921 <label class="six wide column middle aligned">
1922 <?php
1923 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_verify_connection_method', (int) $general_verify_con );
1924 esc_html_e( 'Verify connection method', 'mainwp' );
1925 ?>
1926 </label>
1927 <div class="ui six wide column" data-tooltip="<?php esc_attr_e( 'Select Verify connection method. If you are not sure, select "Default".', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1928 <select class="ui dropdown settings-field-value-change-handler" id="mainwp_settings_verify_connection_method" name="mainwp_settings_verify_connection_method">
1929 <option <?php echo ( empty( $general_verify_con ) || 1 === $general_verify_con ) ? 'selected' : ''; ?> value="1"><?php esc_html_e( 'OpenSSL (default)', 'mainwp' ); ?></option>
1930 <option <?php echo ( 2 === $general_verify_con ) ? 'selected' : ''; ?> value="2"><?php esc_html_e( 'PHPSECLIB (fallback)', 'mainwp' ); ?></option>
1931 </select>
1932 </div>
1933 </div>
1934 <?php
1935 $sign_note = MainWP_Connect_Lib::get_connection_algo_settings_note();
1936 $sign_algs = MainWP_System_Utility::get_open_ssl_sign_algos();
1937 $general_sign_alg = get_option( 'mainwp_connect_signature_algo', false );
1938 if ( false === $general_sign_alg ) {
1939 $general_sign_alg = defined( 'OPENSSL_ALGO_SHA256' ) ? OPENSSL_ALGO_SHA256 : 1;
1940 MainWP_Utility::update_option( 'mainwp_connect_signature_algo', $general_sign_alg );
1941 } else {
1942 $general_sign_alg = intval( $general_sign_alg );
1943 }
1944 $algo_def = defined( 'OPENSSL_ALGO_SHA256' ) ? (int) OPENSSL_ALGO_SHA256 : 1;
1945 ?>
1946 <div default-indi-value="<?php echo esc_attr( $algo_def ); ?>" class="ui grid field mainwp-hide-elemenent-sign-algo settings-field-indicator-wrapper settings-field-indicator-miscellaneous" <?php echo ( 2 === $general_verify_con ) ? 'style="display:none;"' : ''; ?> >
1947 <label class="six wide column middle aligned">
1948 <?php
1949 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_connect_signature_algo', (int) $general_sign_alg );
1950 esc_html_e( 'OpenSSL signature algorithm', 'mainwp' );
1951 ?>
1952 </label>
1953 <div class="ui six wide column" data-tooltip="<?php esc_attr_e( 'Select OpenSSL signature algorithm. If you are not sure, select "Default".', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1954 <select class="ui dropdown settings-field-value-change-handler" id="mainwp_settings_openssl_alg" name="mainwp_settings_openssl_alg">
1955 <?php
1956 foreach ( $sign_algs as $val => $text ) {
1957 ?>
1958 <option <?php echo ( $val === $general_sign_alg ) ? 'selected' : ''; ?> value="<?php echo esc_attr( $val ); ?>"><?php echo esc_html( $text ); ?></option>
1959 <?php
1960 }
1961 ?>
1962 </select>
1963 <div class="ui yellow message mainwp-hide-elemenent-sign-algo-note" <?php echo ( 1 === $general_sign_alg ) ? '' : 'style="display:none;"'; ?>><?php echo esc_html( $sign_note ); ?></div>
1964 </div>
1965 </div>
1966 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-miscellaneous">
1967 <label class="six wide column middle aligned">
1968 <?php
1969 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_forceUseIPv4', (int) get_option( 'mainwp_forceUseIPv4' ) );
1970 esc_html_e( 'Force IPv4', 'mainwp' );
1971 ?>
1972 </label>
1973 <div class="ten wide column ui toggle checkbox" data-tooltip="<?php esc_attr_e( 'Enable if you want to force your MainWP Dashboard to use IPv4 while trying to connect child sites.', 'mainwp' ); ?>" data-inverted="" data-position="bottom left">
1974 <input type="checkbox" class="settings-field-value-change-handler" name="mainwp_forceUseIPv4" id="mainwp_forceUseIPv4" value="checked" <?php echo ( 1 === (int) get_option( 'mainwp_forceUseIPv4' ) ) ? 'checked="checked"' : ''; ?>/><label><?php esc_html_e( 'Default: Disabled', 'mainwp' ); ?></label>
1975 </div>
1976 </div>
1977 <?php
1978 static::render_sync_data_selection();
1979 /**
1980 * Action: mainwp_advanced_settings_form_bottom
1981 *
1982 * Fires at the bottom of advanced settings form.
1983 *
1984 * @since 4.1
1985 */
1986 do_action( 'mainwp_advanced_settings_form_bottom' );
1987
1988 ?>
1989 <div class="ui divider"></div>
1990 <input type="submit" name="submit" id="submit" class="ui green big button" value="<?php esc_attr_e( 'Save Settings', 'mainwp' ); ?>"/>
1991 </form>
1992 </div>
1993 </div>
1994 <?php static::render_disable_installed_plugins_sync_modal(); ?>
1995 <script>
1996 jQuery(document).ready(function() {
1997 const maximumRequests = <?php echo ! empty( get_option( 'mainwp_maximumRequests' ) ) ? esc_js( get_option( 'mainwp_maximumRequests' ) ) : 4; ?>;
1998 jQuery('#mainwp_maximumRequests_slider').slider({
1999 min: 1,
2000 max: 20,
2001 start: maximumRequests,
2002 step: 1,
2003 restrictedLabels: [1,20],
2004 showThumbTooltip: true,
2005 tooltipConfig: {
2006 position: 'top center',
2007 variation: 'small visible black'
2008 },
2009 onChange: function(value) {
2010 jQuery('#mainwp_maximumRequests').val(value);
2011 }
2012 });
2013 const minimumDelay = <?php echo ! empty( get_option( 'mainwp_minimumDelay' ) ) ? esc_js( get_option( 'mainwp_minimumDelay' ) ) : 200; ?>;
2014 jQuery('#mainwp_minimumDelay_slider').slider({
2015 min: 100,
2016 max: 5000,
2017 start: minimumDelay,
2018 step: 100,
2019 restrictedLabels: [100,5000],
2020 showThumbTooltip: true,
2021 tooltipConfig: {
2022 position: 'top center',
2023 variation: 'small visible black'
2024 },
2025 onChange: function(value) {
2026 jQuery('#mainwp_minimumDelay').val(value);
2027 }
2028 });
2029 const maximumIPRequests = <?php echo ! empty( get_option( 'mainwp_maximumIPRequests' ) ) ? esc_js( get_option( 'mainwp_maximumIPRequests' ) ) : 1; ?>;
2030 jQuery('#mainwp_maximumIPRequests_slider').slider({
2031 min: 1,
2032 max: 10,
2033 start: maximumIPRequests,
2034 step: 1,
2035 restrictedLabels: [1,10],
2036 showThumbTooltip: true,
2037 tooltipConfig: {
2038 position: 'top center',
2039 variation: 'small visible black'
2040 },
2041 onChange: function(value) {
2042 jQuery('#mainwp_maximumIPRequests').val(value);
2043 }
2044 });
2045 const minimumIPDelay = <?php echo ! empty( get_option( 'mainwp_minimumIPDelay' ) ) ? esc_js( get_option( 'mainwp_minimumIPDelay' ) ) : 1000; ?>;
2046 jQuery('#mainwp_minimumIPDelay_slider').slider({
2047 min: 500,
2048 max: 5000,
2049 start: minimumIPDelay,
2050 step: 100,
2051 restrictedLabels: [500,5000],
2052 showThumbTooltip: true,
2053 tooltipConfig: {
2054 position: 'top center',
2055 variation: 'small visible black'
2056 },
2057 onChange: function(value) {
2058 jQuery('#mainwp_minimumIPDelay').val(value);
2059 }
2060 });
2061 const maximumSyncRequests = <?php echo ! empty( get_option( 'mainwp_maximumSyncRequests' ) ) ? esc_js( get_option( 'mainwp_maximumSyncRequests' ) ) : 8; ?>;
2062 jQuery('#mainwp_maximumSyncRequests_slider').slider({
2063 min: 1,
2064 max: 20,
2065 start: maximumSyncRequests,
2066 step: 1,
2067 restrictedLabels: [1,20],
2068 showThumbTooltip: true,
2069 tooltipConfig: {
2070 position: 'top center',
2071 variation: 'small visible black'
2072 },
2073 onChange: function(value) {
2074 jQuery('#mainwp_maximumSyncRequests').val(value);
2075 }
2076 });
2077 const maximumInstallUpdateRequests = <?php echo ! empty( get_option( 'mainwp_maximumInstallUpdateRequests' ) ) ? esc_js( get_option( 'mainwp_maximumInstallUpdateRequests' ) ) : 3; ?>;
2078 jQuery('#mainwp_maximumInstallUpdateRequests_slider').slider({
2079 min: 1,
2080 max: 20,
2081 start: maximumInstallUpdateRequests,
2082 step: 1,
2083 restrictedLabels: [1,20],
2084 showThumbTooltip: true,
2085 tooltipConfig: {
2086 position: 'top center',
2087 variation: 'small visible black'
2088 },
2089 onChange: function(value) {
2090 jQuery('#mainwp_maximumInstallUpdateRequests').val(value);
2091 }
2092 });
2093 const maximumUptimeMonitoringRequests = <?php echo ! empty( get_option( 'mainwp_maximum_uptime_monitoring_requests' ) ) ? esc_js( get_option( 'mainwp_maximum_uptime_monitoring_requests' ) ) : 10; ?>;
2094 jQuery('#mainwp_maximumUptimeMonitoringRequests_slider').slider({
2095 min: 1,
2096 max: 100,
2097 start: maximumUptimeMonitoringRequests,
2098 step: 1,
2099 restrictedLabels: [1,100],
2100 showThumbTooltip: true,
2101 tooltipConfig: {
2102 position: 'top center',
2103 variation: 'small visible black'
2104 },
2105 onChange: function(value) {
2106 jQuery('#mainwp_maximumUptimeMonitoringRequests').val(value).change();
2107 }
2108 });
2109 jQuery('#mainwp_maximumUptimeMonitoringRequests_slider').slider('set value', maximumUptimeMonitoringRequests);
2110
2111 jQuery('#mainwp_chunksitesnumber_slider').slider({
2112 min: 1,
2113 max: 30,
2114 start: <?php echo false !== get_option( 'mainwp_chunksitesnumber' ) ? intval( get_option( 'mainwp_chunksitesnumber' ) ) : 10; ?>,
2115 step: 1,
2116 restrictedLabels: [1,30],
2117 showThumbTooltip: true,
2118 tooltipConfig: {
2119 position: 'top center',
2120 variation: 'small visible black'
2121 },
2122 onChange: function(value) {
2123 jQuery('#mainwp_chunksitesnumber').val(value).change();
2124 }
2125 });
2126
2127 jQuery('#mainwp_chunksleepinterval_slider').slider({
2128 min: 0,
2129 max: 20,
2130 start: <?php echo false !== get_option( 'mainwp_chunksleepinterval' ) ? intval( get_option( 'mainwp_chunksleepinterval' ) ) : 5; ?>,
2131 step: 1,
2132 restrictedLabels: [0,20],
2133 showThumbTooltip: true,
2134 tooltipConfig: {
2135 position: 'top center',
2136 variation: 'small visible black'
2137 },
2138 onChange: function(value) {
2139 jQuery('#mainwp_chunksleepinterval').val(value).change();
2140 }
2141 });
2142 });
2143 </script>
2144 <?php
2145 static::render_footer( 'Advanced' );
2146 }
2147
2148 /**
2149 * Method render_sync_data_selection().
2150 *
2151 * @return void
2152 */
2153 public static function render_sync_data_selection() {
2154
2155 $default_sync = static::get_data_sync_default();
2156
2157 $sync_data_settings = get_option( 'mainwp_settings_sync_data' );
2158
2159 $sync_data_settings = ! empty( $sync_data_settings ) ? json_decode( $sync_data_settings, true ) : array();
2160
2161 if ( ! is_array( $sync_data_settings ) ) {
2162 $sync_data_settings = array();
2163 }
2164
2165 $setting_page = true;
2166
2167 ?>
2168 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-miscellaneous">
2169 <label class="six wide column top aligned">
2170 <?php
2171 MainWP_Settings_Indicator::render_indicator( 'header', 'settings-field-indicator-sync-data' );
2172 esc_html_e( 'Select data to sync', 'mainwp' );
2173 ?>
2174 </label>
2175 <div class="ten wide column" <?php echo $setting_page ? 'data-tooltip="' . esc_attr__( 'Select data that you want to sync.', 'mainwp' ) . '"' : ''; ?> data-inverted="" data-position="top left">
2176 <ul class="mainwp_hide_wpmenu_checkboxes">
2177 <?php
2178 foreach ( $default_sync as $name => $title ) {
2179 $_selected = '';
2180 if ( ! isset( $sync_data_settings[ $name ] ) || 1 === (int) $sync_data_settings[ $name ] ) {
2181 $_selected = 'checked';
2182 }
2183 ?>
2184 <li>
2185 <div class="ui checkbox">
2186 <input type="checkbox" class="settings-field-value-change-handler" id="mainwp_select_sync_<?php echo esc_attr( $name ); ?>" name="mainwp_settings_sync_data[]" <?php echo esc_html( $_selected ); ?> value="<?php echo esc_attr( $name ); ?>">
2187 <label for="mainwp_select_sync_<?php echo esc_attr( $name ); ?>" ><?php echo esc_html( $title ); ?></label>
2188 </div>
2189 <input type="hidden" name="mainwp_settings_sync_name[]" value="<?php echo esc_attr( $name ); ?>">
2190 </li>
2191 <?php
2192 }
2193 ?>
2194 </ul>
2195 </div>
2196 </div>
2197 <?php
2198 }
2199
2200 /**
2201 * Render the Installed plugins sync warning modal.
2202 *
2203 * @since 6.1.3
2204 *
2205 * @return void
2206 */
2207 public static function render_disable_installed_plugins_sync_modal() {
2208 ?>
2209 <div class="ui small modal" id="mainwp-disable-installed-plugins-sync-modal">
2210 <div class="header"><?php esc_html_e( 'Disable Installed Plugins Sync?', 'mainwp' ); ?></div>
2211 <div class="content">
2212 <div class="ui yellow message">
2213 <div class="header"><?php esc_html_e( 'MainWP Add-ons may not work as expected', 'mainwp' ); ?></div>
2214 <p><?php esc_html_e( 'Some MainWP Add-ons need the installed plugins data to detect required plugins on your Child Sites. If you disable this option, those Add-ons may not work as expected.', 'mainwp' ); ?></p>
2215 </div>
2216 </div>
2217 <div class="actions">
2218 <div class="ui basic cancel button"><?php esc_html_e( 'Cancel', 'mainwp' ); ?></div>
2219 <div class="ui green approve button"><?php esc_html_e( 'I understand', 'mainwp' ); ?></div>
2220 </div>
2221 </div>
2222 <script type="text/javascript">
2223 jQuery( document ).ready( function () {
2224 const installedPluginsCheckbox = jQuery( '#mainwp_select_sync_plugins' );
2225 const warningModal = jQuery( '#mainwp-disable-installed-plugins-sync-modal' );
2226 let disableConfirmed = false;
2227
2228 installedPluginsCheckbox.on( 'change', function () {
2229 if ( installedPluginsCheckbox.is( ':checked' ) ) {
2230 disableConfirmed = false;
2231 return;
2232 }
2233
2234 if ( disableConfirmed ) {
2235 return;
2236 }
2237
2238 warningModal.modal( {
2239 closable: false,
2240 onApprove: function () {
2241 disableConfirmed = true;
2242 },
2243 onDeny: function () {
2244 installedPluginsCheckbox.prop( 'checked', true ).trigger( 'change' );
2245 }
2246 } ).modal( 'show' );
2247 } );
2248 } );
2249 </script>
2250 <?php
2251 }
2252
2253 /**
2254 * Method get_data_sync_default().
2255 *
2256 * @return array data.
2257 */
2258 public static function get_data_sync_default() {
2259 return array(
2260 'wp_updates' => __( 'WordPress updates information', 'mainwp' ),
2261 'plugin_updates' => __( 'Plugins updates information', 'mainwp' ),
2262 'theme_updates' => __( 'Themes updates information', 'mainwp' ),
2263 'translation_updates' => __( 'Translations updates information', 'mainwp' ),
2264 'recent_comments' => __( 'Recent comments', 'mainwp' ),
2265 'recent_posts' => __( 'Recent posts', 'mainwp' ),
2266 'recent_pages' => __( 'Recent pages', 'mainwp' ),
2267 'securityStats' => __( 'Site hardening information', 'mainwp' ),
2268 'directories' => __( 'Site directory listing (needed for legacy backup feature)', 'mainwp' ),
2269 'categories' => __( 'Posts catetegories', 'mainwp' ),
2270 'totalsize' => __( 'Website size (needed for Clone and legacy backup features)', 'mainwp' ),
2271 'dbsize' => __( 'Database size information', 'mainwp' ),
2272 'plugins' => __( 'Installed plugins', 'mainwp' ),
2273 'themes' => __( 'Installed Themes', 'mainwp' ),
2274 'users' => __( 'Users information', 'mainwp' ),
2275 'plugins_outdate_info' => __( 'Abandoned plugins information', 'mainwp' ),
2276 'themes_outdate_info' => __( 'Abandoned themes information', 'mainwp' ),
2277 'health_site_status' => __( 'Site health information', 'mainwp' ),
2278 'child_site_actions_data' => __( 'Non-MainWP changes data', 'mainwp' ),
2279 'othersData' => __( 'Other data (required by some extensions)', 'mainwp' ),
2280 );
2281 }
2282
2283 /**
2284 * Method get_data_list_to_sync().
2285 *
2286 * @return array Data list to sync.
2287 */
2288 public function get_data_list_to_sync() {
2289 $sync_data_settings = get_option( 'mainwp_settings_sync_data' );
2290
2291 if ( false === $sync_data_settings ) {
2292 $default_sync = static::get_data_sync_default();
2293 $sync_lists = array_fill_keys( array_keys( $default_sync ), 1 );
2294 MainWP_Utility::update_option( 'mainwp_settings_sync_data', wp_json_encode( $sync_lists ) );
2295 return $sync_lists;
2296 }
2297
2298 $sync_lists = ! empty( $sync_data_settings ) ? json_decode( $sync_data_settings, true ) : array();
2299
2300 if ( ! is_array( $sync_lists ) ) {
2301 $sync_lists = array();
2302 }
2303 return $sync_lists;
2304 }
2305
2306
2307 /**
2308 * Render MainWP Tools SubPage.
2309 *
2310 * @uses \MainWP\Dashboard\MainWP_UI::render_screen_options()
2311 */
2312 public static function render_mainwp_tools() { // phpcs:ignore -- NOSONAR - complex.
2313 if ( ! \mainwp_current_user_can( 'dashboard', 'manage_dashboard_settings' ) ) {
2314 \mainwp_do_not_have_permissions( esc_html__( 'manage dashboard settings', 'mainwp' ) );
2315 return;
2316 }
2317 static::render_header( 'MainWPTools' );
2318 ?>
2319 <div id="mainwp-tools-settings" class="ui padded segment">
2320 <div id="mainwp-message-zone" style="display:none;" class="ui message"></div>
2321 <?php if ( MainWP_Utility::show_mainwp_message( 'notice', 'mainwp-tools-info-message' ) ) : ?>
2322 <div class="ui info message">
2323 <i class="close icon mainwp-notice-dismiss" notice-id="mainwp-tools-info-message"></i>
2324 <?php
2325 // translators: 1: Opening anchor tag. 2: Closing anchor tag.
2326 printf( esc_html__( 'Use MainWP tools to adjust your MainWP Dashboard to your needs and perform specific actions when needed. For additional help, review this %1$shelp document%2$s.', 'mainwp' ), '<a href="https://docs.mainwp.com/sites/management/mainwp-dashboard-settings#mainwp-dashboard-settings" target="_blank">', '</a> <i class="external alternate icon"></i>' );
2327 ?>
2328 </div>
2329 <?php endif; ?>
2330 <?php if ( MainWP_Utility::show_mainwp_message( 'notice', 'mainwp-tools-info-custom-theme' ) ) : ?>
2331 <div class="ui info message">
2332 <i class="close icon mainwp-notice-dismiss" notice-id="mainwp-tools-info-custom-theme"></i>
2333 <div><?php esc_html_e( 'Here you can select a theme for your MainWP Dashboard.', 'mainwp' ); ?></div>
2334 <div><?php esc_html_e( 'To create a custom theme, copy the `mainwp-dark-theme.css` file from the MainWP Custom Dashboard Extension located in the `css` directory, make your edits and upload the file to the `../wp-content/uploads/mainwp/custom-dashboard/` directory.', 'mainwp' ); ?></div>
2335 </div>
2336 <?php endif; ?>
2337 <?php
2338 $show_saved_message = false;
2339 if ( isset( $_POST['submit'] ) && isset( $_POST['wp_nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['wp_nonce'] ), 'MainWPTools' ) ) {
2340 $show_saved_message = true;
2341 } elseif ( get_transient( 'mainwp_settings_saved' ) ) {
2342 $show_saved_message = true;
2343 delete_transient( 'mainwp_settings_saved' ); // Remove transient after showing message.
2344 }
2345 ?>
2346 <?php if ( $show_saved_message ) : ?>
2347 <div class="ui green message">
2348 <i class="close icon"></i>
2349 <?php esc_html_e( 'Settings have been saved successfully!', 'mainwp' ); ?>
2350 </div>
2351 <?php endif; ?>
2352 <?php if ( isset( $_POST['mainwp_restore_info_messages'] ) && isset( $_POST['wp_nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['wp_nonce'] ), 'MainWPTools' ) ) : ?>
2353 <div class="ui green message"><i class="close icon"></i><?php esc_html_e( 'Info messages have been restored successfully!', 'mainwp' ); ?></div>
2354 <?php endif; ?>
2355 <div class="ui form">
2356 <form method="POST" action="">
2357 <?php MainWP_UI::generate_wp_nonce( 'mainwp-admin-nonce' ); ?>
2358 <input type="hidden" name="wp_nonce" value="<?php echo esc_attr( wp_create_nonce( 'MainWPTools' ) ); ?>" />
2359
2360 <?php
2361 /**
2362 * Action: mainwp_tools_form_top
2363 *
2364 * Fires at the top of MainWP tools form.
2365 *
2366 * @since 4.1
2367 */
2368 do_action( 'mainwp_tools_form_top' );
2369
2370 $show_qsw = apply_filters( 'mainwp_show_qsw', true );
2371
2372 static::get_instance()->render_select_custom_themes();
2373
2374 ?>
2375 <?php if ( get_option( 'mainwp_not_start_encrypt_keys' ) ) { ?>
2376 <div class="ui grid field">
2377 <label class="six wide column middle aligned"><?php esc_html_e( 'OpenSSL Key Encryption', 'mainwp' ); ?></label>
2378 <div class="ten wide column" data-tooltip="<?php esc_attr_e( 'To enhance security, we\'ve added a feature to encrypt your private keys stored in the database.', 'mainwp' ); ?>" data-inverted="" data-position="top left">
2379 <input type="button" name="" id="increase-connection-security-btn" data-inverted="" data-position="top right" data-tooltip="<?php esc_attr_e( 'To enhance security, we\'ve added a feature to encrypt your private keys stored in the database.', 'mainwp' ); ?>" class="ui green basic button" value="<?php esc_attr_e( 'Encrypt Keys Now', 'mainwp' ); ?>" />
2380 </div>
2381 </div>
2382 <?php } ?>
2383 <div class="ui grid field">
2384 <label class="six wide column middle aligned"><?php esc_html_e( 'Force your MainWP Dashboard to establish a new connection', 'mainwp' ); ?></label>
2385 <div class="ten wide column" data-tooltip="<?php esc_attr_e( 'Force your MainWP Dashboard to reconnect with your child sites. Only needed if suggested by MainWP Support.', 'mainwp' ); ?>" data-inverted="" data-position="top left">
2386 <input type="button" name="" id="force-destroy-sessions-button" data-inverted="" data-position="top right" data-tooltip="<?php esc_attr_e( 'Forces your dashboard to reconnect with your child sites. This feature will log out any currently logged in users on the Child sites and require them to re-log in. Only needed if suggested by MainWP Support.', 'mainwp' ); ?>" class="ui green basic button" value="<?php esc_attr_e( 'Re-establish Connections', 'mainwp' ); ?>" />
2387 </div>
2388 </div>
2389 <div class="ui grid field">
2390 <label class="six wide column middle aligned"><?php esc_html_e( 'Force your MainWP Dashboard to set a new pair of OpenSSL Keys', 'mainwp' ); ?></label>
2391 <div class="ten wide column" id="mainwp-renew-connections-tool" data-content="<?php esc_attr_e( 'This will function renew connection and reconnect site right away.', 'mainwp' ); ?>" data-variation="inverted" data-position="top left">
2392 <a href="javascript:void(0)" onclick="mainwp_tool_renew_connections_show(); return false;" class="ui button green basic"><?php esc_html_e( 'Reset OpenSSL Key Pair', 'mainwp' ); ?></a>
2393 </div>
2394 </div>
2395 <?php if ( $show_qsw ) { ?>
2396 <div class="ui grid field">
2397 <label class="six wide column middle aligned"><?php esc_html_e( 'Start the MainWP Quick Setup Wizard', 'mainwp' ); ?></label>
2398 <div class="ten wide column" data-tooltip="<?php esc_attr_e( 'Click this button to start the Quick Setup Wizard', 'mainwp' ); ?>" data-inverted="" data-position="top left"><a href="admin.php?page=mainwp-setup" class="ui green button basic" ><?php esc_html_e( 'Start Quick Setup Wizard', 'mainwp' ); ?></a></div>
2399 </div>
2400 <?php } ?>
2401 <div class="ui grid field">
2402 <label class="six wide column middle aligned"><?php esc_html_e( 'Export child sites to CSV file', 'mainwp' ); ?></label>
2403 <div class="ten wide column" data-tooltip="<?php esc_attr_e( 'Click this button to export all connected sites to a CSV file.', 'mainwp' ); ?>" data-inverted="" data-position="top left"><a href="admin.php?page=MainWPTools&doExportSites=yes&_wpnonce=<?php echo esc_attr( wp_create_nonce( 'export_sites' ) ); ?>" class="ui button green basic"><?php esc_html_e( 'Export Child Sites', 'mainwp' ); ?></a></div>
2404 </div>
2405 <div class="ui grid field">
2406 <label class="six wide column middle aligned"><?php esc_html_e( 'Import child sites', 'mainwp' ); ?></label>
2407 <div class="ten wide column" data-tooltip="<?php esc_attr_e( 'Click this button to import websites to your MainWP Dashboard.', 'mainwp' ); ?>" data-inverted="" data-position="top left"><a href="admin.php?page=managesites&do=bulknew" class="ui button green basic"><?php esc_html_e( 'Import Child Sites', 'mainwp' ); ?></a></div>
2408 </div>
2409 <div class="ui grid field">
2410 <label class="six wide column middle aligned"><?php esc_html_e( 'Disconnect all child sites', 'mainwp' ); ?></label>
2411 <div class="ten wide column" id="mainwp-disconnect-sites-tool" data-content="<?php esc_attr_e( 'This will function will break the connection and leave the MainWP Child plugin active and which makes your sites vulnerable. Use only if you attend to reconnect site to the same or a different dashboard right away.', 'mainwp' ); ?>" data-variation="inverted" data-position="top left">
2412 <a href="admin.php?page=MainWPTools&disconnectSites=yes&_wpnonce=<?php echo esc_attr( wp_create_nonce( 'disconnect_sites' ) ); ?>" onclick="mainwp_tool_disconnect_sites(); return false;" class="ui button green basic"><?php esc_html_e( 'Disconnect Sites', 'mainwp' ); ?></a>
2413 </div>
2414 </div>
2415 <div class="ui grid field">
2416 <label class="six wide column middle aligned"><?php esc_html_e( 'Delete add-ons API Activation data', 'mainwp' ); ?></label>
2417 <div class="ten wide column" id="mainwp-clear-activation-data" data-content="<?php esc_attr_e( 'This does not affect extensions settings, it just removes API activation data.', 'mainwp' ); ?>" data-variation="inverted" data-position="top left">
2418 <a href="admin.php?page=MainWPTools&clearActivationData=yes&_wpnonce=<?php echo esc_attr( wp_create_nonce( 'clear_activation_data' ) ); ?>" onclick="mainwp_tool_confirm_to_process(this); return false;" class="ui button green basic"><?php esc_html_e( 'Delete Add-ons API Activation Data', 'mainwp' ); ?></a>
2419 </div>
2420 </div>
2421 <div class="ui grid field">
2422 <label class="six wide column middle aligned"><?php esc_html_e( 'Delete archived Network Activity data', 'mainwp' ); ?></label>
2423 <div class="ten wide column" id="mainwp-clear-archived-sites-changes-data" data-content="<?php esc_attr_e( 'Delete archived sNetwork Activity data.', 'mainwp' ); ?>" data-variation="inverted" data-position="top left">
2424 <a href="admin.php?page=MainWPTools&clearArchivedSitesChangesData=yes&_wpnonce=<?php echo esc_attr( wp_create_nonce( 'clear_archived_sites_changes' ) ); ?>" onclick="mainwp_tool_confirm_to_process(this); return false;" class="ui button green basic"><?php esc_html_e( 'Delete Archived Network Activity Data', 'mainwp' ); ?></a>
2425 </div>
2426 </div>
2427 <div class="ui grid field">
2428 <label class="six wide column middle aligned"><?php esc_html_e( 'Restore all info messages', 'mainwp' ); ?></label>
2429 <div class="ten wide column" data-tooltip="<?php esc_attr_e( 'Click this button to restore all info messages in your MainWP Dashboard and Extensions.', 'mainwp' ); ?>" data-inverted="" data-position="top left">
2430 <input type="submit" name="mainwp_restore_info_messages" id="mainwp_restore_info_messages" class="ui button" value="<?php esc_attr_e( 'Restore Info Messages', 'mainwp' ); ?>"/>
2431 </div>
2432 </div>
2433
2434 <h3 class="ui dividing header">
2435 <?php esc_html_e( 'Privacy & Third-Party Services Permissions', 'mainwp' ); ?>
2436 <div class="sub header"><?php esc_html_e( 'These tools are implemented using JavaScript and are subject to their respective privacy policies. You can choose which services to enable below, and update preferences at any time.', 'mainwp' ); ?></div>
2437 </h3>
2438
2439 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-tools">
2440 <label class="six wide column middle aligned">
2441 <?php
2442 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_enable_guided_tours', (int) get_option( 'mainwp_enable_guided_tours', 0 ) );
2443 esc_html_e( 'Usetiful (Interactive Guides & Tips)', 'mainwp' );
2444 ?>
2445 <span class="ui blue mini label"><?php esc_html_e( 'BETA', 'mainwp' ); ?></span>
2446 </label>
2447 <div class="ten wide column " data-tooltip="<?php esc_attr_e( 'Check this option to enable, or uncheck to disable MainWP guided tours.', 'mainwp' ); ?>" data-inverted="" data-position="bottom left">
2448 <div class="ui toggle checkbox">
2449 <input type="checkbox" class="settings-field-value-change-handler" name="mainwp-guided-tours-option" id="mainwp-guided-tours-option" <?php echo 1 === (int) get_option( 'mainwp_enable_guided_tours', 0 ) ? 'checked="true"' : ''; ?> />
2450 <label><?php esc_html_e( 'Enable guided tours, tooltips, and onboarding assistance to help you navigate MainWP more efficiently.', 'mainwp' ); ?></label>
2451 </div>
2452 </div>
2453 </div>
2454
2455 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-tools">
2456 <label class="six wide column middle aligned">
2457 <?php
2458 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_enable_guided_chatbase', (int) get_option( 'mainwp_enable_guided_chatbase', 0 ) );
2459 esc_html_e( 'Chatbase (AI-Powered Chat Support)', 'mainwp' );
2460 ?>
2461 <span class="ui blue mini label"><?php esc_html_e( 'BETA', 'mainwp' ); ?></span>
2462 </label>
2463 <div class="ten wide column " data-tooltip="<?php esc_attr_e( 'Check this option to enable, or uncheck to disable MainWP AI drive support.', 'mainwp' ); ?>" data-inverted="" data-position="bottom left">
2464 <div class="ui toggle checkbox">
2465 <input type="checkbox" class="settings-field-value-change-handler" name="mainwp-guided-chatbase-option" id="mainwp-guided-chatbase-option" <?php echo 1 === (int) get_option( 'mainwp_enable_guided_chatbase', 0 ) ? 'checked="true"' : ''; ?> />
2466 <label><?php esc_html_e( 'Get AI-driven support within the MainWP Dashboard for quick answers to common questions.', 'mainwp' ); ?></label>
2467 </div>
2468 </div>
2469 </div>
2470
2471 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-tools">
2472 <label class="six wide column middle aligned">
2473 <?php
2474 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_enable_guided_video', (int) get_option( 'mainwp_enable_guided_video', 0 ) );
2475 esc_html_e( 'Youtube Embeds (Video Tutorials)', 'mainwp' );
2476 ?>
2477 </label>
2478 <div class="ten wide column " data-tooltip="<?php esc_attr_e( 'Check this option to enable, or uncheck to disable MainWP video tutorials.', 'mainwp' ); ?>" data-inverted="" data-position="bottom left">
2479 <div class="ui toggle checkbox">
2480 <input type="checkbox" class="settings-field-value-change-handler" name="mainwp-guided-video-option" id="mainwp-guided-video-option" <?php echo 1 === (int) get_option( 'mainwp_enable_guided_video', 0 ) ? 'checked="true"' : ''; ?> />
2481 <label><?php esc_html_e( 'Enable embedded YouTube video tutorials within MainWP for step-by-step guidance.', 'mainwp' ); ?></label>
2482 </div>
2483 </div>
2484 </div>
2485 <?php
2486 /**
2487 * Action: mainwp_tools_form_bottom
2488 *
2489 * Fires at the bottom of mainwp tools form.
2490 *
2491 * @since 4.1
2492 */
2493 do_action( 'mainwp_tools_form_bottom' );
2494 $el_id_sbm_btn_1 = 'submit';
2495 ?>
2496 <div class="ui divider"></div>
2497 <input type="submit" name="submit" id="<?php echo esc_attr( $el_id_sbm_btn_1 ); ?>" class="ui green big button" value="<?php esc_attr_e( 'Save Settings', 'mainwp' ); ?>"/>
2498 </form>
2499 </div>
2500 </div>
2501 <script type="text/javascript">
2502 jQuery( '#mainwp-disconnect-sites-tool' ).popup();
2503 jQuery( '#mainwp-clear-activation-data' ).popup();
2504 </script>
2505 <?php
2506 static::render_footer( 'MainWPTools' );
2507 MainWP_Connect_Helper::render_renew_connections_modal();
2508 }
2509
2510 /**
2511 * Method is_basic_auth_dashboard_enabled.
2512 *
2513 * @return bool true|false.
2514 */
2515 public static function is_basic_auth_dashboard_enabled() { // phpcs:ignore -- NOSONAR - complex.
2516 $response = wp_remote_get( get_site_url() . '/wp-json' );
2517 $code = wp_remote_retrieve_response_code( $response );
2518 if ( 404 === (int) $code || 401 === (int) $code ) {
2519 return true;
2520 }
2521 return false;
2522 }
2523
2524
2525 /**
2526 * Render MainWP themes selection.
2527 */
2528 public function render_select_custom_themes() { // phpcs:ignore -- NOSONAR - complex.
2529 $custom_theme = $this->get_current_user_theme();
2530 if ( false === $custom_theme ) {
2531 // to compatible with Custom Dashboard extension settings.
2532 $compat_settings = get_option( 'mainwp_custom_dashboard_settings' );
2533 if ( is_array( $compat_settings ) && isset( $compat_settings['theme'] ) ) {
2534 $compat_theme = $compat_settings['theme'];
2535 }
2536 if ( null !== $compat_theme ) {
2537 $custom_theme = $compat_theme;
2538 }
2539 }
2540 $themes_files = static::get_instance()->get_custom_themes_files();
2541 if ( empty( $themes_files ) ) {
2542 $themes_files = array();
2543 }
2544 ?>
2545 <div class="ui grid field settings-field-indicator-wrapper settings-field-indicator-tools" default-indi-value="default">
2546 <label class="six wide column middle aligned">
2547 <?php
2548 MainWP_Settings_Indicator::render_not_default_indicator( 'mainwp_selected_theme', $custom_theme );
2549 esc_html_e( 'Select MainWP Dashboard theme', 'mainwp' );
2550 ?>
2551 </label>
2552 <div class="ten wide column" tabindex="0" data-tooltip="<?php esc_attr_e( 'Select your MainWP Dashboard theme.', 'mainwp' ); ?>" data-inverted="" data-position="top left">
2553 <select name="mainwp_settings_custom_theme" id="mainwp_settings_custom_theme" class="ui dropdown selection settings-field-value-change-handler">
2554 <option value="default" <?php echo ( 'default' === $custom_theme || empty( $custom_theme ) ) ? 'selected' : ''; ?>><?php esc_html_e( 'Light', 'mainwp' ); ?></option>
2555 <option value="default-dark" <?php echo ( 'default-dark' === $custom_theme || empty( $custom_theme ) ) ? 'selected' : ''; ?>><?php esc_html_e( 'Dark', 'mainwp' ); ?></option>
2556 <?php if ( 'default-2024' === $custom_theme ) { ?>
2557 <option value="default-2024" <?php echo ( 'default-2024' === $custom_theme ) ? 'selected' : ''; ?>><?php esc_html_e( 'Default 2024', 'mainwp' ); ?></option>
2558 <?php } ?>
2559 <?php if ( 'dark' === $custom_theme ) { ?>
2560 <option value="dark" <?php echo ( 'dark' === $custom_theme ) ? 'selected' : ''; ?>><?php esc_html_e( 'Dark 2024', 'mainwp' ); ?></option>
2561 <?php } ?>
2562 <?php if ( 'classic' === $custom_theme ) { ?>
2563 <option value="classic" <?php echo ( 'classic' === $custom_theme ) ? 'selected' : ''; ?>><?php esc_html_e( 'Classic (Legacy)', 'mainwp' ); ?></option>
2564 <?php } ?>
2565 <?php if ( 'wpadmin' === $custom_theme ) { ?>
2566 <option value="wpadmin" <?php echo ( 'wpadmin' === $custom_theme ) ? 'selected' : ''; ?>><?php esc_html_e( 'WP Admin (Legacy)', 'mainwp' ); ?></option>
2567 <?php } ?>
2568 <?php if ( 'minimalistic' === $custom_theme ) { ?>
2569 <option value="minimalistic" <?php echo ( 'minimalistic' === $custom_theme ) ? 'selected' : ''; ?>><?php esc_html_e( 'Minimalistic (Legacy)', 'mainwp' ); ?></option>
2570 <?php } ?>
2571 <?php
2572 foreach ( $themes_files as $file_name => $theme ) {
2573 $theme = ucfirst( $theme );
2574 $_select = '';
2575 if ( $custom_theme === $file_name ) {
2576 $_select = 'selected';
2577 }
2578 echo '<option value="' . esc_attr( $file_name ) . '" ' . esc_attr( $_select ) . '>' . esc_html( $theme ) . '</option>';
2579 }
2580 ?>
2581 </select>
2582 </div>
2583 </div>
2584 <?php
2585 }
2586
2587 /**
2588 * Get custom themes files.
2589 */
2590 public function get_custom_themes_files() {
2591 // get themes files.
2592 $dirs = $this->get_custom_theme_folder();
2593 $scan_dir = $dirs[0];
2594 $handle = opendir( $scan_dir );
2595 $themes = array();
2596 if ( $handle ) {
2597 $filename = readdir( $handle );
2598 while ( false !== $filename ) {
2599 $correct_file = true;
2600 if ( '.' === substr( $filename, 0, 1 ) || 'index.php' === $filename || '.css' !== substr( $filename, - 4 ) ) {
2601 $correct_file = false;
2602 }
2603 if ( $correct_file ) {
2604 $theme = basename( $filename, '.css' );
2605 $theme = str_replace( '-theme', '', $theme );
2606 $themes[ $filename ] = trim( $theme );
2607 }
2608 $filename = readdir( $handle ); // to while loop.
2609 }
2610 closedir( $handle );
2611 }
2612 return $themes;
2613 }
2614
2615 /**
2616 * Get selected MainWP theme name.
2617 */
2618 public function get_selected_theme() {
2619 $selected_theme = false;
2620
2621 $custom_theme = $this->get_current_user_theme();
2622
2623 if ( false === $custom_theme ) {
2624 // to compatible with Custom Dashboard extension settings.
2625 $compat_settings = get_option( 'mainwp_custom_dashboard_settings' );
2626 if ( is_array( $compat_settings ) && isset( $compat_settings['theme'] ) ) {
2627 $compat_theme = $compat_settings['theme'];
2628 }
2629
2630 if ( null !== $compat_theme ) {
2631 $custom_theme = $compat_theme;
2632 }
2633 }
2634
2635 if ( ! empty( $custom_theme ) ) {
2636 if ( 'default' === $custom_theme || 'default-dark' === $custom_theme || 'default-2024' === $custom_theme || 'dark' === $custom_theme || 'wpadmin' === $custom_theme || 'minimalistic' === $custom_theme ) {
2637 return $custom_theme;
2638 }
2639 $dirs = $this->get_custom_theme_folder();
2640 $theme_dir = $dirs[0];
2641 $file = $theme_dir . $custom_theme;
2642 if ( file_exists( $file ) && '.css' === substr( $file, - 4 ) ) {
2643 $selected_theme = $custom_theme;
2644 }
2645 }
2646 return $selected_theme;
2647 }
2648
2649
2650 /**
2651 * Get custom MainWP theme folder.
2652 */
2653 public function get_custom_theme_folder() {
2654 $dirs = MainWP_System_Utility::get_mainwp_dir();
2655 global $wp_filesystem;
2656 if ( is_array( $dirs ) && ! $wp_filesystem->exists( $dirs[0] . 'themes' ) && $wp_filesystem->exists( $dirs[0] . 'custom-dashboard' ) ) {
2657 // re-name the custom-dashboard folder to compatible.
2658 $wp_filesystem->move( $dirs[0] . 'custom-dashboard', $dirs[0] . 'themes' );
2659 }
2660 return MainWP_System_Utility::get_mainwp_dir_allow_access( 'themes' );
2661 }
2662
2663
2664 /**
2665 * Get current user's selected theme.
2666 */
2667 public function get_current_user_theme() {
2668 $custom_theme = get_user_option( 'mainwp_selected_theme' );
2669 if ( empty( $custom_theme ) ) {
2670 $custom_theme = get_option( 'mainwp_selected_theme', 'default' );
2671 }
2672 return $custom_theme;
2673 }
2674
2675 /**
2676 * Export Child Sites and save as .csv file.
2677 *
2678 * @uses \MainWP\Dashboard\MainWP_DB::query()
2679 * @uses \MainWP\Dashboard\MainWP_DB::get_sql_websites_for_current_user()
2680 * @uses \MainWP\Dashboard\MainWP_DB::data_seek()
2681 * @uses \MainWP\Dashboard\MainWP_DB::fetch_object()
2682 * @uses \MainWP\Dashboard\MainWP_Utility::map_site()
2683 */
2684 public static function export_sites() {
2685 if ( isset( $_GET['doExportSites'] ) && isset( $_GET['_wpnonce'] ) && wp_verify_nonce( sanitize_key( $_GET['_wpnonce'] ), 'export_sites' ) ) {
2686
2687 $sql = MainWP_DB::instance()->get_sql_websites_for_current_user( true );
2688 $websites = MainWP_DB::instance()->query( $sql );
2689
2690 if ( ! $websites ) {
2691 die( 'Not found sites' );
2692 }
2693
2694 $keys = array( 'name', 'url', 'adminname', 'adminpasswd', 'wpgroups', 'uniqueId', 'http_user', 'http_pass', 'verify_certificate', 'ssl_version' );
2695 $allowedHeaders = array( 'site name', 'url', 'admin name', 'admin password', 'tag', 'security id', 'http username', 'http password', 'verify certificate', 'ssl version' );
2696 $csv = "#\r";
2697 $csv .= '# Your password is never stored by your Dashboard and never sent to MainWP.com. Once this initial connection is complete, your MainWP Dashboard generates a secure Public and Private key pair (2048 bits) using OpenSSL, allowing future connections without needing your password again. For added security, you can even change this admin password once connected, just be sure not to delete the admin account, as this would disrupt the connection.' . "\r";
2698 $csv .= "#\r";
2699 $csv .= implode( ',', $allowedHeaders ) . "\r";
2700 MainWP_DB::data_seek( $websites, 0 );
2701 while ( $websites && ( $website = MainWP_DB::fetch_object( $websites ) ) ) {
2702 if ( empty( $website ) ) {
2703 continue;
2704 }
2705 $row = MainWP_Utility::map_site( $website, $keys, false );
2706 // MWP-1548: decrypt http_user / http_pass before they hit
2707 // the CSV. The export file is meant for cross-install
2708 // transfer (admin re-imports on another dashboard); a
2709 // file_key envelope from this install would be unreadable
2710 // there. Plaintext on disk preserves today's portability
2711 // contract -- the export was already plaintext pre-fix,
2712 // and this hop neither widens nor narrows that exposure.
2713 if ( isset( $row['http_user'] ) ) {
2714 $row['http_user'] = MainWP_Credential_Storage::decrypt_credential( $row['http_user'] );
2715 }
2716 if ( isset( $row['http_pass'] ) ) {
2717 $row['http_pass'] = MainWP_Credential_Storage::decrypt_credential( $row['http_pass'] );
2718 }
2719
2720 $row = array_map(
2721 static function ( $value ) {
2722 return str_replace( '"', '""', (string) $value );
2723 },
2724 $row
2725 );
2726
2727 $csv .= '"' . implode( '","', $row ) . '"' . "\r";
2728 }
2729
2730 header( 'Content-Type: text/csv; charset=utf-8' );
2731 header( 'Content-Disposition: attachment; filename=export-sites.csv' );
2732 echo $csv; // phpcs:ignore WordPress.Security.EscapeOutput
2733 exit();
2734 }
2735 }
2736
2737 /**
2738 * Render MainWP Email Settings SubPage.
2739 *
2740 * @uses \MainWP\Dashboard\MainWP_Notification_Settings::get_notification_types()
2741 * @uses \MainWP\Dashboard\MainWP_Notification_Settings::render_edit_settings()
2742 * @uses \MainWP\Dashboard\MainWP_Notification_Settings::emails_general_settings_handle()
2743 * @uses \MainWP\Dashboard\MainWP_Notification_Settings::render_all_settings()
2744 * @uses \MainWP\Dashboard\MainWP_Notification_Template::handle_template_file_action()
2745 */
2746 public static function render_email_settings() {
2747 $notification_emails = MainWP_Notification_Settings::get_notification_types();
2748 static::render_header( 'Emails' );
2749 $edit_email = isset( $_GET['edit-email'] ) ? sanitize_text_field( wp_unslash( $_GET['edit-email'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
2750 if ( ! empty( $edit_email ) && isset( $notification_emails[ $edit_email ] ) ) {
2751 $updated_templ = MainWP_Notification_Template::instance()->handle_template_file_action();
2752 MainWP_Notification_Settings::instance()->render_edit_settings( $edit_email, $updated_templ );
2753 } else {
2754 $updated = MainWP_Notification_Settings::emails_general_settings_handle();
2755 MainWP_Notification_Settings::instance()->render_all_settings( $updated );
2756 }
2757 static::render_footer( 'Emails' );
2758 }
2759
2760 /**
2761 * Method mainwp_help_content()
2762 *
2763 * Creates the MainWP Help Documentation List for the help component in the sidebar.
2764 */
2765 public static function mainwp_help_content() {
2766 if ( isset( $_GET['page'] ) && ( 'Settings' === $_GET['page'] || 'SettingsAdvanced' === $_GET['page'] || 'MainWPTools' === $_GET['page'] || 'MonitoringSettings' === $_GET['page'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
2767 ?>
2768 <p><?php esc_html_e( 'If you need help with your MainWP Dashboard settings, please review following help documents', 'mainwp' ); ?></p>
2769 <div class="ui list">
2770 <div class="item"><i class="external alternate icon"></i> <a href="https://docs.mainwp.com/sites/management/mainwp-dashboard-settings#mainwp-dashboard-settings" target="_blank">MainWP Dashboard Settings</a></div>
2771 </div>
2772 <?php
2773 /**
2774 * Action: mainwp_settings_help_item
2775 *
2776 * Fires at the bottom of the help articles list in the Help sidebar on the Settings page.
2777 *
2778 * Suggested HTML markup:
2779 *
2780 * <div class="item"><a href="Your custom URL">Your custom text</a></div>
2781 *
2782 * @since 5.2
2783 */
2784 do_action( 'mainwp_settings_help_item' );
2785
2786 }
2787 }
2788
2789 /**
2790 * Method render_monitoring()
2791 *
2792 * Render Monitoring Settings.
2793 *
2794 * @uses \MainWP\Dashboard\MainWP_Monitoring_View::render_settings()
2795 */
2796 public static function render_monitoring() {
2797 if ( ! \mainwp_current_user_can( 'dashboard', 'manage_dashboard_settings' ) ) {
2798 \mainwp_do_not_have_permissions( esc_html__( 'manage dashboard settings', 'mainwp' ) );
2799 return;
2800 }
2801 static::render_header( 'Monitoring' );
2802 ?>
2803 <div id="mainwp-monitoring-settings" class="ui padded segment">
2804 <?php if ( isset( $_GET['message'] ) && 'saved' === sanitize_text_field( wp_unslash( $_GET['message'] ) ) ) : // phpcs:ignore WordPress.Security.NonceVerification.Recommended ?>
2805 <div class="ui green message"><i class="close icon"></i><?php esc_html_e( 'Monitoring settings have been saved successfully!', 'mainwp' ); ?></div>
2806 <?php endif; ?>
2807 <div class="ui form">
2808 <form method="POST" action="">
2809 <?php wp_nonce_field( 'mainwp-admin-nonce' ); ?>
2810 <input type="hidden" name="wp_nonce" value="<?php echo esc_attr( wp_create_nonce( 'MonitoringSettings' ) ); ?>" />
2811 <?php
2812 /**
2813 * Action: mainwp_monitoring_settings_form_top
2814 *
2815 * Fires at the top of monitoring settings form.
2816 *
2817 * @since 4.1
2818 */
2819 do_action( 'mainwp_monitoring_settings_form_top' );
2820 ?>
2821 <?php MainWP_Monitoring_View::render_settings(); ?>
2822 <?php
2823 /**
2824 * Action: mainwp_monitoring_form_bottom
2825 *
2826 * Fires at the bottom of mainwp monitoring form.
2827 *
2828 * @since 4.1
2829 */
2830 do_action( 'mainwp_monitoring_settings_form_bottom' );
2831 ?>
2832 <div class="ui divider"></div>
2833 <input type="submit" name="submit" id="submit-monitoring" class="ui green big button" value="<?php esc_attr_e( 'Save Settings', 'mainwp' ); ?>"/>
2834 </form>
2835 </div>
2836 </div>
2837 <?php
2838 static::render_footer( 'Monitoring' );
2839 }
2840 }
2841