Welcome Page add_menu_page( __( 'AgeWallet', 'agewallet-oidc-client' ), __( 'AgeWallet', 'agewallet-oidc-client' ), $cap, $this->base_slug, array( $this, 'render_welcome_page' ), 'dashicons-shield-alt' ); // 2. Welcome Submenu add_submenu_page( $this->base_slug, __( 'Welcome', 'agewallet-oidc-client' ), __( 'Welcome', 'agewallet-oidc-client' ), $cap, 'agewallet-welcome', array( $this, 'render_welcome_page' ) ); // 3. Step 1: API Credentials add_submenu_page( $this->base_slug, __( 'API Credentials', 'agewallet-oidc-client' ), __( 'API Credentials', 'agewallet-oidc-client' ), $cap, 'agewallet-credentials', array( $this, 'render_credentials_page' ) ); // 4. Step 2: Content Guarding add_submenu_page( $this->base_slug, __( 'Content Guarding', 'agewallet-oidc-client' ), __( 'Content Guarding', 'agewallet-oidc-client' ), $cap, 'agewallet-guarding', array( $this, 'render_guarding_page' ) ); // 5. Step 3: Appearance add_submenu_page( $this->base_slug, __( 'Gate Appearance', 'agewallet-oidc-client' ), __( 'Gate Appearance', 'agewallet-oidc-client' ), $cap, 'agewallet-appearance', array( $this, 'render_appearance_page' ) ); // 6. Step 4: Strict Mode Settings add_submenu_page( $this->base_slug, __( 'Strict Mode Settings', 'agewallet-oidc-client' ), __( 'Strict Mode Settings', 'agewallet-oidc-client' ), $cap, 'agewallet-strict-mode', array( $this, 'render_scripts_page' ) ); // 7. Cache Control add_submenu_page( $this->base_slug, __( 'Cache Control', 'agewallet-oidc-client' ), __( 'Cache Control', 'agewallet-oidc-client' ), $cap, 'agewallet-cache-control', array( $this, 'render_debug_page' ) ); // 8. Documentation Pages add_submenu_page( $this->base_slug, __( 'Usage Guide', 'agewallet-oidc-client' ), __( 'Usage Guide', 'agewallet-oidc-client' ), $cap, 'agewallet-usage', array( $this, 'render_usage_page' ) ); add_submenu_page( $this->base_slug, __( 'CSS Guide', 'agewallet-oidc-client' ), __( 'CSS Guide', 'agewallet-oidc-client' ), $cap, 'agewallet-css-guide', array( $this, 'render_style_guide_page' ) ); add_submenu_page( $this->base_slug, __( 'Developer Hooks', 'agewallet-oidc-client' ), __( 'Developer Hooks', 'agewallet-oidc-client' ), $cap, 'agewallet-hooks', array( $this, 'render_hooks_page' ) ); } /** * Registers settings sections and fields using the Settings API. */ public function register_settings() { // --- Group 1: Credentials --- register_setting( $this->group_credentials, AgeWalletOIDCClientPro::OPT_CLIENT_ID, array( 'sanitize_callback' => 'sanitize_text_field', 'default' => '' ) ); register_setting( $this->group_credentials, AgeWalletOIDCClientPro::OPT_CLIENT_SECRET, array( 'sanitize_callback' => 'sanitize_text_field', 'default' => '' ) ); register_setting( $this->group_credentials, AgeWalletOIDCClientPro::OPT_METADATA_DEFAULT, array( 'sanitize_callback' => array( $this, 'sanitize_metadata' ), 'default' => '' ) ); register_setting( $this->group_credentials, 'agewallet_metadata_mode', array( 'sanitize_callback' => array( $this, 'sanitize_metadata_mode' ), 'default' => AgeWallet_Metadata_Builder::MODE_STATIC ) ); register_setting( $this->group_credentials, 'agewallet_auto_metadata_fields', array( 'sanitize_callback' => array( $this, 'sanitize_auto_metadata_fields' ), 'default' => array() ) ); add_settings_section( 'agewallet_sec_creds', __( 'API Configuration', 'agewallet-oidc-client' ), '__return_false', 'agewallet-credentials' ); add_settings_field( AgeWalletOIDCClientPro::OPT_CLIENT_ID, __( 'Client ID', 'agewallet-oidc-client' ), array( $this, 'render_text_input' ), 'agewallet-credentials', 'agewallet_sec_creds', array( 'label_for' => AgeWalletOIDCClientPro::OPT_CLIENT_ID, 'class' => 'regular-text' ) ); add_settings_field( AgeWalletOIDCClientPro::OPT_CLIENT_SECRET, __( 'Client Secret', 'agewallet-oidc-client' ), array( $this, 'render_text_input' ), 'agewallet-credentials', 'agewallet_sec_creds', array( 'label_for' => AgeWalletOIDCClientPro::OPT_CLIENT_SECRET, 'class' => 'regular-text', 'type' => 'password' ) ); add_settings_field( 'oidc_redirect_uri', __( 'Redirect URI', 'agewallet-oidc-client' ), array( $this, 'render_redirect_uri' ), 'agewallet-credentials', 'agewallet_sec_creds' ); add_settings_section( 'agewallet_sec_metadata', __( 'Verification Metadata', 'agewallet-oidc-client' ), array( $this, 'render_metadata_section_description' ), 'agewallet-credentials' ); add_settings_field( 'agewallet_metadata_mode', __( 'Metadata source', 'agewallet-oidc-client' ), array( $this, 'render_metadata_source_ui' ), 'agewallet-credentials', 'agewallet_sec_metadata' ); // --- Group 2: Guarding --- register_setting( $this->group_guarding, 'agewallet_protection_mode', array( 'sanitize_callback' => 'sanitize_text_field', 'default' => 'standard' ) ); register_setting( $this->group_guarding, AgeWalletOIDCClientPro::OPT_BLOCK_MODE, array( 'sanitize_callback' => array( $this, 'sanitize_block_mode' ), 'default' => 'none' ) ); register_setting( $this->group_guarding, AgeWalletOIDCClientPro::OPT_BLOCKED_PATHS, array( 'sanitize_callback' => array( $this, 'sanitize_paths_textarea' ), 'default' => '' ) ); register_setting( $this->group_guarding, 'agewallet_excluded_paths', array( 'sanitize_callback' => array( $this, 'sanitize_paths_textarea' ), 'default' => '' ) ); // NEW: Taxonomy Rules register_setting( $this->group_guarding, 'agewallet_taxonomy_rules', array( 'sanitize_callback' => array( $this, 'sanitize_taxonomy_rules' ), 'default' => array() ) ); add_settings_section( 'agewallet_sec_guard', __( 'Protection Rules', 'agewallet-oidc-client' ), array( $this, 'render_guarding_section_description' ), 'agewallet-guarding' ); add_settings_field( 'agewallet_protection_mode', __( 'Security Mode', 'agewallet-oidc-client' ), array( $this, 'render_protection_mode_radio' ), 'agewallet-guarding', 'agewallet_sec_guard' ); add_settings_field( AgeWalletOIDCClientPro::OPT_BLOCK_MODE, __( 'Scope of Protection', 'agewallet-oidc-client' ), array( $this, 'render_radio_buttons' ), 'agewallet-guarding', 'agewallet_sec_guard', array( 'option_name' => AgeWalletOIDCClientPro::OPT_BLOCK_MODE, 'options' => array( 'none' => __( 'No automatic protection.', 'agewallet-oidc-client' ), 'all_but_home' => __( 'Protect entire site, except homepage.', 'agewallet-oidc-client' ), 'all' => __( 'Protect entire site, including homepage.', 'agewallet-oidc-client' ), 'specific' => __( 'Protect only specific URL paths.', 'agewallet-oidc-client' ) ) ) ); add_settings_field( AgeWalletOIDCClientPro::OPT_BLOCKED_PATHS, __( 'Paths to Protect', 'agewallet-oidc-client' ), array( $this, 'render_textarea' ), 'agewallet-guarding', 'agewallet_sec_guard', array( 'label_for' => AgeWalletOIDCClientPro::OPT_BLOCKED_PATHS, 'class' => 'large-text', 'rows' => 5, 'placeholder' => '/shop/, /articles/premium-content/', 'desc' => __( 'Only used if Scope is "specific". Enter comma-separated paths.', 'agewallet-oidc-client' ) ) ); add_settings_field( 'agewallet_excluded_paths', __( 'Paths to Exclude', 'agewallet-oidc-client' ), array( $this, 'render_simple_textarea' ), 'agewallet-guarding', 'agewallet_sec_guard', array( 'label_for' => 'agewallet_excluded_paths', 'class' => 'large-text', 'rows' => 3, 'placeholder' => '/privacy-policy/, /contact/', 'desc' => __( 'Exceptions to Global Protection. Any URL containing these paths will be visible.', 'agewallet-oidc-client' ) ) ); // Taxonomy Rules UI add_settings_section( 'agewallet_sec_tax_rules', __( 'Taxonomy Rules', 'agewallet-oidc-client' ), '__return_false', 'agewallet-guarding' ); add_settings_field( 'agewallet_taxonomy_rules', __( 'Configure Taxonomies', 'agewallet-oidc-client' ), array( $this, 'render_taxonomy_rules_ui' ), 'agewallet-guarding', 'agewallet_sec_tax_rules' ); // WooCommerce Rules — only shown when WC is active. if ( class_exists( 'WooCommerce' ) ) { register_setting( $this->group_guarding, AgeWalletOIDCClientPro::OPT_WC_GATE_CHECKOUT, array( 'sanitize_callback' => array( $this, 'sanitize_wc_gate_mode' ), 'default' => AgeWalletOIDCClientPro::WC_GATE_MODE_OFF ) ); register_setting( $this->group_guarding, AgeWalletOIDCClientPro::OPT_WC_METADATA_FIELDS, array( 'sanitize_callback' => array( $this, 'sanitize_wc_metadata_fields' ), 'default' => array( 'cart_hash', 'cart_total', 'currency' ) ) ); add_settings_section( 'agewallet_sec_wc', __( 'WooCommerce', 'agewallet-oidc-client' ), array( $this, 'render_wc_section_description' ), 'agewallet-guarding' ); add_settings_field( AgeWalletOIDCClientPro::OPT_WC_GATE_CHECKOUT, __( 'Checkout gating', 'agewallet-oidc-client' ), array( $this, 'render_wc_gate_mode_radio' ), 'agewallet-guarding', 'agewallet_sec_wc', array( 'label_for' => AgeWalletOIDCClientPro::OPT_WC_GATE_CHECKOUT ) ); add_settings_field( AgeWalletOIDCClientPro::OPT_WC_METADATA_FIELDS, __( 'Checkout metadata fields', 'agewallet-oidc-client' ), array( $this, 'render_wc_metadata_fields_ui' ), 'agewallet-guarding', 'agewallet_sec_wc' ); } // --- Group 3: Appearance --- register_setting( $this->group_appearance, AgeWalletOIDCClientPro::OPT_LOGO_ID, array( 'sanitize_callback' => array( $this, 'sanitize_positive_int' ), 'default' => 0 ) ); register_setting( $this->group_appearance, AgeWalletOIDCClientPro::OPT_LOGO_WIDTH_PX, array( 'sanitize_callback' => array( $this, 'sanitize_positive_int' ), 'default' => 0 ) ); register_setting( $this->group_appearance, AgeWalletOIDCClientPro::OPT_COPY_WYSIWYG, array( 'sanitize_callback' => array( $this, 'sanitize_wysiwyg' ), 'default' => $this->get_default_copy() ) ); register_setting( $this->group_appearance, AgeWalletOIDCClientPro::OPT_HIDE_HEADING, array( 'sanitize_callback' => array( $this, 'sanitize_checkbox' ), 'default' => 0 ) ); // Structured colour + radius options. Each maps to a CSS custom property // rendered into