diff --git a/WordPress/Classes/Services/SiteAddressService.swift b/WordPress/Classes/Services/SiteAddressService.swift index a7a96520998b..af5c41ada729 100644 --- a/WordPress/Classes/Services/SiteAddressService.swift +++ b/WordPress/Classes/Services/SiteAddressService.swift @@ -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: diff --git a/WordPress/Classes/Utility/AB Testing/ABTest.swift b/WordPress/Classes/Utility/AB Testing/ABTest.swift index 11359e5bca87..4aeb74cec7cf 100644 --- a/WordPress/Classes/Utility/AB Testing/ABTest.swift +++ b/WordPress/Classes/Utility/AB Testing/ABTest.swift @@ -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() } } diff --git a/WordPress/Classes/Utility/Analytics/WPAnalytics+Domains.swift b/WordPress/Classes/Utility/Analytics/WPAnalytics+Domains.swift index 35ab93fa47c1..d3877434ca99 100644 --- a/WordPress/Classes/Utility/Analytics/WPAnalytics+Domains.swift +++ b/WordPress/Classes/Utility/Analytics/WPAnalytics+Domains.swift @@ -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) @@ -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 } diff --git a/WordPress/Classes/ViewRelated/Blog/Blog List/BlogListViewController+SiteCreation.swift b/WordPress/Classes/ViewRelated/Blog/Blog List/BlogListViewController+SiteCreation.swift index 52cefc5e90d4..328a1ad45978 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog List/BlogListViewController+SiteCreation.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog List/BlogListViewController+SiteCreation.swift @@ -13,7 +13,7 @@ extension BlogListViewController { return } self.present(wizard, animated: true) - WPAnalytics.track(.enhancedSiteCreationAccessed, withProperties: ["source": source]) + SiteCreationAnalyticsHelper.trackSiteCreationAccessed(source: source) }) } } diff --git a/WordPress/Classes/ViewRelated/Blog/My Site/MySiteViewController.swift b/WordPress/Classes/ViewRelated/Blog/My Site/MySiteViewController.swift index 97a8398d09c9..5c97bc11a29d 100644 --- a/WordPress/Classes/ViewRelated/Blog/My Site/MySiteViewController.swift +++ b/WordPress/Classes/ViewRelated/Blog/My Site/MySiteViewController.swift @@ -734,7 +734,7 @@ class MySiteViewController: UIViewController, NoResultsViewHost { return } self.present(wizard, animated: true) - WPAnalytics.track(.enhancedSiteCreationAccessed, withProperties: ["source": source]) + SiteCreationAnalyticsHelper.trackSiteCreationAccessed(source: source) }) } diff --git a/WordPress/Classes/ViewRelated/NUX/WordPressAuthenticationManager.swift b/WordPress/Classes/ViewRelated/NUX/WordPressAuthenticationManager.swift index c919fccb2d84..a5bcc6074deb 100644 --- a/WordPress/Classes/ViewRelated/NUX/WordPressAuthenticationManager.swift +++ b/WordPress/Classes/ViewRelated/NUX/WordPressAuthenticationManager.swift @@ -395,7 +395,7 @@ extension WordPressAuthenticationManager: WordPressAuthenticatorDelegate { } navigationController.present(wizard, animated: true) - WPAnalytics.track(.enhancedSiteCreationAccessed, withProperties: ["source": source]) + SiteCreationAnalyticsHelper.trackSiteCreationAccessed(source: source) }) } diff --git a/WordPress/Classes/ViewRelated/Site Creation/Final Assembly/SiteAssemblyContentView.swift b/WordPress/Classes/ViewRelated/Site Creation/Final Assembly/SiteAssemblyContentView.swift index 312d762aa337..a33543678f00 100644 --- a/WordPress/Classes/ViewRelated/Site Creation/Final Assembly/SiteAssemblyContentView.swift +++ b/WordPress/Classes/ViewRelated/Site Creation/Final Assembly/SiteAssemblyContentView.swift @@ -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 diff --git a/WordPress/Classes/ViewRelated/Site Creation/Shared/SiteCreationAnalyticsEvent.swift b/WordPress/Classes/ViewRelated/Site Creation/Shared/SiteCreationAnalyticsEvent.swift new file mode 100644 index 000000000000..f40209048265 --- /dev/null +++ b/WordPress/Classes/ViewRelated/Site Creation/Shared/SiteCreationAnalyticsEvent.swift @@ -0,0 +1,5 @@ +import Foundation + +enum SiteCreationAnalyticsEvent: String { + case domainPurchasingExperiment = "site_creation_domain_purchasing_experiment" +} diff --git a/WordPress/Classes/ViewRelated/Site Creation/Shared/SiteCreationAnalyticsHelper.swift b/WordPress/Classes/ViewRelated/Site Creation/Shared/SiteCreationAnalyticsHelper.swift index 2c248f2d0388..40370021915f 100644 --- a/WordPress/Classes/ViewRelated/Site Creation/Shared/SiteCreationAnalyticsHelper.swift +++ b/WordPress/Classes/ViewRelated/Site Creation/Shared/SiteCreationAnalyticsHelper.swift @@ -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() { @@ -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] = [:] diff --git a/WordPress/Classes/ViewRelated/Site Creation/Web Address/AddressTableViewCell.swift b/WordPress/Classes/ViewRelated/Site Creation/Web Address/AddressTableViewCell.swift index 7e305ff31bab..627b81c35fc1 100644 --- a/WordPress/Classes/ViewRelated/Site Creation/Web Address/AddressTableViewCell.swift +++ b/WordPress/Classes/ViewRelated/Site Creation/Web Address/AddressTableViewCell.swift @@ -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 diff --git a/WordPress/Classes/ViewRelated/Site Creation/Web Address/WebAddressWizardContent.swift b/WordPress/Classes/ViewRelated/Site Creation/Web Address/WebAddressWizardContent.swift index d300d19b614b..7bf39b69a59d 100644 --- a/WordPress/Classes/ViewRelated/Site Creation/Web Address/WebAddressWizardContent.swift +++ b/WordPress/Classes/ViewRelated/Site Creation/Web Address/WebAddressWizardContent.swift @@ -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 @@ -146,7 +148,7 @@ final class WebAddressWizardContent: CollapsableHeaderViewController { } private func configureUIIfNeeded() { - guard FeatureFlag.siteCreationDomainPurchasing.enabled else { + guard domainPurchasingEnabled else { return } @@ -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) @@ -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) } @@ -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)) @@ -422,7 +424,7 @@ final class WebAddressWizardContent: CollapsableHeaderViewController { "search_term": lastSearchQuery as AnyObject ] - if FeatureFlag.siteCreationDomainPurchasing.enabled { + if domainPurchasingEnabled { domainSuggestionProperties["domain_cost"] = domainSuggestion.costString } @@ -447,7 +449,7 @@ 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 @@ -455,7 +457,7 @@ final class WebAddressWizardContent: CollapsableHeaderViewController { } private func addAddressHintView() { - if FeatureFlag.siteCreationDomainPurchasing.enabled { + if domainPurchasingEnabled { guard let siteCreationView = siteTemplateHostingController.view else { return } @@ -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() diff --git a/WordPress/Classes/ViewRelated/Site Creation/Wizard/SiteCreator.swift b/WordPress/Classes/ViewRelated/Site Creation/Wizard/SiteCreator.swift index 3aa83891d526..f879b7211708 100644 --- a/WordPress/Classes/ViewRelated/Site Creation/Wizard/SiteCreator.swift +++ b/WordPress/Classes/ViewRelated/Site Creation/Wizard/SiteCreator.swift @@ -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, diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 6fb002c11362..e66d539178a2 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -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 /* cool-green-icon-app-76@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F465976928E4669200D5F49A /* cool-green-icon-app-76@2x.png */; }; F465976F28E4669200D5F49A /* cool-green-icon-app-76.png in Resources */ = {isa = PBXBuildFile; fileRef = F465976A28E4669200D5F49A /* cool-green-icon-app-76.png */; }; @@ -8890,6 +8892,7 @@ F44FB6CA287895AF0001E3CE /* SuggestionsListViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuggestionsListViewModelTests.swift; sourceTree = ""; }; F44FB6CC287897F90001E3CE /* SuggestionsTableViewMockDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuggestionsTableViewMockDelegate.swift; sourceTree = ""; }; F44FB6D02878A1020001E3CE /* user-suggestions.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "user-suggestions.json"; sourceTree = ""; }; + F45326D729F6B8A6005F9F31 /* SiteCreationAnalyticsEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SiteCreationAnalyticsEvent.swift; sourceTree = ""; }; F465976928E4669200D5F49A /* cool-green-icon-app-76@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "cool-green-icon-app-76@2x.png"; sourceTree = ""; }; F465976A28E4669200D5F49A /* cool-green-icon-app-76.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "cool-green-icon-app-76.png"; sourceTree = ""; }; F465976B28E4669200D5F49A /* cool-green-icon-app-60@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "cool-green-icon-app-60@3x.png"; sourceTree = ""; }; @@ -12520,6 +12523,7 @@ 738B9A5D21B8632E0005062B /* UITableView+Header.swift */, 738B9A5B21B85EB00005062B /* UIView+ContentLayout.swift */, 46D6114E2555DAED00B0B7BB /* SiteCreationAnalyticsHelper.swift */, + F45326D729F6B8A6005F9F31 /* SiteCreationAnalyticsEvent.swift */, ); path = Shared; sourceTree = ""; @@ -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 */, @@ -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 */,