options = is_array($options) ? $options : array(); } /** * Render the complete settings dashboard. * * @return void */ public function render() { $header_fields = $this->get_header_fields(); $feature_fields = $this->get_feature_fields(); $directive_fields = $this->get_csp_directive_fields(); $general_fields = $this->get_csp_general_fields(); $header_total = count($header_fields); $feature_total = count($feature_fields); $header_active = $this->count_enabled(array_keys($header_fields)); $feature_active = $this->count_enabled(array_keys($feature_fields)); $csp_enabled = $this->is_enabled('content_security_policy'); $status = $this->get_security_status($header_active, $header_total, $feature_active, $feature_total); ?>

render_help_menu(); ?>

$field) : ?> render_toggle_row($id, $field['label'], $field['description'], 'headers'); ?>

$field) : ?> render_toggle_row($id, $field['label'], $field['description'], 'features'); ?>

render_toggle_row('content_security_policy', esc_html__('Enable Content Security Policy', 'abdal-security-headers'), esc_html__('When enabled, the generated Content-Security-Policy header is sent with HTTP responses.', 'abdal-security-headers'), 'csp'); ?> $field) : ?> render_text_field($id, $field['label'], $field['description'], $field['directive']); ?>

$field) : ?> render_text_field($id, $field['label'], $field['description'], $field['directive'], true); ?>


                        

render_confirm_modal(); ?> render_credit_footer(); ?>

render_help_menu(); ?>

render_toggle_row( 'remove_data_on_uninstall', __('Delete all plugin data on uninstall', 'abdal-security-headers'), __('When enabled, deleting this plugin also removes its settings, CSP assistant data, custom tables, and related stored files. This cannot be undone.', 'abdal-security-headers'), 'plugin', 'ash_plugin_settings', $plugin_settings ); ?>

render_confirm_modal(); ?> render_credit_footer(); ?>
options; $checked = isset($source[$id]) && (string) $source[$id] === '1'; ?>
render_info_icon($description); ?>
options[$id]) ? $this->options[$id] : ''; ?>
render_info_icon($description); ?>
>
array( 'label' => __('X-XSS-Protection', 'abdal-security-headers'), 'description' => __('Enables the legacy browser XSS filter for older clients.', 'abdal-security-headers'), ), 'x_content_type_options' => array( 'label' => __('X-Content-Type-Options', 'abdal-security-headers'), 'description' => __('Prevents browsers from MIME-sniffing a response away from the declared content type.', 'abdal-security-headers'), ), 'strict_transport_security' => array( 'label' => __('Strict-Transport-Security', 'abdal-security-headers'), 'description' => __('Forces browsers to use HTTPS for future requests to this host.', 'abdal-security-headers'), ), 'permissions_policy' => array( 'label' => __('Permissions-Policy', 'abdal-security-headers'), 'description' => __('Restricts access to powerful browser features such as camera and geolocation.', 'abdal-security-headers'), ), 'x_frame_options' => array( 'label' => __('X-Frame-Options', 'abdal-security-headers'), 'description' => __('Controls whether the site can be embedded in frames to reduce clickjacking risk.', 'abdal-security-headers'), ), 'referrer_policy' => array( 'label' => __('Referrer-Policy', 'abdal-security-headers'), 'description' => __('Limits referrer information sent with navigations and resource requests.', 'abdal-security-headers'), ), ); } /** * Get additional security feature toggle definitions. * * @return array */ private function get_feature_fields() { return array( 'remove_x_powered_by' => array( 'label' => __('Remove X-Powered-By Header', 'abdal-security-headers'), 'description' => __('Hides server technology details exposed by the X-Powered-By header.', 'abdal-security-headers'), ), 'hide_wp_version' => array( 'label' => __('Hide WordPress Version', 'abdal-security-headers'), 'description' => __('Removes the public WordPress version from markup, feeds, scripts, and styles.', 'abdal-security-headers'), ), 'remove_login_errors' => array( 'label' => __('Remove Login Error Messages', 'abdal-security-headers'), 'description' => __('Replaces detailed login errors with a generic message to reduce user enumeration.', 'abdal-security-headers'), ), 'disable_xmlrpc' => array( 'label' => __('Disable XML-RPC', 'abdal-security-headers'), 'description' => __('Disables XML-RPC methods and blocks direct access to xmlrpc.php.', 'abdal-security-headers'), ), 'remove_x_pingback' => array( 'label' => __('Remove X-Pingback Header', 'abdal-security-headers'), 'description' => __('Removes the X-Pingback response header from WordPress output.', 'abdal-security-headers'), ), 'restrict_rest_api' => array( 'label' => __('Restrict REST API Access', 'abdal-security-headers'), 'description' => __('Blocks REST API access and removes REST discovery links from the front end.', 'abdal-security-headers'), ), ); } /** * Get CSP source directive fields shown in the main grid. * * @return array */ private function get_csp_directive_fields() { return array( 'csp_default_src' => array( 'label' => __('Default Source', 'abdal-security-headers'), 'directive' => 'default-src', 'description' => __('Default fallback for other resource types', 'abdal-security-headers'), ), 'csp_script_src' => array( 'label' => __('Script Source', 'abdal-security-headers'), 'directive' => 'script-src', 'description' => __('Valid sources for JavaScript files', 'abdal-security-headers'), ), 'csp_style_src' => array( 'label' => __('Style Source', 'abdal-security-headers'), 'directive' => 'style-src', 'description' => __('Valid sources for CSS files', 'abdal-security-headers'), ), 'csp_img_src' => array( 'label' => __('Image Source', 'abdal-security-headers'), 'directive' => 'img-src', 'description' => __('Valid sources for images', 'abdal-security-headers'), ), 'csp_connect_src' => array( 'label' => __('Connect Source', 'abdal-security-headers'), 'directive' => 'connect-src', 'description' => __('Valid sources for AJAX, WebSocket, or EventSource connections', 'abdal-security-headers'), ), 'csp_font_src' => array( 'label' => __('Font Source', 'abdal-security-headers'), 'directive' => 'font-src', 'description' => __('Valid sources for fonts', 'abdal-security-headers'), ), 'csp_object_src' => array( 'label' => __('Object Source', 'abdal-security-headers'), 'directive' => 'object-src', 'description' => __('Valid sources for plugins', 'abdal-security-headers'), ), 'csp_media_src' => array( 'label' => __('Media Source', 'abdal-security-headers'), 'directive' => 'media-src', 'description' => __('Valid sources for audio and video elements', 'abdal-security-headers'), ), 'csp_frame_src' => array( 'label' => __('Frame Source', 'abdal-security-headers'), 'directive' => 'frame-src', 'description' => __('Valid sources for iframes', 'abdal-security-headers'), ), 'csp_worker_src' => array( 'label' => __('Worker Source', 'abdal-security-headers'), 'directive' => 'worker-src', 'description' => __('Valid sources for web workers', 'abdal-security-headers'), ), 'csp_form_action' => array( 'label' => __('Form Action', 'abdal-security-headers'), 'directive' => 'form-action', 'description' => __('Valid targets for form submissions', 'abdal-security-headers'), ), 'csp_base_uri' => array( 'label' => __('Base URI', 'abdal-security-headers'), 'directive' => 'base-uri', 'description' => __('Valid values for the base element', 'abdal-security-headers'), ), 'csp_sandbox' => array( 'label' => __('Sandbox', 'abdal-security-headers'), 'directive' => 'sandbox', 'description' => __('Enables sandbox for the requested resource', 'abdal-security-headers'), ), ); } /** * Get CSP reporting fields shown in the general settings panel. * * @return array */ private function get_csp_general_fields() { return array( 'csp_report_uri' => array( 'label' => __('Report URI', 'abdal-security-headers'), 'directive' => 'report-uri', 'description' => __('URI to send violation reports to', 'abdal-security-headers'), ), 'csp_report_to' => array( 'label' => __('Report To', 'abdal-security-headers'), 'directive' => 'report-to', 'description' => __('Group name for violation reports', 'abdal-security-headers'), ), ); } /** * Check whether a stored option is enabled. * * @param string $key Option key. * @return bool */ private function is_enabled($key) { return isset($this->options[$key]) && (string) $this->options[$key] === '1'; } /** * Count enabled options from a list of keys. * * @param array $keys Option keys. * @return int */ private function count_enabled($keys) { $count = 0; foreach ($keys as $key) { if ($this->is_enabled($key)) { $count++; } } return $count; } /** * Derive the summary security status from enabled settings. * * @param int $header_active Enabled header count. * @param int $header_total Total header count. * @param int $feature_active Enabled feature count. * @param int $feature_total Total feature count. * @return array */ private function get_security_status($header_active, $header_total, $feature_active, $feature_total) { $total = $header_total + $feature_total; $active = $header_active + $feature_active; $ratio = $total > 0 ? ($active / $total) : 0; if ($ratio >= 0.75) { return array( 'tone' => 'green', 'label' => _x('Good', 'security status', 'abdal-security-headers'), 'hint' => __('Most security controls are enabled.', 'abdal-security-headers'), ); } if ($ratio >= 0.4) { return array( 'tone' => 'warning', 'label' => _x('Fair', 'security status', 'abdal-security-headers'), 'hint' => __('Some recommended security controls are still disabled.', 'abdal-security-headers'), ); } return array( 'tone' => 'muted', 'label' => _x('Needs attention', 'security status', 'abdal-security-headers'), 'hint' => __('Enable more security headers and hardening options.', 'abdal-security-headers'), ); } }