Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
40.00% covered (danger)
40.00%
6 / 15
60.00% covered (warning)
60.00%
3 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
WPCom_Themes_Tiers
40.00% covered (danger)
40.00%
6 / 15
60.00% covered (warning)
60.00%
3 / 5
37.14
0.00% covered (danger)
0.00%
0 / 1
 plan_for
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 plan_name_for
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
30
 tier_of
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 feature_for
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 site_can_use
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
3.14
1<?php
2/**
3 * Class WPCom_Themes_Tiers.
4 * What a site's plan includes, by theme tier.
5 *
6 * @package automattic/jetpack-mu-wpcom
7 */
8
9/**
10 * Answers which theme tiers a site's plan includes.
11 *
12 * Entitlement only. Whether a surface shows a tier it cannot install is that surface's own
13 * decision: core's Add Themes tabs hide partner themes because they need their own subscription,
14 * while the Marketplace tab lists them to sell them.
15 */
16class WPCom_Themes_Tiers {
17
18    /**
19     * The tier every site can use.
20     */
21    const FREE = 'free';
22
23    /**
24     * The tier whose themes each need a subscription of their own.
25     */
26    const PARTNER = 'partner';
27
28    /**
29     * The plan each tier needs, by tier slug.
30     *
31     * These are the plans that grant the tier's capability, so buying one satisfies
32     * site_can_use(). A tier that is not listed needs no plan.
33     */
34    const MINIMUM_PLAN = array(
35        'personal'    => 'personal-bundle',
36        'premium'     => 'personal-bundle',
37        'partner'     => 'personal-bundle',
38        'woocommerce' => 'business-bundle',
39        'sensei'      => 'business-bundle',
40        'community'   => 'business-bundle',
41    );
42
43    /**
44     * The plan a tier needs.
45     *
46     * @param string $tier Tier slug.
47     * @return string Plan slug, empty for a tier that needs none.
48     */
49    public static function plan_for( string $tier ): string {
50        return self::MINIMUM_PLAN[ $tier ] ?? '';
51    }
52
53    /**
54     * What to call the plan a tier needs, for a card that offers the upgrade.
55     *
56     * @param string $tier Tier slug.
57     * @return string Plan name, empty for a tier that needs none.
58     */
59    public static function plan_name_for( string $tier ): string {
60        switch ( self::plan_for( $tier ) ) {
61            case 'personal-bundle':
62                return __( 'Personal plan', 'jetpack-mu-wpcom' );
63            case 'value_bundle':
64                return __( 'Premium plan', 'jetpack-mu-wpcom' );
65            case 'business-bundle':
66                return __( 'Business plan', 'jetpack-mu-wpcom' );
67            default:
68                return '';
69        }
70    }
71
72    /**
73     * The tier of a theme as WordPress.com returns it.
74     *
75     * @param stdClass $theme A theme from the WordPress.com themes API.
76     * @return string Tier slug, premium for a theme that reports none.
77     */
78    public static function tier_of( $theme ): string {
79        return $theme->theme_tier->slug ?? 'premium';
80    }
81
82    /**
83     * The capability name gating a tier.
84     *
85     * @param string $tier Tier slug.
86     * @return string
87     */
88    public static function feature_for( string $tier ): string {
89        return $tier . '-themes';
90    }
91
92    /**
93     * Whether this site's plan includes a tier.
94     *
95     * Necessary but not sufficient for the partner tier, which every paid plan includes while each
96     * partner theme still needs its own subscription that no plan feature reports.
97     *
98     * @param string $tier Tier slug.
99     * @return bool True for the free tier, which needs no plan. For the rest, false when the
100     *              platform cannot answer, so an unknown host offers nothing.
101     */
102    public static function site_can_use( string $tier ): bool {
103        // There is no free-themes capability, so asking the platform would deny every free theme.
104        if ( self::FREE === $tier ) {
105            return true;
106        }
107
108        return function_exists( 'wpcom_site_has_feature' )
109            && (bool) wpcom_site_has_feature( self::feature_for( $tier ) );
110    }
111}