*/ public static function utm_params(): array { return array( 'utm_source' => 'source', 'utm_medium' => 'medium', 'utm_campaign' => 'campaign', 'utm_term' => 'term', 'utm_content' => 'content', // The GA4 set, stored under descriptive names rather than the bare suffix. 'utm_id' => 'campaign_id', 'utm_source_platform' => 'source_platform', 'utm_creative_format' => 'creative_format', 'utm_marketing_tactic' => 'marketing_tactic', ); } /** * Advertising click IDs. The query parameter and the storage key match. * * @return string[] */ public static function click_id_params(): array { return array( 'gclid', 'gbraid', 'wbraid', 'fbclid', 'msclkid' ); } /** * Custom query parameters configured in the settings, as parameter => key. * * @return array */ public static function custom_params(): array { $params = array(); foreach ( Settings::get( 'custom_params' ) as $param ) { $params[ $param ] = $param; } return $params; } /** * Every query parameter the capture script reads, as parameter => storage key. * * @return array */ public static function tracked_params(): array { $params = self::utm_params(); foreach ( self::click_id_params() as $click_id ) { $params[ $click_id ] = $click_id; } /** * Filters the query parameters captured on every page view. * * @param array $params Query parameter name => storage key. */ return apply_filters( 'wpat_tracked_params', $params + self::custom_params() ); } /** * The storage keys of a single touch record, grouped for display. * * @return array}> */ public static function groups(): array { $groups = array( 'campaign' => array( 'label' => __( 'Campaign', 'ghizo-attribution-tracker' ), 'keys' => array( 'source' => __( 'Traffic source, for example google or newsletter', 'ghizo-attribution-tracker' ), 'medium' => __( 'Traffic medium, for example cpc or organic', 'ghizo-attribution-tracker' ), 'campaign' => __( 'Campaign name', 'ghizo-attribution-tracker' ), 'term' => __( 'Paid keyword', 'ghizo-attribution-tracker' ), 'content' => __( 'Ad or creative variant', 'ghizo-attribution-tracker' ), 'channel' => __( 'Classified channel, for example paid_search', 'ghizo-attribution-tracker' ), ), ), 'campaign_extra' => array( 'label' => __( 'Campaign detail', 'ghizo-attribution-tracker' ), 'keys' => array( 'campaign_id' => __( 'Campaign ID, from utm_id', 'ghizo-attribution-tracker' ), 'source_platform' => __( 'Platform that sent the traffic, from utm_source_platform', 'ghizo-attribution-tracker' ), 'creative_format' => __( 'Creative format, from utm_creative_format', 'ghizo-attribution-tracker' ), 'marketing_tactic' => __( 'Marketing tactic, from utm_marketing_tactic', 'ghizo-attribution-tracker' ), ), ), 'click_id' => array( 'label' => __( 'Ad click IDs', 'ghizo-attribution-tracker' ), 'keys' => array( 'gclid' => __( 'Google Ads click ID', 'ghizo-attribution-tracker' ), 'gbraid' => __( 'Google Ads click ID (app to web)', 'ghizo-attribution-tracker' ), 'wbraid' => __( 'Google Ads click ID (web to app)', 'ghizo-attribution-tracker' ), 'fbclid' => __( 'Meta / Facebook click ID', 'ghizo-attribution-tracker' ), 'msclkid' => __( 'Microsoft Advertising click ID', 'ghizo-attribution-tracker' ), ), ), 'context' => array( 'label' => __( 'Context', 'ghizo-attribution-tracker' ), 'keys' => array( 'landing_page' => __( 'Landing page URL for this touch', 'ghizo-attribution-tracker' ), 'referrer' => __( 'External referrer for this touch', 'ghizo-attribution-tracker' ), 'timestamp' => __( 'When the touch was recorded (ISO 8601, UTC)', 'ghizo-attribution-tracker' ), ), ), ); $custom = self::custom_params(); if ( ! empty( $custom ) ) { $groups['custom'] = array( 'label' => __( 'Custom parameters', 'ghizo-attribution-tracker' ), 'keys' => array_map( /* translators: %s: query parameter name */ static fn( string $key ): string => sprintf( __( 'Value of the %s query parameter', 'ghizo-attribution-tracker' ), $key ), $custom ), ); } return $groups; } /** * Every storage key of a touch record, as key => description. * * @return array */ public static function keys(): array { $keys = array(); foreach ( self::groups() as $group ) { $keys += $group['keys']; } return $keys; } /** * Every form token the plugin can populate, as token => description. * * @return array */ public static function tokens(): array { $tokens = array(); foreach ( array( self::TOUCH_FIRST, self::TOUCH_LAST ) as $touch ) { foreach ( self::keys() as $key => $description ) { $tokens[ $touch . '_' . $key ] = $description; } } return $tokens; } /** * Whether a string is a token this plugin knows how to populate. */ public static function is_token( string $token ): bool { return isset( self::tokens()[ $token ] ); } /** * Split a token into its touch and storage key, or null when unknown. * * @return array{0: string, 1: string}|null */ public static function parse_token( string $token ): ?array { if ( ! self::is_token( $token ) ) { return null; } [ $touch, $key ] = explode( '_', $token, 2 ); return array( $touch, $key ); } /** * The label given to a Gravity Forms field created for a token. */ public static function token_label( string $token ): string { $parsed = self::parse_token( $token ); if ( null === $parsed ) { return $token; } [ $touch, $key ] = $parsed; $touch_label = self::TOUCH_FIRST === $touch ? __( 'First touch', 'ghizo-attribution-tracker' ) : __( 'Last touch', 'ghizo-attribution-tracker' ); $key_label = in_array( $key, self::click_id_params(), true ) ? strtoupper( $key ) : ucfirst( str_replace( '_', ' ', $key ) ); // "Campaign id" reads like a typo on a form field. if ( str_ends_with( $key_label, ' id' ) ) { $key_label = substr( $key_label, 0, -3 ) . ' ID'; } return $touch_label . ': ' . $key_label; } }