*/ const DEFAULTS = array( 'tag_post_types' => 'all', 'tag_exclude_logged_in' => false, 'tag_exclude_admins' => false, 'tag_exclude_urls' => '', 'tag_consent_mode' => 'manual', 'tag_didomi_vendor' => '', 'tag_didomi_purposes' => '', 'tag_consent_legacy_off' => false, 'show_dashboard_widget' => true, 'default_date_range' => '30d', 'api_base' => '', 'console_url' => '', 'tag_url' => '', ); /** * The tag's consent modes (AdPriva/tag#138, Didomi in tag#165), rendered as * data-consent-mode, in the order the console offers them. * * @var array */ const CONSENT_MODES = array( 'manual', 'didomi', 'tcf', 'off' ); /** * Mode used for a missing, unknown or unusable value. Never `off`. */ const DEFAULT_CONSENT_MODE = 'manual'; /** * The tag rejects this placeholder from its README, so the console and the * plugin do too (console tag-snippet.ts DIDOMI_PURPOSE_PLACEHOLDER). */ const DIDOMI_PURPOSE_PLACEHOLDER = 'YOUR_ADPRIVA_PURPOSE_ID'; /** * Set once the 1.3.2 consent-default migration has run. */ const MIGRATED_OPTION = 'adpriva_consent_default_migrated'; const CONSENT_DOCS_URL = 'https://docs.adpriva.com/developer-docs/tag-installation/#consent-modes'; /** * Built-in tag script URL (AdPriva/infrastructure#27). Loaded from this host, the * tag sends to ingest.adpriva.com. The legacy cdn.adpriva-ads.com/tag.js (which * sends to server.adpriva-ads.com) stays live for a Tag script URL override or an * ADPRIVA_TAG_URL constant. * * @var string */ const DEFAULT_TAG_URL = 'https://cdn.adpriva.com/tag.js'; /** * Map of override key => the wp-config constant that pins (and overrides) it. * * @var array */ const ENDPOINT_CONSTANTS = array( 'api_base' => 'ADPRIVA_API_BASE', 'console_url' => 'ADPRIVA_CONSOLE_URL', 'tag_url' => 'ADPRIVA_TAG_URL', ); /** * Register hooks (Settings API registration runs on admin_init). * * @return void */ public function hooks() { add_action( 'admin_init', array( __CLASS__, 'register' ) ); add_action( 'admin_notices', array( __CLASS__, 'notice_legacy_off' ) ); } /** * One-time upgrade step for the 1.3.2 consent default (wordpress-plugin#42). * * Before 1.3.2 a site that never saved the setting ran on `off`. The default is * now `manual`, which would silently stop that site's data. So the first time this * runs, a CONNECTED site with no stored mode is pinned to an explicit `off` and * flagged for the admin notice. A fresh install, or a site that connects later, * is not touched and resolves to `manual`. * * @return void */ public static function migrate_consent_default() { if ( get_option( self::MIGRATED_OPTION, false ) ) { return; } $stored = get_option( self::OPTION, array() ); $stored = is_array( $stored ) ? $stored : array(); if ( Adpriva_Tokens::is_connected() && ! array_key_exists( 'tag_consent_mode', $stored ) ) { $stored['tag_consent_mode'] = 'off'; $stored['tag_consent_legacy_off'] = true; update_option( self::OPTION, $stored ); } update_option( self::MIGRATED_OPTION, '1' ); } /** * Admin notice for a site upgraded onto an implicit `off`. It ends when the owner * saves the Settings page (sanitize() resets the flag). * * @return void */ public static function notice_legacy_off() { if ( ! current_user_can( 'manage_options' ) || ! self::get( 'tag_consent_legacy_off' ) || 'off' !== self::tag_consent_mode() ) { return; } $url = admin_url( 'admin.php?page=' . self::PAGE ); printf( '

%1$s %3$s

', esc_html__( 'AdPriva is collecting before visitor consent: this site was set to Off when the plugin was updated. Choose Manual, TCF or Didomi so nothing is collected until consent is given.', 'adpriva' ), esc_url( $url ), esc_html__( 'Choose a consent mode', 'adpriva' ) ); } /** * What is wrong with the Didomi inputs, keyed vendor|purposes. Empty when both * are usable. Same rules as the console (tag-snippet.ts validateDidomi()). * * @param string $vendor Custom vendor id, starts with c:. * @param string $purposes Comma-separated purpose ids. * @return array */ public static function validate_didomi( $vendor, $purposes ) { $errors = array(); $v = trim( (string) $vendor ); if ( 0 !== strpos( $v, 'c:' ) || ! preg_match( '/^[A-Za-z0-9._-]+$/', substr( $v, 2 ) ) ) { $errors['vendor'] = __( 'Enter the custom vendor ID from the Didomi Console. It starts with c:', 'adpriva' ); } $list = self::purpose_list( (string) $purposes ); if ( empty( $list ) ) { $errors['purposes'] = __( 'Enter at least one purpose ID from the Didomi Console.', 'adpriva' ); } elseif ( in_array( strtolower( self::DIDOMI_PURPOSE_PLACEHOLDER ), array_map( 'strtolower', $list ), true ) ) { $errors['purposes'] = __( 'Replace the placeholder with the purpose ID you created in Didomi.', 'adpriva' ); } else { foreach ( $list as $id ) { if ( ! preg_match( '/^[A-Za-z0-9._-]+$/', $id ) ) { $errors['purposes'] = __( 'Purpose IDs use letters, digits, dots, hyphens and underscores only.', 'adpriva' ); break; } } } return $errors; } /** * Comma-separated ids, trimmed, empties dropped. * * @param string $purposes Raw list. * @return array */ private static function purpose_list( $purposes ) { $out = array(); foreach ( explode( ',', $purposes ) as $id ) { $id = trim( $id ); if ( '' !== $id ) { $out[] = $id; } } return $out; } /** * The attributes the tag's