Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
9.91% covered (danger)
9.91%
11 / 111
16.67% covered (danger)
16.67%
1 / 6
CRAP
n/a
0 / 0
wpcom_should_show_launch_button
19.05% covered (danger)
19.05%
4 / 21
0.00% covered (danger)
0.00%
0 / 1
134.36
wpcom_get_launch_button_back_to
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
4
wpcom_add_launch_button_to_admin_bar
8.33% covered (danger)
8.33%
2 / 24
0.00% covered (danger)
0.00%
0 / 1
5.08
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 * The URL of the screen the launch button was rendered on.
63 *
64 * Sent as `back_to`, so the launch flow's Back button returns to that screen. Calypso only honours it
65 * when its host is the launched site's own.
66 *
67 * @return string
68 */
69function wpcom_get_launch_button_back_to(): string {
70    $host        = isset( $_SERVER['HTTP_HOST'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_HOST'] ) ) : '';
71    $request_uri = isset( $_SERVER['REQUEST_URI'] ) ? esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '/';
72
73    if ( '' === $host ) {
74        return admin_url();
75    }
76
77    return set_url_scheme( 'http://' . $host . $request_uri, 'https' );
78}
79
80/**
81 * Adds a "launch site" button to the admin bar.
82 *
83 * @param WP_Admin_Bar $admin_bar The WordPress admin bar.
84 */
85function wpcom_add_launch_button_to_admin_bar( WP_Admin_Bar $admin_bar ) {
86    if ( ! wpcom_should_show_launch_button() ) {
87        return;
88    }
89
90    $icon = '<svg viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
91        <path
92            fill-rule="evenodd"
93            clip-rule="evenodd"
94            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"
95        />
96        <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" />
97    </svg>';
98
99    $blog_domain = wp_parse_url( home_url(), PHP_URL_HOST );
100    $admin_bar->add_menu(
101        array(
102            'id'     => 'launch-site',
103            'parent' => null,
104            'group'  => null,
105            'title'  => '<span class="ab-icon">' . $icon . '</span><span class="ab-label">' . __( 'Launch site', 'jetpack-mu-wpcom' ) . '</span>',
106            'href'   => add_query_arg(
107                array(
108                    'siteSlug' => $blog_domain,
109                    'ref'      => 'wp-admin',
110                    'back_to'  => rawurlencode( wpcom_get_launch_button_back_to() ),
111                ),
112                'https://wordpress.com/start/launch-site'
113            ),
114            'meta'   => array(
115                // Use `admin-color-modern` to keep the button always in blueberry (modern scheme).
116                'class' => 'launch-site admin-color-modern',
117            ),
118        )
119    );
120}
121
122/**
123 * Enqueue wp-components styles and the celebration modal bundle CSS.
124 *
125 * The celebration modal uses @wordpress/components (Modal, Button, etc.).
126 * On the frontend, wp-components CSS is not loaded automatically, so we enqueue
127 * it here together with the compiled bundle CSS that contains the modal's own styles.
128 */
129function wpcom_enqueue_components_styles() {
130    if ( ! wpcom_should_show_launch_button() ) {
131        return;
132    }
133
134    // Enqueue WordPress's built-in wp-components stylesheet.
135    // In admin contexts it may already be queued; wp_enqueue_style() is idempotent.
136    wp_enqueue_style( 'wp-components' );
137
138    // Enqueue the compiled bundle CSS (contains the celebration modal styles).
139    $css_file = is_rtl() ? 'adminbar-launch-button.rtl.css' : 'adminbar-launch-button.css';
140    $css_path = Jetpack_Mu_Wpcom::BASE_DIR . 'build/adminbar-launch-button/' . $css_file;
141
142    // Fall back to LTR file if RTL file is missing.
143    if ( ! file_exists( $css_path ) ) {
144        $css_file = 'adminbar-launch-button.css';
145        $css_path = Jetpack_Mu_Wpcom::BASE_DIR . 'build/adminbar-launch-button/' . $css_file;
146    }
147
148    if ( file_exists( $css_path ) ) {
149        wp_enqueue_style(
150            'adminbar-launch-button-bundle',
151            plugins_url( 'build/adminbar-launch-button/' . $css_file, Jetpack_Mu_Wpcom::BASE_FILE ),
152            array( 'wp-components' ),
153            filemtime( $css_path )
154        );
155    }
156}
157
158/**
159 * Enqueue the necessary assets for the admin bar button.
160 */
161function wpcom_enqueue_launch_button_assets() {
162    if ( ! wpcom_should_show_launch_button() ) {
163        return;
164    }
165
166    $version = filemtime( __DIR__ . '/style.css' );
167    wp_enqueue_style( 'launch-banner', plugins_url( 'style.css', __FILE__ ), array(), $version );
168
169    $asset_file = include Jetpack_Mu_Wpcom::BASE_DIR . 'build/adminbar-launch-button/adminbar-launch-button.asset.php';
170
171    wp_enqueue_script(
172        'adminbar-launch-button',
173        plugins_url( 'build/adminbar-launch-button/adminbar-launch-button.js', Jetpack_Mu_Wpcom::BASE_FILE ),
174        $asset_file['dependencies'] ?? array(),
175        $asset_file['version'] ?? filemtime( Jetpack_Mu_Wpcom::BASE_DIR . 'build/adminbar-launch-button/adminbar-launch-button.js' ),
176        true
177    );
178
179    // Load the translations to avoid wp.i18n overwriting server-side translations
180    // with English strings, and in general make it possible to use translations
181    // in JS.
182    wp_set_script_translations( 'adminbar-launch-button', 'jetpack-mu-wpcom' );
183
184    $bundles      = function_exists( 'wpcom_get_site_purchases' ) ? wp_list_filter( wpcom_get_site_purchases(), array( 'product_type' => 'bundle' ) ) : array();
185    $current_plan = array_pop( $bundles );
186
187    $launch_button_data = wp_json_encode(
188        array(
189            'blogId'          => get_current_blog_id(),
190            'siteUrl'         => home_url(),
191            'siteName'        => get_bloginfo( 'name' ),
192            'siteDomain'      => wp_parse_url( home_url(), PHP_URL_HOST ),
193            'sitePlan'        => $current_plan,
194            'hasCustomDomain' => function_exists( 'wpcom_site_has_feature' ) && wpcom_site_has_feature( 'custom-domain' ),
195            'isTrial'         => function_exists( 'wpcom_site_has_feature' ) && wpcom_site_has_feature( 'trial' ),
196        ),
197        JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP
198    );
199
200    wp_add_inline_script(
201        'adminbar-launch-button',
202        "var JETPACK_LAUNCH_BUTTON_DATA = $launch_button_data;",
203        'before'
204    );
205
206    Common\wpcom_enqueue_tracking_scripts( 'adminbar-launch-button' );
207}
208
209/**
210 * Enqueue a wp-admin only script that flags the launch button as being in wp-admin.
211 *
212 * This is used to determine whether to reload the page when the celebration modal is closed.
213 */
214function wpcom_enqueue_admin_launch_button_assets() {
215    if ( ! wpcom_should_show_launch_button() ) {
216        return;
217    }
218
219    wp_add_inline_script(
220        'adminbar-launch-button',
221        'var JETPACK_LAUNCH_BUTTON_DATA_ADMIN = true;',
222        'before'
223    );
224}
225
226add_action( 'admin_bar_menu', 'wpcom_add_launch_button_to_admin_bar', 500 );
227add_action( 'wp_enqueue_scripts', 'wpcom_enqueue_components_styles' );
228add_action( 'wp_enqueue_scripts', 'wpcom_enqueue_launch_button_assets' );
229add_action( 'admin_enqueue_scripts', 'wpcom_enqueue_components_styles' );
230add_action( 'admin_enqueue_scripts', 'wpcom_enqueue_launch_button_assets' );
231add_action( 'admin_enqueue_scripts', 'wpcom_enqueue_admin_launch_button_assets' );