1, 'track_admins' => 0, // count logged-in users who can edit posts? 'track_query_string' => 0, // keep the full query string on paths? 'respect_dnt' => 1, // honour Do Not Track / GPC 'hash_salt_rotated' => '', // Y-m-d of last salt rotation (internal) // Data handling. 'retention_days' => 60, // raw hits kept this long, then pruned 'session_timeout' => 30, // minutes of inactivity ends a session // Network. 'trust_proxy' => '', // '' | 'cloudflare' | 'xff' // Geo. 'geoip_enabled' => 1, 'geoip_auto_update' => SXANL_Edition::is_pro() ? 1 : 0, // free edition: opt-in (downloads from repo.sentrixa.co.uk) // Front-end. 'show_credit' => 0, // "Analytics by Sentrixa" line on the site // Updates. 'auto_update' => 1, // let WordPress auto-install Sentrixa Analytics updates // Search Console (phase 3 — populated by SiteHub). 'gsc_property' => '', ); } /** * Seed defaults on activation without clobbering existing values. */ public static function seed_defaults() { $current = get_option( self::OPTION ); if ( ! is_array( $current ) ) { $current = array(); } update_option( self::OPTION, array_merge( self::defaults(), $current ), false ); } /** * Get one setting. * * @param string $key Setting key. * @return mixed */ public static function get( $key ) { $all = self::all(); return array_key_exists( $key, $all ) ? $all[ $key ] : null; } /** Settings shared with the other Sentrixa plugins: local key => Sentrixa site profile key. */ public static function profile_map() { return array( 'gsc_property' => 'gsc_property' ); } /** What this plugin already holds, for the shared profile import (never overwrites). */ public static function profile_import() { return function_exists( 'sentrixa_profile_import_from_option' ) ? sentrixa_profile_import_from_option( self::OPTION, self::profile_map() ) : array(); } /** * Get all settings merged over defaults. * * @return array */ public static function all() { $stored = get_option( self::OPTION ); if ( ! is_array( $stored ) ) { $stored = array(); } $all = array_merge( self::defaults(), $stored ); if ( function_exists( 'sentrixa_profile_overlay' ) ) { $all = sentrixa_profile_overlay( $all, self::profile_map() ); // The shared Sentrixa site profile wins. } return $all; } /** * Persist a partial update. * * @param array $patch Keys to change. */ public static function update( array $patch ) { update_option( self::OPTION, array_merge( self::all(), $patch ), false ); } /** * Register the settings screen (called from SXANL_Admin). */ public static function register() { register_setting( 'sxanl_settings_group', self::OPTION, array( __CLASS__, 'sanitize' ) ); } /** * Sanitize the whole option array from the settings form. * * @param mixed $input Raw form input. * @return array */ public static function sanitize( $input ) { $out = self::all(); $in = is_array( $input ) ? $input : array(); $bool = array( 'tracking_enabled', 'track_admins', 'track_query_string', 'respect_dnt', 'geoip_enabled', 'geoip_auto_update', 'show_credit', 'auto_update' ); foreach ( $bool as $k ) { $out[ $k ] = empty( $in[ $k ] ) ? 0 : 1; } $out['retention_days'] = max( 7, min( 400, (int) ( $in['retention_days'] ?? $out['retention_days'] ) ) ); $out['session_timeout'] = max( 5, min( 240, (int) ( $in['session_timeout'] ?? $out['session_timeout'] ) ) ); $trust = isset( $in['trust_proxy'] ) ? (string) $in['trust_proxy'] : ''; $out['trust_proxy'] = in_array( $trust, array( '', 'cloudflare', 'xff' ), true ) ? $trust : ''; $gsc = isset( $in['gsc_property'] ) ? trim( (string) $in['gsc_property'] ) : $out['gsc_property']; $out['gsc_property'] = 0 === strpos( $gsc, 'sc-domain:' ) ? 'sc-domain:' . preg_replace( '/[^a-z0-9.\-]/i', '', substr( $gsc, 10 ) ) : esc_url_raw( $gsc ); // URL-prefix or domain property. if ( function_exists( 'sentrixa_profile_push' ) && isset( $in['gsc_property'] ) ) { sentrixa_profile_push( array( 'gsc_property' => $out['gsc_property'] ), self::profile_map() ); } return $out; } }