Files
hub-insurance/wp-content/plugins/visual-regression-tests/includes/features/class-settings-page.php
T
2026-07-02 15:54:39 -06:00

452 lines
15 KiB
PHP

<?php
namespace Vrts\Features;
use Vrts\Core\Utilities\Sanitization;
use Vrts\Core\Utilities\Url_Helpers;
use Vrts\Features\Subscription;
use Vrts\Services\Test_Service;
class Settings_Page {
/**
* Page slug.
*
* @var string
*/
protected $page_slug = 'vrts-settings';
/**
* Constructor.
*/
public function __construct() {
add_action( 'init', [ $this, 'add_settings' ] );
add_action( 'admin_menu', [ $this, 'add_submenu_page' ] );
add_action( 'admin_init', [ $this, 'settings_migration' ] );
add_action( 'add_option_vrts_click_selectors', [ $this, 'do_after_update_click_selectors' ], 10, 2 );
add_action( 'update_option_vrts_click_selectors', [ $this, 'do_after_update_click_selectors' ], 10, 2 );
add_action( 'pre_update_option_vrts_license_key', [ $this, 'do_before_add_license_key' ], 10, 2 );
add_action( 'pre_update_option_vrts_email_update_notification_address', [ $this, 'do_before_updating_email_address' ], 10 );
add_action( 'pre_update_option_vrts_email_api_notification_address', [ $this, 'do_before_updating_email_address' ], 10 );
add_action( 'update_option_vrts_automatic_comparison', [ $this, 'do_after_update_vrts_automatic_comparison' ], 10, 2 );
}
/**
* Add submenu.
*/
public function add_submenu_page() {
$submenu_page = add_submenu_page(
'vrts',
esc_html__( 'Settings', 'visual-regression-tests' ),
esc_html__( 'Settings', 'visual-regression-tests' ),
'manage_options',
$this->page_slug,
[ $this, 'render_page' ]
);
add_action( 'load-' . $submenu_page, [ $this, 'init_notifications' ] );
}
/**
* Render settings page.
*/
public function render_page() {
vrts()->component( 'settings-page', [
'title' => esc_html__( 'Settings', 'visual-regression-tests' ),
'settings_fields' => $this->page_slug,
'settings_sections' => $this->page_slug,
] );
}
/**
* Register settings.
*/
public function add_settings() {
$has_subscription = (bool) Subscription::get_subscription_status();
vrts()->settings()->add_section([
'id' => 'vrts-settings-section-general',
'page' => $this->page_slug,
'title' => '',
]);
// Notice:
// value_type can be one of these 'string', 'boolean', 'integer', 'number', 'array', and 'object'.
// sanitize_callback can be a default wp sanitize function or a custom function from the Sanitization class.
// 'sanitize_callback' => '[ Sanitization::class, 'sanitize_checkbox' ]'.
vrts()->settings()->add_setting([
'type' => 'text',
'id' => 'vrts_click_selectors',
'section' => 'vrts-settings-section-general',
'title' => esc_html__( 'Click Element', 'visual-regression-tests' ),
'description' => sprintf(
'%s<br>%s',
sprintf(
/* translators: %s: link wrapper. */
esc_html__( 'Add a %1$sCSS selector%2$s to click on the first element found before creating a new snapshot.', 'visual-regression-tests' ),
'<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors" target="_blank">',
'</a>'
),
esc_html__( 'Useful to accept cookie banners or anything else that should be clicked after page load.', 'visual-regression-tests' )
),
'placeholder' => esc_html__( 'e.g.: #accept-cookies', 'visual-regression-tests' ),
'sanitize_callback' => 'sanitize_text_field',
'show_in_rest' => true,
'value_type' => 'string',
'default' => '',
]);
vrts()->settings()->add_setting([
'type' => 'text',
'id' => 'vrts_license_key',
'section' => 'vrts-settings-section-general',
'title' => esc_html__( 'License Key', 'visual-regression-tests' ),
'description' => sprintf(
'%1$s <a href="%2$s" title="%3$s">%3$s</a>',
esc_html__( 'No license key yet?', 'visual-regression-tests' ),
esc_url( Url_Helpers::get_page_url( 'upgrade' ) ),
esc_html__( 'Upgrade here.', 'visual-regression-tests' )
),
'placeholder' => esc_html_x( 'XXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXXXXX', 'license key placeholder', 'visual-regression-tests' ),
'sanitize_callback' => 'sanitize_text_field',
'show_in_rest' => true,
'value_type' => 'string',
'value' => ! empty( vrts()->settings()->get_option( 'vrts_license_key', false ) ) ? 'XXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXXXXX' : '',
'default' => '',
]);
vrts()->settings()->add_section([
'id' => 'vrts-settings-section-triggers',
'page' => $this->page_slug,
'title' => esc_html__( 'Triggers', 'visual-regression-tests' ) . '<span>' . esc_html__( 'When your Tests are run.', 'visual-regression-tests' ) . '</span>',
]);
vrts()->settings()->add_setting([
'type' => 'checkbox',
'id' => 'vrts_automatic_comparison',
'section' => 'vrts-settings-section-triggers',
'title' => esc_html__( 'Schedule', 'visual-regression-tests' ),
'label' => esc_html__( 'Run Tests every 24 hours.', 'visual-regression-tests' ),
'sanitize_callback' => [ Sanitization::class, 'sanitize_checkbox' ],
'show_in_rest' => true,
'value_type' => 'boolean',
'value' => 1,
'default' => 1,
'disabled' => 1,
]);
vrts()->settings()->add_setting([
'type' => 'checkbox',
'id' => 'vrts_updates_comparison',
'section' => 'vrts-settings-section-triggers',
'title' => esc_html__( 'Update', 'visual-regression-tests' ),
'label' => esc_html__( 'Run Tests after WordPress and plugin updates.', 'visual-regression-tests' ),
'sanitize_callback' => [ Sanitization::class, 'sanitize_checkbox' ],
'show_in_rest' => true,
'value_type' => 'boolean',
'value' => $has_subscription,
'default' => $has_subscription,
'disabled' => $has_subscription,
'readonly' => ! $has_subscription,
'is_pro' => $has_subscription,
]);
vrts()->settings()->add_setting([
'type' => 'checkbox',
'id' => 'vrts_api_comparison',
'section' => 'vrts-settings-section-triggers',
'title' => esc_html__( 'API', 'visual-regression-tests' ),
'label' => sprintf(
/* translators: %1$s, %2$s: link wrapper. */
wp_kses_post( __( 'Run Tests with your favorite apps. %1$sRead the docs%2$s.', 'visual-regression-tests' ) ),
'<a href="' . esc_url( 'https://vrts.app/docs/' ) . '" target="_blank">',
'</a>'
),
'sanitize_callback' => [ Sanitization::class, 'sanitize_checkbox' ],
'show_in_rest' => true,
'value_type' => 'boolean',
'value' => $has_subscription,
'default' => $has_subscription,
'disabled' => $has_subscription,
'readonly' => ! $has_subscription,
'is_pro' => $has_subscription,
]);
vrts()->settings()->add_setting([
'type' => 'checkbox',
'id' => 'vrts_manual_comparison',
'section' => 'vrts-settings-section-triggers',
'title' => esc_html__( 'Manual', 'visual-regression-tests' ),
'label' => esc_html__( 'Run Tests on demand.', 'visual-regression-tests' ),
'sanitize_callback' => [ Sanitization::class, 'sanitize_checkbox' ],
'show_in_rest' => true,
'value_type' => 'boolean',
'value' => $has_subscription,
'default' => $has_subscription,
'disabled' => $has_subscription,
'readonly' => ! $has_subscription,
'is_pro' => $has_subscription,
]);
vrts()->settings()->add_section([
'id' => 'vrts-settings-section-notifications',
'page' => $this->page_slug,
'title' => esc_html__( 'Notifications', 'visual-regression-tests' ) . '<span>' . esc_html__( 'Notify team members based on specific Trigger events.', 'visual-regression-tests' ) . '</span>',
]);
vrts()->settings()->add_setting([
'type' => 'text',
'id' => 'vrts_email_notification_address',
'section' => 'vrts-settings-section-notifications',
'title' => esc_html__( 'Schedule', 'visual-regression-tests' ),
'description' => esc_html__( 'Separate multiple email addresses with commas. Or leave blank to disable notifications.', 'visual-regression-tests' ),
'placeholder' => esc_html__( 'Email address(es)', 'visual-regression-tests' ),
'sanitize_callback' => [ Sanitization::class, 'sanitize_multiple_emails' ],
'show_in_rest' => true,
'value_type' => 'string',
'default' => get_bloginfo( 'admin_email' ),
'return_value_callback' => [ $this, 'get_sanitized_emails' ],
]);
vrts()->settings()->add_setting([
'type' => 'text',
'id' => 'vrts_email_update_notification_address',
'section' => 'vrts-settings-section-notifications',
'title' => esc_html__( 'Update', 'visual-regression-tests' ),
'placeholder' => esc_html__( 'Email address(es)', 'visual-regression-tests' ),
'sanitize_callback' => [ Sanitization::class, 'sanitize_multiple_emails' ],
'show_in_rest' => true,
'value_type' => 'string',
'default' => '',
'readonly' => ! $has_subscription,
'is_pro' => $has_subscription,
'return_value_callback' => [ $this, 'get_sanitized_emails' ],
]);
vrts()->settings()->add_setting([
'type' => 'text',
'id' => 'vrts_email_api_notification_address',
'section' => 'vrts-settings-section-notifications',
'title' => esc_html__( 'API', 'visual-regression-tests' ),
'placeholder' => esc_html__( 'Email address(es)', 'visual-regression-tests' ),
'sanitize_callback' => [ Sanitization::class, 'sanitize_multiple_emails' ],
'show_in_rest' => true,
'value_type' => 'string',
'default' => '',
'readonly' => ! $has_subscription,
'is_pro' => $has_subscription,
'return_value_callback' => [ $this, 'get_sanitized_emails' ],
]);
vrts()->settings()->add_setting([
'type' => 'info',
'id' => 'vrts_email_manual_notification_address',
'section' => 'vrts-settings-section-notifications',
'title' => esc_html__( 'Manual', 'visual-regression-tests' ),
'description' => esc_html__( 'Alerts are automatically sent to the user who triggers the Manual Test.', 'visual-regression-tests' ),
'is_pro' => $has_subscription,
]);
}
/**
* Settings migration.
*/
public function settings_migration() {
$has_subscription = (bool) Subscription::get_subscription_status();
$old_cc_email = get_option( 'vrts_email_notification_cc_address' );
$update_email = get_option( 'vrts_email_update_notification_address' );
$api_email = get_option( 'vrts_email_api_notification_address' );
if ( $old_cc_email ) {
$old_cc_email = $this->get_sanitized_emails( $old_cc_email );
$schedule_email = vrts()->settings()->get_option( 'vrts_email_notification_address' );
$schedule_email = array_unique( array_merge( $schedule_email, $old_cc_email ) );
$schedule_email = implode( ', ', $schedule_email );
update_option( 'vrts_email_notification_address', $schedule_email );
delete_option( 'vrts_email_notification_cc_address' );
}
if ( $has_subscription ) {
$schedule_email = vrts()->settings()->get_option( 'vrts_email_notification_address', false );
if ( false === $update_email ) {
update_option( 'vrts_email_update_notification_address', $schedule_email );
}
if ( false === $api_email ) {
update_option( 'vrts_email_api_notification_address', $schedule_email );
}
if ( get_option( 'vrts_license_success' ) ) {
update_option( 'vrts_email_update_notification_address', $schedule_email );
update_option( 'vrts_email_api_notification_address', $schedule_email );
}
}
}
/**
* Update global click selector settings for project in service
*
* @param string $old Old value.
* @param string $new_value New value.
*/
public function do_after_update_click_selectors( $old, $new_value ) {
if ( $old !== $new_value ) {
$service_project_id = get_option( 'vrts_project_id' );
$service_api_route = 'sites/' . $service_project_id;
$parameters = [
'screenshot_options' => [
'clickSelectors' => $new_value,
],
];
$response = Service::rest_service_request( $service_api_route, $parameters, 'put' );
$service = new Test_Service();
$service->resume_tests();
}
}
/**
* Register the Gumroad API key with the service.
*
* @param mixed $new_value new value.
* @param mixed $old old value.
*/
public function do_before_add_license_key( $new_value, $old ) {
// If license key is empty but was previously added.
if ( ! $new_value && $old ) {
self::remove_license_key();
update_option( 'vrts_license_failed', true );
return '';
}
if ( 'XXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXXXXX' === $new_value ) {
return $old;
}
if ( $old !== $new_value ) {
$service_project_id = get_option( 'vrts_project_id' );
$service_api_route = 'sites/' . $service_project_id . '/register';
$parameters = [
'license_key' => $new_value,
];
$response = Service::rest_service_request( $service_api_route, $parameters, 'post' );
$status_code = $response['status_code'];
Subscription::get_latest_status();
if ( 200 !== $status_code ) {
// If new key is not valid, remove the old one.
self::remove_license_key();
update_option( 'vrts_license_failed', true );
return '';
}
update_option( 'vrts_license_success', true );
return $new_value;
}//end if
return $old;
}
/**
* Prevent updating email address if there is no subscription
*
* @param string $value New value.
*/
public function do_before_updating_email_address( $value ) {
$has_subscription = (bool) Subscription::get_subscription_status();
return $has_subscription ? $value : '';
}
/**
* Update automatic comparison settings for project in service
*
* @param string $old Old value.
* @param string $new_value New value.
*/
public function do_after_update_vrts_automatic_comparison( $old, $new_value ) {
if ( $old !== $new_value ) {
$service_project_id = get_option( 'vrts_project_id' );
$service_api_route = 'sites/' . $service_project_id;
$parameters = [
'automatic_comparison' => empty( $new_value ) ? false : true,
];
$response = Service::rest_service_request( $service_api_route, $parameters, 'put' );
}
}
/**
* Remove license key from the service
*/
public static function remove_license_key() {
$service_project_id = get_option( 'vrts_project_id' );
$service_api_route = 'sites/' . $service_project_id . '/unregister';
$response = Service::rest_service_request( $service_api_route, [], 'post' );
Subscription::get_latest_status();
}
/**
* Init notifications.
*/
public function init_notifications() {
if ( true === (bool) get_option( 'vrts_license_success' ) ) {
add_action( 'admin_notices', [ $this, 'render_notification_license_added' ] );
delete_option( 'vrts_license_success' );
} elseif ( true === (bool) get_option( 'vrts_license_failed' ) ) {
add_action( 'admin_notices', [ $this, 'render_notification_license_not_added' ] );
delete_option( 'vrts_license_failed' );
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- It's OK.
} elseif ( isset( $_GET['settings-updated'] ) && true === (bool) $_GET['settings-updated'] ) {
add_action( 'admin_notices', [ $this, 'render_notification_settings_saved' ] );
}
}
/**
* Render Settings saved notification.
*/
public function render_notification_settings_saved() {
Admin_Notices::render_notification( 'settings_saved', false );
}
/**
* Render License added notification.
*/
public function render_notification_license_added() {
Admin_Notices::render_notification( 'license_added', false );
}
/**
* Render License adding failed notification.
*/
public function render_notification_license_not_added() {
Admin_Notices::render_notification( 'license_not_added', false );
}
/**
* Render License adding removed notification.
*/
public function render_notification_license_removed() {
Admin_Notices::render_notification( 'license_removed', false );
}
/**
* Sanitize multiple emails.
*
* @param string $emails The emails.
*
* @return array
*/
public function get_sanitized_emails( $emails ) {
return array_filter( array_map( 'sanitize_email', explode( ',', $emails ) ) );
}
}