Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
55.42% covered (warning)
55.42%
46 / 83
35.29% covered (danger)
35.29%
6 / 17
CRAP
0.00% covered (danger)
0.00%
0 / 1
Stats
55.56% covered (warning)
55.56%
45 / 81
35.29% covered (danger)
35.29%
6 / 17
172.53
0.00% covered (danger)
0.00%
0 / 1
 get_name
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_title
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 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%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 get_pricing_for_ui
100.00% covered (success)
100.00%
7 / 7
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_wpcom_pwyw_product_slug
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_wpcom_free_product_slug
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_status
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
3.14
 is_upgradable
23.53% covered (danger)
23.53%
4 / 17
0.00% covered (danger)
0.00%
0 / 1
65.11
 get_paid_plan_product_slugs
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 get_url_product_type
22.22% covered (danger)
22.22%
4 / 18
0.00% covered (danger)
0.00%
0 / 1
57.05
 has_trial_support
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_purchase_url
90.00% covered (success)
90.00%
9 / 10
0.00% covered (danger)
0.00%
0 / 1
2.00
 get_manage_url
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 is_upgradable_by_bundle
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * Jetpack Stats product
4 *
5 * @package my-jetpack
6 */
7
8namespace Automattic\Jetpack\My_Jetpack\Products;
9
10use Automattic\Jetpack\My_Jetpack\Initializer;
11use Automattic\Jetpack\My_Jetpack\Module_Product;
12use Automattic\Jetpack\My_jetpack\Products;
13use Automattic\Jetpack\My_Jetpack\Wpcom_Products;
14use Automattic\Jetpack\Status\Host;
15use Jetpack_Options;
16
17if ( ! defined( 'ABSPATH' ) ) {
18    exit( 0 );
19}
20
21/**
22 * Class responsible for handling the Jetpack Stats product
23 */
24class Stats extends Module_Product {
25    /**
26     * The product slug
27     *
28     * @var string
29     */
30    public static $slug = 'stats';
31
32    /**
33     * The Jetpack module name associated with this product
34     *
35     * @var string|null
36     */
37    public static $module_name = 'stats';
38
39    /**
40     * The category of the product
41     *
42     * @var string
43     */
44    public static $category = 'growth';
45
46    /**
47     * The Plugin slug associated with stats
48     *
49     * @var string|null
50     */
51    public static $plugin_slug = self::JETPACK_PLUGIN_SLUG;
52
53    /**
54     * The Plugin file associated with stats
55     *
56     * @var string|null
57     */
58    public static $plugin_filename = self::JETPACK_PLUGIN_FILENAME;
59
60    /**
61     * Stats only requires site connection, not user connection
62     *
63     * @var bool
64     */
65    public static $requires_user_connection = false;
66
67    /**
68     * Stats does not have a standalone plugin (yet?)
69     *
70     * @var bool
71     */
72    public static $has_standalone_plugin = false;
73
74    /**
75     * Whether this product has a free offering
76     *
77     * @var bool
78     */
79    public static $has_free_offering = true;
80
81    /**
82     * The feature slug that identifies the paid plan
83     *
84     * @var string
85     */
86    public static $feature_identifying_paid_plan = 'stats-paid';
87
88    /**
89     * Get the product name
90     *
91     * @return string
92     */
93    public static function get_name() {
94        return 'Stats';
95    }
96
97    /**
98     * Get the product title
99     *
100     * @return string
101     */
102    public static function get_title() {
103        return 'Jetpack Stats';
104    }
105
106    /**
107     * Get the internationalized product description
108     *
109     * @return string
110     */
111    public static function get_description() {
112        return __( 'Clear, concise, and actionable analysis of your site performance.', 'jetpack-my-jetpack' );
113    }
114
115    /**
116     * Get the internationalized product long description
117     *
118     * @return string
119     */
120    public static function get_long_description() {
121        return __( 'With Jetpack Stats, you don’t need to be a data scientist to see how your site is performing, understand your visitors, and grow your site.', 'jetpack-my-jetpack' );
122    }
123
124    /**
125     * Get the internationalized features list
126     *
127     * @return array CRM features list
128     */
129    public static function get_features() {
130        return array(
131            __( 'Real-time data on visitors', 'jetpack-my-jetpack' ),
132            __( 'Traffic stats and trends for post and pages', 'jetpack-my-jetpack' ),
133            __( 'Detailed statistics about links leading to your site', 'jetpack-my-jetpack' ),
134            __( 'GDPR compliant', 'jetpack-my-jetpack' ),
135            __( 'Access to upcoming advanced features', 'jetpack-my-jetpack' ),
136            __( 'Priority support', 'jetpack-my-jetpack' ),
137            __( 'Commercial use', 'jetpack-my-jetpack' ),
138        );
139    }
140
141    /**
142     * Get the product pricing details
143     * Only showing the pricing details for the commercial product
144     *
145     * @return array Pricing details
146     */
147    public static function get_pricing_for_ui() {
148        return array_merge(
149            array(
150                'available'          => true,
151                'wpcom_product_slug' => static::get_wpcom_product_slug(),
152            ),
153            Wpcom_Products::get_product_pricing( static::get_wpcom_product_slug() )
154        );
155    }
156
157    /**
158     * Get the WPCOM product slug used to make the purchase
159     *
160     * @return ?string
161     */
162    public static function get_wpcom_product_slug() {
163        return 'jetpack_stats_yearly';
164    }
165
166    /**
167     * Get the WPCOM Pay Whatever You Want product slug used to make the purchase
168     *
169     * @return ?string
170     */
171    public static function get_wpcom_pwyw_product_slug() {
172        return 'jetpack_stats_pwyw_yearly';
173    }
174
175    /**
176     * Get the WPCOM free product slug
177     *
178     * @return ?string
179     */
180    public static function get_wpcom_free_product_slug() {
181        return 'jetpack_stats_free_yearly';
182    }
183
184    /**
185     * Gets the 'status' of the Stats product
186     *
187     * @return string
188     */
189    public static function get_status() {
190        $status = parent::get_status();
191        if ( Products::STATUS_MODULE_DISABLED === $status && ! Initializer::is_registered() ) {
192            // If the site has never been connected before, show the "Learn more" CTA,
193            // that points to the add Stats product interstitial.
194            $status = Products::STATUS_NEEDS_FIRST_SITE_CONNECTION;
195        }
196        return $status;
197    }
198    /**
199     * Checks whether the product can be upgraded to a different product.
200     * Stats Commercial plan (highest tier) & Jetpack Complete are not upgradable.
201     * Also we don't push PWYW users to upgrade.
202     *
203     * @return boolean
204     */
205    public static function is_upgradable() {
206        // For now, atomic sites with stats are not in a position to upgrade
207        if ( ( new Host() )->is_woa_site() ) {
208            return false;
209        }
210
211        $purchases_data = Wpcom_Products::get_site_current_purchases();
212        if ( ! is_wp_error( $purchases_data ) && is_array( $purchases_data ) && ! empty( $purchases_data ) ) {
213            foreach ( $purchases_data as $purchase ) {
214                // Jetpack complete includes Stats commercial & cannot be upgraded
215                if (
216                    str_starts_with( $purchase->product_slug, 'jetpack_complete' ) ||
217                    str_starts_with( $purchase->product_slug, 'jetpack_growth' )
218                ) {
219                    return false;
220                } elseif (
221                    // Stats commercial purchased with highest tier cannot be upgraded.
222                    in_array(
223                        $purchase->product_slug,
224                        array( 'jetpack_stats_yearly', 'jetpack_stats_monthly', 'jetpack_stats_bi_yearly' ),
225                        true
226                    ) && $purchase->current_price_tier_slug === 'more_than_1m_views'
227                ) {
228                    return false;
229                } elseif (
230                    // If user already has Stats PWYW, we won't push them to upgrade.
231                    $purchase->product_slug === 'jetpack_stats_pwyw_yearly'
232                ) {
233                    return false;
234                }
235            }
236        }
237        return true;
238    }
239
240    /**
241     * Get the product-slugs of the paid plans for this product (not including bundles)
242     *
243     * @return array
244     */
245    public static function get_paid_plan_product_slugs() {
246        return array(
247            'jetpack_stats_yearly',
248            'jetpack_stats_monthly',
249            'jetpack_stats_bi_yearly',
250            'jetpack_stats_pwyw_yearly',
251        );
252    }
253
254    /**
255     * Returns a productType parameter for an upgrade URL, determining whether
256     * to show the PWYW upgrade interstitial or commercial upgrade interstitial.
257     *
258     * @return string
259     */
260    public static function get_url_product_type() {
261        $purchases_data     = Wpcom_Products::get_site_current_purchases();
262        $is_commercial_site = Initializer::is_commercial_site();
263        if ( is_wp_error( $purchases_data ) ) {
264            return $is_commercial_site ? '&productType=commercial' : '';
265        }
266        if ( $is_commercial_site ) {
267            return '&productType=commercial';
268        }
269        if ( is_array( $purchases_data ) && ! empty( $purchases_data ) ) {
270            foreach ( $purchases_data as $purchase ) {
271                if (
272                    str_starts_with( $purchase->product_slug, static::get_wpcom_free_product_slug() )
273                ) {
274                    return '&productType=personal';
275                } elseif (
276                    in_array(
277                        $purchase->product_slug,
278                        array( 'jetpack_stats_yearly', 'jetpack_stats_monthly', 'jetpack_stats_bi_yearly' ),
279                        true
280                    ) &&
281                    ! empty( $purchase->current_price_tier_slug )
282                ) {
283                    return '&productType=commercial';
284                }
285            }
286        }
287        return '';
288    }
289
290    /**
291     * Checks whether the product supports trial or not.
292     * Since Jetpack Stats has been widely available as a free product in the past, it "supports" a trial.
293     *
294     * @return boolean
295     */
296    public static function has_trial_support() {
297        return true;
298    }
299
300    /**
301     * Get the WordPress.com URL for purchasing Jetpack Stats for the current site.
302     *
303     * @return ?string
304     */
305    public static function get_purchase_url() {
306        $status = static::get_status();
307        if ( $status === Products::STATUS_NEEDS_FIRST_SITE_CONNECTION ) {
308            return null;
309        }
310        // The returning URL could be customized by changing the `redirect_uri` param with relative path.
311        return sprintf(
312            '%s#!/stats/purchase/%d?from=jetpack-my-jetpack%s&redirect_uri=%s',
313            admin_url( 'admin.php?page=stats' ),
314            Jetpack_Options::get_option( 'id' ),
315            static::get_url_product_type(),
316            rawurlencode( 'admin.php?page=stats' )
317        );
318    }
319
320    /**
321     * Get the URL where the user manages the product
322     *
323     * @return ?string
324     */
325    public static function get_manage_url() {
326        return admin_url( 'admin.php?page=stats' );
327    }
328
329    /**
330     * Return product bundles list
331     * that supports the product.
332     *
333     * @return boolean|array Products bundle list.
334     */
335    public static function is_upgradable_by_bundle() {
336        return array( 'growth', 'complete' );
337    }
338}