Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
89.58% covered (warning)
89.58%
43 / 48
90.00% covered (success)
90.00%
9 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
Pro
89.58% covered (warning)
89.58%
43 / 48
90.00% covered (success)
90.00%
9 / 10
22.55
0.00% covered (danger)
0.00%
0 / 1
 get_name
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get_title
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get_description
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get_long_description
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get_features
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
1
 get_wpcom_product_slug
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get_paid_plan_product_slugs
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get_pricing_for_ui
66.67% covered (warning)
66.67%
10 / 15
0.00% covered (danger)
0.00%
0 / 1
5.93
 has_purchase_requiring_support
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
8
 has_required_plan
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2/**
3 * Jetpack Pro bundle.
4 *
5 * @package my-jetpack
6 */
7
8namespace Automattic\Jetpack\My_Jetpack\Products;
9
10use Automattic\Jetpack\My_Jetpack\Wpcom_Products;
11
12/**
13 * Pro reuses Complete's product installation and activation.
14 */
15class Pro extends Complete {
16    /**
17     * Product slug.
18     *
19     * @var string
20     */
21    public static $slug = 'pro';
22
23    /**
24     * Bundle module name.
25     *
26     * @var string
27     */
28    public static $module_name = 'pro';
29
30    /**
31     * Product name.
32     *
33     * @return string
34     */
35    public static function get_name() {
36        return 'Pro Bundle';
37    }
38
39    /**
40     * Product title.
41     *
42     * @return string
43     */
44    public static function get_title() {
45        return 'Jetpack Pro';
46    }
47
48    /**
49     * Product description.
50     *
51     * @return string
52     */
53    public static function get_description() {
54        return __( 'Security, performance, and growth tools for your website.', 'jetpack-my-jetpack' );
55    }
56
57    /**
58     * Detailed product description.
59     *
60     * @return string
61     */
62    public static function get_long_description() {
63        return static::get_description();
64    }
65
66    /**
67     * Included features and limits.
68     *
69     * @return string[]
70     */
71    public static function get_features() {
72        return array(
73            __( 'VaultPress Backup (50GB, 30 days of history)', 'jetpack-my-jetpack' ),
74            __( 'Activity Log (30 days of history)', 'jetpack-my-jetpack' ),
75            'Scan',
76            __( 'Akismet Anti-spam (10K calls per month)', 'jetpack-my-jetpack' ),
77            __( 'Stats (50K site views per month)', 'jetpack-my-jetpack' ),
78            __( 'Search (10K records and 10K requests per month)', 'jetpack-my-jetpack' ),
79            __( 'VideoPress (1TB storage)', 'jetpack-my-jetpack' ),
80            'Boost',
81            'Social',
82            'AI Assistant',
83            _x( 'CRM Entrepreneur', 'Pro Product Feature', 'jetpack-my-jetpack' ),
84            _x( 'Newsletter and monetization tools', 'Pro Product Feature', 'jetpack-my-jetpack' ),
85        );
86    }
87
88    /**
89     * Store slug for the default term.
90     *
91     * @return string
92     */
93    public static function get_wpcom_product_slug() {
94        return 'jetpack_pro_yearly';
95    }
96
97    /**
98     * Recognized subscription slugs, including billing-only monthly.
99     *
100     * @return string[]
101     */
102    public static function get_paid_plan_product_slugs() {
103        return array( 'jetpack_pro_yearly', 'jetpack_pro_bi_yearly', 'jetpack_pro_monthly' );
104    }
105
106    /**
107     * Catalog-controlled yearly and two-year offers.
108     *
109     * @return array
110     */
111    public static function get_pricing_for_ui() {
112        if ( ! method_exists( static::class, 'get_bundle_pricing' ) ) {
113            return array(
114                'available'          => false,
115                'catalog_available'  => false,
116                'wpcom_product_slug' => static::get_wpcom_product_slug(),
117            );
118        }
119        $pricing = static::get_bundle_pricing( array( 'jetpack_pro_yearly', 'jetpack_pro_bi_yearly' ) );
120        // Calypso's rollout follows yearly availability, independently of customer eligibility.
121        $catalog_product              = Wpcom_Products::get_product( static::get_wpcom_product_slug() );
122        $pricing['catalog_available'] = true === ( $catalog_product->available ?? false );
123        // Complete changes are support-assisted; recognition does not create a downgrade offer.
124        if ( Complete::has_paid_plan_for_product() || static::has_purchase_requiring_support() ) {
125            $pricing['requires_support'] = true;
126            $pricing['available']        = false;
127            foreach ( $pricing['terms'] as &$term ) {
128                $term['available'] = false;
129            }
130        }
131        return $pricing;
132    }
133
134    /**
135     * Preserve subscriptions that Pro cannot replace through standard checkout.
136     *
137     * @see https://linear.app/a8c/issue/JETPACK-2825
138     * @see \WPCOM_Store::get_jetpack_products_covered_by_pro()
139     * @see \WPCOM_Store::site_blocks_jetpack_pro()
140     * @return bool
141     */
142    private static function has_purchase_requiring_support() {
143        $purchases = Wpcom_Products::get_site_current_purchases();
144        if ( ! is_array( $purchases ) ) {
145            return false;
146        }
147        foreach ( $purchases as $purchase ) {
148            $slug = $purchase->product_slug;
149            if (
150                false !== strpos( $slug, '_free' ) ||
151                ( 'jetpack_stats_pwyw_yearly' === $slug && false === ( $purchase->is_auto_renew_enabled ?? null ) )
152            ) {
153                continue;
154            }
155            foreach ( array( 'jetpack_search', 'jetpack_stats', 'jetpack_backup_t2_', 'jetpack_backup_realtime', 'jetpack_security_t2_', 'jetpack_security_realtime', 'jetpack_monitor' ) as $prefix ) {
156                if ( str_starts_with( $slug, $prefix ) ) {
157                    return true;
158                }
159            }
160        }
161        return false;
162    }
163
164    /**
165     * Whether Pro or Complete covers this bundle.
166     *
167     * @return bool
168     */
169    public static function has_required_plan() {
170        return static::has_paid_plan_for_product() || Complete::has_required_plan();
171    }
172}