true, 'block' => true, 'analytics_default' => false, 'media_default' => false, 'region_defaults' => true, 'gpc' => true, 'footer_link' => true, 'badge' => true, 'badge_position' => 'left', 'badge_offset' => 20, 'staff_roles' => array(), 'staff_roles_set' => false, 'banner_mode' => 'always', 'local_fonts' => false, 'banner_position' => 'center', 'banner_color' => '#0e7a52', 'policy_date' => gmdate( 'Y-m-d' ), 'privacy_page' => 0, 'version' => 1, 'overrides' => array(), 'location' => '', 'industries' => array(), 'markets' => array(), 'consumers' => 'lt3k', 'revenue_25m' => false, 'earns_from_data' => false, 'sba_small' => true, 'sensitive_data' => false, 'business_name' => get_bloginfo( 'name' ), 'privacy_email' => get_option( 'admin_email' ), 'email_alerts' => true, 'traffic' => true, 'traffic_admins' => false, 'enforce_at' => 0, ); } /** * All settings merged over defaults. * * @return array */ public function all() { if ( null === $this->values ) { $stored = get_option( self::OPTION, array() ); $this->values = array_merge( self::defaults(), is_array( $stored ) ? $stored : array() ); } return $this->values; } /** * Get one setting. * * @param string $key Setting key. * @return mixed */ public function get( $key ) { $all = $this->all(); return array_key_exists( $key, $all ) ? $all[ $key ] : null; } /** * Sanitize and save one setting. * * @param string $key Setting key. * @param mixed $value Raw value. * @return mixed|\WP_Error The stored value, or an error for unknown keys. */ public function set( $key, $value ) { if ( ! array_key_exists( $key, self::defaults() ) ) { return new \WP_Error( 'goconsent_unknown_setting', __( 'Unknown setting.', 'goconsent' ), array( 'status' => 400 ) ); } $clean = $this->sanitize( $key, $value ); $all = $this->all(); // Choosing Real estate or Restaurant turns on maps & videos by default (listing maps and tours; directions). if ( 'industries' === $key && array_diff( array_intersect( array( 'realestate', 'restaurant' ), (array) $clean ), (array) $all['industries'] ) ) { $all['media_default'] = true; } // Once an admin picks staff roles, their list replaces auto-detection. if ( 'staff_roles' === $key ) { $all['staff_roles_set'] = true; } $all[ $key ] = $clean; $this->values = $all; update_option( self::OPTION, $all ); /** * Fires after a GoConsent setting changes. * * @param string $key Setting key. * @param mixed $clean New value. */ do_action( 'goconsent_setting_updated', $key, $clean ); return $clean; } /** * Per-key sanitizer. * * @param string $key Setting key. * @param mixed $value Raw value. * @return mixed */ public function sanitize( $key, $value ) { switch ( $key ) { case 'enabled': case 'local_fonts': case 'block': case 'analytics_default': case 'media_default': case 'region_defaults': case 'gpc': case 'footer_link': case 'badge': case 'staff_roles_set': case 'email_alerts': case 'traffic': case 'traffic_admins': case 'revenue_25m': case 'earns_from_data': case 'sba_small': case 'sensitive_data': return rest_sanitize_boolean( $value ); case 'consumers': return ( 'lt10k' !== $value && isset( \GoConsent\Rules\Applicability::BANDS[ $value ] ) ) ? (string) $value : 'lt3k'; case 'markets': $m = array(); foreach ( (array) $value as $code ) { $c = Laws::sanitize_location( $code ); if ( '' !== $c && 'OTHER' !== $c ) { $m[] = $c; } } return array_values( array_unique( $m ) ); case 'banner_mode': return 'us_optout' === $value ? 'us_optout' : 'always'; case 'banner_position': return in_array( $value, array( 'center', 'left', 'bar' ), true ) ? $value : 'center'; case 'staff_roles': return array_values( array_intersect( array_map( 'sanitize_key', (array) $value ), array_keys( \GoConsent\Frontend\Skip::site_roles() ) ) ); case 'badge_position': return 'right' === $value ? 'right' : 'left'; case 'badge_offset': return max( 12, min( 160, absint( $value ) ) ); case 'banner_color': $c = sanitize_hex_color( (string) $value ); return $c ? $c : '#0e7a52'; case 'policy_date': $v = sanitize_text_field( (string) $value ); return preg_match( '/^\d{4}-\d{2}-\d{2}$/', $v ) ? $v : gmdate( 'Y-m-d' ); case 'privacy_page': case 'version': case 'enforce_at': return absint( $value ); case 'overrides': $out = array(); foreach ( (array) $value as $id => $cat ) { $id = sanitize_text_field( (string) $id ); $cat = sanitize_key( (string) $cat ); if ( '' !== $id && in_array( $cat, array( 'necessary', 'analytics', 'marketing' ), true ) ) { $out[ $id ] = $cat; } } return $out; case 'location': return Laws::sanitize_location( $value ); case 'industries': return array_values( array_intersect( array_map( 'sanitize_key', (array) $value ), array_keys( Industries::all() ) ) ); case 'business_name': return sanitize_text_field( (string) $value ); case 'privacy_email': $e = sanitize_email( (string) $value ); return is_email( $e ) ? $e : ''; } return null; } /** * Set a category override for one detected tool. * * @param string $id Tool id. * @param string $category necessary|analytics|marketing. * @return array */ public function set_override( $id, $category ) { $all = (array) $this->get( 'overrides' ); $all[ $id ] = $category; return $this->set( 'overrides', $all ); } /** * Timestamp when unknown scripts start being held (24 h after first run). * * @return int */ public function enforce_at() { $t = (int) $this->get( 'enforce_at' ); if ( ! $t ) { $t = time() + DAY_IN_SECONDS; $this->set( 'enforce_at', $t ); } return $t; } /** * Whether the 24-hour watch period is over. * * @return bool */ public function enforcing() { return time() >= $this->enforce_at(); } /** * Privacy policy page id (setting, then WP setting, then common slugs). * * @return int */ public function privacy_page_id() { $id = absint( $this->get( 'privacy_page' ) ); if ( ! $id ) { $id = absint( get_option( 'wp_page_for_privacy_policy' ) ); } if ( ! $id ) { foreach ( array( 'legal/privacy-policy', 'privacy-policy', 'privacy' ) as $path ) { $p = get_page_by_path( $path ); if ( $p ) { $id = (int) $p->ID; break; } } } return ( $id && 'publish' === get_post_status( $id ) ) ? $id : 0; } }