Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
82.76% covered (warning)
82.76%
72 / 87
45.45% covered (danger)
45.45%
5 / 11
CRAP
n/a
0 / 0
wpcom_site_has_wordpress_agent_plan
80.00% covered (warning)
80.00%
4 / 5
0.00% covered (danger)
0.00%
0 / 1
4.13
wpcom_is_wordpress_agent_enabled
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
5
is_fully_managed_agency_site
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
is_wpcom_user
80.00% covered (warning)
80.00%
8 / 10
0.00% covered (danger)
0.00%
0 / 1
3.07
wpcom_get_site_slug
57.14% covered (warning)
57.14%
4 / 7
0.00% covered (danger)
0.00%
0 / 1
8.83
wpcom_get_calypso_origin
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
3
jetpack_mu_wpcom_enqueue_assets
93.33% covered (success)
93.33%
28 / 30
0.00% covered (danger)
0.00%
0 / 1
9.02
get_wpcom_blog_id
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
7
is_woa_site
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
is_user_connected
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
12
wpcom_has_blog_sticker
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
5
1<?php
2/**
3 * Utility functions for jetpack-mu-wpcom.
4 *
5 * @package automattic/jetpack-mu-wpcom
6 */
7
8use Automattic\Jetpack\Connection\Manager as Connection_Manager;
9use Automattic\Jetpack\Jetpack_Mu_Wpcom;
10
11/**
12 * Whether the site has a plan that grants the Big Sky feature.
13 *
14 * Simple reads the platform feature, and also counts the legacy Big Sky free trial,
15 * which has no plan. Atomic asks Jetpack's Current_Plan, which resolves through the
16 * platform plan features. Without either source the answer is true, which falls back to
17 * the option alone, so a host that cannot tell is not locked out.
18 *
19 * @return bool
20 */
21function wpcom_site_has_wordpress_agent_plan(): bool {
22    if ( function_exists( 'big_sky_is_available_for_site' ) ) {
23        // @phan-suppress-next-line PhanUndeclaredFunction -- Provided by WPCOM's Big Sky mu-plugin; guarded above.
24        return (bool) big_sky_is_available_for_site() || wpcom_has_blog_sticker( 'big-sky-free-trial', get_wpcom_blog_id() );
25    }
26
27    if ( class_exists( '\Automattic\Jetpack\Current_Plan' ) ) {
28        return \Automattic\Jetpack\Current_Plan::supports( 'big-sky' );
29    }
30
31    return true;
32}
33
34/**
35 * Whether the WordPress Agent is enabled on this site.
36 *
37 * Simple combines the platform state with the saved option; Atomic reads the option.
38 * Both also need a plan that grants Big Sky, so a site downgraded to Free, which
39 * keeps its sticker and option, falls back to the Jetpack AI panel.
40 *
41 * @return bool
42 */
43function wpcom_is_wordpress_agent_enabled(): bool {
44    // The plan check is the costly one, so it goes last.
45    if ( function_exists( 'big_sky_is_enabled' ) ) {
46        // @phan-suppress-next-line PhanUndeclaredFunction -- Provided by WPCOM's Big Sky mu-plugin; guarded above.
47        return (bool) get_option( 'big_sky_enable', '1' ) && (bool) big_sky_is_enabled() && wpcom_site_has_wordpress_agent_plan();
48    }
49
50    return (bool) get_option( 'big_sky_enable', '0' ) && wpcom_site_has_wordpress_agent_plan();
51}
52
53/**
54 * Whether the site is fully managed agency site.
55 *
56 * @return bool True if the site is fully managed agency site.
57 */
58function is_fully_managed_agency_site() {
59    return ! empty( get_option( 'is_fully_managed_agency_site' ) );
60}
61
62/**
63 * Whether the current user is logged-in via WordPress.com account.
64 *
65 * @return bool True if the user has associated WordPress.com account.
66 */
67function is_wpcom_user() {
68    // If the site is explicitly marked as agency-managed, treat the user as non-wpcom user.
69    if ( is_fully_managed_agency_site() ) {
70        return false;
71    }
72
73    $user_id = get_current_user_id();
74
75    if ( function_exists( '\A8C\Billingdaddy\Users\get_wpcom_user' ) ) {
76        // On Simple sites, use get_wpcom_user function to check if the user has a WordPress.com account.
77        $user        = \A8C\Billingdaddy\Users\get_wpcom_user( $user_id );
78        $has_account = isset( $user->ID );
79    } else {
80        // On Atomic sites, use the Connection Manager to check if the user has a WordPress.com account.
81        $connection_manager = new Connection_Manager();
82        $wpcom_user_data    = $connection_manager->get_connected_user_data( $user_id );
83        $has_account        = isset( $wpcom_user_data['ID'] );
84    }
85
86    return $has_account;
87}
88
89/**
90 * Helper function to return the site slug for Calypso URLs.
91 * The fallback logic here is derived from the following code:
92 *
93 * @see https://github.com/Automattic/wc-calypso-bridge/blob/85664e2c7836b2ddc29e99871ec2c5dc4015bcc8/class-wc-calypso-bridge.php#L227-L251
94 *
95 * @return string
96 */
97function wpcom_get_site_slug() {
98    if ( defined( 'IS_WPCOM' ) && IS_WPCOM && class_exists( 'WPCOM_Masterbar' ) && method_exists( 'WPCOM_Masterbar', 'get_calypso_site_slug' ) ) {
99        return WPCOM_Masterbar::get_calypso_site_slug( get_current_blog_id() );
100    }
101
102    // The Jetpack class should be auto-loaded if Jetpack has been loaded,
103    // but we've seen fatal errors from cases where the class wasn't defined.
104    // So let's make double-sure it exists before calling it.
105    if ( class_exists( '\Automattic\Jetpack\Status' ) ) {
106        $jetpack_status = new \Automattic\Jetpack\Status();
107
108        return $jetpack_status->get_site_suffix();
109    }
110
111    // If the Jetpack Status class doesn't exist, fall back on site_url()
112    // with any trailing '/' characters removed.
113    $site_url = untrailingslashit( site_url( '/', 'https' ) );
114
115    // Remove the leading 'https://' and replace any remaining `/` characters with ::
116    return str_replace( '/', '::', substr( $site_url, 8 ) );
117}
118
119/**
120 * Returns the Calypso domain that originated the current request.
121 *
122 * @return string
123 */
124function wpcom_get_calypso_origin() {
125    $origin  = ! empty( $_GET['calypso_origin'] ) ? wp_unslash( $_GET['calypso_origin'] ) : 'https://wordpress.com'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
126    $allowed = array(
127        'http://calypso.localhost:3000',
128        'http://127.0.0.1:41050', // Desktop App.
129        'https://wpcalypso.wordpress.com',
130        'https://horizon.wordpress.com',
131        'https://wordpress.com',
132        'http://my.localhost:3000',
133        'https://my.wordpress.com',
134    );
135    return in_array( $origin, $allowed, true ) ? $origin : 'https://wordpress.com';
136}
137
138/**
139 * Returns the Calypso domain that originated the current request.
140 *
141 * @param string $asset_name The name of the asset.
142 * @param array  $asset_types The types of the asset.
143 *
144 * @return string
145 */
146function jetpack_mu_wpcom_enqueue_assets( $asset_name, $asset_types = array() ) {
147    $asset_handle = "jetpack-mu-wpcom-$asset_name";
148    $asset_path   = Jetpack_Mu_Wpcom::BASE_DIR . "build/$asset_name/$asset_name.asset.php";
149    $asset_file   = file_exists( $asset_path ) ? include $asset_path : array();
150    if ( ! is_array( $asset_file ) ) {
151        $asset_file = array();
152    }
153
154    if ( in_array( 'js', $asset_types, true ) ) {
155        $js_file      = "build/$asset_name/$asset_name.js";
156        $js_path      = Jetpack_Mu_Wpcom::BASE_DIR . $js_file;
157        $dependencies = $asset_file['dependencies'] ?? array();
158        $version      = $asset_file['version'] ?? ( file_exists( $js_path ) ? filemtime( $js_path ) : null );
159        wp_enqueue_script(
160            "jetpack-mu-wpcom-$asset_name",
161            plugins_url( $js_file, Jetpack_Mu_Wpcom::BASE_FILE ),
162            $dependencies,
163            $version,
164            true
165        );
166        if ( in_array( 'wp-i18n', $dependencies, true ) ) {
167            wp_set_script_translations( $asset_handle, 'jetpack-mu-wpcom' );
168        }
169    }
170
171    if ( in_array( 'css', $asset_types, true ) ) {
172        $css_ext  = is_rtl() ? 'rtl.css' : 'css';
173        $css_file = "build/$asset_name/$asset_name.$css_ext";
174        $css_path = Jetpack_Mu_Wpcom::BASE_DIR . $css_file;
175        wp_enqueue_style(
176            "jetpack-mu-wpcom-$asset_name",
177            plugins_url( $css_file, Jetpack_Mu_Wpcom::BASE_FILE ),
178            array(),
179            file_exists( $css_path ) ? filemtime( $css_path ) : null
180        );
181    }
182
183    return $asset_handle;
184}
185
186/**
187 * Returns the WP.com blog ID for the current site.
188 *
189 * @return int|false The WP.com blog ID, or false if the site does not have a WP.com blog ID.
190 */
191function get_wpcom_blog_id() {
192    if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
193        return get_current_blog_id();
194    }
195
196    if ( defined( 'IS_ATOMIC' ) && IS_ATOMIC ) {
197        /*
198         * Atomic sites have the WP.com blog ID stored as a Jetpack option. This
199         * code deliberately doesn't use `Jetpack_Options::get_option` so it
200         * works even when Jetpack has not been loaded.
201         */
202        $jetpack_options = get_option( 'jetpack_options' );
203        if ( is_array( $jetpack_options ) && isset( $jetpack_options['id'] ) ) {
204            return (int) $jetpack_options['id'];
205        }
206
207        return get_current_blog_id();
208    }
209
210    return false;
211}
212
213/**
214 * Check if the site is a WordPress.com Atomic site.
215 *
216 * @return bool
217 */
218function is_woa_site() {
219    if ( ! class_exists( 'Automattic\Jetpack\Status\Host' ) ) {
220        return false;
221    }
222    $host = new Automattic\Jetpack\Status\Host();
223    return $host->is_woa_site();
224}
225
226/**
227 * Whether the current user is connected to WordPress.com.
228 *
229 * @param int $user_id the user identifier. Default is the current user.
230 * @return bool Boolean is the user connected?
231 */
232function is_user_connected( $user_id ) {
233    if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
234        return true;
235    }
236
237    return ( new Connection_Manager( 'jetpack' ) )->is_user_connected( $user_id );
238}
239
240/**
241 * Wrapper to test a blog sticker on both Simple and Atomic sites at once.
242 *
243 * @param string $blog_sticker The blog sticker.
244 * @param int    $blog_id The WPCOM blog ID.
245 * @return bool Whether the site has the blog sticker.
246 */
247function wpcom_has_blog_sticker( $blog_sticker, $blog_id ) {
248    if ( function_exists( 'has_blog_sticker' ) && has_blog_sticker( $blog_sticker, $blog_id ) ) {
249        return true;
250    }
251    if ( function_exists( 'wpcomsh_is_site_sticker_active' ) && wpcomsh_is_site_sticker_active( $blog_sticker ) ) {
252        return true;
253    }
254    return false;
255}