Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 98
0.00% covered (danger)
0.00%
0 / 5
CRAP
n/a
0 / 0
wpcom_should_show_launch_button
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
240
wpcom_add_launch_button_to_admin_bar
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
20
wpcom_enqueue_components_styles
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
30
wpcom_enqueue_launch_button_assets
0.00% covered (danger)
0.00%
0 / 33
0.00% covered (danger)
0.00%
0 / 1
30
wpcom_enqueue_admin_launch_button_assets
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2/**
3 * Adds a "launch site" button to the admin bar.
4 *
5 * @package automattic/jetpack-mu-wpcom
6 */
7
8use Automattic\Jetpack\Jetpack_Mu_Wpcom;
9use Automattic\Jetpack\Jetpack_Mu_Wpcom\Common;
10
11/**
12 * Determine whether the launch button should be shown/enhanced on this request.
13 *
14 * @return bool
15 */
16function wpcom_should_show_launch_button(): bool {
17    $current_blog_id = get_current_blog_id();
18
19    if ( function_exists( 'is_graylisted' ) && is_graylisted( $current_blog_id ) ) {
20        return false;
21    }
22
23    if ( ! is_user_logged_in() ) {
24        return false;
25    }
26
27    if ( ! is_user_member_of_blog( get_current_user_id(), $current_blog_id ) ) {
28        return false;
29    }
30
31    if ( ! current_user_can( 'manage_options' ) ) {
32        return false;
33    }
34
35    if ( function_exists( 'has_blog_sticker' ) && has_blog_sticker( 'difm-lite-in-progress' ) ) {
36        return false;
37    }
38
39    // No button for agency-managed sites.
40    if ( ! empty( get_option( 'is_fully_managed_agency_site' ) ) ) {
41        return false;
42    }
43
44    if ( get_option( 'launch-status' ) !== 'unlaunched' ) {
45        return false;
46    }
47
48    if ( $current_blog_id === 1 && defined( 'IS_WPCOM' ) && IS_WPCOM ) {
49        return false;
50    }
51
52    // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is a context check, not a form submission.
53    $is_preview = isset( $_GET['preview'] ) && 'true' === sanitize_text_field( wp_unslash( $_GET['preview'] ) );
54    if ( $is_preview ) {
55        return false;
56    }
57
58    return true;
59}
60
61/**
62 * Adds a "launch site" button to the admin bar.
63 *
64 * @param WP_Admin_Bar $admin_bar The WordPress admin bar.
65 */
66function wpcom_add_launch_button_to_admin_bar( WP_Admin_Bar $admin_bar ) {
67    if ( ! wpcom_should_show_launch_button() ) {
68        return;
69    }
70
71    $icon = '<svg viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
72        <path
73            fill-rule="evenodd"
74            clip-rule="evenodd"
75            d="M10.6242 9.74354L7.62419 12.1261V13.2995C7.62419 13.4418 7.77653 13.5322 7.90147 13.4641L10.5265 12.0322C10.5867 11.9994 10.6242 11.9363 10.6242 11.8676V9.74354ZM6.49919 12.0875L3.91203 9.50037H2.7001C1.70383 9.50037 1.07079 8.43399 1.54786 7.55937L2.97968 4.93437C3.20967 4.51272 3.65161 4.25036 4.13191 4.25036H7.17569C9.1325 2.16798 11.3176 0.754637 14.1427 0.531305C14.9004 0.471402 15.5282 1.09911 15.4682 1.85687C15.2449 4.68199 13.8316 6.86706 11.7492 8.82386V11.8676C11.7492 12.3479 11.4868 12.7899 11.0652 13.0199L8.44018 14.4517C7.56557 14.9288 6.49919 14.2957 6.49919 13.2995V12.0875ZM6.25602 5.37536H4.13191C4.0633 5.37536 4.00017 5.41284 3.96731 5.47308L2.53549 8.09808C2.46734 8.22303 2.55777 8.37536 2.7001 8.37536H3.87344L6.25602 5.37536Z"
76        />
77        <path d="M0.498047 13.3962C0.498047 12.2341 1.44011 11.2921 2.60221 11.2921C3.76431 11.2921 4.70638 12.2341 4.70638 13.3962C4.70638 14.5583 3.76431 15.5004 2.60221 15.5004H1.06055C0.749887 15.5004 0.498047 15.2486 0.498047 14.9379V13.3962Z" />
78    </svg>';
79
80    $admin_bar->add_menu(
81        array(
82            'id'     => 'launch-site',
83            'parent' => null,
84            'group'  => null,
85            'title'  => '<span class="ab-icon">' . $icon . '</span><span class="ab-label">' . __( 'Launch site', 'jetpack-mu-wpcom' ) . '</span>',
86            // The JS button reuses this href, refreshing only its `back_to`.
87            // The Omnibar fetches this node over REST, where the request URL is no page to go back to.
88            'href'   => Common\wpcom_get_launch_site_url( defined( 'REST_REQUEST' ) && REST_REQUEST ? array() : array( 'back_to' => Common\wpcom_get_launch_site_back_to() ) ),
89            'meta'   => array(
90                // Use `admin-color-modern` to keep the button always in blueberry (modern scheme).
91                'class' => 'launch-site admin-color-modern',
92            ),
93        )
94    );
95}
96
97/**
98 * Enqueue wp-components styles and the celebration modal bundle CSS.
99 *
100 * The celebration modal uses @wordpress/components (Modal, Button, etc.).
101 * On the frontend, wp-components CSS is not loaded automatically, so we enqueue
102 * it here together with the compiled bundle CSS that contains the modal's own styles.
103 */
104function wpcom_enqueue_components_styles() {
105    if ( ! wpcom_should_show_launch_button() ) {
106        return;
107    }
108
109    // Enqueue WordPress's built-in wp-components stylesheet.
110    // In admin contexts it may already be queued; wp_enqueue_style() is idempotent.
111    wp_enqueue_style( 'wp-components' );
112
113    // Enqueue the compiled bundle CSS (contains the celebration modal styles).
114    $css_file = is_rtl() ? 'adminbar-launch-button.rtl.css' : 'adminbar-launch-button.css';
115    $css_path = Jetpack_Mu_Wpcom::BASE_DIR . 'build/adminbar-launch-button/' . $css_file;
116
117    // Fall back to LTR file if RTL file is missing.
118    if ( ! file_exists( $css_path ) ) {
119        $css_file = 'adminbar-launch-button.css';
120        $css_path = Jetpack_Mu_Wpcom::BASE_DIR . 'build/adminbar-launch-button/' . $css_file;
121    }
122
123    if ( file_exists( $css_path ) ) {
124        wp_enqueue_style(
125            'adminbar-launch-button-bundle',
126            plugins_url( 'build/adminbar-launch-button/' . $css_file, Jetpack_Mu_Wpcom::BASE_FILE ),
127            array( 'wp-components' ),
128            filemtime( $css_path )
129        );
130    }
131}
132
133/**
134 * Enqueue the necessary assets for the admin bar button.
135 */
136function wpcom_enqueue_launch_button_assets() {
137    if ( ! wpcom_should_show_launch_button() ) {
138        return;
139    }
140
141    $version = filemtime( __DIR__ . '/style.css' );
142    wp_enqueue_style( 'launch-banner', plugins_url( 'style.css', __FILE__ ), array(), $version );
143
144    $asset_file = include Jetpack_Mu_Wpcom::BASE_DIR . 'build/adminbar-launch-button/adminbar-launch-button.asset.php';
145
146    wp_enqueue_script(
147        'adminbar-launch-button',
148        plugins_url( 'build/adminbar-launch-button/adminbar-launch-button.js', Jetpack_Mu_Wpcom::BASE_FILE ),
149        $asset_file['dependencies'] ?? array(),
150        $asset_file['version'] ?? filemtime( Jetpack_Mu_Wpcom::BASE_DIR . 'build/adminbar-launch-button/adminbar-launch-button.js' ),
151        true
152    );
153
154    // Load the translations to avoid wp.i18n overwriting server-side translations
155    // with English strings, and in general make it possible to use translations
156    // in JS.
157    wp_set_script_translations( 'adminbar-launch-button', 'jetpack-mu-wpcom' );
158
159    $bundles      = function_exists( 'wpcom_get_site_purchases' ) ? wp_list_filter( wpcom_get_site_purchases(), array( 'product_type' => 'bundle' ) ) : array();
160    $current_plan = array_pop( $bundles );
161
162    $launch_button_data = wp_json_encode(
163        array(
164            'blogId'          => get_current_blog_id(),
165            'siteUrl'         => home_url(),
166            'siteName'        => get_bloginfo( 'name' ),
167            'siteDomain'      => wp_parse_url( home_url(), PHP_URL_HOST ),
168            'sitePlan'        => $current_plan,
169            'hasCustomDomain' => function_exists( 'wpcom_site_has_feature' ) && wpcom_site_has_feature( 'custom-domain' ),
170            'isTrial'         => function_exists( 'wpcom_site_has_feature' ) && wpcom_site_has_feature( 'trial' ),
171        ),
172        JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP
173    );
174
175    wp_add_inline_script(
176        'adminbar-launch-button',
177        "var JETPACK_LAUNCH_BUTTON_DATA = $launch_button_data;",
178        'before'
179    );
180
181    Common\wpcom_enqueue_tracking_scripts( 'adminbar-launch-button' );
182}
183
184/**
185 * Enqueue a wp-admin only script that flags the launch button as being in wp-admin.
186 *
187 * This is used to determine whether to reload the page when the celebration modal is closed.
188 */
189function wpcom_enqueue_admin_launch_button_assets() {
190    if ( ! wpcom_should_show_launch_button() ) {
191        return;
192    }
193
194    wp_add_inline_script(
195        'adminbar-launch-button',
196        'var JETPACK_LAUNCH_BUTTON_DATA_ADMIN = true;',
197        'before'
198    );
199}
200
201add_action( 'admin_bar_menu', 'wpcom_add_launch_button_to_admin_bar', 500 );
202add_action( 'wp_enqueue_scripts', 'wpcom_enqueue_components_styles' );
203add_action( 'wp_enqueue_scripts', 'wpcom_enqueue_launch_button_assets' );
204add_action( 'admin_enqueue_scripts', 'wpcom_enqueue_components_styles' );
205add_action( 'admin_enqueue_scripts', 'wpcom_enqueue_launch_button_assets' );
206add_action( 'admin_enqueue_scripts', 'wpcom_enqueue_admin_launch_button_assets' );