admin_url( 'admin-ajax.php' ), 'testNonce' => wp_create_nonce( 'ageonce_test_connection' ), 'testingText' => __( 'Testing connection...', 'age-verification-with-ageonce' ), 'missingFieldsText' => __( 'Enter Client ID and Client Secret first.', 'age-verification-with-ageonce' ), 'genericErrorText' => __( 'Connection test failed. Please try again.', 'age-verification-with-ageonce' ), 'successTitleText' => __( 'Connection verified', 'age-verification-with-ageonce' ), 'successHintText' => __( 'Next: configure rules and run your first checkout/content test below.', 'age-verification-with-ageonce' ), 'errorTitleText' => __( 'Connection failed', 'age-verification-with-ageonce' ), 'saveNonce' => wp_create_nonce( 'ageonce_save_settings' ), 'saveTitleText' => __( 'Settings saved', 'age-verification-with-ageonce' ), 'saveHintText' => __( 'Changes were saved without page reload.', 'age-verification-with-ageonce' ), 'savingText' => __( 'Saving...', 'age-verification-with-ageonce' ), 'selectedCountText' => __( '%d selected', 'age-verification-with-ageonce' ), 'settingsUpdated' => isset( $_GET['settings-updated'] ) && sanitize_text_field( wp_unslash( $_GET['settings-updated'] ) ) === 'true', ) ); } public function clean_admin_notices() { $screen = get_current_screen(); if ( $screen && $screen->id === 'toplevel_page_ageonce-settings' ) { remove_all_actions( 'admin_notices' ); remove_all_actions( 'all_admin_notices' ); } } public function register_menu_page() { add_menu_page( __( 'AgeOnce Settings', 'age-verification-with-ageonce' ), __( 'AgeOnce', 'age-verification-with-ageonce' ), 'manage_options', 'ageonce-settings', array( $this, 'render_settings_page' ), 'dashicons-shield', 56 ); } public function register_settings() { register_setting( 'ageonce_group', 'ageonce_enabled', array( 'type' => 'string', 'default' => 'no', 'sanitize_callback' => function ( $value ) { return in_array( $value, array( 'yes', 'no' ), true ) ? $value : 'no'; }, ) ); register_setting( 'ageonce_group', 'ageonce_client_id', array( 'type' => 'string', 'default' => '', 'sanitize_callback' => 'sanitize_text_field', ) ); register_setting( 'ageonce_group', 'ageonce_client_secret', array( 'type' => 'string', 'default' => '', 'sanitize_callback' => 'sanitize_text_field', ) ); register_setting( 'ageonce_group', 'ageonce_rules', array( 'type' => 'array', 'default' => array(), 'sanitize_callback' => array( $this, 'sanitize_rules' ), ) ); register_setting( 'ageonce_group', 'ageonce_registration_enabled', array( 'type' => 'string', 'default' => 'no', 'sanitize_callback' => function ( $value ) { return in_array( $value, array( 'yes', 'no' ), true ) ? $value : 'no'; }, ) ); register_setting( 'ageonce_group', 'ageonce_registration_age', array( 'type' => 'string', 'default' => '18', 'sanitize_callback' => function ( $value ) { $age = (string) absint( $value ); return in_array( $age, array( '16', '18', '21' ), true ) ? $age : '18'; }, ) ); } /** * Sanitize content rules option (nested array). * * @param mixed $value Raw option value. * @return array Sanitized rules. */ public function sanitize_rules( $value ) { if ( ! is_array( $value ) ) { return array(); } $allowed_ages = array( '16', '18', '21' ); $out = array(); foreach ( $value as $pt_raw => $data ) { $pt = sanitize_key( (string) $pt_raw ); if ( $pt === '' || ! post_type_exists( $pt ) || ! is_array( $data ) ) { continue; } $out[ $pt ] = array(); if ( isset( $data['enabled'] ) ) { $out[ $pt ]['enabled'] = ( $data['enabled'] === 'yes' ) ? 'yes' : 'no'; } if ( isset( $data['manual_lock_enabled'] ) ) { $out[ $pt ]['manual_lock_enabled'] = ( $data['manual_lock_enabled'] === 'yes' ) ? 'yes' : 'no'; } if ( $pt === 'product' ) { $out[ $pt ]['gate_product_pages'] = ( isset( $data['gate_product_pages'] ) && $data['gate_product_pages'] === 'yes' ) ? 'yes' : 'no'; } if ( isset( $data['enabled_ages'] ) && is_array( $data['enabled_ages'] ) ) { $clean_ages = array(); foreach ( $data['enabled_ages'] as $a ) { $a = (string) absint( $a ); if ( in_array( $a, $allowed_ages, true ) ) { $clean_ages[] = $a; } } $clean_ages = array_values( array_unique( $clean_ages ) ); if ( ! empty( $clean_ages ) ) { $out[ $pt ]['enabled_ages'] = $clean_ages; } } if ( isset( $data['ages'] ) && is_array( $data['ages'] ) ) { $tax_for_pt = get_object_taxonomies( $pt, 'names' ); $out[ $pt ]['ages'] = array(); foreach ( $data['ages'] as $age_key => $age_block ) { $age_str = (string) absint( $age_key ); if ( ! in_array( $age_str, $allowed_ages, true ) || ! is_array( $age_block ) ) { continue; } if ( empty( $age_block['taxonomies'] ) || ! is_array( $age_block['taxonomies'] ) ) { continue; } $out[ $pt ]['ages'][ $age_str ] = array( 'taxonomies' => array() ); foreach ( $age_block['taxonomies'] as $tax_raw => $term_ids ) { $tax = sanitize_key( (string) $tax_raw ); if ( $tax === '' || ! in_array( $tax, $tax_for_pt, true ) || ! is_array( $term_ids ) ) { continue; } $valid_ids = array(); foreach ( $term_ids as $tid ) { $tid = absint( $tid ); if ( $tid <= 0 ) { continue; } $term = get_term( $tid, $tax ); if ( $term && ! is_wp_error( $term ) ) { $valid_ids[] = $tid; } } $valid_ids = array_values( array_unique( $valid_ids ) ); if ( ! empty( $valid_ids ) ) { $out[ $pt ]['ages'][ $age_str ]['taxonomies'][ $tax ] = $valid_ids; } } } } } return $out; } private function get_formatted_terms( $taxonomy ) { $terms = get_terms( array( 'taxonomy' => $taxonomy, 'hide_empty' => false, 'suppress_filter' => true, ) ); if ( empty( $terms ) || is_wp_error( $terms ) ) { return array(); } $term_list = array(); $id_map = array(); foreach ( $terms as $term ) { $id_map[ $term->term_id ] = $term; } foreach ( $terms as $term ) { $name_parts = array( $term->name ); $current_parent = $term->parent; while ( $current_parent && isset( $id_map[ $current_parent ] ) ) { $parent_term = $id_map[ $current_parent ]; array_unshift( $name_parts, $parent_term->name ); $current_parent = $parent_term->parent; } $term_list[ $term->term_id ] = implode( ' > ', $name_parts ); } asort( $term_list ); return $term_list; } private function has_configured_rules( array $rules ) { foreach ( $rules as $data ) { if ( ! is_array( $data ) || ! isset( $data['enabled'] ) || $data['enabled'] !== 'yes' ) { continue; } if ( ! empty( $data['manual_lock_enabled'] ) && $data['manual_lock_enabled'] === 'yes' ) { return true; } if ( ! empty( $data['ages'] ) && is_array( $data['ages'] ) ) { foreach ( $data['ages'] as $age_block ) { if ( ! empty( $age_block['taxonomies'] ) && is_array( $age_block['taxonomies'] ) ) { foreach ( $age_block['taxonomies'] as $term_ids ) { if ( ! empty( $term_ids ) ) { return true; } } } } } } return false; } private function get_connection_signature( $client_id, $client_secret ) { return hash( 'sha256', (string) $client_id . '|' . (string) $client_secret . '|' . AgeOnce_API::get_redirect_uri() ); } private function is_connection_tested( $client_id, $client_secret ) { if ( trim( (string) $client_id ) === '' || trim( (string) $client_secret ) === '' ) { return false; } return get_option( 'ageonce_connection_test_signature', '' ) === $this->get_connection_signature( $client_id, $client_secret ); } private function render_setup_step( $is_done, $label, $description, $link_url = '', $link_label = '', $step_key = '' ) { $classes = 'ageonce-setup-step' . ( $is_done ? ' is-done' : '' ); $icon = $is_done ? 'dashicons-yes' : 'dashicons-marker'; $step_attr = $step_key ? ' data-ageonce-setup-step="' . esc_attr( $step_key ) . '"' : ''; ?>