Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
92.86% covered (success)
92.86%
13 / 14
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
AI_Launchpad_Bring_Your_AI_Tool
92.86% covered (success)
92.86%
13 / 14
50.00% covered (danger)
50.00%
1 / 2
12.05
0.00% covered (danger)
0.00%
0 / 1
 get_variation
87.50% covered (warning)
87.50%
7 / 8
0.00% covered (danger)
0.00%
0 / 1
6.07
 is_free_site
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
6
1<?php
2/**
3 * AI Launchpad: the "Bring your AI tool" experiment.
4 *
5 * @package automattic/jetpack-mu-wpcom
6 */
7
8use Automattic\Jetpack\Jetpack_Mu_Wpcom\Expiry_Notices\Expiry_Data;
9use Automattic\Jetpack\Status\Host;
10
11/**
12 * Assigns free sites to the experiment that opens the wizard on a "Guide me" or "Build with AI" choice.
13 */
14class AI_Launchpad_Bring_Your_AI_Tool {
15
16    /**
17     * The ExPlat experiment.
18     */
19    const EXPERIMENT = 'wpcom_ai_launchpad_bring_your_ai_tool_202611';
20
21    /**
22     * The variation that opens the wizard on the setup choice. The other variation, `control`, opens on the goals.
23     */
24    const TREATMENT = 'bring_your_ai_tool';
25
26    /**
27     * The user's variation, or null for a user the experiment is not for.
28     *
29     * Only an administrator of a Free Simple site is assigned. Every other check runs first, so an
30     * ineligible user never enters the experiment.
31     *
32     * @return string|null
33     */
34    public static function get_variation() {
35        if ( ! current_user_can( 'manage_options' ) || ! self::is_free_site() ) {
36            return null;
37        }
38
39        /**
40         * Overrides the "Bring your AI tool" experiment assignment on the Site Setup page, for testing.
41         *
42         * The eligibility checks still apply; only the assignment is replaced.
43         *
44         * @param bool|null $override True to force the treatment, false to force control, or null to ask ExPlat.
45         */
46        $override = apply_filters( 'wpcom_ai_launchpad_bring_your_ai_tool_override_is_treatment', null );
47        if ( null !== $override ) {
48            return $override ? self::TREATMENT : 'control';
49        }
50
51        if ( ! function_exists( '\ExPlat\assign_current_user' ) ) {
52            return null;
53        }
54
55        return \ExPlat\assign_current_user( self::EXPERIMENT );
56    }
57
58    /**
59     * Whether the site is on the Free plan: a Simple site with no paid plan bundle. Atomic sites always have one.
60     *
61     * Fails closed when the purchases helper is missing: an empty list would otherwise read as Free.
62     *
63     * @return bool
64     */
65    private static function is_free_site() {
66        if ( ! ( new Host() )->is_wpcom_simple() || ! function_exists( 'wpcom_expiry_get_purchases' ) ) {
67            return false;
68        }
69
70        // Real plan bundles only, as in AI_Launchpad_Difm_Offer::has_eligible_plan().
71        $bundles = wp_list_filter( (array) wpcom_expiry_get_purchases(), array( 'product_type' => 'bundle' ) );
72        $plan    = Expiry_Data::pick_primary_plan_purchase( $bundles );
73        $slug    = $plan && isset( $plan->product_slug ) && is_string( $plan->product_slug ) ? $plan->product_slug : 'free_plan';
74
75        return 'free_plan' === $slug;
76    }
77}