← Back
Editing: settings.php
<?php declare(strict_types=1); /** * Admin Settings for Simple Password Protect Plugin * * @package SimplePasswordProtect */ // Prevent direct access if (!defined('ABSPATH')) { exit; } /** * Admin Settings Class */ class Spwdprot_Admin { /** * Admin instance * * @var Spwdprot_Admin|null */ private static ?Spwdprot_Admin $instance = null; /** * Settings page slug */ private const SETTINGS_PAGE = 'simple-password-protect'; /** * Settings group */ private const SETTINGS_GROUP = 'spwdprot_settings_group'; /** * Get admin instance (Singleton pattern) * * @return Spwdprot_Admin */ public static function getInstance(): Spwdprot_Admin { if (self::$instance === null) { self::$instance = new self(); } return self::$instance; } /** * Constructor */ private function __construct() { add_action('admin_menu', [$this, 'addSettingsPage']); add_action('admin_init', [$this, 'initSettings']); add_action('admin_notices', [$this, 'showAdminNotices']); add_filter('plugin_action_links_' . SPWDPROT_PLUGIN_BASENAME, [$this, 'addPluginActionLinks']); // Handle password saving before WordPress processes the options add_action('admin_init', [$this, 'handlePasswordSave'], 5); } /** * Add settings page to admin menu */ public function addSettingsPage(): void { add_options_page( __('Simple Password Protect Settings', 'simple-password-protect'), __('Password Protect', 'simple-password-protect'), 'manage_options', self::SETTINGS_PAGE, [$this, 'renderSettingsPage'] ); } /** * Handle password save before WordPress Settings API */ public function handlePasswordSave(): void { // Check if this is our settings page submission if (!isset($_POST['option_page']) || $_POST['option_page'] !== self::SETTINGS_GROUP) { return; } // Verify nonce if (!isset($_POST['_wpnonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['_wpnonce'])), self::SETTINGS_GROUP . '-options')) { return; } // Check if user has permission if (!current_user_can('manage_options')) { return; } // Check if password field was submitted if (!isset($_POST['spwdprot_password']) || empty($_POST['spwdprot_password'])) { return; } // Get the raw password - intentionally not sanitized to preserve password characters // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash $password = $_POST['spwdprot_password']; // Hash the password $hashedPassword = password_hash($password, PASSWORD_DEFAULT); if ($hashedPassword === false) { add_settings_error( 'spwdprot_password', 'password_hash_failed', __('Failed to hash password. Please try again.', 'simple-password-protect'), 'error' ); return; } // Save to database $updated = update_option('spwdprot_password_hash', $hashedPassword, true); // Debug logging if (WP_DEBUG && WP_DEBUG_LOG) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log error_log('SPP: Password save attempt - Length: ' . strlen($password) . ', Hash length: ' . strlen($hashedPassword) . ', Update result: ' . ($updated ? 'SUCCESS' : 'FAILED')); // Verify it was saved $savedHash = get_option('spwdprot_password_hash', ''); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log error_log('SPP: Verification after save - Hash exists: ' . (!empty($savedHash) ? 'YES' : 'NO') . ', Matches: ' . ($savedHash === $hashedPassword ? 'YES' : 'NO')); // Test if password verifies $testVerify = password_verify($password, $savedHash); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log error_log('SPP: Immediate password verification: ' . ($testVerify ? 'SUCCESS' : 'FAILED')); } // Add success notice add_settings_error( 'spwdprot_password', 'password_updated', /* translators: %d is the number of characters in the password */ sprintf(__('Password updated successfully! (Length: %d characters)', 'simple-password-protect'), strlen($password)), 'success' ); // Set transient to show success message set_transient('spwdprot_password_updated', true, 30); } /** * Initialize settings using WordPress Settings API */ public function initSettings(): void { // Register settings register_setting( self::SETTINGS_GROUP, 'spwdprot_plugin_enabled', [ 'type' => 'boolean', 'default' => true, 'sanitize_callback' => 'rest_sanitize_boolean' ] ); register_setting( self::SETTINGS_GROUP, 'spwdprot_password_hash', [ 'type' => 'string', 'default' => '', 'sanitize_callback' => [$this, 'sanitizePassword'] ] ); register_setting( self::SETTINGS_GROUP, 'spwdprot_impressum_page', [ 'type' => 'integer', 'default' => 0, 'sanitize_callback' => 'absint' ] ); register_setting( self::SETTINGS_GROUP, 'spwdprot_privacy_page', [ 'type' => 'integer', 'default' => 0, 'sanitize_callback' => 'absint' ] ); register_setting( self::SETTINGS_GROUP, 'spwdprot_logo_url', [ 'type' => 'string', 'default' => '', 'sanitize_callback' => 'esc_url_raw' ] ); register_setting( self::SETTINGS_GROUP, 'spwdprot_logo_shape', [ 'type' => 'string', 'default' => 'square', 'sanitize_callback' => [$this, 'sanitizeLogoShape'] ] ); register_setting( self::SETTINGS_GROUP, 'spwdprot_page_title', [ 'type' => 'string', 'default' => __('Password Protected', 'simple-password-protect'), 'sanitize_callback' => 'sanitize_text_field' ] ); register_setting( self::SETTINGS_GROUP, 'spwdprot_login_text', [ 'type' => 'string', 'default' => __('Please enter the password to access this site.', 'simple-password-protect'), 'sanitize_callback' => 'sanitize_textarea_field' ] ); // Styling settings register_setting( self::SETTINGS_GROUP, 'spwdprot_background_color', [ 'type' => 'string', 'default' => '#ffffff', 'sanitize_callback' => 'sanitize_hex_color' ] ); register_setting( self::SETTINGS_GROUP, 'spwdprot_button_color', [ 'type' => 'string', 'default' => '#17525b', 'sanitize_callback' => 'sanitize_hex_color' ] ); register_setting( self::SETTINGS_GROUP, 'spwdprot_button_text_color', [ 'type' => 'string', 'default' => '#ffffff', 'sanitize_callback' => 'sanitize_hex_color' ] ); register_setting( self::SETTINGS_GROUP, 'spwdprot_link_color', [ 'type' => 'string', 'default' => '#17525b', 'sanitize_callback' => 'sanitize_hex_color' ] ); // Admin login button setting register_setting( self::SETTINGS_GROUP, 'spwdprot_show_admin_login', [ 'type' => 'boolean', 'default' => false, 'sanitize_callback' => 'rest_sanitize_boolean' ] ); // Show legal links setting register_setting( self::SETTINGS_GROUP, 'spwdprot_show_legal_links', [ 'type' => 'boolean', 'default' => true, 'sanitize_callback' => 'rest_sanitize_boolean' ] ); // Add settings sections add_settings_section( 'spwdprot_general_section', __('General Settings', 'simple-password-protect'), [$this, 'renderGeneralSectionCallback'], self::SETTINGS_PAGE ); add_settings_section( 'spwdprot_content_section', __('Content & Appearance', 'simple-password-protect'), [$this, 'renderContentSectionCallback'], self::SETTINGS_PAGE ); add_settings_section( 'spwdprot_legal_section', __('Legal Pages (GDPR)', 'simple-password-protect'), [$this, 'renderLegalSectionCallback'], self::SETTINGS_PAGE ); add_settings_section( 'spwdprot_admin_section', __('Admin Access', 'simple-password-protect'), [$this, 'renderAdminSectionCallback'], self::SETTINGS_PAGE ); add_settings_section( 'spwdprot_styling_section', __('Styling & Colors', 'simple-password-protect'), [$this, 'renderStylingSectionCallback'], self::SETTINGS_PAGE ); // Add settings fields $this->addSettingsFields(); } /** * Add all settings fields */ private function addSettingsFields(): void { // General settings fields add_settings_field( 'spwdprot_plugin_enabled', __('Enable Password Protection', 'simple-password-protect'), [$this, 'renderEnabledField'], self::SETTINGS_PAGE, 'spwdprot_general_section' ); add_settings_field( 'spwdprot_password_hash', __('Site Password', 'simple-password-protect'), [$this, 'renderPasswordField'], self::SETTINGS_PAGE, 'spwdprot_general_section' ); // Content & Appearance fields add_settings_field( 'spwdprot_page_title', __('Page Title', 'simple-password-protect'), [$this, 'renderPageTitleField'], self::SETTINGS_PAGE, 'spwdprot_content_section' ); add_settings_field( 'spwdprot_login_text', __('Login Page Text', 'simple-password-protect'), [$this, 'renderLoginTextField'], self::SETTINGS_PAGE, 'spwdprot_content_section' ); add_settings_field( 'spwdprot_logo_url', __('Logo URL', 'simple-password-protect'), [$this, 'renderLogoField'], self::SETTINGS_PAGE, 'spwdprot_content_section' ); add_settings_field( 'spwdprot_logo_shape', __('Logo Shape', 'simple-password-protect'), [$this, 'renderLogoShapeField'], self::SETTINGS_PAGE, 'spwdprot_content_section' ); // Legal pages fields add_settings_field( 'spwdprot_show_legal_links', __('Show Legal Links', 'simple-password-protect'), [$this, 'renderShowLegalLinksField'], self::SETTINGS_PAGE, 'spwdprot_legal_section' ); add_settings_field( 'spwdprot_impressum_page', __('Legal Disclosure Page', 'simple-password-protect'), [$this, 'renderImpressumPageField'], self::SETTINGS_PAGE, 'spwdprot_legal_section' ); add_settings_field( 'spwdprot_privacy_page', __('Privacy Policy Page', 'simple-password-protect'), [$this, 'renderPrivacyPageField'], self::SETTINGS_PAGE, 'spwdprot_legal_section' ); // Admin access field add_settings_field( 'spwdprot_show_admin_login', __('Show Admin Login Button', 'simple-password-protect'), [$this, 'renderShowAdminLoginField'], self::SETTINGS_PAGE, 'spwdprot_admin_section' ); // Styling fields add_settings_field( 'spwdprot_background_color', __('Background Color', 'simple-password-protect'), [$this, 'renderBackgroundColorField'], self::SETTINGS_PAGE, 'spwdprot_styling_section' ); add_settings_field( 'spwdprot_button_color', __('Button Color', 'simple-password-protect'), [$this, 'renderButtonColorField'], self::SETTINGS_PAGE, 'spwdprot_styling_section' ); add_settings_field( 'spwdprot_button_text_color', __('Button Text Color', 'simple-password-protect'), [$this, 'renderButtonTextColorField'], self::SETTINGS_PAGE, 'spwdprot_styling_section' ); add_settings_field( 'spwdprot_link_color', __('Link Color', 'simple-password-protect'), [$this, 'renderLinkColorField'], self::SETTINGS_PAGE, 'spwdprot_styling_section' ); } /** * Render settings page */ public function renderSettingsPage(): void { if (!current_user_can('manage_options')) { wp_die(esc_html__('You do not have sufficient permissions to access this page.', 'simple-password-protect')); } ?> <div class="wrap"> <h1><?php echo esc_html(get_admin_page_title()); ?></h1> <form method="post" action="options.php"> <?php settings_fields(self::SETTINGS_GROUP); do_settings_sections(self::SETTINGS_PAGE); submit_button(); ?> </form> </div> <?php } /** * Render status information */ private function renderStatusInfo(): void { $isEnabled = get_option('spwdprot_plugin_enabled', true); $passwordHash = get_option('spwdprot_password_hash', ''); $hasPassword = !empty($passwordHash); ?> <div class="spp-status-info"> <h3><?php esc_html_e('Current Status', 'simple-password-protect'); ?></h3> <p> <strong><?php esc_html_e('Plugin Status:', 'simple-password-protect'); ?></strong> <?php if ($isEnabled): ?> <span style="color: green;"><?php esc_html_e('Enabled', 'simple-password-protect'); ?></span> <?php else: ?> <span style="color: orange;"><?php esc_html_e('Disabled', 'simple-password-protect'); ?></span> <?php endif; ?> </p> <?php if ($hasPassword): ?> <p style="color: green;"> <strong><?php esc_html_e('✓ Password is set', 'simple-password-protect'); ?></strong> </p> <p style="font-size: 11px; color: #666;"> <strong>Hash Info (for debugging):</strong><br> Algorithm: <?php echo esc_html(substr($passwordHash, 0, 4) === '$2y$' ? 'bcrypt' : 'unknown'); ?><br> Hash Length: <?php echo esc_html(strlen($passwordHash)); ?> characters<br> Hash Preview: <code><?php echo esc_html(substr($passwordHash, 0, 20)) . '...'; ?></code> </p> <?php endif; ?> <?php if ($isEnabled && $hasPassword): ?> <p> <a href="<?php echo esc_url(home_url()); ?>" target="_blank" class="button button-secondary"> <?php esc_html_e('Open Site in New Tab', 'simple-password-protect'); ?> </a> </p> <?php endif; ?> <!-- Password Test Tool --> <div style="margin-top: 20px; padding: 15px; background: #fff3cd; border-left: 4px solid #ffc107;"> <h4 style="margin-top: 0;"><?php esc_html_e('Password Test Tool', 'simple-password-protect'); ?></h4> <p><?php esc_html_e('Test if your password works correctly:', 'simple-password-protect'); ?></p> <form method="post" action="" style="display: inline-block;"> <?php wp_nonce_field('spwdprot_test_password', 'spwdprot_test_nonce'); ?> <input type="password" name="test_password" placeholder="Enter password to test" style="width: 250px;" /> <input type="hidden" name="spwdprot_test_password_action" value="1" /> <button type="submit" class="button"><?php esc_html_e('Test Password', 'simple-password-protect'); ?></button> </form> <?php // Handle password test if (isset($_POST['spwdprot_test_password_action']) && isset($_POST['test_password'])) { $test_nonce = isset($_POST['spwdprot_test_nonce']) ? sanitize_text_field(wp_unslash($_POST['spwdprot_test_nonce'])) : ''; if (wp_verify_nonce($test_nonce, 'spwdprot_test_password')) { // Get password without sanitization to preserve exact characters // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash $testPassword = $_POST['test_password']; $storedHash = get_option('spwdprot_password_hash', ''); if (empty($storedHash)) { echo '<p style="color: red; margin-top: 10px;"><strong>❌ No password hash is stored in the database.</strong></p>'; } else { $result = password_verify($testPassword, $storedHash); if ($result) { echo '<p style="color: green; margin-top: 10px;"><strong>✅ SUCCESS! This password is CORRECT.</strong></p>'; } else { echo '<p style="color: red; margin-top: 10px;"><strong>❌ FAILED! This password is INCORRECT.</strong></p>'; echo '<p style="font-size: 11px; color: #666;">Password length tested: ' . esc_html((string) strlen($testPassword)) . ' characters</p>'; } } } } ?> </div> </div> <?php } /** * Render general section callback */ public function renderGeneralSectionCallback(): void { echo '<p>' . esc_html__('Configure the basic password protection settings.', 'simple-password-protect') . '</p>'; } /** * Render content section callback */ public function renderContentSectionCallback(): void { echo '<p>' . esc_html__('Customize the appearance of the password protection page.', 'simple-password-protect') . '</p>'; } /** * Render legal section callback */ public function renderLegalSectionCallback(): void { echo '<p>' . esc_html__('Select pages to display as modal links on the password protection page (GDPR compliance). Legal Disclosure replaces Impressum for international compatibility.', 'simple-password-protect') . '</p>'; } /** * Render admin section callback */ public function renderAdminSectionCallback(): void { echo '<p>' . esc_html__('Configure admin access options for the password protection page.', 'simple-password-protect') . '</p>'; } /** * Render styling section callback */ public function renderStylingSectionCallback(): void { echo '<p>' . esc_html__('Customize the colors and appearance of the password protection page.', 'simple-password-protect') . '</p>'; } /** * Render enabled field */ public function renderEnabledField(): void { $enabled = get_option('spwdprot_plugin_enabled', true); ?> <input type="checkbox" id="spwdprot_plugin_enabled" name="spwdprot_plugin_enabled" value="1" <?php checked($enabled); ?> /> <label for="spwdprot_plugin_enabled"> <?php esc_html_e('Enable password protection for the entire site', 'simple-password-protect'); ?> </label> <p class="description"> <?php esc_html_e('When enabled, visitors must enter a password to access any page on your site.', 'simple-password-protect'); ?> </p> <?php } /** * Render password field */ public function renderPasswordField(): void { $hasPassword = !empty(get_option('spwdprot_password_hash', '')); $passwordUpdated = get_transient('spwdprot_password_updated'); if ($passwordUpdated) { delete_transient('spwdprot_password_updated'); } ?> <input type="password" id="spwdprot_password" name="spwdprot_password" class="regular-text" placeholder="<?php esc_html_e('Enter new password', 'simple-password-protect'); ?>" autocomplete="new-password" /> <?php if ($passwordUpdated): ?> <p class="description" style="color: green; font-weight: bold;"> <?php esc_html_e('✓ Password was just updated successfully!', 'simple-password-protect'); ?> </p> <?php elseif ($hasPassword): ?> <p class="description" style="color: green;"> <?php esc_html_e('✓ Password is currently set. Enter a new password to change it, or leave empty to keep current password.', 'simple-password-protect'); ?> </p> <?php else: ?> <p class="description" style="color: #666;"> <?php esc_html_e('Enter a password to protect your site.', 'simple-password-protect'); ?> </p> <?php endif; ?> <?php } /** * Render page title field */ public function renderPageTitleField(): void { $title = get_option('spwdprot_page_title', __('Password Protected', 'simple-password-protect')); ?> <input type="text" id="spwdprot_page_title" name="spwdprot_page_title" value="<?php echo esc_attr($title); ?>" class="regular-text" /> <p class="description"> <?php esc_html_e('The main title displayed on the password protection page.', 'simple-password-protect'); ?> </p> <?php } /** * Render login text field */ public function renderLoginTextField(): void { $text = get_option('spwdprot_login_text', __('Please enter the password to access this site.', 'simple-password-protect')); ?> <textarea id="spwdprot_login_text" name="spwdprot_login_text" rows="3" cols="50" class="large-text"><?php echo esc_textarea($text); ?></textarea> <p class="description"> <?php esc_html_e('This text will be displayed on the password protection page.', 'simple-password-protect'); ?> </p> <?php } /** * Render logo field */ public function renderLogoField(): void { $logoUrl = get_option('spwdprot_logo_url', ''); ?> <input type="url" id="spwdprot_logo_url" name="spwdprot_logo_url" value="<?php echo esc_attr($logoUrl); ?>" class="regular-text" /> <button type="button" class="button" id="spwdprot_upload_logo_button"> <?php esc_html_e('Upload Logo', 'simple-password-protect'); ?> </button> <p class="description"> <?php esc_html_e('Optional: Upload or enter URL for a logo to display on the password page.', 'simple-password-protect'); ?> </p> <?php if ($logoUrl): ?> <div class="spp-logo-preview-container"> <?php // Check if logo URL is a WordPress attachment $attachment_id = attachment_url_to_postid($logoUrl); if ($attachment_id) { // Use WordPress function for attachments echo wp_get_attachment_image($attachment_id, 'thumbnail', false, [ 'class' => 'spp-logo-preview ' . esc_attr(get_option('spwdprot_logo_shape', 'square')), 'id' => 'spwdprot-logo-preview', 'alt' => 'Logo Preview' ]); } else { // Check if it might be a WordPress media URL without attachment_id $upload_dir = wp_upload_dir(); if (strpos($logoUrl, $upload_dir['baseurl']) !== false) { // Try to get attachment by URL $attachment_id = attachment_url_to_postid($logoUrl); if ($attachment_id) { echo wp_get_attachment_image($attachment_id, 'medium', false, [ 'class' => 'spp-logo-preview ' . esc_attr(get_option('spwdprot_logo_shape', 'square')), 'id' => 'spwdprot-logo-preview', 'alt' => 'Logo Preview' ]); } else { // Fallback: Create img element using WordPress standards $this->renderFallbackImage($logoUrl, 'Logo Preview', 'spp-logo-preview ' . esc_attr(get_option('spwdprot_logo_shape', 'square')), 'spwdprot-logo-preview'); } } else { // External URL fallback: Create img element using WordPress standards $this->renderFallbackImage($logoUrl, 'Logo Preview', 'spp-logo-preview ' . esc_attr(get_option('spwdprot_logo_shape', 'square')), 'spwdprot-logo-preview'); } } ?> </div> <?php endif; ?> <?php } /** * Render show legal links field */ public function renderShowLegalLinksField(): void { $showLegalLinks = get_option('spwdprot_show_legal_links', true); ?> <input type="checkbox" id="spwdprot_show_legal_links" name="spwdprot_show_legal_links" value="1" <?php checked($showLegalLinks); ?> /> <label for="spwdprot_show_legal_links"> <?php esc_html_e('Display legal page links on the password protection page', 'simple-password-protect'); ?> </label> <p class="description"> <?php esc_html_e('When enabled, links to your selected legal pages will appear at the bottom of the password form.', 'simple-password-protect'); ?> </p> <?php } /** * Render impressum page field */ public function renderImpressumPageField(): void { $impressumPageId = get_option('spwdprot_impressum_page', 0); $pages = spwdprot_get_pages_for_dropdown(); ?> <select id="spwdprot_impressum_page" name="spwdprot_impressum_page"> <option value="0"><?php esc_html_e('-- Select Page --', 'simple-password-protect'); ?></option> <?php foreach ($pages as $pageId => $pageTitle): ?> <option value="<?php echo intval($pageId); ?>" <?php selected($impressumPageId, $pageId); ?>> <?php echo esc_html($pageTitle); ?> </option> <?php endforeach; ?> </select> <p class="description"> <?php esc_html_e('Select a page to display in a modal window. The page title will be used as the link text.', 'simple-password-protect'); ?> </p> <?php } /** * Render privacy page field */ public function renderPrivacyPageField(): void { $selectedPage = get_option('spwdprot_privacy_page', 0); // Get pages with fallback if (function_exists('spwdprot_get_pages_for_dropdown')) { $pages = spwdprot_get_pages_for_dropdown(); } else { // Fallback if helper function is not available $pages = [0 => __('-- Select Page --', 'simple-password-protect')]; if (function_exists('get_pages')) { $wp_pages = get_pages(['sort_column' => 'post_title', 'sort_order' => 'ASC', 'post_status' => 'publish']); foreach ($wp_pages as $page) { $pages[$page->ID] = $page->post_title; } } } ?> <select id="spwdprot_privacy_page" name="spwdprot_privacy_page"> <?php foreach ($pages as $pageId => $pageTitle): ?> <option value="<?php echo esc_attr($pageId); ?>" <?php selected($selectedPage, $pageId); ?>> <?php echo esc_html($pageTitle); ?> </option> <?php endforeach; ?> </select> <p class="description"> <?php esc_html_e('Select a page to display in a modal window. The page title will be used as the link text.', 'simple-password-protect'); ?> </p> <?php } /** * Render logo shape field */ public function renderLogoShapeField(): void { $shape = get_option('spwdprot_logo_shape', 'square'); ?> <select id="spwdprot_logo_shape" name="spwdprot_logo_shape"> <option value="square" <?php selected($shape, 'square'); ?>> <?php esc_html_e('Square/Rectangle', 'simple-password-protect'); ?> </option> <option value="round" <?php selected($shape, 'round'); ?>> <?php esc_html_e('Round/Circle', 'simple-password-protect'); ?> </option> </select> <p class="description"> <?php esc_html_e('Choose the shape style for your logo display.', 'simple-password-protect'); ?> </p> <?php } /** * Render background color field */ public function renderBackgroundColorField(): void { $color = get_option('spwdprot_background_color', '#ffffff'); ?> <input type="color" id="spwdprot_background_color" name="spwdprot_background_color" value="<?php echo esc_attr($color); ?>" /> <input type="text" id="spwdprot_background_color_text" value="<?php echo esc_attr($color); ?>" class="regular-text" readonly /> <p class="description"> <?php esc_html_e('The background color of the password protection page.', 'simple-password-protect'); ?> </p> <?php } /** * Render button color field */ public function renderButtonColorField(): void { $color = get_option('spwdprot_button_color', '#17525b'); ?> <input type="color" id="spwdprot_button_color" name="spwdprot_button_color" value="<?php echo esc_attr($color); ?>" /> <input type="text" id="spwdprot_button_color_text" value="<?php echo esc_attr($color); ?>" class="regular-text" readonly /> <p class="description"> <?php esc_html_e('The background color of the login button.', 'simple-password-protect'); ?> </p> <?php } /** * Render button text color field */ public function renderButtonTextColorField(): void { $color = get_option('spwdprot_button_text_color', '#ffffff'); ?> <input type="color" id="spwdprot_button_text_color" name="spwdprot_button_text_color" value="<?php echo esc_attr($color); ?>" /> <input type="text" id="spwdprot_button_text_color_text" value="<?php echo esc_attr($color); ?>" class="regular-text" readonly /> <p class="description"> <?php esc_html_e('The text color of the login button.', 'simple-password-protect'); ?> </p> <?php } /** * Render link color field */ public function renderLinkColorField(): void { $color = get_option('spwdprot_link_color', '#17525b'); ?> <input type="color" id="spwdprot_link_color" name="spwdprot_link_color" value="<?php echo esc_attr($color); ?>" /> <input type="text" id="spwdprot_link_color_text" value="<?php echo esc_attr($color); ?>" class="regular-text" readonly /> <p class="description"> <?php esc_html_e('The color of the legal page links (Legal Disclosure, Privacy Policy).', 'simple-password-protect'); ?> </p> <?php } /** * Render show admin login field */ public function renderShowAdminLoginField(): void { $showAdminLogin = get_option('spwdprot_show_admin_login', false); ?> <input type="checkbox" id="spwdprot_show_admin_login" name="spwdprot_show_admin_login" value="1" <?php checked($showAdminLogin); ?> /> <label for="spwdprot_show_admin_login"> <?php esc_html_e('Display a secondary "Admin Login" button on the password protection page', 'simple-password-protect'); ?> </label> <p class="description"> <?php esc_html_e('When enabled, a secondary button will appear below the main password form that allows administrators to access the WordPress login page.', 'simple-password-protect'); ?> </p> <?php } /** * Render fallback image using WordPress standards */ private function renderFallbackImage(string $src, string $alt, string $class, string $id = ''): void { // Use WordPress HTML API if available (WordPress 6.2+) if (class_exists('WP_HTML_Tag_Processor')) { $processor = new WP_HTML_Tag_Processor('<img>'); if ($processor->next_tag('img')) { $processor->set_attribute('src', $src); $processor->set_attribute('alt', $alt); $processor->set_attribute('class', $class); if (!empty($id)) { $processor->set_attribute('id', $id); } echo wp_kses($processor->get_updated_html(), [ 'img' => [ 'src' => [], 'alt' => [], 'class' => [], 'id' => [] ] ]); return; } } // Fallback: Build attributes array and use wp_kses $attributes = [ 'src' => esc_url($src), 'alt' => esc_attr($alt), 'class' => esc_attr($class) ]; if (!empty($id)) { $attributes['id'] = esc_attr($id); } $img_html = '<img'; foreach ($attributes as $key => $value) { $img_html .= ' ' . $key . '="' . $value . '"'; } $img_html .= ' />'; // Use wp_kses to ensure the HTML is safe echo wp_kses($img_html, [ 'img' => [ 'src' => [], 'alt' => [], 'class' => [], 'id' => [] ] ]); } /** * Sanitize password - this is now just a placeholder since we handle it in handlePasswordSave() * We keep this for backward compatibility but don't rely on it */ public function sanitizeAndStorePassword($input): string { // Password is now handled in handlePasswordSave() which runs earlier // This is just here as a fallback return ''; } /** * Fallback password validation */ private function validatePasswordFallback($password) { if (empty($password)) { if (class_exists('WP_Error')) { return new WP_Error('empty_password', __('Password cannot be empty.', 'simple-password-protect')); } return false; } if (strlen($password) < 6) { if (class_exists('WP_Error')) { return new WP_Error('password_too_short', __('Password must be at least 6 characters long.', 'simple-password-protect')); } return false; } if (strlen($password) > 100) { if (class_exists('WP_Error')) { return new WP_Error('password_too_long', __('Password cannot be longer than 100 characters.', 'simple-password-protect')); } return false; } return function_exists('sanitize_text_field') ? sanitize_text_field($password) : wp_strip_all_tags($password); } /** * Fallback password hashing */ private function hashPasswordFallback(string $password): string { if (function_exists('password_hash')) { return password_hash($password, PASSWORD_DEFAULT); } if (function_exists('wp_hash_password')) { return wp_hash_password($password); } return hash('sha256', $password . 'spwdprot_salt_' . time()); } /** * Legacy sanitize password method (kept for backward compatibility) */ public function sanitizePassword($input): string { return get_option('spwdprot_password_hash', ''); } /** * Sanitize logo shape */ public function sanitizeLogoShape($input): string { $allowedShapes = ['square', 'round']; return in_array($input, $allowedShapes, true) ? $input : 'square'; } /** * Show admin notices */ public function showAdminNotices(): void { // Admin notices disabled per user request // Users can see plugin status in the Current Status section } /** * Add plugin action links */ public function addPluginActionLinks(array $links): array { $settingsLink = sprintf( '<a href="%s">%s</a>', admin_url('options-general.php?page=' . self::SETTINGS_PAGE), __('Settings', 'simple-password-protect') ); array_unshift($links, $settingsLink); return $links; } }
Save File
Cancel