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

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

1,376 lines 60.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * System Handler
4 *
5 * @package MainWP/Dashboard
6 */
7
8 namespace MainWP\Dashboard;
9
10 // Exit if accessed directly.
11 if ( ! defined( 'ABSPATH' ) ) {
12 exit;
13 }
14
15 /**
16 * Class MainWP_System_Handler
17 *
18 * @package MainWP\Dashboard
19 */
20 class MainWP_System_Handler { // phpcs:ignore Generic.Classes.OpeningBraceSameLine.ContentAfterBrace -- NOSONAR.
21
22 // phpcs:disable WordPress.WP.AlternativeFunctions -- use system functions
23
24 /**
25 * Private static variable to hold the single instance of the class.
26 *
27 * @static
28 *
29 * @var mixed Default null
30 */
31 private static $instance = null;
32
33 /**
34 * Private variable to hold the upgrade version info.
35 *
36 * @var \stdClass|null Version info.
37 */
38 private $upgradeVersionInfo = null;
39
40 /**
41 * Method instance()
42 *
43 * Create public static instance.
44 *
45 * @static
46 * @return MainWP_System
47 */
48 public static function instance() {
49 if ( null === static::$instance ) {
50 static::$instance = new self();
51 }
52
53 return static::$instance;
54 }
55
56 /**
57 * MainWP_System_Handler constructor.
58 *
59 * Run each time the class is called.
60 *
61 * @uses \MainWP\Dashboard\MainWP_Extensions_Handler::get_class_name()
62 */
63 public function __construct() {
64 add_filter( 'mainwp-extension-enabled-check', array( MainWP_Extensions_Handler::get_class_name(), 'is_extension_enabled' ) ); // @deprecated Use 'mainwp_extension_enabled_check' instead.
65 add_filter( 'mainwp_extension_enabled_check', array( MainWP_Extensions_Handler::get_class_name(), 'is_extension_enabled' ) );
66
67 /**
68 * This hook allows you to get a list of sites via the 'mainwp-getsites' filter.
69 *
70 * @link http://codex.mainwp.com/#mainwp-getsites
71 *
72 * @see \MainWP_Extensions::hook_get_sites
73 */
74 add_filter( 'mainwp-getsites', array( MainWP_Extensions_Handler::get_class_name(), 'hook_get_sites' ), 10, 5 ); // @deprecated Use 'mainwp_getsites' instead.
75 add_filter( 'mainwp-getdbsites', array( MainWP_Extensions_Handler::get_class_name(), 'hook_get_db_sites' ), 10, 6 ); // @deprecated Use 'mainwp_getdbsites' instead.
76
77 add_filter( 'mainwp_getsites', array( MainWP_Extensions_Handler::get_class_name(), 'hook_get_sites' ), 10, 5 );
78 add_filter( 'mainwp_getdbsites', array( MainWP_Extensions_Handler::get_class_name(), 'hook_get_db_sites' ), 10, 6 );
79 add_filter( 'mainwp_get_db_websites', array( MainWP_Extensions_Handler::get_class_name(), 'hook_get_db_websites' ), 10, 5 );
80
81 /**
82 * This hook allows you to get a information about groups via the 'mainwp-getgroups' filter.
83 *
84 * @link http://codex.mainwp.com/#mainwp-getgroups
85 *
86 * @see \MainWP_Extensions::hook_get_groups
87 */
88 add_filter( 'mainwp-getgroups', array( MainWP_Extensions_Handler::get_class_name(), 'hook_get_groups' ), 10, 4 ); // @deprecated Use 'mainwp_getgroups' instead.
89 add_filter( 'mainwp_getgroups', array( MainWP_Extensions_Handler::get_class_name(), 'hook_get_groups' ), 10, 4 );
90 add_action( 'mainwp_fetchurlsauthed', array( &$this, 'filter_fetch_urls_authed' ), 10, 7 );
91 add_filter( 'mainwp_fetchurlauthed', array( &$this, 'filter_fetch_url_authed' ), 10, 6 );
92 add_filter( 'mainwp_getsqlwebsites_for_current_user', array( static::class, 'hook_get_sql_websites_for_current_user' ), 10, 4 );
93 add_filter( 'mainwp_fetchurlverifyaction', array( &$this, 'hook_fetch_url_verify_action' ), 10, 4 );
94
95 add_filter(
96 'mainwp_getdashboardsites',
97 array(
98 MainWP_Extensions_Handler::get_class_name(),
99 'hook_get_dashboard_sites',
100 ),
101 10,
102 7
103 );
104
105 // @deprecated Use 'mainwp_manager_getextensions' instead.
106 add_filter(
107 'mainwp-manager-getextensions',
108 array(
109 MainWP_Extensions_Handler::get_class_name(),
110 'hook_get_all_extensions',
111 )
112 );
113
114 add_filter(
115 'mainwp_manager_getextensions',
116 array(
117 MainWP_Extensions_Handler::get_class_name(),
118 'hook_get_all_extensions',
119 )
120 );
121
122 add_action( 'admin_init', array( &$this, 'admin_init' ) );
123
124 if ( false !== get_option( 'mainwp_upgradeVersionInfo' ) && '' !== get_option( 'mainwp_upgradeVersionInfo' ) ) {
125 $this->upgradeVersionInfo = get_option( 'mainwp_upgradeVersionInfo' );
126 if ( ! is_object( $this->upgradeVersionInfo ) ) {
127 $this->upgradeVersionInfo = new \stdClass();
128 }
129 }
130 }
131
132 /**
133 * Method filter_fetch_urls_authed()
134 *
135 * Filter fetch authorized urls.
136 *
137 * @param mixed $pluginFile MainWP extention.
138 * @param string $key MainWP Licence Key.
139 * @param object $dbwebsites Child Sites.
140 * @param string $what Function to perform.
141 * @param array $params Function paramerters.
142 * @param mixed $handle Function handle.
143 * @param mixed $output Function output.
144 *
145 * @return mixed MainWP_Extensions_Handler::hook_fetch_urls_authed() Hook fetch authorized URLs.
146 *
147 * @uses \MainWP\Dashboard\MainWP_Extensions_Handler::hook_fetch_urls_authed()
148 */
149 public function filter_fetch_urls_authed( $pluginFile, $key, $dbwebsites, $what, $params, $handle, $output ) {
150 return MainWP_Extensions_Handler::hook_fetch_urls_authed( $pluginFile, $key, $dbwebsites, $what, $params, $handle, $output );
151 }
152
153 /**
154 * Method filter_fetch_url_authed()
155 *
156 * Filter fetch Authorized URL.
157 *
158 * @param mixed $pluginFile MainWP extention.
159 * @param string $key MainWP licence key.
160 * @param int $websiteId Website ID.
161 * @param string $what Function to perform.
162 * @param array $params Function paramerters.
163 * @param null $raw_response Raw response.
164 *
165 * @return mixed MainWP_Extensions_Handler::hook_fetch_url_authed() Hook fetch authorized URL.
166 *
167 * @uses \MainWP\Dashboard\MainWP_Extensions_Handler::hook_fetch_url_authed()
168 */
169 public function filter_fetch_url_authed( $pluginFile, $key, $websiteId, $what, $params, $raw_response = null ) {
170 return MainWP_Extensions_Handler::hook_fetch_url_authed( $pluginFile, $key, $websiteId, $what, $params, $raw_response );
171 }
172
173 /**
174 * Method hook_fetch_url_verify_action()
175 *
176 * Filter fetch Authorized URL.
177 *
178 * @param mixed $pluginFile MainWP extention.
179 * @param string $childKey Extension child key.
180 * @param int $websiteId Website ID.
181 * @param array $params Function paramerters.
182 *
183 * @return mixed MainWP_Extensions_Handler::hook_fetch_url_authed() Hook fetch authorized URL.
184 */
185 public function hook_fetch_url_verify_action( $pluginFile, $childKey, $websiteId, $params ) {
186 if ( ! is_array( $params ) || ! isset( $params['actionnonce'] ) ) {
187 return false;
188 }
189 $what = 'verify_action';
190 return MainWP_Extensions_Handler::hook_fetch_url_authed( $pluginFile, $childKey, $websiteId, $what, $params );
191 }
192
193 /**
194 * Method apply_filter()
195 *
196 * Apply filter
197 *
198 * @param string $filter The filter.
199 * @param array $value Input value.
200 *
201 * @return array $output Output array.
202 *
203 * @uses \MainWP\Dashboard\MainWP_Extensions_Handler::hook_verify()
204 */
205 public function apply_filters( $filter, $value = array() ) {
206
207 if ( 'mainwp-getmetaboxes' === $filter ) {
208 $output = apply_filters_deprecated( 'mainwp-getmetaboxes', array( $value ), '4.0.7.2', 'mainwp_getmetaboxes' ); // @deprecated Use 'mainwp_getmetaboxes' instead. NOSONAR - not IP.
209 } else {
210 $output = apply_filters( $filter, $value );
211 }
212
213 if ( ! is_array( $output ) ) {
214 return array();
215 }
216 return $output;
217 }
218
219 /**
220 * Method admin_init()
221 *
222 * Do nothing if current user is not an Admin.
223 */
224 public function admin_init() { // phpcs:ignore -- NOSONAR - complex function.
225 if ( ! MainWP_System_Utility::is_admin() ) {
226 return;
227 }
228
229 $this->handle_quick_theme_change();
230
231 global $pagenow;
232
233 if ( 'plugins.php' === $pagenow && isset( $_GET['do'] ) && 'checkUpgrade' === $_GET['do'] && ( ( time() - $this->upgradeVersionInfo->updated ) > 30 ) ) { // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
234 $this->check_upgrade();
235 delete_site_transient( 'update_plugins' ); // to forced refresh 'update_plugins' transient.
236 wp_safe_redirect( admin_url( 'plugins.php' ) );
237 exit;
238 }
239 }
240
241 /**
242 * Method hook_get_sql_websites_for_current_user()
243 *
244 * Get sql websites for current user.
245 *
246 * @param mixed $input_value First input filter value.
247 * @param string $pluginFile Extension plugin file to verify.
248 * @param string $key The child-key.
249 * @param mixed $params Input params data.
250 *
251 * @return string sql.
252 */
253 public static function hook_get_sql_websites_for_current_user( $input_value, $pluginFile, $key, $params ) {
254 unset( $input_value );
255 if ( ! MainWP_Extensions_Handler::hook_verify( $pluginFile, $key ) ) {
256 return false;
257 }
258
259 // Prevent conflicts in wp_options query conditions.
260 // If use_join_wp_options is not enabled,
261 // force the use of a compatible subquery approach to ensure the query remains correct.
262 if ( is_array( $params ) && empty( $params['use_join_wp_options'] ) ) {
263 $params['use_compatible_subquery'] = 1;
264 }
265
266 return MainWP_DB::instance()->get_sql_wp_for_current_user( $params );
267 }
268 /**
269 * Method handle_manage_sites_screen_settings()
270 *
271 * Handle manage sites screen settings
272 */
273 public function handle_manage_sites_screen_settings() { // phpcs:ignore -- NOSONAR - required to achieve desired results, pull request solutions appreciated.
274 if ( isset( $_POST['wp_nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['wp_nonce'] ), 'ManageSitesScrOptions' ) ) {
275 $show_cols = array();
276 foreach ( array_map( 'sanitize_text_field', wp_unslash( $_POST ) ) as $key => $val ) {
277 if ( false !== strpos( $key, 'mainwp_show_column_' ) ) {
278 $col = str_replace( 'mainwp_show_column_', '', $key );
279 $show_cols[ $col ] = 1;
280 }
281 }
282 if ( isset( $_POST['show_columns_name'] ) ) {
283 foreach ( array_map( 'sanitize_text_field', wp_unslash( $_POST['show_columns_name'] ) ) as $col ) {
284 if ( ! isset( $show_cols[ $col ] ) ) {
285 $show_cols[ $col ] = 0; // uncheck, hide columns.
286 }
287 }
288 }
289 MainWP_Utility::update_option( 'mainwp_use_favicon', 1 );
290 MainWP_Utility::update_option( 'mainwp_optimize', ( ! isset( $_POST['mainwp_optimize'] ) ? 0 : 1 ) );
291 $user = wp_get_current_user();
292 if ( $user ) {
293 $val = ( isset( $_POST['mainwp_sitesviewmode'] ) ? sanitize_text_field( wp_unslash( $_POST['mainwp_sitesviewmode'] ) ) : 'grid' );
294 if ( 'grid' !== $val && 'table' !== $val ) {
295 $val = 'grid';
296 }
297 update_user_option( $user->ID, 'mainwp_sitesviewmode', $val, true );
298 update_user_option( $user->ID, 'mainwp_settings_show_manage_sites_columns', $show_cols, true );
299 update_option( 'mainwp_default_sites_per_page', ( isset( $_POST['mainwp_default_sites_per_page'] ) ? intval( $_POST['mainwp_default_sites_per_page'] ) : 25 ) );
300 }
301 } elseif ( isset( $_POST['wp_nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['wp_nonce'] ), 'SreenshotsSitesScrOptions' ) ) {
302 $user = wp_get_current_user();
303 if ( $user ) {
304 $val = ( isset( $_POST['mainwp_sitesviewmode'] ) ? sanitize_text_field( wp_unslash( $_POST['mainwp_sitesviewmode'] ) ) : 'grid' );
305 if ( 'grid' !== $val && 'table' !== $val ) {
306 $val = 'grid';
307 }
308 update_user_option( $user->ID, 'mainwp_sitesviewmode', $val, true );
309 }
310 }
311 }
312
313 /**
314 * Method handle_monitoring_sites_screen_settings()
315 *
316 * Handle monitoring sites screen settings
317 */
318 public function handle_monitoring_sites_screen_settings() { // phpcs:ignore -- NOSONAR - complex.
319 if ( isset( $_POST['wp_nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['wp_nonce'] ), 'MonitoringSitesScrOptions' ) ) {
320 $show_cols = array();
321 foreach ( array_map( 'sanitize_text_field', wp_unslash( $_POST ) ) as $key => $val ) {
322 if ( false !== strpos( $key, 'mainwp_show_column_' ) ) {
323 $col = str_replace( 'mainwp_show_column_', '', $key );
324 $show_cols[ $col ] = 1;
325 }
326 }
327 if ( isset( $_POST['show_columns_name'] ) ) {
328 foreach ( array_map( 'sanitize_text_field', wp_unslash( $_POST['show_columns_name'] ) ) as $col ) {
329 if ( ! isset( $show_cols[ $col ] ) ) {
330 $show_cols[ $col ] = 0; // uncheck, hide columns.
331 }
332 }
333 }
334
335 $user = wp_get_current_user();
336 if ( $user ) {
337 update_user_option( $user->ID, 'mainwp_settings_show_monitoring_sites_columns', $show_cols, true );
338 update_option( 'mainwp_default_monitoring_sites_per_page', ( isset( $_POST['mainwp_default_monitoring_sites_per_page'] ) ? intval( $_POST['mainwp_default_monitoring_sites_per_page'] ) : 25 ) );
339 }
340
341 update_option( 'mainwp_disableSitesHealthMonitoring', ( ! isset( $_POST['mainwp_disable_sitesHealthMonitoring'] ) ? 1 : 0 ) );
342
343 $val = isset( $_POST['mainwp_site_healthThreshold'] ) ? intval( $_POST['mainwp_site_healthThreshold'] ) : 80;
344 update_option( 'mainwp_sitehealthThreshold', $val );
345 }
346 }
347
348 /**
349 * Method handle_clients_screen_settings()
350 *
351 * Handle manage clients screen settings
352 */
353 public function handle_clients_screen_settings() { // phpcs:ignore -- NOSONAR - complex.
354 if ( isset( $_POST['wp_nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['wp_nonce'] ), 'ManageClientsScrOptions' ) ) {
355 $show_cols = array();
356 foreach ( array_map( 'sanitize_text_field', wp_unslash( $_POST ) ) as $key => $val ) {
357 if ( false !== strpos( $key, 'mainwp_show_column_' ) ) {
358 $col = str_replace( 'mainwp_show_column_', '', $key );
359 $show_cols[ $col ] = 1;
360 }
361 }
362 if ( isset( $_POST['show_columns_name'] ) ) {
363 foreach ( array_map( 'sanitize_text_field', wp_unslash( $_POST['show_columns_name'] ) ) as $col ) {
364 if ( ! isset( $show_cols[ $col ] ) ) {
365 $show_cols[ $col ] = 0; // uncheck, hide columns.
366 }
367 }
368 }
369
370 $user = wp_get_current_user();
371 if ( $user ) {
372 update_user_option( $user->ID, 'mainwp_settings_show_manage_clients_columns', $show_cols, true );
373 update_option( 'mainwp_default_manage_clients_per_page', ( isset( $_POST['mainwp_default_manage_clients_per_page'] ) ? intval( $_POST['mainwp_default_manage_clients_per_page'] ) : 25 ) );
374 }
375 }
376 }
377
378 /**
379 * Method handle_insights_events_screen_settings()
380 *
381 * Handle manage insights events screen settings
382 */
383 public function handle_insights_events_screen_settings() { // phpcs:ignore -- NOSONAR - complex.
384 if ( isset( $_POST['wp_nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['wp_nonce'] ), 'ManageEventsScrOptions' ) ) {
385 $show_cols = array();
386 foreach ( array_map( 'sanitize_text_field', wp_unslash( $_POST ) ) as $key => $val ) {
387 if ( false !== strpos( $key, 'mainwp_show_column_' ) ) {
388 $col = str_replace( 'mainwp_show_column_', '', $key );
389 $show_cols[ $col ] = 1;
390 }
391 }
392 if ( isset( $_POST['show_columns_name'] ) ) {
393 foreach ( array_map( 'sanitize_text_field', wp_unslash( $_POST['show_columns_name'] ) ) as $col ) {
394 if ( ! isset( $show_cols[ $col ] ) ) {
395 $show_cols[ $col ] = 0; // uncheck, hide columns.
396 }
397 }
398 }
399
400 $user = wp_get_current_user();
401 if ( $user ) {
402 update_user_option( $user->ID, 'mainwp_settings_show_insights_events_columns', $show_cols, true );
403 update_option( 'mainwp_default_manage_insights_events_per_page', ( isset( $_POST['mainwp_default_sites_per_page'] ) ? intval( $_POST['mainwp_default_sites_per_page'] ) : 25 ) );
404 }
405 wp_safe_redirect( admin_url( 'admin.php?page=InsightsManage&message=savedscreenopts' ) );
406 exit();
407 }
408 }
409
410 /**
411 * Method handle_clients_screen_settings()
412 *
413 * Handle manage clients screen settings
414 */
415 public function handle_updates_screen_settings() { //phpcs:ignore -- NOSONAR - complex.
416 if ( isset( $_POST['wp_nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['wp_nonce'] ), 'UpdatesScrOptions' ) ) {
417 $val = ( ! isset( $_POST['mainwp_pluginAutomaticDailyUpdate'] ) ? 0 : intval( $_POST['mainwp_pluginAutomaticDailyUpdate'] ) );
418 MainWP_Utility::update_option( 'mainwp_pluginAutomaticDailyUpdate', $val );
419 $val = ( ! isset( $_POST['mainwp_themeAutomaticDailyUpdate'] ) ? 0 : intval( $_POST['mainwp_themeAutomaticDailyUpdate'] ) );
420 MainWP_Utility::update_option( 'mainwp_themeAutomaticDailyUpdate', $val );
421 $val = ( ! isset( $_POST['mainwp_transAutomaticDailyUpdate'] ) ? 0 : intval( $_POST['mainwp_transAutomaticDailyUpdate'] ) );
422 MainWP_Utility::update_option( 'mainwp_transAutomaticDailyUpdate', $val );
423 $val = ( ! isset( $_POST['mainwp_automaticDailyUpdate'] ) ? 0 : intval( $_POST['mainwp_automaticDailyUpdate'] ) );
424 MainWP_Utility::update_option( 'mainwp_automaticDailyUpdate', $val );
425 $val = ( isset( $_POST['mainwp_delay_autoupdate'] ) ? intval( $_POST['mainwp_delay_autoupdate'] ) : 1 );
426 MainWP_Utility::update_option( 'mainwp_delay_autoupdate', $val );
427 $val = ( ! isset( $_POST['mainwp_show_language_updates'] ) ? 0 : 1 );
428 MainWP_Utility::update_option( 'mainwp_show_language_updates', $val );
429 $val = ( ! isset( $_POST['mainwp_disable_update_confirmations'] ) ? 0 : intval( $_POST['mainwp_disable_update_confirmations'] ) );
430 MainWP_Utility::update_option( 'mainwp_disable_update_confirmations', $val );
431 }
432 }
433
434 /**
435 * Method handle_quick_theme_change()
436 *
437 * Handle quick theme switching via URL parameter.
438 */
439 public function handle_quick_theme_change() {
440 if ( ! isset( $_GET['mainwp_quick_theme_change'] ) || ! isset( $_GET['_wpnonce'] ) ) {
441 return;
442 }
443
444 if ( ! wp_verify_nonce( sanitize_key( $_GET['_wpnonce'] ), 'mainwp_quick_theme_change' ) ) {
445 wp_die( esc_html__( 'Security check failed', 'mainwp' ) );
446 }
447
448 $user = wp_get_current_user();
449
450 if ( ! $user || ! $user->ID || $user->ID <= 0 ) {
451 wp_die( esc_html__( 'Authentication required', 'mainwp' ) );
452 }
453
454 $theme = sanitize_text_field( wp_unslash( $_GET['mainwp_quick_theme_change'] ) );
455
456 $allowed_themes = array( 'default', 'default-dark' );
457 if ( ! in_array( $theme, $allowed_themes, true ) ) {
458 wp_die( esc_html__( 'Invalid theme selection', 'mainwp' ) );
459 }
460
461 update_user_option( $user->ID, 'mainwp_selected_theme', $theme );
462 set_transient( 'mainwp_settings_saved', 1, 30 );
463
464 $redirect_url = remove_query_arg( array( 'mainwp_quick_theme_change', '_wpnonce' ) );
465 wp_safe_redirect( $redirect_url );
466 exit;
467 }
468
469 /**
470 * Method handle_mainwp_tools_settings()
471 *
472 * Handle mainwp tools settings.
473 *
474 * @uses \MainWP\Dashboard\MainWP_Twitter::clear_all_twitter_messages()
475 * @uses \MainWP\Dashboard\MainWP_Utility::update_option()
476 */
477 public function handle_mainwp_tools_settings() { // phpcs:ignore -- NOSONAR -Current complexity is the only way to achieve desired results, pull request solutions appreciated.
478
479 $user = wp_get_current_user();
480
481 $update_selected_mainwp_themes = false;
482 $should_redirect = false; // Redirect status.
483
484 if ( isset( $_GET['page'] ) && 'MainWPTools' === $_GET['page'] && isset( $_POST['wp_nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['wp_nonce'] ), 'MainWPTools' ) ) {
485
486 $old_settings = MainWP_Settings::get_all_settings_values();
487
488 if ( isset( $_POST['mainwp_restore_info_messages'] ) && ! empty( $_POST['mainwp_restore_info_messages'] ) ) {
489 delete_user_option( $user->ID, 'mainwp_notice_saved_status' );
490 }
491 $enabled_tours = ! isset( $_POST['mainwp-guided-tours-option'] ) ? 0 : 1;
492 MainWP_Utility::update_option( 'mainwp_enable_guided_tours', $enabled_tours );
493
494 $enabled1 = ! isset( $_POST['mainwp-guided-chatbase-option'] ) ? 0 : 1;
495 MainWP_Utility::update_option( 'mainwp_enable_guided_chatbase', $enabled1 );
496
497 $enabled2 = ! isset( $_POST['mainwp-guided-video-option'] ) ? 0 : 1;
498 MainWP_Utility::update_option( 'mainwp_enable_guided_video', $enabled2 );
499
500 if ( isset( $_POST['mainwp_settings_custom_theme'] ) ) {
501 $update_selected_mainwp_themes = true;
502 }
503
504 $new_settings = MainWP_Settings::get_all_settings_values();
505
506 /**
507 * Action: mainwp_after_save_settings
508 *
509 * Fires after save settings.
510 *
511 * @since 6.0
512 *
513 * @param array $new_settings The new settings.
514 * @param array $old_settings The old settings.
515 */
516 do_action( 'mainwp_after_save_settings', $new_settings, $old_settings );
517 $should_redirect = true;
518 set_transient( 'mainwp_settings_saved', 1, 30 );
519 }
520
521 if ( isset( $_POST['wp_scr_options_nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['wp_scr_options_nonce'] ), 'MainWPSelectThemes' ) ) {
522 $update_selected_mainwp_themes = true;
523 $should_redirect = true;
524 set_transient( 'mainwp_settings_saved', 1, 30 );
525 }
526
527 if ( $update_selected_mainwp_themes && isset( $_POST['mainwp_settings_custom_theme'] ) ) {
528 $custom_theme = sanitize_text_field( wp_unslash( $_POST['mainwp_settings_custom_theme'] ) );
529 update_user_option( $user->ID, 'mainwp_selected_theme', $custom_theme );
530 }
531
532 $update_screen_options = false;
533 if ( isset( $_POST['wp_nonce'] ) && ( wp_verify_nonce( sanitize_key( $_POST['wp_nonce'] ), 'Settings' ) || wp_verify_nonce( sanitize_key( $_POST['wp_nonce'] ), 'MainWPScrOptions' ) ) ) {
534 $update_screen_options = true;
535 }
536
537 if ( $update_screen_options ) {
538 $show_wids = array();
539 if ( isset( $_POST['mainwp_show_widgets'] ) && is_array( $_POST['mainwp_show_widgets'] ) ) {
540 $selected_wids = array_map( 'sanitize_text_field', wp_unslash( $_POST['mainwp_show_widgets'] ) );
541 foreach ( $selected_wids as $name ) {
542 $show_wids[ $name ] = 1;
543 }
544 }
545
546 if ( isset( $_POST['mainwp_widgets_name'] ) && is_array( $_POST['mainwp_widgets_name'] ) ) {
547 $name_wids = array_map( 'sanitize_text_field', wp_unslash( $_POST['mainwp_widgets_name'] ) );
548 foreach ( $name_wids as $name ) {
549 if ( ! isset( $show_wids[ $name ] ) ) {
550 $show_wids[ $name ] = 0;
551 }
552 }
553 }
554
555 $show_cols = array();
556 if ( isset( $_POST['mainwp_show_columns'] ) && is_array( $_POST['mainwp_show_columns'] ) ) {
557 $selected_cols = array_map( 'sanitize_text_field', wp_unslash( $_POST['mainwp_show_columns'] ) );
558 foreach ( $selected_cols as $name ) {
559 $show_cols[ $name ] = 1;
560 }
561 }
562
563 if ( isset( $_POST['mainwp_columns_name'] ) && is_array( $_POST['mainwp_columns_name'] ) ) {
564 $name_cols = array_map( 'sanitize_text_field', wp_unslash( $_POST['mainwp_columns_name'] ) );
565 foreach ( $name_cols as $name ) {
566 if ( ! isset( $show_cols[ $name ] ) ) {
567 $show_cols[ $name ] = 0;
568 }
569 }
570 }
571
572 $val = ( isset( $_POST['mainwp_sidebarPosition'] ) ? intval( $_POST['mainwp_sidebarPosition'] ) : 1 );
573 if ( $user ) {
574 update_user_option( $user->ID, 'mainwp_settings_show_widgets', $show_wids, true );
575 update_user_option( $user->ID, 'mainwp_sidebarPosition', $val, true );
576
577 if ( isset( $_POST['mainwp_manageposts_show_columns_settings'] ) ) {
578 update_user_option( $user->ID, 'mainwp_manageposts_show_columns', $show_cols, true );
579 }
580
581 if ( isset( $_POST['mainwp_managepages_show_columns_settings'] ) ) {
582 update_user_option( $user->ID, 'mainwp_managepages_show_columns', $show_cols, true );
583 }
584
585 if ( isset( $_POST['mainwp_manageusers_show_columns_settings'] ) ) {
586 update_user_option( $user->ID, 'mainwp_manageusers_show_columns', $show_cols, true );
587 }
588 }
589
590 MainWP_Utility::update_option( 'mainwp_hide_update_everything', ( ! isset( $_POST['hide_update_everything'] ) ? 0 : 1 ) );
591
592 if ( isset( $_POST['reset_overview_settings'] ) && ! empty( $_POST['reset_overview_settings'] ) && isset( $_POST['reset_overview_which_settings'] ) && 'overview_settings' === $_POST['reset_overview_which_settings'] ) {
593 update_user_option( $user->ID, 'mainwp_widgets_sorted_toplevel_page_mainwp_tab', false, true );
594 update_user_option( $user->ID, 'mainwp_widgets_sorted_mainwp_page_managesites', false, true );
595 MainWP_Cache_Warm_Helper::invalidate_manage_pages( array( 'mainwp_tab' ) );
596 }
597 }
598
599 $update_clients_screen_options = false;
600 if ( isset( $_POST['wp_scr_options_nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['wp_scr_options_nonce'] ), 'MainWPClientsScrOptions' ) ) {
601 $update_clients_screen_options = true;
602 }
603 if ( $update_clients_screen_options ) {
604
605 $show_wids = array();
606 if ( isset( $_POST['mainwp_show_widgets'] ) && is_array( $_POST['mainwp_show_widgets'] ) ) {
607 $selected_wids = array_map( 'sanitize_text_field', wp_unslash( $_POST['mainwp_show_widgets'] ) );
608 foreach ( $selected_wids as $name ) {
609 $show_wids[ $name ] = 1;
610 }
611 }
612
613 if ( isset( $_POST['mainwp_widgets_name'] ) && is_array( $_POST['mainwp_widgets_name'] ) ) {
614 $name_wids = array_map( 'sanitize_text_field', wp_unslash( $_POST['mainwp_widgets_name'] ) );
615 foreach ( $name_wids as $name ) {
616 if ( ! isset( $show_wids[ $name ] ) ) {
617 $show_wids[ $name ] = 0;
618 }
619 }
620 }
621
622 if ( $user ) {
623 update_user_option( $user->ID, 'mainwp_clients_show_widgets', $show_wids, true );
624 }
625
626 if ( isset( $_POST['reset_client_overview_settings'] ) && ! empty( $_POST['reset_client_overview_settings'] ) ) {
627 update_user_option( $user->ID, 'mainwp_widgets_sorted_mainwp_page_manageclients', false, true );
628 }
629 }
630
631 // Redirect after save settings and redirect to the same page.
632 if ( $should_redirect ) {
633 $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : 'MainWPTools';
634 wp_safe_redirect( admin_url( 'admin.php?page=' . $page ) );
635 exit();
636 }
637 }
638
639 /**
640 * Method handle_settings_post()
641 *
642 * Handle saving settings page.
643 *
644 * @uses \MainWP\Dashboard\MainWP_Backup_Handler::handle_settings_post()
645 * @uses \MainWP\Dashboard\MainWP_DB_Common::get_user_extension()
646 * @uses \MainWP\Dashboard\MainWP_DB_Common::update_user_extension()
647 * @uses \MainWP\Dashboard\MainWP_Monitoring_Handler::handle_settings_post()
648 * @uses \MainWP\Dashboard\MainWP_Settings::handle_settings_post()
649 */
650 public function handle_settings_post() { // phpcs:ignore -- NOSONAR - complex method.
651
652 if ( isset( $_GET['page'] ) && ( isset( $_POST['wp_nonce'] ) || isset( $_POST['wp_scr_options_nonce'] ) ) ) {
653 $this->include_pluggable();
654 $this->handle_mainwp_tools_settings();
655 $this->handle_manage_sites_screen_settings();
656 $this->handle_monitoring_sites_screen_settings();
657 $this->handle_clients_screen_settings();
658 $this->handle_updates_screen_settings();
659 $this->handle_insights_events_screen_settings();
660 }
661
662 if ( isset( $_POST['select_mainwp_options_siteview'] ) ) {
663 $this->include_pluggable();
664 if ( check_admin_referer( 'mainwp-admin-nonce' ) ) {
665 $userExtension = MainWP_DB_Common::instance()->get_user_extension();
666 $userExtension->site_view = ( empty( $_POST['select_mainwp_options_siteview'] ) ? MAINWP_VIEW_PER_PLUGIN_THEME : intval( $_POST['select_mainwp_options_siteview'] ) );
667 MainWP_DB_Common::instance()->update_user_extension( $userExtension );
668 }
669 }
670
671 if ( isset( $_POST['select_mainwp_options_plugintheme_view'] ) ) {
672 $this->include_pluggable();
673 if ( check_admin_referer( 'mainwp-admin-nonce' ) ) {
674 $view_per = ( empty( $_POST['select_mainwp_options_plugintheme_view'] ) ? MAINWP_VIEW_PER_PLUGIN_THEME : intval( $_POST['select_mainwp_options_plugintheme_view'] ) );
675 $which = isset( $_POST['whichview'] ) ? sanitize_text_field( wp_unslash( $_POST['whichview'] ) ) : '';
676 if ( 'plugin' === $which ) {
677 MainWP_Utility::update_user_option( 'mainwp_manage_plugin_view', $view_per );
678 } else {
679 MainWP_Utility::update_user_option( 'mainwp_manage_theme_view', $view_per );
680 }
681 }
682 }
683
684 if ( isset( $_POST['submit'] ) && isset( $_POST['wp_nonce'] ) ) {
685 $this->include_pluggable();
686 $nonce = sanitize_key( $_POST['wp_nonce'] );
687 // Check for both 'Settings' or 'MonitoringSettings' nonces.
688 $is_valid_nonce = wp_verify_nonce( $nonce, 'Settings' ) || wp_verify_nonce( $nonce, 'MonitoringSettings' );
689 if ( $is_valid_nonce ) {
690 $updated = MainWP_Settings::handle_settings_post();
691 $updated |= MainWP_Backup_Handler::handle_settings_post();
692 $updated |= MainWP_Monitoring_Handler::handle_settings_post();
693 $msg = '';
694 if ( $updated ) {
695 $msg = '&message=saved';
696 }
697
698 // Redirect to the correct page based on the nonce.
699 $url_page = 'admin.php?page=Settings' . $msg;
700 if ( wp_verify_nonce( $nonce, 'MonitoringSettings' ) ) {
701 $url_page = 'admin.php?page=MonitoringSettings' . $msg;
702 }
703 wp_safe_redirect( admin_url( $url_page ) );
704 exit();
705 }
706 }
707
708 if ( isset( $_POST['mainwp_sidebar_position'] ) && isset( $_POST['wp_nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['wp_nonce'] ), 'onchange_sidebarposition' ) ) {
709 $val = isset( $_POST['mainwp_sidebar_position'] ) && ! empty( $_POST['mainwp_sidebar_position'] ) ? 1 : 0;
710 $user = wp_get_current_user();
711 if ( $user ) {
712 update_user_option( $user->ID, 'mainwp_sidebarPosition', $val, true );
713 }
714 return true;
715 }
716
717 if ( isset( $_GET['viewmode'] ) && isset( $_GET['modenonce'] ) ) {
718 $viewmode = sanitize_text_field( wp_unslash( $_GET['viewmode'] ) );
719 $nonce = sanitize_key( $_GET['modenonce'] );
720 if ( ( 'table' === $viewmode || 'grid' === $viewmode ) && wp_verify_nonce( sanitize_key( $nonce ), 'viewmode' ) ) {
721 $user = wp_get_current_user();
722 if ( $user ) {
723 update_user_option( $user->ID, 'mainwp_sitesviewmode', $viewmode, true );
724 wp_safe_redirect( admin_url( 'admin.php?page=managesites' ) );
725 exit;
726 }
727 }
728 }
729
730 // Redirect current page after reset and save overview settings.
731 if ( isset( $_GET['page'] ) && isset( $_POST['reset_overview_settings'] ) && ( isset( $_POST['reset_overview_which_settings'] ) && 'overview_settings' === $_POST['reset_overview_which_settings'] ) ) {
732 $page = isset( $_GET['page'] ) ? sanitize_key( wp_unslash( $_GET['page'] ) ) : '';
733 $url = 'admin.php?page=' . $page;
734
735 $dashboard_id = isset( $_GET['dashboard'] ) ? absint( $_GET['dashboard'] ) : 0;
736 if ( ! empty( $dashboard_id ) ) {
737 $url .= '&dashboard=' . $dashboard_id;
738 }
739
740 wp_safe_redirect( admin_url( $url ) );
741 exit;
742 }
743 }
744
745 /**
746 * Method include_pluggable()
747 *
748 * Include pluggable functions.
749 */
750 public function include_pluggable() {
751 // may causing of conflict with Post S m t p plugin.
752 if ( ! function_exists( 'wp_create_nonce' ) ) {
753 include_once ABSPATH . WPINC . '/pluggable.php'; // NOSONAR - WP compatible.
754 }
755 }
756
757 /**
758 * Method plugins_api_extension_info()
759 *
760 * Get MainWP Extension api information.
761 *
762 * @param mixed $input_value Return value.
763 * @param mixed $action Action being performed.
764 * @param mixed $arg Action arguments. Should be the plugin slug.
765 *
766 * @return mixed $info|$input_value
767 *
768 * @uses \MainWP\Dashboard\MainWP_API_Handler::get_update_information()
769 * @uses \MainWP\Dashboard\MainWP_Extensions_View::get_available_extensions()
770 * @uses \MainWP\Dashboard\MainWP_System::get_plugin_slug()
771 * @uses \MainWP\Dashboard\MainWP_Extensions_Handler::get_slugs()
772 */
773 public function plugins_api_extension_info( $input_value, $action, $arg ) { // phpcs:ignore -- NOSONAR - complex.
774 if ( 'plugin_information' !== $action ) {
775 return $input_value;
776 }
777
778 if ( is_array( $arg ) ) {
779 $arg = (object) $arg;
780 }
781
782 if ( ! isset( $arg->slug ) || ( '' === $arg->slug ) ) {
783 return $input_value;
784 }
785
786 if ( dirname( MainWP_System::instance()->get_plugin_slug() ) === $arg->slug ) {
787 return $input_value;
788 }
789
790 $result = MainWP_Extensions_Handler::get_slugs();
791 $am_slugs = $result['am_slugs'];
792
793 if ( '' !== $am_slugs ) {
794 $am_slugs = explode( ',', $am_slugs );
795 if ( false !== strpos( $arg->slug, '/' ) ) { // to fix.
796 $dir_slug = dirname( $arg->slug );
797 } else {
798 $dir_slug = $arg->slug;
799 }
800 if ( in_array( $dir_slug, $am_slugs ) ) {
801 $info = MainWP_API_Handler::get_update_information( $dir_slug );
802 if ( is_object( $info ) && property_exists( $info, 'sections' ) ) {
803 if ( ! is_array( $info->sections ) || ! isset( $info->sections['changelog'] ) || empty( $info->sections['changelog'] ) ) {
804 $exts_data = MainWP_Extensions_View::get_available_extensions();
805 if ( isset( $exts_data[ $arg->slug ] ) ) {
806 $ext_info = $exts_data[ $arg->slug ];
807 $changelog_link = rtrim( $ext_info['changelog_url'], '/' );
808 $info->sections['changelog'] = '<a href="' . $changelog_link . '" target="_blank">' . $changelog_link . '</a>';
809 }
810 }
811 return $info;
812 }
813 return $info;
814 }
815 }
816
817 return $input_value;
818 }
819
820 /**
821 * Method plugins_api_wp_plugins_api_result()
822 *
823 * Hook after get plugins api information.
824 *
825 * @param mixed $res api information value.
826 * @param mixed $action Action being performed.
827 * @param mixed $arg Action arguments. Should be the plugin slug.
828 *
829 * @return mixed $res
830 */
831 public function plugins_api_wp_plugins_api_result( $res, $action, $arg ) { // phpcs:ignore -- NOSONAR - complex.
832
833 if ( 'plugin_information' !== $action ) {
834 return $res;
835 }
836
837 if ( is_object( $res ) && property_exists( $res, 'slug' ) && property_exists( $res, 'sections' ) ) {
838 return $res;
839 }
840
841 if ( ! isset( $_GET['wpplugin'] ) || ! is_numeric( $_GET['wpplugin'] ) || empty( $_GET['wpplugin'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
842 return $res;
843 }
844
845 if ( is_array( $arg ) ) {
846 $arg = (object) $arg;
847 }
848
849 if ( ! isset( $arg->slug ) || ( '' === $arg->slug ) ) {
850 return $res;
851 }
852
853 $site_id = intval( $_GET['wpplugin'] ); // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
854
855 if ( $site_id ) {
856 $website = MainWP_DB::instance()->get_website_by_id( $site_id );
857 if ( $website && ! empty( $website->plugin_upgrades ) ) {
858 $plugin_upgrades = json_decode( $website->plugin_upgrades, true );
859
860 if ( is_array( $plugin_upgrades ) ) {
861 $found_update = false;
862 $empty_sections = false;
863 foreach ( $plugin_upgrades as $plugin_slug => $info ) {
864 if ( false !== strpos( $plugin_slug, $arg->slug ) && isset( $info['update'] ) ) {
865 $found_update = true;
866 if ( isset( $info['update']['slug'] ) && $arg->slug === $info['update']['slug'] && isset( $info['update']['new_version'] ) && ! empty( $info['update']['new_version'] ) && isset( $info['update']['sections'] ) && ! empty( $info['update']['sections'] ) ) {
867 $info_update = (object) $info['update'];
868 $info_update->external = false;
869 return $info_update;
870 }
871 $empty_sections = true;
872 break;
873 }
874 }
875
876 if ( $found_update && $empty_sections ) {
877 try {
878 $info = MainWP_Connect::fetch_url_authed(
879 $website,
880 'plugin_action',
881 array(
882 'action' => 'changelog_info', // try to get changelog from the child site.
883 'slug' => $arg->slug,
884 )
885 );
886 if ( is_array( $info ) && isset( $info['update'] ) && ! empty( $info['update']['sections'] ) ) {
887 $info_update = (object) $info['update'];
888 $info_update->external = true;
889 return $info_update;
890 }
891 } catch ( \Exception $e ) {
892 // error happen.
893 }
894 }
895 }
896 }
897 }
898
899 return $res;
900 }
901
902 /**
903 * Method check_update_custom()
904 *
905 * Check MainWP Extensions for updates.
906 *
907 * @param object $transient Transient information.
908 *
909 * @return object $transient Transient information.
910 *
911 * @uses \MainWP\Dashboard\MainWP_API_Handler::get_upgrade_information()
912 * @uses \MainWP\Dashboard\MainWP_Extensions_Handler::get_indexed_extensions_infor()
913 * @uses \MainWP\Dashboard\MainWP_Extensions_Handler::get_extension_slug()
914 * @uses \MainWP\Dashboard\MainWP_Utility::update_option()
915 */
916 public function check_update_custom( $transient ) { // phpcs:ignore -- NOSONAR -Current complexity is the only way to achieve desired results, pull request solutions appreciated.
917 if ( isset( $_POST['action'] ) && ( ( 'update-plugin' === $_POST['action'] ) || ( 'update-selected' === $_POST['action'] ) ) && is_object( $transient ) && property_exists( $transient, 'response' ) ) { // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
918 $extensions = MainWP_Extensions_Handler::get_indexed_extensions_infor( array( 'activated' => true ) );
919 if ( defined( 'DOING_AJAX' ) && isset( $_POST['plugin'] ) && 'update-plugin' === $_POST['action'] ) { // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
920
921 if ( empty( $transient->response ) ) {
922 $transient->response = array();
923 }
924
925 $plugin_slug = sanitize_text_field( wp_unslash( $_POST['plugin'] ) ); // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
926 if ( isset( $extensions[ $plugin_slug ] ) ) {
927
928 if ( ! isset( $transient->response[ $plugin_slug ] ) || ! is_object( $transient->response[ $plugin_slug ] ) || ! property_exists( $transient->response[ $plugin_slug ], 'new_version' ) ) {
929 return $transient;
930 }
931
932 if ( isset( $transient->response[ $plugin_slug ] ) && version_compare( $transient->response[ $plugin_slug ]->new_version, $extensions[ $plugin_slug ]['version'], '=' ) ) {
933 return $transient;
934 }
935
936 $api_slug = dirname( $plugin_slug );
937 $rslt = MainWP_API_Handler::get_upgrade_information( $api_slug );
938
939 if ( ! empty( $rslt ) && is_object( $rslt ) && property_exists( $rslt, 'new_version' ) && ! empty( $rslt->new_version ) && version_compare( $rslt->new_version, $extensions[ $plugin_slug ]['version'], '>' ) ) {
940 $transient->response[ $plugin_slug ] = static::map_rslt_obj( $rslt );
941 }
942
943 return $transient;
944 }
945 } elseif ( 'update-selected' === $_POST['action'] && isset( $_POST['checked'] ) && is_array( $_POST['checked'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
946
947 if ( empty( $transient->response ) ) {
948 $transient->response = array();
949 }
950
951 $updated = false;
952 foreach ( wp_unslash( $_POST['checked'] ) as $plugin_slug ) { // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
953 if ( isset( $extensions[ $plugin_slug ] ) ) {
954
955 if ( ! isset( $transient->response[ $plugin_slug ] ) ) {
956 $transient->response[ $plugin_slug ] = new \stdClass();
957 }
958
959 if ( isset( $transient->response[ $plugin_slug ] ) && version_compare( $transient->response[ $plugin_slug ]->new_version, $extensions[ $plugin_slug ]['version'], '=' ) ) {
960 continue;
961 }
962 $api_slug = dirname( $plugin_slug );
963 $rslt = MainWP_API_Handler::get_upgrade_information( $api_slug );
964 if ( ! empty( $rslt ) && is_object( $rslt ) && property_exists( $rslt, 'new_version' ) && ! empty( $rslt->new_version ) && version_compare( $rslt->new_version, $extensions[ $plugin_slug ]['version'], '>' ) ) {
965 $this->upgradeVersionInfo->result[ $api_slug ] = $rslt;
966 $transient->response[ $plugin_slug ] = static::map_rslt_obj( $rslt );
967 $updated = true;
968 }
969 }
970 }
971 if ( $updated ) {
972 MainWP_Utility::update_option( 'mainwp_upgradeVersionInfo', $this->upgradeVersionInfo );
973 }
974
975 return $transient;
976 }
977 }
978
979 if ( empty( $transient->checked ) ) {
980 return $transient;
981 }
982
983 if ( ! empty( $this->upgradeVersionInfo ) && property_exists( $this->upgradeVersionInfo, 'result' ) && is_array( $this->upgradeVersionInfo->result ) ) {
984 foreach ( $this->upgradeVersionInfo->result as $rslt ) {
985 if ( ! isset( $rslt->slug ) ) {
986 continue;
987 }
988
989 $plugin_slug = MainWP_Extensions_Handler::get_extension_slug( $rslt->slug );
990 if ( isset( $transient->checked[ $plugin_slug ] ) && property_exists( $rslt, 'new_version' ) && ! empty( $rslt->new_version ) && version_compare( $rslt->new_version, $transient->checked[ $plugin_slug ], '>' ) ) {
991 $transient->response[ $plugin_slug ] = static::map_rslt_obj( $rslt );
992 }
993 }
994 }
995
996 return $transient;
997 }
998
999
1000 /**
1001 * Method map_rslt_obj()
1002 *
1003 * Map resulting object.
1004 *
1005 * @param object $result Resulting information.
1006 *
1007 * @return object $obj Mapped resulting object.
1008 */
1009 public static function map_rslt_obj( $result ) {
1010 $obj = new \stdClass();
1011 $obj->slug = $result->slug;
1012 $obj->new_version = $result->new_version;
1013 $obj->url = 'https://mainwp.com/';
1014 $obj->package = $result->package;
1015
1016 return $obj;
1017 }
1018
1019 /**
1020 * Method check_upgrade()
1021 *
1022 * Check if Extension has an update.
1023 *
1024 * @uses \MainWP\Dashboard\MainWP_API_Handler::check_exts_upgrade()
1025 * @uses \MainWP\Dashboard\MainWP_Utility::update_option()
1026 */
1027 private function check_upgrade() { // phpcs:ignore -- NOSONAR - validates and preserves per-extension update state.
1028 $expected_extensions = $this->get_expected_extension_updates();
1029 $has_full_scope = $this->has_full_extension_update_scope( $expected_extensions );
1030
1031 if ( null === $this->upgradeVersionInfo ) {
1032 $this->upgradeVersionInfo = new \stdClass();
1033 }
1034
1035 $this->upgradeVersionInfo->updated = time();
1036
1037 if ( empty( $expected_extensions ) ) {
1038 if ( $has_full_scope ) {
1039 $this->clear_extension_update_failure();
1040 }
1041 MainWP_Utility::update_option( 'mainwp_upgradeVersionInfo', $this->upgradeVersionInfo );
1042 return $has_full_scope;
1043 }
1044
1045 $result = MainWP_API_Handler::check_exts_upgrade();
1046 $previous_result = property_exists( $this->upgradeVersionInfo, 'result' ) && is_array( $this->upgradeVersionInfo->result ) ? $this->upgradeVersionInfo->result : array();
1047 $fresh_result = array();
1048 $failed = ! is_array( $result );
1049
1050 foreach ( $expected_extensions as $api_slug => $installed_version ) {
1051 $fresh = is_array( $result ) && isset( $result[ $api_slug ] ) ? $result[ $api_slug ] : null;
1052 if ( $this->is_usable_extension_update_result( $fresh, $api_slug, $installed_version ) ) {
1053 $fresh_result[ $api_slug ] = $fresh;
1054 } else {
1055 $failed = true;
1056 }
1057 }
1058
1059 if ( ! $failed ) {
1060 $this->upgradeVersionInfo->result = $has_full_scope ? $fresh_result : array_merge( $previous_result, $fresh_result );
1061 }
1062
1063 if ( $has_full_scope ) {
1064 if ( $failed ) {
1065 $this->record_extension_update_failure();
1066 } else {
1067 $this->clear_extension_update_failure();
1068 }
1069 }
1070
1071 MainWP_Utility::update_option( 'mainwp_upgradeVersionInfo', $this->upgradeVersionInfo );
1072 return ! $failed;
1073 }
1074
1075 /**
1076 * Get Add-ons expected in an update-check response.
1077 *
1078 * @return array API slugs keyed to installed versions.
1079 */
1080 private function get_expected_extension_updates() {
1081 $expected = array();
1082
1083 foreach ( MainWP_Extensions_Handler::get_extensions() as $extension ) {
1084 if ( ! isset( $extension['activated_key'] ) || 'Activated' !== $extension['activated_key'] || empty( $extension['api'] ) ) {
1085 continue;
1086 }
1087
1088 $expected[ $extension['api'] ] = isset( $extension['version'] ) ? (string) $extension['version'] : '';
1089 }
1090
1091 return $expected;
1092 }
1093
1094 /**
1095 * Check whether visible Add-ons cover the shared update cache.
1096 *
1097 * @param array $expected Visible Add-ons expected in the response.
1098 *
1099 * @return bool Whether this request covers every activated Add-on.
1100 */
1101 private function has_full_extension_update_scope( $expected ) {
1102 $all_expected = array();
1103
1104 foreach ( get_option( 'mainwp_extensions', array() ) as $extension ) {
1105 if ( isset( $extension['activated_key'], $extension['api'] ) && 'Activated' === $extension['activated_key'] && '' !== $extension['api'] ) {
1106 $all_expected[] = $extension['api'];
1107 }
1108 }
1109
1110 $visible = array_keys( $expected );
1111 sort( $all_expected );
1112 sort( $visible );
1113
1114 return $all_expected === $visible;
1115 }
1116
1117 /**
1118 * Check whether an Add-on update result is safe to persist.
1119 *
1120 * @param mixed $result Update result.
1121 * @param string $api_slug Expected API slug.
1122 * @param string $installed_version Installed Add-on version.
1123 *
1124 * @return bool Whether the result is usable.
1125 */
1126 private function is_usable_extension_update_result( $result, $api_slug, $installed_version ) {
1127 if ( ! is_object( $result ) || ! isset( $result->slug ) || $api_slug !== $result->slug || ! property_exists( $result, 'new_version' ) || ! is_string( $result->new_version ) ) {
1128 return false;
1129 }
1130
1131 $new_version = trim( $result->new_version );
1132 if ( '' === $new_version || ( property_exists( $result, 'error' ) && ! empty( $result->error ) ) ) {
1133 return false;
1134 }
1135
1136 if ( version_compare( $new_version, $installed_version, '>' ) ) {
1137 return property_exists( $result, 'package' ) && is_string( $result->package ) && '' !== trim( $result->package );
1138 }
1139
1140 return true;
1141 }
1142
1143 /**
1144 * Record a failed Add-on update-check attempt.
1145 */
1146 private function record_extension_update_failure() {
1147 $failure_count = property_exists( $this->upgradeVersionInfo, 'extension_update_failure_count' ) ? (int) $this->upgradeVersionInfo->extension_update_failure_count : 0;
1148
1149 if ( $failure_count < 1 || ! property_exists( $this->upgradeVersionInfo, 'extension_update_failure_episode' ) || empty( $this->upgradeVersionInfo->extension_update_failure_episode ) ) {
1150 $this->upgradeVersionInfo->extension_update_failure_episode = wp_generate_uuid4();
1151 }
1152
1153 $this->upgradeVersionInfo->extension_update_failure_count = $failure_count + 1;
1154 }
1155
1156 /**
1157 * Clear Add-on update-check failure state after a complete response.
1158 */
1159 private function clear_extension_update_failure() {
1160 unset( $this->upgradeVersionInfo->extension_update_failure_count, $this->upgradeVersionInfo->extension_update_failure_episode );
1161 }
1162
1163 /**
1164 * Get the active repeated-failure notice ID.
1165 *
1166 * @return string Notice ID, or an empty string before the second consecutive failure.
1167 */
1168 public function get_extension_update_failure_notice_id() {
1169 if ( ! $this->has_full_extension_update_scope( $this->get_expected_extension_updates() ) || ! is_object( $this->upgradeVersionInfo ) || ! property_exists( $this->upgradeVersionInfo, 'extension_update_failure_count' ) || 2 > (int) $this->upgradeVersionInfo->extension_update_failure_count || ! property_exists( $this->upgradeVersionInfo, 'extension_update_failure_episode' ) ) {
1170 return '';
1171 }
1172
1173 $episode = sanitize_key( $this->upgradeVersionInfo->extension_update_failure_episode );
1174 return '' !== $episode ? 'mainwp-extension-update-check-failure-' . $episode : '';
1175 }
1176
1177 /**
1178 * Retry the Add-on update check and refresh WordPress update data.
1179 *
1180 * @return bool Whether every expected Add-on returned a usable result.
1181 */
1182 public function retry_extension_update_check() {
1183 $success = $this->check_upgrade();
1184 delete_site_transient( 'update_plugins' );
1185 return $success;
1186 }
1187
1188 /**
1189 * Method pre_check_update_custom()
1190 *
1191 * Pre-check for extension updates.
1192 *
1193 * @param object $transient Transient information.
1194 *
1195 * @return object $transient Transient information.
1196 *
1197 * @uses \MainWP\Dashboard\MainWP_Extensions_Handler::get_indexed_extensions_infor()
1198 * @uses \MainWP\Dashboard\MainWP_Extensions_Handler::get_extension_slug()
1199 */
1200 public function pre_check_update_custom( $transient ) {
1201 if ( ! isset( $transient->checked ) ) {
1202 return $transient;
1203 }
1204
1205 if ( defined( 'MAINWP_PLUGIN_UPGRADING' ) && true === MAINWP_PLUGIN_UPGRADING ) {
1206 return $transient;
1207 }
1208
1209 MainWP_Logger::instance()->log_events( 'extension-updates-check', 'pre_set_site_transient_update_plugins' );
1210
1211 if ( ( null === $this->upgradeVersionInfo ) || ! property_exists( $this->upgradeVersionInfo, 'updated' ) || ( ( time() - $this->upgradeVersionInfo->updated ) > 60 ) ) {
1212 $this->check_upgrade();
1213 }
1214
1215 if ( empty( $transient->response ) ) {
1216 $transient->response = array();
1217 }
1218
1219 if ( ! empty( $this->upgradeVersionInfo ) && property_exists( $this->upgradeVersionInfo, 'result' ) && is_array( $this->upgradeVersionInfo->result ) ) {
1220 $extensions = MainWP_Extensions_Handler::get_indexed_extensions_infor( array( 'activated' => true ) );
1221 foreach ( $this->upgradeVersionInfo->result as $rslt ) {
1222 $plugin_slug = MainWP_Extensions_Handler::get_extension_slug( $rslt->slug );
1223 if ( isset( $extensions[ $plugin_slug ] ) && property_exists( $rslt, 'new_version' ) && ! empty( $rslt->new_version ) && version_compare( $rslt->new_version, $extensions[ $plugin_slug ]['version'], '>' ) ) {
1224 $transient->response[ $plugin_slug ] = static::map_rslt_obj( $rslt );
1225 }
1226 }
1227 }
1228
1229 return $transient;
1230 }
1231
1232 /**
1233 * Method hook_refresh_trusted_extension_package_url
1234 *
1235 * @param mixed $reply The reply from the upgrader.
1236 * @param mixed $package The package URL.
1237 * @param mixed $upgrader The upgrader instance.
1238 * @param mixed $hook_extra Extra information about the upgrade, including the plugin being updated.
1239 * @return void
1240 */
1241 public function hook_refresh_trusted_extension_package_url( $reply, $package, $upgrader, $hook_extra ) {
1242 if ( isset( $hook_extra['plugin'] ) ) { // && isset( $_POST['mainwpsignature'] ) && isset( $_POST['function'] ) && 'upgradeplugintheme' === $_POST['function'] ) { // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- NOSONAR - hook for plugin update action, it is safe to use $_POST here.
1243 $ext_api_slug = dirname( $hook_extra['plugin'] );
1244 if ( ! empty( $ext_api_slug ) ) {
1245 $rslt_info = MainWP_API_Handler::get_upgrade_information( $ext_api_slug );
1246 if ( ! empty( $rslt_info ) && is_object( $rslt_info ) && property_exists( $rslt_info, 'package' ) && ! empty( $rslt_info->package ) ) {
1247 // Replace package URL.
1248 $upgrader->skin->options['package'] = $rslt_info->package;
1249 unset( $package );
1250 }
1251 }
1252 }
1253 return $reply;
1254 }
1255
1256
1257 /**
1258 * Method upload_file()
1259 *
1260 * Upload a file.
1261 *
1262 * @param mixed $file File to upload.
1263 *
1264 * @return void
1265 *
1266 * @uses \MainWP\Dashboard\MainWP_Utility::ends_with()
1267 */
1268 public function upload_file( $file ) {
1269 header( 'Content-Description: File Transfer' );
1270 $dwl_fname = basename( $file );
1271 if ( 'tar.gz' === $dwl_fname || '.tar.gz' === $dwl_fname ) {
1272 $dwl_fname = 'noname.tar.gz'; // to fix name of zip file.
1273 }
1274 header( 'Content-Type: application/octet-stream' );
1275 header( 'Content-Disposition: attachment; filename="' . $dwl_fname . '"' );
1276 header( 'Expires: 0' );
1277 header( 'Cache-Control: must-revalidate' );
1278 header( 'Pragma: public' );
1279 header( 'Content-Length: ' . filesize( $file ) );
1280 while ( ob_get_level() ) {
1281 ob_end_clean();
1282 }
1283 $this->readfile_chunked( $file );
1284 exit();
1285 }
1286
1287 /**
1288 * Method readfile_chunked()
1289 *
1290 * Read Chunked File.
1291 *
1292 * @param mixed $filename Name of file.
1293 *
1294 * @return mixed echo $buffer|false|$handle.
1295 */
1296 public function readfile_chunked( $filename ) {
1297 $chunksize = 1024;
1298 $handle = fopen( $filename, 'rb' );
1299 if ( false === $handle ) {
1300 return false;
1301 }
1302
1303 while ( ! feof( $handle ) ) {
1304 $buffer = fread( $handle, $chunksize );
1305 echo $buffer; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1306 if ( ob_get_length() ) {
1307 ob_flush();
1308 flush();
1309 }
1310 $buffer = null;
1311 }
1312
1313 return fclose( $handle );
1314 }
1315
1316 /**
1317 * Method activate_redirection()
1318 *
1319 * Redirect after activating MainWP Extension.
1320 *
1321 * @param mixed $location Location to redirect to.
1322 *
1323 * @return $location Admin URL + the page to redirect to.
1324 */
1325 public function activate_redirect( $location ) {
1326 unset( $location );
1327 return admin_url( 'admin.php?page=Extensions' );
1328 }
1329
1330 /**
1331 * Method activate_extension()
1332 *
1333 * Activate MainWP Extension.
1334 *
1335 * @param mixed $ext_key Extension API Key.
1336 * @param array $info Extension Info.
1337 *
1338 * @uses \MainWP\Dashboard\MainWP_Api_Manager::set_activation_info()
1339 * @uses \MainWP\Dashboard\MainWP_Api_Manager_Password_Management::generate_password()
1340 */
1341 public function activate_extension( $ext_key, $info = array() ) {
1342
1343 add_filter( 'wp_redirect', array( $this, 'activate_redirect' ) );
1344
1345 if ( is_array( $info ) && isset( $info['product_id'] ) && isset( $info['software_version'] ) ) {
1346 $act_info = array(
1347 'product_id' => $info['product_id'],
1348 'software_version' => $info['software_version'],
1349 'activated_key' => 'Deactivated',
1350 'instance_id' => MainWP_Api_Manager_Password_Management::generate_password( 12, false ),
1351 );
1352 MainWP_Api_Manager::instance()->set_activation_info( $ext_key, $act_info );
1353 }
1354 }
1355
1356 /**
1357 * Method deactivate_extension()
1358 *
1359 * Deactivate MaiNWP Extension.
1360 *
1361 * @param mixed $ext_key Exnension API Key.
1362 * @param bool $dashboard_only Deactive API Key on dashboard only.
1363 *
1364 * @uses \MainWP\Dashboard\MainWP_Api_Manager::set_activation_info()
1365 */
1366 public function deactivate_extension( $ext_key, $dashboard_only = false ) {
1367 // try to deactivate license.
1368 if ( ! $dashboard_only ) {
1369 $mainwp_api_key = MainWP_Api_Manager_Key::instance()->get_decrypt_master_api_key();
1370 MainWP_Api_Manager::instance()->license_key_deactivation( $ext_key, $mainwp_api_key );
1371 }
1372
1373 MainWP_Api_Manager::instance()->remove_activation_info( $ext_key );
1374 }
1375 }
1376