Skip to content

Commit

Permalink
Add A/B test experiment for domain purchasing (wordpress-mobile#20590)
Browse files Browse the repository at this point in the history
  • Loading branch information
mokagio authored May 2, 2023
2 parents 74f92c5 + 89da278 commit 41dc007
Show file tree
Hide file tree
Showing 13 changed files with 88 additions and 25 deletions.
5 changes: 4 additions & 1 deletion WordPress/Classes/Services/SiteAddressService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ final class DomainsServiceAdapter: SiteAddressService {

// MARK: Properties

private let domainPurchasingEnabled = FeatureFlag.siteCreationDomainPurchasing.enabled
/// Checks if the Domain Purchasing Feature Flag and AB Experiment are enabled
private var domainPurchasingEnabled: Bool {
FeatureFlag.siteCreationDomainPurchasing.enabled && ABTest.siteCreationDomainPurchasing.isTreatmentVariation
}

/**
Corresponds to:
Expand Down
22 changes: 16 additions & 6 deletions WordPress/Classes/Utility/AB Testing/ABTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,35 @@ import AutomatticTracks
// Jetpack is not supported
enum ABTest: String, CaseIterable {
case unknown = "unknown"
case siteCreationDomainPurchasing = "jpios_site_creation_domain_purchasing_v1"

/// Returns a variation for the given experiment
var variation: Variation {
return ExPlat.shared?.experiment(self.rawValue) ?? .control
}

/// Flag indicating whether the experiment's variation is treament or not.
var isTreatmentVariation: Bool {
switch variation {
case .treatment, .customTreatment: return true
case .control: return false
}
}
}

extension ABTest {
/// Start the AB Testing platform if any experiment exists
///
static func start() {
guard ABTest.allCases.count > 1, AccountHelper.isLoggedIn,
AppConfiguration.isWordPress else {
guard ABTest.allCases.count > 1,
AccountHelper.isLoggedIn,
AppConfiguration.isJetpack,
let exPlat = ExPlat.shared
else {
return
}

let experimentNames = ABTest.allCases.filter { $0 != .unknown }.map { $0.rawValue }
ExPlat.shared?.register(experiments: experimentNames)

ExPlat.shared?.refresh()
exPlat.register(experiments: experimentNames)
exPlat.refresh()
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import Foundation

extension WPAnalytics {

/// Checks if the Domain Purchasing Feature Flag and AB Experiment are enabled
private static var domainPurchasingEnabled: Bool {
FeatureFlag.siteCreationDomainPurchasing.enabled && ABTest.siteCreationDomainPurchasing.isTreatmentVariation
}

static func domainsProperties(for blog: Blog) -> [AnyHashable: Any] {
// For now we do not have the `siteCreation` route implemented so hardcoding `menu`
domainsProperties(usingCredit: blog.canRegisterDomainWithPaidPlan, origin: .menu)
Expand All @@ -11,7 +17,7 @@ extension WPAnalytics {
origin: DomainPurchaseWebViewViewOrigin?
) -> [AnyHashable: Any] {
var dict: [AnyHashable: Any] = ["using_credit": usingCredit.stringLiteral]
if FeatureFlag.siteCreationDomainPurchasing.enabled,
if Self.domainPurchasingEnabled,
let origin = origin {
dict["origin"] = origin.rawValue
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ extension BlogListViewController {
return
}
self.present(wizard, animated: true)
WPAnalytics.track(.enhancedSiteCreationAccessed, withProperties: ["source": source])
SiteCreationAnalyticsHelper.trackSiteCreationAccessed(source: source)
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -734,7 +734,7 @@ class MySiteViewController: UIViewController, NoResultsViewHost {
return
}
self.present(wizard, animated: true)
WPAnalytics.track(.enhancedSiteCreationAccessed, withProperties: ["source": source])
SiteCreationAnalyticsHelper.trackSiteCreationAccessed(source: source)
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ extension WordPressAuthenticationManager: WordPressAuthenticatorDelegate {
}

navigationController.present(wizard, animated: true)
WPAnalytics.track(.enhancedSiteCreationAccessed, withProperties: ["source": source])
SiteCreationAnalyticsHelper.trackSiteCreationAccessed(source: source)
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ final class SiteAssemblyContentView: UIView {
label.font = WPStyleGuide.fontForTextStyle(.title1, fontWeight: .bold)
label.textColor = .text

if FeatureFlag.siteCreationDomainPurchasing.enabled {
if siteCreator.domainPurchasingEnabled {
label.textAlignment = .natural
} else {
label.textAlignment = .center
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Foundation

enum SiteCreationAnalyticsEvent: String {
case domainPurchasingExperiment = "site_creation_domain_purchasing_experiment"
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,25 @@ class SiteCreationAnalyticsHelper {
private static let variationKey = "variation"
private static let siteNameKey = "site_name"
private static let recommendedKey = "recommended"
private static let customTreatmentNameKey = "custom_treatment_variation_name"

// MARK: - Lifecycle
static func trackSiteCreationAccessed(source: String) {
WPAnalytics.track(.enhancedSiteCreationAccessed, withProperties: ["source": source])

if FeatureFlag.siteCreationDomainPurchasing.enabled {
let domainPurchasingExperimentProperties: [String: String] = {
var dict: [String: String] = [Self.variationKey: ABTest.siteCreationDomainPurchasing.variation.tracksProperty]

if case let .customTreatment(name) = ABTest.siteCreationDomainPurchasing.variation {
dict[Self.customTreatmentNameKey] = name
}

return dict
}()
Self.track(.domainPurchasingExperiment, properties: domainPurchasingExperimentProperties)
}
}

// MARK: - Site Intent
static func trackSiteIntentViewed() {
Expand Down Expand Up @@ -137,6 +156,11 @@ class SiteCreationAnalyticsHelper {
}

// MARK: - Common
private static func track(_ event: SiteCreationAnalyticsEvent, properties: [String: String] = [:]) {
let event = AnalyticsEvent(name: event.rawValue, properties: properties)
WPAnalytics.track(event)
}

private static func commonProperties(_ properties: Any?...) -> [AnyHashable: Any] {
var result: [AnyHashable: Any] = [:]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ final class AddressTableViewCell: UITableViewCell {

// MARK: - Dependencies

private let domainPurchasingEnabled = FeatureFlag.siteCreationDomainPurchasing.enabled
private var domainPurchasingEnabled: Bool {
FeatureFlag.siteCreationDomainPurchasing.enabled && ABTest.siteCreationDomainPurchasing.isTreatmentVariation
}

// MARK: - Views

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ final class WebAddressWizardContent: CollapsableHeaderViewController {
return .hidden
}

/// Checks if the Domain Purchasing Feature Flag is enabled
private let domainPurchasingEnabled = FeatureFlag.siteCreationDomainPurchasing.enabled
/// Checks if the Domain Purchasing Feature Flag and AB Experiment are enabled
private var domainPurchasingEnabled: Bool {
return siteCreator.domainPurchasingEnabled
}

/// The creator collects user input as they advance through the wizard flow.
private let siteCreator: SiteCreator
Expand Down Expand Up @@ -146,7 +148,7 @@ final class WebAddressWizardContent: CollapsableHeaderViewController {
}

private func configureUIIfNeeded() {
guard FeatureFlag.siteCreationDomainPurchasing.enabled else {
guard domainPurchasingEnabled else {
return
}

Expand All @@ -160,7 +162,7 @@ final class WebAddressWizardContent: CollapsableHeaderViewController {

private func loadHeaderView() {

if FeatureFlag.siteCreationDomainPurchasing.enabled {
if domainPurchasingEnabled {
searchBar.searchBarStyle = UISearchBar.Style.default
searchBar.translatesAutoresizingMaskIntoConstraints = false
WPStyleGuide.configureSearchBar(searchBar, backgroundColor: .clear, returnKeyType: .search)
Expand Down Expand Up @@ -215,9 +217,9 @@ final class WebAddressWizardContent: CollapsableHeaderViewController {
updateNoResultsLabelTopInset()

coordinator.animate(alongsideTransition: nil) { [weak self] (_) in
guard let `self` = self else { return }
guard let self else { return }

if FeatureFlag.siteCreationDomainPurchasing.enabled {
if self.domainPurchasingEnabled {
if !self.siteTemplateHostingController.view.isHidden {
self.updateTitleViewVisibility(true)
}
Expand Down Expand Up @@ -332,7 +334,7 @@ final class WebAddressWizardContent: CollapsableHeaderViewController {
}

private func restoreSearchIfNeeded() {
if FeatureFlag.siteCreationDomainPurchasing.enabled {
if domainPurchasingEnabled {
search(searchBar.text)
} else {
search(query(from: searchTextField))
Expand Down Expand Up @@ -422,7 +424,7 @@ final class WebAddressWizardContent: CollapsableHeaderViewController {
"search_term": lastSearchQuery as AnyObject
]

if FeatureFlag.siteCreationDomainPurchasing.enabled {
if domainPurchasingEnabled {
domainSuggestionProperties["domain_cost"] = domainSuggestion.costString
}

Expand All @@ -447,15 +449,15 @@ final class WebAddressWizardContent: CollapsableHeaderViewController {
// MARK: - Search logic

private func setAddressHintVisibility(isHidden: Bool) {
if FeatureFlag.siteCreationDomainPurchasing.enabled {
if domainPurchasingEnabled {
siteTemplateHostingController.view?.isHidden = isHidden
} else {
sitePromptView.isHidden = isHidden
}
}

private func addAddressHintView() {
if FeatureFlag.siteCreationDomainPurchasing.enabled {
if domainPurchasingEnabled {
guard let siteCreationView = siteTemplateHostingController.view else {
return
}
Expand Down Expand Up @@ -661,7 +663,7 @@ extension WebAddressWizardContent: UITableViewDelegate {
let domainSuggestion = data[indexPath.row]
self.selectedDomain = domainSuggestion

if FeatureFlag.siteCreationDomainPurchasing.enabled {
if domainPurchasingEnabled {
searchBar.resignFirstResponder()
} else {
searchTextField.resignFirstResponder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,14 @@ final class SiteCreator {
information?.title != nil
}

/// Checks if the Domain Purchasing Feature Flag and AB Experiment are enabled
var domainPurchasingEnabled: Bool {
FeatureFlag.siteCreationDomainPurchasing.enabled && ABTest.siteCreationDomainPurchasing.isTreatmentVariation
}

/// Flag indicating whether the domain checkout flow should appear or not.
var shouldShowDomainCheckout: Bool {
return FeatureFlag.siteCreationDomainPurchasing.enabled && !(address?.isFree ?? false)
domainPurchasingEnabled && !(address?.isFree ?? false)
}

/// Returns the domain suggestion if there's one,
Expand Down
6 changes: 6 additions & 0 deletions WordPress/WordPress.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3532,6 +3532,8 @@
F44FB6CB287895AF0001E3CE /* SuggestionsListViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F44FB6CA287895AF0001E3CE /* SuggestionsListViewModelTests.swift */; };
F44FB6CD287897F90001E3CE /* SuggestionsTableViewMockDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F44FB6CC287897F90001E3CE /* SuggestionsTableViewMockDelegate.swift */; };
F44FB6D12878A1020001E3CE /* user-suggestions.json in Resources */ = {isa = PBXBuildFile; fileRef = F44FB6D02878A1020001E3CE /* user-suggestions.json */; };
F45326D829F6B8A6005F9F31 /* SiteCreationAnalyticsEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = F45326D729F6B8A6005F9F31 /* SiteCreationAnalyticsEvent.swift */; };
F45326D929F6B8A6005F9F31 /* SiteCreationAnalyticsEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = F45326D729F6B8A6005F9F31 /* SiteCreationAnalyticsEvent.swift */; };
F4552086299D147B00D9F6A8 /* BlockedSite.swift in Sources */ = {isa = PBXBuildFile; fileRef = F48D44B5298992C30051EAA6 /* BlockedSite.swift */; };
F465976E28E4669200D5F49A /* [email protected] in Resources */ = {isa = PBXBuildFile; fileRef = F465976928E4669200D5F49A /* [email protected] */; };
F465976F28E4669200D5F49A /* cool-green-icon-app-76.png in Resources */ = {isa = PBXBuildFile; fileRef = F465976A28E4669200D5F49A /* cool-green-icon-app-76.png */; };
Expand Down Expand Up @@ -8890,6 +8892,7 @@
F44FB6CA287895AF0001E3CE /* SuggestionsListViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuggestionsListViewModelTests.swift; sourceTree = "<group>"; };
F44FB6CC287897F90001E3CE /* SuggestionsTableViewMockDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuggestionsTableViewMockDelegate.swift; sourceTree = "<group>"; };
F44FB6D02878A1020001E3CE /* user-suggestions.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "user-suggestions.json"; sourceTree = "<group>"; };
F45326D729F6B8A6005F9F31 /* SiteCreationAnalyticsEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SiteCreationAnalyticsEvent.swift; sourceTree = "<group>"; };
F465976928E4669200D5F49A /* [email protected] */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "[email protected]"; sourceTree = "<group>"; };
F465976A28E4669200D5F49A /* cool-green-icon-app-76.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "cool-green-icon-app-76.png"; sourceTree = "<group>"; };
F465976B28E4669200D5F49A /* [email protected] */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "[email protected]"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -12520,6 +12523,7 @@
738B9A5D21B8632E0005062B /* UITableView+Header.swift */,
738B9A5B21B85EB00005062B /* UIView+ContentLayout.swift */,
46D6114E2555DAED00B0B7BB /* SiteCreationAnalyticsHelper.swift */,
F45326D729F6B8A6005F9F31 /* SiteCreationAnalyticsEvent.swift */,
);
path = Shared;
sourceTree = "<group>";
Expand Down Expand Up @@ -21083,6 +21087,7 @@
80A2154629D15B88002FE8EB /* RemoteConfigOverrideStore.swift in Sources */,
F4DDE2C229C92F0D00C02A76 /* CrashLogging+Singleton.swift in Sources */,
4629E4212440C5B20002E15C /* GutenbergCoverUploadProcessor.swift in Sources */,
F45326D829F6B8A6005F9F31 /* SiteCreationAnalyticsEvent.swift in Sources */,
FF00889F204E01AE007CCE66 /* MediaQuotaCell.swift in Sources */,
982DDF94263238A6002B3904 /* LikeUserPreferredBlog+CoreDataClass.swift in Sources */,
F5844B6B235EAF3D007C6557 /* PartScreenPresentationController.swift in Sources */,
Expand Down Expand Up @@ -23804,6 +23809,7 @@
8B55F9EE2614D977007D618E /* UnifiedPrologueStatsContentView.swift in Sources */,
FABB21932602FC2C00C8785C /* GutenbergTenorMediaPicker.swift in Sources */,
3F8B45A029283D6C00730FA4 /* DashboardMigrationSuccessCell.swift in Sources */,
F45326D929F6B8A6005F9F31 /* SiteCreationAnalyticsEvent.swift in Sources */,
FA98B61A29A3BF050071AAE8 /* BlazeCardView.swift in Sources */,
FABB21942602FC2C00C8785C /* AztecPostViewController.swift in Sources */,
F1585442267D3BF900A2E966 /* CalendarDayToggleButton.swift in Sources */,
Expand Down

0 comments on commit 41dc007

Please sign in to comment.