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 / includes / rest-api / controller / version2 / class-mainwp-rest-settings-controller.php

class-mainwp-rest-settings-controller.php in MainWP Dashboard: Self-hosted WordPress Management for Agencies 6.2.1, at includes/rest-api/controller/version2/class-mainwp-rest-settings-controller.php

4,735 lines 199.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * MainWP REST Controller
4 *
5 * This class handles the REST API
6 *
7 * @package MainWP\Dashboard
8 */
9
10 use MainWP\Dashboard\MainWP_DB;
11 use MainWP\Dashboard\MainWP_Utility;
12 use MainWP\Dashboard\MainWP_Settings;
13 use MainWP\Dashboard\MainWP_Notification_Settings;
14 use MainWP\Dashboard\MainWP_Settings_Indicator;
15 use MainWP\Dashboard\MainWP_System_Utility;
16 use MainWP\Dashboard\Module\CostTracker\Cost_Tracker_Utility;
17 use MainWP\Dashboard\Module\CostTracker\Cost_Tracker_Admin;
18 use MainWP\Dashboard\Module\ApiBackups\Api_Backups_3rd_Party;
19 use MainWP\Dashboard\Module\ApiBackups\Api_Backups_Utility;
20 use MainWP\Dashboard\MainWP_Keys_Manager;
21 use MainWP\Dashboard\MainWP_Api_Manager;
22 use MainWP\Dashboard\MainWP_Connect;
23 use MainWP\Dashboard\MainWP_Logger;
24 use MainWP\Dashboard\MainWP_Sync;
25 use MainWP\Dashboard\MainWP_Manage_Sites_View;
26 use MainWP\Dashboard\MainWP_Uptime_Monitoring_Handle;
27 use MainWP\Dashboard\MainWP_Uptime_Monitoring_Edit;
28 use MainWP\Dashboard\MainWP_Credential_Render;
29
30 // Exit if accessed directly.
31 if ( ! defined( 'ABSPATH' ) ) {
32 exit;
33 }
34
35
36 /**
37 * Class MainWP_Rest_Settings_Controller
38 *
39 * @package MainWP\Dashboard
40 */
41 class MainWP_Rest_Settings_Controller extends MainWP_REST_Controller { //phpcs:ignore -- NOSONAR - multi methods.
42
43 // phpcs:disable Generic.Metrics.CyclomaticComplexity -- complexity.
44
45 /**
46 * Protected static variable to hold the single instance of the class.
47 *
48 * @var mixed Default null
49 */
50 private static $instance = null;
51
52 /**
53 * Route base.
54 *
55 * @var string
56 */
57 protected $rest_base = 'settings';
58
59 /**
60 * Batch size.
61 *
62 * @var int
63 */
64 private static $batch_size = 5;
65
66 /**
67 * Constructor.
68 */
69 public function __construct() {
70 $this->db = MainWP_DB::instance();
71 }
72
73 /**
74 * Method instance()
75 *
76 * Create public static instance.
77 *
78 * @static
79 * @return static::$instance
80 */
81 public static function instance() {
82 if ( null === static::$instance ) {
83 static::$instance = new self();
84 }
85 return static::$instance;
86 }
87
88 /**
89 * Method register_routes()
90 *
91 * Creates the necessary endpoints for the api.
92 * Note, for a request to be successful the URL query parameters consumer_key and consumer_secret need to be set and correct.
93 */
94 public function register_routes() { // phpcs:ignore -- NOSONAR - complex.
95 // Global settings.
96 register_rest_route(
97 $this->namespace,
98 '/' . $this->rest_base . '/general',
99 array(
100 array(
101 'methods' => WP_REST_Server::READABLE,
102 'callback' => array( $this, 'get_general_settings' ),
103 'permission_callback' => array( $this, 'get_rest_permissions_check' ),
104 ),
105 'schema' => array( $this, 'get_public_item_schema' ),
106 )
107 );
108 register_rest_route(
109 $this->namespace,
110 '/' . $this->rest_base . '/general/edit',
111 array(
112 'methods' => 'PUT, PATCH',
113 'callback' => array( $this, 'update_general_settings' ),
114 'permission_callback' => array( $this, 'get_rest_permissions_check' ),
115 'args' => $this->get_update_general_allowed_fields(),
116 'validate_callback' => array( $this, 'validate_update_general_params' ),
117 ),
118 );
119
120 // Advanced settings.
121 register_rest_route(
122 $this->namespace,
123 '/' . $this->rest_base . '/advanced',
124 array(
125 array(
126 'methods' => WP_REST_Server::READABLE,
127 'callback' => array( $this, 'get_advanced_settings' ),
128 'permission_callback' => array( $this, 'get_rest_permissions_check' ),
129 ),
130 )
131 );
132 register_rest_route(
133 $this->namespace,
134 '/' . $this->rest_base . '/advanced/edit',
135 array(
136 array(
137 'methods' => 'PUT, PATCH',
138 'callback' => array( $this, 'update_advanced_settings' ),
139 'permission_callback' => array( $this, 'get_rest_permissions_check' ),
140 'args' => $this->get_update_advanced_allowed_fields(),
141 ),
142 )
143 );
144
145 // Monitoring settings.
146 register_rest_route(
147 $this->namespace,
148 '/' . $this->rest_base . '/monitoring',
149 array(
150 array(
151 'methods' => WP_REST_Server::READABLE,
152 'callback' => array( $this, 'get_monitoring_settings' ),
153 'permission_callback' => array( $this, 'get_rest_permissions_check' ),
154 ),
155 )
156 );
157 register_rest_route(
158 $this->namespace,
159 '/' . $this->rest_base . '/monitoring/edit',
160 array(
161 array(
162 'methods' => 'PUT, PATCH',
163 'callback' => array( $this, 'update_monitoring_settings' ),
164 'permission_callback' => array( $this, 'get_rest_permissions_check' ),
165 'args' => $this->get_update_monitoring_allowed_fields(),
166 ),
167 )
168 );
169
170 // Email settings.
171 register_rest_route(
172 $this->namespace,
173 '/' . $this->rest_base . '/emails',
174 array(
175 array(
176 'methods' => WP_REST_Server::READABLE,
177 'callback' => array( $this, 'get_emails_settings' ),
178 'permission_callback' => array( $this, 'get_rest_permissions_check' ),
179 ),
180 )
181 );
182 register_rest_route(
183 $this->namespace,
184 '/' . $this->rest_base . '/emails/(?P<mail_type>[a-zA-Z0-9\-\.\_]+)/edit',
185 array(
186 array(
187 'methods' => 'PUT, PATCH',
188 'callback' => array( $this, 'update_emails_settings' ),
189 'permission_callback' => array( $this, 'get_rest_permissions_check' ),
190 'args' => $this->get_update_emails_allowed_fields(),
191 ),
192 )
193 );
194
195 // Cost Tracker Settings.
196 register_rest_route(
197 $this->namespace,
198 '/' . $this->rest_base . '/cost-tracker',
199 array(
200 array(
201 'methods' => WP_REST_Server::READABLE,
202 'callback' => array( $this, 'get_cost_tracker_settings' ),
203 'permission_callback' => array( $this, 'get_rest_permissions_check' ),
204 ),
205 )
206 );
207 register_rest_route(
208 $this->namespace,
209 '/' . $this->rest_base . '/cost-tracker/edit',
210 array(
211 array(
212 'methods' => 'PUT, PATCH',
213 'callback' => array( $this, 'edit_cost_tracker_settings' ),
214 'permission_callback' => array( $this, 'get_rest_permissions_check' ),
215 'args' => $this->get_cost_tracker_allowed_fields(),
216 ),
217 )
218 );
219 register_rest_route(
220 $this->namespace,
221 '/' . $this->rest_base . '/cost-tracker/product-types/add',
222 array(
223 array(
224 'methods' => WP_REST_Server::CREATABLE,
225 'callback' => array( $this, 'add_cost_tracker_product_type' ),
226 'permission_callback' => array( $this, 'get_rest_permissions_check' ),
227 'args' => $this->get_add_cost_tracker_product_type_allowed_fields(),
228 ),
229 )
230 );
231 register_rest_route(
232 $this->namespace,
233 '/' . $this->rest_base . '/cost-tracker/product-types/(?P<slug>[a-zA-Z0-9\-\.\_]+)/edit',
234 array(
235 array(
236 'methods' => 'PUT, PATCH',
237 'callback' => array( $this, 'update_cost_tracker_product_type' ),
238 'permission_callback' => array( $this, 'get_rest_permissions_check' ),
239 'args' => $this->get_edit_cost_tracker_product_type_allowed_fields(),
240 ),
241 )
242 );
243 register_rest_route(
244 $this->namespace,
245 '/' . $this->rest_base . '/cost-tracker/product-types/(?P<slug>[a-zA-Z0-9\-\.\_]+)/delete',
246 array(
247 array(
248 'methods' => WP_REST_Server::DELETABLE,
249 'callback' => array( $this, 'delete_cost_tracker_product_type' ),
250 'permission_callback' => array( $this, 'get_rest_permissions_check' ),
251 'args' => $this->get_allowed_product_type_slug_field(),
252 ),
253 )
254 );
255 register_rest_route(
256 $this->namespace,
257 '/' . $this->rest_base . '/cost-tracker/payment-methods/add',
258 array(
259 array(
260 'methods' => WP_REST_Server::CREATABLE,
261 'callback' => array( $this, 'add_cost_tracker_payment_method' ),
262 'permission_callback' => array( $this, 'get_rest_permissions_check' ),
263 'args' => $this->get_add_cost_tracker_payment_method_allowed_fields(),
264 ),
265 )
266 );
267 register_rest_route(
268 $this->namespace,
269 '/' . $this->rest_base . '/cost-tracker/payment-methods/(?P<slug>[a-zA-Z0-9\-\.\_]+)/edit',
270 array(
271 array(
272 'methods' => 'PUT, PATCH',
273 'callback' => array( $this, 'update_cost_tracker_payment_method' ),
274 'permission_callback' => array( $this, 'get_rest_permissions_check' ),
275 'args' => $this->get_edit_cost_tracker_payment_method_allowed_fields(),
276 ),
277 )
278 );
279 register_rest_route(
280 $this->namespace,
281 '/' . $this->rest_base . '/cost-tracker/payment-methods/(?P<slug>[a-zA-Z0-9\-\.\_]+)/delete',
282 array(
283 array(
284 'methods' => WP_REST_Server::DELETABLE,
285 'callback' => array( $this, 'delete_cost_tracker_payment_method' ),
286 'permission_callback' => array( $this, 'get_rest_permissions_check' ),
287 'args' => $this->get_allowed_payment_method_slug_field(),
288 ),
289 )
290 );
291
292 // Dashboard Insights Settings.
293 register_rest_route(
294 $this->namespace,
295 '/' . $this->rest_base . '/dashboard-insights',
296 array(
297 array(
298 'methods' => WP_REST_Server::READABLE,
299 'callback' => array( $this, 'get_dashboard_insights_settings' ),
300 'permission_callback' => array( $this, 'get_rest_permissions_check' ),
301 ),
302 )
303 );
304 register_rest_route(
305 $this->namespace,
306 '/' . $this->rest_base . '/dashboard-insights/edit',
307 array(
308 array(
309 'methods' => 'PUT, PATCH',
310 'callback' => array( $this, 'update_dashboard_insights_settings' ),
311 'permission_callback' => array( $this, 'get_rest_permissions_check' ),
312 'args' => $this->get_edit_dashboard_insight_allowed_fields(),
313 ),
314 )
315 );
316
317 // Backup API Providers Settings.
318 register_rest_route(
319 $this->namespace,
320 '/' . $this->rest_base . '/api-backups',
321 array(
322 array(
323 'methods' => WP_REST_Server::READABLE,
324 'callback' => array( $this, 'get_api_backup_settings' ),
325 'permission_callback' => array( $this, 'get_rest_permissions_check' ),
326 ),
327 )
328 );
329 register_rest_route(
330 $this->namespace,
331 '/' . $this->rest_base . '/api-backups/(?P<api_slug>[a-zA-Z0-9\-\.\_]+)/edit',
332 array(
333 array(
334 'methods' => 'PUT, PATCH',
335 'callback' => array( $this, 'update_api_backup_settings' ),
336 'permission_callback' => array( $this, 'get_rest_permissions_check' ),
337 'args' => $this->get_edit_api_backup_allowed_fields(),
338 ),
339 )
340 );
341
342 // MainWP Dashboard Tools Settings.
343 register_rest_route(
344 $this->namespace,
345 '/' . $this->rest_base . '/tools',
346 array(
347 array(
348 'methods' => WP_REST_Server::READABLE,
349 'callback' => array( $this, 'get_tool_settings' ),
350 'permission_callback' => array( $this, 'get_rest_permissions_check' ),
351 ),
352 )
353 );
354 register_rest_route(
355 $this->namespace,
356 '/' . $this->rest_base . '/tools/edit',
357 array(
358 array(
359 'methods' => 'PUT, PATCH',
360 'callback' => array( $this, 'update_tools_settings' ),
361 'permission_callback' => array( $this, 'get_rest_permissions_check' ),
362 'args' => $this->get_edit_tools_allowed_fields(),
363 ),
364 )
365 );
366 register_rest_route(
367 $this->namespace,
368 '/' . $this->rest_base . '/tools/destroy-sessions',
369 array(
370 array(
371 'methods' => WP_REST_Server::CREATABLE,
372 'callback' => array( $this, 'destroy_sessions' ),
373 'permission_callback' => array( $this, 'get_rest_permissions_check' ),
374 ),
375 )
376 );
377 register_rest_route(
378 $this->namespace,
379 '/' . $this->rest_base . '/tools/destroy-sessions-status/(?P<destroy_id>[a-zA-Z0-9_.\-]+)',
380 array(
381 array(
382 'methods' => WP_REST_Server::READABLE,
383 'callback' => array( $this, 'get_destroy_sessions_status' ),
384 'permission_callback' => array( $this, 'get_rest_permissions_check' ),
385 'args' => array(
386 'destroy_id' => array(
387 'required' => true,
388 'type' => 'string',
389 ),
390 ),
391 ),
392 )
393 );
394 register_rest_route(
395 $this->namespace,
396 '/' . $this->rest_base . '/tools/renew-connections',
397 array(
398 array(
399 'methods' => WP_REST_Server::CREATABLE,
400 'callback' => array( $this, 'renew_connections' ),
401 'permission_callback' => array( $this, 'get_rest_permissions_check' ),
402 ),
403 )
404 );
405 register_rest_route(
406 $this->namespace,
407 '/' . $this->rest_base . '/tools/renew-connections-status/(?P<renew_id>[a-zA-Z0-9_.\-]+)',
408 array(
409 array(
410 'methods' => WP_REST_Server::READABLE,
411 'callback' => array( $this, 'get_renew_connection_status' ),
412 'permission_callback' => array( $this, 'get_rest_permissions_check' ),
413 'args' => array(
414 'renew_id' => array(
415 'required' => true,
416 'type' => 'string',
417 ),
418 ),
419 ),
420 )
421 );
422 register_rest_route(
423 $this->namespace,
424 '/' . $this->rest_base . '/tools/disconnect-all-sites',
425 array(
426 array(
427 'methods' => WP_REST_Server::CREATABLE,
428 'callback' => array( $this, 'disconnect_all_sites' ),
429 'permission_callback' => array( $this, 'get_rest_permissions_check' ),
430 ),
431 )
432 );
433 register_rest_route(
434 $this->namespace,
435 '/' . $this->rest_base . '/tools/disconnect-all-sites-status/(?P<disconnect_id>[a-zA-Z0-9_.\-]+)',
436 array(
437 array(
438 'methods' => WP_REST_Server::READABLE,
439 'callback' => array( $this, 'get_disconnect_status' ),
440 'permission_callback' => array( $this, 'get_rest_permissions_check' ),
441 'args' => array(
442 'disconnect_id' => array(
443 'required' => true,
444 'type' => 'string',
445 ),
446 ),
447 ),
448 )
449 );
450 register_rest_route(
451 $this->namespace,
452 '/' . $this->rest_base . '/tools/clear-activation-data',
453 array(
454 array(
455 'methods' => WP_REST_Server::CREATABLE,
456 'callback' => array( $this, 'clear_activation_data' ),
457 'permission_callback' => array( $this, 'get_rest_permissions_check' ),
458 ),
459 )
460 );
461 register_rest_route(
462 $this->namespace,
463 '/' . $this->rest_base . '/tools/restore-info-messages',
464 array(
465 array(
466 'methods' => WP_REST_Server::CREATABLE,
467 'callback' => array( $this, 'restore_info_messages' ),
468 'permission_callback' => array( $this, 'get_rest_permissions_check' ),
469 ),
470 )
471 );
472 }
473
474 /**
475 * Get all general settings.
476 *
477 * @param WP_REST_Request $request Full details about the request.
478 *
479 * @return WP_Error|WP_REST_Response
480 */
481 public function get_general_settings( $request ) { // phpcs:ignore -- NOSONAR - complex.
482 // Get general settings data.
483 $settings = $this->get_general_settings_data();
484
485 // Response data by allowed fields.
486 return rest_ensure_response(
487 array(
488 'success' => 1,
489 'data' => $this->filter_response_data_by_allowed_fields( $settings, 'view' ),
490 )
491 );
492 }
493
494 /**
495 * Update general settings.
496 *
497 * @param WP_REST_Request $request Full details about the request.
498 *
499 * @uses MainWP_Utility::update_option()
500 *
501 * @return WP_Error|WP_REST_Response
502 */
503 public function update_general_settings( $request ) { // phpcs:ignore -- NOSONAR - complex.
504
505 // Check content type.
506 $content_type = $this->validate_content_type( $request );
507 if ( is_wp_error( $content_type ) ) {
508 return $content_type;
509 }
510
511 // Get request body.
512 $body = $this->get_request_body( $request );
513 if ( is_wp_error( $body ) ) {
514 return $body;
515 }
516
517 // Get current user id.
518 $user_id = $this->get_user_id();
519 if ( is_wp_error( $user_id ) ) {
520 return $user_id;
521 }
522
523 try {
524 // Hepper function to update if present.
525 $update_if_present = function ( $key, $option_name, $cast = null ) use ( $body ) {
526 return $this->update_option_if_present( $body, $key, $option_name, $cast );
527 };
528
529 // Hepper function to update if present.
530 $update_use_option = function ( $key, $option_name, $cast = null ) use ( $body, $user_id ) {
531 if ( array_key_exists( $key, $body ) ) {
532 $val = $body[ $key ];
533 $val = $this->cast_field_value( $val, $cast );
534 if ( 'mainwp_widgets' === $key ) {
535 $show_widgets = get_user_option( 'mainwp_settings_show_widgets' );
536 $val = array_replace( $show_widgets, (array) $val );
537 }
538 update_user_option( $user_id, $option_name, $val, true );
539 }
540 };
541
542 // Update option setting.
543 $update_if_present( 'time_daily_update', 'mainwp_timeDailyUpdate', 'string' );
544 $update_if_present( 'frequency_daily_update', 'mainwp_frequencyDailyUpdate', 'int' );
545 $update_if_present( 'date_format', 'date_format', 'string' );
546 $update_if_present( 'time_format', 'time_format', 'string' );
547 $update_if_present( 'timezone_string', 'gmt_offset', 'string' );
548 $update_if_present( 'hide_update_everything', 'mainwp_hide_update_everything', 'int' );
549 $update_if_present( 'plugin_automatic_daily_update', 'mainwp_pluginAutomaticDailyUpdate', 'int' );
550 $update_if_present( 'theme_automatic_daily_update', 'mainwp_themeAutomaticDailyUpdate', 'int' );
551 $update_if_present( 'trans_automatic_daily_update', 'mainwp_transAutomaticDailyUpdate', 'int' );
552 $update_if_present( 'automatic_daily_update', 'mainwp_automaticDailyUpdate', 'int' );
553 $update_if_present( 'frequency_auto_update', 'mainwp_frequency_AutoUpdate', 'string' );
554 $update_if_present( 'time_auto_update', 'mainwp_time_AutoUpdate', 'string' );
555 $update_if_present( 'show_language_updates', 'mainwp_show_language_updates', 'int' );
556 $update_if_present( 'disable_update_confirmations', 'mainwp_disable_update_confirmations', 'int' );
557 $update_if_present( 'check_http_response', 'mainwp_check_http_response', 'int' );
558 $update_if_present( 'check_http_response_method', 'mainwp_check_http_response_method', 'string' );
559 $update_if_present( 'backup_before_upgrade', 'mainwp_backup_before_upgrade', 'int' );
560 $update_if_present( 'backup_before_upgrade_days', 'mainwp_backup_before_upgrade_days', 'int' );
561 $update_if_present( 'numberdays_outdate_plugin_theme', 'mainwp_numberdays_Outdate_Plugin_Theme', 'int' );
562 $update_if_present( 'dayinweek_auto_update', 'mainwp_dayinweek_AutoUpdate', 'int' );
563 $update_if_present( 'dayinmonth_auto_update', 'mainwp_dayinmonth_AutoUpdate', 'int' );
564 $update_if_present( 'delay_autoupdate', 'mainwp_delay_autoupdate', 'int' );
565
566 // Update backup settings.
567 $update_if_present( 'mainwp_primary_backup', 'mainwp_primaryBackup', 'string' );
568 $update_if_present( 'mainwp_enable_legacy_backup_feature', 'mainwp_enableLegacyBackupFeature', 'int' );
569 $update_if_present( 'mainwp_backups_on_server', 'mainwp_backupsOnServer', 'string' );
570 $update_if_present( 'mainwp_backup_on_external_sources', 'mainwp_backupOnExternalSources', 'string' );
571 $update_if_present( 'mainwp_archive_format', 'mainwp_archiveFormat', 'string' );
572 $update_if_present( 'mainwp_notification_on_backup_fail', 'mainwp_notificationOnBackupFail', 'int' );
573 $update_if_present( 'mainwp_notification_on_backup_start', 'mainwp_notificationOnBackupStart', 'int' );
574 $update_if_present( 'mainwp_chunked_backup_tasks', 'mainwp_chunkedBackupTasks', 'int' );
575
576 // Update Sidebar.
577 $update_use_option( 'sidebar_position', 'mainwp_sidebarPosition', 'int' );
578 $update_use_option( 'mainwp_widgets', 'mainwp_settings_show_widgets', 'array' );
579
580 // Get general settings data.
581 $settings = $this->get_general_settings_data();
582 } catch ( \Exception $e ) {
583 do_action( 'mainwp_debug_log', 'Update general settings error: ' . $e->getMessage() );
584 return new WP_Error(
585 'rest_invalid_param',
586 /* translators: %s: Error message */ sprintf( __( 'Update general settings error: %s', 'mainwp' ), $e->getMessage() ),
587 array( 'status' => 500 )
588 );
589 }
590
591 return rest_ensure_response(
592 array(
593 'success' => 1,
594 'message' => esc_html__( 'General settings updated successfully.', 'mainwp' ),
595 'data' => $this->filter_response_data_by_allowed_fields( $settings, 'edit' ),
596 )
597 );
598 }
599
600 /**
601 * Get all advanced settings.
602 *
603 * @param WP_REST_Request $request Full details about the request.
604 *
605 * @return WP_Error|WP_REST_Response
606 */
607 public function get_advanced_settings( $request ) { // phpcs:ignore -- NOSONAR - complex.
608 // Get advanced settings data.
609 $settings = $this->get_advanced_settings_data();
610
611 return rest_ensure_response(
612 array(
613 'success' => 1,
614 'data' => $this->filter_response_data_by_allowed_fields( $settings, 'advanced_view', 'advanced_edit' ),
615 )
616 );
617 }
618
619 /**
620 * Update advanced settings.
621 *
622 * @param WP_REST_Request $request Full details about the request.
623 *
624 * @uses MainWP_Utility::update_option()
625 * @uses MainWP_System_Utility::get_open_ssl_sign_algos()
626 *
627 * @return WP_Error|WP_REST_Response
628 */
629 public function update_advanced_settings( $request ) { // phpcs:ignore -- NOSONAR - long method.
630 // Check content type.
631 $content_type = $this->validate_content_type( $request );
632 if ( is_wp_error( $content_type ) ) {
633 return $content_type;
634 }
635
636 // Get request body.
637 $body = $this->get_request_body( $request );
638 if ( is_wp_error( $body ) ) {
639 return $body;
640 }
641
642 try {
643 // Hepper function to update if present.
644 $update_if_present = function ( $key, $option_name, $cast = null ) use ( $body ) {
645 return $this->update_option_if_present( $body, $key, $option_name, $cast );
646 };
647
648 // Update option setting.
649 $update_if_present( 'mainwp_maximum_requests', 'mainwp_maximumRequests', 'int' );
650 $update_if_present( 'mainwp_minimum_delay', 'mainwp_minimumDelay', 'int' );
651 $update_if_present( 'mainwp_maximum_ip_requests', 'mainwp_maximumIPRequests', 'int' );
652 $update_if_present( 'mainwp_minimum_ip_delay', 'mainwp_minimumIPDelay', 'int' );
653 $update_if_present( 'mainwp_chunksitesnumber', 'mainwp_chunksitesnumber', 'int' );
654 $update_if_present( 'mainwp_chunksleepinterval', 'mainwp_chunksleepinterval', 'int' );
655 $update_if_present( 'mainwp_maximum_sync_requests', 'mainwp_maximumSyncRequests', 'int' );
656 $update_if_present( 'mainwp_maximum_install_update_requests', 'mainwp_maximumInstallUpdateRequests', 'int' );
657 $update_if_present( 'mainwp_maximum_uptime_monitoring_requests', 'mainwp_maximum_uptime_monitoring_requests', 'int' );
658 $update_if_present( 'mainwp_optimize', 'mainwp_optimize', 'int' );
659 $update_if_present( 'mainwp_wp_cron', 'mainwp_wp_cron', 'int' );
660 $update_if_present( 'mainwp_ssl_verify_certificate', 'mainwp_sslVerifyCertificate', 'int' );
661 $update_if_present( 'mainwp_verify_connection_method', 'mainwp_verify_connection_method', 'int' );
662 $update_if_present( 'mainwp_force_use_ipv4', 'mainwp_forceUseIPv4', 'int' );
663
664 // Update sync data.
665 if ( isset( $body['sync_data'] ) ) {
666 $syncs_data = $this->safe_json_decode( get_option( 'mainwp_settings_sync_data', array() ) ?? '' );
667 $val_sync = array_replace( $syncs_data, (array) $body['sync_data'] );
668 MainWP_Utility::update_option( 'mainwp_settings_sync_data', wp_json_encode( $val_sync ) );
669 }
670
671 // Update signature algorithm.
672 if ( isset( $body['mainwp_connect_signature_algo'] ) ) {
673 $sign_algs = MainWP_System_Utility::get_open_ssl_sign_algos();
674 $val_signature = array_search( $body['mainwp_connect_signature_algo'], $sign_algs, true );
675 if ( false === $val_signature ) {
676 $val_signature = defined( 'OPENSSL_ALGO_SHA256' ) ? (int) OPENSSL_ALGO_SHA256 : 1;
677 }
678
679 MainWP_Utility::update_option( 'mainwp_connect_signature_algo', $val_signature );
680 }
681
682 // Get general settings data.
683 $settings = $this->get_advanced_settings_data();
684 } catch ( \Exception $e ) {
685 do_action( 'mainwp_debug_log', 'Update advanced settings error: ' . $e->getMessage() );
686 return new WP_Error(
687 'rest_invalid_param',
688 /* translators: %s: Error message */ sprintf( __( 'Update advanced settings error: %s', 'mainwp' ), $e->getMessage() ),
689 array( 'status' => 500 )
690 );
691 }
692
693 return rest_ensure_response(
694 array(
695 'success' => 1,
696 'message' => esc_html__( 'General settings updated successfully.', 'mainwp' ),
697 'data' => $this->filter_response_data_by_allowed_fields( $settings, 'advanced_edit' ),
698 )
699 );
700 }
701
702 /**
703 * Get all monitoring settings.
704 *
705 * @param WP_REST_Request $request Full details about the request.
706 *
707 * @return WP_Error|WP_REST_Response
708 */
709 public function get_monitoring_settings( $request ) { // phpcs:ignore -- NOSONAR - complex.
710 // Get monitoring settings data.
711 $settings = $this->get_monitoring_settings_data();
712
713 return rest_ensure_response(
714 array(
715 'success' => 1,
716 'data' => $this->filter_response_data_by_allowed_fields( $settings, 'monitoring_view' ),
717 )
718 );
719 }
720
721 /**
722 * Update monitoring settings.
723 *
724 * @param WP_REST_Request $request Full details about the request.
725 *
726 * @uses MainWP_Uptime_Monitoring_Handle::get_global_monitoring_settings()
727 * @uses MainWP_Uptime_Monitoring_Handle::update_uptime_global_settings()
728 *
729 * @return WP_Error|WP_REST_Response
730 */
731 public function update_monitoring_settings( $request ) { // phpcs:ignore -- NOSONAR - long method.
732 // Check content type.
733 $content_type = $this->validate_content_type( $request );
734 if ( is_wp_error( $content_type ) ) {
735 return $content_type;
736 }
737
738 // Get request body.
739 $body = $this->get_request_body( $request );
740 if ( is_wp_error( $body ) ) {
741 return $body;
742 }
743
744 // Get current settings.
745 $current_settings = MainWP_Uptime_Monitoring_Handle::get_global_monitoring_settings();
746 $updated_settings = $current_settings;
747
748 // Process setting.
749 if ( isset( $body['mainwp_uptime_monitoring_active'] ) ) {
750 $updated_settings['active'] = $body['mainwp_uptime_monitoring_active'] ? 1 : 0;
751 }
752 if ( isset( $body['mainwp_uptime_monitoring_down_confirmation_check'] ) ) {
753 $updated_settings['maxretries'] = $body['mainwp_uptime_monitoring_down_confirmation_check'];
754 }
755 if ( isset( $body['mainwp_uptime_monitoring_up_status_codes'] ) ) {
756 $updated_settings['up_status_codes'] = implode( ',', $body['mainwp_uptime_monitoring_up_status_codes'] );
757 }
758 if ( isset( $body['mainwp_uptime_monitoring_interval'] ) ) {
759 $interval_values = MainWP_Uptime_Monitoring_Edit::get_interval_values( false );
760 $interval = array_search( $body['mainwp_uptime_monitoring_interval'], $interval_values, true );
761 // An empty string passes the enum validator, so an unmatched label has to be rejected here, before anything is saved.
762 if ( false === $interval ) {
763 return new WP_Error(
764 'rest_invalid_param',
765 __( 'Invalid mainwp_uptime_monitoring_interval value.', 'mainwp' ),
766 array( 'status' => 400 )
767 );
768 }
769 $updated_settings['interval'] = $interval;
770 }
771 if ( isset( $body['mainwp_uptime_monitoring_keyword'] ) ) {
772 $updated_settings['keyword'] = $body['mainwp_uptime_monitoring_keyword'];
773 }
774 if ( isset( $body['mainwp_uptime_monitoring_method'] ) ) {
775 $updated_settings['method'] = $body['mainwp_uptime_monitoring_method'];
776 }
777 if ( isset( $body['mainwp_uptime_monitoring_timeout'] ) ) {
778 $timeout_values = MainWP_Uptime_Monitoring_Edit::get_timeout_values( false );
779 $timeout = array_search( $body['mainwp_uptime_monitoring_timeout'], $timeout_values, true );
780 // An empty string passes the enum validator, so an unmatched label has to be rejected here, before anything is saved.
781 if ( false === $timeout ) {
782 return new WP_Error(
783 'rest_invalid_param',
784 __( 'Invalid mainwp_uptime_monitoring_timeout value.', 'mainwp' ),
785 array( 'status' => 400 )
786 );
787 }
788 $updated_settings['timeout'] = $timeout;
789 }
790 if ( isset( $body['mainwp_uptime_monitoring_type'] ) ) {
791 $updated_settings['type'] = $body['mainwp_uptime_monitoring_type'];
792 }
793
794 if ( isset( $body['mainwp_uptime_monitoring_bypass_cache'] ) ) {
795 $updated_settings['bypass_cache'] = $body['mainwp_uptime_monitoring_bypass_cache'] ? 1 : 0;
796 }
797
798 // Save monitoring the updated settings.
799 $updated_settings = apply_filters( 'mainwp_uptime_monitoring_update_global_settings', $updated_settings );
800 MainWP_Uptime_Monitoring_Handle::update_uptime_global_settings( $updated_settings );
801
802 // Save Health Monitoring.
803 if ( isset( $body['mainwp_disable_sites_health_monitoring'] ) ) {
804 update_option( 'mainwp_disableSitesHealthMonitoring', (int) $body['mainwp_disable_sites_health_monitoring'] );
805 }
806 if ( isset( $body['mainwp_sitehealth_threshold'] ) ) {
807 update_option( 'mainwp_sitehealthThreshold', (int) $body['mainwp_sitehealth_threshold'] );
808 }
809
810 return rest_ensure_response(
811 array(
812 'success' => 1,
813 'data' => $this->filter_response_data_by_allowed_fields( $this->get_monitoring_settings_data(), 'monitoring_view' ),
814 )
815 );
816 }
817
818 /**
819 * Get all email settings.
820 *
821 * @param WP_REST_Request $request Full details about the request.
822 *
823 * @uses MainWP_Notification_Settings::get_notification_types()
824 * @uses MainWP_Notification_Settings::get_default_emails_fields()
825 *
826 * @return WP_Error|WP_REST_Response
827 */
828 public function get_emails_settings( $request ) { // phpcs:ignore -- NOSONAR - complex.
829 // Get notification email types.
830 $notification_emails = MainWP_Notification_Settings::get_notification_types();
831 // Get email settings.
832 $emails_settings = get_option( 'mainwp_settings_notification_emails' );
833 if ( ! is_array( $emails_settings ) ) {
834 $emails_settings = array();
835 }
836
837 $settings = array();
838 if ( ! empty( $notification_emails ) ) {
839 foreach ( $notification_emails as $type => $name ) {
840 $options = isset( $emails_settings[ $type ] ) ? $emails_settings[ $type ] : array();
841 $default = MainWP_Notification_Settings::get_default_emails_fields( $type, '', true );
842 $options = array_merge( $default, $options );
843 $record = array(
844 'type' => $type,
845 'heading' => $options['heading'],
846 'subject' => $options['subject'],
847 'recipients' => $options['recipients'],
848 'disable' => $options['disable'],
849 );
850 $settings[] = $this->filter_response_data_by_allowed_fields( $record, 'email_view', 'email_edit' );
851 }
852 }
853
854 return rest_ensure_response(
855 array(
856 'success' => 1,
857 'data' => $settings,
858 )
859 );
860 }
861
862 /**
863 * Update email settings.
864 *
865 * @param WP_REST_Request $request Full details about the request.
866 *
867 * @uses MainWP_Utility::update_option()
868 *
869 * @return WP_Error|WP_REST_Response
870 */
871 public function update_emails_settings( $request ) { // phpcs:ignore -- NOSONAR - complex.
872 // Check content type.
873 $content_type = $this->validate_content_type( $request );
874 if ( is_wp_error( $content_type ) ) {
875 return $content_type;
876 }
877
878 // Get request body.
879 $body = $this->get_request_body( $request );
880 if ( is_wp_error( $body ) ) {
881 return $body;
882 }
883
884 // Get mail type.
885 $setting = $request->get_param( 'mail_type' );
886 if ( empty( $setting ) ) {
887 return new WP_Error( 'invalid_mail_type', __( 'Mail type is not exist.', 'mainwp' ), array( 'status' => 400 ) );
888 }
889
890 $type = $setting['type'] ?? '';
891 if ( empty( $type ) ) {
892 return new WP_Error( 'invalid_mail_type', __( 'Invalid email type.', 'mainwp' ), array( 'status' => 400 ) );
893 }
894
895 // Get email settings.
896 $emails_settings = get_option( 'mainwp_settings_notification_emails' );
897 if ( ! is_array( $emails_settings ) ) {
898 $emails_settings = array();
899 }
900
901 // Update email settings.
902 $emails_settings[ $type ]['heading'] = ! empty( $body['heading'] ) ? $body['heading'] : $setting['heading'];
903 $emails_settings[ $type ]['recipients'] = ! empty( $body['recipients'] ) ? $body['recipients'] : $setting['recipients'];
904 $emails_settings[ $type ]['subject'] = ! empty( $body['subject'] ) ? $body['subject'] : $setting['subject'];
905 $emails_settings[ $type ]['disable'] = ! empty( $body['disable'] ) ? $body['disable'] : $setting['disable'];
906 MainWP_Utility::update_option( 'mainwp_settings_notification_emails', $emails_settings );
907
908 return rest_ensure_response(
909 array(
910 'success' => 1,
911 'message' => __( 'Email settings updated successfully.', 'mainwp' ),
912 'data' => $this->filter_response_data_by_allowed_fields( $emails_settings[ $type ], 'email_edit' ),
913 )
914 );
915 }
916
917 /**
918 * Get all cost tracker settings.
919 *
920 * @param WP_REST_Request $request Full details about the request.
921 *
922 * @uses Cost_Tracker_Utility::get_instance()->get_option()
923 * @uses Cost_Tracker_Utility::default_currency_settings()
924 * @uses Cost_Tracker_Admin::get_product_types()
925 * @uses Cost_Tracker_Admin::get_product_colors()
926 * @uses Cost_Tracker_Admin::get_product_type_icons()
927 *
928 * @return WP_Error|WP_REST_Response
929 */
930 public function get_cost_tracker_settings( $request ) { // phpcs:ignore -- NOSONAR - complex.
931 // Get currency settings.
932 $selected_currency = Cost_Tracker_Utility::get_instance()->get_option( 'currency', 'USD' );
933 $currency_format = Cost_Tracker_Utility::get_instance()->get_option( 'currency_format', array() );
934
935 // Get default currency format.
936 $default = Cost_Tracker_Utility::default_currency_settings();
937 $currency_format = array_merge( $default, $currency_format );
938
939 $currency_position = $currency_format['currency_position'];
940 $thousand_separator = $currency_format['thousand_separator'];
941 $decimal_separator = $currency_format['decimal_separator'];
942 $decimals = $currency_format['decimals'];
943
944 // Get custom payment methods.
945 $custom_payment_methods = Cost_Tracker_Utility::get_instance()->get_option( 'custom_payment_methods', array(), true );
946
947 // Get custom product types.
948 $custom_product_types = Cost_Tracker_Admin::get_product_types();
949
950 // Get product colors.
951 $product_colors = Cost_Tracker_Admin::get_product_colors();
952
953 // Get product icons.
954 $product_types_icons = Cost_Tracker_Admin::get_product_type_icons();
955
956 $product_categories = array();
957 if ( ! empty( $product_types_icons ) && is_array( $product_types_icons ) ) {
958 foreach ( $product_types_icons as $slug => $icon ) {
959 $product_categories[] = array(
960 'slug' => $slug,
961 'title' => isset( $custom_product_types[ $slug ] ) ? $custom_product_types[ $slug ] : '',
962 'icon' => $icon,
963 'color' => isset( $product_colors[ $slug ] ) ? $product_colors[ $slug ] : '#34424D',
964 );
965 }
966 }
967
968 $settings = array(
969 'currency' => $selected_currency,
970 'currency_position' => $currency_position,
971 'thousand_separator' => $thousand_separator,
972 'decimal_separator' => $decimal_separator,
973 'decimals' => $decimals,
974 'product_categories' => $product_categories,
975 'payment_methods' => $custom_payment_methods,
976 );
977
978 return rest_ensure_response(
979 array(
980 'success' => 1,
981 'data' => $this->filter_response_data_by_allowed_fields( $settings, 'cost_tracker_view' ),
982 )
983 );
984 }
985
986 /**
987 * Edit cost tracker settings.
988 *
989 * @param WP_REST_Request $request Full details about the request.
990 *
991 * @uses Cost_Tracker_Utility::get_instance()->get_all_options()
992 * @uses Cost_Tracker_Utility::get_instance()->save_options()
993 *
994 * @return WP_Error|WP_REST_Response
995 */
996 public function edit_cost_tracker_settings( $request ) {
997 // Check content type.
998 $content_type = $this->validate_content_type( $request );
999 if ( is_wp_error( $content_type ) ) {
1000 return $content_type;
1001 }
1002
1003 // Get request body.
1004 $body = $this->get_request_body( $request );
1005 if ( is_wp_error( $body ) ) {
1006 return $body;
1007 }
1008
1009 // Get all options.
1010 $all_opts = Cost_Tracker_Utility::get_instance()->get_all_options();
1011 $currency_format = $all_opts['currency_format'] ?? array(); // Set old currency format setting.
1012
1013 // Map body to variables.
1014 $all_opts['currency'] = ! empty( $body['currency'] ) ? $body['currency'] : $all_opts['currency'];
1015 $all_opts['currency_format'] = array(
1016 'currency_position' => ! empty( $body['currency_position'] ) ? $body['currency_position'] : $currency_format['currency_position'],
1017 'thousand_separator' => ! empty( $body['thousand_separator'] ) ? $body['thousand_separator'] : $currency_format['thousand_separator'],
1018 'decimal_separator' => ! empty( $body['decimal_separator'] ) ? $body['decimal_separator'] : $currency_format['decimal_separator'],
1019 'decimals' => ! empty( $body['decimals'] ) ? $body['decimals'] : $currency_format['decimals'],
1020 );
1021
1022 // Save options.
1023 Cost_Tracker_Utility::get_instance()->save_options( $all_opts );
1024
1025 return rest_ensure_response(
1026 array(
1027 'success' => 1,
1028 'message' => __( 'Cost tracker settings updated successfully.', 'mainwp' ),
1029 'data' => array(
1030 'currency' => $all_opts['currency'],
1031 'currency_format' => $all_opts['currency_format'],
1032 ),
1033 )
1034 );
1035 }
1036
1037 /**
1038 * Add cost tracker product type.
1039 *
1040 * @param WP_REST_Request $request Full details about the request.
1041 *
1042 * @uses Cost_Tracker_Utility::get_instance()->get_all_options()
1043 * @uses Cost_Tracker_Utility::get_instance()->save_options()
1044 *
1045 * @return WP_Error|WP_REST_Response
1046 */
1047 public function add_cost_tracker_product_type( $request ) { // phpcs:ignore -- NOSONAR - long method.
1048 $body = $this->get_request_body( $request );
1049
1050 if ( is_wp_error( $body ) ) {
1051 return $body;
1052 }
1053
1054 // Map body to variables.
1055 $title = $body['title'];
1056 $slug = sanitize_title( $title );
1057 $color = ! empty( $body['color'] ) ? $body['color'] : '#34424D';
1058 $icon = ! empty( $body['icon'] ) ? $body['icon'] : 'deficon:folder open';
1059
1060 // Map product type.
1061 $all_opts = Cost_Tracker_Utility::get_instance()->get_all_options();
1062 $custom_product_types = $this->safe_json_decode( $all_opts['custom_product_types'] ?? '' );
1063
1064 // Check if product type duplicated.
1065 if ( isset( $custom_product_types[ $slug ] ) ) {
1066 return new WP_Error( 'duplicate_title', __( 'Duplicate product type. Please choose another one.', 'mainwp' ), array( 'status' => 400 ) );
1067 }
1068 // Map product type.
1069 $custom_product_types[ $slug ] = $title;
1070 $all_opts['custom_product_types'] = wp_json_encode( $custom_product_types );
1071
1072 // Map product type color.
1073 $product_types_colors = $this->safe_json_decode( $all_opts['product_types_colors'] ?? '' );
1074 $product_types_colors[ $slug ] = $color;
1075 $all_opts['product_types_colors'] = wp_json_encode( $product_types_colors );
1076
1077 // Map product type icon.
1078 $product_types_icons = $this->safe_json_decode( $all_opts['product_types_icons'] ?? '' );
1079 $product_types_icons[ $slug ] = $icon;
1080 $all_opts['product_types_icons'] = wp_json_encode( $product_types_icons );
1081
1082 // Save options.
1083 Cost_Tracker_Utility::get_instance()->save_options( $all_opts );
1084 return rest_ensure_response(
1085 array(
1086 'success' => 1,
1087 'message' => __( 'Product type added successfully.', 'mainwp' ),
1088 'data' => array(
1089 $slug => array(
1090 'title' => $title,
1091 'color' => $color,
1092 'icon' => $icon,
1093 ),
1094 ),
1095 )
1096 );
1097 }
1098
1099 /**
1100 * Update cost tracker product type.
1101 *
1102 * @param WP_REST_Request $request Full details about the request.
1103 *
1104 * @uses Cost_Tracker_Utility::get_instance()->get_all_options()
1105 * @uses Cost_Tracker_Utility::get_instance()->save_options()
1106 *
1107 * @return WP_Error|WP_REST_Response
1108 */
1109 public function update_cost_tracker_product_type( $request ) { // phpcs:ignore -- NOSONAR - long method.
1110 // Check content type.
1111 $content_type = $this->validate_content_type( $request );
1112 if ( is_wp_error( $content_type ) ) {
1113 return $content_type;
1114 }
1115
1116 // Get request body.
1117 $body = $this->get_request_body( $request );
1118 if ( is_wp_error( $body ) ) {
1119 return $body;
1120 }
1121
1122 $slug = $request->get_param( 'slug' );
1123 if ( empty( $slug ) ) {
1124 return new WP_Error( 'invalid_slug', __( 'Invalid product type slug.', 'mainwp' ), array( 'status' => 400 ) );
1125 }
1126
1127 // Default Product Type.
1128 $default_product_types = Cost_Tracker_Admin::get_default_product_types();
1129
1130 // Map body to variables.
1131 $title = $body['title'];
1132 $color = ! empty( $body['color'] ) ? $body['color'] : '#34424D';
1133 $icon = ! empty( $body['icon'] ) ? $body['icon'] : 'deficon:folder open';
1134
1135 // Cannot change title if it's a default product type.
1136 if ( array_key_exists( $slug, $default_product_types ) && $title !== $default_product_types[ $slug ] ) {
1137 return new WP_Error( 'invalid_title', __( 'Cannot change title of default product type.', 'mainwp' ), array( 'status' => 400 ) );
1138 }
1139
1140 // Map product type.
1141 $all_opts = Cost_Tracker_Utility::get_instance()->get_all_options();
1142 $custom_product_types = $this->safe_json_decode( $all_opts['custom_product_types'] ?? '' );
1143 $custom_product_types[ $slug ] = $title;
1144 $all_opts['custom_product_types'] = wp_json_encode( $custom_product_types );
1145
1146 // Map product type color.
1147 $product_types_colors = $this->safe_json_decode( $all_opts['product_types_colors'] ?? '' );
1148 $product_types_colors[ $slug ] = $color;
1149 $all_opts['product_types_colors'] = wp_json_encode( $product_types_colors );
1150
1151 // Map product type icon.
1152 $product_types_icons = $this->safe_json_decode( $all_opts['product_types_icons'] ?? '' );
1153 $product_types_icons[ $slug ] = $icon;
1154 $all_opts['product_types_icons'] = wp_json_encode( $product_types_icons );
1155
1156 // Save options.
1157 Cost_Tracker_Utility::get_instance()->save_options( $all_opts );
1158 return rest_ensure_response(
1159 array(
1160 'success' => 1,
1161 'message' => __( 'Product type updated successfully.', 'mainwp' ),
1162 'data' => array(
1163 $slug => array(
1164 'title' => $title,
1165 'color' => $color,
1166 'icon' => $icon,
1167 ),
1168 ),
1169 )
1170 );
1171 }
1172
1173 /**
1174 * Delete cost tracker product type.
1175 *
1176 * @param WP_REST_Request $request Full details about the request.
1177 *
1178 * @uses Cost_Tracker_Utility::get_instance()->get_all_options()
1179 * @uses Cost_Tracker_Utility::get_instance()->save_options()
1180 *
1181 * @return WP_Error|WP_REST_Response
1182 */
1183 public function delete_cost_tracker_product_type( $request ) { // phpcs:ignore -- NOSONAR - complex.
1184 $slug = $request->get_param( 'slug' );
1185
1186 if ( empty( $slug ) ) {
1187 return new WP_Error( 'invalid_slug', __( 'Invalid product type slug.', 'mainwp' ), array( 'status' => 400 ) );
1188 }
1189
1190 // Default Product Type.
1191 $default_product_types = Cost_Tracker_Admin::get_default_product_types();
1192 // Cannot delete a default product type.
1193 if ( array_key_exists( $slug, $default_product_types ) ) {
1194 return new WP_Error( 'invalid_title', __( 'Cannot delete of default product type.', 'mainwp' ), array( 'status' => 400 ) );
1195 }
1196
1197 // Get all options.
1198 $all_opts = Cost_Tracker_Utility::get_instance()->get_all_options();
1199 $custom_product_types = $this->safe_json_decode( $all_opts['custom_product_types'] ?? '' );
1200 $product_types_colors = $this->safe_json_decode( $all_opts['product_types_colors'] ?? '' );
1201 $product_types_icons = $this->safe_json_decode( $all_opts['product_types_icons'] ?? '' );
1202
1203 // Check if product type exists.
1204 if ( ! isset( $custom_product_types[ $slug ] ) ) {
1205 return new WP_Error( 'invalid_slug', __( 'Product type does not exist.', 'mainwp' ), array( 'status' => 404 ) );
1206 }
1207
1208 // Delete product type.
1209 unset( $custom_product_types[ $slug ] );
1210 unset( $product_types_colors[ $slug ] );
1211 unset( $product_types_icons[ $slug ] );
1212
1213 $all_opts['custom_product_types'] = wp_json_encode( $custom_product_types );
1214 $all_opts['product_types_colors'] = wp_json_encode( $product_types_colors );
1215 $all_opts['product_types_icons'] = wp_json_encode( $product_types_icons );
1216
1217 // Save options.
1218 Cost_Tracker_Utility::get_instance()->save_options( $all_opts );
1219
1220 return rest_ensure_response(
1221 array(
1222 'success' => 1,
1223 'message' => __( 'Product type deleted successfully.', 'mainwp' ),
1224 )
1225 );
1226 }
1227
1228 /**
1229 * Add cost tracker payment method.
1230 *
1231 * @param WP_REST_Request $request Full details about the request.
1232 *
1233 * @uses Cost_Tracker_Utility::get_instance()->get_option()
1234 * @uses Cost_Tracker_Utility::get_instance()->update_option()
1235 *
1236 * @return WP_Error|WP_REST_Response
1237 */
1238 public function add_cost_tracker_payment_method( $request ) { // phpcs:ignore -- NOSONAR - complex.
1239 // Get request body.
1240 $body = $this->get_request_body( $request );
1241 if ( is_wp_error( $body ) ) {
1242 return $body;
1243 }
1244
1245 $title = $body['title'];
1246 $slug = sanitize_title( $title );
1247
1248 // Get all options.
1249 $all_opts = Cost_Tracker_Utility::get_instance()->get_all_options();
1250
1251 // Get payment methods.
1252 $payment_methods = $this->safe_json_decode( $all_opts['custom_payment_methods'] ?? '' );
1253
1254 if ( isset( $payment_methods[ $slug ] ) ) {
1255 return new WP_Error( 'duplicate_title', __( 'Duplicate payment method. Please choose another one.', 'mainwp' ), array( 'status' => 400 ) );
1256 }
1257
1258 // Save payment method.
1259 $payment_methods[ $slug ] = $title;
1260 $all_opts['custom_payment_methods'] = wp_json_encode( $payment_methods );
1261
1262 // Save options.
1263 Cost_Tracker_Utility::get_instance()->save_options( $all_opts );
1264
1265 return rest_ensure_response(
1266 array(
1267 'success' => 1,
1268 'message' => __( 'Payment method added successfully.', 'mainwp' ),
1269 'data' => array(
1270 $slug => $title,
1271 ),
1272 )
1273 );
1274 }
1275
1276 /**
1277 * Edit cost tracker payment method.
1278 *
1279 * @param WP_REST_Request $request Full details about the request.
1280 *
1281 * @uses Cost_Tracker_Utility::get_instance()->get_all_options()
1282 * @uses Cost_Tracker_Utility::get_instance()->update_option()
1283 *
1284 * @return WP_Error|WP_REST_Response
1285 */
1286 public function update_cost_tracker_payment_method( $request ) { // phpcs:ignore -- NOSONAR - complex.
1287 // Check content type.
1288 $content_type = $this->validate_content_type( $request );
1289 if ( is_wp_error( $content_type ) ) {
1290 return $content_type;
1291 }
1292
1293 // Get request body.
1294 $body = $this->get_request_body( $request );
1295 if ( is_wp_error( $body ) ) {
1296 return $body;
1297 }
1298
1299 $slug = $request->get_param( 'slug' );
1300
1301 // Get all options.
1302 $all_opts = Cost_Tracker_Utility::get_instance()->get_all_options();
1303 // Get payment methods.
1304 $payment_methods = $this->safe_json_decode( $all_opts['custom_payment_methods'] ?? '' );
1305 if ( ! isset( $payment_methods[ $slug ] ) ) {
1306 return new WP_Error( 'invalid_slug', __( 'Invalid payment method slug.', 'mainwp' ), array( 'status' => 404 ) );
1307 }
1308
1309 $payment_methods[ $slug ] = $body['title'];
1310 $all_opts['custom_payment_methods'] = wp_json_encode( $payment_methods );
1311 Cost_Tracker_Utility::get_instance()->save_options( $all_opts );
1312
1313 return rest_ensure_response(
1314 array(
1315 'success' => 1,
1316 'message' => __( 'Payment method updated successfully.', 'mainwp' ),
1317 'data' => array(
1318 $slug => $body['title'],
1319 ),
1320 )
1321 );
1322 }
1323
1324 /**
1325 * Delete cost tracker payment method.
1326 *
1327 * @param WP_REST_Request $request Full details about the request.
1328 *
1329 * @uses Cost_Tracker_Utility::get_instance()->get_all_options()
1330 * @uses Cost_Tracker_Utility::get_instance()->update_option()
1331 *
1332 * @return WP_Error|WP_REST_Response
1333 */
1334 public function delete_cost_tracker_payment_method( $request ) { // phpcs:ignore -- NOSONAR - complex.
1335 $slug = $request->get_param( 'slug' );
1336
1337 // Get all options.
1338 $all_opts = Cost_Tracker_Utility::get_instance()->get_all_options();
1339 // Get payment methods.
1340 $payment_methods = $this->safe_json_decode( $all_opts['custom_payment_methods'] ?? '' );
1341 if ( ! isset( $payment_methods[ $slug ] ) ) {
1342 return new WP_Error( 'invalid_slug', __( 'Invalid payment method slug.', 'mainwp' ), array( 'status' => 404 ) );
1343 }
1344
1345 unset( $payment_methods[ $slug ] );
1346 $all_opts['custom_payment_methods'] = wp_json_encode( $payment_methods );
1347 Cost_Tracker_Utility::get_instance()->save_options( $all_opts );
1348
1349 return rest_ensure_response(
1350 array(
1351 'success' => 1,
1352 'message' => __( 'Payment method deleted successfully.', 'mainwp' ),
1353 )
1354 );
1355 }
1356
1357 /**
1358 * Get all dashboard insights settings.
1359 *
1360 * @param WP_REST_Request $request Full details about the request.
1361 *
1362 * @return WP_Error|WP_REST_Response
1363 */
1364 public function get_dashboard_insights_settings( $request ) { // phpcs:ignore -- NOSONAR - complex.
1365 $options = get_option( 'mainwp_module_log_settings', array() );
1366 $settings = array(
1367 'enable_insights_logging' => $options['enabled'] ?? 0,
1368 );
1369
1370 return rest_ensure_response(
1371 array(
1372 'success' => 1,
1373 'data' => $this->filter_response_data_by_allowed_fields( $settings, 'dashboard_insights_view' ),
1374 )
1375 );
1376 }
1377
1378 /**
1379 * Update dashboard insights settings.
1380 *
1381 * @param WP_REST_Request $request Full details about the request.
1382 *
1383 * @return WP_Error|WP_REST_Response
1384 */
1385 public function update_dashboard_insights_settings( $request ) {
1386 // Check content type.
1387 $content_type = $this->validate_content_type( $request );
1388 if ( is_wp_error( $content_type ) ) {
1389 return $content_type;
1390 }
1391
1392 // Get request body.
1393 $body = $this->get_request_body( $request );
1394 if ( is_wp_error( $body ) ) {
1395 return $body;
1396 }
1397
1398 // Get Current settings.
1399 $current_insights_logging = get_option( 'mainwp_module_log_settings', 1 );
1400 $new_insights_logging = $current_insights_logging;
1401 if ( isset( $body['enable_insights_logging'] ) ) {
1402 $new_insights_logging['enabled'] = $body['enable_insights_logging'];
1403 }
1404
1405 // Save settings.
1406 MainWP_Utility::update_option( 'mainwp_module_log_settings', $new_insights_logging );
1407
1408 return rest_ensure_response(
1409 array(
1410 'success' => 1,
1411 'message' => __( 'Dashboard insights settings updated successfully.', 'mainwp' ),
1412 'data' => array(
1413 'enable_insights_logging' => $new_insights_logging['enabled'],
1414 ),
1415 )
1416 );
1417 }
1418
1419 /**
1420 * Get all API backup settings.
1421 *
1422 * @param WP_REST_Request $request Full details about the request.
1423 *
1424 * @return WP_Error|WP_REST_Response
1425 */
1426 public function get_api_backup_settings( $request ) { // phpcs:ignore -- NOSONAR - complex.
1427 // Masked token.
1428 $masked = static function ( $token ) {
1429 $token = (string) $token;
1430 if ( empty( $token ) ) {
1431 return '';
1432 }
1433 return '****' . substr( $token, -4 );
1434 };
1435
1436 // Get all API backup settings.
1437 $defs = $this->get_api_backup_definitions();
1438 $api_backups_data = array();
1439
1440 foreach ( $defs as $slug => $def ) {
1441 $provider = array(
1442 'label' => $def['label'],
1443 'enabled' => (int) get_option( $def['enabled_option'], 0 ),
1444 );
1445
1446 if ( ! empty( $def['options'] ) ) {
1447 foreach ( $def['options'] as $field => $option_key ) {
1448 $provider[ $field ] = get_option( $option_key, '' );
1449 }
1450 }
1451
1452 // Get secrets key.
1453 $secrets = array();
1454 if ( ! empty( $def['secrets'] ) ) {
1455 foreach ( $def['secrets'] as $secret_key => $getter ) {
1456 $value = is_callable( $getter ) ? call_user_func( $getter ) : '';
1457 $secrets[ $secret_key ] = $masked( $value );
1458 }
1459 }
1460 $provider['secrets'] = $secrets;
1461
1462 // Add provider to API backups data.
1463 $api_backups_data[ $slug ] = $provider;
1464 }
1465
1466 return rest_ensure_response(
1467 array(
1468 'success' => 1,
1469 'data' => $this->filter_response_data_by_allowed_fields( array( 'api_backups' => $api_backups_data ), 'api_backups_view' ),
1470 )
1471 );
1472 }
1473
1474 /**
1475 * Update API backup settings.
1476 *
1477 * @param WP_REST_Request $request Full details about the request.
1478 *
1479 * @uses MainWP_Utility::update_option()
1480 * @uses Api_Backups_Utility::get_instance()->update_api_key()
1481 *
1482 * @return WP_Error|WP_REST_Response
1483 */
1484 public function update_api_backup_settings( $request ) {
1485 // Check content type.
1486 $content_type = $this->validate_content_type( $request );
1487 if ( is_wp_error( $content_type ) ) {
1488 return $content_type;
1489 }
1490
1491 // Get request body.
1492 $body = $this->get_request_body( $request );
1493 if ( is_wp_error( $body ) ) {
1494 return $body;
1495 }
1496
1497 // Get API slug data.
1498 $api = $request->get_param( 'api_slug' );
1499 if ( empty( $api ) ) {
1500 return new WP_Error( 'invalid_api_slug', __( 'API backup not exists.', 'mainwp' ), array( 'status' => 400 ) );
1501 }
1502
1503 $updated = array();
1504 // Update option if present.
1505 $update_if_present = function ( $key, $option_name ) use ( $body, &$updated ) {
1506 // Check if key is set and option name is not empty.
1507 if ( isset( $body[ $key ] ) && ! empty( $option_name ) ) {
1508 MainWP_Utility::update_option( $option_name, $body[ $key ] );
1509 $updated[ $key ] = $body[ $key ];
1510 }
1511 };
1512
1513 // Update secrets if present.
1514 $update_secrets_api = function ( $slug, $value, $name = 'api_key' ) use ( &$updated ) { // phpcs:ignore -- NOSONAR - complex.
1515 $success = Api_Backups_Utility::get_instance()->update_api_key( $slug, $value );
1516 if ( $success ) {
1517 $updated[ $name ] = $value;
1518 }
1519 };
1520
1521 // Update api option.
1522 $update_if_present( 'enabled', $api['enabled_option'] ?? '' );
1523 $update_if_present( 'account_email', $api['options']['account_email'] ?? '' );
1524 $update_if_present( 'url', $api['options']['url'] ?? '' );
1525 $update_if_present( 'site_path', $api['options']['site_path'] ?? '' );
1526 $update_if_present( 'username', $api['options']['username'] ?? '' );
1527 $update_if_present( 'company_id', $api['options']['company_id'] ?? '' );
1528
1529 // Update api key or password.
1530 if ( ! empty( $api['slug'] ) ) {
1531 if ( isset( $body['secrets']['api_key'] ) ) {
1532 $update_secrets_api( $api['slug'] ?? '', $body['secrets']['api_key'] ?? '', 'api_key' );
1533 }
1534 if ( isset( $body['password'] ) ) {
1535 $update_secrets_api( $api['slug'] ?? '', $body['password'] ?? '', 'password' );
1536 }
1537 }
1538
1539 if ( ! empty( $api['slug'] ) && 'cloudways' === $api['slug'] && isset( $body['secrets']['access_token'] ) ) {
1540 $success = Api_Backups_Utility::get_instance()->update_api_key( 'cloudways', $body['secrets']['access_token'], 'access_token' );
1541 if ( $success ) {
1542 $updated['access_token'] = $body['secrets']['access_token'];
1543 }
1544 }
1545
1546 // Get secrets key.
1547 $secrets = array( 'api_key', 'access_token', 'password' );
1548 foreach ( $secrets as $secret_key ) {
1549 if ( isset( $updated[ $secret_key ] ) ) {
1550 $updated[ $secret_key ] = MainWP_Credential_Render::value_for_input( false );
1551 }
1552 }
1553
1554 return rest_ensure_response(
1555 array(
1556 'success' => 1,
1557 'message' => __( 'API backup settings updated successfully.', 'mainwp' ),
1558 'data' => $updated,
1559 )
1560 );
1561 }
1562
1563 /**
1564 * Get all tool settings.
1565 *
1566 * @param WP_REST_Request $request Full details about the request.
1567 *
1568 * @return WP_Error|WP_REST_Response
1569 */
1570 public function get_tool_settings( $request ) { // phpcs:ignore -- NOSONAR - complex.
1571 // Get tool settings.
1572 $settings = $this->get_tool_settings_data();
1573
1574 return rest_ensure_response(
1575 array(
1576 'success' => 1,
1577 'data' => $this->filter_response_data_by_allowed_fields( $settings, 'tool_view' ),
1578 )
1579 );
1580 }
1581
1582 /**
1583 * Update tool settings.
1584 *
1585 * @param WP_REST_Request $request Full details about the request.
1586 *
1587 * @return WP_Error|WP_REST_Response
1588 */
1589 public function update_tools_settings( $request ) { // phpcs:ignore -- NOSONAR - complex.
1590 // Check content type.
1591 $content_type = $this->validate_content_type( $request );
1592 if ( is_wp_error( $content_type ) ) {
1593 return $content_type;
1594 }
1595
1596 // Get request body.
1597 $body = $this->get_request_body( $request );
1598 if ( is_wp_error( $body ) ) {
1599 return $body;
1600 }
1601
1602 $user_id = $this->get_user_id();
1603 if ( is_wp_error( $user_id ) ) {
1604 return $user_id;
1605 }
1606
1607 // update theme option.
1608 if ( isset( $body['mainwp_theme'] ) && ! empty( $body['mainwp_theme'] ) ) {
1609 update_user_option( $user_id, 'mainwp_selected_theme', $body['mainwp_theme'] );
1610 }
1611
1612 // Update option.
1613 $this->update_option_if_present( $body, 'mainwp_theme', 'mainwp_selected_theme', 'string' );
1614 $this->update_option_if_present( $body, 'guided_tours', 'mainwp_enable_guided_tours', 'bool' );
1615 $this->update_option_if_present( $body, 'chatbase', 'mainwp_enable_guided_chatbase', 'bool' );
1616 $this->update_option_if_present( $body, 'guided_video', 'mainwp_enable_guided_video', 'bool' );
1617
1618 return rest_ensure_response(
1619 array(
1620 'success' => 1,
1621 'message' => __( 'Tools settings updated successfully.', 'mainwp' ),
1622 'data' => $this->filter_response_data_by_allowed_fields( $this->get_tool_settings_data(), 'tool_view' ),
1623 )
1624 );
1625 }
1626
1627 /**
1628 * Destroy sessions.
1629 *
1630 * @param WP_REST_Request $request Full details about the request.
1631 *
1632 * @return WP_Error|WP_REST_Response
1633 */
1634 public function destroy_sessions( $request ) {
1635 $websites = $this->get_websites();
1636 if ( is_wp_error( $websites ) ) {
1637 return $websites;
1638 }
1639
1640 $destroy_id = uniqid( 'destroy_', true );
1641 $websites = array_column( $websites, 'id' );
1642 set_transient(
1643 "mainwp_tool_destroy_job_{$destroy_id}",
1644 array(
1645 'status' => 'pending',
1646 'total' => count( $websites ),
1647 'processed' => 0,
1648 'failed' => 0,
1649 'created_at' => time(),
1650 'websites' => $websites,
1651 ),
1652 DAY_IN_SECONDS
1653 );
1654
1655 // Schedule background task.
1656 if ( function_exists( 'as_schedule_single_action' ) ) {
1657 as_schedule_single_action(
1658 time(),
1659 'mainwp_cron_destroy_session_batch',
1660 array( $destroy_id )
1661 );
1662 } else {
1663 wp_schedule_single_event( time(), 'mainwp_cron_destroy_session_batch', array( $destroy_id ) );
1664 spawn_cron(); // Run cron now.
1665 }
1666
1667 // Return status url.
1668 $status_url = $this->namespace . '/' . $this->rest_base . '/tools/destroy-sessions-status/' . $destroy_id;
1669 return rest_ensure_response(
1670 array(
1671 'success' => 1,
1672 'message' => __( 'Destroy sessions process started in background.', 'mainwp' ),
1673 'destroy_id' => $destroy_id,
1674 'status_url' => rest_url( $status_url ),
1675 )
1676 );
1677 }
1678
1679 /**
1680 * Get destroy sessions status.
1681 *
1682 * @param WP_REST_Request $request Full details about the request.
1683 *
1684 * @return WP_Error|WP_REST_Response
1685 */
1686 public function get_destroy_sessions_status( $request ) { // phpcs:ignore -- NOSONAR - complex.
1687
1688 $destroy_id = $request->get_param( 'destroy_id' ); // Get id from url.
1689 if ( empty( $destroy_id ) ) {
1690 return new WP_Error(
1691 'missing_destroy_id',
1692 __( 'Destroy ID is required.', 'mainwp' ),
1693 array( 'status' => 400 )
1694 );
1695 }
1696
1697 $destroy_data = get_transient( "mainwp_tool_destroy_job_{$destroy_id}" );
1698 if ( ! $destroy_data ) {
1699 return new WP_Error(
1700 'destroy_session_job_not_found',
1701 __( 'Destroy session job not found.', 'mainwp' ),
1702 array( 'status' => 404 )
1703 );
1704 }
1705
1706 return rest_ensure_response(
1707 array(
1708 'success' => 'completed' === $destroy_data['status'] && 0 === $destroy_data['failed'],
1709 'status' => $destroy_data['status'],
1710 'total' => $destroy_data['total'],
1711 'processed' => $destroy_data['processed'],
1712 'failed' => $destroy_data['failed'],
1713 'progress' => round( ( $destroy_data['processed'] / $destroy_data['total'] ) * 100, 2 ),
1714 'errors' => ! empty( $destroy_data['errors'] ) ? array_slice( $destroy_data['errors'], 0, 10 ) : array(),
1715 'started_at' => $destroy_data['started_at'] ?? '',
1716 'completed_at' => $destroy_data['completed_at'] ?? '',
1717 )
1718 );
1719 }
1720
1721 /**
1722 * Process destroy session batch.
1723 *
1724 * @param string $destroy_id Destroy ID.
1725 *
1726 * @uses MainWP_System_Utility::can_edit_website()
1727 *
1728 * @return void
1729 */
1730 public function process_destroy_session_batch( $destroy_id ) { // phpcs:ignore -- NOSONAR - complex.
1731 $destroy_data = get_transient( "mainwp_tool_destroy_job_{$destroy_id}" );
1732 if ( ! $destroy_data || 'completed' === $destroy_data['status'] ) {
1733 return;
1734 }
1735 $website_ids = $destroy_data['websites'];
1736 $start_index = $destroy_data['processed'];
1737 $batch = array_slice( $website_ids, $start_index, $this->batch_size );
1738
1739 foreach ( $batch as $website_id ) {
1740 try {
1741 $website = $this->get_website_by_id( $website_id, $destroy_data );
1742 if ( empty( $website ) ) {
1743 continue;
1744 }
1745
1746 if ( MainWP_System_Utility::can_edit_website( $website ) ) {
1747 ++$destroy_data['processed'];
1748 } else {
1749 ++$destroy_data['failed'];
1750 ++$destroy_data['processed'];
1751 $destroy_data['errors'][] = array(
1752 'site_id' => $website_id,
1753 'error' => __( 'You cannot edit this website.', 'mainwp' ),
1754 );
1755 }
1756 } catch ( \Exception $e ) {
1757 ++$destroy_data['failed'];
1758 ++$destroy_data['processed'];
1759 $destroy_data['errors'][] = array(
1760 'site_id' => $website_id,
1761 'error' => $e->getMessage(),
1762 );
1763 }
1764 }
1765
1766 // Reschedule or completed.
1767 if ( $destroy_data['processed'] >= $destroy_data['total'] ) {
1768 $destroy_data['status'] = 'completed';
1769 $destroy_data['completed_at'] = time();
1770 delete_transient( "mainwp_tool_destroy_job_{$destroy_id}" ); // Delete transient when completed.
1771 } elseif ( function_exists( 'as_schedule_single_action' ) ) {
1772 as_schedule_single_action(
1773 time() + 3,
1774 'mainwp_cron_destroy_session_batch',
1775 array( $destroy_id )
1776 );
1777 } else {
1778 wp_schedule_single_event( time() + 3, 'mainwp_cron_destroy_session_batch', array( $destroy_id ) );
1779 spawn_cron(); // Run Cron now.
1780 }
1781
1782 // Update transient.
1783 set_transient( "mainwp_tool_destroy_job_{$destroy_id}", $destroy_data, DAY_IN_SECONDS );
1784 }
1785
1786 /**
1787 * Renew connections.
1788 *
1789 * @param WP_REST_Request $request Full details about the request.
1790 *
1791 * @return WP_Error|WP_REST_Response
1792 */
1793 public function renew_connections( $request ) {
1794 $websites = $this->get_websites();
1795 if ( is_wp_error( $websites ) ) {
1796 return $websites;
1797 }
1798
1799 $renew_id = uniqid( 'renew_', true );
1800 $websites = array_column( $websites, 'id' );
1801 set_transient(
1802 "mainwp_tool_renew_job_{$renew_id}",
1803 array(
1804 'status' => 'pending',
1805 'total' => count( $websites ),
1806 'processed' => 0,
1807 'failed' => 0,
1808 'created_at' => time(),
1809 'websites' => $websites,
1810 ),
1811 DAY_IN_SECONDS
1812 );
1813
1814 // Schedule background task.
1815 if ( function_exists( 'as_schedule_single_action' ) ) {
1816 as_schedule_single_action(
1817 time(),
1818 'mainwp_cron_renew_connection_batch',
1819 array( $renew_id )
1820 );
1821 } else {
1822 wp_schedule_single_event( time(), 'mainwp_cron_renew_connection_batch', array( $renew_id ) );
1823 spawn_cron(); // Run cron now.
1824 }
1825
1826 // Return status url.
1827 $status_url = $this->namespace . '/' . $this->rest_base . '/tools/renew-connections-status/' . $renew_id;
1828 return rest_ensure_response(
1829 array(
1830 'success' => 1,
1831 'message' => __( 'Renew connection process started in background.', 'mainwp' ),
1832 'renew_id' => $renew_id,
1833 'status_url' => rest_url( $status_url ),
1834 )
1835 );
1836 }
1837
1838 /**
1839 * Get renew connection status.
1840 *
1841 * @param WP_REST_Request $request Full details about the request.
1842 *
1843 * @return WP_Error|WP_REST_Response
1844 */
1845 public function get_renew_connection_status( $request ) {
1846 $renew_id = $request->get_param( 'renew_id' ); // Get id from url.
1847
1848 if ( empty( $renew_id ) ) {
1849 return new WP_Error(
1850 'missing_renew_id',
1851 __( 'Renew ID is required.', 'mainwp' ),
1852 array( 'status' => 400 )
1853 );
1854 }
1855
1856 // Get disconnect data.
1857 $renew_data = get_transient( "mainwp_tool_renew_job_{$renew_id}" );
1858
1859 if ( ! $renew_data ) {
1860 return new WP_Error(
1861 'renew_connection_job_not_found',
1862 __( 'Renew connection job not found.', 'mainwp' ),
1863 array( 'status' => 404 )
1864 );
1865 }
1866
1867 return rest_ensure_response(
1868 array(
1869 'success' => 'completed' === $renew_data['status'] && 0 === $renew_data['failed'],
1870 'status' => $renew_data['status'],
1871 'total' => $renew_data['total'],
1872 'processed' => $renew_data['processed'],
1873 'failed' => $renew_data['failed'],
1874 'progress' => round( ( $renew_data['processed'] / $renew_data['total'] ) * 100, 2 ),
1875 'errors' => ! empty( $renew_data['errors'] ) ? array_slice( $renew_data['errors'], 0, 10 ) : array(),
1876 'started_at' => $renew_data['started_at'] ?? '',
1877 'completed_at' => $renew_data['completed_at'] ?? '',
1878 )
1879 );
1880 }
1881
1882 /**
1883 * Process renew connection batch.
1884 *
1885 * @param string $renew_id Renew ID.
1886 *
1887 * @uses MainWP_Sync::sync_site()
1888 * @uses MainWP_Connect::fetch_url_authed()
1889 * @uses MainWP_Manage_Sites_View::m_reconnect_site()
1890 * @uses MainWP_Logger::instance()->info_for_website()
1891 */
1892 public function process_renew_connection_batch( $renew_id ) { // phpcs:ignore -- NOSONAR - complex.
1893 $renew_data = get_transient( "mainwp_tool_renew_job_{$renew_id}" );
1894 if ( ! $renew_data || 'completed' === $renew_data['status'] ) {
1895 return;
1896 }
1897 $website_ids = $renew_data['websites'];
1898 $start_index = $renew_data['processed'];
1899 $batch = array_slice( $website_ids, $start_index, $this->batch_size );
1900
1901 foreach ( $batch as $website_id ) {
1902 try {
1903 $website = $this->get_website_by_id( $website_id, $renew_data );
1904 if ( empty( $website ) ) {
1905 continue;
1906 }
1907
1908 if ( '' !== $website->sync_errors ) {
1909 // try reconnect, if failed.
1910 MainWP_Sync::sync_site( $website, true );
1911 }
1912
1913 $result = MainWP_Connect::fetch_url_authed( $website, 'renew' );
1914 if ( is_array( $result ) && isset( $result['result'] ) && 'success' === $result['result'] ) {
1915 // reconnect immediately, to renew.
1916 if ( MainWP_Manage_Sites_View::m_reconnect_site( $website, false ) ) {
1917 MainWP_Logger::instance()->info_for_website( $website, 'renew', 'Renew connection successfully.' );
1918 ++$renew_data['processed'];
1919 } else {
1920 ++$renew_data['failed'];
1921 ++$renew_data['processed'];
1922 $renew_data['errors'][] = array(
1923 'site_id' => $website_id,
1924 'error' => $result['error'] ?? __( 'Try to reconnect site failed', 'mainwp' ),
1925 );
1926 }
1927 } else {
1928 ++$renew_data['failed'];
1929 ++$renew_data['processed'];
1930 $renew_data['errors'][] = array(
1931 'site_id' => $website_id,
1932 'error' => $result['error'] ?? __( 'Try to disconnect site failed', 'mainwp' ),
1933 );
1934 MainWP_Logger::instance()->info_for_website( $website, 'renew', 'Try to disconnect site failed.' );
1935 }
1936 } catch ( \Exception $e ) {
1937 ++$renew_data['failed'];
1938 ++$renew_data['processed'];
1939 $renew_data['errors'][] = array(
1940 'site_id' => $website_id,
1941 'error' => $e->getMessage(),
1942 );
1943 }
1944 }
1945
1946 // Reschedule or completed.
1947 if ( $renew_data['processed'] >= $renew_data['total'] ) {
1948 $renew_data['status'] = 'completed';
1949 $renew_data['completed_at'] = time();
1950 delete_transient( "mainwp_tool_renew_job_{$renew_id}" ); // Delete transient when completed.
1951 } elseif ( function_exists( 'as_schedule_single_action' ) ) {
1952 as_schedule_single_action(
1953 time() + 3,
1954 'mainwp_cron_renew_connection_batch',
1955 array( $renew_id )
1956 );
1957 } else {
1958 wp_schedule_single_event( time() + 3, 'mainwp_cron_renew_connection_batch', array( $renew_id ) );
1959 spawn_cron(); // Run Cron now.
1960 }
1961
1962 // Update transient.
1963 set_transient( "mainwp_tool_renew_job_{$renew_id}", $renew_data, DAY_IN_SECONDS );
1964 }
1965
1966 /**
1967 * Disconnect all sites.
1968 *
1969 * @param WP_REST_Request $request Full details about the request.
1970 *
1971 * @return WP_Error|WP_REST_Response
1972 */
1973 public function disconnect_all_sites( $request ) {
1974 $websites = $this->get_websites();
1975 if ( is_wp_error( $websites ) ) {
1976 return $websites;
1977 }
1978
1979 $disconnect_id = uniqid( 'disconnect_', true );
1980 set_transient(
1981 "mainwp_tool_disconnect_job_{$disconnect_id}",
1982 array(
1983 'status' => 'pending',
1984 'total' => count( $websites ),
1985 'processed' => 0,
1986 'failed' => 0,
1987 'created_at' => time(),
1988 'websites' => array_column( $websites, 'id' ),
1989 ),
1990 DAY_IN_SECONDS
1991 );
1992
1993 // Schedule background task.
1994 if ( function_exists( 'as_schedule_single_action' ) ) {
1995 as_schedule_single_action(
1996 time(),
1997 'mainwp_cron_disconnect_batch',
1998 array( $disconnect_id )
1999 );
2000 } else {
2001 wp_schedule_single_event( time(), 'mainwp_cron_disconnect_batch', array( $disconnect_id ) );
2002 spawn_cron(); // Run cron now.
2003 }
2004
2005 // Return status url.
2006 $status_url = $this->namespace . '/' . $this->rest_base . '/tools/disconnect-status/' . $disconnect_id;
2007 return rest_ensure_response(
2008 array(
2009 'success' => 1,
2010 'message' => __( 'Disconnect process started in background.', 'mainwp' ),
2011 'disconnect_id' => $disconnect_id,
2012 'status_url' => rest_url( $status_url ),
2013 )
2014 );
2015 }
2016
2017 /**
2018 * Process disconnect batch.
2019 *
2020 * @param string $disconnect_id Disconnect ID.
2021 *
2022 * @uses MainWP_Connect::fetch_url_authed()
2023 *
2024 * @return void
2025 */
2026 public function process_disconnect_batch( $disconnect_id ) { // phpcs:ignore -- NOSONAR
2027 $disconnect_data = get_transient( "mainwp_tool_disconnect_job_{$disconnect_id}" );
2028 if ( ! $disconnect_data || 'completed' === $disconnect_data['status'] ) {
2029 return;
2030 }
2031
2032 // Check if websites are available.
2033 if ( empty( $disconnect_data['websites'] ) || ! is_array( $disconnect_data['websites'] ) ) {
2034 return;
2035 }
2036
2037 $website_ids = $disconnect_data['websites'];
2038 $start_index = $disconnect_data['processed'];
2039 $batch = array_slice( $website_ids, $start_index, $this->batch_size );
2040
2041 foreach ( $batch as $website_id ) {
2042 try {
2043 $website = $this->get_website_by_id( $website_id, $disconnect_data );
2044 if ( empty( $website ) ) {
2045 continue;
2046 }
2047
2048 $result = MainWP_Connect::fetch_url_authed( $website, 'disconnect' );
2049 if ( is_array( $result ) && isset( $result['result'] ) && 'success' === $result['result'] ) {
2050 ++$disconnect_data['processed'];
2051 } else {
2052 ++$disconnect_data['failed'];
2053 ++$disconnect_data['processed'];
2054 $disconnect_data['errors'][] = array(
2055 'site_id' => $website_id,
2056 'error' => $result['error'] ?? __( 'Unknown error', 'mainwp' ),
2057 );
2058 }
2059 } catch ( \Exception $e ) {
2060 ++$disconnect_data['failed'];
2061 ++$disconnect_data['processed'];
2062 $disconnect_data['errors'][] = array(
2063 'site_id' => $website_id,
2064 'error' => $e->getMessage(),
2065 );
2066 }
2067 }
2068
2069 if ( $disconnect_data['processed'] >= $disconnect_data['total'] ) {
2070 $disconnect_data['status'] = 'completed';
2071 $disconnect_data['completed_at'] = time();
2072 delete_transient( "mainwp_tool_disconnect_job_{$disconnect_id}" ); // Delete transient when completed.
2073 } elseif ( function_exists( 'as_schedule_single_action' ) ) {
2074 as_schedule_single_action(
2075 time() + 3,
2076 'mainwp_cron_disconnect_batch',
2077 array( $disconnect_id )
2078 );
2079 } else {
2080 wp_schedule_single_event( time() + 3, 'mainwp_disconnect_site_batch', array( $disconnect_id ) );
2081 spawn_cron(); // Run Cron now.
2082 }
2083
2084 set_transient( "mainwp_tool_disconnect_job_{$disconnect_id}", $disconnect_data, DAY_IN_SECONDS );
2085 }
2086
2087 /**
2088 * Get disconnect job status.
2089 *
2090 * @param WP_REST_Request $request REST request.
2091 *
2092 * @return WP_REST_Response|WP_Error Response or error.
2093 */
2094 public function get_disconnect_status( $request ) {
2095 $disconnect_id = $request->get_param( 'disconnect_id' ); // Get id from url.
2096
2097 if ( empty( $disconnect_id ) ) {
2098 return new WP_Error(
2099 'missing_disconnect_id',
2100 __( 'Disconnect ID is required.', 'mainwp' ),
2101 array( 'status' => 400 )
2102 );
2103 }
2104
2105 // Get disconnect data.
2106 $disconnect_data = get_transient( "mainwp_tool_disconnect_job_{$disconnect_id}" );
2107
2108 if ( ! $disconnect_data ) {
2109 return new WP_Error(
2110 'disconnect_job_not_found',
2111 __( 'Job not found.', 'mainwp' ),
2112 array( 'status' => 404 )
2113 );
2114 }
2115
2116 return rest_ensure_response(
2117 array(
2118 'success' => 'completed' === $disconnect_data['status'] && 0 === $disconnect_data['failed'],
2119 'status' => $disconnect_data['status'],
2120 'total' => $disconnect_data['total'],
2121 'processed' => $disconnect_data['processed'],
2122 'failed' => $disconnect_data['failed'],
2123 'progress' => round( ( $disconnect_data['processed'] / $disconnect_data['total'] ) * 100, 2 ),
2124 'errors' => ! empty( $disconnect_data['errors'] ) ? array_slice( $disconnect_data['errors'], 0, 10 ) : array(),
2125 'started_at' => $disconnect_data['started_at'],
2126 'completed_at' => $disconnect_data['completed_at'] ?? null,
2127 )
2128 );
2129 }
2130
2131 /**
2132 * Clear activation data.
2133 *
2134 * @param WP_REST_Request $request Full details about the request.
2135 *
2136 * @uses MainWP_Keys_Manager::instance()->update_key_value()
2137 * @uses MainWP_Api_Manager::instance()->get_activation_info()
2138 * @uses MainWP_Api_Manager::instance()->set_activation_info()
2139 *
2140 * @return WP_Error|WP_REST_Response
2141 */
2142 public function clear_activation_data( $request ) { // phpcs:ignore -- NOSONAR - complex.
2143 // Clear activation data.
2144 delete_option( 'mainwp_extensions_api_username' );
2145 delete_option( 'mainwp_extensions_api_password' );
2146 delete_option( 'mainwp_extensions_api_save_login' );
2147 delete_option( 'mainwp_extensions_plan_info' );
2148
2149 // Clear master api key.
2150 MainWP_Keys_Manager::instance()->update_key_value( 'mainwp_extensions_master_api_key', false );
2151
2152 // Clear extension api key.
2153 $new_extensions = array();
2154 $extensions = get_option( 'mainwp_extensions', array() );
2155
2156 if ( is_array( $extensions ) ) {
2157 foreach ( $extensions as $ext ) {
2158 if ( isset( $ext['api'] ) && isset( $ext['apiManager'] ) && ! empty( $ext['apiManager'] ) ) {
2159 if ( isset( $ext['api_key'] ) ) {
2160 $ext['api_key'] = '';
2161 }
2162 if ( isset( $ext['activation_email'] ) ) {
2163 $ext['activation_email'] = '';
2164 }
2165 if ( isset( $ext['activated_key'] ) ) {
2166 $ext['activated_key'] = 'Deactivated';
2167 }
2168
2169 $act_info = MainWP_Api_Manager::instance()->get_activation_info( $ext['api'] );
2170 if ( isset( $act_info['api_key'] ) ) {
2171 $act_info['api_key'] = '';
2172 }
2173 if ( isset( $act_info['activation_email'] ) ) {
2174 $act_info['activation_email'] = '';
2175 }
2176 if ( isset( $act_info['activated_key'] ) ) {
2177 $act_info['activated_key'] = 'Deactivated';
2178 }
2179 MainWP_Api_Manager::instance()->set_activation_info( $ext['api'], $act_info );
2180 }
2181 $new_extensions[] = $ext;
2182 }
2183 }
2184
2185 MainWP_Utility::update_option( 'mainwp_extensions', $new_extensions );
2186 MainWP_Utility::update_option( 'mainwp_extensions_all_activation_cached', '' );
2187
2188 return rest_ensure_response(
2189 array(
2190 'success' => 1,
2191 'message' => __( 'Activation data cleared successfully.', 'mainwp' ),
2192 )
2193 );
2194 }
2195
2196 /**
2197 * Restore info messages by clearing the saved notice status.
2198 *
2199 * @param WP_REST_Request $request Full details about the request.
2200 *
2201 * @return WP_Error|WP_REST_Response
2202 */
2203 public function restore_info_messages( $request ) {
2204 $user_id = $this->get_user_id();
2205 if ( is_wp_error( $user_id ) ) {
2206 return $user_id;
2207 }
2208
2209 // Delete user option.
2210 delete_user_option( $user_id, 'mainwp_notice_saved_status' );
2211
2212 return rest_ensure_response(
2213 array(
2214 'success' => 1,
2215 'message' => __( 'Info messages restored successfully.', 'mainwp' ),
2216 )
2217 );
2218 }
2219
2220 /**
2221 * Get allowed fields for general settings.
2222 *
2223 * @return array
2224 */
2225 public function get_update_general_allowed_fields() { // phpcs:ignore -- NOSONAR - long method.
2226 $val_bool = array( 0, 1 );
2227 $disable_update = array( 0, 1, 2 );
2228 $days_week = range( 0, 6 );
2229 $days_month = range( 0, 31 );
2230 $delay = array( 0, 1, 2, 3, 4, 5, 6, 7, 14, 30 );
2231 $frequency = array( 'daily', 'weekly', 'monthly' );
2232 $frequency_daily = range( 1, 12 );
2233 $http_methods = array( 'head', 'get' );
2234 $archive_format = array( 'zip', 'tar.gz', 'tar.bz2', 'tar' );
2235 $primary_backup = array( '', 'module-api-backups' );
2236
2237 return array(
2238 'time_daily_update' => array(
2239 'required' => false,
2240 'description' => __( 'Time for daily updates (HH:MM format).', 'mainwp' ),
2241 'type' => 'string',
2242 'validate_callback' => array( $this, 'validate_time_update' ),
2243 'sanitize_callback' => array( $this, 'sanitize_time_update' ),
2244 ),
2245 'frequency_daily_update' => array(
2246 'required' => false,
2247 'description' => __( 'Frequency of daily updates (1-12).', 'mainwp' ),
2248 'type' => 'integer',
2249 'sanitize_callback' => $this->make_enum_sanitizer( $frequency_daily ),
2250 'validate_callback' => $this->make_enum_validator( $frequency_daily ),
2251 ),
2252 'date_format' => array(
2253 'required' => false,
2254 'description' => __( 'Date format.', 'mainwp' ),
2255 'type' => 'string',
2256 'sanitize_callback' => 'sanitize_text_field',
2257 'validate_callback' => array( $this, 'validate_date_format' ),
2258 ),
2259 'time_format' => array(
2260 'required' => false,
2261 'description' => __( 'Time format.', 'mainwp' ),
2262 'type' => 'string',
2263 'sanitize_callback' => 'sanitize_text_field',
2264 'validate_callback' => array( $this, 'validate_time_format' ),
2265 ),
2266 'timezone_string' => array(
2267 'required' => false,
2268 'description' => __( 'Timezone.', 'mainwp' ),
2269 'type' => 'string',
2270 'sanitize_callback' => array( $this, 'sanitize_timezone_field' ),
2271 'validate_callback' => array( $this, 'validate_timezone' ),
2272 ),
2273 'sidebar_position' => array(
2274 'required' => false,
2275 'description' => __( 'Sidebar position.', 'mainwp' ),
2276 'type' => 'boolean',
2277 'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
2278 'validate_callback' => $this->make_enum_validator( $val_bool ),
2279 ),
2280 'hide_update_everything' => array(
2281 'required' => false,
2282 'description' => __( 'Hide update everything button.', 'mainwp' ),
2283 'type' => 'boolean',
2284 'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
2285 'validate_callback' => $this->make_enum_validator( $val_bool ),
2286 ),
2287 'mainwp_widgets' => array(
2288 'required' => false,
2289 'description' => __( 'MainWP dashboard widgets.', 'mainwp' ),
2290 'type' => 'array',
2291 'sanitize_callback' => array( $this, 'sanitize_mainwp_widgets' ),
2292 'validate_callback' => array( $this, 'validate_mainwp_widgets' ),
2293 ),
2294 'plugin_automatic_daily_update' => array(
2295 'required' => false,
2296 'description' => __( 'Plugin automatic daily update.', 'mainwp' ),
2297 'type' => 'integer',
2298 'enum' => $val_bool,
2299 'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
2300 'validate_callback' => $this->make_enum_validator( $val_bool ),
2301 ),
2302 'theme_automatic_daily_update' => array(
2303 'required' => false,
2304 'description' => __( 'Theme automatic daily update.', 'mainwp' ),
2305 'type' => 'integer',
2306 'enum' => $val_bool,
2307 'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
2308 'validate_callback' => $this->make_enum_validator( $val_bool ),
2309 ),
2310 'trans_automatic_daily_update' => array(
2311 'required' => false,
2312 'description' => __( 'Translation automatic daily update enabled.', 'mainwp' ),
2313 'type' => 'integer',
2314 'enum' => $val_bool,
2315 'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
2316 'validate_callback' => $this->make_enum_validator( $val_bool ),
2317 ),
2318 'automatic_daily_update' => array(
2319 'required' => false,
2320 'description' => __( 'Automatic daily update enabled.', 'mainwp' ),
2321 'type' => 'integer',
2322 'enum' => $val_bool,
2323 'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
2324 'validate_callback' => $this->make_enum_validator( $val_bool ),
2325 ),
2326 'frequency_auto_update' => array(
2327 'required' => false,
2328 'description' => __( 'Frequency of auto updates.', 'mainwp' ),
2329 'type' => 'string',
2330 'sanitize_callback' => $this->make_enum_sanitizer( $frequency, 'string' ),
2331 'validate_callback' => $this->make_enum_validator( $frequency, 'string' ),
2332 ),
2333 'time_auto_update' => array(
2334 'required' => false,
2335 'description' => __( 'Auto update time (whole hour, 24h).', 'mainwp' ),
2336 'type' => 'string',
2337 'validate_callback' => array( $this, 'validate_time_update' ),
2338 'sanitize_callback' => array( $this, 'sanitize_time_update' ),
2339 ),
2340 'show_language_updates' => array(
2341 'required' => false,
2342 'description' => __( 'Show language updates.', 'mainwp' ),
2343 'type' => 'boolean',
2344 'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
2345 'validate_callback' => $this->make_enum_validator( $val_bool ),
2346 ),
2347 'disable_update_confirmations' => array(
2348 'required' => false,
2349 'description' => __( 'Disable update confirmations.', 'mainwp' ),
2350 'type' => 'integer',
2351 'sanitize_callback' => $this->make_enum_sanitizer( $disable_update ),
2352 'validate_callback' => $this->make_enum_validator( $disable_update ),
2353 ),
2354 'check_http_response' => array(
2355 'required' => false,
2356 'description' => __( 'Check HTTP response after update.', 'mainwp' ),
2357 'type' => 'boolean',
2358 'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
2359 'validate_callback' => $this->make_enum_validator( $val_bool ),
2360 ),
2361 'check_http_response_method' => array(
2362 'required' => false,
2363 'description' => __( 'HTTP method for response check.', 'mainwp' ),
2364 'type' => 'string',
2365 'sanitize_callback' => $this->make_enum_sanitizer( $http_methods, 'string' ),
2366 'validate_callback' => $this->make_enum_validator( $http_methods, 'string' ),
2367 ),
2368 'backup_before_upgrade' => array(
2369 'required' => false,
2370 'description' => __( 'Backup before upgrade.', 'mainwp' ),
2371 'type' => 'boolean',
2372 'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
2373 'validate_callback' => $this->make_enum_validator( $val_bool ),
2374 ),
2375 'backup_before_upgrade_days' => array(
2376 'required' => false,
2377 'description' => __( 'Days to check for backup before upgrade.', 'mainwp' ),
2378 'type' => 'integer',
2379 'sanitize_callback' => 'absint',
2380 ),
2381 'numberdays_outdate_plugin_theme' => array(
2382 'required' => false,
2383 'description' => __( 'Number of days to consider plugin/theme as outdated.', 'mainwp' ),
2384 'type' => 'integer',
2385 'sanitize_callback' => 'absint',
2386 ),
2387 'dayinweek_auto_update' => array(
2388 'required' => false,
2389 'description' => __( 'Day in week for auto updates.', 'mainwp' ),
2390 'type' => 'integer',
2391 'sanitize_callback' => $this->make_enum_sanitizer( $days_week ),
2392 'validate_callback' => $this->make_enum_validator( $days_week ),
2393 ),
2394 'dayinmonth_auto_update' => array(
2395 'required' => false,
2396 'description' => __( 'Day in month for auto updates.', 'mainwp' ),
2397 'type' => 'integer',
2398 'sanitize_callback' => $this->make_enum_sanitizer( $days_month ),
2399 'validate_callback' => $this->make_enum_validator( $days_month ),
2400 ),
2401 'delay_autoupdate' => array(
2402 'required' => false,
2403 'description' => __( 'Delay automatic updates.', 'mainwp' ),
2404 'type' => 'integer',
2405 'sanitize_callback' => $this->make_enum_sanitizer( $delay ),
2406 'validate_callback' => $this->make_enum_validator( $delay ),
2407 ),
2408 'mainwp_primary_backup' => array(
2409 'required' => false,
2410 'description' => __( 'Primary backup method.', 'mainwp' ),
2411 'type' => 'string',
2412 'sanitize_callback' => $this->make_enum_sanitizer( $primary_backup, 'string' ),
2413 'validate_callback' => $this->make_enum_validator( $primary_backup, 'string' ),
2414 ),
2415 'mainwp_enable_legacy_backup_feature' => array(
2416 'required' => false,
2417 'description' => __( 'Enable legacy backup feature.', 'mainwp' ),
2418 'type' => 'boolean',
2419 'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
2420 'validate_callback' => $this->make_enum_validator( $val_bool ),
2421 ),
2422 'mainwp_backups_on_server' => array(
2423 'required' => false,
2424 'description' => __( 'Backups on server.', 'mainwp' ),
2425 'type' => 'string',
2426 'sanitize_callback' => 'sanitize_text_field',
2427 ),
2428 'mainwp_backup_on_external_sources' => array(
2429 'required' => false,
2430 'description' => __( 'Backup on external sources.', 'mainwp' ),
2431 'type' => 'string',
2432 'sanitize_callback' => 'sanitize_text_field',
2433 ),
2434 'mainwp_archive_format' => array(
2435 'required' => false,
2436 'description' => __( 'Archive format.', 'mainwp' ),
2437 'type' => 'string',
2438 'sanitize_callback' => $this->make_enum_sanitizer( $archive_format, 'string' ),
2439 'validate_callback' => $this->make_enum_validator( $archive_format, 'string' ),
2440 ),
2441 'mainwp_notification_on_backup_fail' => array(
2442 'required' => false,
2443 'description' => __( 'Notification on backup fail.', 'mainwp' ),
2444 'type' => 'boolean',
2445 'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
2446 'validate_callback' => $this->make_enum_validator( $val_bool ),
2447 ),
2448 'mainwp_notification_on_backup_start' => array(
2449 'required' => false,
2450 'description' => __( 'Notification on backup start.', 'mainwp' ),
2451 'type' => 'boolean',
2452 'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
2453 'validate_callback' => $this->make_enum_validator( $val_bool ),
2454 ),
2455 'mainwp_chunked_backup_tasks' => array(
2456 'required' => false,
2457 'description' => __( 'Chunked backup tasks.', 'mainwp' ),
2458 'type' => 'boolean',
2459 'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
2460 'validate_callback' => $this->make_enum_validator( $val_bool ),
2461 ),
2462 );
2463 }
2464
2465 /**
2466 * Get allowed fields for advanced settings.
2467 *
2468 * @uses MainWP_System_Utility::get_open_ssl_sign_algos()
2469 *
2470 * @return array
2471 */
2472 public function get_update_advanced_allowed_fields() { // phpcs:ignore -- NOSONAR - long method.
2473 $val_bool = array( 0, 1 );
2474 $connection_method = array( 1, 2 );
2475 $maximum_requests = range( 1, 20 );
2476 $minimum_delay = range( 100, 5000, 100 );
2477 $maximum_ip_requests = range( 1, 10 );
2478 $minimum_ip_delay = range( 500, 5000, 100 );
2479 $chunk_sites_number = range( 1, 30 );
2480 $chunk_sleep_interval = range( 0, 20 );
2481 $monitoring_requests = range( 1, 100 );
2482 $sign_algs = MainWP_System_Utility::get_open_ssl_sign_algos();
2483
2484 return array(
2485 'mainwp_maximum_requests' => array(
2486 'required' => false,
2487 'description' => __( 'Maximum requests.', 'mainwp' ),
2488 'type' => 'integer',
2489 'sanitize_callback' => $this->make_enum_sanitizer( $maximum_requests ),
2490 'validate_callback' => $this->make_enum_validator( $maximum_requests ),
2491 ),
2492 'mainwp_minimum_delay' => array(
2493 'required' => false,
2494 'description' => __( 'Minimum delay.', 'mainwp' ),
2495 'type' => 'integer',
2496 'sanitize_callback' => $this->make_enum_sanitizer( $minimum_delay ),
2497 'validate_callback' => $this->make_enum_validator( $minimum_delay ),
2498 ),
2499 'mainwp_maximum_ip_requests' => array(
2500 'required' => false,
2501 'description' => __( 'Maximum IP requests.', 'mainwp' ),
2502 'type' => 'integer',
2503 'sanitize_callback' => $this->make_enum_sanitizer( $maximum_ip_requests ),
2504 'validate_callback' => $this->make_enum_validator( $maximum_ip_requests ),
2505 ),
2506 'mainwp_minimum_ip_delay' => array(
2507 'required' => false,
2508 'description' => __( 'Minimum IP delay.', 'mainwp' ),
2509 'type' => 'integer',
2510 'sanitize_callback' => $this->make_enum_sanitizer( $minimum_ip_delay ),
2511 'validate_callback' => $this->make_enum_validator( $minimum_ip_delay ),
2512 ),
2513 'mainwp_chunksitesnumber' => array(
2514 'required' => false,
2515 'description' => __( 'Chunk sites number.', 'mainwp' ),
2516 'type' => 'integer',
2517 'sanitize_callback' => $this->make_enum_sanitizer( $chunk_sites_number ),
2518 'validate_callback' => $this->make_enum_validator( $chunk_sites_number ),
2519 ),
2520 'mainwp_chunksleepinterval' => array(
2521 'required' => false,
2522 'description' => __( 'Chunk sleep interval.', 'mainwp' ),
2523 'type' => 'integer',
2524 'sanitize_callback' => $this->make_enum_sanitizer( $chunk_sleep_interval ),
2525 'validate_callback' => $this->make_enum_validator( $chunk_sleep_interval ),
2526 ),
2527 'mainwp_maximum_sync_requests' => array(
2528 'required' => false,
2529 'description' => __( 'Maximum sync requests.', 'mainwp' ),
2530 'type' => 'integer',
2531 'sanitize_callback' => $this->make_enum_sanitizer( $maximum_requests ),
2532 'validate_callback' => $this->make_enum_validator( $maximum_requests ),
2533 ),
2534 'mainwp_maximum_install_update_requests' => array(
2535 'required' => false,
2536 'description' => __( 'Maximum install and update requests.', 'mainwp' ),
2537 'type' => 'integer',
2538 'sanitize_callback' => $this->make_enum_sanitizer( $maximum_requests ),
2539 'validate_callback' => $this->make_enum_validator( $maximum_requests ),
2540 ),
2541 'mainwp_maximum_uptime_monitoring_requests' => array(
2542 'required' => false,
2543 'description' => __( 'Maximum uptime monitoring requests.', 'mainwp' ),
2544 'type' => 'integer',
2545 'sanitize_callback' => $this->make_enum_sanitizer( $monitoring_requests ),
2546 'validate_callback' => $this->make_enum_validator( $monitoring_requests ),
2547 ),
2548 'mainwp_optimize' => array(
2549 'required' => false,
2550 'description' => __( 'Optimize data loading.', 'mainwp' ),
2551 'type' => 'boolean',
2552 'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
2553 'validate_callback' => $this->make_enum_validator( $val_bool ),
2554 ),
2555 'mainwp_wp_cron' => array(
2556 'required' => false,
2557 'description' => __( 'Use WP Cron.', 'mainwp' ),
2558 'type' => 'boolean',
2559 'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
2560 'validate_callback' => $this->make_enum_validator( $val_bool ),
2561 ),
2562 'mainwp_ssl_verify_certificate' => array(
2563 'required' => false,
2564 'description' => __( 'Verify SSL certificate.', 'mainwp' ),
2565 'type' => 'boolean',
2566 'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
2567 'validate_callback' => $this->make_enum_validator( $val_bool ),
2568 ),
2569 'mainwp_verify_connection_method' => array(
2570 'required' => false,
2571 'description' => __( 'Verify connection method.', 'mainwp' ),
2572 'type' => 'integer',
2573 'sanitize_callback' => $this->make_enum_sanitizer( $connection_method ),
2574 'validate_callback' => $this->make_enum_validator( $connection_method ),
2575 ),
2576 'mainwp_force_use_ipv4' => array(
2577 'required' => false,
2578 'description' => __( 'Force use IPv4.', 'mainwp' ),
2579 'type' => 'boolean',
2580 'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
2581 'validate_callback' => $this->make_enum_validator( $val_bool ),
2582 ),
2583 'mainwp_connect_signature_algo' => array(
2584 'required' => false,
2585 'description' => __( 'OpenSSL signature algorithm.', 'mainwp' ),
2586 'type' => 'integer',
2587 'sanitize_callback' => $this->make_enum_sanitizer( $sign_algs, 'string' ),
2588 'validate_callback' => $this->make_enum_validator( $sign_algs, 'string' ),
2589 ),
2590 'sync_data' => array(
2591 'required' => false,
2592 'description' => __( 'Sync data.', 'mainwp' ),
2593 'type' => 'array',
2594 'sanitize_callback' => array( $this, 'sanitize_sync_data' ),
2595 'validate_callback' => array( $this, 'validate_sync_data' ),
2596 ),
2597 );
2598 }
2599
2600 /**
2601 * Get allowed fields for monitoring settings.
2602 *
2603 * @return array Allowed fields.
2604 */
2605 public function get_update_monitoring_allowed_fields() {
2606 $val_bool = array( 0, 1 );
2607 $threshold = array( 80, 100 );
2608 $monitoring_type = array( 'http', 'ping', 'keyword' );
2609 $timeout_values = array_values( MainWP_Uptime_Monitoring_Edit::get_timeout_values( false ) );
2610 $interval_values = array_values( MainWP_Uptime_Monitoring_Edit::get_interval_values( false ) );
2611
2612 return array(
2613 'mainwp_uptime_monitoring_active' => array(
2614 'required' => false,
2615 'description' => __( 'Active or disable monitoring globally.', 'mainwp' ),
2616 'type' => 'boolean',
2617 'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
2618 'validate_callback' => $this->make_enum_validator( $val_bool ),
2619 ),
2620 'mainwp_uptime_monitoring_down_confirmation_check' => array(
2621 'required' => false,
2622 'description' => __( 'Uptime monitoring down confirmation check.', 'mainwp' ),
2623 'type' => 'integer',
2624 'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
2625 'validate_callback' => $this->make_enum_validator( $val_bool ),
2626 ),
2627 'mainwp_disable_sites_health_monitoring' => array(
2628 'required' => false,
2629 'description' => __( 'Disable sites health monitoring.', 'mainwp' ),
2630 'type' => 'boolean',
2631 'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
2632 'validate_callback' => $this->make_enum_validator( $val_bool ),
2633 ),
2634 'mainwp_sitehealth_threshold' => array(
2635 'required' => false,
2636 'description' => __( 'Site health threshold.', 'mainwp' ),
2637 'type' => 'integer',
2638 'sanitize_callback' => $this->make_enum_sanitizer( $threshold ),
2639 'validate_callback' => $this->make_enum_validator( $threshold ),
2640 ),
2641 'mainwp_uptime_monitoring_type' => array(
2642 'required' => false,
2643 'description' => __( 'Uptime monitoring type.', 'mainwp' ),
2644 'type' => 'string',
2645 'sanitize_callback' => $this->make_enum_sanitizer( $monitoring_type, 'string' ),
2646 'validate_callback' => $this->make_enum_validator( $monitoring_type, 'string' ),
2647 ),
2648 'mainwp_uptime_monitoring_timeout' => array(
2649 'required' => false,
2650 'description' => __( 'Uptime monitoring timeout.', 'mainwp' ),
2651 'type' => 'string',
2652 'enum' => $timeout_values,
2653 'sanitize_callback' => $this->make_enum_sanitizer( $timeout_values, 'string' ),
2654 'validate_callback' => $this->make_enum_validator( $timeout_values, 'string' ),
2655 ),
2656 'mainwp_uptime_monitoring_interval' => array(
2657 'required' => false,
2658 'description' => __( 'Uptime monitoring interval.', 'mainwp' ),
2659 'type' => 'string',
2660 'enum' => $interval_values,
2661 'sanitize_callback' => $this->make_enum_sanitizer( $interval_values, 'string' ),
2662 'validate_callback' => $this->make_enum_validator( $interval_values, 'string' ),
2663 ),
2664 'mainwp_uptime_monitoring_keyword' => array(
2665 'required' => false,
2666 'description' => __( 'Uptime monitoring keyword.', 'mainwp' ),
2667 'type' => 'string',
2668 'sanitize_callback' => 'sanitize_text_field',
2669 ),
2670 'mainwp_uptime_monitoring_bypass_cache' => array(
2671 'required' => false,
2672 'description' => __( 'Uptime monitoring attempt to bypass page cache.', 'mainwp' ),
2673 'type' => 'integer',
2674 'sanitize_callback' => 'intval',
2675 ),
2676 'mainwp_uptime_monitoring_up_status_codes' => array(
2677 'required' => false,
2678 'description' => __( 'Uptime monitoring up status codes.', 'mainwp' ),
2679 'type' => 'array',
2680 'sanitize_callback' => array( $this, 'sanitize_uptime_monitoring_status_codes' ),
2681 'validate_callback' => array( $this, 'validate_uptime_monitoring_status_codes' ),
2682 ),
2683 );
2684 }
2685
2686 /**
2687 * Get update emails allowed fields.
2688 *
2689 * @return array
2690 */
2691 public function get_update_emails_allowed_fields() { // phpcs:ignore -- NOSONAR - long method.
2692 $val_bool = array( 0, 1 );
2693 return array(
2694 'mail_type' => array(
2695 'required' => true,
2696 'description' => __( 'Setting Mail type.', 'mainwp' ),
2697 'type' => 'string',
2698 'sanitize_callback' => array( $this, 'sanitize_email_type' ),
2699 'validate_callback' => array( $this, 'validate_email_type' ),
2700 ),
2701 'disable' => array(
2702 'required' => false,
2703 'description' => __( 'Disable mail.', 'mainwp' ),
2704 'type' => 'boolean',
2705 'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
2706 'validate_callback' => $this->make_enum_validator( $val_bool ),
2707 ),
2708 'heading' => array(
2709 'required' => false,
2710 'description' => __( 'Mail name.', 'mainwp' ),
2711 'type' => 'string',
2712 'sanitize_callback' => 'sanitize_text_field',
2713 ),
2714 'subject' => array(
2715 'required' => false,
2716 'description' => __( 'Mail description.', 'mainwp' ),
2717 'type' => 'string',
2718 'sanitize_callback' => 'sanitize_textarea_field',
2719 ),
2720 'recipients' => array(
2721 'required' => false,
2722 'description' => __( 'Mail recipients.', 'mainwp' ),
2723 'type' => 'string',
2724 'sanitize_callback' => 'sanitize_text_field',
2725 'validate_callback' => function ( $value ) {
2726 if ( ! is_email( $value ) ) {
2727 return new WP_Error(
2728 'invalid_email',
2729 /* translators: %s: Email address */ sprintf( __( 'Invalid email address: %s.', 'mainwp' ), $value ),
2730 array( 'status' => 400 )
2731 );
2732 }
2733 return true;
2734 },
2735 ),
2736 );
2737 }
2738
2739 /**
2740 * Get add cost tracker product type allowed fields.
2741 *
2742 * @return array
2743 */
2744 public function get_add_cost_tracker_product_type_allowed_fields() { // phpcs:ignore -- NOSONAR - long method.
2745 return array(
2746 'title' => array(
2747 'required' => true,
2748 'description' => __( 'Product type title.', 'mainwp' ),
2749 'type' => 'string',
2750 'sanitize_callback' => 'sanitize_text_field',
2751 ),
2752 'color' => array(
2753 'required' => false,
2754 'description' => __( 'Product type color.', 'mainwp' ),
2755 'type' => 'string',
2756 'sanitize_callback' => 'sanitize_text_field',
2757 'validate_callback' => array( $this, 'validate_product_type_color' ),
2758 ),
2759 'icon' => array(
2760 'required' => false,
2761 'description' => __( 'Product type icon.', 'mainwp' ),
2762 'type' => 'string',
2763 'sanitize_callback' => 'sanitize_text_field',
2764 'validate_callback' => array( $this, 'validate_product_type_icon' ),
2765 ),
2766 );
2767 }
2768
2769 /**
2770 * Get cost tracker allowed fields.
2771 *
2772 * @return array
2773 */
2774 public function get_cost_tracker_allowed_fields() { // phpcs:ignore -- NOSONAR - long method.
2775 $currency_position = array(
2776 'left',
2777 'right',
2778 'left_space',
2779 'right_space',
2780 );
2781 return array(
2782 'currency' => array(
2783 'required' => false,
2784 'description' => __( 'Currency.', 'mainwp' ),
2785 'type' => 'string',
2786 'sanitize_callback' => 'sanitize_text_field',
2787 'validate_callback' => array( $this, 'validate_cost_tracker_currency' ),
2788 ),
2789 'currency_position' => array(
2790 'required' => false,
2791 'description' => __( 'Currency position.', 'mainwp' ),
2792 'type' => 'string',
2793 'sanitize_callback' => $this->make_enum_sanitizer( $currency_position, 'string' ),
2794 'validate_callback' => $this->make_enum_validator( $currency_position, 'string' ),
2795 ),
2796 'thousand_separator' => array(
2797 'required' => false,
2798 'description' => __( 'Thousand separator.', 'mainwp' ),
2799 'type' => 'string',
2800 'sanitize_callback' => 'sanitize_text_field',
2801 ),
2802 'decimal_separator' => array(
2803 'required' => false,
2804 'description' => __( 'Decimal separator.', 'mainwp' ),
2805 'type' => 'string',
2806 'sanitize_callback' => 'sanitize_text_field',
2807 ),
2808 );
2809 }
2810
2811 /**
2812 * Get edit cost tracker product type allowed fields.
2813 *
2814 * @return array
2815 */
2816 public function get_edit_cost_tracker_product_type_allowed_fields() { // phpcs:ignore -- NOSONAR - long method.
2817 return array_merge(
2818 $this->get_add_cost_tracker_product_type_allowed_fields(),
2819 $this->get_allowed_product_type_slug_field()
2820 );
2821 }
2822
2823 /**
2824 * Get allowed product type slug field.
2825 *
2826 * @return array
2827 */
2828 public function get_allowed_product_type_slug_field() {
2829 return array(
2830 'slug' => array(
2831 'required' => true,
2832 'description' => __( 'Product type slug.', 'mainwp' ),
2833 'type' => 'string',
2834 'sanitize_callback' => 'sanitize_text_field',
2835 'validate_callback' => array( $this, 'validate_product_type_slug' ),
2836 ),
2837 );
2838 }
2839
2840 /**
2841 * Get add cost tracker payment method allowed fields.
2842 *
2843 * @return array
2844 */
2845 public function get_add_cost_tracker_payment_method_allowed_fields() { // phpcs:ignore -- NOSONAR - long method.
2846 return array(
2847 'title' => array(
2848 'required' => true,
2849 'description' => __( 'Payment method title.', 'mainwp' ),
2850 'type' => 'string',
2851 'sanitize_callback' => 'sanitize_text_field',
2852 ),
2853 );
2854 }
2855
2856 /**
2857 * Get edit cost tracker payment method allowed fields.
2858 *
2859 * @return array
2860 */
2861 public function get_edit_cost_tracker_payment_method_allowed_fields() { // phpcs:ignore -- NOSONAR - long method.
2862 return array_merge(
2863 $this->get_allowed_payment_method_slug_field(),
2864 $this->get_add_cost_tracker_payment_method_allowed_fields()
2865 );
2866 }
2867
2868 /**
2869 * Get allowed payment method slug field.
2870 *
2871 * @return array
2872 */
2873 public function get_allowed_payment_method_slug_field() {
2874 return array(
2875 'slug' => array(
2876 'required' => true,
2877 'description' => __( 'Payment method slug.', 'mainwp' ),
2878 'type' => 'string',
2879 'sanitize_callback' => 'sanitize_text_field',
2880 'validate_callback' => array( $this, 'validate_payment_method_slug' ),
2881 ),
2882 );
2883 }
2884
2885 /**
2886 * Get edit dashboard insights allowed fields.
2887 *
2888 * @return array
2889 */
2890 public function get_edit_dashboard_insight_allowed_fields() { // phpcs:ignore -- NOSONAR - long method.
2891 $val_bool = array( 0, 1 );
2892 return array(
2893 'enable_insights_logging' => array(
2894 'required' => false,
2895 'description' => __( 'Enable insights logging.', 'mainwp' ),
2896 'type' => 'integer',
2897 'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
2898 'validate_callback' => $this->make_enum_validator( $val_bool ),
2899 ),
2900 );
2901 }
2902
2903 /**
2904 * Get edit api backup allowed fields.
2905 *
2906 * @return array
2907 */
2908 public function get_edit_api_backup_allowed_fields() { // phpcs:ignore -- NOSONAR - long method.
2909 return array_merge(
2910 $this->get_allowed_api_slug_field(),
2911 array(
2912 'username' => array(
2913 'required' => false,
2914 'description' => __( 'API username.', 'mainwp' ),
2915 'type' => 'string',
2916 'sanitize_callback' => 'sanitize_text_field',
2917 ),
2918 'password' => array(
2919 'required' => false,
2920 'description' => __( 'API password.', 'mainwp' ),
2921 'type' => 'string',
2922 'sanitize_callback' => 'sanitize_text_field',
2923 ),
2924 )
2925 );
2926 }
2927
2928 /**
2929 * Get allowed API slug field.
2930 *
2931 * @return array
2932 */
2933 public function get_allowed_api_slug_field() {
2934 return array(
2935 'api_slug' => array(
2936 'required' => true,
2937 'description' => __( 'API slug.', 'mainwp' ),
2938 'type' => 'string',
2939 'sanitize_callback' => array( $this, 'sanitize_api_slug' ),
2940 'validate_callback' => array( $this, 'validate_api_slug' ),
2941 ),
2942 'enabled' => array(
2943 'type' => 'boolean',
2944 'required' => false,
2945 'description' => __( 'Enable/Disable the provider.', 'mainwp' ),
2946 'sanitize_callback' => 'rest_sanitize_boolean',
2947 'validate_callback' => 'rest_is_boolean',
2948 ),
2949 'url' => array(
2950 'type' => 'string',
2951 'required' => false,
2952 'description' => __( 'Server URL (for cPanel).', 'mainwp' ),
2953 'sanitize_callback' => 'sanitize_url',
2954 ),
2955 'site_path' => array(
2956 'type' => 'string',
2957 'required' => false,
2958 'description' => __( 'Site path (for cPanel).', 'mainwp' ),
2959 'sanitize_callback' => 'sanitize_text_field',
2960 ),
2961 'username' => array(
2962 'type' => 'string',
2963 'required' => false,
2964 'description' => __( 'Username (for cPanel).', 'mainwp' ),
2965 'sanitize_callback' => 'sanitize_text_field',
2966 ),
2967 'password' => array(
2968 'type' => 'string',
2969 'required' => false,
2970 'description' => __( 'Password (for cPanel).', 'mainwp' ),
2971 'sanitize_callback' => 'sanitize_text_field',
2972 ),
2973 'account_email' => array(
2974 'type' => 'string',
2975 'required' => false,
2976 'description' => __( 'Account email (for Cloudways).', 'mainwp' ),
2977 'sanitize_callback' => 'sanitize_email',
2978 'validate_callback' => 'is_email',
2979 ),
2980 'company_id' => array(
2981 'type' => 'string',
2982 'required' => false,
2983 'description' => __( 'Company ID (for kinsta).', 'mainwp' ),
2984 'sanitize_callback' => 'sanitize_text_field',
2985 ),
2986 'secrets' => array(
2987 'type' => 'object',
2988 'required' => false,
2989 'description' => __( 'Secrets (Cpanel not used).', 'mainwp' ),
2990 'properties' => array(
2991 'api_key' => array(
2992 'type' => 'string',
2993 'required' => false,
2994 'description' => __( 'API key (for kinsta).', 'mainwp' ),
2995 'sanitize_callback' => 'sanitize_text_field',
2996 ),
2997 'access_token' => array(
2998 'type' => 'string',
2999 'required' => false,
3000 'description' => __( 'Access token (for Cloudways).', 'mainwp' ),
3001 'sanitize_callback' => 'sanitize_text_field',
3002 ),
3003 ),
3004 ),
3005 );
3006 }
3007
3008 /**
3009 * Get edit tools allowed fields.
3010 *
3011 * @return array
3012 */
3013 public function get_edit_tools_allowed_fields() { // phpcs:ignore -- NOSONAR - long method.
3014 $themes = array( 'default', 'default-2024', 'classic', 'dark', 'wpadmin', 'minimalistic' );
3015 return array(
3016 'mainwp_theme' => array(
3017 'required' => false,
3018 'description' => __( 'MainWP theme.', 'mainwp' ),
3019 'type' => 'string',
3020 'sanitize_callback' => $this->make_enum_sanitizer( $themes, 'string' ),
3021 'validate_callback' => $this->make_enum_validator( $themes, 'string' ),
3022 ),
3023 'guided_tours' => array(
3024 'required' => false,
3025 'description' => __( 'Enable guided tours.', 'mainwp' ),
3026 'type' => 'boolean',
3027 'sanitize_callback' => 'rest_sanitize_boolean',
3028 'validate_callback' => 'rest_is_boolean',
3029 ),
3030 'chatbase' => array(
3031 'required' => false,
3032 'description' => __( 'Enable chatbase.', 'mainwp' ),
3033 'type' => 'boolean',
3034 'sanitize_callback' => 'rest_sanitize_boolean',
3035 'validate_callback' => 'rest_is_boolean',
3036 ),
3037 'guided_video' => array(
3038 'required' => false,
3039 'description' => __( 'Enable youtube embeds.', 'mainwp' ),
3040 'type' => 'boolean',
3041 'sanitize_callback' => 'rest_sanitize_boolean',
3042 'validate_callback' => 'rest_is_boolean',
3043 ),
3044 );
3045 }
3046
3047 /**
3048 * Sanitize API slug.
3049 *
3050 * @param string $value API slug.
3051 *
3052 * @return array|WP_Error The API backup definition the slug names, with the slug added to it, or WP_Error for a slug with no definition.
3053 */
3054 public function sanitize_api_slug( $value ) {
3055 if ( empty( $value ) ) {
3056 return new WP_Error( 'invalid_slug', __( 'Invalid API slug.', 'mainwp' ), array( 'status' => 400 ) );
3057 }
3058
3059 // Sanitize field.
3060 $value = $this->sanitize_field( $value );
3061 $api_backups = $this->get_api_backup_definitions(); // Get API backup definitions.
3062 if ( ! array_key_exists( $value, $api_backups ) ) {
3063 return new WP_Error( 'invalid_slug', __( 'API slug not exists.', 'mainwp' ), array( 'status' => 400 ) );
3064 }
3065 $api_backups[ $value ]['slug'] = $value; // Add slug to API backup definition.
3066 return $api_backups[ $value ];
3067 }
3068
3069 /**
3070 * Validate API slug.
3071 *
3072 * @param string $value API slug.
3073 * @param WP_REST_Request $request Request object.
3074 *
3075 * @return bool|WP_Error
3076 */
3077 public function validate_api_slug( $value, $request ) {
3078 if ( empty( $value ) ) {
3079 return new WP_Error( 'invalid_slug', __( 'Invalid API slug.', 'mainwp' ), array( 'status' => 400 ) );
3080 }
3081
3082 $value = $this->sanitize_field( $value );
3083
3084 // Check if API slug exists.
3085 $api_backups = $this->get_api_backup_definitions();
3086 if ( ! array_key_exists( $value, $api_backups ) ) {
3087 return new WP_Error( 'invalid_slug', __( 'API slug not exists.', 'mainwp' ), array( 'status' => 400 ) );
3088 }
3089
3090 return true;
3091 }
3092
3093 /**
3094 * Validate currency.
3095 *
3096 * @param string $value Currency.
3097 * @param WP_REST_Request $request Request object.
3098 *
3099 * @uses Cost_Tracker_Utility::get_currency_symbol()
3100 *
3101 * @return bool|WP_Error
3102 */
3103 public function validate_cost_tracker_currency( $value, $request ) {
3104 if ( empty( $value ) ) {
3105 return true;
3106 }
3107
3108 $value = $this->sanitize_field( $value ); // Sanitize field.
3109 $symbol = Cost_Tracker_Utility::get_currency_symbol( $value ); // Get currency symbol.
3110 if ( empty( $symbol ) ) {
3111 return new WP_Error( 'invalid_currency', __( 'Invalid currency.', 'mainwp' ), array( 'status' => 400 ) );
3112 }
3113 return true;
3114 }
3115 /**
3116 * Validate product type color.
3117 *
3118 * @param string $value Product type color.
3119 * @param WP_REST_Request $request Request object.
3120 *
3121 * @return bool|WP_Error
3122 */
3123 public function validate_product_type_color( $value, $request ) {
3124 if ( empty( $value ) ) {
3125 return true;
3126 }
3127
3128 $value = $this->sanitize_field( $value );
3129 if ( ! preg_match( '/^#([A-Fa-f0-9]{6})$/', $value ) ) {
3130 return new WP_Error( 'invalid_color', __( 'Invalid color. Color must be in the format "#RRGGBB".', 'mainwp' ), array( 'status' => 400 ) );
3131 }
3132 return true;
3133 }
3134
3135 /**
3136 * Validate product type icon.
3137 *
3138 * @param string $value Product type icon.
3139 * @param WP_REST_Request $request Request object.
3140 *
3141 * @return bool|WP_Error
3142 */
3143 public function validate_product_type_icon( $value, $request ) {
3144 if ( empty( $value ) ) {
3145 return true;
3146 }
3147
3148 $value = $this->sanitize_field( $value );
3149 if ( ! preg_match( '/^[a-z0-9_\-]+:[a-z0-9_\-\s]+$/i', $value ) ) {
3150 return new WP_Error(
3151 'invalid_icon',
3152 __( 'Invalid icon. Icon must be in the format "icon_type:icon_name".', 'mainwp' ),
3153 array( 'status' => 400 )
3154 );
3155 }
3156 return true;
3157 }
3158
3159 /**
3160 * Validate product type slug.
3161 *
3162 * @param string $value Product type slug.
3163 * @param WP_REST_Request $request Request object.
3164 *
3165 * @uses Cost_Tracker_Utility::get_instance()->get_all_options()
3166 * @uses Cost_Tracker_Admin::get_default_product_types()
3167 *
3168 * @return bool|WP_Error
3169 */
3170 public function validate_product_type_slug( $value, $request ) {
3171 if ( empty( $value ) ) {
3172 return new WP_Error( 'invalid_slug', __( 'Invalid product type slug.', 'mainwp' ), array( 'status' => 400 ) );
3173 }
3174
3175 $value = $this->sanitize_field( $value );
3176 $all_opts = Cost_Tracker_Utility::get_instance()->get_all_options();
3177 $product_types = $this->safe_json_decode( $all_opts['custom_product_types'] ?? '' );
3178
3179 // Add default product types if is edit.
3180 if ( in_array( $request->get_method(), array( 'PUT', 'PATCH' ) ) ) {
3181 $product_types = array_merge( $product_types, Cost_Tracker_Admin::get_default_product_types() );
3182 }
3183
3184 if ( ! isset( $product_types[ $value ] ) ) {
3185 return new WP_Error( 'invalid_slug', __( 'Product type does not exist.', 'mainwp' ), array( 'status' => 400 ) );
3186 }
3187
3188 return true;
3189 }
3190
3191 /**
3192 * Validate payment method slug.
3193 *
3194 * @param string $value Payment method slug.
3195 * @param WP_REST_Request $request Request object.
3196 *
3197 * @uses Cost_Tracker_Utility::get_instance()->get_all_options()
3198 *
3199 * @return bool|WP_Error
3200 */
3201 public function validate_payment_method_slug( $value, $request ) { // phpcs:ignore -- NOSONAR - long method.
3202 if ( empty( $value ) ) {
3203 return new WP_Error( 'invalid_slug', __( 'Invalid payment method slug.', 'mainwp' ), array( 'status' => 400 ) );
3204 }
3205
3206 $value = $this->sanitize_field( $value );
3207 $all_opts = Cost_Tracker_Utility::get_instance()->get_all_options();
3208 $payment_methods = $this->safe_json_decode( $all_opts['custom_payment_methods'] ?? '' );
3209 if ( ! isset( $payment_methods[ $value ] ) ) {
3210 return new WP_Error( 'invalid_slug', __( 'Payment method does not exist.', 'mainwp' ), array( 'status' => 400 ) );
3211 }
3212
3213 return true;
3214 }
3215
3216 /**
3217 * Sanitize mail type.
3218 *
3219 * @param string $value Email type.
3220 *
3221 * @uses MainWP_Notification_Settings::get_default_emails_fields()
3222 *
3223 * @return string|WP_Error
3224 */
3225 public function sanitize_email_type( $value ) { // phpcs:ignore -- NOSONAR - long method.
3226 if ( empty( $value ) ) {
3227 return new WP_Error( 'invalid_mail_type', __( 'Invalid email type.', 'mainwp' ), array( 'status' => 400 ) );
3228 }
3229
3230 // Sanitize email type.
3231 $value = $this->sanitize_field( $value );
3232
3233 // Get default email settings.
3234 $email_setting = MainWP_Notification_Settings::get_default_emails_fields( $value, '', true );
3235 if ( empty( $email_setting ) ) {
3236 return new WP_Error( 'invalid_mail_type', __( 'Invalid email type.', 'mainwp' ), array( 'status' => 400 ) );
3237 }
3238
3239 return array_merge( $email_setting, array( 'type' => $value ) );
3240 }
3241
3242 /**
3243 * Validate mail type.
3244 *
3245 * @param string $value Email type.
3246 * @param WP_REST_Request $request Request object.
3247 *
3248 * @uses MainWP_Notification_Settings::get_notification_types()
3249 *
3250 * @return bool|WP_Error
3251 */
3252 public function validate_email_type( $value, $request ) { // phpcs:ignore -- NOSONAR - long method.
3253 if ( empty( $value ) ) {
3254 return new WP_Error( 'invalid_mail_type', __( 'Invalid email type.', 'mainwp' ), array( 'status' => 400 ) );
3255 }
3256
3257 $value = $this->sanitize_field( $value );
3258 // Get notification email types.
3259 $notification_emails = MainWP_Notification_Settings::get_notification_types();
3260
3261 if ( ! array_key_exists( $value, $notification_emails ) ) {
3262 return new WP_Error( 'invalid_mail_type', __( 'Email type does not exist.', 'mainwp' ), array( 'status' => 400 ) );
3263 }
3264
3265 return true;
3266 }
3267
3268 /**
3269 * Validate frequency daily update.
3270 *
3271 * @param int $value Frequency daily update.
3272 * @param WP_REST_Request $request Request object.
3273 *
3274 * @return bool|WP_Error
3275 */
3276 public function validate_frequency_daily_update( $value, $request ) {
3277 if ( '' === $value || null === $value ) {
3278 return true;
3279 }
3280
3281 $int_value = (int) $this->sanitize_field( $value );
3282 if ( $int_value < 1 || $int_value > 12 ) {
3283 return new WP_Error( 'invalid_frequency_daily_update', __( 'Invalid frequency daily update. Use 1-12.', 'mainwp' ), array( 'status' => 400 ) );
3284 }
3285 return true;
3286 }
3287
3288 /**
3289 * Validate date format.
3290 *
3291 * @param string $value Date format.
3292 * @param WP_REST_Request $request Request object.
3293 *
3294 * @return bool|WP_Error
3295 */
3296 public function validate_date_format( $value, $request ) {
3297 if ( empty( $value ) ) {
3298 return true;
3299 }
3300
3301 $value = $this->sanitize_field( $value );
3302 // No numbers allowed.
3303 if ( preg_match( '/\d/', $value ) ) {
3304 return new WP_Error(
3305 'invalid_date_format_numeric',
3306 __( 'Invalid date format: should not contain digits. Use format characters like F j, Y.', 'mainwp' ),
3307 array( 'status' => 400 )
3308 );
3309 }
3310
3311 // Allows only valid PHP date() format characters and some basic separators.
3312 if ( ! preg_match( '/^[dDjlNSwzWFmMntLoYyaABgGhHisueIOPTZcrU\-\.,:\/\s\\\\]+$/', $value ) ) {
3313 return new WP_Error(
3314 'invalid_date_format',
3315 __( 'Invalid date format. Use valid PHP date format characters like F j, Y.', 'mainwp' ),
3316 array( 'status' => 400 )
3317 );
3318 }
3319
3320 // Check rendering works.
3321 $date = date_i18n( $value, time() );
3322 if ( false === $date || '' === $date ) {
3323 return new WP_Error(
3324 'invalid_date_format_render',
3325 __( 'Invalid or unsupported date format.', 'mainwp' ),
3326 array( 'status' => 400 )
3327 );
3328 }
3329
3330 return true;
3331 }
3332
3333 /**
3334 * Validate time format.
3335 *
3336 * @param string $value Time format.
3337 *
3338 * @return bool|WP_Error
3339 */
3340 public function validate_time_format( $value ) {
3341 if ( empty( $value ) ) {
3342 return true;
3343 }
3344
3345 $value = $this->sanitize_field( $value );
3346 // No numbers allowed.
3347 if ( preg_match( '/\d/', $value ) ) {
3348 return new WP_Error(
3349 'invalid_time_format_numeric',
3350 __( 'Invalid time format: should not contain digits. Use format characters like g:i a.', 'mainwp' ),
3351 array( 'status' => 400 )
3352 );
3353 }
3354
3355 // Allows only valid PHP date() format characters and some basic separators.
3356 if ( ! preg_match( '/^[gGhHisAa\-\.,:\/\s\\\\]+$/', $value ) ) {
3357 return new WP_Error(
3358 'invalid_time_format',
3359 __( 'Invalid time format. Use valid PHP time format characters like g:i a or H:i.', 'mainwp' ),
3360 array( 'status' => 400 )
3361 );
3362 }
3363
3364 // Check rendering works.
3365 $time = date_i18n( $value, time() );
3366 if ( false === $time || '' === $time ) {
3367 return new WP_Error(
3368 'invalid_time_format_render',
3369 __( 'Invalid or unsupported time format.', 'mainwp' ),
3370 array( 'status' => 400 )
3371 );
3372 }
3373
3374 return true;
3375 }
3376
3377 /**
3378 * Sanitize timezone field.
3379 *
3380 * @param string $value Timezone.
3381 *
3382 * @return string|WP_Error
3383 */
3384 public function sanitize_timezone_field( $value ) {
3385 if ( null === $value || '' === $value ) {
3386 return '';
3387 }
3388
3389 $raw = $this->sanitize_field( $value );
3390
3391 // Check time UTC eg: "UTC±H", "UTC±H:MM" .
3392 if ( preg_match( '/^UTC(?:([+-])(0?\d|1[0-4])(?::(00|30))?)?$/i', $raw, $m ) ) {
3393 $sign = ( '-' === $m[1] ) ? -1 : 1;
3394 $hours = isset( $m[2] ) ? (int) $m[2] : 0;
3395 $minutes = isset( $m[3] ) ? (int) $m[3] : 0;
3396
3397 $offset = $sign * ( $hours + ( $minutes / 60.0 ) );
3398 return round( $offset, 2 );
3399 }
3400
3401 $all = timezone_identifiers_list();
3402 if ( in_array( $raw, $all, true ) ) {
3403 // Check timezone.
3404 try {
3405 $tz = new DateTimeZone( $raw );
3406 } catch ( Exception $e ) {
3407 return new WP_Error(
3408 'invalid_timezone_string',
3409 __( 'Invalid timezone. Use a valid format like "UTC+0" or its equivalent name, e.g. "Europe/London".', 'mainwp' ),
3410 array( 'status' => 400 )
3411 );
3412 }
3413
3414 // Convert to UTC offset.
3415 $ts = time();
3416 $dt = new DateTime( '@' . $ts );
3417 $dt->setTimezone( $tz );
3418 $offset_seconds = $tz->getOffset( $dt );
3419 $offset_hours = $offset_seconds / 3600.0;
3420
3421 return round( $offset_hours, 2 );
3422 }
3423
3424 return new WP_Error(
3425 'invalid_timezone_string',
3426 __( 'Invalid timezone. Use a valid format like "UTC+0" or its equivalent name, e.g. "Europe/London".', 'mainwp' ),
3427 array( 'status' => 400 )
3428 );
3429 }
3430
3431 /**
3432 * Validate timezone.
3433 *
3434 * @param string $value Timezone.
3435 * @param WP_REST_Request $request Request object.
3436 *
3437 * @return bool|WP_Error
3438 */
3439 public function validate_timezone( $value, $request ) {
3440 if ( null === $value || '' === $value ) {
3441 return true;
3442 }
3443
3444 $value = $this->sanitize_field( $value );
3445
3446 // eg: UTC, UTC+0, UTC+0:00, UTC+0:30 ,UTC-0:30 ...
3447 if ( preg_match( '/^UTC(?:([+-])(0?\d|1[0-4])(?::(00|30))?)?$/i', $value ) ) {
3448 return true;
3449 }
3450
3451 // Get list timezone.
3452 $valid_timezones = timezone_identifiers_list();
3453
3454 // Check timezone is valid.
3455 if ( in_array( $value, $valid_timezones, true ) ) {
3456 return true;
3457 }
3458
3459 return new WP_Error(
3460 'invalid_timezone_string',
3461 __( 'Invalid timezone. Use a valid format like UTC+0 or its equivalent name, e.g. "Europe/London".', 'mainwp' ),
3462 array( 'status' => 400 )
3463 );
3464 }
3465
3466 /**
3467 * Sanitize mainwp widgets.
3468 *
3469 * @param array $value MainWP widgets.
3470 *
3471 * @return array|WP_Error
3472 */
3473 public function sanitize_mainwp_widgets( $value ) { // phpcs:ignore -- NOSONAR - complex.
3474 if ( ! is_array( $value ) ) {
3475 return new WP_Error(
3476 'invalid_mainwp_widgets_type',
3477 __( 'mainwp_widgets must be an object.', 'mainwp' ),
3478 array( 'status' => 400 )
3479 );
3480 }
3481
3482 $existing = get_user_option( 'mainwp_settings_show_widgets' );
3483 if ( ! is_array( $existing ) ) {
3484 $existing = array();
3485 }
3486
3487 // Sanitize field data.
3488 $values = array_map( 'sanitize_text_field', wp_unslash( $value ) );
3489
3490 foreach ( $values as $k => $v ) {
3491 if ( array_key_exists( $k, $existing ) ) {
3492 $existing[ $k ] = ( 1 === (int) $v ) ? 1 : 0;
3493 }
3494 }
3495
3496 return $existing;
3497 }
3498
3499 /**
3500 * Validate mainwp widgets.
3501 *
3502 * @param array $value MainWP widgets.
3503 * @param WP_REST_Request $request Request object.
3504 *
3505 * @return bool|WP_Error
3506 */
3507 public function validate_mainwp_widgets( $value, $request ) { // phpcs:ignore -- NOSONAR - complex.
3508 if ( empty( $value ) ) {
3509 return true;
3510 }
3511
3512 if ( ! is_array( $value ) ) {
3513 return new WP_Error(
3514 'invalid_mainwp_widgets_type',
3515 __( 'mainwp_widgets must be an object.', 'mainwp' ),
3516 array( 'status' => 400 )
3517 );
3518 }
3519
3520 // Sanitize field data.
3521 $values = array_map( 'sanitize_text_field', wp_unslash( $value ) );
3522
3523 $widgets = get_user_option( 'mainwp_settings_show_widgets' );
3524 $allowed = array_keys( $widgets );
3525 $keys = array_keys( $values );
3526
3527 $invalid_keys = array_values( array_diff( $keys, $allowed ) );
3528
3529 if ( ! empty( $invalid_keys ) ) {
3530 return new WP_Error(
3531 'invalid_mainwp_widgets_keys',
3532 sprintf(
3533 /* translators: 1: invalid keys, 2: allowed keys */
3534 __( 'Invalid widget keys: %1$s. Allowed keys: %2$s.', 'mainwp' ),
3535 esc_html( implode( ', ', $invalid_keys ) ),
3536 esc_html( implode( ', ', $allowed ) )
3537 ),
3538 array( 'status' => 400 )
3539 );
3540 }
3541
3542 foreach ( $values as $k => $v ) {
3543 if ( is_array( $v ) || is_object( $v ) ) {
3544 return new WP_Error(
3545 'invalid_mainwp_widgets_value_type',
3546 /* translators: %s: Widget key name */ sprintf( __( 'Value for "%s" must be 0 or 1.', 'mainwp' ), esc_html( $k ) ),
3547 array( 'status' => 400 )
3548 );
3549 }
3550 $int = (int) $v;
3551 if ( 0 !== $int && 1 !== $int ) {
3552 return new WP_Error(
3553 'invalid_mainwp_widgets_value',
3554 /* translators: %s: Widget key name */ sprintf( __( 'Invalid value for "%s". Allowed: 0 or 1.', 'mainwp' ), esc_html( $k ) ),
3555 array( 'status' => 400 )
3556 );
3557 }
3558 }
3559
3560 return true;
3561 }
3562
3563 /**
3564 * Sanitize uptime monitoring status codes.
3565 *
3566 * @param array $value Status codes array.
3567 *
3568 * @return array|WP_Error
3569 */
3570 public function sanitize_uptime_monitoring_status_codes( $value ) {
3571 if ( empty( $value ) ) {
3572 return array();
3573 }
3574
3575 if ( ! is_array( $value ) ) {
3576 return new WP_Error(
3577 'invalid_status_codes_type',
3578 __( 'Status codes must be an array.', 'mainwp' ),
3579 array( 'status' => 400 )
3580 );
3581 }
3582
3583 // Parse ID list to ensure all values are integers.
3584 $codes = wp_parse_id_list( $value );
3585
3586 // Remove duplicates and sort.
3587 $codes = array_unique( array_map( 'intval', $codes ) );
3588 sort( $codes );
3589
3590 return $codes;
3591 }
3592
3593 /**
3594 * Validate uptime monitoring status codes.
3595 *
3596 * @param array $value Status codes array.
3597 * @param WP_REST_Request $request Request object.
3598 *
3599 * @return bool|WP_Error
3600 */
3601 public function validate_uptime_monitoring_status_codes( $value, $request ) { // phpcs:ignore -- NOSONAR
3602 if ( empty( $value ) ) {
3603 return true; // Allow empty array.
3604 }
3605
3606 if ( ! is_array( $value ) ) {
3607 return new WP_Error(
3608 'invalid_status_codes_type',
3609 __( 'Status codes must be an array.', 'mainwp' ),
3610 array( 'status' => 400 )
3611 );
3612 }
3613
3614 // Get valid HTTP status codes.
3615 $http_error_codes = array_keys( MainWP_Utility::get_http_codes() );
3616 $status_codes = wp_parse_id_list( $value );
3617
3618 // Validate each status code.
3619 foreach ( $status_codes as $code ) {
3620 $code_int = (int) $code;
3621 if ( ! in_array( $code_int, $http_error_codes, true ) ) {
3622 return new WP_Error(
3623 'invalid_status_code',
3624 sprintf(
3625 /* translators: 1: invalid status code, 2: allowed codes list */
3626 __( 'Invalid HTTP status code: %1$d. Allowed codes: %2$s.', 'mainwp' ),
3627 $code_int,
3628 esc_html( implode( ', ', $http_error_codes ) )
3629 ),
3630 array( 'status' => 400 )
3631 );
3632 }
3633 }
3634
3635 return true;
3636 }
3637
3638 /**
3639 * Sanitize sync data.
3640 *
3641 * @param array $value Sync data.
3642 *
3643 * @return array|WP_Error
3644 */
3645 public function sanitize_sync_data( $value ) { // phpcs:ignore -- NOSONAR - complex.
3646 if ( ! is_array( $value ) ) {
3647 return new WP_Error(
3648 'invalid_sync_data_type',
3649 __( 'Sync data must be an object.', 'mainwp' ),
3650 array( 'status' => 400 )
3651 );
3652 }
3653
3654 $values = array_map( 'sanitize_text_field', wp_unslash( $value ) );
3655 // Sync data.
3656 $sync_data = get_option( 'mainwp_settings_sync_data', array() );
3657 $sync_data_settings = $this->safe_json_decode( $sync_data ?? '' );
3658 if ( ! is_array( $sync_data_settings ) ) {
3659 $sync_data_settings = array();
3660 }
3661
3662 foreach ( $values as $k => $v ) {
3663 if ( array_key_exists( $k, $sync_data_settings ) ) {
3664 $sync_data_settings[ $k ] = ( 1 === (int) $v ) ? 1 : 0;
3665 }
3666 }
3667
3668 return $sync_data_settings;
3669 }
3670
3671 /**
3672 * Validate sync data.
3673 *
3674 * @param array $value Sync data.
3675 * @param WP_REST_Request $request Request object.
3676 *
3677 * @return bool|WP_Error
3678 */
3679 public function validate_sync_data( $value, $request ) { // phpcs:ignore -- NOSONAR - complex.
3680 if ( empty( $value ) ) {
3681 return true;
3682 }
3683
3684 if ( ! is_array( $value ) ) {
3685 return new WP_Error(
3686 'invalid_sync_data_type',
3687 __( 'Sync data must be an object.', 'mainwp' ),
3688 array( 'status' => 400 )
3689 );
3690 }
3691 // Sanitize field data.
3692 $values = array_map( 'sanitize_text_field', wp_unslash( $value ) );
3693 // Sync data.
3694 $sync_data = get_option( 'mainwp_settings_sync_data', array() );
3695 $sync_data_settings = $this->safe_json_decode( $sync_data ?? '' );
3696 $allowed = array_keys( $sync_data_settings );
3697 $keys = array_keys( $values );
3698 $invalid_keys = array_values( array_diff( $keys, $allowed ) );
3699
3700 if ( ! empty( $invalid_keys ) ) {
3701 return new WP_Error(
3702 'invalid_sync_data_type',
3703 sprintf(
3704 /* translators: 1: invalid keys, 2: allowed keys */
3705 __( 'Invalid sync data keys: %1$s. Allowed keys: %2$s.', 'mainwp' ),
3706 esc_html( implode( ', ', $invalid_keys ) ),
3707 esc_html( implode( ', ', $allowed ) )
3708 ),
3709 array( 'status' => 400 )
3710 );
3711 }
3712
3713 foreach ( $values as $k => $v ) {
3714 if ( is_array( $v ) || is_object( $v ) ) {
3715 return new WP_Error(
3716 'invalid_sync_data_type',
3717 /* translators: %s: Sync data key name */ sprintf( __( 'Value for "%s" must be 0 or 1.', 'mainwp' ), esc_html( $k ) ),
3718 array( 'status' => 400 )
3719 );
3720 }
3721 $int = (int) $v;
3722 if ( 0 !== $int && 1 !== $int ) {
3723 return new WP_Error(
3724 'invalid_sync_data_type',
3725 /* translators: %s: Sync data key name */ sprintf( __( 'Invalid value for "%s". Allowed: 0 or 1.', 'mainwp' ), esc_html( $k ) ),
3726 array( 'status' => 400 )
3727 );
3728 }
3729 }
3730
3731 return true;
3732 }
3733
3734 /**
3735 * Sanitize time update.
3736 *
3737 * @param string $value Time.
3738 *
3739 * @return string|WP_Error
3740 */
3741 public function sanitize_time_update( $value ) {
3742 if ( empty( $value ) ) {
3743 return empty( $value );
3744 }
3745
3746 $value = $this->sanitize_field( trim( (string) $value ) );
3747 if ( ! preg_match( '/^(?:[01]?\d|2[0-3]):[0-5]\d$/', $value ) ) {
3748 return new WP_Error(
3749 'invalid_time_update',
3750 __( 'Invalid time. Use whole hours in 24h format like 0:00, 9:00, 23:00, etc...', 'mainwp' ),
3751 array( 'status' => 400 )
3752 );
3753 }
3754
3755 return $value;
3756 }
3757
3758 /**
3759 * Validate time update.
3760 *
3761 * @param string $value Time.
3762 * @param WP_REST_Request $request Request object.
3763 *
3764 * @return bool|WP_Error
3765 */
3766 public function validate_time_update( $value, $request ) {
3767 if ( empty( $value ) ) {
3768 return true;
3769 }
3770
3771 $value = $this->sanitize_field( trim( (string) $value ) );
3772 if ( preg_match( '/^(?:[01]?\d|2[0-3]):[0-5]\d$/', $value ) ) {
3773 return true;
3774 }
3775
3776 return new WP_Error(
3777 'invalid_time_update',
3778 __( 'Invalid time. Use whole hours in 24h format like 0:00, 9:00, 23:00, etc...', 'mainwp' ),
3779 array( 'status' => 400 )
3780 );
3781 }
3782
3783 /**
3784 * Validate update general params.
3785 *
3786 * @param WP_REST_Request $request Request object.
3787 *
3788 * @return bool|WP_Error
3789 */
3790 public function validate_update_general_params( $request ) { // phpcs:ignore -- NOSONAR - complex.
3791 $primary_backup = $request->get_param( 'mainwp_primary_backup' );
3792 $backup_feature = $request->get_param( 'mainwp_enable_legacy_backup_feature' );
3793
3794 // Validate mainwp_primary_backup and mainwp_enable_legacy_backup_feature relationship.
3795 if ( null !== $primary_backup || null !== $backup_feature ) {
3796 if ( null === $primary_backup ) {
3797 $primary_backup = get_option( 'mainwp_primaryBackup' );
3798 }
3799
3800 if ( null === $backup_feature ) {
3801 $backup_feature = get_option( 'mainwp_enableLegacyBackupFeature' );
3802 }
3803
3804 $primary_backup_value = $primary_backup;
3805 if ( is_array( $primary_backup ) && isset( $primary_backup['value'] ) ) {
3806 $primary_backup_value = $primary_backup['value'];
3807 }
3808
3809 if ( 'module-api-backups' === $primary_backup_value && ( null !== $backup_feature && '0' !== (string) $backup_feature && 0 !== (int) $backup_feature ) ) {
3810 // When primary backup is module-api-backups, legacy feature must be 0.
3811 return new WP_Error(
3812 'invalid_backup_config',
3813 __( 'When mainwp_primary_backup is "module-api-backups", mainwp_enable_legacy_backup_feature must be disabled (0).', 'mainwp' ),
3814 array( 'status' => 400 )
3815 );
3816 } elseif ( '' === $primary_backup_value && ( null !== $backup_feature && '1' !== (string) $backup_feature && 1 !== (int) $backup_feature ) ) {
3817 // When primary backup is not module-api-backups, legacy feature must be 1.
3818 return new WP_Error(
3819 'invalid_backup_config',
3820 __( 'When mainwp_primary_backup is not "module-api-backups", mainwp_enable_legacy_backup_feature must be enabled (1).', 'mainwp' ),
3821 array( 'status' => 400 )
3822 );
3823 }
3824 }
3825
3826 return true;
3827 }
3828
3829 /**
3830 * Get request body.
3831 *
3832 * @param WP_REST_Request $request Full details about the request.
3833 * @return array|WP_Error
3834 */
3835 private function get_request_body( $request ) {
3836 // Get request body filed.
3837 $body = $request->get_body_params();
3838 if ( ! empty( $body ) && is_array( $body ) ) {
3839 return $body;
3840 }
3841
3842 // Get request body from body.
3843 $body = $request->get_json_params();
3844 if ( ! empty( $body ) && is_array( $body ) ) {
3845 return $body;
3846 }
3847
3848 // Get request body from raw.
3849 $body = $request->get_body();
3850 if ( ! empty( $body ) && is_string( $body ) ) {
3851 $body = json_decode( $body, true );
3852 if ( ! is_array( $body ) ) {
3853 return array();
3854 }
3855 return $body;
3856 }
3857 // Return error.
3858 return new WP_Error(
3859 'empty_body',
3860 __( 'Request body is empty.', 'mainwp' ),
3861 array( 'status' => 400 )
3862 );
3863 }
3864
3865 /**
3866 * Validate content type.
3867 *
3868 * @param WP_REST_Request $request Full details about the request.
3869 * @return bool|WP_Error
3870 */
3871 private function validate_content_type( $request ) {
3872 $content_type = (string) $request->get_header( 'content-type' );
3873 if ( 'application/json' !== $content_type ) {
3874 return new WP_Error(
3875 'invalid_content_type',
3876 __( 'Invalid content type. Expected application/json.', 'mainwp' ),
3877 array( 'status' => 400 )
3878 );
3879 }
3880 return true;
3881 }
3882
3883
3884 /**
3885 * Get site by id or domain.
3886 *
3887 * @param WP_REST_Request $request Full details about the request.
3888 * @return WP_Error|Object Item.
3889 */
3890 public function get_request_item( $request ) {
3891 $value = $request['id_domain'];
3892 $by = 'domain';
3893 if ( is_numeric( $value ) ) {
3894 $by = 'id';
3895 } else {
3896 $value = urldecode( $value );
3897 }
3898 return $this->get_site_by( $by, $value );
3899 }
3900
3901 /**
3902 * Get all websites.
3903 *
3904 * @uses MainWP_DB::instance()->get_sites()
3905 *
3906 * @return array|WP_Error
3907 */
3908 private function get_websites() {
3909 $websites = MainWP_DB::instance()->get_sites();
3910 if ( empty( $websites ) ) {
3911 return new WP_Error(
3912 'no_website_found',
3913 __( 'No website found.', 'mainwp' ),
3914 array( 'status' => 404 )
3915 );
3916 }
3917 return $websites;
3918 }
3919
3920 /**
3921 * Get website by id.
3922 *
3923 * @param int $website_id Website ID.
3924 * @param array $process_data Process data.
3925 *
3926 * @uses MainWP_DB::instance()->get_website_by_id()
3927 *
3928 * @return object|null
3929 */
3930 private function get_website_by_id( $website_id, &$process_data ) {
3931 $website = MainWP_DB::instance()->get_website_by_id( $website_id );
3932 if ( empty( $website ) ) {
3933 ++$process_data['failed'];
3934 ++$process_data['processed'];
3935 $process_data['errors'][] = array(
3936 'site_id' => $website_id,
3937 'error' => __( 'Website not found.', 'mainwp' ),
3938 );
3939 return null;
3940 }
3941 return $website;
3942 }
3943
3944 /**
3945 * Get user ID.
3946 *
3947 * @return int|WP_Error
3948 */
3949 protected function get_user_id() {
3950 $user_id = get_current_user_id();
3951
3952 // Validate user ID.
3953 if ( empty( $user_id ) ) {
3954 return new WP_Error(
3955 'invalid_user',
3956 __( 'User not authenticated.', 'mainwp' ),
3957 array( 'status' => 401 )
3958 );
3959 }
3960 return $user_id;
3961 }
3962
3963 /**
3964 * Cast field value to type.
3965 *
3966 * @param mixed $val Value to cast.
3967 * @param string $type Type to cast to.
3968 *
3969 * @return mixed
3970 */
3971 protected function cast_field_value( $val, $type ) {
3972 switch ( $type ) {
3973 case 'int':
3974 $val = (int) $val;
3975 break;
3976 case 'bool':
3977 $val = (int) ( (bool) $val );
3978 break;
3979 case 'array':
3980 $val = is_array( $val ) ? $val : array();
3981 break;
3982 case 'string':
3983 $val = (string) $val;
3984 break;
3985 default:
3986 break;
3987 }
3988 return $val;
3989 }
3990
3991 /**
3992 * Update option if present.
3993 *
3994 * @param array $body Request body.
3995 * @param string $key Key to check.
3996 * @param string $option_name Option name.
3997 * @param string $cast Type to cast to.
3998 *
3999 * @uses \MainWP\Dashboard\MainWP_Utility::update_option()
4000 *
4001 * @return bool|WP_Error
4002 */
4003 protected function update_option_if_present( $body, $key, $option_name, $cast = null ) {
4004 if ( array_key_exists( $key, $body ) ) {
4005 $val = $body[ $key ];
4006 $val = $this->cast_field_value( $val, $cast );
4007 MainWP_Utility::update_option( $option_name, $val );
4008 return true;
4009 }
4010 // translators: %s: Missing key.
4011 return new WP_Error( 'missing_key', sprintf( __( 'Missing key %s.', 'mainwp' ), esc_html( $key ) ), array( 'status' => 400 ) );
4012 }
4013
4014 /**
4015 * Format date.
4016 *
4017 * @param int $date Date.
4018 * @param string $format Date format.
4019 *
4020 * @return string
4021 */
4022 protected function format_date( int $date, $format = 'F j, Y' ) {
4023 return gmdate( $format, (int) $date );
4024 }
4025
4026 /**
4027 * Safe json decode.
4028 *
4029 * @param mixed $json JSON to decode.
4030 *
4031 * @return array
4032 */
4033 protected function safe_json_decode( $json ) {
4034 if ( empty( $json ) ) {
4035 return array();
4036 }
4037 $arr = json_decode( (string) $json, true );
4038 return is_array( $arr ) ? $arr : array();
4039 }
4040
4041 /**
4042 * Build api data.
4043 *
4044 * @uses Api_Backups_3rd_Party::get_cloudways_api_key()
4045 * @uses Api_Backups_3rd_Party::get_gridpane_api_key()
4046 * @uses Api_Backups_3rd_Party::get_vultr_api_key()
4047 * @uses Api_Backups_3rd_Party::get_linode_api_key()
4048 * @uses Api_Backups_3rd_Party::get_digitalocean_api_key()
4049 * @uses Api_Backups_3rd_Party::get_cpanel_api_key()
4050 * @uses Api_Backups_3rd_Party::get_plesk_api_key()
4051 * @uses Api_Backups_3rd_Party::get_kinsta_api_key()
4052 *
4053 * @return array<string,array{
4054 * label: string,
4055 * enabled_option: string,
4056 * options?: array<string,string>,
4057 * secrets?: array<string, callable>
4058 * }>
4059 */
4060 protected function get_api_backup_definitions() {
4061 return array(
4062 'cloudways' => array(
4063 'label' => 'Cloudways',
4064 'enabled_option' => 'mainwp_enable_cloudways_api',
4065 'options' => array(
4066 'account_email' => 'mainwp_cloudways_api_account_email',
4067 ),
4068 'secrets' => array(
4069 'api_key' => array( Api_Backups_3rd_Party::class, 'get_cloudways_api_key' ),
4070 'access_token' => array( Api_Backups_3rd_Party::class, 'get_cloudways_access_token' ),
4071 ),
4072 ),
4073 'gridpane' => array(
4074 'label' => 'GridPane',
4075 'enabled_option' => 'mainwp_enable_gridpane_api',
4076 'secrets' => array(
4077 'api_key' => array( Api_Backups_3rd_Party::class, 'get_gridpane_api_key' ),
4078 ),
4079 ),
4080 'vultr' => array(
4081 'label' => 'Vultr',
4082 'enabled_option' => 'mainwp_enable_vultr_api',
4083 'secrets' => array(
4084 'api_key' => array( Api_Backups_3rd_Party::class, 'get_vultr_api_key' ),
4085 ),
4086 ),
4087 'linode' => array(
4088 'label' => 'Akamai (Linode)',
4089 'enabled_option' => 'mainwp_enable_linode_api',
4090 'secrets' => array(
4091 'api_key' => array( Api_Backups_3rd_Party::class, 'get_linode_api_key' ),
4092 ),
4093 ),
4094 'digitalocean' => array(
4095 'label' => 'DigitalOcean',
4096 'enabled_option' => 'mainwp_enable_digitalocean_api',
4097 'secrets' => array(
4098 'api_key' => array( Api_Backups_3rd_Party::class, 'get_digitalocean_api_key' ),
4099 ),
4100 ),
4101 'cpanel' => array(
4102 'label' => 'cPanel (WP Toolkit)',
4103 'enabled_option' => 'mainwp_enable_cpanel_api',
4104 'options' => array(
4105 'url' => 'mainwp_cpanel_url',
4106 'site_path' => 'mainwp_cpanel_site_path',
4107 'username' => 'mainwp_cpanel_account_username',
4108 ),
4109 ),
4110 'plesk' => array(
4111 'label' => 'Plesk',
4112 'enabled_option' => 'mainwp_enable_plesk_api',
4113 'options' => array(
4114 'url' => 'mainwp_plesk_api_url',
4115 ),
4116 'secrets' => array(
4117 'api_key' => array( Api_Backups_3rd_Party::class, 'get_plesk_api_key' ),
4118 ),
4119 ),
4120 'kinsta' => array(
4121 'label' => 'Kinsta',
4122 'enabled_option' => 'mainwp_enable_kinsta_api',
4123 'options' => array(
4124 'account_email' => 'mainwp_kinsta_api_account_email',
4125 'company_id' => 'mainwp_kinsta_company_id',
4126 ),
4127 'secrets' => array(
4128 'api_key' => array( Api_Backups_3rd_Party::class, 'get_kinsta_api_key' ),
4129 ),
4130 ),
4131 );
4132 }
4133
4134 /**
4135 * Get tool settings data.
4136 *
4137 * @uses MainWP_Settings::get_instance()->get_current_user_theme()
4138 *
4139 * @return array<string,mixed> Tool settings data.
4140 */
4141 protected function get_tool_settings_data() {
4142 return array(
4143 'mainwp_theme' => MainWP_Settings::get_instance()->get_current_user_theme(),
4144 'guided_tours' => get_option( 'mainwp_enable_guided_tours', 0 ),
4145 'chatbase' => get_option( 'mainwp_enable_guided_chatbase', 0 ),
4146 'guided_video' => get_option( 'mainwp_enable_guided_video', 0 ),
4147 );
4148 }
4149
4150 /**
4151 * Get general settings data.
4152 *
4153 * @uses MainWP_Settings_Indicator::get_defaults_value()
4154 *
4155 * @return array
4156 */
4157 protected function get_general_settings_data() {
4158 // Default Setting.
4159 $default_setting = MainWP_Settings_Indicator::get_defaults_value();
4160 $show_widgets = get_user_option( 'mainwp_settings_show_widgets' );
4161
4162 if ( ! is_array( $show_widgets ) ) {
4163 $show_widgets = array();
4164 }
4165
4166 // Map settings.
4167 $gmt_offset = (float) get_option( 'gmt_offset', 0 );
4168 $tz_sign = $gmt_offset >= 0 ? '+' : '-';
4169 $tz_value = (string) abs( $gmt_offset );
4170 $tz_string = sprintf( 'UTC%s%s', $tz_sign, $tz_value );
4171
4172 // Primary backup.
4173 $primary_backup = get_option( 'mainwp_primaryBackup' );
4174
4175 // Get primary backup methods.
4176 $primary_methods = array();
4177 $primary_methods = apply_filters_deprecated( 'mainwp-getprimarybackup-methods', array( $primary_methods ), '4.0.7.2', 'mainwp_getprimarybackup_methods' ); // @deprecated Use 'mainwp_getprimarybackup_methods' instead. NOSONAR - not IP.
4178 $primary_backup_methods = apply_filters( 'mainwp_getprimarybackup_methods', $primary_methods );
4179
4180 if ( ! is_array( $primary_backup_methods ) ) {
4181 $primary_backup_methods = array();
4182 }
4183
4184 // Get selected backup method.
4185 $backup_method = array_filter(
4186 $primary_backup_methods,
4187 function ( $method ) use ( $primary_backup ) {
4188 return $method['value'] === $primary_backup;
4189 }
4190 );
4191
4192 if ( empty( $backup_method ) ) {
4193 $backup_method = array(
4194 'value' => '',
4195 'title' => 'Native backups',
4196 );
4197 }
4198
4199 $enable_legacy_backup = get_option( 'mainwp_enableLegacyBackupFeature' );
4200
4201 // get_user_option()'s second argument is a user id, not a default, and the defaults array keys this on the option name rather than the response field name.
4202 $sidebar_position = get_user_option( 'mainwp_sidebarPosition' );
4203 if ( false === $sidebar_position ) {
4204 $sidebar_position = $default_setting['mainwp_sidebarPosition'];
4205 }
4206
4207 return array(
4208 // General settings.
4209 'time_daily_update' => get_option( 'mainwp_timeDailyUpdate', $default_setting['mainwp_timeDailyUpdate'] ),
4210 'frequency_daily_update' => (int) get_option( 'mainwp_frequencyDailyUpdate', $default_setting['mainwp_frequencyDailyUpdate'] ),
4211 'date_format' => get_option( 'date_format', $default_setting['date_format'] ),
4212 'time_format' => get_option( 'time_format', $default_setting['time_format'] ),
4213 'timezone_string' => $tz_string,
4214 'sidebar_position' => (int) $sidebar_position,
4215 'hide_update_everything' => get_option( 'mainwp_hide_update_everything', $default_setting['mainwp_hide_update_everything'] ),
4216 'mainwp_widgets' => $show_widgets,
4217 'plugin_automatic_daily_update' => (int) get_option( 'mainwp_pluginAutomaticDailyUpdate', $default_setting['mainwp_pluginAutomaticDailyUpdate'] ),
4218 'theme_automatic_daily_update' => (int) get_option( 'mainwp_themeAutomaticDailyUpdate', $default_setting['mainwp_themeAutomaticDailyUpdate'] ),
4219 'trans_automatic_daily_update' => (int) get_option( 'mainwp_transAutomaticDailyUpdate', 0 ),
4220 'automatic_daily_update' => (int) get_option( 'mainwp_automaticDailyUpdate', $default_setting['mainwp_automaticDailyUpdate'] ),
4221 'frequency_auto_update' => get_option( 'mainwp_frequency_AutoUpdate', $default_setting['mainwp_frequency_AutoUpdate'] ),
4222 'time_auto_update' => get_option( 'mainwp_time_AutoUpdate', $default_setting['mainwp_time_AutoUpdate'] ),
4223 'show_language_updates' => (int) get_option( 'mainwp_show_language_updates', $default_setting['mainwp_show_language_updates'] ),
4224 'disable_update_confirmations' => (int) get_option( 'mainwp_disable_update_confirmations', $default_setting['mainwp_disable_update_confirmations'] ),
4225 'check_http_response' => (int) get_option( 'mainwp_check_http_response', $default_setting['mainwp_check_http_response'] ),
4226 'check_http_response_method' => get_option( 'mainwp_check_http_response_method', $default_setting['mainwp_check_http_response_method'] ),
4227 'backup_before_upgrade' => (int) get_option( 'mainwp_backup_before_upgrade', $default_setting['mainwp_backup_before_upgrade'] ),
4228 'backup_before_upgrade_days' => (int) get_option( 'mainwp_backup_before_upgrade_days', $default_setting['mainwp_backup_before_upgrade_days'] ),
4229 'numberdays_outdate_plugin_theme' => (int) get_option( 'mainwp_numberdays_Outdate_Plugin_Theme', $default_setting['mainwp_numberdays_Outdate_Plugin_Theme'] ),
4230 'dayinweek_auto_update' => (int) get_option( 'mainwp_dayinweek_AutoUpdate', $default_setting['mainwp_dayinweek_AutoUpdate'] ),
4231 'dayinmonth_auto_update' => (int) get_option( 'mainwp_dayinmonth_AutoUpdate', $default_setting['mainwp_dayinmonth_AutoUpdate'] ),
4232 'delay_autoupdate' => (int) get_option( 'mainwp_delay_autoupdate', $default_setting['mainwp_delay_autoupdate'] ),
4233 'mainwp_primary_backup' => $backup_method,
4234 'mainwp_enable_legacy_backup_feature' => $enable_legacy_backup,
4235 'mainwp_backups_on_server' => get_option( 'mainwp_backupsOnServer' ),
4236 'mainwp_backup_on_external_sources' => get_option( 'mainwp_backupOnExternalSources' ),
4237 'mainwp_archive_format' => get_option( 'mainwp_archiveFormat' ),
4238 'mainwp_notification_on_backup_fail' => get_option( 'mainwp_notificationOnBackupFail' ),
4239 'mainwp_notification_on_backup_start' => get_option( 'mainwp_notificationOnBackupStart' ),
4240 'mainwp_chunked_backup_tasks' => get_option( 'mainwp_chunkedBackupTasks' ),
4241 );
4242 }
4243
4244 /**
4245 * Get advanced settings data.
4246 *
4247 * @uses MainWP_Settings_Indicator::get_defaults_value()
4248 * @uses MainWP_System_Utility::get_open_ssl_sign_algos()
4249 *
4250 * @return array
4251 */
4252 protected function get_advanced_settings_data() {
4253 // Default Setting.
4254 $default_setting = MainWP_Settings_Indicator::get_defaults_value();
4255 // Sync data.
4256 $sync_data = get_option( 'mainwp_settings_sync_data', array() );
4257 $sync_data_settings = $this->safe_json_decode( $sync_data ?? '' );
4258 // Signature algorithm.
4259 $sign_algs = MainWP_System_Utility::get_open_ssl_sign_algos();
4260 $signature_algo = (int) get_option( 'mainwp_connect_signature_algo', $default_setting['mainwp_connect_signature_algo'] );
4261
4262 return array(
4263 'mainwp_maximum_requests' => (int) get_option( 'mainwp_maximumRequests', $default_setting['mainwp_maximumRequests'] ),
4264 'mainwp_minimum_delay' => (int) get_option( 'mainwp_minimumDelay', $default_setting['mainwp_minimumDelay'] ),
4265 'mainwp_maximum_ip_requests' => (int) get_option( 'mainwp_maximumIPRequests', $default_setting['mainwp_maximumIPRequests'] ),
4266 'mainwp_minimum_ip_delay' => (int) get_option( 'mainwp_minimumIPDelay', $default_setting['mainwp_minimumIPDelay'] ),
4267 'mainwp_chunksitesnumber' => (int) get_option( 'mainwp_chunksitesnumber', 10 ),
4268 'mainwp_chunksleepinterval' => (int) get_option( 'mainwp_chunksleepinterval', 5 ),
4269 'mainwp_maximum_sync_requests' => (int) get_option( 'mainwp_maximumSyncRequests', $default_setting['mainwp_maximumSyncRequests'] ),
4270 'mainwp_maximum_install_update_requests' => (int) get_option( 'mainwp_maximumInstallUpdateRequests', $default_setting['mainwp_maximum_install_update_requests'] ),
4271 'mainwp_maximum_uptime_monitoring_requests' => (int) get_option( 'mainwp_maximum_uptime_monitoring_requests', $default_setting['mainwp_maximum_uptime_monitoring_requests'] ),
4272 'mainwp_optimize' => (int) get_option( 'mainwp_optimize', $default_setting['mainwp_optimize'] ),
4273 'mainwp_wp_cron' => (int) get_option( 'mainwp_wp_cron', $default_setting['mainwp_wp_cron'] ),
4274 'mainwp_ssl_verify_certificate' => (int) get_option( 'mainwp_sslVerifyCertificate', $default_setting['mainwp_ssl_verify_certificate'] ),
4275 'mainwp_verify_connection_method' => (int) get_option( 'mainwp_verify_connection_method', $default_setting['mainwp_verify_connection_method'] ),
4276 'mainwp_connect_signature_algo' => isset( $sign_algs[ $signature_algo ] ) ? $sign_algs[ $signature_algo ] : $default_setting['mainwp_connect_signature_algo'],
4277 'mainwp_force_use_ipv4' => (int) get_option( 'mainwp_forceUseIPv4', $default_setting['mainwp_forceUseIPv4'] ),
4278 'sync_data' => $sync_data_settings,
4279 );
4280 }
4281
4282 /**
4283 * Get monitoring settings data.
4284 *
4285 * @uses MainWP_Uptime_Monitoring_Handle::get_global_monitoring_settings()
4286 * @uses MainWP_Uptime_Monitoring_Edit::get_interval_values()
4287 * @uses MainWP_Uptime_Monitoring_Edit::get_timeout_values()
4288 *
4289 * @return array
4290 */
4291 protected function get_monitoring_settings_data() {
4292 $monitoring_settings = MainWP_Uptime_Monitoring_Handle::get_global_monitoring_settings();
4293
4294 // Get interval values.
4295 $interval_values = MainWP_Uptime_Monitoring_Edit::get_interval_values( false );
4296 $interval = $monitoring_settings['interval'] ?? 60;
4297 $interval = isset( $interval_values[ $interval ] ) ? $interval_values[ $interval ] : $interval_values[60];
4298
4299 // Get timeout values.
4300 $timeout_values = MainWP_Uptime_Monitoring_Edit::get_timeout_values( false );
4301 $timeout = $monitoring_settings['timeout'] ?? 60;
4302 $timeout = isset( $timeout_values[ $timeout ] ) ? $timeout_values[ $timeout ] : $timeout_values[60];
4303
4304 return array(
4305 'mainwp_uptime_monitoring_active' => (int) $monitoring_settings['active'] ?? 0,
4306 'mainwp_uptime_monitoring_interval' => $interval,
4307 'mainwp_uptime_monitoring_method' => $monitoring_settings['method'] ?? 'head',
4308 'mainwp_uptime_monitoring_timeout' => $timeout,
4309 'mainwp_uptime_monitoring_type' => $monitoring_settings['type'] ?? 'http',
4310 'mainwp_uptime_monitoring_up_status_codes' => explode( ',', $monitoring_settings['up_status_codes'] ) ?? array(),
4311 'mainwp_uptime_monitoring_down_confirmation_check' => (int) $monitoring_settings['maxretries'] ?? 1,
4312 'mainwp_uptime_monitoring_keyword' => $monitoring_settings['keyword'] ?? '',
4313 'mainwp_uptime_monitoring_bypass_cache' => (int) ( $monitoring_settings['bypass_cache'] ?? 0 ),
4314 'mainwp_disable_sites_health_monitoring' => (int) get_option( 'mainwp_disableSitesHealthMonitoring', 1 ),
4315 'mainwp_sitehealth_threshold' => (int) get_option( 'mainwp_sitehealthThreshold', 80 ),
4316 );
4317 }
4318
4319 /**
4320 * Get the API keys schema, conforming to JSON Schema.
4321 *
4322 * @since 5.2
4323 * @return array
4324 */
4325 public function get_item_schema() { // phpcs:ignore -- NOSONAR - long schema.
4326 return array(
4327 '$schema' => 'http://json-schema.org/draft-04/schema#',
4328 'title' => 'settings',
4329 'type' => 'object',
4330 'properties' => array(
4331 'time_daily_update' => array(
4332 'type' => 'string',
4333 'description' => __( 'Time for daily updates.', 'mainwp' ),
4334 'context' => array( 'view', 'edit' ),
4335 ),
4336 'frequency_daily_update' => array(
4337 'type' => 'integer',
4338 'description' => __( 'Frequency of daily updates.', 'mainwp' ),
4339 'context' => array( 'view', 'edit' ),
4340 ),
4341 'date_format' => array(
4342 'type' => 'string',
4343 'description' => __( 'Date format.', 'mainwp' ),
4344 'context' => array( 'view', 'edit' ),
4345 ),
4346 'time_format' => array(
4347 'type' => 'string',
4348 'description' => __( 'Time format.', 'mainwp' ),
4349 'context' => array( 'view', 'edit' ),
4350 ),
4351 'timezone_string' => array(
4352 'type' => 'string',
4353 'description' => __( 'Timezone string.', 'mainwp' ),
4354 'context' => array( 'view', 'edit' ),
4355 ),
4356 'sidebar_position' => array(
4357 'type' => 'integer',
4358 'description' => __( 'Plugin automatic daily update enabled.', 'mainwp' ),
4359 'context' => array( 'view', 'edit' ),
4360 ),
4361 'hide_update_everything' => array(
4362 'type' => 'integer',
4363 'description' => __( 'Hide update everything.', 'mainwp' ),
4364 'context' => array( 'view', 'edit' ),
4365 ),
4366 'mainwp_widgets' => array(
4367 'type' => 'array',
4368 'description' => __( 'MainWP widgets.', 'mainwp' ),
4369 'context' => array( 'view', 'edit' ),
4370 'items' => array(
4371 'type' => 'integer',
4372 ),
4373 ),
4374 'plugin_automatic_daily_update' => array(
4375 'type' => 'integer',
4376 'description' => __( 'Plugin automatic daily update enabled.', 'mainwp' ),
4377 'context' => array( 'view', 'edit' ),
4378 ),
4379 'theme_automatic_daily_update' => array(
4380 'type' => 'integer',
4381 'description' => __( 'Theme automatic daily update enabled.', 'mainwp' ),
4382 'context' => array( 'view', 'edit' ),
4383 ),
4384 'trans_automatic_daily_update' => array(
4385 'type' => 'integer',
4386 'description' => __( 'Translation automatic daily update enabled.', 'mainwp' ),
4387 'context' => array( 'view', 'edit' ),
4388 ),
4389 'automatic_daily_update' => array(
4390 'type' => 'integer',
4391 'description' => __( 'Automatic daily update enabled.', 'mainwp' ),
4392 'context' => array( 'view', 'edit' ),
4393 ),
4394 'frequency_auto_update' => array(
4395 'type' => 'string',
4396 'description' => __( 'Frequency of auto updates.', 'mainwp' ),
4397 'context' => array( 'view', 'edit' ),
4398 ),
4399 'time_auto_update' => array(
4400 'type' => 'string',
4401 'description' => __( 'Time for auto updates.', 'mainwp' ),
4402 'context' => array( 'view', 'edit' ),
4403 ),
4404 'show_language_updates' => array(
4405 'type' => 'integer',
4406 'description' => __( 'Show language updates.', 'mainwp' ),
4407 'context' => array( 'view', 'edit' ),
4408 ),
4409 'disable_update_confirmations' => array(
4410 'type' => 'integer',
4411 'description' => __( 'Disable update confirmations.', 'mainwp' ),
4412 'context' => array( 'view' ),
4413 ),
4414 'check_http_response' => array(
4415 'type' => 'integer',
4416 'description' => __( 'Check HTTP response after update.', 'mainwp' ),
4417 'context' => array( 'view', 'edit' ),
4418 ),
4419 'check_http_response_method' => array(
4420 'type' => 'string',
4421 'description' => __( 'HTTP method for response check.', 'mainwp' ),
4422 'context' => array( 'view', 'edit' ),
4423 ),
4424 'backup_before_upgrade' => array(
4425 'type' => 'integer',
4426 'description' => __( 'Backup before upgrade enabled.', 'mainwp' ),
4427 'context' => array( 'view' ),
4428 ),
4429 'backup_before_upgrade_days' => array(
4430 'type' => 'integer',
4431 'description' => __( 'Days to check for backup before upgrade.', 'mainwp' ),
4432 'context' => array( 'view', 'edit' ),
4433 ),
4434 'numberdays_outdate_plugin_theme' => array(
4435 'type' => 'integer',
4436 'description' => __( 'Number of days to consider plugin/theme as outdated.', 'mainwp' ),
4437 'context' => array( 'view', 'edit' ),
4438 ),
4439 'dayinweek_auto_update' => array(
4440 'type' => 'integer',
4441 'description' => __( 'Day in week for auto updates.', 'mainwp' ),
4442 'context' => array( 'view', 'edit' ),
4443 ),
4444 'dayinmonth_auto_update' => array(
4445 'type' => 'integer',
4446 'description' => __( 'Day in month for auto updates.', 'mainwp' ),
4447 'context' => array( 'view', 'edit' ),
4448 ),
4449 'delay_autoupdate' => array(
4450 'type' => 'integer',
4451 'description' => __( 'Delay for auto updates.', 'mainwp' ),
4452 'context' => array( 'view', 'edit' ),
4453 ),
4454 'mainwp_maximum_requests' => array(
4455 'type' => 'integer',
4456 'description' => __( 'Maximum requests.', 'mainwp' ),
4457 'context' => array( 'advanced_view', 'advanced_edit' ),
4458 ),
4459 'mainwp_minimum_delay' => array(
4460 'type' => 'integer',
4461 'description' => __( 'Minimum delay.', 'mainwp' ),
4462 'context' => array( 'advanced_view', 'advanced_edit' ),
4463 ),
4464 'mainwp_maximum_ip_requests' => array(
4465 'type' => 'integer',
4466 'description' => __( 'Maximum IP requests.', 'mainwp' ),
4467 'context' => array( 'advanced_view', 'advanced_edit' ),
4468 ),
4469 'mainwp_minimum_ip_delay' => array(
4470 'type' => 'integer',
4471 'description' => __( 'Minimum IP delay.', 'mainwp' ),
4472 'context' => array( 'advanced_view', 'advanced_edit' ),
4473 ),
4474 'mainwp_chunksitesnumber' => array(
4475 'type' => 'integer',
4476 'description' => __( 'Chunk sites number.', 'mainwp' ),
4477 'context' => array( 'advanced_view', 'advanced_edit' ),
4478 ),
4479 'mainwp_chunksleepinterval' => array(
4480 'type' => 'integer',
4481 'description' => __( 'Chunk sleep interval.', 'mainwp' ),
4482 'context' => array( 'advanced_view', 'advanced_edit' ),
4483 ),
4484 'mainwp_maximum_sync_requests' => array(
4485 'type' => 'integer',
4486 'description' => __( 'Maximum sync requests.', 'mainwp' ),
4487 'context' => array( 'advanced_view', 'advanced_edit' ),
4488 ),
4489 'mainwp_maximum_install_update_requests' => array(
4490 'type' => 'integer',
4491 'description' => __( 'Maximum install and update requests.', 'mainwp' ),
4492 'context' => array( 'advanced_view', 'advanced_edit' ),
4493 ),
4494 'mainwp_maximum_uptime_monitoring_requests' => array(
4495 'type' => 'integer',
4496 'description' => __( 'Maximum uptime monitoring requests.', 'mainwp' ),
4497 'context' => array( 'advanced_view', 'advanced_edit' ),
4498 ),
4499 'mainwp_optimize' => array(
4500 'type' => 'integer',
4501 'description' => __( 'Optimize data loading.', 'mainwp' ),
4502 'context' => array( 'advanced_view', 'advanced_edit' ),
4503 ),
4504 'mainwp_wp_cron' => array(
4505 'type' => 'integer',
4506 'description' => __( 'Use WP Cron.', 'mainwp' ),
4507 'context' => array( 'advanced_view', 'advanced_edit' ),
4508 ),
4509 'mainwp_ssl_verify_certificate' => array(
4510 'type' => 'integer',
4511 'description' => __( 'Verify SSL certificate.', 'mainwp' ),
4512 'context' => array( 'advanced_view', 'advanced_edit' ),
4513 ),
4514 'mainwp_verify_connection_method' => array(
4515 'type' => 'integer',
4516 'description' => __( 'Verify connection method.', 'mainwp' ),
4517 'context' => array( 'advanced_view', 'advanced_edit' ),
4518 ),
4519 'mainwp_connect_signature_algo' => array(
4520 'type' => 'integer',
4521 'description' => __( 'OpenSSL signature algorithm.', 'mainwp' ),
4522 'context' => array( 'advanced_view', 'advanced_edit' ),
4523 ),
4524 'mainwp_force_use_ipv4' => array(
4525 'type' => 'integer',
4526 'description' => __( 'Force use IPv4.', 'mainwp' ),
4527 'context' => array( 'advanced_view', 'advanced_edit' ),
4528 ),
4529 'sync_data' => array(
4530 'type' => 'array',
4531 'description' => __( 'Sync data.', 'mainwp' ),
4532 'context' => array( 'advanced_view', 'advanced_edit' ),
4533 'items' => array(
4534 'type' => 'string',
4535 ),
4536 ),
4537 'heading' => array(
4538 'type' => 'string',
4539 'description' => __( 'Mail heading.', 'mainwp' ),
4540 'context' => array( 'email_view', 'email_edit' ),
4541 ),
4542 'type' => array(
4543 'type' => 'string',
4544 'description' => __( 'Type.', 'mainwp' ),
4545 'context' => array( 'email_view' ),
4546 ),
4547 'subject' => array(
4548 'type' => 'string',
4549 'description' => __( 'Mail subject.', 'mainwp' ),
4550 'context' => array( 'email_view', 'email_edit' ),
4551 ),
4552 'recipients' => array(
4553 'type' => 'string',
4554 'description' => __( 'Recipients.', 'mainwp' ),
4555 'context' => array( 'email_view', 'email_edit' ),
4556 ),
4557 'disable' => array(
4558 'type' => 'integer',
4559 'description' => __( 'Disable.', 'mainwp' ),
4560 'context' => array( 'email_view', 'email_edit' ),
4561 ),
4562 'currency' => array(
4563 'type' => 'string',
4564 'description' => __( 'Currency.', 'mainwp' ),
4565 'context' => array( 'cost_tracker_view' ),
4566 ),
4567 'currency_position' => array(
4568 'type' => 'string',
4569 'description' => __( 'Currency position.', 'mainwp' ),
4570 'context' => array( 'cost_tracker_view' ),
4571 ),
4572 'thousand_separator' => array(
4573 'type' => 'string',
4574 'description' => __( 'Thousand separator.', 'mainwp' ),
4575 'context' => array( 'cost_tracker_view' ),
4576 ),
4577 'decimal_separator' => array(
4578 'type' => 'string',
4579 'description' => __( 'Decimal separator.', 'mainwp' ),
4580 'context' => array( 'cost_tracker_view' ),
4581 ),
4582 'decimals' => array(
4583 'type' => 'integer',
4584 'description' => __( 'Decimals.', 'mainwp' ),
4585 'context' => array( 'cost_tracker_view' ),
4586 ),
4587 'product_categories' => array(
4588 'type' => 'array',
4589 'description' => __( 'Product categories.', 'mainwp' ),
4590 'context' => array( 'cost_tracker_view' ),
4591 'items' => array(
4592 'type' => 'object',
4593 ),
4594 ),
4595 'payment_methods' => array(
4596 'type' => 'array',
4597 'description' => __( 'Payment methods.', 'mainwp' ),
4598 'context' => array( 'cost_tracker_view' ),
4599 'items' => array(
4600 'type' => 'string',
4601 ),
4602 ),
4603 'enable_insights_logging' => array(
4604 'type' => 'integer',
4605 'description' => __( 'Enable insights logging.', 'mainwp' ),
4606 'context' => array( 'dashboard_insights_view' ),
4607 ),
4608 'api_backups' => array(
4609 'type' => 'array',
4610 'description' => __( 'API backups.', 'mainwp' ),
4611 'context' => array( 'api_backups_view' ),
4612 'items' => array(
4613 'type' => 'object',
4614 ),
4615 ),
4616 'mainwp_theme' => array(
4617 'type' => 'string',
4618 'description' => __( 'MainWP theme.', 'mainwp' ),
4619 'context' => array( 'tool_view' ),
4620 ),
4621 'guided_tours' => array(
4622 'type' => 'integer',
4623 'description' => __( 'Usetiful (Interactiive Guides & Tips).', 'mainwp' ),
4624 'context' => array( 'tool_view' ),
4625 ),
4626 'chatbase' => array(
4627 'type' => 'integer',
4628 'description' => __( 'Chatbase (AI-Powered Chat Support).', 'mainwp' ),
4629 'context' => array( 'tool_view' ),
4630 ),
4631 'guided_video' => array(
4632 'type' => 'integer',
4633 'description' => __( 'Youtube Embeds (Video Tutorials).', 'mainwp' ),
4634 'context' => array( 'tool_view' ),
4635 ),
4636 'mainwp_disable_sites_health_monitoring' => array(
4637 'type' => 'integer',
4638 'description' => __( 'Disable sites health monitoring.', 'mainwp' ),
4639 'context' => array( 'monitoring_view' ),
4640 ),
4641 'mainwp_sitehealth_threshold' => array(
4642 'type' => 'integer',
4643 'description' => __( 'Site health threshold.', 'mainwp' ),
4644 'context' => array( 'monitoring_view' ),
4645 ),
4646 'mainwp_uptime_monitoring_active' => array(
4647 'type' => 'integer',
4648 'description' => __( 'Uptime monitoring active.', 'mainwp' ),
4649 'context' => array( 'monitoring_view' ),
4650 ),
4651 'mainwp_uptime_monitoring_interval' => array(
4652 'type' => 'string',
4653 'description' => __( 'Uptime monitoring interval.', 'mainwp' ),
4654 'context' => array( 'monitoring_view' ),
4655 ),
4656 'mainwp_uptime_monitoring_method' => array(
4657 'type' => 'string',
4658 'description' => __( 'Uptime monitoring method.', 'mainwp' ),
4659 'context' => array( 'monitoring_view' ),
4660 ),
4661 'mainwp_uptime_monitoring_timeout' => array(
4662 'type' => 'string',
4663 'description' => __( 'Uptime monitoring timeout.', 'mainwp' ),
4664 'context' => array( 'monitoring_view' ),
4665 ),
4666 'mainwp_uptime_monitoring_type' => array(
4667 'type' => 'string',
4668 'description' => __( 'Uptime monitoring type.', 'mainwp' ),
4669 'context' => array( 'monitoring_view' ),
4670 ),
4671 'mainwp_uptime_monitoring_up_status_codes' => array(
4672 'type' => 'array',
4673 'description' => __( 'Uptime monitoring up status codes.', 'mainwp' ),
4674 'context' => array( 'monitoring_view' ),
4675 ),
4676 'mainwp_uptime_monitoring_down_confirmation_check' => array(
4677 'type' => 'integer',
4678 'description' => __( 'Uptime monitoring down confirmation check.', 'mainwp' ),
4679 'context' => array( 'monitoring_view' ),
4680 ),
4681 'mainwp_uptime_monitoring_keyword' => array(
4682 'type' => 'string',
4683 'description' => __( 'Uptime monitoring keyword.', 'mainwp' ),
4684 'context' => array( 'monitoring_view' ),
4685 ),
4686 'mainwp_uptime_monitoring_bypass_cache' => array(
4687 'type' => 'integer',
4688 'description' => __( 'Uptime monitoring attempt to bypass page cache.', 'mainwp' ),
4689 'context' => array( 'monitoring_view' ),
4690 ),
4691 'mainwp_primary_backup' => array(
4692 'type' => 'object',
4693 'description' => __( 'Primary backup.', 'mainwp' ),
4694 'context' => array( 'view', 'edit' ),
4695 ),
4696 'mainwp_enable_legacy_backup_feature' => array(
4697 'type' => 'integer',
4698 'description' => __( 'Enable legacy backup feature.', 'mainwp' ),
4699 'context' => array( 'view' ),
4700 ),
4701 'mainwp_backups_on_server' => array(
4702 'type' => 'integer',
4703 'description' => __( 'Backups on server.', 'mainwp' ),
4704 'context' => array( 'view', 'edit' ),
4705 ),
4706 'mainwp_backup_on_external_sources' => array(
4707 'type' => 'integer',
4708 'description' => __( 'Backups on external sources.', 'mainwp' ),
4709 'context' => array( 'view', 'edit' ),
4710 ),
4711 'mainwp_archive_format' => array(
4712 'type' => 'string',
4713 'description' => __( 'Archive format.', 'mainwp' ),
4714 'context' => array( 'view', 'edit' ),
4715 ),
4716 'mainwp_notification_on_backup_fail' => array(
4717 'type' => 'integer',
4718 'description' => __( 'Notification on backup fail.', 'mainwp' ),
4719 'context' => array( 'view', 'edit' ),
4720 ),
4721 'mainwp_notification_on_backup_start' => array(
4722 'type' => 'integer',
4723 'description' => __( 'Notification on backup start.', 'mainwp' ),
4724 'context' => array( 'view', 'edit' ),
4725 ),
4726 'mainwp_chunked_backup_tasks' => array(
4727 'type' => 'integer',
4728 'description' => __( 'Chunked backup tasks.', 'mainwp' ),
4729 'context' => array( 'view', 'edit' ),
4730 ),
4731 ),
4732 );
4733 }
4734 }
4735