summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/jetpack/modules/masterbar/admin-menu')
-rw-r--r--plugins/jetpack/modules/masterbar/admin-menu/admin-menu-rtl.css490
-rw-r--r--plugins/jetpack/modules/masterbar/admin-menu/admin-menu-rtl.min.css1
-rw-r--r--plugins/jetpack/modules/masterbar/admin-menu/admin-menu.css488
-rw-r--r--plugins/jetpack/modules/masterbar/admin-menu/admin-menu.js124
-rw-r--r--plugins/jetpack/modules/masterbar/admin-menu/admin-menu.min.css2
-rw-r--r--plugins/jetpack/modules/masterbar/admin-menu/class-admin-menu.php542
-rw-r--r--plugins/jetpack/modules/masterbar/admin-menu/class-atomic-admin-menu.php427
-rw-r--r--plugins/jetpack/modules/masterbar/admin-menu/class-base-admin-menu.php694
-rw-r--r--plugins/jetpack/modules/masterbar/admin-menu/class-dashboard-switcher-tracking.php175
-rw-r--r--plugins/jetpack/modules/masterbar/admin-menu/class-domain-only-admin-menu.php28
-rw-r--r--plugins/jetpack/modules/masterbar/admin-menu/class-jetpack-admin-menu.php252
-rw-r--r--plugins/jetpack/modules/masterbar/admin-menu/class-p2-admin-menu.php199
-rw-r--r--plugins/jetpack/modules/masterbar/admin-menu/class-wpcom-admin-menu.php461
-rw-r--r--plugins/jetpack/modules/masterbar/admin-menu/dashicon-set.php358
-rw-r--r--plugins/jetpack/modules/masterbar/admin-menu/load.php126
-rw-r--r--plugins/jetpack/modules/masterbar/admin-menu/menu-mappings.php31
16 files changed, 4398 insertions, 0 deletions
diff --git a/plugins/jetpack/modules/masterbar/admin-menu/admin-menu-rtl.css b/plugins/jetpack/modules/masterbar/admin-menu/admin-menu-rtl.css
new file mode 100644
index 00000000..854a83b1
--- /dev/null
+++ b/plugins/jetpack/modules/masterbar/admin-menu/admin-menu-rtl.css
@@ -0,0 +1,490 @@
+/* Do not modify this file directly. It is concatenated from individual module CSS files. */
+#adminmenu {
+ margin: 0;
+}
+
+/**
+ * Menu width
+ */
+#wpcontent,
+#wpfooter {
+ margin-right: 272px;
+}
+
+#adminmenuback,
+#adminmenuwrap,
+#adminmenu,
+#adminmenu .wp-submenu {
+ width: 272px;
+}
+
+#adminmenu .wp-submenu {
+ right: 272px;
+}
+
+#adminmenu .wp-not-current-submenu .wp-submenu,
+.folded #adminmenu .wp-has-current-submenu .wp-submenu {
+ min-width: 272px;
+}
+
+/**
+ * Fixes Gutenberg in not fullscreen mode.
+ */
+ @media (min-width: 783px) {
+ .interface-interface-skeleton,
+ .edit-post-layout .components-editor-notices__snackbar {
+ right: 272px;
+ }
+}
+
+@media (min-width: 961px) {
+ .auto-fold .interface-interface-skeleton,
+ .auto-fold .edit-post-layout .components-editor-notices__snackbar,
+ .jp-dialogue-modern-full__container {
+ right: 272px;
+ }
+
+ .global-notices {
+ max-width: calc( 100% - 48px - 272px );
+ }
+}
+
+/**
+ * Jetpack logo
+ */
+#adminmenu [class*="activity-log"] .wp-menu-image img {
+ padding-top: 7px;
+}
+
+/**
+ * Site Card
+ */
+#adminmenu .toplevel_page_site-card .wp-menu-name {
+ margin-right: 40px; /* icon width (32) + padding (8). */
+ padding: 0;
+}
+
+#adminmenu li.toplevel_page_site-card a {
+ padding: 10px 8px 10px 0;
+}
+
+/**
+ * Site Notices
+ */
+#adminmenu a.toplevel_page_site-notices:hover,
+#adminmenu a.toplevel_page_site-notices:focus,
+#adminmenu li.toplevel_page_site-notices:hover,
+#adminmenu li.toplevel_page_site-notices:focus {
+ background-color: inherit !important;
+ color: inherit !important;
+}
+
+#adminmenu li.toplevel_page_site-notices .wp-menu-image {
+ display: none;
+}
+
+#adminmenu .toplevel_page_site-notices .wp-menu-image {
+ border-radius: 2px;
+ background-color: #fff;
+}
+
+#adminmenu .toplevel_page_site-notices .wp-menu-image:before {
+ content: '\f534';
+ font-family: 'dashicons';
+ font-size: 20px;
+ line-height: 20px;
+ background-color: #a7aaad;
+ color: white;
+ border-radius: 50%;
+ margin: 5px;
+ padding: 0;
+}
+
+#adminmenu .toplevel_page_site-notices:hover .wp-menu-image:before {
+ color: #fff;
+}
+
+#adminmenu .toplevel_page_site-notices .upsell_banner {
+ display: flex;
+ flex-grow: 1;
+ flex-wrap: nowrap;
+ align-items: center;
+ justify-content: space-between;
+ position: relative;
+ width: 100%;
+ padding: 7px 12px;
+ right: -28px;
+ border-radius: 2px;
+ font-size: 12px;
+ line-height: 1.4;
+ -webkit-hyphens: none;
+ hyphens: none;
+}
+
+#adminmenu .toplevel_page_site-notices .upsell_banner .banner__info {
+ margin-left: 12px;
+}
+
+#adminmenu .toplevel_page_site-notices .upsell_banner .button {
+ font-size: 12px;
+ line-height: 12px;
+ padding: 0 7px;
+ border: 0;
+ min-height: 26px;
+}
+
+#adminmenu .toplevel_page_site-notices .upsell_banner svg.dismissible-card__close-icon {
+ height: 24px;
+ width: 24px;
+ margin-right: 10px;
+}
+
+@media screen and (min-width: 782px) {
+ .folded #adminmenu .toplevel_page_site-notices .wp-menu-image {
+ display: block;
+ width: 30px;
+ }
+
+ .folded #adminmenu .toplevel_page_site-notices {
+ height: 50px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+}
+
+@media screen and (min-width: 782px) and (max-width: 960px){
+ .auto-fold #adminmenu .toplevel_page_site-notices .wp-menu-image {
+ display: block;
+ width: 30px;
+ }
+
+ .auto-fold #adminmenu .toplevel_page_site-notices {
+ height: 50px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+}
+
+/* Prevent box-shadow at the top of the sidebar */
+#adminmenu .site-switcher:hover,
+#adminmenu .toplevel_page_site-card:hover,
+#adminmenu .toplevel_page_site-notices:hover {
+ box-shadow: none;
+}
+
+/**
+ * Site icon inline-styles for height and width are defined in set_site_icon_inline_styles
+ */
+#adminmenu .toplevel_page_site-card .wp-menu-image {
+ background-image: none;
+ background-position: center;
+ background-repeat: no-repeat;
+ background-size: 18px 18px;
+ transform: translateZ(0);
+ transition-property: background-image,background-color;
+ transition-duration: .2s;
+}
+
+#adminmenu a.toplevel_page_site-card:hover,
+#adminmenu li.toplevel_page_site-card:hover {
+ background-color: inherit;
+}
+
+#adminmenu .toplevel_page_site-card img {
+ opacity: initial;
+}
+
+#adminmenu .toplevel_page_site-card.has-site-icon img {
+ padding: 0;
+}
+
+#adminmenu .toplevel_page_site-card:hover div.wp-menu-image,
+#adminmenu .toplevel_page_site-card a:focus div.wp-menu-image {
+ background-image: url("data:image/svg+xml,%3Csvg class='gridicon gridicons-house' height='24' width='24' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg%3E%3Cpath fill='%23fff' d='M22 9L12 1 2 9v2h2v10h5v-4c0-1.657 1.343-3 3-3s3 1.343 3 3v4h5V11h2V9z'/%3E%3C/g%3E%3C/svg%3E%0A");
+}
+
+#adminmenu .toplevel_page_site-card:not(.has-site-icon) .wp-menu-image {
+ background-color: #c3c4c7;
+}
+
+#adminmenu .toplevel_page_site-card:not(.has-site-icon) .wp-menu-image img[src^="data:image/svg"] {
+ height: auto;
+ padding-top: 7px;
+ width: 18px;
+}
+
+#adminmenu .toplevel_page_site-card:hover div.wp-menu-image img,
+#adminmenu .toplevel_page_site-card a:focus div.wp-menu-image img {
+ display: none;
+}
+
+.site__info .site__title {
+ display: block;
+ font-size: 14px;
+ font-weight: 400;
+ line-height: 1.3;
+}
+
+.site__info .site__domain {
+ display: block;
+ max-width: 95%;
+ font-size: 12px;
+ line-height: 1.4;
+ margin-top: 2px;
+}
+
+.site__info .site__title,
+.site__info .site__domain {
+ overflow: hidden;
+ white-space: nowrap;
+}
+.site__info .site__title::after,
+.site__info .site__domain::after {
+ content: "";
+ display: block;
+ position: absolute;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ user-select: none;
+ pointer-events: none;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: auto;
+ width: 20%;
+ height: auto;
+}
+
+.site__info > .site__badge {
+ font-size: 12px;
+ border-radius: 12px;
+ clear: both;
+ display: inline-block;
+ margin-top: 6px;
+ margin-left: 3px;
+ padding: 1px 10px;
+}
+
+/**
+ * Inline text in a menu title
+ */
+.inline-text {
+ display: block !important;
+ position: absolute;
+ left: 20px;
+ top: 50%;
+ transform: translateY( -50% );
+ opacity: 0.8;
+}
+
+/**
+ * Stats
+ */
+[class*="toplevel_page_https://wordpress.com/stats/day"] .sidebar-unified__sparkline {
+ float: left;
+ margin-left: 8px;
+}
+
+/**
+ * Folded State
+ */
+.folded #adminmenu a.menu-top {
+ height: 31px;
+}
+
+.folded #adminmenu li.toplevel_page_site-card a {
+ padding-right: 0;
+}
+
+/* Auto-folding of the admin menu */
+@media only screen and (max-width: 960px) {
+ #adminmenu,
+ #adminmenuwrap,
+ #adminmenuback {
+ width: 272px;
+ }
+
+ .auto-fold #adminmenu a[class*="toplevel_page_http"].wp-first-item {
+ height: auto;
+ }
+
+ .wp-responsive-open #adminmenu a.menu-top {
+ height: auto;
+ }
+
+ .auto-fold #adminmenu div.wp-menu-image {
+ width: 36px;
+ }
+}
+
+@media screen and (min-width: 782px) and (max-width: 960px) {
+ .auto-fold #adminmenu a.menu-top {
+ height: 34px;
+ }
+
+ .auto-fold #adminmenu li.toplevel_page_site-card a {
+ height: 36px;
+ padding-right: 1px;
+ }
+}
+
+@media screen and (max-width: 782px) {
+ #adminmenu li.menu-top .wp-submenu>li>a,
+ .auto-fold #adminmenu li.menu-top .wp-submenu>li>a {
+ padding-right: 42px;
+ }
+
+ .wp-responsive-open #wpbody {
+ left: inherit;
+ }
+
+ .wp-responsive-open #wpcontent {
+ margin-right: 272px;
+ }
+
+ .auto-fold #adminmenu, .auto-fold #adminmenuback, .auto-fold #adminmenuwrap {
+ width: 272px;
+ }
+
+ .auto-fold #adminmenu a.site-switcher,
+ #adminmenu a.site-switcher {
+ font-size: 14px;
+ }
+}
+
+@media only screen and (max-width: 660px) {
+ #adminmenuback,
+ #adminmenuwrap,
+ #adminmenu,
+ #adminmenu .wp-submenu,
+ .auto-fold #adminmenu,
+ .auto-fold #adminmenuback,
+ .auto-fold #adminmenuwrap {
+ width: 100%;
+ z-index: 171;
+ }
+
+ .wp-responsive-open #wpcontent {
+ margin-right: 0;
+ }
+
+ ul#adminmenu a.wp-has-current-submenu:after,
+ ul#adminmenu>li.current>a.current:after,
+ ul#adminmenu li:hover a.wp-has-current-submenu:after,
+ .auto-fold ul#adminmenu li:hover a.wp-has-current-submenu:after {
+ display: none;
+ }
+
+ .auto-fold #adminmenu li.toplevel_page_site-card a {
+ padding: 18px 12px 18px 0;
+ }
+}
+
+/*
+ * Styles for the nav-unification prototype (see pbAPfg-O2)
+ * TODO: depending on project outcome move or delete styles
+ */
+#wpadminbar #wp-admin-bar-notes #wpnt-notes-unread-count.wpn-unread {
+ top: 50%;
+ right: 50%;
+ transform: translate( 10px, -13px );
+
+}
+
+#wpadminbar .quicklinks li#wp-admin-bar-my-account.with-avatar {
+ transform: translateX( -1px );
+}
+
+#wpadminbar #wp-admin-bar-notes.active .noticon-bell:before {
+ background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0Ij48cmVjdCB4PSIwIiBmaWxsPSJub25lIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiLz48Zz48cGF0aCBmaWxsPSIjZmZmZmZmIiBkPSJNNi4xNCAxNC45N2wyLjgyOCAyLjgyN2MtLjM2Mi4zNjItLjg2Mi41ODYtMS40MTQuNTg2LTEuMTA1IDAtMi0uODk1LTItMiAwLS41NTIuMjI0LTEuMDUyLjU4Ni0xLjQxNHptOC44NjcgNS4zMjRMMTQuMyAyMSAzIDkuN2wuNzA2LS43MDcgMS4xMDIuMTU3Yy43NTQuMTA4IDEuNjktLjEyMiAyLjA3Ny0uNTFsMy44ODUtMy44ODRjMi4zNC0yLjM0IDYuMTM1LTIuMzQgOC40NzUgMHMyLjM0IDYuMTM1IDAgOC40NzVsLTMuODg1IDMuODg2Yy0uMzg4LjM4OC0uNjE4IDEuMzIzLS41MSAyLjA3N2wuMTU3IDEuMXoiLz48L2c+PC9zdmc+") !important;
+}
+
+#wpadminbar > #wp-toolbar .wpnt-show span.noticon,
+#wpadminbar #wp-admin-bar-notes.wpnt-show .noticon {
+ color: #ffffff;
+}
+
+#wpadminbar .quicklinks ul#wp-admin-bar-root-default {
+ padding-right: 0 !important;
+}
+
+#wpadminbar #wp-admin-bar-menu-toggle {
+ display: none;
+}
+
+@media screen and (max-width: 782px) {
+ #wpadminbar #wp-toolbar > ul > li {
+ display: block;
+ }
+
+ #wpadminbar .ab-top-menu > li > .ab-item {
+ box-sizing: border-box;
+ line-height: 32px;
+ }
+
+ #wpadminbar #wp-admin-bar-ab-new-post > .ab-item {
+ box-sizing: inherit !important;
+ }
+
+ #wpadminbar #wp-admin-bar-my-account > .ab-item {
+ padding: 7px 15px;
+ width: auto;
+ }
+
+ #wpadminbar #wp-toolbar.quicklinks li#wp-admin-bar-my-account.with-avatar > a img {
+ display: block;
+ left: auto;
+ right: auto;
+ position: static;
+ margin-top: 3px;
+ top: 13px;
+ }
+
+ /* Hide debug bar. */
+ #wpadminbar #wp-toolbar.quicklinks li#wp-admin-bar-debug-bar {
+ display: none;
+ }
+}
+
+@media screen and (max-width: 480px) {
+ #wpadminbar #wp-toolbar.quicklinks li#wp-admin-bar-my-account.with-avatar > a {
+ width: auto;
+ }
+
+ #wpadminbar #wp-toolbar.quicklinks li#wp-admin-bar-my-account.with-avatar > a img {
+ margin-top: 12px;
+ }
+}
+
+/* Fixes the order of screen options,
+ * showing the dashboard switcher button always first.
+*/
+#adv-settings {
+ display: flex;
+ flex-direction: column;
+}
+
+/* Switcher should always be in the top */
+#adv-settings #dashboard-switcher {
+ order: 0;
+}
+
+#adv-settings .dashboard-switcher-text {
+ margin-top: 0;
+}
+
+#adv-settings .dashboard-switcher-button {
+ padding: 3px 16px;
+}
+
+/* Core registered options should be after the switcher */
+#adv-settings fieldset {
+ order: 1;
+}
+
+/* Submit button should always be in the bottom */
+#adv-settings .submit {
+ order: 2;
+}
diff --git a/plugins/jetpack/modules/masterbar/admin-menu/admin-menu-rtl.min.css b/plugins/jetpack/modules/masterbar/admin-menu/admin-menu-rtl.min.css
new file mode 100644
index 00000000..63bf1689
--- /dev/null
+++ b/plugins/jetpack/modules/masterbar/admin-menu/admin-menu-rtl.min.css
@@ -0,0 +1 @@
+#adminmenu{margin:0}#wpcontent,#wpfooter{margin-right:272px}#adminmenu,#adminmenu .wp-submenu,#adminmenuback,#adminmenuwrap{width:272px}#adminmenu .wp-submenu{right:272px}#adminmenu .wp-not-current-submenu .wp-submenu,.folded #adminmenu .wp-has-current-submenu .wp-submenu{min-width:272px}@media (min-width:783px){.edit-post-layout .components-editor-notices__snackbar,.interface-interface-skeleton{right:272px}}@media (min-width:961px){.auto-fold .edit-post-layout .components-editor-notices__snackbar,.auto-fold .interface-interface-skeleton,.jp-dialogue-modern-full__container{right:272px}.global-notices{max-width:calc(100% - 48px - 272px)}}#adminmenu [class*=activity-log] .wp-menu-image img{padding-top:7px}#adminmenu .toplevel_page_site-card .wp-menu-name{margin-right:40px;padding:0}#adminmenu li.toplevel_page_site-card a{padding:10px 8px 10px 0}#adminmenu a.toplevel_page_site-notices:focus,#adminmenu a.toplevel_page_site-notices:hover,#adminmenu li.toplevel_page_site-notices:focus,#adminmenu li.toplevel_page_site-notices:hover{background-color:inherit!important;color:inherit!important}#adminmenu li.toplevel_page_site-notices .wp-menu-image{display:none}#adminmenu .toplevel_page_site-notices .wp-menu-image{border-radius:2px;background-color:#fff}#adminmenu .toplevel_page_site-notices .wp-menu-image:before{content:'\f534';font-family:dashicons;font-size:20px;line-height:20px;background-color:#a7aaad;color:#fff;border-radius:50%;margin:5px;padding:0}#adminmenu .toplevel_page_site-notices:hover .wp-menu-image:before{color:#fff}#adminmenu .toplevel_page_site-notices .upsell_banner{display:flex;flex-grow:1;flex-wrap:nowrap;align-items:center;justify-content:space-between;position:relative;width:100%;padding:7px 12px;right:-28px;border-radius:2px;font-size:12px;line-height:1.4;-webkit-hyphens:none;hyphens:none}#adminmenu .toplevel_page_site-notices .upsell_banner .banner__info{margin-left:12px}#adminmenu .toplevel_page_site-notices .upsell_banner .button{font-size:12px;line-height:12px;padding:0 7px;border:0;min-height:26px}#adminmenu .toplevel_page_site-notices .upsell_banner svg.dismissible-card__close-icon{height:24px;width:24px;margin-right:10px}@media screen and (min-width:782px){.folded #adminmenu .toplevel_page_site-notices .wp-menu-image{display:block;width:30px}.folded #adminmenu .toplevel_page_site-notices{height:50px;display:flex;align-items:center;justify-content:center}}@media screen and (min-width:782px) and (max-width:960px){.auto-fold #adminmenu .toplevel_page_site-notices .wp-menu-image{display:block;width:30px}.auto-fold #adminmenu .toplevel_page_site-notices{height:50px;display:flex;align-items:center;justify-content:center}}#adminmenu .site-switcher:hover,#adminmenu .toplevel_page_site-card:hover,#adminmenu .toplevel_page_site-notices:hover{box-shadow:none}#adminmenu .toplevel_page_site-card .wp-menu-image{background-image:none;background-position:center;background-repeat:no-repeat;background-size:18px 18px;transform:translateZ(0);transition-property:background-image,background-color;transition-duration:.2s}#adminmenu a.toplevel_page_site-card:hover,#adminmenu li.toplevel_page_site-card:hover{background-color:inherit}#adminmenu .toplevel_page_site-card img{opacity:initial}#adminmenu .toplevel_page_site-card.has-site-icon img{padding:0}#adminmenu .toplevel_page_site-card a:focus div.wp-menu-image,#adminmenu .toplevel_page_site-card:hover div.wp-menu-image{background-image:url("data:image/svg+xml,%3Csvg class='gridicon gridicons-house' height='24' width='24' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg%3E%3Cpath fill='%23fff' d='M22 9L12 1 2 9v2h2v10h5v-4c0-1.657 1.343-3 3-3s3 1.343 3 3v4h5V11h2V9z'/%3E%3C/g%3E%3C/svg%3E%0A")}#adminmenu .toplevel_page_site-card:not(.has-site-icon) .wp-menu-image{background-color:#c3c4c7}#adminmenu .toplevel_page_site-card:not(.has-site-icon) .wp-menu-image img[src^="data:image/svg"]{height:auto;padding-top:7px;width:18px}#adminmenu .toplevel_page_site-card a:focus div.wp-menu-image img,#adminmenu .toplevel_page_site-card:hover div.wp-menu-image img{display:none}.site__info .site__title{display:block;font-size:14px;font-weight:400;line-height:1.3}.site__info .site__domain{display:block;max-width:95%;font-size:12px;line-height:1.4;margin-top:2px}.site__info .site__domain,.site__info .site__title{overflow:hidden;white-space:nowrap}.site__info .site__domain::after,.site__info .site__title::after{content:"";display:block;position:absolute;-webkit-touch-callout:none;-webkit-user-select:none;user-select:none;pointer-events:none;top:0;bottom:0;left:0;right:auto;width:20%;height:auto}.site__info>.site__badge{font-size:12px;border-radius:12px;clear:both;display:inline-block;margin-top:6px;margin-left:3px;padding:1px 10px}.inline-text{display:block!important;position:absolute;left:20px;top:50%;transform:translateY(-50%);opacity:.8}[class*="toplevel_page_https://wordpress.com/stats/day"] .sidebar-unified__sparkline{float:left;margin-left:8px}.folded #adminmenu a.menu-top{height:31px}.folded #adminmenu li.toplevel_page_site-card a{padding-right:0}@media only screen and (max-width:960px){#adminmenu,#adminmenuback,#adminmenuwrap{width:272px}.auto-fold #adminmenu a[class*=toplevel_page_http].wp-first-item{height:auto}.wp-responsive-open #adminmenu a.menu-top{height:auto}.auto-fold #adminmenu div.wp-menu-image{width:36px}}@media screen and (min-width:782px) and (max-width:960px){.auto-fold #adminmenu a.menu-top{height:34px}.auto-fold #adminmenu li.toplevel_page_site-card a{height:36px;padding-right:1px}}@media screen and (max-width:782px){#adminmenu li.menu-top .wp-submenu>li>a,.auto-fold #adminmenu li.menu-top .wp-submenu>li>a{padding-right:42px}.wp-responsive-open #wpbody{left:inherit}.wp-responsive-open #wpcontent{margin-right:272px}.auto-fold #adminmenu,.auto-fold #adminmenuback,.auto-fold #adminmenuwrap{width:272px}#adminmenu a.site-switcher,.auto-fold #adminmenu a.site-switcher{font-size:14px}}@media only screen and (max-width:660px){#adminmenu,#adminmenu .wp-submenu,#adminmenuback,#adminmenuwrap,.auto-fold #adminmenu,.auto-fold #adminmenuback,.auto-fold #adminmenuwrap{width:100%;z-index:171}.wp-responsive-open #wpcontent{margin-right:0}.auto-fold ul#adminmenu li:hover a.wp-has-current-submenu:after,ul#adminmenu a.wp-has-current-submenu:after,ul#adminmenu li:hover a.wp-has-current-submenu:after,ul#adminmenu>li.current>a.current:after{display:none}.auto-fold #adminmenu li.toplevel_page_site-card a{padding:18px 12px 18px 0}}#wpadminbar #wp-admin-bar-notes #wpnt-notes-unread-count.wpn-unread{top:50%;right:50%;transform:translate(10px,-13px)}#wpadminbar .quicklinks li#wp-admin-bar-my-account.with-avatar{transform:translateX(-1px)}#wpadminbar #wp-admin-bar-notes.active .noticon-bell:before{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0Ij48cmVjdCB4PSIwIiBmaWxsPSJub25lIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiLz48Zz48cGF0aCBmaWxsPSIjZmZmZmZmIiBkPSJNNi4xNCAxNC45N2wyLjgyOCAyLjgyN2MtLjM2Mi4zNjItLjg2Mi41ODYtMS40MTQuNTg2LTEuMTA1IDAtMi0uODk1LTItMiAwLS41NTIuMjI0LTEuMDUyLjU4Ni0xLjQxNHptOC44NjcgNS4zMjRMMTQuMyAyMSAzIDkuN2wuNzA2LS43MDcgMS4xMDIuMTU3Yy43NTQuMTA4IDEuNjktLjEyMiAyLjA3Ny0uNTFsMy44ODUtMy44ODRjMi4zNC0yLjM0IDYuMTM1LTIuMzQgOC40NzUgMHMyLjM0IDYuMTM1IDAgOC40NzVsLTMuODg1IDMuODg2Yy0uMzg4LjM4OC0uNjE4IDEuMzIzLS41MSAyLjA3N2wuMTU3IDEuMXoiLz48L2c+PC9zdmc+)!important}#wpadminbar #wp-admin-bar-notes.wpnt-show .noticon,#wpadminbar>#wp-toolbar .wpnt-show span.noticon{color:#fff}#wpadminbar .quicklinks ul#wp-admin-bar-root-default{padding-right:0!important}#wpadminbar #wp-admin-bar-menu-toggle{display:none}@media screen and (max-width:782px){#wpadminbar #wp-toolbar>ul>li{display:block}#wpadminbar .ab-top-menu>li>.ab-item{box-sizing:border-box;line-height:32px}#wpadminbar #wp-admin-bar-ab-new-post>.ab-item{box-sizing:inherit!important}#wpadminbar #wp-admin-bar-my-account>.ab-item{padding:7px 15px;width:auto}#wpadminbar #wp-toolbar.quicklinks li#wp-admin-bar-my-account.with-avatar>a img{display:block;left:auto;right:auto;position:static;margin-top:3px;top:13px}#wpadminbar #wp-toolbar.quicklinks li#wp-admin-bar-debug-bar{display:none}}@media screen and (max-width:480px){#wpadminbar #wp-toolbar.quicklinks li#wp-admin-bar-my-account.with-avatar>a{width:auto}#wpadminbar #wp-toolbar.quicklinks li#wp-admin-bar-my-account.with-avatar>a img{margin-top:12px}}#adv-settings{display:flex;flex-direction:column}#adv-settings #dashboard-switcher{order:0}#adv-settings .dashboard-switcher-text{margin-top:0}#adv-settings .dashboard-switcher-button{padding:3px 16px}#adv-settings fieldset{order:1}#adv-settings .submit{order:2} \ No newline at end of file
diff --git a/plugins/jetpack/modules/masterbar/admin-menu/admin-menu.css b/plugins/jetpack/modules/masterbar/admin-menu/admin-menu.css
new file mode 100644
index 00000000..92b762cb
--- /dev/null
+++ b/plugins/jetpack/modules/masterbar/admin-menu/admin-menu.css
@@ -0,0 +1,488 @@
+#adminmenu {
+ margin: 0;
+}
+
+/**
+ * Menu width
+ */
+#wpcontent,
+#wpfooter {
+ margin-left: 272px;
+}
+
+#adminmenuback,
+#adminmenuwrap,
+#adminmenu,
+#adminmenu .wp-submenu {
+ width: 272px;
+}
+
+#adminmenu .wp-submenu {
+ left: 272px;
+}
+
+#adminmenu .wp-not-current-submenu .wp-submenu,
+.folded #adminmenu .wp-has-current-submenu .wp-submenu {
+ min-width: 272px;
+}
+
+/**
+ * Fixes Gutenberg in not fullscreen mode.
+ */
+ @media (min-width: 783px) {
+ .interface-interface-skeleton,
+ .edit-post-layout .components-editor-notices__snackbar {
+ left: 272px;
+ }
+}
+
+@media (min-width: 961px) {
+ .auto-fold .interface-interface-skeleton,
+ .auto-fold .edit-post-layout .components-editor-notices__snackbar,
+ .jp-dialogue-modern-full__container {
+ left: 272px;
+ }
+
+ .global-notices {
+ max-width: calc( 100% - 48px - 272px );
+ }
+}
+
+/**
+ * Jetpack logo
+ */
+#adminmenu [class*="activity-log"] .wp-menu-image img {
+ padding-top: 7px;
+}
+
+/**
+ * Site Card
+ */
+#adminmenu .toplevel_page_site-card .wp-menu-name {
+ margin-left: 40px; /* icon width (32) + padding (8). */
+ padding: 0;
+}
+
+#adminmenu li.toplevel_page_site-card a {
+ padding: 10px 0 10px 8px;
+}
+
+/**
+ * Site Notices
+ */
+#adminmenu a.toplevel_page_site-notices:hover,
+#adminmenu a.toplevel_page_site-notices:focus,
+#adminmenu li.toplevel_page_site-notices:hover,
+#adminmenu li.toplevel_page_site-notices:focus {
+ background-color: inherit !important;
+ color: inherit !important;
+}
+
+#adminmenu li.toplevel_page_site-notices .wp-menu-image {
+ display: none;
+}
+
+#adminmenu .toplevel_page_site-notices .wp-menu-image {
+ border-radius: 2px;
+ background-color: #fff;
+}
+
+#adminmenu .toplevel_page_site-notices .wp-menu-image:before {
+ content: '\f534';
+ font-family: 'dashicons';
+ font-size: 20px;
+ line-height: 20px;
+ background-color: #a7aaad;
+ color: white;
+ border-radius: 50%;
+ margin: 5px;
+ padding: 0;
+}
+
+#adminmenu .toplevel_page_site-notices:hover .wp-menu-image:before {
+ color: #fff;
+}
+
+#adminmenu .toplevel_page_site-notices .upsell_banner {
+ display: flex;
+ flex-grow: 1;
+ flex-wrap: nowrap;
+ align-items: center;
+ justify-content: space-between;
+ position: relative;
+ width: 100%;
+ padding: 7px 12px;
+ left: -28px;
+ border-radius: 2px;
+ font-size: 12px;
+ line-height: 1.4;
+ hyphens: none;
+}
+
+#adminmenu .toplevel_page_site-notices .upsell_banner .banner__info {
+ margin-right: 12px;
+}
+
+#adminmenu .toplevel_page_site-notices .upsell_banner .button {
+ font-size: 12px;
+ line-height: 12px;
+ padding: 0 7px;
+ border: 0;
+ min-height: 26px;
+}
+
+#adminmenu .toplevel_page_site-notices .upsell_banner svg.dismissible-card__close-icon {
+ height: 24px;
+ width: 24px;
+ margin-left: 10px;
+}
+
+@media screen and (min-width: 782px) {
+ .folded #adminmenu .toplevel_page_site-notices .wp-menu-image {
+ display: block;
+ width: 30px;
+ }
+
+ .folded #adminmenu .toplevel_page_site-notices {
+ height: 50px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+}
+
+@media screen and (min-width: 782px) and (max-width: 960px){
+ .auto-fold #adminmenu .toplevel_page_site-notices .wp-menu-image {
+ display: block;
+ width: 30px;
+ }
+
+ .auto-fold #adminmenu .toplevel_page_site-notices {
+ height: 50px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+}
+
+/* Prevent box-shadow at the top of the sidebar */
+#adminmenu .site-switcher:hover,
+#adminmenu .toplevel_page_site-card:hover,
+#adminmenu .toplevel_page_site-notices:hover {
+ box-shadow: none;
+}
+
+/**
+ * Site icon inline-styles for height and width are defined in set_site_icon_inline_styles
+ */
+#adminmenu .toplevel_page_site-card .wp-menu-image {
+ background-image: none;
+ background-position: center;
+ background-repeat: no-repeat;
+ background-size: 18px 18px;
+ transform: translateZ(0);
+ transition-property: background-image,background-color;
+ transition-duration: .2s;
+}
+
+#adminmenu a.toplevel_page_site-card:hover,
+#adminmenu li.toplevel_page_site-card:hover {
+ background-color: inherit;
+}
+
+#adminmenu .toplevel_page_site-card img {
+ opacity: initial;
+}
+
+#adminmenu .toplevel_page_site-card.has-site-icon img {
+ padding: 0;
+}
+
+#adminmenu .toplevel_page_site-card:hover div.wp-menu-image,
+#adminmenu .toplevel_page_site-card a:focus div.wp-menu-image {
+ background-image: url("data:image/svg+xml,%3Csvg class='gridicon gridicons-house' height='24' width='24' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg%3E%3Cpath fill='%23fff' d='M22 9L12 1 2 9v2h2v10h5v-4c0-1.657 1.343-3 3-3s3 1.343 3 3v4h5V11h2V9z'/%3E%3C/g%3E%3C/svg%3E%0A");
+}
+
+#adminmenu .toplevel_page_site-card:not(.has-site-icon) .wp-menu-image {
+ background-color: #c3c4c7;
+}
+
+#adminmenu .toplevel_page_site-card:not(.has-site-icon) .wp-menu-image img[src^="data:image/svg"] {
+ height: auto;
+ padding-top: 7px;
+ width: 18px;
+}
+
+#adminmenu .toplevel_page_site-card:hover div.wp-menu-image img,
+#adminmenu .toplevel_page_site-card a:focus div.wp-menu-image img {
+ display: none;
+}
+
+.site__info .site__title {
+ display: block;
+ font-size: 14px;
+ font-weight: 400;
+ line-height: 1.3;
+}
+
+.site__info .site__domain {
+ display: block;
+ max-width: 95%;
+ font-size: 12px;
+ line-height: 1.4;
+ margin-top: 2px;
+}
+
+.site__info .site__title,
+.site__info .site__domain {
+ overflow: hidden;
+ white-space: nowrap;
+}
+.site__info .site__title::after,
+.site__info .site__domain::after {
+ content: "";
+ display: block;
+ position: absolute;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ user-select: none;
+ pointer-events: none;
+ top: 0;
+ bottom: 0;
+ right: 0;
+ left: auto;
+ width: 20%;
+ height: auto;
+}
+
+.site__info > .site__badge {
+ font-size: 12px;
+ border-radius: 12px;
+ clear: both;
+ display: inline-block;
+ margin-top: 6px;
+ margin-right: 3px;
+ padding: 1px 10px;
+}
+
+/**
+ * Inline text in a menu title
+ */
+.inline-text {
+ display: block !important;
+ position: absolute;
+ right: 20px;
+ top: 50%;
+ transform: translateY( -50% );
+ opacity: 0.8;
+}
+
+/**
+ * Stats
+ */
+[class*="toplevel_page_https://wordpress.com/stats/day"] .sidebar-unified__sparkline {
+ float: right;
+ margin-right: 8px;
+}
+
+/**
+ * Folded State
+ */
+.folded #adminmenu a.menu-top {
+ height: 31px;
+}
+
+.folded #adminmenu li.toplevel_page_site-card a {
+ padding-left: 0;
+}
+
+/* Auto-folding of the admin menu */
+@media only screen and (max-width: 960px) {
+ #adminmenu,
+ #adminmenuwrap,
+ #adminmenuback {
+ width: 272px;
+ }
+
+ .auto-fold #adminmenu a[class*="toplevel_page_http"].wp-first-item {
+ height: auto;
+ }
+
+ .wp-responsive-open #adminmenu a.menu-top {
+ height: auto;
+ }
+
+ .auto-fold #adminmenu div.wp-menu-image {
+ width: 36px;
+ }
+}
+
+@media screen and (min-width: 782px) and (max-width: 960px) {
+ .auto-fold #adminmenu a.menu-top {
+ height: 34px;
+ }
+
+ .auto-fold #adminmenu li.toplevel_page_site-card a {
+ height: 36px;
+ padding-left: 1px;
+ }
+}
+
+@media screen and (max-width: 782px) {
+ #adminmenu li.menu-top .wp-submenu>li>a,
+ .auto-fold #adminmenu li.menu-top .wp-submenu>li>a {
+ padding-left: 42px;
+ }
+
+ .wp-responsive-open #wpbody {
+ right: inherit;
+ }
+
+ .wp-responsive-open #wpcontent {
+ margin-left: 272px;
+ }
+
+ .auto-fold #adminmenu, .auto-fold #adminmenuback, .auto-fold #adminmenuwrap {
+ width: 272px;
+ }
+
+ .auto-fold #adminmenu a.site-switcher,
+ #adminmenu a.site-switcher {
+ font-size: 14px;
+ }
+}
+
+@media only screen and (max-width: 660px) {
+ #adminmenuback,
+ #adminmenuwrap,
+ #adminmenu,
+ #adminmenu .wp-submenu,
+ .auto-fold #adminmenu,
+ .auto-fold #adminmenuback,
+ .auto-fold #adminmenuwrap {
+ width: 100%;
+ z-index: 171;
+ }
+
+ .wp-responsive-open #wpcontent {
+ margin-left: 0;
+ }
+
+ ul#adminmenu a.wp-has-current-submenu:after,
+ ul#adminmenu>li.current>a.current:after,
+ ul#adminmenu li:hover a.wp-has-current-submenu:after,
+ .auto-fold ul#adminmenu li:hover a.wp-has-current-submenu:after {
+ display: none;
+ }
+
+ .auto-fold #adminmenu li.toplevel_page_site-card a {
+ padding: 18px 0 18px 12px;
+ }
+}
+
+/*
+ * Styles for the nav-unification prototype (see pbAPfg-O2)
+ * TODO: depending on project outcome move or delete styles
+ */
+#wpadminbar #wp-admin-bar-notes #wpnt-notes-unread-count.wpn-unread {
+ top: 50%;
+ left: 50%;
+ transform: translate( -10px, -13px );
+
+}
+
+#wpadminbar .quicklinks li#wp-admin-bar-my-account.with-avatar {
+ transform: translateX( 1px );
+}
+
+#wpadminbar #wp-admin-bar-notes.active .noticon-bell:before {
+ background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0Ij48cmVjdCB4PSIwIiBmaWxsPSJub25lIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiLz48Zz48cGF0aCBmaWxsPSIjZmZmZmZmIiBkPSJNNi4xNCAxNC45N2wyLjgyOCAyLjgyN2MtLjM2Mi4zNjItLjg2Mi41ODYtMS40MTQuNTg2LTEuMTA1IDAtMi0uODk1LTItMiAwLS41NTIuMjI0LTEuMDUyLjU4Ni0xLjQxNHptOC44NjcgNS4zMjRMMTQuMyAyMSAzIDkuN2wuNzA2LS43MDcgMS4xMDIuMTU3Yy43NTQuMTA4IDEuNjktLjEyMiAyLjA3Ny0uNTFsMy44ODUtMy44ODRjMi4zNC0yLjM0IDYuMTM1LTIuMzQgOC40NzUgMHMyLjM0IDYuMTM1IDAgOC40NzVsLTMuODg1IDMuODg2Yy0uMzg4LjM4OC0uNjE4IDEuMzIzLS41MSAyLjA3N2wuMTU3IDEuMXoiLz48L2c+PC9zdmc+") !important;
+}
+
+#wpadminbar > #wp-toolbar .wpnt-show span.noticon,
+#wpadminbar #wp-admin-bar-notes.wpnt-show .noticon {
+ color: #ffffff;
+}
+
+#wpadminbar .quicklinks ul#wp-admin-bar-root-default {
+ padding-left: 0 !important;
+}
+
+#wpadminbar #wp-admin-bar-menu-toggle {
+ display: none;
+}
+
+@media screen and (max-width: 782px) {
+ #wpadminbar #wp-toolbar > ul > li {
+ display: block;
+ }
+
+ #wpadminbar .ab-top-menu > li > .ab-item {
+ box-sizing: border-box;
+ line-height: 32px;
+ }
+
+ #wpadminbar #wp-admin-bar-ab-new-post > .ab-item {
+ box-sizing: inherit !important;
+ }
+
+ #wpadminbar #wp-admin-bar-my-account > .ab-item {
+ padding: 7px 15px;
+ width: auto;
+ }
+
+ #wpadminbar #wp-toolbar.quicklinks li#wp-admin-bar-my-account.with-avatar > a img {
+ display: block;
+ right: auto;
+ left: auto;
+ position: static;
+ margin-top: 3px;
+ top: 13px;
+ }
+
+ /* Hide debug bar. */
+ #wpadminbar #wp-toolbar.quicklinks li#wp-admin-bar-debug-bar {
+ display: none;
+ }
+}
+
+@media screen and (max-width: 480px) {
+ #wpadminbar #wp-toolbar.quicklinks li#wp-admin-bar-my-account.with-avatar > a {
+ width: auto;
+ }
+
+ #wpadminbar #wp-toolbar.quicklinks li#wp-admin-bar-my-account.with-avatar > a img {
+ margin-top: 12px;
+ }
+}
+
+/* Fixes the order of screen options,
+ * showing the dashboard switcher button always first.
+*/
+#adv-settings {
+ display: flex;
+ flex-direction: column;
+}
+
+/* Switcher should always be in the top */
+#adv-settings #dashboard-switcher {
+ order: 0;
+}
+
+#adv-settings .dashboard-switcher-text {
+ margin-top: 0;
+}
+
+#adv-settings .dashboard-switcher-button {
+ padding: 3px 16px;
+}
+
+/* Core registered options should be after the switcher */
+#adv-settings fieldset {
+ order: 1;
+}
+
+/* Submit button should always be in the bottom */
+#adv-settings .submit {
+ order: 2;
+}
diff --git a/plugins/jetpack/modules/masterbar/admin-menu/admin-menu.js b/plugins/jetpack/modules/masterbar/admin-menu/admin-menu.js
new file mode 100644
index 00000000..ce385913
--- /dev/null
+++ b/plugins/jetpack/modules/masterbar/admin-menu/admin-menu.js
@@ -0,0 +1,124 @@
+/* global ajaxurl, jetpackAdminMenu */
+
+( function () {
+ function init() {
+ var adminbar = document.querySelector( '#wpadminbar' );
+ var wpwrap = document.querySelector( '#wpwrap' );
+ var adminMenu = document.querySelector( '#adminmenu' );
+
+ if ( ! adminbar ) {
+ return;
+ }
+
+ function setAriaExpanded( value ) {
+ var anchors = adminbar.querySelectorAll( '#wp-admin-bar-blog a' );
+ for ( var i = 0; i < anchors.length; i++ ) {
+ anchors[ i ].setAttribute( 'aria-expanded', value );
+ }
+ }
+
+ setFocusOnActiveMenuItem();
+ setAriaExpanded( 'false' );
+
+ var adminbarBlog = adminbar.querySelector( '#wp-admin-bar-blog' );
+ // Toggle sidebar when toggle is clicked.
+ if ( adminbarBlog ) {
+ adminbarBlog.addEventListener( 'click', function ( event ) {
+ event.preventDefault();
+
+ // Close any open toolbar submenus.
+ var hovers = adminbar.querySelectorAll( '.hover' );
+ for ( var i = 0; i < hovers.length; i++ ) {
+ hovers[ i ].classList.remove( 'hover' );
+ }
+
+ wpwrap.classList.toggle( 'wp-responsive-open' );
+ if ( wpwrap.classList.contains( 'wp-responsive-open' ) ) {
+ setAriaExpanded( 'true' );
+ var first = document.querySelector( '#adminmenu a' );
+ if ( first ) {
+ first.focus();
+ }
+ } else {
+ setAriaExpanded( 'false' );
+ }
+ } );
+ }
+
+ if ( adminMenu ) {
+ var collapseButton = adminMenu.querySelector( '#collapse-button' );
+ // Nav-Unification feature:
+ // Saves the sidebar state in server when "Collapse menu" is clicked.
+ // This is needed so that we update WPCOM for this preference in real-time.
+ if ( collapseButton ) {
+ collapseButton.addEventListener( 'click', function ( event ) {
+ // Let's the core event listener be triggered first.
+ setTimeout( function () {
+ saveSidebarIsExpanded( event.target.parentNode.ariaExpanded );
+ }, 50 );
+ } );
+ }
+
+ const jitmDismissButton = adminMenu.querySelector( '.dismissible-card__close-icon' );
+ if ( jitmDismissButton ) {
+ jitmDismissButton.addEventListener( 'click', function ( event ) {
+ event.preventDefault();
+
+ const siteNotice = document.getElementById( 'toplevel_page_site-notices' );
+ if ( siteNotice ) {
+ siteNotice.style.display = 'none';
+ }
+
+ makeAjaxRequest(
+ 'POST',
+ ajaxurl,
+ 'application/x-www-form-urlencoded; charset=UTF-8',
+ 'id=' +
+ encodeURIComponent( jitmDismissButton.dataset.feature_id ) +
+ '&feature_class=' +
+ encodeURIComponent( jitmDismissButton.dataset.feature_class ) +
+ '&action=jitm_dismiss' +
+ '&_ajax_nonce=' +
+ jetpackAdminMenu.jitmDismissNonce
+ );
+ } );
+ }
+ }
+ }
+
+ function makeAjaxRequest( method, url, contentType, body ) {
+ var xhr = new XMLHttpRequest();
+ xhr.open( method, url, true );
+ xhr.setRequestHeader( 'X-Requested-With', 'XMLHttpRequest' );
+ if ( contentType ) {
+ xhr.setRequestHeader( 'Content-Type', contentType );
+ }
+ xhr.withCredentials = true;
+ xhr.send( body );
+ }
+
+ function saveSidebarIsExpanded( expanded ) {
+ makeAjaxRequest(
+ 'POST',
+ ajaxurl,
+ 'application/x-www-form-urlencoded; charset=UTF-8',
+ 'action=sidebar_state&expanded=' + expanded
+ );
+ }
+
+ function setFocusOnActiveMenuItem() {
+ var currentMenuItem = document.querySelector( '.wp-submenu .current > a' );
+
+ if ( ! currentMenuItem ) {
+ return;
+ }
+
+ currentMenuItem.focus();
+ }
+
+ if ( document.readyState === 'loading' ) {
+ document.addEventListener( 'DOMContentLoaded', init );
+ } else {
+ init();
+ }
+} )();
diff --git a/plugins/jetpack/modules/masterbar/admin-menu/admin-menu.min.css b/plugins/jetpack/modules/masterbar/admin-menu/admin-menu.min.css
new file mode 100644
index 00000000..1b50ea73
--- /dev/null
+++ b/plugins/jetpack/modules/masterbar/admin-menu/admin-menu.min.css
@@ -0,0 +1,2 @@
+/* Do not modify this file directly. It is concatenated from individual module CSS files. */
+#adminmenu{margin:0}#wpcontent,#wpfooter{margin-left:272px}#adminmenu,#adminmenu .wp-submenu,#adminmenuback,#adminmenuwrap{width:272px}#adminmenu .wp-submenu{left:272px}#adminmenu .wp-not-current-submenu .wp-submenu,.folded #adminmenu .wp-has-current-submenu .wp-submenu{min-width:272px}@media (min-width:783px){.edit-post-layout .components-editor-notices__snackbar,.interface-interface-skeleton{left:272px}}@media (min-width:961px){.auto-fold .edit-post-layout .components-editor-notices__snackbar,.auto-fold .interface-interface-skeleton,.jp-dialogue-modern-full__container{left:272px}.global-notices{max-width:calc(100% - 48px - 272px)}}#adminmenu [class*=activity-log] .wp-menu-image img{padding-top:7px}#adminmenu .toplevel_page_site-card .wp-menu-name{margin-left:40px;padding:0}#adminmenu li.toplevel_page_site-card a{padding:10px 0 10px 8px}#adminmenu a.toplevel_page_site-notices:focus,#adminmenu a.toplevel_page_site-notices:hover,#adminmenu li.toplevel_page_site-notices:focus,#adminmenu li.toplevel_page_site-notices:hover{background-color:inherit!important;color:inherit!important}#adminmenu li.toplevel_page_site-notices .wp-menu-image{display:none}#adminmenu .toplevel_page_site-notices .wp-menu-image{border-radius:2px;background-color:#fff}#adminmenu .toplevel_page_site-notices .wp-menu-image:before{content:'\f534';font-family:dashicons;font-size:20px;line-height:20px;background-color:#a7aaad;color:#fff;border-radius:50%;margin:5px;padding:0}#adminmenu .toplevel_page_site-notices:hover .wp-menu-image:before{color:#fff}#adminmenu .toplevel_page_site-notices .upsell_banner{display:flex;flex-grow:1;flex-wrap:nowrap;align-items:center;justify-content:space-between;position:relative;width:100%;padding:7px 12px;left:-28px;border-radius:2px;font-size:12px;line-height:1.4;-webkit-hyphens:none;hyphens:none}#adminmenu .toplevel_page_site-notices .upsell_banner .banner__info{margin-right:12px}#adminmenu .toplevel_page_site-notices .upsell_banner .button{font-size:12px;line-height:12px;padding:0 7px;border:0;min-height:26px}#adminmenu .toplevel_page_site-notices .upsell_banner svg.dismissible-card__close-icon{height:24px;width:24px;margin-left:10px}@media screen and (min-width:782px){.folded #adminmenu .toplevel_page_site-notices .wp-menu-image{display:block;width:30px}.folded #adminmenu .toplevel_page_site-notices{height:50px;display:flex;align-items:center;justify-content:center}}@media screen and (min-width:782px) and (max-width:960px){.auto-fold #adminmenu .toplevel_page_site-notices .wp-menu-image{display:block;width:30px}.auto-fold #adminmenu .toplevel_page_site-notices{height:50px;display:flex;align-items:center;justify-content:center}}#adminmenu .site-switcher:hover,#adminmenu .toplevel_page_site-card:hover,#adminmenu .toplevel_page_site-notices:hover{box-shadow:none}#adminmenu .toplevel_page_site-card .wp-menu-image{background-image:none;background-position:center;background-repeat:no-repeat;background-size:18px 18px;transform:translateZ(0);transition-property:background-image,background-color;transition-duration:.2s}#adminmenu a.toplevel_page_site-card:hover,#adminmenu li.toplevel_page_site-card:hover{background-color:inherit}#adminmenu .toplevel_page_site-card img{opacity:initial}#adminmenu .toplevel_page_site-card.has-site-icon img{padding:0}#adminmenu .toplevel_page_site-card a:focus div.wp-menu-image,#adminmenu .toplevel_page_site-card:hover div.wp-menu-image{background-image:url("data:image/svg+xml,%3Csvg class='gridicon gridicons-house' height='24' width='24' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg%3E%3Cpath fill='%23fff' d='M22 9L12 1 2 9v2h2v10h5v-4c0-1.657 1.343-3 3-3s3 1.343 3 3v4h5V11h2V9z'/%3E%3C/g%3E%3C/svg%3E%0A")}#adminmenu .toplevel_page_site-card:not(.has-site-icon) .wp-menu-image{background-color:#c3c4c7}#adminmenu .toplevel_page_site-card:not(.has-site-icon) .wp-menu-image img[src^="data:image/svg"]{height:auto;padding-top:7px;width:18px}#adminmenu .toplevel_page_site-card a:focus div.wp-menu-image img,#adminmenu .toplevel_page_site-card:hover div.wp-menu-image img{display:none}.site__info .site__title{display:block;font-size:14px;font-weight:400;line-height:1.3}.site__info .site__domain{display:block;max-width:95%;font-size:12px;line-height:1.4;margin-top:2px}.site__info .site__domain,.site__info .site__title{overflow:hidden;white-space:nowrap}.site__info .site__domain::after,.site__info .site__title::after{content:"";display:block;position:absolute;-webkit-touch-callout:none;-webkit-user-select:none;user-select:none;pointer-events:none;top:0;bottom:0;right:0;left:auto;width:20%;height:auto}.site__info>.site__badge{font-size:12px;border-radius:12px;clear:both;display:inline-block;margin-top:6px;margin-right:3px;padding:1px 10px}.inline-text{display:block!important;position:absolute;right:20px;top:50%;transform:translateY(-50%);opacity:.8}[class*="toplevel_page_https://wordpress.com/stats/day"] .sidebar-unified__sparkline{float:right;margin-right:8px}.folded #adminmenu a.menu-top{height:31px}.folded #adminmenu li.toplevel_page_site-card a{padding-left:0}@media only screen and (max-width:960px){#adminmenu,#adminmenuback,#adminmenuwrap{width:272px}.auto-fold #adminmenu a[class*=toplevel_page_http].wp-first-item{height:auto}.wp-responsive-open #adminmenu a.menu-top{height:auto}.auto-fold #adminmenu div.wp-menu-image{width:36px}}@media screen and (min-width:782px) and (max-width:960px){.auto-fold #adminmenu a.menu-top{height:34px}.auto-fold #adminmenu li.toplevel_page_site-card a{height:36px;padding-left:1px}}@media screen and (max-width:782px){#adminmenu li.menu-top .wp-submenu>li>a,.auto-fold #adminmenu li.menu-top .wp-submenu>li>a{padding-left:42px}.wp-responsive-open #wpbody{right:inherit}.wp-responsive-open #wpcontent{margin-left:272px}.auto-fold #adminmenu,.auto-fold #adminmenuback,.auto-fold #adminmenuwrap{width:272px}#adminmenu a.site-switcher,.auto-fold #adminmenu a.site-switcher{font-size:14px}}@media only screen and (max-width:660px){#adminmenu,#adminmenu .wp-submenu,#adminmenuback,#adminmenuwrap,.auto-fold #adminmenu,.auto-fold #adminmenuback,.auto-fold #adminmenuwrap{width:100%;z-index:171}.wp-responsive-open #wpcontent{margin-left:0}.auto-fold ul#adminmenu li:hover a.wp-has-current-submenu:after,ul#adminmenu a.wp-has-current-submenu:after,ul#adminmenu li:hover a.wp-has-current-submenu:after,ul#adminmenu>li.current>a.current:after{display:none}.auto-fold #adminmenu li.toplevel_page_site-card a{padding:18px 0 18px 12px}}#wpadminbar #wp-admin-bar-notes #wpnt-notes-unread-count.wpn-unread{top:50%;left:50%;transform:translate(-10px,-13px)}#wpadminbar .quicklinks li#wp-admin-bar-my-account.with-avatar{transform:translateX(1px)}#wpadminbar #wp-admin-bar-notes.active .noticon-bell:before{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0Ij48cmVjdCB4PSIwIiBmaWxsPSJub25lIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiLz48Zz48cGF0aCBmaWxsPSIjZmZmZmZmIiBkPSJNNi4xNCAxNC45N2wyLjgyOCAyLjgyN2MtLjM2Mi4zNjItLjg2Mi41ODYtMS40MTQuNTg2LTEuMTA1IDAtMi0uODk1LTItMiAwLS41NTIuMjI0LTEuMDUyLjU4Ni0xLjQxNHptOC44NjcgNS4zMjRMMTQuMyAyMSAzIDkuN2wuNzA2LS43MDcgMS4xMDIuMTU3Yy43NTQuMTA4IDEuNjktLjEyMiAyLjA3Ny0uNTFsMy44ODUtMy44ODRjMi4zNC0yLjM0IDYuMTM1LTIuMzQgOC40NzUgMHMyLjM0IDYuMTM1IDAgOC40NzVsLTMuODg1IDMuODg2Yy0uMzg4LjM4OC0uNjE4IDEuMzIzLS41MSAyLjA3N2wuMTU3IDEuMXoiLz48L2c+PC9zdmc+)!important}#wpadminbar #wp-admin-bar-notes.wpnt-show .noticon,#wpadminbar>#wp-toolbar .wpnt-show span.noticon{color:#fff}#wpadminbar .quicklinks ul#wp-admin-bar-root-default{padding-left:0!important}#wpadminbar #wp-admin-bar-menu-toggle{display:none}@media screen and (max-width:782px){#wpadminbar #wp-toolbar>ul>li{display:block}#wpadminbar .ab-top-menu>li>.ab-item{box-sizing:border-box;line-height:32px}#wpadminbar #wp-admin-bar-ab-new-post>.ab-item{box-sizing:inherit!important}#wpadminbar #wp-admin-bar-my-account>.ab-item{padding:7px 15px;width:auto}#wpadminbar #wp-toolbar.quicklinks li#wp-admin-bar-my-account.with-avatar>a img{display:block;right:auto;left:auto;position:static;margin-top:3px;top:13px}#wpadminbar #wp-toolbar.quicklinks li#wp-admin-bar-debug-bar{display:none}}@media screen and (max-width:480px){#wpadminbar #wp-toolbar.quicklinks li#wp-admin-bar-my-account.with-avatar>a{width:auto}#wpadminbar #wp-toolbar.quicklinks li#wp-admin-bar-my-account.with-avatar>a img{margin-top:12px}}#adv-settings{display:flex;flex-direction:column}#adv-settings #dashboard-switcher{order:0}#adv-settings .dashboard-switcher-text{margin-top:0}#adv-settings .dashboard-switcher-button{padding:3px 16px}#adv-settings fieldset{order:1}#adv-settings .submit{order:2} \ No newline at end of file
diff --git a/plugins/jetpack/modules/masterbar/admin-menu/class-admin-menu.php b/plugins/jetpack/modules/masterbar/admin-menu/class-admin-menu.php
new file mode 100644
index 00000000..46b7f8bf
--- /dev/null
+++ b/plugins/jetpack/modules/masterbar/admin-menu/class-admin-menu.php
@@ -0,0 +1,542 @@
+<?php
+/**
+ * Admin Menu file.
+ *
+ * @package automattic/jetpack
+ */
+
+namespace Automattic\Jetpack\Dashboard_Customizations;
+
+use Automattic\Jetpack\Redirect;
+
+require_once __DIR__ . '/class-base-admin-menu.php';
+
+/**
+ * Class Admin_Menu.
+ */
+class Admin_Menu extends Base_Admin_Menu {
+
+ /**
+ * Create the desired menu output.
+ */
+ public function reregister_menu_items() {
+ // Remove separators.
+ remove_menu_page( 'separator1' );
+
+ $this->add_stats_menu();
+ $this->add_upgrades_menu();
+ $this->add_posts_menu();
+ $this->add_media_menu();
+ $this->add_page_menu();
+ $this->add_testimonials_menu();
+ $this->add_portfolio_menu();
+ $this->add_comments_menu();
+ $this->add_appearance_menu();
+ $this->add_plugins_menu();
+ $this->add_users_menu();
+ $this->add_tools_menu();
+ $this->add_options_menu();
+ $this->add_jetpack_menu();
+ $this->add_gutenberg_menus();
+
+ // Remove Links Manager menu since its usage is discouraged. https://github.com/Automattic/wp-calypso/issues/51188.
+ // @see https://core.trac.wordpress.org/ticket/21307#comment:73.
+ if ( $this->should_disable_links_manager() ) {
+ remove_menu_page( 'link-manager.php' );
+ }
+
+ ksort( $GLOBALS['menu'] );
+ }
+
+ /**
+ * Get the preferred view for the given screen.
+ *
+ * @param string $screen Screen identifier.
+ * @param bool $fallback_global_preference (Optional) Whether the global preference for all screens should be used
+ * as fallback if there is no specific preference for the given screen.
+ * Default: true.
+ * @return string
+ */
+ public function get_preferred_view( $screen, $fallback_global_preference = true ) {
+ // When no preferred view has been set for "Users > All Users" or "Settings > General", keep the previous
+ // behavior that forced the default view regardless of the global preference.
+ if (
+ $fallback_global_preference &&
+ in_array( $screen, array( 'users.php', 'options-general.php' ), true )
+ ) {
+ $preferred_view = parent::get_preferred_view( $screen, false );
+ if ( self::UNKNOWN_VIEW === $preferred_view ) {
+ return self::DEFAULT_VIEW;
+ }
+ return $preferred_view;
+ }
+
+ return parent::get_preferred_view( $screen, $fallback_global_preference );
+ }
+
+ /**
+ * Check if Links Manager is being used.
+ */
+ public function should_disable_links_manager() {
+ // The max ID number of the auto-generated links.
+ // See /wp-content/mu-plugins/wpcom-wp-install-defaults.php in WP.com.
+ $max_default_id = 10;
+
+ // We are only checking the latest entry link_id so are limiting the query to 1.
+ $link_manager_links = get_bookmarks(
+ array(
+ 'orderby' => 'link_id',
+ 'order' => 'DESC',
+ 'limit' => 1,
+ 'hide_invisible' => 0,
+ )
+ );
+
+ // Ordered links by ID descending, check if the first ID is more than $max_default_id.
+ if ( count( $link_manager_links ) > 0 && $link_manager_links[0]->link_id > $max_default_id ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Adds My Home menu.
+ */
+ public function add_my_home_menu() {
+ $this->update_menu( 'index.php', 'https://wordpress.com/home/' . $this->domain, __( 'My Home', 'jetpack' ), 'edit_posts', 'dashicons-admin-home' );
+ }
+
+ /**
+ * Adds upsell nudge as a menu.
+ *
+ * @param object $nudge The $nudge object containing the content, CTA, link and tracks.
+ */
+ public function add_upsell_nudge( $nudge ) {
+ $dismiss_button = '';
+ if ( $nudge['dismissible'] ) {
+ $dismiss_button = '<svg xmlns="http://www.w3.org/2000/svg" data-feature_class="%1$s" data-feature_id="%2$s" viewBox="0 0 24 24" class="gridicon gridicons-cross dismissible-card__close-icon" height="24" width="24"><g><path d="M18.36 19.78L12 13.41l-6.36 6.37-1.42-1.42L10.59 12 4.22 5.64l1.42-1.42L12 10.59l6.36-6.36 1.41 1.41L13.41 12l6.36 6.36z"></path></g></svg>';
+ $dismiss_button = sprintf( $dismiss_button, esc_attr( $nudge['feature_class'] ), esc_attr( $nudge['id'] ) );
+ }
+
+ $message = '
+<div class="upsell_banner">
+ <div class="banner__info">
+ <div class="banner__title">%1$s</div>
+ </div>
+ <div class="banner__action">
+ <button type="button" class="button">%2$s</button>
+ </div>%3$s
+</div>';
+
+ $message = sprintf(
+ $message,
+ wp_kses( $nudge['content'], array() ),
+ wp_kses( $nudge['cta'], array() ),
+ $dismiss_button
+ );
+
+ $menu_slug = $nudge['link'];
+ if ( wp_startswith( $menu_slug, '/' ) ) {
+ $menu_slug = 'https://wordpress.com' . $menu_slug;
+ }
+
+ add_menu_page( 'site-notices', $message, 'read', $menu_slug, null, null, 1 );
+ add_filter( 'add_menu_classes', array( $this, 'set_site_notices_menu_class' ) );
+ }
+
+ /**
+ * Adds a custom element class and id for Site Notices's menu item.
+ *
+ * @param array $menu Associative array of administration menu items.
+ * @return array
+ */
+ public function set_site_notices_menu_class( array $menu ) {
+ foreach ( $menu as $key => $menu_item ) {
+ if ( 'site-notices' !== $menu_item[3] ) {
+ continue;
+ }
+
+ $classes = ' toplevel_page_site-notices';
+
+ if ( isset( $menu_item[4] ) ) {
+ $menu[ $key ][4] = $menu_item[4] . $classes;
+ $menu[ $key ][5] = 'toplevel_page_site-notices';
+ break;
+ }
+ }
+
+ return $menu;
+ }
+
+ /**
+ * Adds Inbox menu.
+ */
+ public function add_inbox_menu() {
+ add_menu_page( __( 'Inbox', 'jetpack' ), __( 'Inbox', 'jetpack' ), 'manage_options', 'https://wordpress.com/inbox/' . $this->domain, null, 'dashicons-email', '4.64424' );
+ }
+
+ /**
+ * Adds Stats menu.
+ */
+ public function add_stats_menu() {
+ add_menu_page( __( 'Stats', 'jetpack' ), __( 'Stats', 'jetpack' ), 'view_stats', 'https://wordpress.com/stats/day/' . $this->domain, null, 'dashicons-chart-bar', 3 );
+ }
+
+ /**
+ * Adds Upgrades menu.
+ *
+ * @param string $plan The current WPCOM plan of the blog.
+ */
+ public function add_upgrades_menu( $plan = null ) {
+ global $menu;
+
+ $menu_exists = false;
+ foreach ( $menu as $item ) {
+ if ( 'paid-upgrades.php' === $item[2] ) {
+ $menu_exists = true;
+ break;
+ }
+ }
+
+ if ( ! $menu_exists ) {
+ if ( $plan ) {
+ // Add display:none as a default for cases when CSS is not loaded.
+ $site_upgrades = '%1$s<span class="inline-text" style="display:none">%2$s</span>';
+ $site_upgrades = sprintf(
+ $site_upgrades,
+ __( 'Upgrades', 'jetpack' ),
+ $plan
+ );
+ } else {
+ $site_upgrades = __( 'Upgrades', 'jetpack' );
+ }
+
+ add_menu_page( __( 'Upgrades', 'jetpack' ), $site_upgrades, 'manage_options', 'paid-upgrades.php', null, 'dashicons-cart', 4 );
+ }
+
+ add_submenu_page( 'paid-upgrades.php', __( 'Plans', 'jetpack' ), __( 'Plans', 'jetpack' ), 'manage_options', 'https://wordpress.com/plans/' . $this->domain, null, 1 );
+ add_submenu_page( 'paid-upgrades.php', __( 'Purchases', 'jetpack' ), __( 'Purchases', 'jetpack' ), 'manage_options', 'https://wordpress.com/purchases/subscriptions/' . $this->domain, null, 2 );
+
+ if ( ! $menu_exists ) {
+ // Remove the submenu auto-created by Core.
+ $this->hide_submenu_page( 'paid-upgrades.php', 'paid-upgrades.php' );
+ }
+ }
+
+ /**
+ * Adds Posts menu.
+ */
+ public function add_posts_menu() {
+ $submenus_to_update = array();
+
+ if ( self::DEFAULT_VIEW === $this->get_preferred_view( 'edit.php' ) ) {
+ $submenus_to_update['edit.php'] = 'https://wordpress.com/posts/' . $this->domain;
+ $submenus_to_update['post-new.php'] = 'https://wordpress.com/post/' . $this->domain;
+ }
+
+ if ( self::DEFAULT_VIEW === $this->get_preferred_view( 'edit-tags.php?taxonomy=category' ) ) {
+ $submenus_to_update['edit-tags.php?taxonomy=category'] = 'https://wordpress.com/settings/taxonomies/category/' . $this->domain;
+ }
+
+ if ( self::DEFAULT_VIEW === $this->get_preferred_view( 'edit-tags.php?taxonomy=post_tag' ) ) {
+ $submenus_to_update['edit-tags.php?taxonomy=post_tag'] = 'https://wordpress.com/settings/taxonomies/post_tag/' . $this->domain;
+ }
+
+ $this->update_submenus( 'edit.php', $submenus_to_update );
+ }
+
+ /**
+ * Adds Media menu.
+ */
+ public function add_media_menu() {
+ if ( self::CLASSIC_VIEW === $this->get_preferred_view( 'upload.php' ) ) {
+ return;
+ }
+
+ $this->hide_submenu_page( 'upload.php', 'media-new.php' );
+
+ $this->update_menu( 'upload.php', 'https://wordpress.com/media/' . $this->domain );
+ }
+
+ /**
+ * Adds Page menu.
+ */
+ public function add_page_menu() {
+ if ( self::CLASSIC_VIEW === $this->get_preferred_view( 'edit.php?post_type=page' ) ) {
+ return;
+ }
+
+ $submenus_to_update = array(
+ 'edit.php?post_type=page' => 'https://wordpress.com/pages/' . $this->domain,
+ 'post-new.php?post_type=page' => 'https://wordpress.com/page/' . $this->domain,
+ );
+ $this->update_submenus( 'edit.php?post_type=page', $submenus_to_update );
+ }
+
+ /**
+ * Adds Testimonials menu.
+ */
+ public function add_testimonials_menu() {
+ $this->add_custom_post_type_menu( 'jetpack-testimonial' );
+ }
+
+ /**
+ * Adds Portfolio menu.
+ */
+ public function add_portfolio_menu() {
+ $this->add_custom_post_type_menu( 'jetpack-portfolio' );
+ }
+
+ /**
+ * Adds a custom post type menu.
+ *
+ * @param string $post_type Custom post type.
+ */
+ public function add_custom_post_type_menu( $post_type ) {
+ if ( self::CLASSIC_VIEW === $this->get_preferred_view( 'edit.php?post_type=' . $post_type ) ) {
+ return;
+ }
+
+ $submenus_to_update = array(
+ 'edit.php?post_type=' . $post_type => 'https://wordpress.com/types/' . $post_type . '/' . $this->domain,
+ 'post-new.php?post_type=' . $post_type => 'https://wordpress.com/edit/' . $post_type . '/' . $this->domain,
+ );
+ $this->update_submenus( 'edit.php?post_type=' . $post_type, $submenus_to_update );
+ }
+
+ /**
+ * Adds Comments menu.
+ */
+ public function add_comments_menu() {
+ if ( self::CLASSIC_VIEW === $this->get_preferred_view( 'edit-comments.php' ) ) {
+ return;
+ }
+
+ $this->update_menu( 'edit-comments.php', 'https://wordpress.com/comments/all/' . $this->domain );
+ }
+
+ /**
+ * Adds Appearance menu.
+ *
+ * @return string The Customizer URL.
+ */
+ public function add_appearance_menu() {
+ $request_uri = isset( $_SERVER['REQUEST_URI'] ) ? esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '';
+ $default_customize_slug = add_query_arg( 'return', rawurlencode( remove_query_arg( wp_removable_query_args(), $request_uri ) ), 'customize.php' );
+ $default_customize_header_slug_1 = add_query_arg( array( 'autofocus' => array( 'control' => 'header_image' ) ), $default_customize_slug );
+ // TODO: Remove WPCom_Theme_Customizer::modify_header_menu_links() and WPcom_Custom_Header::modify_admin_menu_links().
+ $default_customize_header_slug_2 = admin_url( 'themes.php?page=custom-header' );
+ $default_customize_background_slug_1 = add_query_arg( array( 'autofocus' => array( 'control' => 'background_image' ) ), $default_customize_slug );
+ // TODO: Remove Colors_Manager::modify_header_menu_links() and Colors_Manager_Common::modify_header_menu_links().
+ $default_customize_background_slug_2 = add_query_arg( array( 'autofocus' => array( 'section' => 'colors_manager_tool' ) ), admin_url( 'customize.php' ) );
+
+ if ( $this->is_api_request ) {
+ // In case this is an api request we will have to add the 'return' querystring via JS.
+ $customize_url = 'customize.php';
+ } else {
+ $customize_url = $default_customize_slug;
+ }
+
+ $submenus_to_update = array(
+ $default_customize_slug => $customize_url,
+ $default_customize_header_slug_1 => add_query_arg( array( 'autofocus' => array( 'control' => 'header_image' ) ), $customize_url ),
+ $default_customize_header_slug_2 => add_query_arg( array( 'autofocus' => array( 'control' => 'header_image' ) ), $customize_url ),
+ $default_customize_background_slug_1 => add_query_arg( array( 'autofocus' => array( 'section' => 'colors_manager_tool' ) ), $customize_url ),
+ $default_customize_background_slug_2 => add_query_arg( array( 'autofocus' => array( 'section' => 'colors_manager_tool' ) ), $customize_url ),
+ );
+
+ if ( self::DEFAULT_VIEW === $this->get_preferred_view( 'themes.php' ) ) {
+ $submenus_to_update['themes.php'] = 'https://wordpress.com/themes/' . $this->domain;
+ }
+
+ $this->update_submenus( 'themes.php', $submenus_to_update );
+
+ $this->hide_submenu_page( 'themes.php', 'custom-header' );
+ $this->hide_submenu_page( 'themes.php', 'custom-background' );
+
+ return $customize_url;
+ }
+
+ /**
+ * Adds Plugins menu.
+ */
+ public function add_plugins_menu() {
+ $this->hide_submenu_page( 'plugins.php', 'plugin-install.php' );
+ $this->hide_submenu_page( 'plugins.php', 'plugin-editor.php' );
+
+ $this->update_menu( 'plugins.php', 'https://wordpress.com/plugins/' . $this->domain );
+ }
+
+ /**
+ * Adds Users menu.
+ */
+ public function add_users_menu() {
+ $submenus_to_update = array(
+ 'profile.php' => 'https://wordpress.com/me',
+ );
+
+ if ( self::DEFAULT_VIEW === $this->get_preferred_view( 'users.php' ) ) {
+ $submenus_to_update['users.php'] = 'https://wordpress.com/people/team/' . $this->domain;
+ $submenus_to_update['user-new.php'] = 'https://wordpress.com/people/new/' . $this->domain;
+ }
+
+ $slug = current_user_can( 'list_users' ) ? 'users.php' : 'profile.php';
+ $this->update_submenus( $slug, $submenus_to_update );
+ add_submenu_page( $slug, esc_attr__( 'Account Settings', 'jetpack' ), __( 'Account Settings', 'jetpack' ), 'read', 'https://wordpress.com/me/account' );
+ }
+
+ /**
+ * Adds Tools menu.
+ */
+ public function add_tools_menu() {
+ $submenus_to_update = array();
+ if ( self::DEFAULT_VIEW === $this->get_preferred_view( 'import.php' ) ) {
+ $submenus_to_update['import.php'] = 'https://wordpress.com/import/' . $this->domain;
+ }
+ if ( self::DEFAULT_VIEW === $this->get_preferred_view( 'export.php' ) ) {
+ $submenus_to_update['export.php'] = 'https://wordpress.com/export/' . $this->domain;
+ }
+ $this->update_submenus( 'tools.php', $submenus_to_update );
+
+ $this->hide_submenu_page( 'tools.php', 'tools.php' );
+ $this->hide_submenu_page( 'tools.php', 'delete-blog' );
+
+ add_submenu_page( 'tools.php', esc_attr__( 'Marketing', 'jetpack' ), __( 'Marketing', 'jetpack' ), 'publish_posts', 'https://wordpress.com/marketing/tools/' . $this->domain, null, 0 );
+ add_submenu_page( 'tools.php', esc_attr__( 'Earn', 'jetpack' ), __( 'Earn', 'jetpack' ), 'manage_options', 'https://wordpress.com/earn/' . $this->domain, null, 1 );
+ }
+
+ /**
+ * Adds Settings menu.
+ */
+ public function add_options_menu() {
+ $submenus_to_update = array();
+
+ $this->hide_submenu_page( 'options-general.php', 'sharing' );
+
+ if ( self::DEFAULT_VIEW === $this->get_preferred_view( 'options-general.php' ) ) {
+ $submenus_to_update['options-general.php'] = 'https://wordpress.com/settings/general/' . $this->domain;
+ }
+
+ if ( self::DEFAULT_VIEW === $this->get_preferred_view( 'options-writing.php' ) ) {
+ $submenus_to_update['options-writing.php'] = 'https://wordpress.com/settings/writing/' . $this->domain;
+ }
+
+ if ( self::DEFAULT_VIEW === $this->get_preferred_view( 'options-discussion.php' ) ) {
+ $submenus_to_update['options-discussion.php'] = 'https://wordpress.com/settings/discussion/' . $this->domain;
+ }
+
+ $this->update_submenus( 'options-general.php', $submenus_to_update );
+
+ add_submenu_page( 'options-general.php', esc_attr__( 'Performance', 'jetpack' ), __( 'Performance', 'jetpack' ), 'manage_options', 'https://wordpress.com/settings/performance/' . $this->domain, null, 1 );
+ }
+
+ /**
+ * Adds Jetpack menu.
+ */
+ public function add_jetpack_menu() {
+ $this->add_admin_menu_separator( 50, 'manage_options' );
+
+ // TODO: Replace with proper SVG data url.
+ $icon = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 40 40' %3E%3Cpath fill='%23a0a5aa' d='M20 0c11.046 0 20 8.954 20 20s-8.954 20-20 20S0 31.046 0 20 8.954 0 20 0zm11 17H21v19l10-19zM19 4L9 23h10V4z'/%3E%3C/svg%3E";
+
+ $is_menu_updated = $this->update_menu( 'jetpack', null, null, null, $icon, 51 );
+ if ( ! $is_menu_updated ) {
+ add_menu_page( esc_attr__( 'Jetpack', 'jetpack' ), __( 'Jetpack', 'jetpack' ), 'manage_options', 'jetpack', null, $icon, 51 );
+ }
+
+ add_submenu_page( 'jetpack', esc_attr__( 'Activity Log', 'jetpack' ), __( 'Activity Log', 'jetpack' ), 'manage_options', 'https://wordpress.com/activity-log/' . $this->domain, null, 2 );
+ add_submenu_page( 'jetpack', esc_attr__( 'Backup', 'jetpack' ), __( 'Backup', 'jetpack' ), 'manage_options', 'https://wordpress.com/backup/' . $this->domain, null, 3 );
+ /* translators: Jetpack sidebar menu item. */
+ add_submenu_page( 'jetpack', esc_attr__( 'Search', 'jetpack' ), __( 'Search', 'jetpack' ), 'manage_options', 'https://wordpress.com/jetpack-search/' . $this->domain, null, 4 );
+
+ $this->hide_submenu_page( 'jetpack', 'jetpack#/settings' );
+ $this->hide_submenu_page( 'jetpack', 'stats' );
+ $this->hide_submenu_page( 'jetpack', esc_url( Redirect::get_url( 'calypso-backups' ) ) );
+ $this->hide_submenu_page( 'jetpack', esc_url( Redirect::get_url( 'calypso-scanner' ) ) );
+
+ if ( ! $is_menu_updated ) {
+ // Remove the submenu auto-created by Core just to be sure that there no issues on non-admin roles.
+ remove_submenu_page( 'jetpack', 'jetpack' );
+ }
+ }
+
+ /**
+ * Update Site Editor menu item's link and position.
+ */
+ public function add_gutenberg_menus() {
+ if ( self::CLASSIC_VIEW === $this->get_preferred_view( 'admin.php?page=gutenberg-edit-site' ) ) {
+ return;
+ }
+
+ $this->update_menu( 'gutenberg-edit-site', 'https://wordpress.com/site-editor/' . $this->domain, null, null, null, 59 );
+
+ // Gutenberg 11.9 moves the Site Editor to an Appearance submenu as Editor.
+ $submenus_to_update = array(
+ 'gutenberg-edit-site' => 'https://wordpress.com/site-editor/' . $this->domain,
+ );
+ $this->update_submenus( 'themes.php', $submenus_to_update );
+ // Gutenberg 11.9 adds an redundant site editor entry point that requires some calypso work
+ // before it can be exposed. Note, there are also already discussions to remove this excess
+ // item in Gutenberg.
+ $this->hide_submenu_page( 'themes.php', 'gutenberg-edit-site&styles=open' );
+ }
+
+ /**
+ * Add the calypso /woocommerce-installation/ menu item.
+ *
+ * @param array $current_plan The site's plan if they have one. This is passed from WPcom_Admin_Menu to prevent
+ * redundant database queries.
+ */
+ public function add_woocommerce_installation_menu( $current_plan = null ) {
+ /**
+ * Whether to show the WordPress.com WooCommerce Installation menu.
+ *
+ * @use add_filter( 'jetpack_show_wpcom_woocommerce_installation_menu', '__return_true' );
+ * @module masterbar
+ * @since 10.3.0
+ * @param bool $jetpack_show_wpcom_woocommerce_installation_menu Load the WordPress.com WooCommerce Installation menu item. Default to false.
+ * @param array $current_plan Data about the current site's plan.
+ */
+ if ( apply_filters( 'jetpack_show_wpcom_woocommerce_installation_menu', false, $current_plan ) ) {
+ $this->add_admin_menu_separator( 54, 'activate_plugins' );
+
+ $icon_url = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDI0IDEwMjQiPjxwYXRoIGZpbGw9IiNhMmFhYjIiIGQ9Ik02MTIuMTkyIDQyNi4zMzZjMC02Ljg5Ni0zLjEzNi01MS42LTI4LTUxLjYtMzcuMzYgMC00Ni43MDQgNzIuMjU2LTQ2LjcwNCA4Mi42MjQgMCAzLjQwOCAzLjE1MiA1OC40OTYgMjguMDMyIDU4LjQ5NiAzNC4xOTItLjAzMiA0Ni42NzItNzIuMjg4IDQ2LjY3Mi04OS41MnptMjAyLjE5MiAwYzAtNi44OTYtMy4xNTItNTEuNi0yOC4wMzItNTEuNi0zNy4yOCAwLTQ2LjYwOCA3Mi4yNTYtNDYuNjA4IDgyLjYyNCAwIDMuNDA4IDMuMDcyIDU4LjQ5NiAyNy45NTIgNTguNDk2IDM0LjE5Mi0uMDMyIDQ2LjY4OC03Mi4yODggNDYuNjg4LTg5LjUyek0xNDEuMjk2Ljc2OGMtNjguMjI0IDAtMTIzLjUwNCA1NS40ODgtMTIzLjUwNCAxMjMuOTJ2NjUwLjcyYzAgNjguNDMyIDU1LjI5NiAxMjMuOTIgMTIzLjUwNCAxMjMuOTJoMzM5LjgwOGwxMjMuNTA0IDEyMy45MzZWODk5LjMyOGgyNzguMDQ4YzY4LjIyNCAwIDEyMy41Mi01NS40NzIgMTIzLjUyLTEyMy45MnYtNjUwLjcyYzAtNjguNDMyLTU1LjI5Ni0xMjMuOTItMTIzLjUyLTEyMy45MmgtNzQxLjM2em01MjYuODY0IDQyMi4xNmMwIDU1LjA4OC0zMS4wODggMTU0Ljg4LTEwMi42NCAxNTQuODgtNi4yMDggMC0xOC40OTYtMy42MTYtMjUuNDI0LTYuMDE2LTMyLjUxMi0xMS4xNjgtNTAuMTkyLTQ5LjY5Ni01Mi4zNTItNjYuMjU2IDAgMC0zLjA3Mi0xNy43OTItMy4wNzItNDAuNzUyIDAtMjIuOTkyIDMuMDcyLTQ1LjMyOCAzLjA3Mi00NS4zMjggMTUuNTUyLTc1LjcyOCA0My41NTItMTA2LjczNiA5Ni40NDgtMTA2LjczNiA1OS4wNzItLjAzMiA4My45NjggNTguNTI4IDgzLjk2OCAxMTAuMjA4ek00ODYuNDk2IDMwMi40YzAgMy4zOTItNDMuNTUyIDE0MS4xNjgtNDMuNTUyIDIxMy40MjR2NzUuNzEyYy0yLjU5MiAxMi4wOC00LjE2IDI0LjE0NC0yMS44MjQgMjQuMTQ0LTQ2LjYwOCAwLTg4Ljg4LTE1MS40NzItOTIuMDE2LTE2MS44NC02LjIwOCA2Ljg5Ni02Mi4yNCAxNjEuODQtOTYuNDQ4IDE2MS44NC0yNC44NjQgMC00My41NTItMTEzLjY0OC00Ni42MDgtMTIzLjkzNkMxNzYuNzA0IDQzNi42NzIgMTYwIDMzNC4yMjQgMTYwIDMyNy4zMjhjMC0yMC42NzIgMS4xNTItMzguNzM2IDI2LjA0OC0zOC43MzYgNi4yMDggMCAyMS42IDYuMDY0IDIzLjcxMiAxNy4xNjggMTEuNjQ4IDYyLjAzMiAxNi42ODggMTIwLjUxMiAyOS4xNjggMTg1Ljk2OCAxLjg1NiAyLjkyOCAxLjUwNCA3LjAwOCA0LjU2IDEwLjQzMiAzLjE1Mi0xMC4yODggNjYuOTI4LTE2OC43ODQgOTQuOTYtMTY4Ljc4NCAyMi41NDQgMCAzMC40IDQ0LjU5MiAzMy41MzYgNjEuODI0IDYuMjA4IDIwLjY1NiAxMy4wODggNTUuMjE2IDIyLjQxNiA4Mi43NTIgMC0xMy43NzYgMTIuNDgtMjAzLjEyIDY1LjM5Mi0yMDMuMTIgMTguNTkyLjAzMiAyNi43MDQgNi45MjggMjYuNzA0IDI3LjU2OHpNODcwLjMyIDQyMi45MjhjMCA1NS4wODgtMzEuMDg4IDE1NC44OC0xMDIuNjQgMTU0Ljg4LTYuMTkyIDAtMTguNDQ4LTMuNjE2LTI1LjQyNC02LjAxNi0zMi40MzItMTEuMTY4LTUwLjE3Ni00OS42OTYtNTIuMjg4LTY2LjI1NiAwIDAtMy44ODgtMTcuOTItMy44ODgtNDAuODk2czMuODg4LTQ1LjE4NCAzLjg4OC00NS4xODRjMTUuNTUyLTc1LjcyOCA0My40ODgtMTA2LjczNiA5Ni4zODQtMTA2LjczNiA1OS4xMDQtLjAzMiA4My45NjggNTguNTI4IDgzLjk2OCAxMTAuMjA4eiIvPjwvc3ZnPg==';
+ $menu_url = 'https://wordpress.com/woocommerce-installation/' . $this->domain;
+
+ // Only show the menu if the user has the capability to activate_plugins.
+ add_menu_page( esc_attr__( 'WooCommerce', 'jetpack' ), esc_attr__( 'WooCommerce', 'jetpack' ), 'activate_plugins', $menu_url, null, $icon_url, 55 );
+ }
+ }
+
+ /**
+ * Prepend a dashboard swithcer to the "Screen Options" box of the current page.
+ * Callback for the 'screen_settings' filter (available in WP 3.0 and up).
+ *
+ * @param string $current The currently added panels in screen options.
+ *
+ * @return string The HTML code to append to "Screen Options"
+ */
+ public function register_dashboard_switcher( $current ) {
+ $menu_mappings = require __DIR__ . '/menu-mappings.php';
+ $screen = $this->get_current_screen();
+
+ // Let's show the switcher only in screens that we have a Calypso mapping to switch to.
+ if ( ! isset( $menu_mappings[ $screen ] ) ) {
+ return;
+ }
+
+ $contents = sprintf(
+ '<div id="dashboard-switcher"><h5>%s</h5><p class="dashboard-switcher-text">%s</p><a class="button button-primary dashboard-switcher-button" href="%s">%s</a></div>',
+ __( 'Screen features', 'jetpack' ),
+ __( 'Currently you are seeing the classic WP-Admin view of this page. Would you like to see the default WordPress.com view?', 'jetpack' ),
+ add_query_arg( 'preferred-view', 'default' ),
+ __( 'Use WordPress.com view', 'jetpack' )
+ );
+
+ // Prepend the Dashboard swither to the other custom panels.
+ $current = $contents . $current;
+
+ return $current;
+ }
+}
diff --git a/plugins/jetpack/modules/masterbar/admin-menu/class-atomic-admin-menu.php b/plugins/jetpack/modules/masterbar/admin-menu/class-atomic-admin-menu.php
new file mode 100644
index 00000000..b3bd7c64
--- /dev/null
+++ b/plugins/jetpack/modules/masterbar/admin-menu/class-atomic-admin-menu.php
@@ -0,0 +1,427 @@
+<?php
+/**
+ * Atomic Admin Menu file.
+ *
+ * @package automattic/jetpack
+ */
+
+namespace Automattic\Jetpack\Dashboard_Customizations;
+
+use Automattic\Jetpack\Connection\Client;
+use Jetpack_Plan;
+
+require_once __DIR__ . '/class-admin-menu.php';
+
+/**
+ * Class Atomic_Admin_Menu.
+ */
+class Atomic_Admin_Menu extends Admin_Menu {
+
+ /**
+ * Atomic_Admin_Menu constructor.
+ */
+ protected function __construct() {
+ parent::__construct();
+
+ add_action( 'wp_enqueue_scripts', array( $this, 'dequeue_scripts' ), 20 );
+ add_action( 'admin_enqueue_scripts', array( $this, 'dequeue_scripts' ), 20 );
+ add_action( 'wp_ajax_sidebar_state', array( $this, 'ajax_sidebar_state' ) );
+ add_action( 'wp_ajax_jitm_dismiss', array( $this, 'wp_ajax_jitm_dismiss' ) );
+
+ if ( ! $this->is_api_request ) {
+ add_filter( 'submenu_file', array( $this, 'override_the_theme_installer' ), 10, 2 );
+ }
+
+ add_action(
+ 'admin_menu',
+ function () {
+ remove_action( 'admin_menu', 'gutenberg_menu', 9 );
+ },
+ 0
+ );
+ }
+
+ /**
+ * Dequeues unnecessary scripts.
+ */
+ public function dequeue_scripts() {
+ wp_dequeue_script( 'a8c_wpcom_masterbar_overrides' ); // Initially loaded in modules/masterbar/masterbar/class-masterbar.php.
+ }
+
+ /**
+ * Determines whether the current locale is right-to-left (RTL).
+ *
+ * Performs the check against the current locale set on the WordPress.com's account settings.
+ * See `Masterbar::__construct` in `modules/masterbar/masterbar/class-masterbar.php`.
+ */
+ public function is_rtl() {
+ return get_user_option( 'jetpack_wpcom_is_rtl' );
+ }
+
+ /**
+ * Create the desired menu output.
+ */
+ public function reregister_menu_items() {
+ parent::reregister_menu_items();
+
+ $this->add_my_home_menu();
+ $this->add_inbox_menu();
+ $this->hide_search_menu_for_calypso();
+
+ // Not needed outside of wp-admin.
+ if ( ! $this->is_api_request ) {
+ $this->add_browse_sites_link();
+ $this->add_site_card_menu();
+ $nudge = $this->get_upsell_nudge();
+ if ( $nudge ) {
+ parent::add_upsell_nudge( $nudge );
+ }
+
+ $this->add_new_site_link();
+ }
+
+ $this->add_woocommerce_installation_menu();
+
+ ksort( $GLOBALS['menu'] );
+ }
+
+ /**
+ * Get the preferred view for the given screen.
+ *
+ * @param string $screen Screen identifier.
+ * @param bool $fallback_global_preference (Optional) Whether the global preference for all screens should be used
+ * as fallback if there is no specific preference for the given screen.
+ * Default: true.
+ * @return string
+ */
+ public function get_preferred_view( $screen, $fallback_global_preference = true ) {
+ // Export on Atomic sites are always managed on WP Admin.
+ if ( in_array( $screen, array( 'export.php' ), true ) ) {
+ return self::CLASSIC_VIEW;
+ }
+
+ /**
+ * When Jetpack SSO is disabled, we need to force Calypso because it might create confusion to be redirected to WP-Admin.
+ * Furthermore, because we don't display the quick switcher, users having an WP-Admin interface by default won't be able to go back to the Calyso version.
+ */
+ if ( ! \Jetpack::is_module_active( 'sso' ) ) {
+ return self::DEFAULT_VIEW;
+ }
+
+ return parent::get_preferred_view( $screen, $fallback_global_preference );
+ }
+
+ /**
+ * Adds Plugins menu.
+ */
+ public function add_plugins_menu() {
+ global $submenu;
+ if (
+ isset( $submenu['plugins.php'] )
+ /**
+ * Whether to enable the marketplace feature entrypoint.
+ * This filter is specific to WPCOM, that's why there is no
+ * need to use `jetpack_` prefix.
+ *
+ * @use add_filter( 'wpcom_marketplace_enabled', '__return_true' );
+ * @module masterbar
+ * @since 10.3
+ * @param bool $wpcom_marketplace_enabled Load the WordPress.com Marketplace feature. Default to false.
+ */
+ && apply_filters( 'wpcom_marketplace_enabled', false )
+ ) {
+ $plugins_submenu = $submenu['plugins.php'];
+ $slug_to_update = 'plugin-install.php';
+
+ // Move "Add New" plugin submenu ( `plugin-install.php` ) to the top position.
+ foreach ( $plugins_submenu as $submenu_key => $submenu_keys ) {
+ if ( $submenu_keys[2] === $slug_to_update ) {
+ // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
+ $submenu['plugins.php'] = array( $submenu_key => $plugins_submenu[ $submenu_key ] ) + $plugins_submenu;
+ }
+ }
+
+ $submenus_to_update = array( $slug_to_update => 'https://wordpress.com/plugins/' . $this->domain );
+ $this->update_submenus( 'plugins.php', $submenus_to_update );
+ }
+ }
+
+ /**
+ * Adds the site switcher link if user has more than one site.
+ */
+ public function add_browse_sites_link() {
+ $site_count = get_user_option( 'wpcom_site_count' );
+ if ( ! $site_count || $site_count < 2 ) {
+ return;
+ }
+
+ // Add the menu item.
+ add_menu_page( __( 'site-switcher', 'jetpack' ), __( 'Browse sites', 'jetpack' ), 'read', 'https://wordpress.com/home', null, 'dashicons-arrow-left-alt2', 0 );
+ add_filter( 'add_menu_classes', array( $this, 'set_browse_sites_link_class' ) );
+ }
+
+ /**
+ * Adds a custom element class for Site Switcher menu item.
+ *
+ * @param array $menu Associative array of administration menu items.
+ *
+ * @return array
+ */
+ public function set_browse_sites_link_class( array $menu ) {
+ foreach ( $menu as $key => $menu_item ) {
+ if ( 'site-switcher' !== $menu_item[3] ) {
+ continue;
+ }
+
+ $menu[ $key ][4] = add_cssclass( 'site-switcher', $menu_item[4] );
+ break;
+ }
+
+ return $menu;
+ }
+
+ /**
+ * Adds a link to the menu to create a new site.
+ */
+ public function add_new_site_link() {
+ $site_count = get_user_option( 'wpcom_site_count' );
+ if ( $site_count && $site_count > 1 ) {
+ return;
+ }
+
+ $this->add_admin_menu_separator();
+ add_menu_page( __( 'Add New Site', 'jetpack' ), __( 'Add New Site', 'jetpack' ), 'read', 'https://wordpress.com/start?ref=calypso-sidebar', null, 'dashicons-plus-alt' );
+ }
+
+ /**
+ * Adds site card component.
+ */
+ public function add_site_card_menu() {
+ $default = 'data:image/svg+xml,' . rawurlencode( '<svg class="gridicon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>Globe</title><rect fill-opacity="0" x="0" width="24" height="24"/><g><path fill="#fff" d="M12 2C6.477 2 2 6.477 2 12s4.477 10 10 10 10-4.477 10-10S17.523 2 12 2zm0 18l2-2 1-1v-2h-2v-1l-1-1H9v3l2 2v1.93c-3.94-.494-7-3.858-7-7.93l1 1h2v-2h2l3-3V6h-2L9 5v-.41C9.927 4.21 10.94 4 12 4s2.073.212 3 .59V6l-1 1v2l1 1 3.13-3.13c.752.897 1.304 1.964 1.606 3.13H18l-2 2v2l1 1h2l.286.286C18.03 18.06 15.24 20 12 20z"/></g></svg>' );
+ $icon = get_site_icon_url( 32, $default );
+ $blog_name = get_option( 'blogname' ) !== '' ? get_option( 'blogname' ) : $this->domain;
+ $is_coming_soon = ( function_exists( 'site_is_coming_soon' ) && site_is_coming_soon() ) || (bool) get_option( 'wpcom_public_coming_soon' );
+
+ $badge = '';
+ if ( ( function_exists( 'site_is_private' ) && site_is_private() ) || $is_coming_soon ) {
+ $badge .= sprintf(
+ '<span class="site__badge site__badge-private">%s</span>',
+ $is_coming_soon ? esc_html__( 'Coming Soon', 'jetpack' ) : esc_html__( 'Private', 'jetpack' )
+ );
+ }
+
+ $site_card = '
+<div class="site__info">
+ <div class="site__title">%1$s</div>
+ <div class="site__domain">%2$s</div>
+ %3$s
+</div>';
+
+ $site_card = sprintf(
+ $site_card,
+ $blog_name,
+ $this->domain,
+ $badge
+ );
+
+ add_menu_page( 'site-card', $site_card, 'read', get_home_url(), null, $icon, 1 );
+ add_filter( 'add_menu_classes', array( $this, 'set_site_card_menu_class' ) );
+ }
+
+ /**
+ * Adds a custom element class and id for Site Card's menu item.
+ *
+ * @param array $menu Associative array of administration menu items.
+ *
+ * @return array
+ */
+ public function set_site_card_menu_class( array $menu ) {
+ foreach ( $menu as $key => $menu_item ) {
+ if ( 'site-card' !== $menu_item[3] ) {
+ continue;
+ }
+
+ $classes = ' toplevel_page_site-card';
+
+ // webclip.png is the default on WoA sites. Anything other than that means we have a custom site icon.
+ if ( has_site_icon() && 'https://s0.wp.com/i/webclip.png' !== get_site_icon_url( 512 ) ) {
+ $classes .= ' has-site-icon';
+ }
+
+ $menu[ $key ][4] = $menu_item[4] . $classes;
+ $menu[ $key ][5] = 'toplevel_page_site_card';
+ break;
+ }
+
+ return $menu;
+ }
+
+ /**
+ * Returns the first available upsell nudge.
+ *
+ * @return array
+ */
+ public function get_upsell_nudge() {
+ $jitm = \Automattic\Jetpack\JITMS\JITM::get_instance();
+ $message_path = 'calypso:sites:sidebar_notice';
+ $message = $jitm->get_messages( $message_path, wp_json_encode( array( 'message_path' => $message_path ) ), false );
+
+ if ( isset( $message[0] ) ) {
+ $message = $message[0];
+ return array(
+ 'content' => $message->content->message,
+ 'cta' => $message->CTA->message, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
+ 'link' => $message->CTA->link, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
+ 'tracks_impression_event_name' => $message->tracks->display->name,
+ 'tracks_impression_cta_name' => $message->tracks->display->props->cta_name,
+ 'tracks_click_event_name' => $message->tracks->click->name,
+ 'tracks_click_cta_name' => $message->tracks->click->props->cta_name,
+ 'dismissible' => $message->is_dismissible,
+ 'feature_class' => $message->feature_class,
+ 'id' => $message->id,
+ );
+ }
+ }
+
+ /**
+ * Adds Stats menu.
+ */
+ public function add_stats_menu() {
+ $menu_title = __( 'Stats', 'jetpack' );
+
+ if (
+ ! $this->is_api_request &&
+ \Jetpack::is_module_active( 'stats' ) &&
+ function_exists( 'stats_get_image_chart_src' )
+ ) {
+ $img_src = esc_attr(
+ stats_get_image_chart_src( 'admin-bar-hours-scale-2x', array( 'masterbar' => '' ) )
+ );
+ $alt = esc_attr__( 'Hourly views', 'jetpack' );
+
+ $menu_title .= "<img class='sidebar-unified__sparkline' src='$img_src' width='80' height='20' alt='$alt'>";
+ }
+
+ add_menu_page( __( 'Stats', 'jetpack' ), $menu_title, 'edit_posts', 'https://wordpress.com/stats/day/' . $this->domain, null, 'dashicons-chart-bar', 3 );
+ }
+
+ /**
+ * Adds Upgrades menu.
+ *
+ * @param string $plan The current WPCOM plan of the blog.
+ */
+ public function add_upgrades_menu( $plan = null ) {
+ $products = Jetpack_Plan::get();
+ if ( array_key_exists( 'product_name_short', $products ) ) {
+ $plan = $products['product_name_short'];
+ }
+ parent::add_upgrades_menu( $plan );
+
+ $last_upgrade_submenu_position = $this->get_submenu_item_count( 'paid-upgrades.php' );
+
+ add_submenu_page( 'paid-upgrades.php', __( 'Domains', 'jetpack' ), __( 'Domains', 'jetpack' ), 'manage_options', 'https://wordpress.com/domains/manage/' . $this->domain, null, $last_upgrade_submenu_position - 1 );
+
+ /**
+ * Whether to show the WordPress.com Emails submenu under the main Upgrades menu.
+ *
+ * @use add_filter( 'jetpack_show_wpcom_upgrades_email_menu', '__return_true' );
+ * @module masterbar
+ *
+ * @since 9.7.0
+ *
+ * @param bool $show_wpcom_upgrades_email_menu Load the WordPress.com Emails submenu item. Default to false.
+ */
+ if ( apply_filters( 'jetpack_show_wpcom_upgrades_email_menu', false ) ) {
+ add_submenu_page( 'paid-upgrades.php', __( 'Emails', 'jetpack' ), __( 'Emails', 'jetpack' ), 'manage_options', 'https://wordpress.com/email/' . $this->domain, null, $last_upgrade_submenu_position );
+ }
+ }
+
+ /**
+ * Adds Settings menu.
+ */
+ public function add_options_menu() {
+ parent::add_options_menu();
+
+ if ( Jetpack_Plan::supports( 'security-settings' ) ) {
+ add_submenu_page(
+ 'options-general.php',
+ esc_attr__( 'Security', 'jetpack' ),
+ __( 'Security', 'jetpack' ),
+ 'manage_options',
+ 'https://wordpress.com/settings/security/' . $this->domain,
+ null,
+ 2
+ );
+ }
+ add_submenu_page( 'options-general.php', esc_attr__( 'Hosting Configuration', 'jetpack' ), __( 'Hosting Configuration', 'jetpack' ), 'manage_options', 'https://wordpress.com/hosting-config/' . $this->domain, null, 11 );
+ add_submenu_page( 'options-general.php', esc_attr__( 'Jetpack', 'jetpack' ), __( 'Jetpack', 'jetpack' ), 'manage_options', 'https://wordpress.com/settings/jetpack/' . $this->domain, null, 12 );
+
+ // Page Optimize is active by default on all Atomic sites and registers a Settings > Performance submenu which
+ // would conflict with our own Settings > Performance that links to Calypso, so we hide it it since the Calypso
+ // performance settings already have a link to Page Optimize settings page.
+ $this->hide_submenu_page( 'options-general.php', 'page-optimize' );
+ }
+
+ /**
+ * Override the global submenu_file for theme-install.php page so the WP Admin menu item gets highlighted correctly.
+ *
+ * @param string $submenu_file The current pages $submenu_file global variable value.
+ * @return string | null
+ */
+ public function override_the_theme_installer( $submenu_file ) {
+ global $pagenow;
+
+ if ( 'themes.php' === $submenu_file && 'theme-install.php' === $pagenow ) {
+ return null;
+ }
+ return $submenu_file;
+ }
+
+ /**
+ * Also remove the Gutenberg plugin menu.
+ */
+ public function add_gutenberg_menus() {
+ // Always remove the Gutenberg menu.
+ remove_menu_page( 'gutenberg' );
+ parent::add_gutenberg_menus();
+ }
+
+ /**
+ * Saves the sidebar state ( expanded / collapsed ) via an ajax request.
+ */
+ public function ajax_sidebar_state() {
+ $expanded = filter_var( $_REQUEST['expanded'], FILTER_VALIDATE_BOOLEAN ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ Client::wpcom_json_api_request_as_user(
+ '/me/preferences',
+ '2',
+ array(
+ 'method' => 'POST',
+ ),
+ (object) array( 'calypso_preferences' => (object) array( 'sidebarCollapsed' => ! $expanded ) ),
+ 'wpcom'
+ );
+
+ wp_die();
+ }
+
+ /**
+ * Handle ajax requests to dismiss a just-in-time-message
+ */
+ public function wp_ajax_jitm_dismiss() {
+ check_ajax_referer( 'jitm_dismiss' );
+ $jitm = \Automattic\Jetpack\JITMS\JITM::get_instance();
+ $jitm->dismiss( $_REQUEST['id'], $_REQUEST['feature_class'] );
+ wp_die();
+ }
+
+ /**
+ * Hide Calypso Search menu for Atomic sites.
+ *
+ * For simple sites, where search dashboard doesn't exist, we use the Calypso page / menu item.
+ * For Atomic sites, the admin-menu is originated from the sites and forwarded by WPCOM `public-api`.
+ * We have search dashboard for Atomic/JP sites, so we need to hide the duplicated menu item.
+ */
+ public function hide_search_menu_for_calypso() {
+ $this->hide_submenu_page( 'jetpack', 'https://wordpress.com/jetpack-search/' . $this->domain );
+ }
+}
diff --git a/plugins/jetpack/modules/masterbar/admin-menu/class-base-admin-menu.php b/plugins/jetpack/modules/masterbar/admin-menu/class-base-admin-menu.php
new file mode 100644
index 00000000..5f3b1f51
--- /dev/null
+++ b/plugins/jetpack/modules/masterbar/admin-menu/class-base-admin-menu.php
@@ -0,0 +1,694 @@
+<?php
+/**
+ * Base Admin Menu file.
+ *
+ * @package automattic/jetpack
+ */
+
+namespace Automattic\Jetpack\Dashboard_Customizations;
+
+use Automattic\Jetpack\Status;
+
+/**
+ * Class Base_Admin_Menu
+ */
+abstract class Base_Admin_Menu {
+ /**
+ * Holds class instances.
+ *
+ * @var array
+ */
+ protected static $instances;
+
+ /**
+ * Whether the current request is a REST API request.
+ *
+ * @var bool
+ */
+ protected $is_api_request = false;
+
+ /**
+ * Domain of the current site.
+ *
+ * @var string
+ */
+ protected $domain;
+
+ /**
+ * The CSS classes used to hide the submenu items in navigation.
+ *
+ * @var string
+ */
+ const HIDE_CSS_CLASS = 'hide-if-js';
+
+ /**
+ * Identifier denoting that the default WordPress.com view should be used for a certain screen.
+ *
+ * @var string
+ */
+ const DEFAULT_VIEW = 'default';
+
+ /**
+ * Identifier denoting that the classic WP Admin view should be used for a certain screen.
+ *
+ * @var string
+ */
+ const CLASSIC_VIEW = 'classic';
+
+ /**
+ * Identifier denoting no preferred view has been set for a certain screen.
+ *
+ * @var string
+ */
+ const UNKNOWN_VIEW = 'unknown';
+
+ /**
+ * Base_Admin_Menu constructor.
+ */
+ protected function __construct() {
+ $this->is_api_request = defined( 'REST_REQUEST' ) && REST_REQUEST || 0 === strpos( $_SERVER['REQUEST_URI'], '/?rest_route=%2Fwpcom%2Fv2%2Fadmin-menu' );
+ $this->domain = ( new Status() )->get_site_suffix();
+
+ add_action( 'admin_menu', array( $this, 'reregister_menu_items' ), 99998 );
+ add_action( 'admin_menu', array( $this, 'hide_parent_of_hidden_submenus' ), 99999 );
+
+ if ( ! $this->is_api_request ) {
+ add_filter( 'admin_menu', array( $this, 'override_svg_icons' ), 99999 );
+ add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ), 11 );
+ add_action( 'admin_head', array( $this, 'set_site_icon_inline_styles' ) );
+ add_filter( 'screen_settings', array( $this, 'register_dashboard_switcher' ), 99999 );
+ add_action( 'admin_menu', array( $this, 'handle_preferred_view' ), 99997 );
+ add_filter( 'admin_body_class', array( $this, 'admin_body_class' ) );
+ }
+ }
+
+ /**
+ * Returns class instance.
+ *
+ * @return Admin_Menu
+ */
+ public static function get_instance() {
+ $class = static::class;
+
+ if ( empty( static::$instances[ $class ] ) ) {
+ static::$instances[ $class ] = new $class();
+ }
+
+ return static::$instances[ $class ];
+ }
+
+ /**
+ * Updates the menu data of the given menu slug.
+ *
+ * @param string $slug Slug of the menu to update.
+ * @param string $url New menu URL.
+ * @param string $title New menu title.
+ * @param string $cap New menu capability.
+ * @param string $icon New menu icon.
+ * @param int $position New menu position.
+ * @return bool Whether the menu has been updated.
+ */
+ public function update_menu( $slug, $url = null, $title = null, $cap = null, $icon = null, $position = null ) {
+ global $menu, $submenu;
+
+ $menu_item = null;
+ $menu_position = null;
+
+ foreach ( $menu as $i => $item ) {
+ if ( $slug === $item[2] ) {
+ $menu_item = $item;
+ $menu_position = $i;
+ break;
+ }
+ }
+
+ if ( ! $menu_item ) {
+ return false;
+ }
+
+ if ( $title ) {
+ $menu_item[0] = $title;
+ $menu_item[3] = esc_attr( $title );
+ }
+
+ if ( $cap ) {
+ $menu_item[1] = $cap;
+ }
+
+ // Change parent slug only if there are no submenus (the slug of the 1st submenu will be used if there are submenus).
+ if ( $url ) {
+ $this->hide_submenu_page( $slug, $slug );
+
+ if ( ! isset( $submenu[ $slug ] ) || ! $this->has_visible_items( $submenu[ $slug ] ) ) {
+ $menu_item[2] = $url;
+ }
+ }
+
+ if ( $icon ) {
+ $menu_item[4] = 'menu-top';
+ $menu_item[6] = $icon;
+ }
+
+ // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
+ unset( $menu[ $menu_position ] );
+ if ( $position ) {
+ $menu_position = $position;
+ }
+ $this->set_menu_item( $menu_item, $menu_position );
+
+ // Only add submenu when there are other submenu items.
+ if ( $url && isset( $submenu[ $slug ] ) && $this->has_visible_items( $submenu[ $slug ] ) ) {
+ add_submenu_page( $slug, $menu_item[3], $menu_item[0], $menu_item[1], $url, null, 0 );
+ }
+
+ return true;
+ }
+
+ /**
+ * Updates the submenus of the given menu slug.
+ *
+ * It hides the menu by adding the `hide-if-js` css class and duplicates the submenu with the new slug.
+ *
+ * @param string $slug Menu slug.
+ * @param array $submenus_to_update Array of new submenu slugs.
+ */
+ public function update_submenus( $slug, $submenus_to_update ) {
+ global $submenu;
+
+ if ( ! isset( $submenu[ $slug ] ) ) {
+ return;
+ }
+
+ // This is needed for cases when the submenus to update have the same new slug.
+ $submenus_to_update = array_filter(
+ $submenus_to_update,
+ static function ( $item, $old_slug ) {
+ return $item !== $old_slug;
+ },
+ ARRAY_FILTER_USE_BOTH
+ );
+
+ /**
+ * Iterate over all submenu items and add the hide the submenus with CSS classes.
+ * This is done separately of the second foreach because the position of the submenu might change.
+ */
+ foreach ( $submenu[ $slug ] as $index => $item ) {
+ if ( ! array_key_exists( $item[2], $submenus_to_update ) ) {
+ continue;
+ }
+
+ $this->hide_submenu_element( $index, $slug, $item );
+ }
+
+ $submenu_items = array_values( $submenu[ $slug ] );
+
+ /**
+ * Iterate again over the submenu array. We need a copy of the array because add_submenu_page will add new elements
+ * to submenu array that might cause an infinite loop.
+ */
+ foreach ( $submenu_items as $i => $submenu_item ) {
+ if ( ! array_key_exists( $submenu_item[2], $submenus_to_update ) ) {
+ continue;
+ }
+
+ add_submenu_page(
+ $slug,
+ isset( $submenu_item[3] ) ? $submenu_item[3] : '',
+ isset( $submenu_item[0] ) ? $submenu_item[0] : '',
+ isset( $submenu_item[1] ) ? $submenu_item[1] : 'read',
+ $submenus_to_update[ $submenu_item[2] ],
+ '',
+ 0 === $i ? 0 : $i + 1
+ );
+ }
+ }
+
+ /**
+ * Adds a menu separator.
+ *
+ * @param int $position The position in the menu order this item should appear.
+ * @param string $cap Optional. The capability required for this menu to be displayed to the user.
+ * Default: 'read'.
+ */
+ public function add_admin_menu_separator( $position = null, $cap = 'read' ) {
+ $menu_item = array(
+ '', // Menu title (ignored).
+ $cap, // Required capability.
+ wp_unique_id( 'separator-custom-' ), // URL or file (ignored, but must be unique).
+ '', // Page title (ignored).
+ 'wp-menu-separator', // CSS class. Identifies this item as a separator.
+ );
+
+ $this->set_menu_item( $menu_item, $position );
+ }
+
+ /**
+ * Enqueues scripts and styles.
+ */
+ public function enqueue_scripts() {
+ $is_wpcom = defined( 'IS_WPCOM' ) && IS_WPCOM;
+
+ if ( $this->is_rtl() ) {
+ if ( $is_wpcom ) {
+ $css_path = 'rtl/admin-menu-rtl.css';
+ } else {
+ $css_path = 'admin-menu-rtl.css';
+ }
+ } else {
+ $css_path = 'admin-menu.css';
+ }
+
+ wp_enqueue_style(
+ 'jetpack-admin-menu',
+ plugins_url( $css_path, __FILE__ ),
+ array(),
+ JETPACK__VERSION
+ );
+
+ wp_style_add_data( 'jetpack-admin-menu', 'rtl', $this->is_rtl() );
+ $this->configure_colors_for_rtl_stylesheets();
+
+ wp_enqueue_script(
+ 'jetpack-admin-menu',
+ plugins_url( 'admin-menu.js', __FILE__ ),
+ array(),
+ JETPACK__VERSION,
+ true
+ );
+
+ wp_localize_script(
+ 'jetpack-admin-menu',
+ 'jetpackAdminMenu',
+ array( 'jitmDismissNonce' => wp_create_nonce( 'jitm_dismiss' ) )
+ );
+ }
+
+ /**
+ * Mark the core colors stylesheets as RTL depending on the value from the environment.
+ * This fixes a core issue where the extra RTL data is not added to the colors stylesheet.
+ * https://core.trac.wordpress.org/ticket/53090
+ */
+ public function configure_colors_for_rtl_stylesheets() {
+ wp_style_add_data( 'colors', 'rtl', $this->is_rtl() );
+ }
+
+ /**
+ * Injects inline-styles for site icon for when third-party plugins remove enqueued stylesheets.
+ * Unable to use wp_add_inline_style as plugins remove styles from all non-standard handles
+ */
+ public function set_site_icon_inline_styles() {
+ echo '<style>
+ #adminmenu .toplevel_page_site-card .wp-menu-image,
+ #adminmenu .toplevel_page_site-card .wp-menu-image img {
+ height: 32px;
+ width: 32px;
+ }
+ </style>';
+ }
+
+ /**
+ * Hide the submenu page based on slug and return the item that was hidden.
+ *
+ * Instead of actually removing the submenu item, a safer approach is to hide it and filter it in the API response.
+ * In this manner we'll avoid breaking third-party plugins depending on items that no longer exist.
+ *
+ * A false|array value is returned to be consistent with remove_submenu_page() function
+ *
+ * @param string $menu_slug The parent menu slug.
+ * @param string $submenu_slug The submenu slug that should be hidden.
+ * @return false|array
+ */
+ public function hide_submenu_page( $menu_slug, $submenu_slug ) {
+ global $submenu;
+
+ if ( ! isset( $submenu[ $menu_slug ] ) ) {
+ return false;
+ }
+
+ foreach ( $submenu[ $menu_slug ] as $i => $item ) {
+ if ( $submenu_slug !== $item[2] ) {
+ continue;
+ }
+
+ $this->hide_submenu_element( $i, $menu_slug, $item );
+
+ return $item;
+ }
+
+ return false;
+ }
+
+ /**
+ * Apply the hide-if-js CSS class to a submenu item.
+ *
+ * @param int $index The position of a submenu item in the submenu array.
+ * @param string $parent_slug The parent slug.
+ * @param array $item The submenu item.
+ */
+ public function hide_submenu_element( $index, $parent_slug, $item ) {
+ global $submenu;
+
+ $css_classes = empty( $item[4] ) ? self::HIDE_CSS_CLASS : $item[4] . ' ' . self::HIDE_CSS_CLASS;
+
+ // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
+ $submenu [ $parent_slug ][ $index ][4] = $css_classes;
+ }
+
+ /**
+ * Check if the menu has submenu items visible
+ *
+ * @param array $submenu_items The submenu items.
+ * @return bool
+ */
+ public function has_visible_items( $submenu_items ) {
+ $visible_items = array_filter(
+ $submenu_items,
+ array( $this, 'is_item_visible' )
+ );
+
+ return array() !== $visible_items;
+ }
+
+ /**
+ * Return the number of existing submenu items under the supplied parent slug.
+ *
+ * @param string $parent_slug The slug of the parent menu.
+ * @return int The number of submenu items under $parent_slug.
+ */
+ public function get_submenu_item_count( $parent_slug ) {
+ global $submenu;
+
+ if ( empty( $parent_slug ) || empty( $submenu[ $parent_slug ] ) || ! is_array( $submenu[ $parent_slug ] ) ) {
+ return 0;
+ }
+
+ return count( $submenu[ $parent_slug ] );
+ }
+
+ /**
+ * Adds the given menu item in the specified position.
+ *
+ * @param array $item The menu item to add.
+ * @param int $position The position in the menu order this item should appear.
+ */
+ public function set_menu_item( $item, $position = null ) {
+ global $menu;
+
+ // Handle position (avoids overwriting menu items already populated in the given position).
+ // Inspired by https://core.trac.wordpress.org/browser/trunk/src/wp-admin/menu.php?rev=49837#L160.
+ if ( null === $position ) {
+ $menu[] = $item; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
+ } elseif ( isset( $menu[ "$position" ] ) ) {
+ $position = $position + substr( base_convert( md5( $item[2] . $item[0] ), 16, 10 ), -5 ) * 0.00001;
+ $menu[ "$position" ] = $item; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
+ } else {
+ $menu[ $position ] = $item; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
+ }
+ }
+
+ /**
+ * Determines whether the current locale is right-to-left (RTL).
+ */
+ public function is_rtl() {
+ return is_rtl();
+ }
+
+ /**
+ * Checks for any SVG icons in the menu, and overrides things so that
+ * we can display the icon in the correct colour for the theme.
+ */
+ public function override_svg_icons() {
+ global $menu;
+
+ $svg_items = array();
+ foreach ( $menu as $idx => $menu_item ) {
+ // Menu items that don't have icons, for example separators, have less than 7
+ // elements, partly because the 7th is the icon. So, if we have less than 7,
+ // let's skip it.
+ if ( count( $menu_item ) < 7 ) {
+ continue;
+ }
+
+ // If the hookname contain a URL than sanitize it by replacing invalid characters.
+ if ( false !== strpos( $menu_item[5], '://' ) ) {
+ $menu_item[5] = preg_replace( '![:/.]+!', '_', $menu_item[5] );
+ }
+
+ if ( 0 === strpos( $menu_item[6], 'data:image/svg+xml' ) && 'site-card' !== $menu_item[3] ) {
+ $svg_items[] = array(
+ 'icon' => $menu_item[6],
+ 'id' => $menu_item[5],
+ );
+ $menu_item[4] .= ' menu-svg-icon';
+ $menu_item[6] = 'none';
+ }
+ // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
+ $menu[ $idx ] = $menu_item;
+ }
+ if ( count( $svg_items ) > 0 ) {
+ $styles = '.menu-svg-icon .wp-menu-image { background-repeat: no-repeat; background-position: center center } ';
+ foreach ( $svg_items as $svg_item ) {
+ $styles .= sprintf( '#%s .wp-menu-image { background-image: url( "%s" ) }', $svg_item['id'], $svg_item['icon'] );
+ }
+ $styles .= '@supports ( mask-image: none ) or ( -webkit-mask-image: none ) { ';
+ $styles .= '.menu-svg-icon .wp-menu-image { background-image: none; } ';
+ $styles .= '.menu-svg-icon .wp-menu-image::before { background-color: currentColor; ';
+ $styles .= 'mask-size: contain; mask-position: center center; mask-repeat: no-repeat; ';
+ $styles .= '-webkit-mask-size: contain; -webkit-mask-position: center center; -webkit-mask-repeat: no-repeat; content:"" } ';
+ foreach ( $svg_items as $svg_item ) {
+ $styles .= sprintf(
+ '#%s .wp-menu-image { background-image: none; } #%s .wp-menu-image::before{ mask-image: url( "%s" ); -webkit-mask-image: url( "%s" ) }',
+ $svg_item['id'],
+ $svg_item['id'],
+ $svg_item['icon'],
+ $svg_item['icon']
+ );
+ }
+ $styles .= '}';
+
+ wp_register_style( 'svg-menu-overrides', false, array(), '20210331' );
+ wp_enqueue_style( 'svg-menu-overrides' );
+ wp_add_inline_style( 'svg-menu-overrides', $styles );
+ }
+ }
+
+ /**
+ * Hide menus that are unauthorized and don't have visible submenus and cases when the menu has the same slug
+ * as the first submenu item.
+ *
+ * This must be done at the end of menu and submenu manipulation in order to avoid performing this check each time
+ * the submenus are altered.
+ */
+ public function hide_parent_of_hidden_submenus() {
+ global $menu, $submenu;
+
+ $this->sort_hidden_submenus();
+
+ foreach ( $menu as $menu_index => $menu_item ) {
+ $has_submenus = isset( $submenu[ $menu_item[2] ] );
+
+ // Skip if the menu doesn't have submenus.
+ if ( ! $has_submenus ) {
+ continue;
+ }
+
+ // If the first submenu item is hidden then we should also hide the parent.
+ // Since the submenus are ordered by self::HIDE_CSS_CLASS (hidden submenus should be at the end of the array),
+ // we can say that if the first submenu is hidden then we should also hide the menu.
+ $first_submenu_item = array_values( $submenu[ $menu_item[2] ] )[0];
+ $is_first_submenu_visible = $this->is_item_visible( $first_submenu_item );
+
+ // if the user does not have access to the menu and the first submenu is hidden, then hide the menu.
+ if ( ! current_user_can( $menu_item[1] ) && ! $is_first_submenu_visible ) {
+ // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
+ $menu[ $menu_index ][4] = self::HIDE_CSS_CLASS;
+ }
+
+ // if the menu has the same slug as the first submenu then hide the submenu.
+ if ( $menu_item[2] === $first_submenu_item[2] && ! $is_first_submenu_visible ) {
+ // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
+ $menu[ $menu_index ][4] = self::HIDE_CSS_CLASS;
+ }
+ }
+ }
+
+ /**
+ * Sort the hidden submenus by moving them at the end of the array in order to avoid WP using them as default URLs.
+ *
+ * This operation has to be done at the end of submenu manipulation in order to guarantee that the hidden submenus
+ * are at the end of the array.
+ */
+ public function sort_hidden_submenus() {
+ global $submenu;
+
+ foreach ( $submenu as $menu_slug => $submenu_items ) {
+ foreach ( $submenu_items as $submenu_index => $submenu_item ) {
+ if ( $this->is_item_visible( $submenu_item ) ) {
+ continue;
+ }
+
+ unset( $submenu[ $menu_slug ][ $submenu_index ] );
+ // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
+ $submenu[ $menu_slug ][] = $submenu_item;
+ }
+ }
+ }
+
+ /**
+ * Check if the given item is visible or not in the admin menu.
+ *
+ * @param array $item A menu or submenu array.
+ */
+ public function is_item_visible( $item ) {
+ return ! isset( $item[4] ) || false === strpos( $item[4], self::HIDE_CSS_CLASS );
+ }
+
+ /**
+ * Sets the given view as preferred for the givens screen.
+ *
+ * @param string $screen Screen identifier.
+ * @param string $view Preferred view.
+ */
+ public function set_preferred_view( $screen, $view ) {
+ $preferred_views = $this->get_preferred_views();
+ $preferred_views[ $screen ] = $view;
+ update_user_option( get_current_user_id(), 'jetpack_admin_menu_preferred_views', $preferred_views );
+ }
+
+ /**
+ * Get the preferred views for all screens.
+ *
+ * @return array
+ */
+ public function get_preferred_views() {
+ $preferred_views = get_user_option( 'jetpack_admin_menu_preferred_views' );
+
+ if ( ! $preferred_views ) {
+ return array();
+ }
+
+ return $preferred_views;
+ }
+
+ /**
+ * Get the preferred view for the given screen.
+ *
+ * @param string $screen Screen identifier.
+ * @param bool $fallback_global_preference (Optional) Whether the global preference for all screens should be used
+ * as fallback if there is no specific preference for the given screen.
+ * Default: true.
+ * @return string
+ */
+ public function get_preferred_view( $screen, $fallback_global_preference = true ) {
+ $preferred_views = $this->get_preferred_views();
+
+ if ( ! isset( $preferred_views[ $screen ] ) ) {
+ if ( ! $fallback_global_preference ) {
+ return self::UNKNOWN_VIEW;
+ }
+ return $this->should_link_to_wp_admin() ? self::CLASSIC_VIEW : self::DEFAULT_VIEW;
+ }
+
+ return $preferred_views[ $screen ];
+ }
+
+ /**
+ * Gets the identifier of the current screen.
+ *
+ * @return string
+ */
+ public function get_current_screen() {
+ // phpcs:disable WordPress.Security.NonceVerification
+ global $pagenow;
+ $screen = isset( $_REQUEST['screen'] ) ? $_REQUEST['screen'] : $pagenow;
+ if ( isset( $_GET['post_type'] ) ) {
+ $screen = add_query_arg( 'post_type', $_GET['post_type'], $screen );
+ }
+ if ( isset( $_GET['taxonomy'] ) ) {
+ $screen = add_query_arg( 'taxonomy', $_GET['taxonomy'], $screen );
+ }
+ if ( isset( $_GET['page'] ) ) {
+ $screen = add_query_arg( 'page', $_GET['page'], $screen );
+ }
+ return sanitize_text_field( wp_unslash( $screen ) );
+ // phpcs:enable WordPress.Security.NonceVerification
+ }
+
+ /**
+ * Stores the preferred view for the current screen.
+ */
+ public function handle_preferred_view() {
+ // phpcs:disable WordPress.Security.NonceVerification
+ if ( ! isset( $_GET['preferred-view'] ) ) {
+ return;
+ }
+
+ // phpcs:disable WordPress.Security.NonceVerification
+ $preferred_view = $_GET['preferred-view'];
+
+ if ( ! in_array( $preferred_view, array( self::DEFAULT_VIEW, self::CLASSIC_VIEW ), true ) ) {
+ return;
+ }
+
+ $current_screen = $this->get_current_screen();
+
+ $this->set_preferred_view( $current_screen, $preferred_view );
+
+ /**
+ * Dashboard Quick switcher action triggered when a user switches to a different view.
+ *
+ * @module masterbar
+ *
+ * @since 9.9.1
+ *
+ * @param string The current screen of the user.
+ * @param string The preferred view the user selected.
+ */
+ \do_action( 'jetpack_dashboard_switcher_changed_view', $current_screen, $preferred_view );
+
+ if ( self::DEFAULT_VIEW === $preferred_view ) {
+ // Redirect to default view if that's the newly preferred view.
+ $menu_mappings = require __DIR__ . '/menu-mappings.php';
+ if ( isset( $menu_mappings[ $current_screen ] ) ) {
+ // Using `wp_redirect` intentionally because we're redirecting to Calypso.
+ wp_redirect( $menu_mappings[ $current_screen ] . $this->domain ); // phpcs:ignore WordPress.Security.SafeRedirect
+ exit;
+ }
+ } elseif ( self::CLASSIC_VIEW === $preferred_view ) {
+ // Removes the `preferred-view` param from the URL to avoid issues with
+ // screens that don't expect this param to be present in the URL.
+ wp_safe_redirect( remove_query_arg( 'preferred-view' ) );
+ exit;
+ }
+ // phpcs:enable WordPress.Security.NonceVerification
+ }
+
+ /**
+ * Adds the necessary CSS class to the admin body class.
+ *
+ * @param string $admin_body_classes Contains all the admin body classes.
+ *
+ * @return string
+ */
+ public function admin_body_class( $admin_body_classes ) {
+ return " is-nav-unification $admin_body_classes ";
+ }
+
+ /**
+ * Whether to use wp-admin pages rather than Calypso.
+ *
+ * Options:
+ * false - Calypso (Default).
+ * true - wp-admin.
+ *
+ * @return bool
+ */
+ public function should_link_to_wp_admin() {
+ return get_user_option( 'jetpack_admin_menu_link_destination' );
+ }
+
+ /**
+ * Create the desired menu output.
+ */
+ abstract public function reregister_menu_items();
+}
diff --git a/plugins/jetpack/modules/masterbar/admin-menu/class-dashboard-switcher-tracking.php b/plugins/jetpack/modules/masterbar/admin-menu/class-dashboard-switcher-tracking.php
new file mode 100644
index 00000000..b3fe7cd8
--- /dev/null
+++ b/plugins/jetpack/modules/masterbar/admin-menu/class-dashboard-switcher-tracking.php
@@ -0,0 +1,175 @@
+<?php
+/**
+ * Quick switcher tracking file.
+ *
+ * @package automattic/jetpack
+ */
+
+namespace Automattic\Jetpack\Dashboard_Customizations;
+
+use Automattic\Jetpack\Status\Host;
+use Automattic\Jetpack\Terms_Of_Service;
+use Automattic\Jetpack\Tracking;
+use Jetpack_Plan;
+
+/**
+ * Class Dashboard_Switcher_Tracking
+ */
+class Dashboard_Switcher_Tracking {
+
+ /**
+ * Jetpack Tracking library will prefix the event name with "jetpack_*" automatically.
+ */
+ const JETPACK_EVENT_NAME = 'dashboard_quick_switch_link_clicked';
+
+ const WPCOM_EVENT_NAME = 'wpcom_dashboard_quick_switch_link_clicked';
+ /**
+ * Jetpack tracking object.
+ *
+ * @var Tracking
+ */
+ private $tracking;
+
+ /**
+ * Current site plan.
+ *
+ * @var string
+ */
+ private $plan;
+
+ /**
+ * The wpcom_tracks wrapper function.
+ *
+ * @var callable
+ */
+ private $wpcom_tracking;
+
+ /**
+ * Dashboard_Switcher_Tracking constructor.
+ *
+ * @param Tracking $tracking Jetpack tracking object.
+ * @param callable $wpcom_tracking A wrapper over wpcom event record.
+ * @param string $plan The current site plan.
+ */
+ public function __construct( Tracking $tracking, callable $wpcom_tracking, $plan ) {
+ $this->tracking = $tracking;
+ $this->plan = $plan;
+ $this->wpcom_tracking = $wpcom_tracking;
+ }
+
+ /**
+ * Create an event for the Quick switcher when the user changes it's preferred view.
+ *
+ * @param string $screen The screen page.
+ * @param string $view The new preferred view.
+ */
+ public function record_switch_event( $screen, $view ) {
+ $event_props = array(
+ 'current_page' => $screen,
+ 'destination' => $view,
+ 'plan' => $this->plan,
+ );
+
+ if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
+ $event_props['blog_id'] = get_current_blog_id();
+
+ /**
+ * Callable injected in the constructor with the static::wpcom_tracks_record_event() static method.
+ *
+ * @see wpcom_tracks_record_event A static method from this class that executes the actual WPCOM event record.
+ */
+ $wpcom_tracking = $this->wpcom_tracking;
+ $wpcom_tracking( $event_props );
+ } else {
+ $this->record_jetpack_event( $event_props );
+ }
+ }
+
+ /**
+ * Get the current site plan or 'N/A' when we cannot determine site's plan.
+ *
+ * @todo: This method can be reused as a wrapper over WPCOM and Atomic as way to get site's current plan (display name).
+ *
+ * @return string
+ */
+ public static function get_plan() {
+ if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
+ if ( class_exists( '\WPCOM_Store_API' ) ) {
+ // @todo: Maybe introduce a wrapper for this since we are duplicating it from WPCOM_Admin_Menu:253
+ $products = \WPCOM_Store_API::get_current_plan( \get_current_blog_id() );
+ if ( array_key_exists( 'product_name_short', $products ) ) {
+ return $products['product_name_short'];
+ }
+ }
+
+ return 'N/A'; // maybe we should return free or null? At the moment it's safe to return 'N/A' since we use it only for passing it to the event.
+ }
+
+ // @todo: Maybe introduce a helper for this since we are duplicating it from Atomic_Admin_Menu:240
+ $products = Jetpack_Plan::get();
+ if ( array_key_exists( 'product_name_short', $products ) ) {
+ return $products['product_name_short'];
+ }
+
+ return 'N/A'; // maybe we should return free or null? At the moment we use it for passing it to the event.
+ }
+
+ /**
+ * Record the event with Jetpack implementation.
+ *
+ * For Atomic sites we mark the Jetpack ToS option temporary as read.
+ *
+ * @todo Remove the jetpack_options_tos_agreed filter for Atomic sites after the Tracking is properly working for AT sites.
+ *
+ * @param array $event_properties The event properties.
+ */
+ private function record_jetpack_event( $event_properties ) {
+ $woa = ( new Host() )->is_woa_site();
+ if ( $woa ) {
+ add_filter( 'jetpack_options', array( __CLASS__, 'mark_jetpack_tos_as_read' ), 10, 2 );
+ }
+
+ $this->tracking->record_user_event( self::JETPACK_EVENT_NAME, $event_properties );
+
+ if ( $woa ) {
+ \remove_filter( 'jetpack_options', array( __CLASS__, 'mark_jetpack_tos_as_read' ) );
+ }
+ }
+
+ /**
+ * Trigger the WPCOM tracks_record_event.
+ *
+ * @param array $event_props Event props.
+ */
+ public static function wpcom_tracks_record_event( $event_props ) {
+ jetpack_require_lib( 'tracks/client' );
+ \tracks_record_event( \wp_get_current_user(), self::WPCOM_EVENT_NAME, $event_props );
+ }
+
+ /**
+ * Get the tracking product name for the Tracking library.
+ *
+ * The tracking product name is used by the Tracking as a prefix for the event name.
+ *
+ * @return string
+ */
+ public static function get_jetpack_tracking_product() {
+ return ( new Host() )->is_woa_site() ? 'atomic' : 'jetpack';
+ }
+
+ /**
+ * Mark the Jetpack ToS as read for Atomic Sites.
+ *
+ * @param mixed $option_value The value of the Jetpack option.
+ * @param string $option_name The name of the Jetpack option.
+ *
+ * @return bool
+ */
+ public static function mark_jetpack_tos_as_read( $option_value, $option_name ) {
+ if ( Terms_Of_Service::OPTION_NAME === $option_name ) {
+ return true;
+ }
+
+ return $option_value;
+ }
+}
diff --git a/plugins/jetpack/modules/masterbar/admin-menu/class-domain-only-admin-menu.php b/plugins/jetpack/modules/masterbar/admin-menu/class-domain-only-admin-menu.php
new file mode 100644
index 00000000..7f9507a2
--- /dev/null
+++ b/plugins/jetpack/modules/masterbar/admin-menu/class-domain-only-admin-menu.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * Domain-only sites Admin Menu file.
+ *
+ * @package automattic/jetpack
+ */
+
+namespace Automattic\Jetpack\Dashboard_Customizations;
+
+require_once __DIR__ . '/class-base-admin-menu.php';
+
+/**
+ * Class Domain_Only_Admin_Menu.
+ */
+class Domain_Only_Admin_Menu extends Base_Admin_Menu {
+
+ /**
+ * Create the desired menu output.
+ */
+ public function reregister_menu_items() {
+ global $menu, $submenu;
+
+ $menu = array(); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
+ $submenu = array(); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
+
+ add_menu_page( esc_attr__( 'Settings', 'jetpack' ), __( 'Settings', 'jetpack' ), 'manage_options', 'https://wordpress.com/domains/manage/' . $this->domain, null, 'dashicons-admin-settings' );
+ }
+}
diff --git a/plugins/jetpack/modules/masterbar/admin-menu/class-jetpack-admin-menu.php b/plugins/jetpack/modules/masterbar/admin-menu/class-jetpack-admin-menu.php
new file mode 100644
index 00000000..c61628b5
--- /dev/null
+++ b/plugins/jetpack/modules/masterbar/admin-menu/class-jetpack-admin-menu.php
@@ -0,0 +1,252 @@
+<?php
+/**
+ * Jetpack Admin Menu file.
+ *
+ * @package Jetpack
+ */
+
+namespace Automattic\Jetpack\Dashboard_Customizations;
+
+require_once __DIR__ . '/class-admin-menu.php';
+
+/**
+ * Class Jetpack_Admin_Menu.
+ */
+class Jetpack_Admin_Menu extends Admin_Menu {
+ /**
+ * Determines whether the current locale is right-to-left (RTL).
+ *
+ * Performs the check against the current locale set on the WordPress.com's account settings.
+ * See `Masterbar::__construct` in `modules/masterbar/masterbar/class-masterbar.php`.
+ */
+ public function is_rtl() {
+ return get_user_option( 'jetpack_wpcom_is_rtl' );
+ }
+
+ /**
+ * Create the desired menu output.
+ */
+ public function reregister_menu_items() {
+ global $menu, $submenu;
+
+ // Reset menus so there are no third-party plugin items.
+ $menu = array(); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
+ $submenu = array(); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
+
+ parent::reregister_menu_items();
+
+ $this->add_feedback_menu();
+ $this->add_wp_admin_menu();
+
+ ksort( $GLOBALS['menu'] );
+ }
+
+ /**
+ * Get the preferred view for the given screen.
+ *
+ * @param string $screen Screen identifier.
+ * @param bool $fallback_global_preference (Optional) Whether the global preference for all screens should be used
+ * as fallback if there is no specific preference for the given screen.
+ * Default: true.
+ * @return string
+ */
+ public function get_preferred_view( $screen, $fallback_global_preference = true ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
+ // Force default views (Calypso) on Jetpack sites since Nav Unification is disabled on WP Admin.
+ return self::DEFAULT_VIEW;
+ }
+
+ /**
+ * Adds Posts menu.
+ */
+ public function add_posts_menu() {
+ $post = get_post_type_object( 'post' );
+ add_menu_page( esc_attr( $post->labels->menu_name ), $post->labels->menu_name, $post->cap->edit_posts, 'https://wordpress.com/posts/' . $this->domain, null, 'dashicons-admin-post' );
+ }
+
+ /**
+ * Adds Media menu.
+ */
+ public function add_media_menu() {
+ add_menu_page( __( 'Media', 'jetpack' ), __( 'Media', 'jetpack' ), 'upload_files', 'https://wordpress.com/media/' . $this->domain, null, 'dashicons-admin-media' );
+ }
+
+ /**
+ * Adds Page menu.
+ */
+ public function add_page_menu() {
+ $page = get_post_type_object( 'page' );
+ add_menu_page( esc_attr( $page->labels->menu_name ), $page->labels->menu_name, $page->cap->edit_posts, 'https://wordpress.com/pages/' . $this->domain, null, 'dashicons-admin-page' );
+ }
+
+ /**
+ * Adds a custom post type menu.
+ *
+ * @param string $post_type Custom post type.
+ */
+ public function add_custom_post_type_menu( $post_type ) {
+ $ptype_obj = get_post_type_object( $post_type );
+ if ( empty( $ptype_obj ) ) {
+ return;
+ }
+
+ $menu_slug = 'https://wordpress.com/types/' . $post_type . '/' . $this->domain;
+
+ // Menu icon.
+ $menu_icon = 'dashicons-admin-post';
+ if ( is_string( $ptype_obj->menu_icon ) ) {
+ // Special handling for data:image/svg+xml and Dashicons.
+ if ( 0 === strpos( $ptype_obj->menu_icon, 'data:image/svg+xml;base64,' ) || 0 === strpos( $ptype_obj->menu_icon, 'dashicons-' ) ) {
+ $menu_icon = $ptype_obj->menu_icon;
+ } else {
+ $menu_icon = esc_url( $ptype_obj->menu_icon );
+ }
+ }
+
+ add_menu_page( esc_attr( $ptype_obj->labels->menu_name ), $ptype_obj->labels->menu_name, $ptype_obj->cap->edit_posts, $menu_slug, null, $menu_icon );
+ }
+
+ /**
+ * Adds Comments menu.
+ */
+ public function add_comments_menu() {
+ add_menu_page( esc_attr__( 'Comments', 'jetpack' ), __( 'Comments', 'jetpack' ), 'edit_posts', 'https://wordpress.com/comments/all/' . $this->domain, null, 'dashicons-admin-comments' );
+ }
+
+ /**
+ * Adds Feedback menu.
+ */
+ public function add_feedback_menu() {
+ $post_type = 'feedback';
+
+ $ptype_obj = get_post_type_object( $post_type );
+ if ( empty( $ptype_obj ) ) {
+ return;
+ }
+
+ $slug = 'edit.php?post_type=' . $post_type;
+ $name = __( 'Feedback', 'jetpack' );
+ $capability = $ptype_obj->cap->edit_posts;
+ $icon = $ptype_obj->menu_icon;
+ $position = 45; // Before Jetpack.
+
+ add_menu_page( esc_attr( $name ), $name, $capability, $slug, null, $icon, $position );
+ }
+
+ /**
+ * Adds Jetpack menu.
+ */
+ public function add_jetpack_menu() {
+ parent::add_jetpack_menu();
+
+ // Place "Scan" submenu after Backup.
+ $position = 0;
+ global $submenu;
+ foreach ( $submenu['jetpack'] as $submenu_item ) {
+ $position ++;
+ if ( __( 'Backup', 'jetpack' ) === $submenu_item[3] ) {
+ break;
+ }
+ }
+ add_submenu_page( 'jetpack', esc_attr__( 'Scan', 'jetpack' ), __( 'Scan', 'jetpack' ), 'manage_options', 'https://wordpress.com/scan/' . $this->domain, null, $position );
+ }
+
+ /**
+ * Adds Appearance menu.
+ *
+ * @return string The Customizer URL.
+ */
+ public function add_appearance_menu() {
+ $themes_url = 'https://wordpress.com/themes/' . $this->domain;
+ // Customize on Jetpack sites is always done on WP Admin (unsupported by Calypso).
+ $customize_url = 'customize.php';
+
+ add_menu_page( esc_attr__( 'Appearance', 'jetpack' ), __( 'Appearance', 'jetpack' ), 'switch_themes', $themes_url, null, 'dashicons-admin-appearance', 60 );
+ add_submenu_page( $themes_url, esc_attr__( 'Themes', 'jetpack' ), __( 'Themes', 'jetpack' ), 'switch_themes', 'https://wordpress.com/themes/' . $this->domain );
+ add_submenu_page( $themes_url, esc_attr__( 'Customize', 'jetpack' ), __( 'Customize', 'jetpack' ), 'customize', $customize_url );
+
+ return $customize_url;
+ }
+
+ /**
+ * Adds Plugins menu.
+ */
+ public function add_plugins_menu() {
+ add_menu_page( esc_attr__( 'Plugins', 'jetpack' ), __( 'Plugins', 'jetpack' ), 'activate_plugins', 'https://wordpress.com/plugins/' . $this->domain, null, 'dashicons-admin-plugins', 65 );
+ }
+
+ /**
+ * Adds Users menu.
+ */
+ public function add_users_menu() {
+ if ( current_user_can( 'list_users' ) ) {
+ add_menu_page( esc_attr__( 'Users', 'jetpack' ), __( 'Users', 'jetpack' ), 'list_users', 'https://wordpress.com/people/team/' . $this->domain, null, 'dashicons-admin-users', 70 );
+ } else {
+ add_menu_page( esc_attr__( 'My Profile', 'jetpack' ), __( 'Profile', 'jetpack' ), 'read', 'https://wordpress.com/me', null, 'dashicons-admin-users', 70 );
+ }
+ }
+
+ /**
+ * Adds Tools menu.
+ */
+ public function add_tools_menu() {
+ add_menu_page( esc_attr__( 'Tools', 'jetpack' ), __( 'Tools', 'jetpack' ), 'publish_posts', 'tools.php', null, 'dashicons-admin-tools', 75 );
+
+ add_submenu_page( 'tools.php', esc_attr__( 'Marketing', 'jetpack' ), __( 'Marketing', 'jetpack' ), 'publish_posts', 'https://wordpress.com/marketing/tools/' . $this->domain );
+ add_submenu_page( 'tools.php', esc_attr__( 'Earn', 'jetpack' ), __( 'Earn', 'jetpack' ), 'manage_options', 'https://wordpress.com/earn/' . $this->domain );
+
+ // Import/Export on Jetpack sites is always handled on WP Admin.
+ add_submenu_page( 'tools.php', esc_attr__( 'Import', 'jetpack' ), __( 'Import', 'jetpack' ), 'import', 'import.php' );
+ add_submenu_page( 'tools.php', esc_attr__( 'Export', 'jetpack' ), __( 'Export', 'jetpack' ), 'export', 'export.php' );
+
+ // Remove the submenu auto-created by Core.
+ $this->hide_submenu_page( 'tools.php', 'tools.php' );
+ }
+
+ /**
+ * Adds Settings menu.
+ */
+ public function add_options_menu() {
+ $slug = 'https://wordpress.com/settings/general/' . $this->domain;
+ add_menu_page( esc_attr__( 'Settings', 'jetpack' ), __( 'Settings', 'jetpack' ), 'manage_options', $slug, null, 'dashicons-admin-settings', 80 );
+ add_submenu_page( $slug, esc_attr__( 'General', 'jetpack' ), __( 'General', 'jetpack' ), 'manage_options', $slug );
+ add_submenu_page( $slug, esc_attr__( 'Security', 'jetpack' ), __( 'Security', 'jetpack' ), 'manage_options', 'https://wordpress.com/settings/security/' . $this->domain );
+ add_submenu_page( $slug, esc_attr__( 'Performance', 'jetpack' ), __( 'Performance', 'jetpack' ), 'manage_options', 'https://wordpress.com/settings/performance/' . $this->domain );
+ add_submenu_page( $slug, esc_attr__( 'Writing', 'jetpack' ), __( 'Writing', 'jetpack' ), 'manage_options', 'https://wordpress.com/settings/writing/' . $this->domain );
+ add_submenu_page( $slug, esc_attr__( 'Discussion', 'jetpack' ), __( 'Discussion', 'jetpack' ), 'manage_options', 'https://wordpress.com/settings/discussion/' . $this->domain );
+
+ $plan_supports_scan = \Jetpack_Plan::supports( 'scan' );
+ $products = \Jetpack_Plan::get_products();
+ $has_scan_product = false;
+
+ if ( is_array( $products ) ) {
+ foreach ( $products as $product ) {
+ if ( strpos( $product['product_slug'], 'jetpack_scan' ) === 0 ) {
+ $has_scan_product = true;
+ break;
+ }
+ }
+ }
+
+ $has_scan = $plan_supports_scan || $has_scan_product;
+ $rewind_state = get_transient( 'jetpack_rewind_state' );
+ $has_backup = $rewind_state && in_array( $rewind_state->state, array( 'awaiting_credentials', 'provisioning', 'active' ), true );
+ if ( $has_scan || $has_backup ) {
+ add_submenu_page( $slug, esc_attr__( 'Jetpack', 'jetpack' ), __( 'Jetpack', 'jetpack' ), 'manage_options', 'https://wordpress.com/settings/jetpack/' . $this->domain );
+ }
+ }
+
+ /**
+ * Adds WP Admin menu.
+ */
+ public function add_wp_admin_menu() {
+ global $menu;
+
+ // Attempt to get last position.
+ ksort( $menu );
+ end( $menu );
+ $position = key( $menu );
+
+ $this->add_admin_menu_separator( ++ $position );
+ add_menu_page( __( 'WP Admin', 'jetpack' ), __( 'WP Admin', 'jetpack' ), 'read', 'index.php', null, 'dashicons-wordpress-alt', $position );
+ }
+}
diff --git a/plugins/jetpack/modules/masterbar/admin-menu/class-p2-admin-menu.php b/plugins/jetpack/modules/masterbar/admin-menu/class-p2-admin-menu.php
new file mode 100644
index 00000000..6b45422d
--- /dev/null
+++ b/plugins/jetpack/modules/masterbar/admin-menu/class-p2-admin-menu.php
@@ -0,0 +1,199 @@
+<?php
+/**
+ * P2 Admin Menu file.
+ *
+ * @package Jetpack
+ */
+
+namespace Automattic\Jetpack\Dashboard_Customizations;
+
+require_once __DIR__ . '/class-wpcom-admin-menu.php';
+
+/**
+ * Class P2_Admin_Menu.
+ */
+class P2_Admin_Menu extends WPcom_Admin_Menu {
+
+ /**
+ * Slug for the "Appearance" menu item.
+ *
+ * @var string
+ */
+ private $appearance_slug = 'themes.php';
+
+ /**
+ * Slug for the "Jetpack" menu item.
+ *
+ * @var string
+ */
+ private $jetpack_slug = 'jetpack';
+
+ /**
+ * Slug for the "Upgrades" menu item.
+ *
+ * @var string
+ */
+ private $upgrades_slug = 'paid-upgrades.php';
+
+ /**
+ * Slug for the "Plugins" menu item.
+ *
+ * @var string
+ */
+ private $plugins_slug = 'plugins.php';
+
+ /**
+ * Slug for the "Tools" menu item.
+ *
+ * @var string
+ */
+ private $tools_slug = 'tools.php';
+
+ /**
+ * Whether or not the P2 is a hub.
+ *
+ * @var bool
+ */
+ private $is_hub = false;
+
+ /**
+ * Whether or not the P2 has a paid plan.
+ *
+ * @var bool
+ */
+ private $is_paid = false;
+
+ /**
+ * P2_Admin_Menu constructor.
+ */
+ protected function __construct() {
+ parent::__construct();
+
+ if (
+ defined( 'IS_WPCOM' ) && IS_WPCOM &&
+ function_exists( 'require_lib' )
+ ) {
+ require_lib( 'wpforteams' );
+
+ $current_blog_id = get_current_blog_id();
+ $this->is_hub = \WPForTeams\Workspace\is_workspace_hub( $current_blog_id );
+ $this->is_paid = \WPForTeams\has_p2_plus_plan( \WPForTeams\Workspace\get_hub_blog_id_from_blog_id( $current_blog_id ) );
+ }
+ // Appearance -> AMP. This needs to be called here in the constructor.
+ // Running it from reregister_menu_items is not early enough.
+ remove_action( 'admin_menu', 'amp_add_customizer_link' );
+ }
+
+ /**
+ * Create the desired menu output.
+ */
+ public function reregister_menu_items() {
+ parent::reregister_menu_items();
+
+ if ( ! $this->is_hub ) {
+ $this->remove_menus_for_p2_space();
+ } else {
+ $this->remove_menus_for_hub();
+ }
+
+ $this->remove_menus_for_all_p2s();
+ }
+
+ /**
+ * Remove menu items that are not applicable for P2 workspace sites.
+ */
+ private function remove_menus_for_p2_space() {
+ // Non-hub P2s can't have plans at all.
+ remove_menu_page( $this->upgrades_slug );
+ // Jetpack -> Backup.
+ remove_submenu_page( $this->jetpack_slug, 'https://wordpress.com/backup/' . $this->domain );
+ // Appearance -> Themes.
+ remove_submenu_page( $this->appearance_slug, 'https://wordpress.com/themes/' . $this->domain );
+ // Appearance -> Additional CSS.
+ $customize_custom_css_url = add_query_arg(
+ array( 'autofocus' => array( 'section' => 'css_nudge' ) ),
+ 'https://wordpress.com/customize/' . $this->domain
+ );
+ remove_submenu_page( $this->appearance_slug, $customize_custom_css_url );
+ }
+
+ /**
+ * Remove menu items that are not applicable for P2 hubs.
+ */
+ private function remove_menus_for_hub() {
+ // Hubs can have plans, but not domain and email products.
+ remove_submenu_page( $this->upgrades_slug, 'https://wordpress.com/domains/manage/' . $this->domain );
+ remove_submenu_page( $this->upgrades_slug, 'https://wordpress.com/email/' . $this->domain );
+ // Stats.
+ remove_menu_page( 'https://wordpress.com/stats/day/' . $this->domain );
+ // Hide all Jetpack for hubs.
+ remove_menu_page( $this->jetpack_slug );
+ // Hide posts.
+ remove_menu_page( 'edit.php' );
+ // Hide pages.
+ remove_menu_page( 'edit.php?post_type=page' );
+ // Hide media.
+ remove_menu_page( 'https://wordpress.com/media/' . $this->domain );
+ // Hide comments.
+ remove_menu_page( 'https://wordpress.com/comments/all/' . $this->domain );
+ // Hide appearance.
+ remove_menu_page( $this->appearance_slug );
+ // Tools.
+ remove_menu_page( $this->tools_slug );
+ // Hide settings.
+ remove_submenu_page( 'options-general.php', 'options-reading.php' );
+ remove_submenu_page( 'options-general.php', 'options-writing.php' );
+ remove_submenu_page( 'options-general.php', 'options-discussion.php' );
+ }
+
+ /**
+ * Remove menu items that are not applicable for all P2s.
+ */
+ private function remove_menus_for_all_p2s() {
+ // For free sites remove Jetpack menu item.
+ if ( ! $this->is_paid ) {
+ remove_menu_page( $this->jetpack_slug );
+ }
+
+ // The following menu items are hidden for both hubs and P2 sites.
+ remove_menu_page( 'link-manager.php' );
+ remove_menu_page( 'feedback' );
+ remove_menu_page( $this->plugins_slug );
+ remove_menu_page( 'https://wordpress.com/plugins/' . $this->domain );
+ remove_menu_page( 'https://wordpress.com/inbox/' . $this->domain );
+
+ remove_submenu_page( $this->tools_slug, 'https://wordpress.com/marketing/tools/' . $this->domain );
+ remove_submenu_page( $this->tools_slug, 'https://wordpress.com/earn/' . $this->domain );
+
+ remove_submenu_page( 'https://wordpress.com/settings/general/' . $this->domain, 'sharing' );
+ remove_submenu_page( 'https://wordpress.com/settings/general/' . $this->domain, 'polls&action=options' );
+ remove_submenu_page( 'https://wordpress.com/settings/general/' . $this->domain, 'ratings&action=options' );
+ remove_submenu_page(
+ 'options-general.php',
+ 'https://wordpress.com/hosting-config/' . $this->domain
+ );
+ remove_submenu_page(
+ 'https://wordpress.com/settings/general/' . $this->domain,
+ 'https://wordpress.com/marketing/sharing-buttons/' . $this->domain
+ );
+
+ /** This action is documented in `wp-content/plugins/p2-editor/classes/p2-editor-admin.php` */
+ if ( apply_filters( 'p2tenberg_admin_patterns', apply_filters( 'p2editor_admin_patterns', true ) ) !== true ) {
+ remove_menu_page( 'edit.php?post_type=p2_pattern' );
+ }
+ remove_submenu_page(
+ 'edit.php?post_type=p2_pattern',
+ 'edit-tags.php?taxonomy=post_tag&amp;post_type=p2_pattern'
+ );
+
+ // Hide performance settings.
+ remove_submenu_page( 'options-general.php', 'https://wordpress.com/settings/performance/' . $this->domain );
+ }
+
+ /**
+ * Override, don't add the woocommerce installation menu on any p2s.
+ *
+ * @param array|null $current_plan The site's plan.
+ */
+ public function add_woocommerce_installation_menu( $current_plan = null ) {} // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
+}
diff --git a/plugins/jetpack/modules/masterbar/admin-menu/class-wpcom-admin-menu.php b/plugins/jetpack/modules/masterbar/admin-menu/class-wpcom-admin-menu.php
new file mode 100644
index 00000000..12535a4e
--- /dev/null
+++ b/plugins/jetpack/modules/masterbar/admin-menu/class-wpcom-admin-menu.php
@@ -0,0 +1,461 @@
+<?php
+/**
+ * WP.com Admin Menu file.
+ *
+ * @package automattic/jetpack
+ */
+
+namespace Automattic\Jetpack\Dashboard_Customizations;
+
+use JITM;
+
+require_once __DIR__ . '/class-admin-menu.php';
+
+/**
+ * Class WPcom_Admin_Menu.
+ */
+class WPcom_Admin_Menu extends Admin_Menu {
+ /**
+ * Holds the current plan, set by get_current_plan().
+ *
+ * @var array
+ */
+ private $current_plan = array();
+
+ /**
+ * WPcom_Admin_Menu constructor.
+ */
+ protected function __construct() {
+ parent::__construct();
+
+ add_action( 'wp_ajax_sidebar_state', array( $this, 'ajax_sidebar_state' ) );
+ add_action( 'wp_ajax_jitm_dismiss', array( $this, 'wp_ajax_jitm_dismiss' ) );
+ add_action( 'admin_init', array( $this, 'sync_sidebar_collapsed_state' ) );
+ add_action( 'admin_menu', array( $this, 'remove_submenus' ), 140 ); // After hookpress hook at 130.
+ }
+
+ /**
+ * Create the desired menu output.
+ */
+ public function reregister_menu_items() {
+ parent::reregister_menu_items();
+
+ $this->add_my_home_menu();
+ $this->add_inbox_menu();
+
+ // Not needed outside of wp-admin.
+ if ( ! $this->is_api_request ) {
+ $this->add_browse_sites_link();
+ $this->add_site_card_menu();
+ $nudge = $this->get_upsell_nudge();
+ if ( $nudge ) {
+ parent::add_upsell_nudge( $nudge );
+ }
+ $this->add_new_site_link();
+ }
+
+ $this->add_woocommerce_installation_menu( $this->get_current_plan() );
+
+ ksort( $GLOBALS['menu'] );
+ }
+
+ /**
+ * Get the preferred view for the given screen.
+ *
+ * @param string $screen Screen identifier.
+ * @param bool $fallback_global_preference (Optional) Whether the global preference for all screens should be used
+ * as fallback if there is no specific preference for the given screen.
+ * Default: true.
+ * @return string
+ */
+ public function get_preferred_view( $screen, $fallback_global_preference = true ) {
+ // When no preferred view has been set for Themes, keep the previous behavior that forced the default view
+ // regardless of the global preference.
+ if ( $fallback_global_preference && 'themes.php' === $screen ) {
+ $preferred_view = parent::get_preferred_view( $screen, false );
+ if ( self::UNKNOWN_VIEW === $preferred_view ) {
+ return self::DEFAULT_VIEW;
+ }
+ return $preferred_view;
+ }
+
+ // Plugins on Simple sites are always managed on Calypso.
+ if ( 'plugins.php' === $screen ) {
+ return self::DEFAULT_VIEW;
+ }
+
+ return parent::get_preferred_view( $screen, $fallback_global_preference );
+ }
+
+ /**
+ * Adds the site switcher link if user has more than one site.
+ */
+ public function add_browse_sites_link() {
+ if ( count( get_blogs_of_user( get_current_user_id() ) ) < 2 ) {
+ return;
+ }
+
+ // Add the menu item.
+ add_menu_page( __( 'site-switcher', 'jetpack' ), __( 'Browse sites', 'jetpack' ), 'read', 'https://wordpress.com/home', null, 'dashicons-arrow-left-alt2', 0 );
+ add_filter( 'add_menu_classes', array( $this, 'set_browse_sites_link_class' ) );
+ }
+
+ /**
+ * Adds a custom element class for Site Switcher menu item.
+ *
+ * @param array $menu Associative array of administration menu items.
+ * @return array
+ */
+ public function set_browse_sites_link_class( array $menu ) {
+ foreach ( $menu as $key => $menu_item ) {
+ if ( 'site-switcher' !== $menu_item[3] ) {
+ continue;
+ }
+
+ $menu[ $key ][4] = add_cssclass( 'site-switcher', $menu_item[4] );
+ break;
+ }
+
+ return $menu;
+ }
+
+ /**
+ * Adds a link to the menu to create a new site.
+ */
+ public function add_new_site_link() {
+ if ( count( get_blogs_of_user( get_current_user_id() ) ) > 1 ) {
+ return;
+ }
+
+ $this->add_admin_menu_separator();
+ add_menu_page( __( 'Add New Site', 'jetpack' ), __( 'Add New Site', 'jetpack' ), 'read', 'https://wordpress.com/start?ref=calypso-sidebar', null, 'dashicons-plus-alt' );
+ }
+
+ /**
+ * Adds site card component.
+ */
+ public function add_site_card_menu() {
+ $default = 'data:image/svg+xml,' . rawurlencode( '<svg class="gridicon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>Globe</title><rect fill-opacity="0" x="0" width="24" height="24"/><g><path fill="#fff" d="M12 2C6.477 2 2 6.477 2 12s4.477 10 10 10 10-4.477 10-10S17.523 2 12 2zm0 18l2-2 1-1v-2h-2v-1l-1-1H9v3l2 2v1.93c-3.94-.494-7-3.858-7-7.93l1 1h2v-2h2l3-3V6h-2L9 5v-.41C9.927 4.21 10.94 4 12 4s2.073.212 3 .59V6l-1 1v2l1 1 3.13-3.13c.752.897 1.304 1.964 1.606 3.13H18l-2 2v2l1 1h2l.286.286C18.03 18.06 15.24 20 12 20z"/></g></svg>' );
+ $icon = get_site_icon_url( 32, $default );
+ $blog_name = get_option( 'blogname' ) !== '' ? get_option( 'blogname' ) : $this->domain;
+ $is_coming_soon = ( wpcom_is_coming_soon() && is_private_blog() ) || (bool) get_option( 'wpcom_public_coming_soon' );
+
+ if ( $default === $icon && blavatar_exists( $this->domain ) ) {
+ $icon = blavatar_url( $this->domain, 'img', 32 );
+ }
+
+ $badge = '';
+ if ( is_private_blog() || $is_coming_soon ) {
+ $badge .= sprintf(
+ '<span class="site__badge site__badge-private">%s</span>',
+ $is_coming_soon ? esc_html__( 'Coming Soon', 'jetpack' ) : esc_html__( 'Private', 'jetpack' )
+ );
+ }
+
+ if ( function_exists( 'is_simple_site_redirect' ) && is_simple_site_redirect( $this->domain ) ) {
+ $badge .= '<span class="site__badge site__badge-redirect">' . esc_html__( 'Redirect', 'jetpack' ) . '</span>';
+ }
+
+ if ( ! empty( get_option( 'options' )['is_domain_only'] ) ) {
+ $badge .= '<span class="site__badge site__badge-domain-only">' . esc_html__( 'Domain', 'jetpack' ) . '</span>';
+ }
+
+ $site_card = '
+<div class="site__info">
+ <div class="site__title">%1$s</div>
+ <div class="site__domain">%2$s</div>
+ %3$s
+</div>';
+
+ $site_card = sprintf(
+ $site_card,
+ $blog_name,
+ $this->domain,
+ $badge
+ );
+
+ add_menu_page( 'site-card', $site_card, 'read', get_home_url(), null, $icon, 1 );
+ add_filter( 'add_menu_classes', array( $this, 'set_site_card_menu_class' ) );
+ }
+
+ /**
+ * Adds a custom element class and id for Site Card's menu item.
+ *
+ * @param array $menu Associative array of administration menu items.
+ * @return array
+ */
+ public function set_site_card_menu_class( array $menu ) {
+ foreach ( $menu as $key => $menu_item ) {
+ if ( 'site-card' !== $menu_item[3] ) {
+ continue;
+ }
+
+ $classes = ' toplevel_page_site-card';
+ if ( blavatar_exists( $this->domain ) ) {
+ $classes .= ' has-site-icon';
+ }
+
+ $menu[ $key ][4] = $menu_item[4] . $classes;
+ $menu[ $key ][5] = 'toplevel_page_site_card';
+ break;
+ }
+
+ return $menu;
+ }
+
+ /**
+ * Returns the first available upsell nudge.
+ *
+ * @return array
+ */
+ public function get_upsell_nudge() {
+ require_lib( 'jetpack-jitm/jitm-engine' );
+ $jitm_engine = new JITM\Engine();
+
+ $message_path = 'calypso:sites:sidebar_notice';
+ $current_user = wp_get_current_user();
+ $user_id = $current_user->ID;
+ $user_roles = implode( ',', $current_user->roles );
+ $query_string = array(
+ 'message_path' => $message_path,
+ );
+
+ // Get the top message only.
+ $message = $jitm_engine->get_top_messages( $message_path, $user_id, $user_roles, $query_string );
+
+ if ( isset( $message[0] ) ) {
+ $message = $message[0];
+ return array(
+ 'content' => $message->content['message'],
+ 'cta' => $message->CTA['message'], // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
+ 'link' => $message->CTA['link'], // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
+ 'tracks_impression_event_name' => $message->tracks['display']['name'],
+ 'tracks_impression_cta_name' => $message->tracks['display']['props']['cta_name'],
+ 'tracks_click_event_name' => $message->tracks['click']['name'],
+ 'tracks_click_cta_name' => $message->tracks['click']['props']['cta_name'],
+ 'dismissible' => $message->is_dismissible,
+ 'feature_class' => $message->feature_class,
+ 'id' => $message->id,
+ );
+ }
+ }
+
+ /**
+ * Adds Stats menu.
+ */
+ public function add_stats_menu() {
+ $menu_title = __( 'Stats', 'jetpack' );
+
+ if ( ! $this->is_api_request ) {
+ $menu_title .= sprintf(
+ '<img class="sidebar-unified__sparkline" width="80" height="20" src="%1$s" alt="%2$s">',
+ esc_url( site_url( 'wp-includes/charts/admin-bar-hours-scale-2x.php?masterbar=1&s=' . get_current_blog_id() ) ),
+ esc_attr__( 'Hourly views', 'jetpack' )
+ );
+ }
+
+ add_menu_page( __( 'Stats', 'jetpack' ), $menu_title, 'edit_posts', 'https://wordpress.com/stats/day/' . $this->domain, null, 'dashicons-chart-bar', 3 );
+ }
+
+ /**
+ * Gets the current plan and stores it in $this->current_plan so the database is only called once per request.
+ *
+ * @return array
+ */
+ private function get_current_plan() {
+ if ( empty( $this->current_plan ) && class_exists( 'WPCOM_Store_API' ) ) {
+ $this->current_plan = \WPCOM_Store_API::get_current_plan( get_current_blog_id() );
+ }
+ return $this->current_plan;
+ }
+
+ /**
+ * Adds Upgrades menu.
+ *
+ * @param string $plan The current WPCOM plan of the blog.
+ */
+ public function add_upgrades_menu( $plan = null ) {
+ $current_plan = $this->get_current_plan();
+ if ( ! empty( $current_plan['product_name_short'] ) ) {
+ $plan = $current_plan['product_name_short'];
+ }
+
+ parent::add_upgrades_menu( $plan );
+
+ $last_upgrade_submenu_position = $this->get_submenu_item_count( 'paid-upgrades.php' );
+
+ add_submenu_page( 'paid-upgrades.php', __( 'Domains', 'jetpack' ), __( 'Domains', 'jetpack' ), 'manage_options', 'https://wordpress.com/domains/manage/' . $this->domain, null, $last_upgrade_submenu_position - 1 );
+
+ /** This filter is already documented in modules/masterbar/admin-menu/class-atomic-admin-menu.php */
+ if ( apply_filters( 'jetpack_show_wpcom_upgrades_email_menu', false ) ) {
+ add_submenu_page( 'paid-upgrades.php', __( 'Emails', 'jetpack' ), __( 'Emails', 'jetpack' ), 'manage_options', 'https://wordpress.com/email/' . $this->domain, null, $last_upgrade_submenu_position );
+ }
+ }
+
+ /**
+ * Adds Appearance menu.
+ */
+ public function add_appearance_menu() {
+ $customize_url = parent::add_appearance_menu();
+
+ $this->hide_submenu_page( 'themes.php', 'theme-editor.php' );
+
+ $user_can_customize = current_user_can( 'customize' );
+
+ if ( $user_can_customize ) {
+ $customize_custom_css_url = add_query_arg( array( 'autofocus' => array( 'section' => 'jetpack_custom_css' ) ), $customize_url );
+ add_submenu_page( 'themes.php', esc_attr__( 'Additional CSS', 'jetpack' ), __( 'Additional CSS', 'jetpack' ), 'customize', esc_url( $customize_custom_css_url ), null, 20 );
+ }
+ }
+
+ /**
+ * Adds Users menu.
+ */
+ public function add_users_menu() {
+ $submenus_to_update = array(
+ 'grofiles-editor' => 'https://wordpress.com/me',
+ 'grofiles-user-settings' => 'https://wordpress.com/me/account',
+ );
+
+ if ( self::DEFAULT_VIEW === $this->get_preferred_view( 'users.php' ) ) {
+ $submenus_to_update['users.php'] = 'https://wordpress.com/people/team/' . $this->domain;
+ }
+
+ $slug = current_user_can( 'list_users' ) ? 'users.php' : 'profile.php';
+ $this->update_submenus( $slug, $submenus_to_update );
+ add_submenu_page( 'users.php', esc_attr__( 'Add New', 'jetpack' ), __( 'Add New', 'jetpack' ), 'promote_users', 'https://wordpress.com/people/new/' . $this->domain, null, 1 );
+ }
+
+ /**
+ * Adds Settings menu.
+ */
+ public function add_options_menu() {
+ parent::add_options_menu();
+
+ add_submenu_page( 'options-general.php', esc_attr__( 'Hosting Configuration', 'jetpack' ), __( 'Hosting Configuration', 'jetpack' ), 'manage_options', 'https://wordpress.com/hosting-config/' . $this->domain, null, 10 );
+ }
+
+ /**
+ * Also remove the Gutenberg plugin menu.
+ */
+ public function add_gutenberg_menus() {
+ // Always remove the Gutenberg menu.
+ remove_menu_page( 'gutenberg' );
+ parent::add_gutenberg_menus();
+ }
+
+ /**
+ * Whether to use wp-admin pages rather than Calypso.
+ *
+ * @return bool
+ */
+ public function should_link_to_wp_admin() {
+ $result = false; // Calypso.
+
+ $user_attribute = get_user_attribute( get_current_user_id(), 'calypso_preferences' );
+ if ( ! empty( $user_attribute['linkDestination'] ) ) {
+ $result = $user_attribute['linkDestination'];
+ }
+
+ return $result;
+ }
+
+ /**
+ * Adds Plugins menu.
+ */
+ public function add_plugins_menu() {
+ // TODO: Remove wpcom_menu (/wp-content/admin-plugins/wpcom-misc.php).
+ $count = '';
+ if ( ! is_multisite() && current_user_can( 'update_plugins' ) ) {
+ $update_data = wp_get_update_data();
+ $count = sprintf(
+ '<span class="update-plugins count-%s"><span class="plugin-count">%s</span></span>',
+ $update_data['counts']['plugins'],
+ number_format_i18n( $update_data['counts']['plugins'] )
+ );
+ }
+ /* translators: %s: Number of pending plugin updates. */
+ add_menu_page( esc_attr__( 'Plugins', 'jetpack' ), sprintf( __( 'Plugins %s', 'jetpack' ), $count ), 'activate_plugins', 'plugins.php', null, 'dashicons-admin-plugins', 65 );
+
+ parent::add_plugins_menu();
+ }
+
+ /**
+ * Saves the sidebar state ( expanded / collapsed ) via an ajax request.
+ */
+ public function ajax_sidebar_state() {
+ $expanded = filter_var( $_REQUEST['expanded'], FILTER_VALIDATE_BOOLEAN ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ $user_id = get_current_user_id();
+ $preferences = get_user_attribute( $user_id, 'calypso_preferences' );
+ if ( empty( $preferences ) ) {
+ $preferences = array();
+ }
+
+ $value = array_merge( (array) $preferences, array( 'sidebarCollapsed' => ! $expanded ) );
+ $value = array_filter(
+ $value,
+ function ( $preference ) {
+ return null !== $preference;
+ }
+ );
+
+ update_user_attribute( $user_id, 'calypso_preferences', $value );
+
+ die();
+ }
+
+ /**
+ * Handle ajax requests to dismiss a just-in-time-message
+ */
+ public function wp_ajax_jitm_dismiss() {
+ check_ajax_referer( 'jitm_dismiss' );
+ require_lib( 'jetpack-jitm/jitm-engine' );
+ JITM\Engine::dismiss( $_REQUEST['id'], $_REQUEST['feature_class'] );
+ wp_die();
+ }
+
+ /**
+ * Syncs the sidebar collapsed state from Calypso Preferences.
+ */
+ public function sync_sidebar_collapsed_state() {
+ $calypso_preferences = get_user_attribute( get_current_user_id(), 'calypso_preferences' );
+
+ $sidebar_collapsed = isset( $calypso_preferences['sidebarCollapsed'] ) ? $calypso_preferences['sidebarCollapsed'] : false;
+ set_user_setting( 'mfold', $sidebar_collapsed ? 'f' : 'o' );
+ }
+
+ /**
+ * Removes unwanted submenu items.
+ *
+ * These submenus are added across wp-content and should be removed together with these function calls.
+ */
+ public function remove_submenus() {
+ global $_registered_pages;
+
+ remove_submenu_page( 'index.php', 'akismet-stats' );
+ remove_submenu_page( 'index.php', 'my-comments' );
+ remove_submenu_page( 'index.php', 'stats' );
+ remove_submenu_page( 'index.php', 'subscriptions' );
+
+ /* @see https://github.com/Automattic/wp-calypso/issues/49210 */
+ remove_submenu_page( 'index.php', 'my-blogs' );
+ $_registered_pages['admin_page_my-blogs'] = true; // phpcs:ignore
+
+ remove_submenu_page( 'paid-upgrades.php', 'premium-themes' );
+ remove_submenu_page( 'paid-upgrades.php', 'domains' );
+ remove_submenu_page( 'paid-upgrades.php', 'my-upgrades' );
+ remove_submenu_page( 'paid-upgrades.php', 'billing-history' );
+
+ remove_submenu_page( 'themes.php', 'customize.php?autofocus[panel]=amp_panel&return=' . rawurlencode( admin_url() ) );
+
+ remove_submenu_page( 'users.php', 'wpcom-invite-users' ); // Wpcom_Invite_Users::action_admin_menu.
+
+ remove_submenu_page( 'options-general.php', 'adcontrol' );
+
+ // Remove menu item but continue allowing access.
+ foreach ( array( 'openidserver', 'webhooks' ) as $page_slug ) {
+ remove_submenu_page( 'options-general.php', $page_slug );
+ $_registered_pages[ 'admin_page_' . $page_slug ] = true; // phpcs:ignore
+ }
+ }
+}
diff --git a/plugins/jetpack/modules/masterbar/admin-menu/dashicon-set.php b/plugins/jetpack/modules/masterbar/admin-menu/dashicon-set.php
new file mode 100644
index 00000000..41695b06
--- /dev/null
+++ b/plugins/jetpack/modules/masterbar/admin-menu/dashicon-set.php
@@ -0,0 +1,358 @@
+<?php
+/**
+ * Array that contains all the core dashicons.
+ *
+ * @package automattic/jetpack
+ */
+
+return array(
+ 'dashicons-admin-appearance' => true,
+ 'dashicons-admin-collapse' => true,
+ 'dashicons-admin-comments' => true,
+ 'dashicons-admin-customizer' => true,
+ 'dashicons-admin-generic' => true,
+ 'dashicons-admin-home' => true,
+ 'dashicons-admin-links' => true,
+ 'dashicons-admin-media' => true,
+ 'dashicons-admin-multisite' => true,
+ 'dashicons-admin-network' => true,
+ 'dashicons-admin-page' => true,
+ 'dashicons-admin-plugins' => true,
+ 'dashicons-admin-post' => true,
+ 'dashicons-admin-settings' => true,
+ 'dashicons-admin-site-alt' => true,
+ 'dashicons-admin-site-alt2' => true,
+ 'dashicons-admin-site-alt3' => true,
+ 'dashicons-admin-site' => true,
+ 'dashicons-admin-tools' => true,
+ 'dashicons-admin-users' => true,
+ 'dashicons-airplane' => true,
+ 'dashicons-album' => true,
+ 'dashicons-align-center' => true,
+ 'dashicons-align-full-width' => true,
+ 'dashicons-align-left' => true,
+ 'dashicons-align-none' => true,
+ 'dashicons-align-pull-left' => true,
+ 'dashicons-align-pull-right' => true,
+ 'dashicons-align-right' => true,
+ 'dashicons-align-wide' => true,
+ 'dashicons-amazon' => true,
+ 'dashicons-analytics' => true,
+ 'dashicons-archive' => true,
+ 'dashicons-arrow-down-alt' => true,
+ 'dashicons-arrow-down-alt2' => true,
+ 'dashicons-arrow-down' => true,
+ 'dashicons-arrow-left-alt' => true,
+ 'dashicons-arrow-left-alt2' => true,
+ 'dashicons-arrow-left' => true,
+ 'dashicons-arrow-right-alt' => true,
+ 'dashicons-arrow-right-alt2' => true,
+ 'dashicons-arrow-right' => true,
+ 'dashicons-arrow-up-alt' => true,
+ 'dashicons-arrow-up-alt2' => true,
+ 'dashicons-arrow-up-duplicate' => true,
+ 'dashicons-arrow-up' => true,
+ 'dashicons-art' => true,
+ 'dashicons-awards' => true,
+ 'dashicons-backup' => true,
+ 'dashicons-bank' => true,
+ 'dashicons-beer' => true,
+ 'dashicons-bell' => true,
+ 'dashicons-block-default' => true,
+ 'dashicons-book-alt' => true,
+ 'dashicons-book' => true,
+ 'dashicons-buddicons-activity' => true,
+ 'dashicons-buddicons-bbpress-logo' => true,
+ 'dashicons-buddicons-buddypress-logo' => true,
+ 'dashicons-buddicons-community' => true,
+ 'dashicons-buddicons-forums' => true,
+ 'dashicons-buddicons-friends' => true,
+ 'dashicons-buddicons-groups' => true,
+ 'dashicons-buddicons-pm' => true,
+ 'dashicons-buddicons-replies' => true,
+ 'dashicons-buddicons-topics' => true,
+ 'dashicons-buddicons-tracking' => true,
+ 'dashicons-building' => true,
+ 'dashicons-businessman' => true,
+ 'dashicons-businessperson' => true,
+ 'dashicons-businesswoman' => true,
+ 'dashicons-button' => true,
+ 'dashicons-calculator' => true,
+ 'dashicons-calendar-alt' => true,
+ 'dashicons-calendar' => true,
+ 'dashicons-camera-alt' => true,
+ 'dashicons-camera' => true,
+ 'dashicons-car' => true,
+ 'dashicons-carrot' => true,
+ 'dashicons-cart' => true,
+ 'dashicons-category' => true,
+ 'dashicons-chart-area' => true,
+ 'dashicons-chart-bar' => true,
+ 'dashicons-chart-line' => true,
+ 'dashicons-chart-pie' => true,
+ 'dashicons-clipboard' => true,
+ 'dashicons-clock' => true,
+ 'dashicons-cloud-saved' => true,
+ 'dashicons-cloud-upload' => true,
+ 'dashicons-cloud' => true,
+ 'dashicons-code-standards' => true,
+ 'dashicons-coffee' => true,
+ 'dashicons-color-picker' => true,
+ 'dashicons-columns' => true,
+ 'dashicons-controls-back' => true,
+ 'dashicons-controls-forward' => true,
+ 'dashicons-controls-pause' => true,
+ 'dashicons-controls-play' => true,
+ 'dashicons-controls-repeat' => true,
+ 'dashicons-controls-skipback' => true,
+ 'dashicons-controls-skipforward' => true,
+ 'dashicons-controls-volumeoff' => true,
+ 'dashicons-controls-volumeon' => true,
+ 'dashicons-cover-image' => true,
+ 'dashicons-dashboard' => true,
+ 'dashicons-database-add' => true,
+ 'dashicons-database-export' => true,
+ 'dashicons-database-import' => true,
+ 'dashicons-database-remove' => true,
+ 'dashicons-database-view' => true,
+ 'dashicons-database' => true,
+ 'dashicons-desktop' => true,
+ 'dashicons-dismiss' => true,
+ 'dashicons-download' => true,
+ 'dashicons-drumstick' => true,
+ 'dashicons-edit-large' => true,
+ 'dashicons-edit-page' => true,
+ 'dashicons-edit' => true,
+ 'dashicons-editor-aligncenter' => true,
+ 'dashicons-editor-alignleft' => true,
+ 'dashicons-editor-alignright' => true,
+ 'dashicons-editor-bold' => true,
+ 'dashicons-editor-break' => true,
+ 'dashicons-editor-code-duplicate' => true,
+ 'dashicons-editor-code' => true,
+ 'dashicons-editor-contract' => true,
+ 'dashicons-editor-customchar' => true,
+ 'dashicons-editor-expand' => true,
+ 'dashicons-editor-help' => true,
+ 'dashicons-editor-indent' => true,
+ 'dashicons-editor-insertmore' => true,
+ 'dashicons-editor-italic' => true,
+ 'dashicons-editor-justify' => true,
+ 'dashicons-editor-kitchensink' => true,
+ 'dashicons-editor-ltr' => true,
+ 'dashicons-editor-ol-rtl' => true,
+ 'dashicons-editor-ol' => true,
+ 'dashicons-editor-outdent' => true,
+ 'dashicons-editor-paragraph' => true,
+ 'dashicons-editor-paste-text' => true,
+ 'dashicons-editor-paste-word' => true,
+ 'dashicons-editor-quote' => true,
+ 'dashicons-editor-removeformatting' => true,
+ 'dashicons-editor-rtl' => true,
+ 'dashicons-editor-spellcheck' => true,
+ 'dashicons-editor-strikethrough' => true,
+ 'dashicons-editor-table' => true,
+ 'dashicons-editor-textcolor' => true,
+ 'dashicons-editor-ul' => true,
+ 'dashicons-editor-underline' => true,
+ 'dashicons-editor-unlink' => true,
+ 'dashicons-editor-video' => true,
+ 'dashicons-ellipsis' => true,
+ 'dashicons-email-alt' => true,
+ 'dashicons-email-alt2' => true,
+ 'dashicons-email' => true,
+ 'dashicons-embed-audio' => true,
+ 'dashicons-embed-generic' => true,
+ 'dashicons-embed-photo' => true,
+ 'dashicons-embed-post' => true,
+ 'dashicons-embed-video' => true,
+ 'dashicons-excerpt-view' => true,
+ 'dashicons-exit' => true,
+ 'dashicons-external' => true,
+ 'dashicons-facebook-alt' => true,
+ 'dashicons-facebook' => true,
+ 'dashicons-feedback' => true,
+ 'dashicons-filter' => true,
+ 'dashicons-flag' => true,
+ 'dashicons-food' => true,
+ 'dashicons-format-aside' => true,
+ 'dashicons-format-audio' => true,
+ 'dashicons-format-chat' => true,
+ 'dashicons-format-gallery' => true,
+ 'dashicons-format-image' => true,
+ 'dashicons-format-quote' => true,
+ 'dashicons-format-status' => true,
+ 'dashicons-format-video' => true,
+ 'dashicons-forms' => true,
+ 'dashicons-fullscreen-alt' => true,
+ 'dashicons-fullscreen-exit-alt' => true,
+ 'dashicons-games' => true,
+ 'dashicons-google' => true,
+ 'dashicons-googleplus' => true,
+ 'dashicons-grid-view' => true,
+ 'dashicons-groups' => true,
+ 'dashicons-hammer' => true,
+ 'dashicons-heading' => true,
+ 'dashicons-heart' => true,
+ 'dashicons-hidden' => true,
+ 'dashicons-hourglass' => true,
+ 'dashicons-html' => true,
+ 'dashicons-id-alt' => true,
+ 'dashicons-id' => true,
+ 'dashicons-image-crop' => true,
+ 'dashicons-image-filter' => true,
+ 'dashicons-image-flip-horizontal' => true,
+ 'dashicons-image-flip-vertical' => true,
+ 'dashicons-image-rotate-left' => true,
+ 'dashicons-image-rotate-right' => true,
+ 'dashicons-image-rotate' => true,
+ 'dashicons-images-alt' => true,
+ 'dashicons-images-alt2' => true,
+ 'dashicons-index-card' => true,
+ 'dashicons-info-outline' => true,
+ 'dashicons-info' => true,
+ 'dashicons-insert-after' => true,
+ 'dashicons-insert-before' => true,
+ 'dashicons-insert' => true,
+ 'dashicons-instagram' => true,
+ 'dashicons-laptop' => true,
+ 'dashicons-layout' => true,
+ 'dashicons-leftright' => true,
+ 'dashicons-lightbulb' => true,
+ 'dashicons-linkedin' => true,
+ 'dashicons-list-view' => true,
+ 'dashicons-location-alt' => true,
+ 'dashicons-location' => true,
+ 'dashicons-lock-duplicate' => true,
+ 'dashicons-lock' => true,
+ 'dashicons-marker' => true,
+ 'dashicons-media-archive' => true,
+ 'dashicons-media-audio' => true,
+ 'dashicons-media-code' => true,
+ 'dashicons-media-default' => true,
+ 'dashicons-media-document' => true,
+ 'dashicons-media-interactive' => true,
+ 'dashicons-media-spreadsheet' => true,
+ 'dashicons-media-text' => true,
+ 'dashicons-media-video' => true,
+ 'dashicons-megaphone' => true,
+ 'dashicons-menu-alt' => true,
+ 'dashicons-menu-alt2' => true,
+ 'dashicons-menu-alt3' => true,
+ 'dashicons-menu' => true,
+ 'dashicons-microphone' => true,
+ 'dashicons-migrate' => true,
+ 'dashicons-minus' => true,
+ 'dashicons-money-alt' => true,
+ 'dashicons-money' => true,
+ 'dashicons-move' => true,
+ 'dashicons-nametag' => true,
+ 'dashicons-networking' => true,
+ 'dashicons-no-alt' => true,
+ 'dashicons-no' => true,
+ 'dashicons-open-folder' => true,
+ 'dashicons-palmtree' => true,
+ 'dashicons-paperclip' => true,
+ 'dashicons-pdf' => true,
+ 'dashicons-performance' => true,
+ 'dashicons-pets' => true,
+ 'dashicons-phone' => true,
+ 'dashicons-pinterest' => true,
+ 'dashicons-playlist-audio' => true,
+ 'dashicons-playlist-video' => true,
+ 'dashicons-plugins-checked' => true,
+ 'dashicons-plus-alt' => true,
+ 'dashicons-plus-alt2' => true,
+ 'dashicons-plus' => true,
+ 'dashicons-podio' => true,
+ 'dashicons-portfolio' => true,
+ 'dashicons-post-status' => true,
+ 'dashicons-pressthis' => true,
+ 'dashicons-printer' => true,
+ 'dashicons-privacy' => true,
+ 'dashicons-products' => true,
+ 'dashicons-randomize' => true,
+ 'dashicons-reddit' => true,
+ 'dashicons-redo' => true,
+ 'dashicons-remove' => true,
+ 'dashicons-rest-api' => true,
+ 'dashicons-rss' => true,
+ 'dashicons-saved' => true,
+ 'dashicons-schedule' => true,
+ 'dashicons-screenoptions' => true,
+ 'dashicons-search' => true,
+ 'dashicons-share-alt' => true,
+ 'dashicons-share-alt2' => true,
+ 'dashicons-share' => true,
+ 'dashicons-shield-alt' => true,
+ 'dashicons-shield' => true,
+ 'dashicons-shortcode' => true,
+ 'dashicons-slides' => true,
+ 'dashicons-smartphone' => true,
+ 'dashicons-smiley' => true,
+ 'dashicons-sort' => true,
+ 'dashicons-sos' => true,
+ 'dashicons-spotify' => true,
+ 'dashicons-star-empty' => true,
+ 'dashicons-star-filled' => true,
+ 'dashicons-star-half' => true,
+ 'dashicons-sticky' => true,
+ 'dashicons-store' => true,
+ 'dashicons-superhero-alt' => true,
+ 'dashicons-superhero' => true,
+ 'dashicons-table-col-after' => true,
+ 'dashicons-table-col-before' => true,
+ 'dashicons-table-col-delete' => true,
+ 'dashicons-table-row-after' => true,
+ 'dashicons-table-row-before' => true,
+ 'dashicons-table-row-delete' => true,
+ 'dashicons-tablet' => true,
+ 'dashicons-tag' => true,
+ 'dashicons-tagcloud' => true,
+ 'dashicons-testimonial' => true,
+ 'dashicons-text-page' => true,
+ 'dashicons-text' => true,
+ 'dashicons-thumbs-down' => true,
+ 'dashicons-thumbs-up' => true,
+ 'dashicons-tickets-alt' => true,
+ 'dashicons-tickets' => true,
+ 'dashicons-tide' => true,
+ 'dashicons-translation' => true,
+ 'dashicons-trash' => true,
+ 'dashicons-twitch' => true,
+ 'dashicons-twitter-alt' => true,
+ 'dashicons-twitter' => true,
+ 'dashicons-undo' => true,
+ 'dashicons-universal-access-alt' => true,
+ 'dashicons-universal-access' => true,
+ 'dashicons-unlock' => true,
+ 'dashicons-update-alt' => true,
+ 'dashicons-update' => true,
+ 'dashicons-upload' => true,
+ 'dashicons-vault' => true,
+ 'dashicons-video-alt' => true,
+ 'dashicons-video-alt2' => true,
+ 'dashicons-video-alt3' => true,
+ 'dashicons-visibility' => true,
+ 'dashicons-warning' => true,
+ 'dashicons-welcome-add-page' => true,
+ 'dashicons-welcome-comments' => true,
+ 'dashicons-welcome-learn-more' => true,
+ 'dashicons-welcome-view-site' => true,
+ 'dashicons-welcome-widgets-menus' => true,
+ 'dashicons-welcome-write-blog' => true,
+ 'dashicons-whatsapp' => true,
+ 'dashicons-wordpress-alt' => true,
+ 'dashicons-wordpress' => true,
+ 'dashicons-xing' => true,
+ 'dashicons-yes-alt' => true,
+ 'dashicons-yes' => true,
+ 'dashicons-youtube' => true,
+ 'dashicons-editor-distractionfree' => true,
+ 'dashicons-exerpt-view' => true,
+ 'dashicons-format-links' => true,
+ 'dashicons-format-standard' => true,
+ 'dashicons-post-trash' => true,
+ 'dashicons-share1' => true,
+ 'dashicons-welcome-edit-page' => true,
+);
diff --git a/plugins/jetpack/modules/masterbar/admin-menu/load.php b/plugins/jetpack/modules/masterbar/admin-menu/load.php
new file mode 100644
index 00000000..412819ef
--- /dev/null
+++ b/plugins/jetpack/modules/masterbar/admin-menu/load.php
@@ -0,0 +1,126 @@
+<?php
+/**
+ * Admin Menu loader.
+ *
+ * @package Jetpack
+ */
+
+namespace Automattic\Jetpack\Dashboard_Customizations;
+
+use Automattic\Jetpack\Status\Host;
+use Automattic\Jetpack\Tracking;
+
+/**
+ * Checks whether the navigation customizations should be performed for the given class.
+ *
+ * @param string $admin_menu_class Class name.
+ *
+ * @return bool
+ */
+function should_customize_nav( $admin_menu_class ) {
+ // Make sure the class extends the base admin menu class.
+ if ( ! is_subclass_of( $admin_menu_class, Base_Admin_Menu::class ) ) {
+ return false;
+ }
+
+ $is_api_request = defined( 'REST_REQUEST' ) && REST_REQUEST || 0 === strpos( $_SERVER['REQUEST_URI'], '/?rest_route=%2Fwpcom%2Fv2%2Fadmin-menu' );
+
+ // No nav customizations on WP Admin of Atomic sites when SSO is disabled.
+ if ( is_a( $admin_menu_class, Atomic_Admin_Menu::class, true ) && ! $is_api_request && ! \Jetpack::is_module_active( 'sso' ) ) {
+ return false;
+ }
+
+ // No nav customizations on WP Admin of Jetpack sites.
+ if ( is_a( $admin_menu_class, Jetpack_Admin_Menu::class, true ) && ! $is_api_request ) {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Gets the name of the class that customizes the admin menu.
+ *
+ * @return string Class name.
+ */
+function get_admin_menu_class() {
+ // WordPress.com Atomic sites.
+ if ( ( new Host() )->is_woa_site() ) {
+ require_once __DIR__ . '/class-atomic-admin-menu.php';
+ return Atomic_Admin_Menu::class;
+ }
+
+ // WordPress.com Simple sites.
+ if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
+ $blog_id = get_current_blog_id();
+
+ // Domain-only sites.
+ $blog_options = get_blog_option( $blog_id, 'options' );
+ $is_domain_only = ! empty( $blog_options['is_domain_only'] );
+ if ( $is_domain_only ) {
+ require_once __DIR__ . '/class-domain-only-admin-menu.php';
+ return Domain_Only_Admin_Menu::class;
+ }
+
+ // DIFM Lite In Progress Sites. Uses the same menu used for domain-only sites.
+ // Ignore this check if we are in a support session.
+ $is_difm_lite_in_progress = has_blog_sticker( 'difm-lite-in-progress' );
+ $is_support_session = defined( 'WPCOM_SUPPORT_SESSION' ) && WPCOM_SUPPORT_SESSION;
+ if ( $is_difm_lite_in_progress && ! $is_support_session ) {
+ require_once __DIR__ . '/class-domain-only-admin-menu.php';
+ return Domain_Only_Admin_Menu::class;
+ }
+
+ // P2 sites.
+ require_once WP_CONTENT_DIR . '/lib/wpforteams/functions.php';
+ if ( \WPForTeams\is_wpforteams_site( $blog_id ) ) {
+ require_once __DIR__ . '/class-p2-admin-menu.php';
+ return P2_Admin_Menu::class;
+ }
+
+ // Rest of simple sites.
+ require_once __DIR__ . '/class-wpcom-admin-menu.php';
+ return WPcom_Admin_Menu::class;
+ }
+
+ // Jetpack sites.
+ require_once __DIR__ . '/class-jetpack-admin-menu.php';
+ return Jetpack_Admin_Menu::class;
+}
+
+/**
+ * Filters the name of the class that customizes the admin menu. It should extends the `Base_Admin_Menu` class.
+ *
+ * @module masterbar
+ *
+ * @since 9.6.0
+ *
+ * @param string $admin_menu_class Class name.
+ */
+$admin_menu_class = apply_filters( 'jetpack_admin_menu_class', get_admin_menu_class() );
+if ( should_customize_nav( $admin_menu_class ) ) {
+ /** The admin menu singleton instance. @var Base_Admin_Menu $instance */
+ $admin_menu_class::get_instance();
+
+ /**
+ * Trigger an event when the user uses the dashboard quick switcher.
+ *
+ * @param string $screen The current screen.
+ * @param string $view The view the user choosed to go to.
+ */
+ function dashboard_quick_switcher_record_usage( $screen, $view ) {
+ require_once __DIR__ . '/class-dashboard-switcher-tracking.php';
+
+ $tracking = new Dashboard_Switcher_Tracking(
+ new Tracking( Dashboard_Switcher_Tracking::get_jetpack_tracking_product() ),
+ array( Dashboard_Switcher_Tracking::class, 'wpcom_tracks_record_event' ),
+ Dashboard_Switcher_Tracking::get_plan()
+ );
+
+ $tracking->record_switch_event( $screen, $view );
+ }
+
+ \add_action( 'jetpack_dashboard_switcher_changed_view', __NAMESPACE__ . '\dashboard_quick_switcher_record_usage', 10, 2 );
+} else {
+ \add_filter( 'jetpack_load_admin_menu_class', '__return_false' );
+}
diff --git a/plugins/jetpack/modules/masterbar/admin-menu/menu-mappings.php b/plugins/jetpack/modules/masterbar/admin-menu/menu-mappings.php
new file mode 100644
index 00000000..f17acb9e
--- /dev/null
+++ b/plugins/jetpack/modules/masterbar/admin-menu/menu-mappings.php
@@ -0,0 +1,31 @@
+<?php
+/**
+ * Helper mapping between WP Admin pages and WordPress.com
+ *
+ * @package automattic/jetpack
+ */
+
+$common_mappings = array(
+ 'upload.php' => 'https://wordpress.com/media/',
+ 'edit.php' => 'https://wordpress.com/posts/',
+ 'edit-comments.php' => 'https://wordpress.com/comments/',
+ 'import.php' => 'https://wordpress.com/import/',
+ 'edit.php?post_type=page' => 'https://wordpress.com/pages/',
+ 'edit.php?post_type=post' => 'https://wordpress.com/posts/',
+ 'users.php' => 'https://wordpress.com/people/team/',
+ 'options-general.php' => 'https://wordpress.com/settings/general/',
+ 'options-discussion.php' => 'https://wordpress.com/settings/discussion/',
+ 'options-writing.php' => 'https://wordpress.com/settings/writing/',
+ 'themes.php' => 'https://wordpress.com/themes/',
+ 'edit-tags.php?taxonomy=category' => 'https://wordpress.com/settings/taxonomies/category/',
+ 'edit-tags.php?taxonomy=post_tag' => 'https://wordpress.com/settings/taxonomies/post_tag/',
+ 'edit.php?post_type=jetpack-portfolio' => 'https://wordpress.com/types/jetpack-portfolio/',
+ 'edit.php?post_type=jetpack-testimonial' => 'https://wordpress.com/types/jetpack-testimonial/',
+);
+
+if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
+ // WPCOM Specific mappings.
+ $common_mappings['export.php'] = 'https://wordpress.com/export/';
+}
+
+return $common_mappings;