'manual', // 'manual' or 'api' 'cf_api_token' => '', 'cf_zone_id' => '', 'cf_zone_name' => '', 'cf_auto_publish' => true, 'zaraz_events_path' => '', // Per-site HTTP Events API path, generated on first use 'zaraz_debug_key' => '', // Per-site Zaraz debug key, generated on first use // General Tracking 'track_pageview' => true, 'track_scroll' => true, 'scroll_thresholds' => [25, 50, 75, 90], 'track_time_on_page' => true, 'time_thresholds' => [10, 30, 60, 120, 300], 'track_outbound' => true, 'track_email_clicks' => true, 'track_phone_clicks' => true, 'track_downloads' => true, 'download_extensions' => 'pdf,zip,csv,docx,xlsx,mp3,mp4', 'track_search' => true, 'track_404' => true, // WooCommerce Funnel 'wc_track_product_view' => true, 'wc_track_add_to_cart' => true, 'wc_track_remove_from_cart' => true, 'wc_track_view_cart' => true, 'wc_track_begin_checkout' => true, 'wc_track_purchase' => true, 'wc_track_refund' => true, 'wc_track_coupons' => true, 'wc_server_dispatch' => true, // Hybrid server-side dispatch 'server_customer_matching' => false, // Pro: customer details with server-sent purchases 'wc_server_fallback_delay' => 600, // Seconds to wait for the browser before the server sends 'wc_track_renewals' => true, // Send WooCommerce Subscriptions renewal orders (Pro) 'wc_use_parent_id_for_variations' => false, 'wc_track_variant_selection' => true, 'wc_track_payment_info' => true, // Pro feature // Interaction & Lifecycle Tracking 'track_unsubmitted_search' => true, 'track_search_selection' => true, 'track_external_links' => true, 'track_login' => true, 'track_registration' => true, 'track_comments' => true, 'exclude_logged_in_users' => false, 'excluded_user_roles' => ['administrator', 'shop_manager'], // Lead Forms 'track_forms' => true, 'forms_cf7' => true, 'forms_wpforms' => true, 'forms_gravity' => true, 'forms_fluent' => true, 'forms_elementor' => true, 'forms_generic' => false, // User Data & Privacy 'enhanced_conversions' => true, // Consent Suite & Banner Customization 'consent_provider' => 'auto', // 'auto', 'native', 'banner', 'disabled' 'gcm_v2_enabled' => true, 'gcm_ad_storage_default' => 'denied', 'gcm_analytics_default' => 'denied', 'banner_enabled' => false, 'consent_gate_tools' => false, // Hold Zaraz tools until a consent plugin grants consent 'banner_geo_eu_only' => false, 'banner_cookie_lifetime' => 180, 'banner_privacy_page_id' => 0, 'banner_privacy_custom_url'=> '', 'banner_privacy_link_text' => 'Privacy Policy', 'banner_gcm_enabled' => true, 'banner_theme_mode' => 'auto', // 'auto', 'light', 'dark' 'banner_bg_color' => '', 'banner_text_color' => '', 'banner_title' => 'We value your privacy', 'banner_text' => 'We use cookies and edge technologies to improve your experience and analyze traffic.', 'banner_accept_text' => 'Accept All', 'banner_reject_text' => 'Reject Non-Essential', 'banner_settings_text' => 'Customize', 'banner_reopen_button' => true, 'banner_reopen_position' => 'bottom-left', // 'bottom-left', 'bottom-right' 'banner_font_family' => 'inherit', 'banner_layout' => 'bottom_floating', // 'bottom_floating', 'bottom_bar', 'modal' 'banner_border_radius' => 8, 'banner_primary_color' => '#0284c7', // Tools & Credentials 'ga4_measurement_id' => '', 'google_ads_conversion_id' => '', 'google_ads_label' => '', 'google_ads_lead_label' => '', 'meta_pixel_id' => '', 'meta_capi_token' => '', 'snapchat_pixel_id' => '', 'tiktok_pixel_id' => '', 'tiktok_access_token' => '', 'pinterest_tag_id' => '', 'pinterest_ad_account_id' => '', 'pinterest_capi_token' => '', 'bing_tag_id' => '', 'linkedin_partner_id' => '', 'linkedin_purchase_conversion_id' => '', 'linkedin_lead_conversion_id' => '', 'reddit_pixel_id' => '', 'x_pixel_id' => '', 'x_purchase_event_id' => '', 'x_lead_event_id' => '', // Instagram posts rendered by Zaraz on Cloudflare (no Instagram script in the browser) 'instagram_embeds' => false, // Debugging 'debug_mode' => false, // Onboarding & Wizard Visibility 'wizard_completed' => false, 'show_wizard_in_menu' => true, ]; } /** * Retrieves all saved settings merged with defaults. * * @return array */ public static function getAll(): array { $saved = get_option(self::OPTION_KEY, []); if (!is_array($saved)) { $saved = []; } return array_merge(self::defaults(), $saved); } /** * Gets a single option value. * * @param string $key * @param mixed $default * @return mixed */ public static function get(string $key, $default = null) { $options = self::getAll(); if (array_key_exists($key, $options)) { return $options[$key]; } return $default !== null ? $default : (self::defaults()[$key] ?? null); } /** * Sets a single option value. * * @param string $key * @param mixed $value * @return bool */ public static function set(string $key, $value): bool { $options = self::getAll(); $options[$key] = $value; return update_option(self::OPTION_KEY, $options); } /** * Returns this site's Zaraz HTTP Events API path, generating a hard-to-guess one on first use. * * @return string */ public static function eventsApiPath(): string { $path = (string) self::get('zaraz_events_path', ''); if ($path === '') { $path = '/zaraz/' . bin2hex(random_bytes(8)); self::set('zaraz_events_path', $path); } return $path; } /** * Returns this site's Zaraz debug key, generating a random one on first use. * * @return string */ public static function debugKey(): string { $key = (string) self::get('zaraz_debug_key', ''); if ($key === '') { $key = bin2hex(random_bytes(10)); self::set('zaraz_debug_key', $key); } return $key; } /** * Keys generated by the plugin that settings forms must never overwrite. */ private const GENERATED_KEYS = ['zaraz_events_path', 'zaraz_debug_key']; /** * Keeps only known settings from a submitted form and casts each to its default's type. * * @param array $submitted Already unslashed values * @return array */ public static function sanitizeSubmitted(array $submitted): array { $defaults = self::defaults(); $clean = []; foreach ($submitted as $key => $value) { $key = (string) $key; if (!array_key_exists($key, $defaults) || in_array($key, self::GENERATED_KEYS, true)) { continue; } $default = $defaults[$key]; if (is_bool($default)) { $clean[$key] = filter_var($value, FILTER_VALIDATE_BOOLEAN); } elseif (is_int($default)) { $clean[$key] = (int) $value; } elseif (is_array($default)) { if (is_array($value)) { $clean[$key] = array_map('sanitize_text_field', $value); } } else { $clean[$key] = sanitize_text_field((string) $value); } } return $clean; } /** * Updates multiple options at once. * * @param array $newValues * @return bool */ public static function updateMany(array $newValues): bool { $options = self::getAll(); $updated = array_merge($options, $newValues); return update_option(self::OPTION_KEY, $updated); } }