File: /wordpress/plugins/wp-cloud-client/1.1.2/src/Settings/SettingsPage.php
<?php
declare(strict_types=1);
namespace VPlugins\WPCloudClient\Settings;
use VPlugins\WPCloudClient\Analytics\GoogleAnalytics4;
use VPlugins\WPCloudClient\BusinessProfile\ProfileHelperPage;
use VPlugins\WPCloudClient\Mail\MailSettings;
class SettingsPage {
private const SLUG = 'wpcc-settings';
private const OPTION_GROUP = 'wpcc_settings_group';
private const OPTION_KEY = 'wpcc_settings';
private const SECTION_ANALYTICS = 'wpcc_section_analytics';
private const SECTION_MAIL = 'wpcc_section_mail';
private const TAB_ANALYTICS = 'analytics';
private const TAB_MAIL = 'email-history';
private const TAB_PROFILE = 'business-profile';
/**
* Class constructor.
*
* @param SettingsRepository $settings Settings repository instance.
* @param GoogleAnalytics4 $ga4 Google Analytics 4 instance.
* @param MailSettings $mailSettings Mail settings instance.
* @param ProfileHelperPage $profileHelper Business profile helper page.
*/
public function __construct(
private readonly SettingsRepository $settings,
private readonly GoogleAnalytics4 $ga4,
private readonly MailSettings $mailSettings,
private readonly ?ProfileHelperPage $profileHelper,
) {}
/**
* Register the settings menu page under the Settings menu.
*
* @return void
*/
public function addMenuPage(): void {
add_options_page(
__( 'WP Cloud Client', 'wp-cloud-client' ),
__( 'WP Cloud Client', 'wp-cloud-client' ),
'manage_options',
self::SLUG,
[ $this, 'render' ],
);
}
/**
* Register settings sections and fields.
*
* @return void
*/
public function registerSettings(): void {
register_setting(
self::OPTION_GROUP,
self::OPTION_KEY,
[
'sanitize_callback' => [ $this, 'sanitize' ],
'default' => [],
]
);
// Analytics section — omitted on staging sites; GA4 is fully disabled there.
if ( ! $this->settings->isStaging() ) {
add_settings_section(
self::SECTION_ANALYTICS,
__( 'Google Analytics 4', 'wp-cloud-client' ),
static fn () => printf(
'<p>%s</p>',
esc_html__( 'Optionally connect a custom Google Analytics 4 property to track this site.', 'wp-cloud-client' ),
),
self::SLUG,
);
$this->addGa4TrackingIdField();
}
// Mail / Email History section
$this->mailSettings->register();
}
/**
* Get the tab definitions.
*
* @return array<string, array{label: string, sections: string[], form: bool}>
*/
private function getTabs(): array {
$tabs = [
self::TAB_ANALYTICS => [
'label' => __( 'Google Analytics 4', 'wp-cloud-client' ),
'sections' => [ self::SECTION_ANALYTICS ],
'form' => true,
],
self::TAB_MAIL => [
'label' => __( 'Email History', 'wp-cloud-client' ),
'sections' => [ self::SECTION_MAIL ],
'form' => true,
],
self::TAB_PROFILE => [
'label' => __( 'Business Profile', 'wp-cloud-client' ),
'sections' => [],
'form' => false,
],
];
if ( $this->settings->isStaging() ) {
unset( $tabs[ self::TAB_ANALYTICS ] );
}
return $tabs;
}
/**
* Get the currently active tab slug.
*
* @return string
*/
private function activeTab(): string {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Tab selection is not a state-changing action.
$tab = isset( $_GET['tab'] ) ? sanitize_key( (string) $_GET['tab'] ) : '';
$tabs = $this->getTabs();
return isset( $tabs[ $tab ] ) ? $tab : (string) ( array_key_first( $tabs ) ?? '' );
}
/**
* Render the settings page HTML.
*
* @return void
*/
public function render(): void {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
$configured = $this->settings->isConfigured();
$activeTab = $this->activeTab();
$tabs = $this->getTabs();
?>
<div class="wrap">
<h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
<?php settings_errors( self::OPTION_KEY ); ?>
<div class="wpcc-status-indicator" style="margin: 15px 0; padding: 10px 15px; border-left: 4px solid <?php echo $configured ? '#00a32a' : '#d63638'; ?>; background: #fff;">
<strong><?php esc_html_e( 'Connection Status:', 'wp-cloud-client' ); ?></strong>
<?php if ( $configured ) : ?>
<span style="color: #00a32a;"><?php esc_html_e( 'Configured', 'wp-cloud-client' ); ?></span>
<?php else : ?>
<span style="color: #d63638;"><?php esc_html_e( 'Not Configured', 'wp-cloud-client' ); ?></span>
<?php endif; ?>
<p class="description"><?php esc_html_e( 'Authentication credentials are provisioned automatically by the server.', 'wp-cloud-client' ); ?></p>
</div>
<nav class="nav-tab-wrapper">
<?php foreach ( $tabs as $slug => $tab ) : ?>
<a href="<?php echo esc_url( add_query_arg( 'tab', $slug, menu_page_url( self::SLUG, false ) ) ); ?>"
class="nav-tab <?php echo $activeTab === $slug ? 'nav-tab-active' : ''; ?>">
<?php echo esc_html( $tab['label'] ); ?>
</a>
<?php endforeach; ?>
</nav>
<div class="wpcc-tab-content" style="margin-top: 20px;">
<?php $this->renderTabContent( $activeTab, $tabs[ $activeTab ] ); ?>
</div>
</div>
<?php
}
/**
* Render the content for a specific tab.
*
* @param string $tabSlug The active tab slug.
* @param array{label: string, sections: string[], form: bool} $tab The tab definition.
* @return void
*/
private function renderTabContent( string $tabSlug, array $tab ): void {
if ( self::TAB_PROFILE === $tabSlug ) {
if ( null !== $this->profileHelper ) {
$this->profileHelper->render();
} else {
printf( '<p>%s</p>', esc_html__( 'Business Profile module is not available.', 'wp-cloud-client' ) );
}
return;
}
?>
<form action="options.php" method="post">
<?php
settings_fields( self::OPTION_GROUP );
// Render only the sections belonging to this tab.
global $wp_settings_sections, $wp_settings_fields;
if ( ! is_array( $wp_settings_sections ) ) {
return;
}
foreach ( $tab['sections'] as $sectionId ) {
if ( ! isset( $wp_settings_sections[ self::SLUG ][ $sectionId ] ) ) {
continue;
}
$section = $wp_settings_sections[ self::SLUG ][ $sectionId ];
if ( '' !== $section['title'] ) {
echo '<h2>' . esc_html( $section['title'] ) . '</h2>';
}
if ( $section['callback'] ) {
call_user_func( $section['callback'], $section );
}
if ( isset( $wp_settings_fields[ self::SLUG ][ $sectionId ] ) ) {
echo '<table class="form-table" role="presentation">';
do_settings_fields( self::SLUG, $sectionId );
echo '</table>';
}
}
submit_button( __( 'Save Settings', 'wp-cloud-client' ) );
?>
</form>
<?php
}
/**
* Sanitize and validate form input before saving.
*
* @param mixed $input Raw form input from $_POST.
* @return array Sanitized settings array.
*/
public function sanitize( mixed $input ): array {
$current = $this->settings->all();
if ( ! is_array( $input ) ) {
add_settings_error(
self::OPTION_KEY,
'wpcc_invalid_input',
__( 'Invalid input received.', 'wp-cloud-client' ),
'error',
);
return $current;
}
$sanitized = [];
$sanitized['debug_mode'] = sanitize_text_field( (string) ( $current['debug_mode'] ?? '' ) );
$sanitized['ga4_tracking_id'] = array_key_exists( 'ga4_tracking_id', $input )
? $this->ga4->sanitizeTrackingId( (string) $input['ga4_tracking_id'] )
: (string) ( $current['ga4_tracking_id'] ?? '' );
$sanitized['disable_mail_interceptor'] = array_key_exists( 'disable_mail_interceptor', $input )
? $this->mailSettings->sanitizeField( $input )
: (string) ( $current['disable_mail_interceptor'] ?? '' );
return $sanitized;
}
/**
* Add the GA4 tracking ID text field.
*
* @return void
*/
private function addGa4TrackingIdField(): void {
add_settings_field(
'ga4_tracking_id',
'<label for="ga4_tracking_id">' . esc_html__( 'Custom Google Analytics 4 Tracking ID', 'wp-cloud-client' ) . '</label>',
function (): void {
$value = $this->settings->getGa4TrackingId() ?? '';
printf(
'<input type="text" id="ga4_tracking_id" name="%s[ga4_tracking_id]" value="%s" class="regular-text" placeholder="G-XXXXXXXXXX" />',
esc_attr( self::OPTION_KEY ),
esc_attr( $value ),
);
printf(
'<p class="description">%s</p>',
esc_html__( 'Enter your own Google Analytics 4 Tracking ID (format: G-XXXXXXXXXX). Tracking will run concurrently with the built-in tracking.', 'wp-cloud-client' ),
);
},
self::SLUG,
self::SECTION_ANALYTICS,
);
}
}