Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 105
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 / 23
0.00% covered (danger)
0.00%
0 / 1
6
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    $blog_domain = wp_parse_url( home_url(), PHP_URL_HOST );
81    $admin_bar->add_menu(
82        array(
83            'id'     => 'menu-id',
84            'parent' => null,
85            'group'  => null,
86            'title'  => '<span class="ab-icon">' . $icon . '</span><span class="ab-label">' . __( 'Launch site', 'jetpack-mu-wpcom' ) . '</span>',
87            'href'   => add_query_arg(
88                array(
89                    'siteSlug' => $blog_domain,
90                    'ref'      => 'wp-admin',
91                ),
92                'https://wordpress.com/start/launch-site'
93            ),
94            'meta'   => array(
95                // Use `admin-color-modern` to keep the button always in blueberry (modern scheme).
96                'class' => 'launch-site admin-color-modern',
97            ),
98        )
99    );
100}
101
102/**
103 * Enqueue wp-components styles and the celebration modal bundle CSS.
104 *
105 * The celebration modal uses @wordpress/components (Modal, Button, etc.).
106 * On the frontend, wp-components CSS is not loaded automatically, so we enqueue
107 * it here together with the compiled bundle CSS that contains the modal's own styles.
108 */
109function wpcom_enqueue_components_styles() {
110    if ( ! wpcom_should_show_launch_button() ) {
111        return;
112    }
113
114    // Enqueue WordPress's built-in wp-components stylesheet.
115    // In admin contexts it may already be queued; wp_enqueue_style() is idempotent.
116    wp_enqueue_style( 'wp-components' );
117
118    // Enqueue the compiled bundle CSS (contains the celebration modal styles).
119    $css_file = is_rtl() ? 'adminbar-launch-button.rtl.css' : 'adminbar-launch-button.css';
120    $css_path = Jetpack_Mu_Wpcom::BASE_DIR . 'build/adminbar-launch-button/' . $css_file;
121
122    // Fall back to LTR file if RTL file is missing.
123    if ( ! file_exists( $css_path ) ) {
124        $css_file = 'adminbar-launch-button.css';
125        $css_path = Jetpack_Mu_Wpcom::BASE_DIR . 'build/adminbar-launch-button/' . $css_file;
126    }
127
128    if ( file_exists( $css_path ) ) {
129        wp_enqueue_style(
130            'adminbar-launch-button-bundle',
131            plugins_url( 'build/adminbar-launch-button/' . $css_file, Jetpack_Mu_Wpcom::BASE_FILE ),
132            array( 'wp-components' ),
133            filemtime( $css_path )
134        );
135    }
136}
137
138/**
139 * Enqueue the necessary assets for the admin bar button.
140 */
141function wpcom_enqueue_launch_button_assets() {
142    if ( ! wpcom_should_show_launch_button() ) {
143        return;
144    }
145
146    $version = filemtime( __DIR__ . '/style.css' );
147    wp_enqueue_style( 'launch-banner', plugins_url( 'style.css', __FILE__ ), array(), $version );
148
149    $asset_file = include Jetpack_Mu_Wpcom::BASE_DIR . 'build/adminbar-launch-button/adminbar-launch-button.asset.php';
150
151    wp_enqueue_script(
152        'adminbar-launch-button',
153        plugins_url( 'build/adminbar-launch-button/adminbar-launch-button.js', Jetpack_Mu_Wpcom::BASE_FILE ),
154        $asset_file['dependencies'] ?? array(),
155        $asset_file['version'] ?? filemtime( Jetpack_Mu_Wpcom::BASE_DIR . 'build/adminbar-launch-button/adminbar-launch-button.js' ),
156        true
157    );
158
159    // Load the translations to avoid wp.i18n overwriting server-side translations
160    // with English strings, and in general make it possible to use translations
161    // in JS.
162    wp_set_script_translations( 'adminbar-launch-button', 'jetpack-mu-wpcom' );
163
164    $bundles      = function_exists( 'wpcom_get_site_purchases' ) ? wp_list_filter( wpcom_get_site_purchases(), array( 'product_type' => 'bundle' ) ) : array();
165    $current_plan = array_pop( $bundles );
166
167    $launch_button_data = wp_json_encode(
168        array(
169            'blogId'          => get_current_blog_id(),
170            'siteUrl'         => home_url(),
171            'siteName'        => get_bloginfo( 'name' ),
172            'siteDomain'      => wp_parse_url( home_url(), PHP_URL_HOST ),
173            'sitePlan'        => $current_plan,
174            'hasCustomDomain' => function_exists( 'wpcom_site_has_feature' ) && wpcom_site_has_feature( 'custom-domain' ),
175            'isTrial'         => function_exists( 'wpcom_site_has_feature' ) && wpcom_site_has_feature( 'trial' ),
176        ),
177        JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP
178    );
179
180    wp_add_inline_script(
181        'adminbar-launch-button',
182        "var JETPACK_LAUNCH_BUTTON_DATA = $launch_button_data;",
183        'before'
184    );
185
186    Common\wpcom_enqueue_tracking_scripts( 'adminbar-launch-button' );
187}
188
189/**
190 * Enqueue a wp-admin only script that flags the launch button as being in wp-admin.
191 *
192 * This is used to determine whether to reload the page when the celebration modal is closed.
193 */
194function wpcom_enqueue_admin_launch_button_assets() {
195    if ( ! wpcom_should_show_launch_button() ) {
196        return;
197    }
198
199    wp_add_inline_script(
200        'adminbar-launch-button',
201        'var JETPACK_LAUNCH_BUTTON_DATA_ADMIN = true;',
202        'before'
203    );
204}
205
206add_action( 'admin_bar_menu', 'wpcom_add_launch_button_to_admin_bar', 500 );
207add_action( 'wp_enqueue_scripts', 'wpcom_enqueue_components_styles' );
208add_action( 'wp_enqueue_scripts', 'wpcom_enqueue_launch_button_assets' );
209add_action( 'admin_enqueue_scripts', 'wpcom_enqueue_components_styles' );
210add_action( 'admin_enqueue_scripts', 'wpcom_enqueue_launch_button_assets' );
211add_action( 'admin_enqueue_scripts', 'wpcom_enqueue_admin_launch_button_assets' );