HEX
Server: nginx
System: Linux pool195-106-36.bur.atomicsites.net 6.12.57+deb12-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.12.57-1~bpo12+1 (2025-11-17) x86_64
User: (0)
PHP: 8.3.32
Disabled: pcntl_fork
Upload Files
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,
		);
	}
}