From dd46d3677f7958302a6b132d2db21c585f9e1bd3 Mon Sep 17 00:00:00 2001 From: Andy Sacher Date: Thu, 3 Nov 2016 18:06:49 -0700 Subject: [PATCH] Add utm query parameters onto links for comments/messages Link.tracking_link adds utm query parameters onto links inside reddit to track which button was clicked, what component type contains the button (e.g. post listing, inbox, post listing embedded on a comments page), what page type the user is visiting, and the page's subreddit. This feature is enabled via feature flag and disabled by admin mode. This commit affects programmatically-generated links to comments and messages. --- r2/example.ini | 1 + r2/r2/lib/pages/pages.py | 9 +++- r2/r2/models/link.py | 63 ++++++++++++++++++++++ r2/r2/models/subreddit.py | 1 + r2/r2/templates/comment.html | 5 +- r2/r2/templates/link.html | 3 +- r2/r2/templates/morerecursion.html | 5 +- r2/r2/templates/printablebuttons.html | 2 +- r2/r2/templates/trendingsubredditsbar.html | 6 ++- 9 files changed, 88 insertions(+), 7 deletions(-) diff --git a/r2/example.ini b/r2/example.ini index fa4c4274fa..0b7f9637db 100644 --- a/r2/example.ini +++ b/r2/example.ini @@ -963,3 +963,4 @@ feature_mobile_native_targeting = {"employee": true} feature_pause_ads = on feature_ads_auction = {"employee": true} feature_cpc_pricing = off +feature_utm_comment_links = off diff --git a/r2/r2/lib/pages/pages.py b/r2/r2/lib/pages/pages.py index 4aa2cb0517..055350555e 100644 --- a/r2/r2/lib/pages/pages.py +++ b/r2/r2/lib/pages/pages.py @@ -1991,7 +1991,7 @@ def cache_key(self): elif num > 100: num = (num / 10) * 10 - _id = make_key_id( + cache_key_args = [ self.article._fullname, self.article.contest_mode, self.article.locked, @@ -2007,7 +2007,12 @@ def cache_key(self): c.can_embed, self.max_depth, self.edits_visible, - ) + ] + + if feature.is_enabled("utm_comment_links"): + cache_key_args.append("utm_comment_links") + + _id = make_key_id(*cache_key_args) key = "pane:%s" % _id return key diff --git a/r2/r2/models/link.py b/r2/r2/models/link.py index 69034a7aa7..dc04d65e3c 100644 --- a/r2/r2/models/link.py +++ b/r2/r2/models/link.py @@ -28,6 +28,9 @@ Thing, Relation, NotFound, MultiRelation, CreationError) from r2.lib.db.operators import desc from r2.lib.errors import RedditError +from r2.lib.tracking import ( + get_site, +) from r2.lib.utils import ( base_url, domain, @@ -471,6 +474,62 @@ def markdown_link_slow(self): title = title.replace("]", r"\]") return "[%s](%s)" % (title, self.make_permalink_slow()) + @classmethod + def tracking_link(cls, + link, + wrapped_thing=None, + element_name=None, + context=None, + site_name=None): + """Add utm query parameters to reddit.com links to track navigation. + + context => ?utm_medium (listing page, post listing on hybrid page) + site_name => ?utm_name (subreddit that user is currently browsing) + element_name => ?utm_content (what element leads to this link) + """ + + if (c.user_is_admin or + not feature.is_enabled('utm_comment_links')): + return link + + urlparser = UrlParser(link) + if not urlparser.path: + # `href="#some_anchor"` + return link + if urlparser.scheme == 'javascript': + return link + if not urlparser.is_reddit_url(): + return link + + query_params = {} + + query_params["utm_source"] = "reddit" + + if context is None: + if (hasattr(wrapped_thing, 'context') and + wrapped_thing.context != cls.get_default_context()): + context = wrapped_thing.context + else: + context = request.route_dict["controller"] + if context: + query_params["utm_medium"] = context + + if element_name: + query_params["utm_content"] = element_name + + if site_name is None: + site_name = get_site() + if site_name: + query_params["utm_name"] = site_name + + query_params = {k: v for (k, v) in query_params.iteritems() if ( + v is not None)} + + if query_params: + urlparser.update_query(**query_params) + return urlparser.unparse() + return link + def _gild(self, user): now = datetime.now(g.tz) @@ -885,6 +944,10 @@ def add_props(cls, user, wrapped): # Run this last Printable.add_props(user, wrapped) + @classmethod + def get_default_context(cls): + return request.route_dict["action_name"] + @property def post_hint(self): """Returns a string that suggests the content of this link. diff --git a/r2/r2/models/subreddit.py b/r2/r2/models/subreddit.py index c042f8ab2a..1374abddf9 100644 --- a/r2/r2/models/subreddit.py +++ b/r2/r2/models/subreddit.py @@ -1777,6 +1777,7 @@ def __init__(self): class _DefaultSR(FakeSubreddit): + analytics_name = 'frontpage' #notice the space before reddit.com name = ' reddit.com' path = '/' diff --git a/r2/r2/templates/comment.html b/r2/r2/templates/comment.html index 645ee117ee..bf213950a3 100644 --- a/r2/r2/templates/comment.html +++ b/r2/r2/templates/comment.html @@ -44,7 +44,10 @@ <%def name="link()" buffered="True"> - + <% media_override = thing.link_child and getattr(thing, 'media_override', False) + url = thing.tracking_link(thing.href_url, thing, name) %> +<%! + from r2.models import Link +%> <%def name="commentBody()"> -${_("continue this thread")} +${_("continue this thread")} <%def name="midcol(cls='')"> diff --git a/r2/r2/templates/printablebuttons.html b/r2/r2/templates/printablebuttons.html index 4f1fc57131..354b74f23d 100644 --- a/r2/r2/templates/printablebuttons.html +++ b/r2/r2/templates/printablebuttons.html @@ -763,7 +763,7 @@ <% data_attrs = {"event-action": event_action} if event_action else None %> ${plain_link( title, - link, + Link.tracking_link(link, thing, element_name=event_action), _class=a_class, rel="nofollow", _sr_path=sr_path, diff --git a/r2/r2/templates/trendingsubredditsbar.html b/r2/r2/templates/trendingsubredditsbar.html index f42bb6ebb9..be79515adf 100644 --- a/r2/r2/templates/trendingsubredditsbar.html +++ b/r2/r2/templates/trendingsubredditsbar.html @@ -20,6 +20,10 @@ ## reddit Inc. All Rights Reserved. ############################################################################### +<%! + from r2.models import Link +%> +