Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
46.57% covered (danger)
46.57%
156 / 335
25.00% covered (danger)
25.00%
3 / 12
CRAP
n/a
0 / 0
wpcom_enqueue_admin_bar_assets
0.00% covered (danger)
0.00%
0 / 46
0.00% covered (danger)
0.00%
0 / 1
30
wpcom_always_use_user_locale
33.33% covered (danger)
33.33%
4 / 12
0.00% covered (danger)
0.00%
0 / 1
8.74
wpcom_replace_wp_logo_with_wpcom_logo_menu
100.00% covered (success)
100.00%
66 / 66
100.00% covered (success)
100.00%
1 / 1
8
wpcom_add_shopping_cart
6.67% covered (danger)
6.67%
2 / 30
0.00% covered (danger)
0.00%
0 / 1
25.33
wpcom_replace_edit_profile_menu_to_me
70.00% covered (warning)
70.00%
7 / 10
0.00% covered (danger)
0.00%
0 / 1
4.43
wpcom_add_my_wpcom_account_submenu
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
1
wpcom_custom_wpcom_admin_bar_class
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
wpcom_edit_site_menu_override
16.67% covered (danger)
16.67%
1 / 6
0.00% covered (danger)
0.00%
0 / 1
4.31
wpcom_add_site_badges_and_plan
57.14% covered (warning)
57.14%
44 / 77
0.00% covered (danger)
0.00%
0 / 1
69.34
wpcom_add_stats_to_site_menu
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
5
wpcom_admin_bar_upsell_get_source
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
30
wpcom_add_free_domain_upsell
8.33% covered (danger)
8.33%
2 / 24
0.00% covered (danger)
0.00%
0 / 1
5.08
1<?php
2/**
3 * WordPress.com admin bar
4 *
5 * Modifies the WordPress admin bar with WordPress.com-specific stuff.
6 *
7 * @package automattic/jetpack-mu-wpcom
8 */
9
10use Automattic\Jetpack\Current_Plan;
11use Automattic\Jetpack\Jetpack_Mu_Wpcom;
12use Automattic\Jetpack\Jetpack_Mu_Wpcom\Free_Domain_Upsell_Experiment;
13use Automattic\Jetpack\Modules;
14use Automattic\Jetpack\Status;
15
16// The $icon-color variable for admin color schemes.
17// See: https://github.com/WordPress/wordpress-develop/blob/679cc0c4a261a77bd8fdb140cd9b0b2ff80ebf37/src/wp-admin/css/colors/_variables.scss#L9
18// Only Core schemes are listed here. Calypso schemes all use #ffffff.
19const WPCOM_ADMIN_ICON_COLORS = array(
20    'blue'      => '#e5f8ff',
21    'coffee'    => '#f3f2f1',
22    'ectoplasm' => '#ece6f6',
23    'midnight'  => '#f3f2f1',
24    'fresh'     => '#a7aaad',
25    'ocean'     => '#f2fcff',
26    'light'     => '#999',
27    'modern'    => '#f3f1f1',
28    'sunrise'   => '#f3f1f1',
29);
30
31/**
32 * Enqueue assets needed by the WordPress.com admin bar.
33 */
34function wpcom_enqueue_admin_bar_assets() {
35    $asset_file = include Jetpack_Mu_Wpcom::BASE_DIR . 'build/wpcom-admin-bar/wpcom-admin-bar.asset.php';
36
37    wp_enqueue_script(
38        'wpcom-admin-bar',
39        plugins_url( 'build/wpcom-admin-bar/wpcom-admin-bar.js', Jetpack_Mu_Wpcom::BASE_FILE ),
40        $asset_file['dependencies'] ?? array(),
41        $asset_file['version'] ?? filemtime( Jetpack_Mu_Wpcom::BASE_DIR . 'build/wpcom-admin-bar/wpcom-admin-bar.js' ),
42        array(
43            'strategy'  => 'defer',
44            'in_footer' => true,
45        )
46    );
47
48    wp_enqueue_style(
49        'wpcom-admin-bar',
50        plugins_url( 'build/wpcom-admin-bar/wpcom-admin-bar.css', Jetpack_Mu_Wpcom::BASE_FILE ),
51        array(),
52        $asset_file['version'] ?? filemtime( Jetpack_Mu_Wpcom::BASE_DIR . 'build/wpcom-admin-bar/wpcom-admin-bar.css' )
53    );
54
55    if ( Free_Domain_Upsell_Experiment::should_show_upsell() ) {
56        wp_add_inline_script(
57            'wpcom-admin-bar',
58            'var wpcomAdminBarUpsellSource = ' . wp_json_encode( wpcom_admin_bar_upsell_get_source(), JSON_HEX_TAG | JSON_HEX_AMP ) . ';'
59            . 'var wpcomAdminBarFreeDomainUpsellSource = ' . wp_json_encode( Free_Domain_Upsell_Experiment::get_upsell_source(), JSON_HEX_TAG | JSON_HEX_AMP ) . ';',
60            'before'
61        );
62    }
63
64    /**
65     * Force the Atomic debug bar menu to be the first menu at the top-right.
66     */
67    if ( defined( 'AT_PROXIED_REQUEST' ) && AT_PROXIED_REQUEST ) {
68        wp_add_inline_style(
69            'wpcom-admin-bar',
70            <<<'CSS'
71                #wpadminbar .quicklinks #wp-admin-bar-top-secondary {
72                    display: flex;
73                }
74
75                #wpadminbar .quicklinks #wp-admin-bar-top-secondary #wp-admin-bar-debug-bar {
76                    order: -1;
77                }
78CSS
79        );
80    }
81
82    $admin_color      = is_admin() ? get_user_option( 'admin_color' ) : 'fresh';
83    $admin_icon_color = WPCOM_ADMIN_ICON_COLORS[ $admin_color ] ?? '#ffffff';
84
85    // Force the icon colors to have desktop color even on mobile viewport.
86    wp_add_inline_style(
87        'wpcom-admin-bar',
88        <<<CSS
89            #wpadminbar.mobile .quicklinks li:not(#wpwrap.wp-responsive-open #wp-admin-bar-menu-toggle) .ab-icon::before,
90            #wpadminbar.mobile .quicklinks li:not(#wpwrap.wp-responsive-open #wp-admin-bar-menu-toggle) .ab-item::before {
91                color: $admin_icon_color !important;
92            }
93CSS
94    );
95
96    // Force wpcom icons to have consistent color.
97    wp_add_inline_style(
98        'wpcom-admin-bar',
99        <<<CSS
100            :where(#wpadminbar .ab-icon) {
101                color: $admin_icon_color;
102            }
103CSS
104    );
105}
106add_action( 'wp_enqueue_scripts', 'wpcom_enqueue_admin_bar_assets' );
107add_action( 'admin_enqueue_scripts', 'wpcom_enqueue_admin_bar_assets' );
108
109/**
110 * Render the admin bar in user locale even on frontend screens.
111 */
112function wpcom_always_use_user_locale() {
113    if ( is_admin() || ! is_admin_bar_showing() ) {
114        return;
115    }
116
117    $site_locale = get_locale();
118    $user_locale = get_user_locale();
119
120    if ( $site_locale !== $user_locale ) {
121        switch_to_locale( $user_locale );
122        add_action(
123            'wp_after_admin_bar_render',
124            function () use ( $site_locale ) {
125                switch_to_locale( $site_locale );
126            }
127        );
128    }
129}
130add_action( 'admin_bar_menu', 'wpcom_always_use_user_locale', -1 );
131
132/**
133 * Replaces the WP logo with WP.com logo.
134 *
135 * @param WP_Admin_Bar $wp_admin_bar The WP_Admin_Bar core object.
136 */
137function wpcom_replace_wp_logo_with_wpcom_logo_menu( $wp_admin_bar ) {
138    $about_node      = $wp_admin_bar->get_node( 'about' );
139    $contribute_node = $wp_admin_bar->get_node( 'contribute' );
140
141    foreach ( $wp_admin_bar->get_nodes() as $node ) {
142        if ( $node->parent === 'wp-logo' || $node->parent === 'wp-logo-external' ) {
143            $wp_admin_bar->remove_node( $node->id );
144        }
145    }
146    $wp_admin_bar->remove_node( 'wp-logo' );
147    $wp_admin_bar->add_node(
148        array(
149            'id'    => 'wp-logo',
150            'title' => '<span class="ab-icon" aria-hidden="true"></span><span class="screen-reader-text">' .
151                        /* translators: Hidden accessibility text. */
152                        'WordPress.com' .
153                        '</span>',
154            'href'  => 'https://my.wordpress.com/sites',
155            'meta'  => array(
156                'menu_title' => 'WordPress.com',
157            ),
158        )
159    );
160
161    $wp_admin_bar->add_node(
162        array(
163            'parent' => 'wp-logo',
164            'id'     => 'wpcom-sites',
165            'title'  => __( 'Sites', 'jetpack-mu-wpcom' ),
166            'href'   => 'https://my.wordpress.com/sites',
167        )
168    );
169
170    $wp_admin_bar->add_node(
171        array(
172            'parent' => 'wp-logo',
173            'id'     => 'wpcom-domains',
174            'title'  => __( 'Domains', 'jetpack-mu-wpcom' ),
175            'href'   => 'https://my.wordpress.com/domains',
176        )
177    );
178
179    $wp_admin_bar->add_node(
180        array(
181            'parent' => 'wp-logo',
182            'id'     => 'wpcom-emails',
183            'title'  => __( 'Emails', 'jetpack-mu-wpcom' ),
184            'href'   => 'https://my.wordpress.com/emails',
185        )
186    );
187
188    $wp_admin_bar->add_node(
189        array(
190            'parent' => 'wp-logo',
191            'id'     => 'wpcom-plugins',
192            'title'  => __( 'Plugins', 'jetpack-mu-wpcom' ),
193            'href'   => 'https://my.wordpress.com/plugins',
194        )
195    );
196
197    if ( ! ( defined( 'IS_WPCOM' ) && IS_WPCOM ) ) {
198        $wp_admin_bar->add_group(
199            array(
200                'parent' => 'wp-logo',
201                'id'     => 'wp-logo-external',
202                'meta'   => array(
203                    'class' => 'ab-sub-secondary',
204                ),
205            )
206        );
207
208        if ( $about_node ) {
209            $about_node->parent = 'wp-logo-external';
210            $wp_admin_bar->add_node( (array) $about_node );
211        }
212        if ( $contribute_node ) {
213            $contribute_node->parent = 'wp-logo-external';
214            $wp_admin_bar->add_node( (array) $contribute_node );
215        }
216    }
217}
218add_action( 'admin_bar_menu', 'wpcom_replace_wp_logo_with_wpcom_logo_menu', 11 );
219
220/**
221 * Adds the Cart menu to the WordPress admin bar.
222 *
223 * @param WP_Admin_Bar $wp_admin_bar The WP_Admin_Bar core object.
224 */
225function wpcom_add_shopping_cart( $wp_admin_bar ) {
226    // Return if the site isn't a simple site
227    if ( ! defined( 'IS_WPCOM' ) || ! IS_WPCOM ) {
228        return;
229    }
230
231    // Include the shopping cart functionality from the specified path.
232    require_once WP_CONTENT_DIR . '/admin-plugins/wpcom-billing/shopping-cart.php';
233
234    // Get the current blog ID.
235    $blog_id = get_current_blog_id();
236
237    $is_empty = \Store_Shopping_Cart::is_cart_empty(
238        array(
239            'blog_id' => $blog_id,
240            'user_id' => get_current_user_id(),
241        )
242    );
243
244    // If the cart is empty (no products), do not add the cart menu.
245    if ( $is_empty ) {
246        return;
247    }
248
249    // Get the Calypso site slug for the current blog.
250    $calypso_site_slug = \WPCOM_Masterbar::get_calypso_site_slug( $blog_id );
251
252    // If no Calypso site slug is found, return early.
253    if ( ! $calypso_site_slug ) {
254        return;
255    }
256
257    // Add the cart menu item to the WordPress admin bar.
258    $wp_admin_bar->add_menu(
259        array(
260            'id'     => 'cart', // Unique ID for the cart menu item.
261            'title'  => '<span class="ab-item cart-icon" aria-hidden="true"></span>' .
262                        '<div class="cart-icon__dot"></div>' .
263                        '<span class="screen-reader-text">' .
264                        /* translators: Hidden accessibility text. */
265                        __( 'Cart', 'jetpack-mu-wpcom' ) .
266                        '</span>',
267            'href'   => 'https://wordpress.com/checkout/' . esc_attr( $calypso_site_slug ), // Link to the checkout page.
268            'meta'   => array(
269                'class' => 'wp-admin-bar-cart', // Custom class for styling the cart menu item.
270            ),
271            'parent' => 'top-secondary', // Position the cart in the 'top-secondary' section of the admin bar.
272        )
273    );
274}
275
276// Hook the cart icon to the admin bar menu, placing it before the reader icon (same as Calypso).
277add_action( 'admin_bar_menu', 'wpcom_add_shopping_cart', 11 );
278
279// Add the reader icon to the admin bar before the help center icon.
280add_action(
281    'wp_loaded',
282    function () {
283        if ( class_exists( '\Automattic\Jetpack\Newsletter\Reader_Link' ) ) {
284            // @phan-suppress-next-line PhanUndeclaredClassMethod -- class_exists guarded above; provided by sibling autoloader.
285            \Automattic\Jetpack\Newsletter\Reader_Link::init();
286        }
287    }
288);
289
290/**
291 * Points the "Edit Profile" and "Howdy,..." to /me if the user is not member of the blog.
292 *
293 * @param WP_Admin_Bar $wp_admin_bar The WP_Admin_Bar core object.
294 */
295function wpcom_replace_edit_profile_menu_to_me( $wp_admin_bar ) {
296    if ( is_user_member_of_blog() ) {
297        return;
298    }
299
300    $edit_profile_node = $wp_admin_bar->get_node( 'user-info' );
301    if ( $edit_profile_node ) {
302        $edit_profile_node->href = 'https://my.wordpress.com/me/account';
303        $wp_admin_bar->add_node( (array) $edit_profile_node );
304    }
305    $my_account_node = $wp_admin_bar->get_node( 'my-account' );
306    if ( $my_account_node ) {
307        $my_account_node->href = 'https://my.wordpress.com/me/account';
308        $wp_admin_bar->add_node( (array) $my_account_node );
309    }
310}
311// Run this function later than Core: https://github.com/WordPress/wordpress-develop/blob/5a30482419f1b0bcc713a7fdee3a14afd67a1bca/src/wp-includes/class-wp-admin-bar.php#L651
312add_action( 'admin_bar_menu', 'wpcom_replace_edit_profile_menu_to_me', 9999 );
313
314/**
315 * Adds "Howdy,..." -> My WP.com Account submenu pointing to /me/account.
316 *
317 * @param WP_Admin_Bar $wp_admin_bar The WP_Admin_Bar core object.
318 */
319function wpcom_add_my_wpcom_account_submenu( $wp_admin_bar ) {
320    $wp_admin_bar->add_group(
321        array(
322            'parent' => 'my-account',
323            'id'     => 'wpcom-account',
324            'meta'   => array(
325                'class' => 'ab-sub-secondary',
326            ),
327        )
328    );
329
330    /* translators: %s: WordPress.com logo */
331    $button_text = sprintf( __( 'My %s WordPress.com Account', 'jetpack-mu-wpcom' ), '<span class="wpcom-logo"></span>' );
332
333    $wp_admin_bar->add_node(
334        array(
335            'parent' => 'wpcom-account',
336            'id'     => 'my-wpcom-account',
337            'title'  => '<span class="button wpcom-button">' . $button_text . '</span>',
338            'href'   => 'https://my.wordpress.com/me/account',
339        )
340    );
341}
342add_action( 'admin_bar_menu', 'wpcom_add_my_wpcom_account_submenu' );
343
344/**
345 * Replaces the default admin bar class with our own.
346 *
347 * @param string $wp_admin_bar_class Admin bar class to use. Default 'WP_Admin_Bar'.
348 * @return string Name of the admin bar class.
349 */
350function wpcom_custom_wpcom_admin_bar_class( $wp_admin_bar_class ) {
351    remove_filter( 'pre_option_wpcom_admin_interface', 'wpcom_admin_interface_pre_get_option' );
352    $is_wp_admin = get_option( 'wpcom_admin_interface' ) === 'wp-admin';
353    add_filter( 'pre_option_wpcom_admin_interface', 'wpcom_admin_interface_pre_get_option', 10 );
354
355    if ( $is_wp_admin ) {
356        return $wp_admin_bar_class;
357    }
358
359    require_once __DIR__ . '/class-wpcom-admin-bar.php';
360    return '\Automattic\Jetpack\Jetpack_Mu_Wpcom\WPCOM_Admin_Bar';
361}
362add_filter( 'wp_admin_bar_class', 'wpcom_custom_wpcom_admin_bar_class' );
363
364/**
365 * Changes the edit site menu to point to the top-level site editor.
366 *
367 * @param WP_Admin_Bar $wp_admin_bar The WP_Admin_Bar core object.
368 */
369function wpcom_edit_site_menu_override( $wp_admin_bar ) {
370    if ( $wp_admin_bar->get_node( 'site-editor' ) ) {
371        $args = array(
372            'id'   => 'site-editor',
373            'href' => admin_url( 'site-editor.php' ),
374        );
375
376        $wp_admin_bar->add_node( $args );
377    }
378}
379add_action( 'admin_bar_menu', 'wpcom_edit_site_menu_override', 41 );
380
381/**
382 * Adds site badges and plan information to the site title dropdown menu.
383 *
384 * @param WP_Admin_Bar $wp_admin_bar The WP_Admin_Bar core object.
385 */
386function wpcom_add_site_badges_and_plan( $wp_admin_bar ) {
387    // Get the current blog ID
388    $blog_id = get_current_blog_id();
389    $status  = new Status();
390
391    // Check for various site types
392    $badge_text = '';
393
394    // Check if this is a P2 site
395    if ( str_contains( get_stylesheet(), 'pub/p2' ) ||
396        ( function_exists( '\WPForTeams\is_wpforteams_site' ) &&
397        \WPForTeams\is_wpforteams_site( $blog_id ) ) ) {
398        $badge_text = 'P2';
399    } elseif ( (bool) get_option( 'wpcom_is_staging_site' ) ) {
400        // Check for staging site
401        $badge_text = __( 'Staging', 'jetpack-mu-wpcom' );
402    } elseif ( function_exists( 'wpcom_site_has_feature' ) && wpcom_site_has_feature( 'trial' ) ) {
403        // Check for trial site
404        $badge_text = __( 'Trial', 'jetpack-mu-wpcom' );
405    } elseif ( get_option( 'launch-status' ) === 'unlaunched' || $status->is_coming_soon() ) {
406        // Check for Coming Soon site
407        $badge_text = __( 'Coming Soon', 'jetpack-mu-wpcom' );
408    } elseif ( $status->is_private_site() ) {
409        // Check for private site
410        $badge_text = __( 'Private', 'jetpack-mu-wpcom' );
411    } elseif ( ( function_exists( 'has_blog_sticker' ) && has_blog_sticker( 'difm-lite-in-progress' ) ) ||
412        ( function_exists( 'wpcomsh_is_site_sticker_active' ) && wpcomsh_is_site_sticker_active( 'difm-lite-in-progress' ) ) ) {
413        // Check for Express service
414        $badge_text = __( 'Express', 'jetpack-mu-wpcom' );
415    } elseif ( function_exists( 'is_simple_site_redirect' ) && is_simple_site_redirect( $status->get_site_suffix() ) ) {
416        // Check for Redirect site
417        $badge_text = __( 'Redirect', 'jetpack-mu-wpcom' );
418    } elseif ( ! empty( get_option( 'options' )['is_domain_only'] ) ) {
419        // Check for Domain Only site
420        $badge_text = __( 'Domain Only', 'jetpack-mu-wpcom' );
421    }
422
423    // Add badge to the site name dropdown if a badge is applicable
424    $status_text = '';
425    if ( $badge_text ) {
426        $status_text = '<div class="wp-admin-bar__site-info">
427                            <span class="wp-admin-bar__site-info-label">' . __( 'Status', 'jetpack-mu-wpcom' ) . '</span>
428                            <span class="wp-admin-bar__info-badges">' . esc_html( $badge_text ) . '</span>
429                        </div>';
430    }
431
432    // Add plan information for non-staging sites
433    $plan_text  = '';
434    $is_staging = (bool) get_option( 'wpcom_is_staging_site' );
435    if ( ! $is_staging ) {
436        if ( class_exists( '\WPCOM_Store_API' ) ) {
437            $current_plan = WPCOM_Store_API::get_current_plan( get_current_blog_id() );
438        } else {
439            $current_plan = Current_Plan::get();
440        }
441        $plan_name = $current_plan['product_name_short'] ?? '';
442
443        if ( $plan_name ) {
444            // wpcom_get_site_slug() resolves the Calypso slug on both Simple and
445            // Atomic (where \WPCOM_Masterbar is absent), falling back to the site
446            // URL so the link still renders.
447            $site_slug = wpcom_get_site_slug();
448
449            if ( $site_slug ) {
450                $plan_text = '<a class="wp-admin-bar__site-info" href="https://wordpress.com/plans/' . esc_attr( $site_slug ) . '">
451                                <span class="wp-admin-bar__site-info-label">' . __( 'Plan', 'jetpack-mu-wpcom' ) . '</span>
452                                <span class="wp-admin-bar__info-badges">' . esc_html( $plan_name ) . '</span>
453                            </a>';
454            } else {
455                $plan_text = '<div class="wp-admin-bar__site-info">
456                                <span class="wp-admin-bar__site-info-label">' . __( 'Plan', 'jetpack-mu-wpcom' ) . '</span>
457                                <span class="wp-admin-bar__info-badges">' . esc_html( $plan_name ) . '</span>
458                            </div>';
459            }
460        }
461    }
462
463    if ( $plan_text ) {
464        $wp_admin_bar->add_group(
465            array(
466                'parent' => 'site-name',
467                'id'     => 'site-plan',
468            )
469        );
470        $wp_admin_bar->add_node(
471            array(
472                'parent' => 'site-plan',
473                'id'     => 'site-plan-badge',
474                'title'  => $plan_text,
475            )
476        );
477    }
478
479    if ( $status_text ) {
480        $wp_admin_bar->add_group(
481            array(
482                'parent' => 'site-name',
483                'id'     => 'site-status',
484                'meta'   => array(
485                    'class' => 'ab-sub-secondary',
486                ),
487            )
488        );
489        $wp_admin_bar->add_node(
490            array(
491                'parent' => 'site-status',
492                'id'     => 'site-status-badge',
493                'title'  => $status_text,
494            )
495        );
496    }
497}
498add_action( 'admin_bar_menu', 'wpcom_add_site_badges_and_plan', 35 );
499
500/**
501 * Adds a "Stats" link to the site-name submenu, alongside "Dashboard"/"Visit Site" (STATS-287).
502 *
503 * Hooks `admin_bar_menu` at priority 40, after core's `wp_admin_bar_site_menu`
504 * (priority 30) has added the `site-name` node and either `dashboard` (front end)
505 * or `view-site` (wp-admin), so this shows in both contexts.
506 *
507 * `view_stats` is not a proxy for the module being on: the Stats package registers
508 * its `map_meta_cap` handler on any wp-admin request, so an administrator keeps the
509 * capability after the module is switched off, while `admin.php?page=stats` stops
510 * being registered. Linking there then renders "Sorry, you are not allowed to access
511 * this page", so check the module too. `is_active()` short-circuits to true on Simple,
512 * where the module can't be switched off; it only narrows anything on Atomic.
513 *
514 * @param WP_Admin_Bar $wp_admin_bar Admin bar instance.
515 */
516function wpcom_add_stats_to_site_menu( $wp_admin_bar ) {
517    if (
518        ( ! $wp_admin_bar->get_node( 'dashboard' ) && ! $wp_admin_bar->get_node( 'view-site' ) )
519        || ! current_user_can( 'view_stats' )
520        || ! ( new Modules() )->is_active( 'stats' )
521    ) {
522        return;
523    }
524
525    $wp_admin_bar->add_node(
526        array(
527            'parent' => 'site-name',
528            'id'     => 'wpcom-stats',
529            'title'  => __( 'Stats', 'jetpack-mu-wpcom' ),
530            /** This filter is documented in projects/packages/stats-admin/src/class-admin-bar.php */
531            'href'   => apply_filters( 'jetpack_stats_url', admin_url( 'admin.php?page=stats' ), array( 'view' => 'dashboard' ) ),
532        )
533    );
534}
535add_action( 'admin_bar_menu', 'wpcom_add_stats_to_site_menu', 40 );
536
537/**
538 * Which source the admin bar upsell is rendering on, for tracking.
539 *
540 * @return string One of 'site-frontend', 'site-editor', 'post-editor', 'wp-admin'.
541 */
542function wpcom_admin_bar_upsell_get_source() {
543    $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
544    if ( ! $screen ) {
545        return 'site-frontend';
546    }
547    if ( 'site-editor' === $screen->id ) {
548        return 'site-editor';
549    }
550    if ( $screen->is_block_editor() ) {
551        return 'post-editor';
552    }
553    return 'wp-admin';
554}
555
556/**
557 * Adds a "Free domain" upsell chip to the admin bar for users in the treatment
558 * of the omnibar upsell experiment.
559 *
560 * @param WP_Admin_Bar $wp_admin_bar The WP_Admin_Bar core object.
561 */
562function wpcom_add_free_domain_upsell( $wp_admin_bar ) {
563    if ( ! Free_Domain_Upsell_Experiment::should_show_upsell() ) {
564        return;
565    }
566
567    $icon = '<svg width="16" height="16" viewBox="4 5 16 14" fill="none" xmlns="http://www.w3.org/2000/svg">
568        <path d="M18.9397 9.87999L15.4197 6.06999L15.3597 6.00999C15.2897 5.93999 15.1997 5.89999 15.0997 5.89999H8.87973C8.77973 5.89999 8.68973 5.93999 8.61973 6.00999L5.05973 9.87999C4.93973 10.01 4.93973 10.21 5.05973 10.34L11.5397 17.86C11.6497 17.99 11.8197 18.07 11.9997 18.07C12.1797 18.07 12.3397 17.99 12.4597 17.86L18.9397 10.34C19.0597 10.21 19.0497 10.01 18.9397 9.87999ZM15.4097 7.53999L17.3297 9.63999H15.1697L15.4097 7.53999ZM14.4297 6.83999L14.1097 9.63999H10.2897L9.64973 6.83999H14.4297ZM8.68973 7.42999L9.19973 9.63999H6.66973L8.68973 7.42999ZM6.61973 10.6H9.42973L10.8397 15.49L6.61973 10.6ZM12.0397 15.87L10.5297 10.6H13.8597L12.0397 15.87ZM14.9697 10.6H17.3797L13.3697 15.24L14.9697 10.6Z" fill="currentColor" />
569    </svg>';
570
571    $wp_admin_bar->add_menu(
572        array(
573            'id'     => 'free-domain-upsell',
574            'parent' => null,
575            'title'  => '<span class="ab-icon" aria-hidden="true">' . $icon . '</span><span class="ab-label">' . esc_html__( 'Free domain', 'jetpack-mu-wpcom' ) . '</span>',
576            'href'   => add_query_arg(
577                array(
578                    'siteSlug' => wpcom_get_site_slug(),
579                    'ref'      => 'omnibar-free-domain',
580                ),
581                'https://wordpress.com/setup/domain-and-plan'
582            ),
583            'meta'   => array(
584                'class'         => 'free-domain-upsell',
585                'title'         => __( 'Free domain with an annual plan', 'jetpack-mu-wpcom' ),
586                'menu_title'    => __( 'Free domain', 'jetpack-mu-wpcom' ),
587                'upsell_source' => Free_Domain_Upsell_Experiment::get_upsell_source(),
588            ),
589        )
590    );
591}
592add_action( 'admin_bar_menu', 'wpcom_add_free_domain_upsell', 81 );