Completed
Push — add/private-sites ( b6781b...7b6a5c )
by
unknown
07:29
created

A8C_WPCOM_Masterbar::create_menu_item_anchor()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 4
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2
3
require_once dirname( __FILE__ ) . '/rtl-admin-bar.php';
4
5
/**
6
 * Custom Admin bar displayed instead of the default WordPress admin bar.
7
 */
8
class A8C_WPCOM_Masterbar {
9
	/**
10
	 * Use for testing changes made to remotely enqueued scripts and styles on your sandbox.
11
	 * If not set it will default to loading the ones from WordPress.com.
12
	 *
13
	 * @var string $sandbox_url
14
	 */
15
	private $sandbox_url = '';
16
17
	/**
18
	 * Current locale.
19
	 *
20
	 * @var string
21
	 */
22
	private $locale;
23
24
	/**
25
	 * Current User ID.
26
	 *
27
	 * @var int
28
	 */
29
	private $user_id;
30
	/**
31
	 * WordPress.com user data of the connected user.
32
	 *
33
	 * @var array
34
	 */
35
	private $user_data;
36
	/**
37
	 * WordPress.com username for the connected user.
38
	 *
39
	 * @var string
40
	 */
41
	private $user_login;
42
	/**
43
	 * WordPress.com email address for the connected user.
44
	 *
45
	 * @var string
46
	 */
47
	private $user_email;
48
	/**
49
	 * WordPress.com display name for the connected user.
50
	 *
51
	 * @var string
52
	 */
53
	private $display_name;
54
	/**
55
	 * Site URL sanitized for usage in WordPress.com slugs.
56
	 *
57
	 * @var string
58
	 */
59
	private $primary_site_slug;
60
	/**
61
	 * Text direction (ltr or rtl) based on connected WordPress.com user's interface settings.
62
	 *
63
	 * @var string
64
	 */
65
	private $user_text_direction;
66
	/**
67
	 * Number of sites owned by connected WordPress.com user.
68
	 *
69
	 * @var int
70
	 */
71
	private $user_site_count;
72
73
	/**
74
	 * Constructor
75
	 */
76
	public function __construct() {
77
		$this->locale  = $this->get_locale();
78
		$this->user_id = get_current_user_id();
79
80
		// Limit the masterbar to be shown only to connected Jetpack users.
81
		if ( ! Jetpack::is_user_connected( $this->user_id ) ) {
82
			return;
83
		}
84
85
		// Don't show the masterbar on WordPress mobile apps.
86
		if ( Jetpack_User_Agent_Info::is_mobile_app() ) {
87
			add_filter( 'show_admin_bar', '__return_false' );
88
			return;
89
		}
90
91
		Jetpack::dns_prefetch(
92
			array(
93
				'//s0.wp.com',
94
				'//s1.wp.com',
95
				'//s2.wp.com',
96
				'//0.gravatar.com',
97
				'//1.gravatar.com',
98
				'//2.gravatar.com',
99
			)
100
		);
101
102
		// Atomic only.
103
		if ( jetpack_is_atomic_site() ) {
104
			/*
105
			 * override user setting that hides masterbar from site's front.
106
			 * https://github.com/Automattic/jetpack/issues/7667
107
			 */
108
			add_filter( 'show_admin_bar', '__return_true' );
109
		}
110
111
		$this->user_data       = Jetpack::get_connected_user_data( $this->user_id );
112
		$this->user_login      = $this->user_data['login'];
113
		$this->user_email      = $this->user_data['email'];
114
		$this->display_name    = $this->user_data['display_name'];
115
		$this->user_site_count = $this->user_data['site_count'];
116
117
		// Used to build menu links that point directly to Calypso.
118
		$this->primary_site_slug = Jetpack::build_raw_urls( get_home_url() );
119
120
		// Used for display purposes and for building WP Admin links.
121
		$this->primary_site_url = str_replace( '::', '/', $this->primary_site_slug );
0 ignored issues
show
Bug introduced by
The property primary_site_url does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
122
123
		// We need to use user's setting here, instead of relying on current blog's text direction.
124
		$this->user_text_direction = $this->user_data['text_direction'];
125
126
		if ( $this->is_rtl() ) {
127
			// Extend core WP_Admin_Bar class in order to add rtl styles.
128
			add_filter( 'wp_admin_bar_class', array( $this, 'get_rtl_admin_bar_class' ) );
129
		}
130
		add_filter( 'admin_body_class', array( $this, 'admin_body_class' ) );
131
132
		add_action( 'wp_before_admin_bar_render', array( $this, 'replace_core_masterbar' ), 99999 );
133
134
		add_action( 'wp_enqueue_scripts', array( $this, 'add_styles_and_scripts' ) );
135
		add_action( 'admin_enqueue_scripts', array( $this, 'add_styles_and_scripts' ) );
136
137
		add_action( 'wp_enqueue_scripts', array( $this, 'remove_core_styles' ) );
138
		add_action( 'admin_enqueue_scripts', array( $this, 'remove_core_styles' ) );
139
140
		if ( Jetpack::is_module_active( 'notes' ) && $this->is_rtl() ) {
141
			// Override Notification module to include RTL styles.
142
			add_action( 'a8c_wpcom_masterbar_enqueue_rtl_notification_styles', '__return_true' );
143
		}
144
145
		add_action( 'wp_logout', array( $this, 'maybe_logout_user_from_wpcom' ) );
146
	}
147
148
	/**
149
	 * Log out from WordPress.com when logging out of the local site.
150
	 */
151
	public function maybe_logout_user_from_wpcom() {
152
		/**
153
		 * Whether we should sign out from wpcom too when signing out from the masterbar.
154
		 *
155
		 * @since 5.9.0
156
		 *
157
		 * @param bool $masterbar_should_logout_from_wpcom True by default.
158
		 */
159
		$masterbar_should_logout_from_wpcom = apply_filters( 'jetpack_masterbar_should_logout_from_wpcom', true );
160
		if (
161
			// No need to check for a nonce here, it happens further up.
162
			isset( $_GET['context'] ) // phpcs:ignore WordPress.Security.NonceVerification.Recommended
163
			&& 'masterbar' === $_GET['context'] // phpcs:ignore WordPress.Security.NonceVerification.Recommended
164
			&& $masterbar_should_logout_from_wpcom
165
		) {
166
			do_action( 'wp_masterbar_logout' );
167
		}
168
	}
169
170
	/**
171
	 * Get class name for RTL sites.
172
	 */
173
	public function get_rtl_admin_bar_class() {
174
		return 'RTL_Admin_Bar';
175
	}
176
177
	/**
178
	 * Adds CSS classes to admin body tag.
179
	 *
180
	 * @since 5.1
181
	 *
182
	 * @param string $admin_body_classes CSS classes that will be added.
183
	 *
184
	 * @return string
185
	 */
186
	public function admin_body_class( $admin_body_classes ) {
187
		return "$admin_body_classes jetpack-masterbar";
188
	}
189
190
	/**
191
	 * Remove the default Admin Bar CSS.
192
	 */
193
	public function remove_core_styles() {
194
		wp_dequeue_style( 'admin-bar' );
195
	}
196
197
	/**
198
	 * Check if the user settings are for an RTL language or not.
199
	 */
200
	public function is_rtl() {
201
		return 'rtl' === $this->user_text_direction ? true : false;
202
	}
203
204
	/**
205
	 * Enqueue our own CSS and JS to display our custom admin bar.
206
	 */
207
	public function add_styles_and_scripts() {
208
209
		if ( $this->is_rtl() ) {
210
			wp_enqueue_style( 'a8c-wpcom-masterbar-rtl', $this->wpcom_static_url( '/wp-content/mu-plugins/admin-bar/rtl/wpcom-admin-bar-rtl.css' ), array(), JETPACK__VERSION );
211
			wp_enqueue_style( 'a8c-wpcom-masterbar-overrides-rtl', $this->wpcom_static_url( '/wp-content/mu-plugins/admin-bar/masterbar-overrides/rtl/masterbar-rtl.css' ), array(), JETPACK__VERSION );
212
		} else {
213
			wp_enqueue_style( 'a8c-wpcom-masterbar', $this->wpcom_static_url( '/wp-content/mu-plugins/admin-bar/wpcom-admin-bar.css' ), array(), JETPACK__VERSION );
214
			wp_enqueue_style( 'a8c-wpcom-masterbar-overrides', $this->wpcom_static_url( '/wp-content/mu-plugins/admin-bar/masterbar-overrides/masterbar.css' ), array(), JETPACK__VERSION );
215
		}
216
217
		// Local overrides.
218
		wp_enqueue_style( 'a8c_wpcom_css_override', plugins_url( 'overrides.css', __FILE__ ), array(), JETPACK__VERSION );
219
220
		if ( ! Jetpack::is_module_active( 'notes ' ) ) {
221
			// Masterbar is relying on some icons from noticons.css.
222
			wp_enqueue_style( 'noticons', $this->wpcom_static_url( '/i/noticons/noticons.css' ), array(), JETPACK__VERSION . '-' . gmdate( 'oW' ) );
223
		}
224
225
		wp_enqueue_script(
226
			'jetpack-accessible-focus',
227
			Jetpack::get_file_url_for_environment( '_inc/build/accessible-focus.min.js', '_inc/accessible-focus.js' ),
228
			array(),
229
			JETPACK__VERSION,
230
			false
231
		);
232
		wp_enqueue_script(
233
			'a8c_wpcom_masterbar_tracks_events',
234
			Jetpack::get_file_url_for_environment(
235
				'_inc/build/masterbar/tracks-events.min.js',
236
				'modules/masterbar/tracks-events.js'
237
			),
238
			array( 'jquery' ),
239
			JETPACK__VERSION,
240
			false
241
		);
242
243
		wp_enqueue_script(
244
			'a8c_wpcom_masterbar_overrides',
245
			$this->wpcom_static_url( '/wp-content/mu-plugins/admin-bar/masterbar-overrides/masterbar.js' ),
246
			array( 'jquery' ),
247
			JETPACK__VERSION,
248
			false
249
		);
250
	}
251
252
	/**
253
	 * Get base URL where our CSS and JS will come from.
254
	 *
255
	 * @param string $file File path for a static resource.
256
	 */
257
	private function wpcom_static_url( $file ) {
258
		if ( ! empty( $this->sandbox_url ) ) {
259
			// For testing undeployed changes to remotely enqueued scripts and styles.
260
			return set_url_scheme( $this->sandbox_url . $file, 'https' );
261
		}
262
263
		$i   = hexdec( substr( md5( $file ), - 1 ) ) % 2;
264
		$url = 'https://s' . $i . '.wp.com' . $file;
265
266
		return set_url_scheme( $url, 'https' );
267
	}
268
269
	/**
270
	 * Remove the default admin bar items and replace it with our own admin bar.
271
	 */
272
	public function replace_core_masterbar() {
273
		global $wp_admin_bar;
274
275
		if ( ! is_object( $wp_admin_bar ) ) {
276
			return false;
277
		}
278
279
		$this->clear_core_masterbar( $wp_admin_bar );
280
		$this->build_wpcom_masterbar( $wp_admin_bar );
281
	}
282
283
	/**
284
	 * Remove all existing toolbar entries from core Masterbar
285
	 *
286
	 * @param WP_Admin_Bar $wp_admin_bar Admin Bar instance.
287
	 */
288
	public function clear_core_masterbar( $wp_admin_bar ) {
289
		foreach ( $wp_admin_bar->get_nodes() as $node ) {
290
			$wp_admin_bar->remove_node( $node->id );
291
		}
292
	}
293
294
	/**
295
	 * Add entries corresponding to WordPress.com Masterbar
296
	 *
297
	 * @param WP_Admin_Bar $wp_admin_bar Admin Bar instance.
298
	 */
299
	public function build_wpcom_masterbar( $wp_admin_bar ) {
300
		// Menu groups.
301
		$this->wpcom_adminbar_add_secondary_groups( $wp_admin_bar );
302
303
		// Left part.
304
		$this->add_my_sites_submenu( $wp_admin_bar );
305
		$this->add_reader_submenu( $wp_admin_bar );
306
307
		// Right part.
308
		if ( Jetpack::is_module_active( 'notes' ) ) {
309
			$this->add_notifications( $wp_admin_bar );
310
		}
311
312
		$this->add_me_submenu( $wp_admin_bar );
313
		$this->add_write_button( $wp_admin_bar );
314
	}
315
316
	/**
317
	 * Get WordPress.com current locale name.
318
	 */
319
	public function get_locale() {
320
		$wpcom_locale = get_locale();
321
322
		if ( ! class_exists( 'GP_Locales' ) ) {
323
			if ( defined( 'JETPACK__GLOTPRESS_LOCALES_PATH' ) && file_exists( JETPACK__GLOTPRESS_LOCALES_PATH ) ) {
324
				require JETPACK__GLOTPRESS_LOCALES_PATH;
325
			}
326
		}
327
328 View Code Duplication
		if ( class_exists( 'GP_Locales' ) ) {
329
			$wpcom_locale_object = GP_Locales::by_field( 'wp_locale', get_locale() );
330
			if ( $wpcom_locale_object instanceof GP_Locale ) {
331
				$wpcom_locale = $wpcom_locale_object->slug;
332
			}
333
		}
334
335
		return $wpcom_locale;
336
	}
337
338
	/**
339
	 * Add the Notifications menu item.
340
	 *
341
	 * @param WP_Admin_Bar $wp_admin_bar Admin Bar instance.
342
	 */
343
	public function add_notifications( $wp_admin_bar ) {
344
		$wp_admin_bar->add_node(
345
			array(
346
				'id'     => 'notes',
347
				'title'  => '<span id="wpnt-notes-unread-count" class="wpnt-loading wpn-read"></span>
348
						 <span class="screen-reader-text">' . esc_html__( 'Notifications', 'jetpack' ) . '</span>
349
						 <span class="noticon noticon-bell"></span>',
350
				'meta'   => array(
351
					'html'  => '<div id="wpnt-notes-panel2" style="display:none" lang="' . esc_attr( $this->locale ) . '" dir="' . ( $this->is_rtl() ? 'rtl' : 'ltr' ) . '">' .
352
								'<div class="wpnt-notes-panel-header">' .
353
								'<span class="wpnt-notes-header">' .
354
								esc_html__( 'Notifications', 'jetpack' ) .
355
								'</span>' .
356
								'<span class="wpnt-notes-panel-link">' .
357
								'</span>' .
358
								'</div>' .
359
								'</div>',
360
					'class' => 'menupop mb-trackable',
361
				),
362
				'parent' => 'top-secondary',
363
			)
364
		);
365
	}
366
367
	/**
368
	 * Add the "Reader" menu item in the root default group.
369
	 *
370
	 * @param WP_Admin_Bar $wp_admin_bar Admin Bar instance.
371
	 */
372
	public function add_reader_submenu( $wp_admin_bar ) {
373
		$wp_admin_bar->add_menu(
374
			array(
375
				'parent' => 'root-default',
376
				'id'     => 'newdash',
377
				'title'  => esc_html__( 'Reader', 'jetpack' ),
378
				'href'   => '#',
379
				'meta'   => array(
380
					'class' => 'mb-trackable',
381
				),
382
			)
383
		);
384
385
		$wp_admin_bar->add_menu(
386
			array(
387
				'parent' => 'newdash',
388
				'id'     => 'streams-header',
389
				'title'  => esc_html_x(
390
					'Streams',
391
					'Title for Reader sub-menu that contains followed sites, likes, and recommendations',
392
					'jetpack'
393
				),
394
				'meta'   => array(
395
					'class' => 'ab-submenu-header',
396
				),
397
			)
398
		);
399
400
		$following_title = $this->create_menu_item_pair(
401
			array(
402
				'url'   => 'https://wordpress.com/',
403
				'id'    => 'wp-admin-bar-followed-sites',
404
				'label' => esc_html__( 'Followed Sites', 'jetpack' ),
405
			),
406
			array(
407
				'url'   => 'https://wordpress.com/following/edit',
408
				'id'    => 'wp-admin-bar-reader-followed-sites-manage',
409
				'label' => esc_html__( 'Manage', 'jetpack' ),
410
			)
411
		);
412
413
		$wp_admin_bar->add_menu(
414
			array(
415
				'parent' => 'newdash',
416
				'id'     => 'following',
417
				'title'  => $following_title,
418
				'meta'   => array( 'class' => 'inline-action' ),
419
			)
420
		);
421
422
		$wp_admin_bar->add_menu(
423
			array(
424
				'parent' => 'newdash',
425
				'id'     => 'discover-discover',
426
				'title'  => esc_html__( 'Discover', 'jetpack' ),
427
				'href'   => 'https://wordpress.com/discover',
428
				'meta'   => array(
429
					'class' => 'mb-icon-spacer',
430
				),
431
			)
432
		);
433
434
		$wp_admin_bar->add_menu(
435
			array(
436
				'parent' => 'newdash',
437
				'id'     => 'discover-search',
438
				'title'  => esc_html__( 'Search', 'jetpack' ),
439
				'href'   => 'https://wordpress.com/read/search',
440
				'meta'   => array(
441
					'class' => 'mb-icon-spacer',
442
				),
443
			)
444
		);
445
446
		$wp_admin_bar->add_menu(
447
			array(
448
				'parent' => 'newdash',
449
				'id'     => 'discover-recommended-blogs',
450
				'title'  => esc_html__( 'Recommendations', 'jetpack' ),
451
				'href'   => 'https://wordpress.com/recommendations',
452
				'meta'   => array(
453
					'class' => 'mb-icon-spacer',
454
				),
455
			)
456
		);
457
458
		$wp_admin_bar->add_menu(
459
			array(
460
				'parent' => 'newdash',
461
				'id'     => 'my-activity-my-likes',
462
				'title'  => esc_html__( 'My Likes', 'jetpack' ),
463
				'href'   => 'https://wordpress.com/activities/likes',
464
				'meta'   => array(
465
					'class' => 'mb-icon-spacer',
466
				),
467
			)
468
		);
469
470
	}
471
472
	/**
473
	 * Merge 2 menu items together into 2 link tags.
474
	 *
475
	 * @param array $primary   Array of menu information.
476
	 * @param array $secondary Array of menu information.
477
	 */
478
	public function create_menu_item_pair( $primary, $secondary ) {
479
		$primary_class   = 'ab-item ab-primary mb-icon';
480
		$secondary_class = 'ab-secondary';
481
482
		$primary_anchor   = $this->create_menu_item_anchor( $primary_class, $primary['url'], $primary['label'], $primary['id'] );
483
		$secondary_anchor = $this->create_menu_item_anchor( $secondary_class, $secondary['url'], $secondary['label'], $secondary['id'] );
484
485
		return $primary_anchor . $secondary_anchor;
486
	}
487
488
	/**
489
	 * Create a link tag based on information about a menu item.
490
	 *
491
	 * @param string $class Menu item CSS class.
492
	 * @param string $url   URL you go to when clicking on the menu item.
493
	 * @param string $label Menu item title.
494
	 * @param string $id    Menu item slug.
495
	 */
496
	public function create_menu_item_anchor( $class, $url, $label, $id ) {
497
		return '<a href="' . $url . '" class="' . $class . '" id="' . $id . '">' . $label . '</a>';
498
	}
499
500
	/**
501
	 * Add Secondary groups for submenu items.
502
	 *
503
	 * @param WP_Admin_Bar $wp_admin_bar Admin Bar instance.
504
	 */
505
	public function wpcom_adminbar_add_secondary_groups( $wp_admin_bar ) {
506
		$wp_admin_bar->add_group(
507
			array(
508
				'id'   => 'root-default',
509
				'meta' => array(
510
					'class' => 'ab-top-menu',
511
				),
512
			)
513
		);
514
515
		$wp_admin_bar->add_group(
516
			array(
517
				'parent' => 'blog',
518
				'id'     => 'blog-secondary',
519
				'meta'   => array(
520
					'class' => 'ab-sub-secondary',
521
				),
522
			)
523
		);
524
525
		$wp_admin_bar->add_group(
526
			array(
527
				'id'   => 'top-secondary',
528
				'meta' => array(
529
					'class' => 'ab-top-secondary',
530
				),
531
			)
532
		);
533
	}
534
535
	/**
536
	 * Add User info menu item.
537
	 *
538
	 * @param WP_Admin_Bar $wp_admin_bar Admin Bar instance.
539
	 */
540
	public function add_me_submenu( $wp_admin_bar ) {
541
		$user_id = get_current_user_id();
542
		if ( empty( $user_id ) ) {
543
			return;
544
		}
545
546
		$avatar = get_avatar( $this->user_email, 32, 'mm', '', array( 'force_display' => true ) );
547
		$class  = empty( $avatar ) ? 'mb-trackable' : 'with-avatar mb-trackable';
548
549
		// Add the 'Me' menu.
550
		$wp_admin_bar->add_menu(
551
			array(
552
				'id'     => 'my-account',
553
				'parent' => 'top-secondary',
554
				'title'  => $avatar . '<span class="ab-text">' . esc_html__( 'Me', 'jetpack' ) . '</span>',
555
				'href'   => '#',
556
				'meta'   => array(
557
					'class' => $class,
558
				),
559
			)
560
		);
561
562
		$id = 'user-actions';
563
		$wp_admin_bar->add_group(
564
			array(
565
				'parent' => 'my-account',
566
				'id'     => $id,
567
			)
568
		);
569
570
		$settings_url = 'https://wordpress.com/me/account';
571
572
		$logout_url = wp_logout_url();
573
		$logout_url = add_query_arg( 'context', 'masterbar', $logout_url );
574
575
		$user_info  = get_avatar( $this->user_email, 128, 'mm', '', array( 'force_display' => true ) );
576
		$user_info .= '<span class="display-name">' . $this->display_name . '</span>';
577
		$user_info .= '<a class="username" href="http://gravatar.com/' . $this->user_login . '">@' . $this->user_login . '</a>';
578
579
		$user_info .= sprintf(
580
			'<div><a href="%s" class="ab-sign-out">%s</a></div>',
581
			$logout_url,
582
			esc_html__( 'Sign Out', 'jetpack' )
583
		);
584
585
		$wp_admin_bar->add_menu(
586
			array(
587
				'parent' => $id,
588
				'id'     => 'user-info',
589
				'title'  => $user_info,
590
				'meta'   => array(
591
					'class'    => 'user-info user-info-item',
592
					'tabindex' => -1,
593
				),
594
			)
595
		);
596
597
		$wp_admin_bar->add_menu(
598
			array(
599
				'parent' => $id,
600
				'id'     => 'profile-header',
601
				'title'  => esc_html__( 'Profile', 'jetpack' ),
602
				'meta'   => array(
603
					'class' => 'ab-submenu-header',
604
				),
605
			)
606
		);
607
608
		$wp_admin_bar->add_menu(
609
			array(
610
				'parent' => $id,
611
				'id'     => 'my-profile',
612
				'title'  => esc_html__( 'My Profile', 'jetpack' ),
613
				'href'   => 'https://wordpress.com/me',
614
				'meta'   => array(
615
					'class' => 'mb-icon',
616
				),
617
			)
618
		);
619
620
		$wp_admin_bar->add_menu(
621
			array(
622
				'parent' => $id,
623
				'id'     => 'account-settings',
624
				'title'  => esc_html__( 'Account Settings', 'jetpack' ),
625
				'href'   => $settings_url,
626
				'meta'   => array(
627
					'class' => 'mb-icon',
628
				),
629
			)
630
		);
631
632
		$wp_admin_bar->add_menu(
633
			array(
634
				'parent' => $id,
635
				'id'     => 'billing',
636
				'title'  => esc_html__( 'Manage Purchases', 'jetpack' ),
637
				'href'   => 'https://wordpress.com/me/purchases',
638
				'meta'   => array(
639
					'class' => 'mb-icon',
640
				),
641
			)
642
		);
643
644
		$wp_admin_bar->add_menu(
645
			array(
646
				'parent' => $id,
647
				'id'     => 'security',
648
				'title'  => esc_html__( 'Security', 'jetpack' ),
649
				'href'   => 'https://wordpress.com/me/security',
650
				'meta'   => array(
651
					'class' => 'mb-icon',
652
				),
653
			)
654
		);
655
656
		$wp_admin_bar->add_menu(
657
			array(
658
				'parent' => $id,
659
				'id'     => 'notifications',
660
				'title'  => esc_html__( 'Notifications', 'jetpack' ),
661
				'href'   => 'https://wordpress.com/me/notifications',
662
				'meta'   => array(
663
					'class' => 'mb-icon',
664
				),
665
			)
666
		);
667
668
		$wp_admin_bar->add_menu(
669
			array(
670
				'parent' => $id,
671
				'id'     => 'special-header',
672
				'title'  => esc_html_x(
673
					'Special',
674
					'Title for Me sub-menu that contains Get Apps, Next Steps, and Help options',
675
					'jetpack'
676
				),
677
				'meta'   => array(
678
					'class' => 'ab-submenu-header',
679
				),
680
			)
681
		);
682
683
		$wp_admin_bar->add_menu(
684
			array(
685
				'parent' => $id,
686
				'id'     => 'get-apps',
687
				'title'  => esc_html__( 'Get Apps', 'jetpack' ),
688
				'href'   => 'https://wordpress.com/me/get-apps',
689
				'meta'   => array(
690
					'class' => 'mb-icon user-info-item',
691
				),
692
			)
693
		);
694
695
		$help_link = 'https://jetpack.com/support/';
696
697
		if ( jetpack_is_atomic_site() ) {
698
			$help_link = 'https://wordpress.com/help';
699
		}
700
701
		$wp_admin_bar->add_menu(
702
			array(
703
				'parent' => $id,
704
				'id'     => 'help',
705
				'title'  => esc_html__( 'Help', 'jetpack' ),
706
				'href'   => $help_link,
707
				'meta'   => array(
708
					'class' => 'mb-icon user-info-item',
709
				),
710
			)
711
		);
712
	}
713
714
	/**
715
	 * Add Write Menu item.
716
	 *
717
	 * @param WP_Admin_Bar $wp_admin_bar Admin Bar instance.
718
	 */
719
	public function add_write_button( $wp_admin_bar ) {
720
		$current_user = wp_get_current_user();
721
722
		$posting_blog_id = get_current_blog_id();
723
		if ( ! is_user_member_of_blog( get_current_user_id(), get_current_blog_id() ) ) {
724
			$posting_blog_id = $current_user->primary_blog;
725
		}
726
727
		$user_can_post = current_user_can_for_blog( $posting_blog_id, 'publish_posts' );
728
729
		if ( ! $posting_blog_id || ! $user_can_post ) {
730
			return;
731
		}
732
733
		$blog_post_page = 'https://wordpress.com/post/' . esc_attr( $this->primary_site_slug );
734
735
		$wp_admin_bar->add_menu(
736
			array(
737
				'parent' => 'top-secondary',
738
				'id'     => 'ab-new-post',
739
				'href'   => $blog_post_page,
740
				'title'  => '<span>' . esc_html__( 'Write', 'jetpack' ) . '</span>',
741
				'meta'   => array(
742
					'class' => 'mb-trackable',
743
				),
744
			)
745
		);
746
	}
747
748
	/**
749
	 * Add the "My Site" menu item in the root default group.
750
	 *
751
	 * @param WP_Admin_Bar $wp_admin_bar Admin Bar instance.
752
	 */
753
	public function add_my_sites_submenu( $wp_admin_bar ) {
754
		$current_user = wp_get_current_user();
755
756
		$blog_name = get_bloginfo( 'name' );
757
		if ( empty( $blog_name ) ) {
758
			$blog_name = $this->primary_site_slug;
759
		}
760
761
		if ( mb_strlen( $blog_name ) > 20 ) {
762
			$blog_name = mb_substr( html_entity_decode( $blog_name, ENT_QUOTES ), 0, 20 ) . '&hellip;';
763
		}
764
765
		$wp_admin_bar->add_menu(
766
			array(
767
				'parent' => 'root-default',
768
				'id'     => 'blog',
769
				'title'  => _n( 'My Site', 'My Sites', $this->user_site_count, 'jetpack' ),
770
				'href'   => '#',
771
				'meta'   => array(
772
					'class' => 'my-sites mb-trackable',
773
				),
774
			)
775
		);
776
777
		if ( $this->user_site_count > 1 ) {
778
			$wp_admin_bar->add_menu(
779
				array(
780
					'parent' => 'blog',
781
					'id'     => 'switch-site',
782
					'title'  => esc_html__( 'Switch Site', 'jetpack' ),
783
					'href'   => 'https://wordpress.com/sites',
784
				)
785
			);
786
		} else {
787
			$wp_admin_bar->add_menu(
788
				array(
789
					'parent' => 'blog',
790
					'id'     => 'new-site',
791
					'title'  => esc_html__( '+ Add New WordPress', 'jetpack' ),
792
					'href'   => 'https://wordpress.com/start?ref=admin-bar-logged-in',
793
				)
794
			);
795
		}
796
797
		if ( is_user_member_of_blog( $current_user->ID ) ) {
798
			$blavatar = '';
799
			$class    = 'current-site';
800
801
			if ( has_site_icon() ) {
802
				$src      = get_site_icon_url();
803
				$blavatar = '<img class="avatar" src="' . esc_attr( $src ) . '" alt="Current site avatar">';
804
				$class    = 'has-blavatar';
805
			}
806
807
			$blog_info  = '<div class="ab-site-icon">' . $blavatar . '</div>';
808
			$blog_info .= '<span class="ab-site-title">' . esc_html( $blog_name ) . '</span>';
809
			$blog_info .= '<span class="ab-site-description">' . esc_html( $this->primary_site_url ) . '</span>';
810
811
			$wp_admin_bar->add_menu(
812
				array(
813
					'parent' => 'blog',
814
					'id'     => 'blog-info',
815
					'title'  => $blog_info,
816
					'href'   => esc_url( trailingslashit( $this->primary_site_url ) ),
817
					'meta'   => array(
818
						'class' => $class,
819
					),
820
				)
821
			);
822
		}
823
824
		// Site Preview.
825
		if ( is_admin() ) {
826
			$wp_admin_bar->add_menu(
827
				array(
828
					'parent' => 'blog',
829
					'id'     => 'site-view',
830
					'title'  => __( 'View Site', 'jetpack' ),
831
					'href'   => home_url(),
832
					'meta'   => array(
833
						'class'  => 'mb-icon',
834
						'target' => '_blank',
835
					),
836
				)
837
			);
838
		}
839
840
		// Stats.
841 View Code Duplication
		if ( Jetpack::is_module_active( 'stats' ) ) {
842
			$wp_admin_bar->add_menu(
843
				array(
844
					'parent' => 'blog',
845
					'id'     => 'blog-stats',
846
					'title'  => esc_html__( 'Stats', 'jetpack' ),
847
					'href'   => 'https://wordpress.com/stats/' . esc_attr( $this->primary_site_slug ),
848
					'meta'   => array(
849
						'class' => 'mb-icon',
850
					),
851
				)
852
			);
853
		}
854
855 View Code Duplication
		if ( current_user_can( 'manage_options' ) ) {
856
			$wp_admin_bar->add_menu(
857
				array(
858
					'parent' => 'blog',
859
					'id'     => 'activity',
860
					'title'  => esc_html__( 'Activity', 'jetpack' ),
861
					'href'   => 'https://wordpress.com/activity-log/' . esc_attr( $this->primary_site_slug ),
862
					'meta'   => array(
863
						'class' => 'mb-icon',
864
					),
865
				)
866
			);
867
		}
868
869
		// Add Calypso plans link and plan type indicator.
870
		if ( is_user_member_of_blog( $current_user->ID ) ) {
871
			$plans_url = 'https://wordpress.com/plans/' . esc_attr( $this->primary_site_slug );
872
			$label     = esc_html__( 'Plan', 'jetpack' );
873
			$plan      = Jetpack_Plan::get();
874
875
			$plan_title = $this->create_menu_item_pair(
876
				array(
877
					'url'   => $plans_url,
878
					'id'    => 'wp-admin-bar-plan',
879
					'label' => $label,
880
				),
881
				array(
882
					'url'   => $plans_url,
883
					'id'    => 'wp-admin-bar-plan-badge',
884
					'label' => $plan['product_name_short'],
885
				)
886
			);
887
888
			$wp_admin_bar->add_menu(
889
				array(
890
					'parent' => 'blog',
891
					'id'     => 'plan',
892
					'title'  => $plan_title,
893
					'meta'   => array(
894
						'class' => 'inline-action',
895
					),
896
				)
897
			);
898
		}
899
900
		// Publish group.
901
		$wp_admin_bar->add_group(
902
			array(
903
				'parent' => 'blog',
904
				'id'     => 'publish',
905
			)
906
		);
907
908
		// Publish header.
909
		$wp_admin_bar->add_menu(
910
			array(
911
				'parent' => 'publish',
912
				'id'     => 'publish-header',
913
				'title'  => esc_html_x( 'Manage', 'admin bar menu group label', 'jetpack' ),
914
				'meta'   => array(
915
					'class' => 'ab-submenu-header',
916
				),
917
			)
918
		);
919
920
		// Pages.
921
		$pages_title = $this->create_menu_item_pair(
922
			array(
923
				'url'   => 'https://wordpress.com/pages/' . esc_attr( $this->primary_site_slug ),
924
				'id'    => 'wp-admin-bar-edit-page',
925
				'label' => esc_html__( 'Site Pages', 'jetpack' ),
926
			),
927
			array(
928
				'url'   => 'https://wordpress.com/page/' . esc_attr( $this->primary_site_slug ),
929
				'id'    => 'wp-admin-bar-new-page-badge',
930
				'label' => esc_html_x( 'Add', 'admin bar menu new item label', 'jetpack' ),
931
			)
932
		);
933
934
		if ( ! current_user_can( 'edit_pages' ) ) {
935
			$pages_title = $this->create_menu_item_anchor(
936
				'ab-item ab-primary mb-icon',
937
				'https://wordpress.com/pages/' . esc_attr( $this->primary_site_slug ),
938
				esc_html__( 'Site Pages', 'jetpack' ),
939
				'wp-admin-bar-edit-page'
940
			);
941
		}
942
943
		$wp_admin_bar->add_menu(
944
			array(
945
				'parent' => 'publish',
946
				'id'     => 'new-page',
947
				'title'  => $pages_title,
948
				'meta'   => array(
949
					'class' => 'inline-action',
950
				),
951
			)
952
		);
953
954
		// Blog Posts.
955
		$posts_title = $this->create_menu_item_pair(
956
			array(
957
				'url'   => 'https://wordpress.com/posts/' . esc_attr( $this->primary_site_slug ),
958
				'id'    => 'wp-admin-bar-edit-post',
959
				'label' => esc_html__( 'Blog Posts', 'jetpack' ),
960
			),
961
			array(
962
				'url'   => 'https://wordpress.com/post/' . esc_attr( $this->primary_site_slug ),
963
				'id'    => 'wp-admin-bar-new-post-badge',
964
				'label' => esc_html_x( 'Add', 'admin bar menu new item label', 'jetpack' ),
965
			)
966
		);
967
968
		if ( ! current_user_can( 'edit_posts' ) ) {
969
			$posts_title = $this->create_menu_item_anchor(
970
				'ab-item ab-primary mb-icon',
971
				'https://wordpress.com/posts/' . esc_attr( $this->primary_site_slug ),
972
				esc_html__( 'Blog Posts', 'jetpack' ),
973
				'wp-admin-bar-edit-post'
974
			);
975
		}
976
977
		$wp_admin_bar->add_menu(
978
			array(
979
				'parent' => 'publish',
980
				'id'     => 'new-post',
981
				'title'  => $posts_title,
982
				'meta'   => array(
983
					'class' => 'inline-action mb-trackable',
984
				),
985
			)
986
		);
987
988
		// Comments.
989 View Code Duplication
		if ( current_user_can( 'moderate_comments' ) ) {
990
			$wp_admin_bar->add_menu(
991
				array(
992
					'parent' => 'publish',
993
					'id'     => 'comments',
994
					'title'  => __( 'Comments', 'jetpack' ),
995
					'href'   => 'https://wordpress.com/comments/' . esc_attr( $this->primary_site_slug ),
996
					'meta'   => array(
997
						'class' => 'mb-icon',
998
					),
999
				)
1000
			);
1001
		}
1002
1003
		// Testimonials.
1004 View Code Duplication
		if ( Jetpack::is_module_active( 'custom-content-types' ) && get_option( 'jetpack_testimonial' ) ) {
1005
			$testimonials_title = $this->create_menu_item_pair(
1006
				array(
1007
					'url'   => 'https://wordpress.com/types/jetpack-testimonial/' . esc_attr( $this->primary_site_slug ),
1008
					'id'    => 'wp-admin-bar-edit-testimonial',
1009
					'label' => esc_html__( 'Testimonials', 'jetpack' ),
1010
				),
1011
				array(
1012
					'url'   => 'https://wordpress.com/edit/jetpack-testimonial/' . esc_attr( $this->primary_site_slug ),
1013
					'id'    => 'wp-admin-bar-new-testimonial',
1014
					'label' => esc_html_x( 'Add', 'Button label for adding a new item via the toolbar menu', 'jetpack' ),
1015
				)
1016
			);
1017
1018
			if ( ! current_user_can( 'edit_pages' ) ) {
1019
				$testimonials_title = $this->create_menu_item_anchor(
1020
					'ab-item ab-primary mb-icon',
1021
					'https://wordpress.com/types/jetpack-testimonial/' . esc_attr( $this->primary_site_slug ),
1022
					esc_html__( 'Testimonials', 'jetpack' ),
1023
					'wp-admin-bar-edit-testimonial'
1024
				);
1025
			}
1026
1027
			$wp_admin_bar->add_menu(
1028
				array(
1029
					'parent' => 'publish',
1030
					'id'     => 'new-jetpack-testimonial',
1031
					'title'  => $testimonials_title,
1032
					'meta'   => array(
1033
						'class' => 'inline-action',
1034
					),
1035
				)
1036
			);
1037
		}
1038
1039
		// Portfolio.
1040 View Code Duplication
		if ( Jetpack::is_module_active( 'custom-content-types' ) && get_option( 'jetpack_portfolio' ) ) {
1041
			$portfolios_title = $this->create_menu_item_pair(
1042
				array(
1043
					'url'   => 'https://wordpress.com/types/jetpack-portfolio/' . esc_attr( $this->primary_site_slug ),
1044
					'id'    => 'wp-admin-bar-edit-portfolio',
1045
					'label' => esc_html__( 'Portfolio', 'jetpack' ),
1046
				),
1047
				array(
1048
					'url'   => 'https://wordpress.com/edit/jetpack-portfolio/' . esc_attr( $this->primary_site_slug ),
1049
					'id'    => 'wp-admin-bar-new-portfolio',
1050
					'label' => esc_html_x( 'Add', 'Button label for adding a new item via the toolbar menu', 'jetpack' ),
1051
				)
1052
			);
1053
1054
			if ( ! current_user_can( 'edit_pages' ) ) {
1055
				$portfolios_title = $this->create_menu_item_anchor(
1056
					'ab-item ab-primary mb-icon',
1057
					'https://wordpress.com/types/jetpack-portfolio/' . esc_attr( $this->primary_site_slug ),
1058
					esc_html__( 'Portfolio', 'jetpack' ),
1059
					'wp-admin-bar-edit-portfolio'
1060
				);
1061
			}
1062
1063
			$wp_admin_bar->add_menu(
1064
				array(
1065
					'parent' => 'publish',
1066
					'id'     => 'new-jetpack-portfolio',
1067
					'title'  => $portfolios_title,
1068
					'meta'   => array(
1069
						'class' => 'inline-action',
1070
					),
1071
				)
1072
			);
1073
		}
1074
1075
		if ( current_user_can( 'edit_theme_options' ) ) {
1076
			// Look and Feel group.
1077
			$wp_admin_bar->add_group(
1078
				array(
1079
					'parent' => 'blog',
1080
					'id'     => 'look-and-feel',
1081
				)
1082
			);
1083
1084
			// Look and Feel header.
1085
			$wp_admin_bar->add_menu(
1086
				array(
1087
					'parent' => 'look-and-feel',
1088
					'id'     => 'look-and-feel-header',
1089
					'title'  => esc_html_x( 'Personalize', 'admin bar menu group label', 'jetpack' ),
1090
					'meta'   => array(
1091
						'class' => 'ab-submenu-header',
1092
					),
1093
				)
1094
			);
1095
1096
			if ( is_admin() ) {
1097
				// In wp-admin the `return` query arg will return to that page after closing the Customizer.
1098
				$customizer_url = add_query_arg(
1099
					array(
1100
						'return' => rawurlencode( site_url( $_SERVER['REQUEST_URI'] ) ),
1101
					),
1102
					wp_customize_url()
1103
				);
1104
			} else {
1105
				/*
1106
				 * On the frontend the `url` query arg will load that page in the Customizer
1107
				 * and also return to it after closing
1108
				 * non-home URLs won't work unless we undo domain mapping
1109
				 * since the Customizer preview is unmapped to always have HTTPS.
1110
				 */
1111
				$current_page   = '//' . $this->primary_site_slug . $_SERVER['REQUEST_URI'];
1112
				$customizer_url = add_query_arg( array( 'url' => rawurlencode( $current_page ) ), wp_customize_url() );
1113
			}
1114
1115
			$theme_title = $this->create_menu_item_pair(
1116
				array(
1117
					'url'   => $customizer_url,
1118
					'id'    => 'wp-admin-bar-cmz',
1119
					'label' => esc_html_x( 'Customize', 'admin bar customize item label', 'jetpack' ),
1120
				),
1121
				array(
1122
					'url'   => 'https://wordpress.com/themes/' . esc_attr( $this->primary_site_slug ),
1123
					'id'    => 'wp-admin-bar-themes',
1124
					'label' => esc_html__( 'Themes', 'jetpack' ),
1125
				)
1126
			);
1127
			$meta        = array(
1128
				'class' => 'mb-icon',
1129
				'class' => 'inline-action',
1130
			);
1131
			$href        = false;
1132
1133
			$wp_admin_bar->add_menu(
1134
				array(
1135
					'parent' => 'look-and-feel',
1136
					'id'     => 'themes',
1137
					'title'  => $theme_title,
1138
					'href'   => $href,
1139
					'meta'   => $meta,
1140
				)
1141
			);
1142
		}
1143
1144
		if ( current_user_can( 'manage_options' ) ) {
1145
			// Configuration group.
1146
			$wp_admin_bar->add_group(
1147
				array(
1148
					'parent' => 'blog',
1149
					'id'     => 'configuration',
1150
				)
1151
			);
1152
1153
			// Configuration header.
1154
			$wp_admin_bar->add_menu(
1155
				array(
1156
					'parent' => 'configuration',
1157
					'id'     => 'configuration-header',
1158
					'title'  => esc_html_x( 'Configure', 'admin bar menu group label', 'jetpack' ),
1159
					'meta'   => array(
1160
						'class' => 'ab-submenu-header',
1161
					),
1162
				)
1163
			);
1164
1165 View Code Duplication
			if ( Jetpack::is_module_active( 'publicize' ) || Jetpack::is_module_active( 'sharedaddy' ) ) {
1166
				$wp_admin_bar->add_menu(
1167
					array(
1168
						'parent' => 'configuration',
1169
						'id'     => 'sharing',
1170
						'title'  => esc_html__( 'Sharing', 'jetpack' ),
1171
						'href'   => 'https://wordpress.com/sharing/' . esc_attr( $this->primary_site_slug ),
1172
						'meta'   => array(
1173
							'class' => 'mb-icon',
1174
						),
1175
					)
1176
				);
1177
			}
1178
1179
			$people_title = $this->create_menu_item_pair(
1180
				array(
1181
					'url'   => 'https://wordpress.com/people/team/' . esc_attr( $this->primary_site_slug ),
1182
					'id'    => 'wp-admin-bar-people',
1183
					'label' => esc_html__( 'People', 'jetpack' ),
1184
				),
1185
				array(
1186
					'url'   => admin_url( 'user-new.php' ),
1187
					'id'    => 'wp-admin-bar-people-add',
1188
					'label' => esc_html_x( 'Add', 'admin bar people item label', 'jetpack' ),
1189
				)
1190
			);
1191
1192
			$wp_admin_bar->add_menu(
1193
				array(
1194
					'parent' => 'configuration',
1195
					'id'     => 'users-toolbar',
1196
					'title'  => $people_title,
1197
					'href'   => false,
1198
					'meta'   => array(
1199
						'class' => 'inline-action',
1200
					),
1201
				)
1202
			);
1203
1204
			$plugins_title = $this->create_menu_item_pair(
1205
				array(
1206
					'url'   => 'https://wordpress.com/plugins/' . esc_attr( $this->primary_site_slug ),
1207
					'id'    => 'wp-admin-bar-plugins',
1208
					'label' => esc_html__( 'Plugins', 'jetpack' ),
1209
				),
1210
				array(
1211
					'url'   => 'https://wordpress.com/plugins/manage/' . esc_attr( $this->primary_site_slug ),
1212
					'id'    => 'wp-admin-bar-plugins-add',
1213
					'label' => esc_html_x( 'Manage', 'Label for the button on the Masterbar to manage plugins', 'jetpack' ),
1214
				)
1215
			);
1216
1217
			$wp_admin_bar->add_menu(
1218
				array(
1219
					'parent' => 'configuration',
1220
					'id'     => 'plugins',
1221
					'title'  => $plugins_title,
1222
					'href'   => false,
1223
					'meta'   => array(
1224
						'class' => 'inline-action',
1225
					),
1226
				)
1227
			);
1228
1229
			if ( jetpack_is_atomic_site() ) {
1230
				$domain_title = $this->create_menu_item_pair(
1231
					array(
1232
						'url'   => 'https://wordpress.com/domains/' . esc_attr( $this->primary_site_slug ),
1233
						'id'    => 'wp-admin-bar-domains',
1234
						'label' => esc_html__( 'Domains', 'jetpack' ),
1235
					),
1236
					array(
1237
						'url'   => 'https://wordpress.com/domains/add/' . esc_attr( $this->primary_site_slug ),
1238
						'id'    => 'wp-admin-bar-domains-add',
1239
						'label' => esc_html_x( 'Add', 'Label for the button on the Masterbar to add a new domain', 'jetpack' ),
1240
					)
1241
				);
1242
				$wp_admin_bar->add_menu(
1243
					array(
1244
						'parent' => 'configuration',
1245
						'id'     => 'domains',
1246
						'title'  => $domain_title,
1247
						'href'   => false,
1248
						'meta'   => array(
1249
							'class' => 'inline-action',
1250
						),
1251
					)
1252
				);
1253
			}
1254
1255
			$wp_admin_bar->add_menu(
1256
				array(
1257
					'parent' => 'configuration',
1258
					'id'     => 'blog-settings',
1259
					'title'  => esc_html__( 'Settings', 'jetpack' ),
1260
					'href'   => 'https://wordpress.com/settings/general/' . esc_attr( $this->primary_site_slug ),
1261
					'meta'   => array(
1262
						'class' => 'mb-icon',
1263
					),
1264
				)
1265
			);
1266
1267
			if ( ! is_admin() ) {
1268
				$wp_admin_bar->add_menu(
1269
					array(
1270
						'parent' => 'configuration',
1271
						'id'     => 'legacy-dashboard',
1272
						'title'  => esc_html__( 'Dashboard', 'jetpack' ),
1273
						'href'   => admin_url(),
1274
						'meta'   => array(
1275
							'class' => 'mb-icon',
1276
						),
1277
					)
1278
				);
1279
			}
1280
1281
			// Restore dashboard menu toggle that is needed on mobile views.
1282
			if ( is_admin() ) {
1283
				$wp_admin_bar->add_menu(
1284
					array(
1285
						'id'    => 'menu-toggle',
1286
						'title' => '<span class="ab-icon"></span><span class="screen-reader-text">' . esc_html__( 'Menu', 'jetpack' ) . '</span>',
1287
						'href'  => '#',
1288
					)
1289
				);
1290
			}
1291
1292
			/**
1293
			 * Fires when menu items are added to the masterbar "My Sites" menu.
1294
			 *
1295
			 * @since 5.4.0
1296
			 */
1297
			do_action( 'jetpack_masterbar' );
1298
		}
1299
	}
1300
}
1301