options = get_option('ash_options', array()); if (!is_array($this->options)) { $this->options = array(); } } public function enqueue_admin_assets($hook) { if (empty($this->page_hook) || $hook !== $this->page_hook) { return; } $css_path = ASH_PLUGIN_DIR . 'assets/css/admin.css'; $js_path = ASH_PLUGIN_DIR . 'assets/js/admin.js'; $css_version = file_exists($css_path) ? (string) filemtime($css_path) : ASH_VERSION; $js_version = file_exists($js_path) ? (string) filemtime($js_path) : ASH_VERSION; wp_enqueue_style( 'ash-admin-styles', ASH_PLUGIN_URL . 'assets/css/admin.css', array('dashicons'), $css_version ); wp_enqueue_script( 'ash-admin-scripts', ASH_PLUGIN_URL . 'assets/js/admin.js', array(), $js_version, true ); $assistant_js_path = ASH_PLUGIN_DIR . 'assets/js/csp-assistant.js'; $assistant_js_version = file_exists($assistant_js_path) ? (string) filemtime($assistant_js_path) : ASH_VERSION; wp_enqueue_script( 'ash-csp-assistant', ASH_PLUGIN_URL . 'assets/js/csp-assistant.js', array('ash-admin-scripts'), $assistant_js_version, true ); wp_localize_script('ash-csp-assistant', 'ashCspAssistant', array( 'ajaxUrl' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('ash_csp_assistant'), 'siteHost' => strtolower((string) wp_parse_url(home_url(), PHP_URL_HOST)), 'optionMap' => class_exists('ASH_CSP_Assistant') ? ASH_CSP_Assistant::OPTION_MAP : array(), 'strings' => class_exists('ASH_CSP_Assistant') ? ASH_CSP_Assistant::ui_strings() : array(), 'initial' => class_exists('ASH_CSP_Assistant') ? ASH_CSP_Assistant::instance()->payload() : array(), )); wp_localize_script('ash-admin-scripts', 'ashAdmin', array( 'headerFields' => array( 'x_xss_protection', 'x_content_type_options', 'strict_transport_security', 'permissions_policy', 'x_frame_options', 'referrer_policy', ), 'featureFields' => array( 'remove_x_powered_by', 'hide_wp_version', 'remove_login_errors', 'disable_xmlrpc', 'remove_x_pingback', 'restrict_rest_api', ), 'strings' => array( 'confirmSave' => __('Are you sure you want to save these settings?', 'abdal-security-headers'), 'confirmReset' => __('Reset unsaved changes and restore the last saved values?', 'abdal-security-headers'), 'saveChanges' => __('Save Changes', 'abdal-security-headers'), 'reset' => __('Reset', 'abdal-security-headers'), 'yes' => __('Yes', 'abdal-security-headers'), 'no' => __('No', 'abdal-security-headers'), 'success' => __('Settings saved successfully', 'abdal-security-headers'), 'ok' => __('OK', 'abdal-security-headers'), 'cancel' => __('Cancel', 'abdal-security-headers'), 'editorOk' => _x('OK', 'csp editor confirm', 'abdal-security-headers'), /* translators: %s: CSP directive name such as script-src */ 'editDirective' => __('Edit %s', 'abdal-security-headers'), 'error' => __('Error', 'abdal-security-headers'), 'errorMessage' => __('An error occurred while saving the settings. Please try again.', 'abdal-security-headers'), 'copied' => __('Copied', 'abdal-security-headers'), 'copyCsp' => __('Copy CSP header', 'abdal-security-headers'), 'copyFailed' => __('Unable to copy the CSP header.', 'abdal-security-headers'), 'cspEmpty' => __('Content-Security-Policy header is enabled but no directives are set.', 'abdal-security-headers'), 'cspDisabled' => __('Content Security Policy is disabled. Enable it to send this header.', 'abdal-security-headers'), 'statusGood' => _x('Good', 'security status', 'abdal-security-headers'), 'statusFair' => _x('Fair', 'security status', 'abdal-security-headers'), 'statusNeedsAttention' => _x('Needs attention', 'security status', 'abdal-security-headers'), 'statusGoodHint' => __('Most security controls are enabled.', 'abdal-security-headers'), 'statusFairHint' => __('Some recommended security controls are still disabled.', 'abdal-security-headers'), 'statusNeedsHint' => __('Enable more security headers and hardening options.', 'abdal-security-headers'), 'cspOn' => _x('Enabled', 'CSP status', 'abdal-security-headers'), 'cspOff' => _x('Disabled', 'CSP status', 'abdal-security-headers'), 'cspOnHint' => __('Content Security Policy is being sent with responses.', 'abdal-security-headers'), 'cspOffHint' => __('Content Security Policy is currently turned off.', 'abdal-security-headers'), /* translators: 1: number of enabled headers, 2: total headers */ 'headersHint' => __('%1$d of %2$d security headers are enabled', 'abdal-security-headers'), /* translators: 1: number of enabled features, 2: total features */ 'featuresHint' => __('%1$d of %2$d additional features are enabled', 'abdal-security-headers'), ), )); } public function add_plugin_page() { $this->page_hook = add_menu_page( esc_html__('Abdal Security Headers', 'abdal-security-headers'), esc_html__('Security Headers', 'abdal-security-headers'), 'manage_options', 'abdal-security-headers', array($this, 'create_admin_page'), 'dashicons-shield', 58 ); } public function create_admin_page() { require_once ASH_PLUGIN_DIR . 'includes/class-ash-admin-ui.php'; $ui = new ASH_Admin_UI($this->options); $ui->render(); } public function page_init() { register_setting( 'ash_options_group', 'ash_options', array($this, 'sanitize') ); // Basic Security Headers Section add_settings_section( 'ash_basic_headers', esc_html__('Basic Security Headers', 'abdal-security-headers'), array($this, 'print_section_info'), 'abdal-security-headers' ); // Original Headers $this->add_checkbox_field('x_xss_protection', esc_html__('X-XSS-Protection', 'abdal-security-headers'), 'ash_basic_headers'); $this->add_checkbox_field('x_content_type_options', esc_html__('X-Content-Type-Options', 'abdal-security-headers'), 'ash_basic_headers'); $this->add_checkbox_field('strict_transport_security', esc_html__('Strict-Transport-Security', 'abdal-security-headers'), 'ash_basic_headers'); $this->add_checkbox_field('permissions_policy', esc_html__('Permissions-Policy', 'abdal-security-headers'), 'ash_basic_headers'); $this->add_checkbox_field('x_frame_options', esc_html__('X-Frame-Options', 'abdal-security-headers'), 'ash_basic_headers'); $this->add_checkbox_field('referrer_policy', esc_html__('Referrer-Policy', 'abdal-security-headers'), 'ash_basic_headers'); // Additional Security Section add_settings_section( 'ash_additional_security', esc_html__('Additional Security Features', 'abdal-security-headers'), array($this, 'print_additional_section_info'), 'abdal-security-headers' ); // New Security Options $this->add_checkbox_field('remove_x_powered_by', esc_html__('Remove X-Powered-By Header', 'abdal-security-headers'), 'ash_additional_security'); $this->add_checkbox_field('hide_wp_version', esc_html__('Hide WordPress Version', 'abdal-security-headers'), 'ash_additional_security'); $this->add_checkbox_field('remove_login_errors', esc_html__('Remove Login Error Messages', 'abdal-security-headers'), 'ash_additional_security'); $this->add_checkbox_field('disable_xmlrpc', esc_html__('Disable XML-RPC', 'abdal-security-headers'), 'ash_additional_security'); $this->add_checkbox_field('remove_x_pingback', esc_html__('Remove X-Pingback Header', 'abdal-security-headers'), 'ash_additional_security'); $this->add_checkbox_field('restrict_rest_api', esc_html__('Restrict REST API Access', 'abdal-security-headers'), 'ash_additional_security'); // CSP Section add_settings_section( 'ash_csp_section', esc_html__('Content Security Policy', 'abdal-security-headers'), array($this, 'print_csp_section_info'), 'abdal-security-headers' ); // CSP Fields $csp_fields = array( 'default-src' => esc_html__('Default Source', 'abdal-security-headers'), 'script-src' => esc_html__('Script Source', 'abdal-security-headers'), 'style-src' => esc_html__('Style Source', 'abdal-security-headers'), 'img-src' => esc_html__('Image Source', 'abdal-security-headers'), 'connect-src' => esc_html__('Connect Source', 'abdal-security-headers'), 'font-src' => esc_html__('Font Source', 'abdal-security-headers'), 'object-src' => esc_html__('Object Source', 'abdal-security-headers'), 'media-src' => esc_html__('Media Source', 'abdal-security-headers'), 'frame-src' => esc_html__('Frame Source', 'abdal-security-headers'), 'worker-src' => esc_html__('Worker Source', 'abdal-security-headers'), 'form-action' => esc_html__('Form Action', 'abdal-security-headers'), 'base-uri' => esc_html__('Base URI', 'abdal-security-headers'), 'sandbox' => esc_html__('Sandbox', 'abdal-security-headers'), 'report-uri' => esc_html__('Report URI', 'abdal-security-headers'), 'report-to' => esc_html__('Report To', 'abdal-security-headers') ); foreach ($csp_fields as $key => $label) { $this->add_text_field('csp_' . str_replace('-', '_', $key), $label, 'ash_csp_section'); } } private function add_checkbox_field($id, $title, $section) { add_settings_field( $id, $title, array($this, 'checkbox_callback'), 'abdal-security-headers', $section, array( 'id' => $id, 'label' => $title, 'class' => 'ash-settings-row' ) ); } private function add_text_field($id, $title, $section) { add_settings_field( $id, $title, array($this, 'text_callback'), 'abdal-security-headers', $section, array( 'id' => $id, 'label' => $title, 'class' => 'ash-settings-row' ) ); } public function checkbox_callback($args) { $id = isset($args['id']) ? $args['id'] : ''; $label = isset($args['label']) ? $args['label'] : ''; $checked = isset($this->options[$id]) ? $this->options[$id] : '0'; ?> options[$id]) ? $this->options[$id] : ''; ?>