diff --git a/projects/plugins/jetpack/_inc/client/components/global-notices/style.scss b/projects/plugins/jetpack/_inc/client/components/global-notices/style.scss index 37bd8777e067..3d7a3ecde72c 100644 --- a/projects/plugins/jetpack/_inc/client/components/global-notices/style.scss +++ b/projects/plugins/jetpack/_inc/client/components/global-notices/style.scss @@ -3,7 +3,6 @@ @use "../../scss/calypso-mixins"; .global-notices { - text-align: right; pointer-events: none; z-index: z-index.z-index("root", ".global-notices"); @@ -39,44 +38,26 @@ } } -.global-notices .dops-notice { - flex-wrap: nowrap; +/* Targets children: `Notice.Root`'s own class is a hashed CSS-module name. */ +.global-notices > * { margin-bottom: 0; - text-align: left; - pointer-events: auto; - border-radius: 0; - box-shadow: - 0 2px 5px rgba(0, 0, 0, 0.2), - 0 0 56px rgba(0, 0, 0, 0.15); - - .dops-notice__icon-wrapper { - border-radius: 0; - } - - @include calypso-mixins.breakpoint( ">660px" ) { - display: flex; - overflow: hidden; - margin-bottom: 24px; - border-radius: 3px; - - .dops-notice__icon-wrapper { - border-radius: 3px 0 0 3px; - } - } -} -.global-notices .dops-notice a.dops-notice__action { + /* A size-contained child reports no width in this shrink-to-fit + container, collapsing the toast. Only titled notices query it. */ + container-type: normal; - @include calypso-mixins.breakpoint( ">660px" ) { - font-size: 14px; - padding: 13px 16px; - } -} + /* The container is click-through, so each notice opts back in. */ + pointer-events: auto; -.global-notices .dops-notice__dismiss { - flex-shrink: 0; + /* `@wordpress/ui`'s medium elevation. Copied, not referenced: its + `--_wp-ui-elevation-md` is redeclared per component, never published. */ + box-shadow: + 0 2px 3px rgba(0, 0, 0, 0.05), + 0 4px 5px rgba(0, 0, 0, 0.04), + 0 12px 12px rgba(0, 0, 0, 0.03), + 0 16px 16px rgba(0, 0, 0, 0.02); @include calypso-mixins.breakpoint( ">660px" ) { - padding: 13px 16px 0; + margin-bottom: 24px; } } diff --git a/projects/plugins/jetpack/_inc/client/components/jetpack-notices/deprecation-notice.jsx b/projects/plugins/jetpack/_inc/client/components/jetpack-notices/deprecation-notice.jsx index 76e31bac2de8..d1f399942aaf 100644 --- a/projects/plugins/jetpack/_inc/client/components/jetpack-notices/deprecation-notice.jsx +++ b/projects/plugins/jetpack/_inc/client/components/jetpack-notices/deprecation-notice.jsx @@ -7,10 +7,10 @@ const DeprecationNotice = ( { dismissNotice, message, link, linkText, title } ) return ( - { title &&
{ title }
}
{ message }
{ link && ( diff --git a/projects/plugins/jetpack/_inc/client/components/jetpack-notices/dismissable.jsx b/projects/plugins/jetpack/_inc/client/components/jetpack-notices/dismissable.jsx index 3347b6c10354..ba5b059cc2d6 100644 --- a/projects/plugins/jetpack/_inc/client/components/jetpack-notices/dismissable.jsx +++ b/projects/plugins/jetpack/_inc/client/components/jetpack-notices/dismissable.jsx @@ -24,7 +24,7 @@ class DismissableNotices extends Component { }; render() { - return
{ this.renderNotices() }
; + return this.renderNotices() || null; } } diff --git a/projects/plugins/jetpack/_inc/client/components/jetpack-notices/error-notice-cycle-connection.jsx b/projects/plugins/jetpack/_inc/client/components/jetpack-notices/error-notice-cycle-connection.jsx index 43addd4dc9c4..25afe5e57550 100644 --- a/projects/plugins/jetpack/_inc/client/components/jetpack-notices/error-notice-cycle-connection.jsx +++ b/projects/plugins/jetpack/_inc/client/components/jetpack-notices/error-notice-cycle-connection.jsx @@ -24,7 +24,6 @@ export default class ErrorNoticeCycleConnection extends Component { showDismiss={ false } text={ this.props.text } status={ 'is-error' } - icon={ 'link-break' } display={ this.props.display } > + { this.props.siteConnectionStatus && this.props.userCanConnectSite && @@ -255,7 +256,7 @@ class JetpackNotices extends Component { linkText={ link.label } /> ) ) } - + ); } } diff --git a/projects/plugins/jetpack/_inc/client/components/jetpack-notices/jetpack-connection-errors.jsx b/projects/plugins/jetpack/_inc/client/components/jetpack-notices/jetpack-connection-errors.jsx index e08566458872..ee967f710f74 100644 --- a/projects/plugins/jetpack/_inc/client/components/jetpack-notices/jetpack-connection-errors.jsx +++ b/projects/plugins/jetpack/_inc/client/components/jetpack-notices/jetpack-connection-errors.jsx @@ -1,4 +1,5 @@ import { __ } from '@wordpress/i18n'; +import { Stack } from '@wordpress/ui'; import PropTypes from 'prop-types'; import { Component, Fragment } from 'react'; import SimpleNotice from 'components/notice'; @@ -33,7 +34,6 @@ export default class JetpackConnectionErrors extends Component { @@ -49,7 +49,6 @@ export default class JetpackConnectionErrors extends Component { @@ -66,11 +65,7 @@ export default class JetpackConnectionErrors extends Component { // Add secondary action if available if ( errorData.secondary_action_url && errorData.secondary_action_label ) { actions.push( - + { errorData.secondary_action_label } ); @@ -80,7 +75,6 @@ export default class JetpackConnectionErrors extends Component { @@ -128,6 +122,10 @@ export default class JetpackConnectionErrors extends Component { } } - return Object.values( errorsToDisplay ).map( error => this.renderOne( error ) ); + return ( + + { Object.values( errorsToDisplay ).map( error => this.renderOne( error ) ) } + + ); } } diff --git a/projects/plugins/jetpack/_inc/client/components/jetpack-notices/notice-action-reconnect.jsx b/projects/plugins/jetpack/_inc/client/components/jetpack-notices/notice-action-reconnect.jsx index 1460babc3077..cd276d3392ed 100644 --- a/projects/plugins/jetpack/_inc/client/components/jetpack-notices/notice-action-reconnect.jsx +++ b/projects/plugins/jetpack/_inc/client/components/jetpack-notices/notice-action-reconnect.jsx @@ -72,15 +72,10 @@ const NoticeActionReconnect = props => { analytics.tracks.recordEvent( 'jetpack_termination_error_notice_view', getEventProps() ); }, [ getEventProps ] ); - return ( - - { props.children } - - ); + return { props.children }; }; NoticeActionReconnect.propTypes = { - icon: PropTypes.string, errorCode: PropTypes.string, errorData: PropTypes.object, action: PropTypes.string, diff --git a/projects/plugins/jetpack/_inc/client/components/jetpack-notices/state-notices.jsx b/projects/plugins/jetpack/_inc/client/components/jetpack-notices/state-notices.jsx index 88bb9997975d..1c174fddcbeb 100644 --- a/projects/plugins/jetpack/_inc/client/components/jetpack-notices/state-notices.jsx +++ b/projects/plugins/jetpack/_inc/client/components/jetpack-notices/state-notices.jsx @@ -300,7 +300,7 @@ class JetpackStateNotices extends Component { }; render() { - return
{ this.state.showNotice ? this.renderContent() : null }
; + return this.state.showNotice ? this.renderContent() ?? null : null; } } diff --git a/projects/plugins/jetpack/_inc/client/components/jetpack-notices/static-warning.jsx b/projects/plugins/jetpack/_inc/client/components/jetpack-notices/static-warning.jsx index 6b304055f199..3cb9176aed5b 100644 --- a/projects/plugins/jetpack/_inc/client/components/jetpack-notices/static-warning.jsx +++ b/projects/plugins/jetpack/_inc/client/components/jetpack-notices/static-warning.jsx @@ -11,12 +11,8 @@ export class StaticWarning extends Component { render() { return ( - -
- #HEADER_TEXT# -
- #TEXT# -
+ +
#TEXT#
); } diff --git a/projects/plugins/jetpack/_inc/client/components/jetpack-notices/test/component.jsx b/projects/plugins/jetpack/_inc/client/components/jetpack-notices/test/component.jsx index 7183536a829a..bd27b2ed7d76 100644 --- a/projects/plugins/jetpack/_inc/client/components/jetpack-notices/test/component.jsx +++ b/projects/plugins/jetpack/_inc/client/components/jetpack-notices/test/component.jsx @@ -148,6 +148,7 @@ describe( 'DevVersionNotice', () => { expect( screen.getByText( 'You are currently running a development version of Jetpack.' ) ).toBeInTheDocument(); - expect( screen.getByRole( 'link', { name: 'Submit Beta feedback' } ) ).toBeInTheDocument(); + // The accessible name carries the design system's "(opens in a new tab)" suffix. + expect( screen.getByRole( 'link', { name: /Submit Beta feedback/ } ) ).toBeInTheDocument(); } ); } ); diff --git a/projects/plugins/jetpack/_inc/client/components/notice/index.jsx b/projects/plugins/jetpack/_inc/client/components/notice/index.jsx index d6dbf0ab2399..c51f47adf528 100644 --- a/projects/plugins/jetpack/_inc/client/components/notice/index.jsx +++ b/projects/plugins/jetpack/_inc/client/components/notice/index.jsx @@ -1,10 +1,7 @@ +import { Notice } from '@wordpress/ui'; import clsx from 'clsx'; import PropTypes from 'prop-types'; import { Component } from 'react'; -import Gridicon from 'components/gridicon'; -import onKeyDownCallback from 'utils/onkeydown-callback'; - -import './style.scss'; const noop = () => {}; @@ -30,8 +27,9 @@ export default class SimpleNotice extends Component { PropTypes.oneOfType( [ PropTypes.string, PropTypes.node ] ), PropTypes.arrayOf( PropTypes.oneOfType( [ PropTypes.string, PropTypes.node ] ) ), ] ), - icon: PropTypes.string, + title: PropTypes.oneOfType( [ PropTypes.string, PropTypes.node ] ), onDismissClick: PropTypes.func, + dismissText: PropTypes.string, className: PropTypes.string, display: PropTypes.bool, }; @@ -50,28 +48,19 @@ export default class SimpleNotice extends Component { } } - getIcon = () => { - let icon; - + getIntent = () => { switch ( this.props.status ) { case 'is-info': - icon = 'info'; - break; + return 'info'; case 'is-success': - icon = 'checkmark'; - break; + return 'success'; case 'is-error': - icon = 'notice'; - break; + return 'error'; case 'is-warning': - icon = 'notice'; - break; + return 'warning'; default: - icon = 'info'; - break; + return 'neutral'; } - - return icon; }; clearText = text => { @@ -85,45 +74,38 @@ export default class SimpleNotice extends Component { const { children, className, - icon, isCompact, onDismissClick, showDismiss = ! isCompact, // by default, show on normal notices, don't show on compact ones - status, text, + title, dismissText, display, } = this.props; - const classes = clsx( 'dops-notice', status, className, { - 'is-compact': isCompact, - 'is-dismissable': showDismiss, - 'is-hidden': ! display, - } ); + + // `text` marks the caller as using the two-slot form, where children are the + // actions. Without it, children are the body. + const body = text ? this.clearText( text ) : children; + const actions = text ? children : null; return ( -
- - - - - { text ? this.clearText( text ) : children } - - { text ? children : null } - { showDismiss && ( - - - - { dismissText } - - + + { title ? { title } : null } + { ( body || body === 0 ) && ( + }>{ body } ) } -
+ { actions ? { actions } : null } + { showDismiss && } + ); } } diff --git a/projects/plugins/jetpack/_inc/client/components/notice/notice-action.jsx b/projects/plugins/jetpack/_inc/client/components/notice/notice-action.jsx index ffb22ad95ea8..c597f729bb0a 100644 --- a/projects/plugins/jetpack/_inc/client/components/notice/notice-action.jsx +++ b/projects/plugins/jetpack/_inc/client/components/notice/notice-action.jsx @@ -1,8 +1,6 @@ +import { Notice } from '@wordpress/ui'; import PropTypes from 'prop-types'; import { Component } from 'react'; -import Gridicon from 'components/gridicon'; - -import './style.scss'; export default class NoticeAction extends Component { static displayName = 'NoticeAction'; @@ -11,8 +9,6 @@ export default class NoticeAction extends Component { href: PropTypes.string, onClick: PropTypes.func, external: PropTypes.bool, - icon: PropTypes.string, - variant: PropTypes.oneOf( [ 'primary', 'secondary' ] ), }; static defaultProps = { @@ -20,27 +16,17 @@ export default class NoticeAction extends Component { }; render() { - let className = 'dops-notice__action'; - if ( this.props.variant === 'secondary' ) { - className += ' is-secondary'; - } - - const attributes = { - className, - href: this.props.href, - onClick: this.props.onClick, - }; - - if ( this.props.external ) { - attributes.target = '_blank'; + const { children, href, onClick, external } = this.props; + + if ( href ) { + // `openInNewTab` also draws the external-link arrow the old Gridicon supplied. + return ( + + { children } + + ); } - return ( - - { this.props.children } - { this.props.icon && } - { this.props.external && } - - ); + return { children }; } } diff --git a/projects/plugins/jetpack/_inc/client/components/notice/test/component.jsx b/projects/plugins/jetpack/_inc/client/components/notice/test/component.jsx new file mode 100644 index 000000000000..810e2d1b3571 --- /dev/null +++ b/projects/plugins/jetpack/_inc/client/components/notice/test/component.jsx @@ -0,0 +1,137 @@ +import { render, screen } from 'test/test-utils'; +import SimpleNotice from '../index'; +import NoticeAction from '../notice-action'; + +describe( 'SimpleNotice', () => { + it( 'renders its children as the body when there is no text', () => { + render( Body copy ); + expect( screen.getByText( 'Body copy' ) ).toBeInTheDocument(); + } ); + + it( 'renders children as actions when text is set', () => { + render( + + Do the thing + + ); + expect( screen.getByText( 'The message' ) ).toBeInTheDocument(); + expect( screen.getByRole( 'link', { name: /Do the thing/ } ) ).toHaveAttribute( + 'href', + 'https://example.com/go' + ); + } ); + + it( 'renders a title above the body', () => { + render( + +
The body
+
+ ); + expect( screen.getByText( 'The heading' ) ).toBeInTheDocument(); + expect( screen.getByText( 'The body' ) ).toBeInTheDocument(); + } ); + + it.each( [ + [ 'is-error', 'error' ], + [ 'is-warning', 'warning' ], + [ 'is-success', 'success' ], + [ 'is-info', 'info' ], + ] )( 'maps status %s to the %s intent', ( status, intent ) => { + const { container } = render( Text ); + // eslint-disable-next-line testing-library/no-container + expect( container.querySelector( '.jp-notice' ).className ).toMatch( + new RegExp( `is-${ intent }` ) + ); + } ); + + // Regression: `display` used to unmount the subtree. Children such as + // NoticeActionReconnect record a Tracks event on mount, so it must hide instead. + it( 'keeps the notice mounted but hidden when display is false', () => { + const onMount = jest.fn(); + const Child = () => { + onMount(); + return Still here; + }; + + const { container } = render( + + + + ); + + // eslint-disable-next-line testing-library/no-container + expect( container.querySelector( '.jp-notice' ) ).toHaveClass( 'is-hidden' ); + expect( onMount ).toHaveBeenCalledTimes( 1 ); + } ); + + it( 'does not re-mount its children when display flips', () => { + const onMount = jest.fn(); + const Child = () => { + onMount(); + return Child; + }; + + const { rerender } = render( + + + + ); + onMount.mockClear(); + + rerender( + + + + ); + rerender( + + + + ); + + // Re-renders, but never a fresh mount. + expect( screen.getByText( 'Child' ) ).toBeInTheDocument(); + expect( onMount ).toHaveBeenCalledTimes( 2 ); + } ); + + it( 'calls onDismissClick from the close button', async () => { + const onDismissClick = jest.fn(); + render( + + ); + screen.getByRole( 'button', { name: 'Dismiss' } ).click(); + expect( onDismissClick ).toHaveBeenCalled(); + } ); + + it( 'renders no close button when showDismiss is false', () => { + render( ); + expect( screen.queryByRole( 'button' ) ).not.toBeInTheDocument(); + } ); +} ); + +describe( 'NoticeAction', () => { + it( 'renders a button when it has no href', () => { + const onClick = jest.fn(); + render( + + Press me + + ); + screen.getByRole( 'button', { name: 'Press me' } ).click(); + expect( onClick ).toHaveBeenCalled(); + } ); + + it( 'opens external links in a new tab', () => { + render( + + + Read the docs + + + ); + expect( screen.getByRole( 'link', { name: /Read the docs/ } ) ).toHaveAttribute( + 'target', + '_blank' + ); + } ); +} ); diff --git a/projects/plugins/jetpack/_inc/client/components/settings-card/style.scss b/projects/plugins/jetpack/_inc/client/components/settings-card/style.scss index 3c6baeb3a94d..29f56d099930 100644 --- a/projects/plugins/jetpack/_inc/client/components/settings-card/style.scss +++ b/projects/plugins/jetpack/_inc/client/components/settings-card/style.scss @@ -52,21 +52,10 @@ border-top: 1px solid var(--jp-gray); } - .dops-notice { - margin-bottom: 0; - - &, - .dops-notice__icon-wrapper { - border-radius: 0; - } - - .dops-notice__text { - - &, - a { - color: var(--jp-white); - } - } + // Notices sit outside `.jp-form-settings-group`, so they need its padding — + // and stay clear of the offline-mode scrim the group paints over its children. + .jp-settings-card__notice { + padding: rem.convert(16px) rem.convert(24px); } .dops-card.is-card-link + .jp-form-settings-group { diff --git a/projects/plugins/jetpack/_inc/client/reader/index.jsx b/projects/plugins/jetpack/_inc/client/reader/index.jsx index 42031139d060..ebafa0502c3a 100644 --- a/projects/plugins/jetpack/_inc/client/reader/index.jsx +++ b/projects/plugins/jetpack/_inc/client/reader/index.jsx @@ -155,7 +155,7 @@ function Reader( props ) { hideButton module={ moduleName } > - { woaNotice } + { woaNotice &&
{ woaNotice }
} { readerToggle } { visitReaderLink } diff --git a/projects/plugins/jetpack/_inc/client/scss/shared/_main.scss b/projects/plugins/jetpack/_inc/client/scss/shared/_main.scss index 53f31e539750..0e73b8c6cea0 100644 --- a/projects/plugins/jetpack/_inc/client/scss/shared/_main.scss +++ b/projects/plugins/jetpack/_inc/client/scss/shared/_main.scss @@ -46,6 +46,21 @@ text-decoration: underline; } +// `@wordpress/ui` sits in `@layer wp-ui`, which loses to the unlayered +// `.jetpack-pagestyles a` above, and its `Link` relies on the UA underline. +// WordPress/gutenberg#82620 narrows this rather than retiring it: the upstream +// defense reaches wp-ui `Link` only, and three notices interpolate a raw ``. +.jetpack-pagestyles .jp-notice a { + text-decoration-line: underline; + text-decoration-thickness: from-font; // `text-decoration: none` above resets it. +} + +// Unlayered on purpose: `Notice.Root` sets `display: grid` +// inside `@layer wp-ui`, which `[hidden]` cannot override. +.jp-notice.is-hidden { + display: none; +} + // restyled the arrow to match our gray .toplevel_page_jetpack ul#adminmenu a.wp-has-current-submenu::after { border-right-color: colors.$gray-light; diff --git a/projects/plugins/jetpack/_inc/client/scss/style.scss b/projects/plugins/jetpack/_inc/client/scss/style.scss index 4f5fda4028b6..99fdf7600e77 100644 --- a/projects/plugins/jetpack/_inc/client/scss/style.scss +++ b/projects/plugins/jetpack/_inc/client/scss/style.scss @@ -38,6 +38,9 @@ @include meta.load-css( "../components/support-card/style" ); @include meta.load-css( "../components/forms/styles" ); @include meta.load-css( "../components/admin-notices/style" ); +// `AdminNotices` rebuilds core notices into the dops chassis with jQuery, +// so these rules outlive `SimpleNotice`'s move to `@wordpress/ui`. +@include meta.load-css( "../components/notice/style" ); @include meta.load-css( "../components/module-toggle/style" ); @include meta.load-css( "../components/navigation-settings/style" ); @include meta.load-css( "../components/settings-nav-tabs/style" ); diff --git a/projects/plugins/jetpack/_inc/client/security/account-protection.jsx b/projects/plugins/jetpack/_inc/client/security/account-protection.jsx index c5ca0764eb69..5c632b063c10 100644 --- a/projects/plugins/jetpack/_inc/client/security/account-protection.jsx +++ b/projects/plugins/jetpack/_inc/client/security/account-protection.jsx @@ -25,14 +25,15 @@ const AccountProtectionComponent = class extends Component { hideButton={ true } > { ! isSupported && ( - + { __( 'Learn more', 'jetpack' ) } - } - /> + + ) } { isSupported && ! isActive && ( - + { __( 'Learn about the risks', 'jetpack' ) } - } - /> + + ) } - { shouldShowLikeBlock && ( + + + { shouldShowLikeBlock && ( +
- ) } - +
+ ) } { shouldShowLikeBlock && configCard() } diff --git a/projects/plugins/jetpack/_inc/client/sharing/share-buttons.jsx b/projects/plugins/jetpack/_inc/client/sharing/share-buttons.jsx index d3e5bc5c8230..e0b840afcb8f 100644 --- a/projects/plugins/jetpack/_inc/client/sharing/share-buttons.jsx +++ b/projects/plugins/jetpack/_inc/client/sharing/share-buttons.jsx @@ -115,17 +115,7 @@ export const ShareButtons = withModuleSettingsFormHelpers( ); if ( ! shouldUseSharingBlockAction ) { - return ( - <> - { toggle } - { shouldShowSharingBlock && ( - - ) } - - ); + return toggle; } if ( isForcedActive ) { @@ -175,6 +165,15 @@ export const ShareButtons = withModuleSettingsFormHelpers( { moduleAction() } + { ! shouldUseSharingBlockAction && shouldShowSharingBlock && ( +
+ +
+ ) } + { ( isActive || shouldShowSharingBlock ) && ! shouldUseSharingBlockAction && configCard() } diff --git a/projects/plugins/jetpack/_inc/client/traffic/index.jsx b/projects/plugins/jetpack/_inc/client/traffic/index.jsx index 888b5f1693b9..67630b95b3a7 100644 --- a/projects/plugins/jetpack/_inc/client/traffic/index.jsx +++ b/projects/plugins/jetpack/_inc/client/traffic/index.jsx @@ -108,9 +108,13 @@ export class Traffic extends Component { /> ) } { seoMovedToDashboard && foundMovedToDashboard && ( - +
- { __( 'Jetpack SEO has its own dashboard', 'jetpack' ) }

{ __( 'Manage your search engine optimization settings from the redesigned SEO dashboard.', diff --git a/projects/plugins/jetpack/_inc/client/traffic/seo.jsx b/projects/plugins/jetpack/_inc/client/traffic/seo.jsx index 49d7b3843f40..bb48fd3a5e3d 100644 --- a/projects/plugins/jetpack/_inc/client/traffic/seo.jsx +++ b/projects/plugins/jetpack/_inc/client/traffic/seo.jsx @@ -192,9 +192,13 @@ export const SEO = withModuleSettingsFormHelpers( ); return ( - +

- { __( 'SEO has a new home', 'jetpack' ) }

{ __( 'Manage all of your search engine optimization from the redesigned Jetpack SEO dashboard.', @@ -265,6 +269,7 @@ export const SEO = withModuleSettingsFormHelpers( return acc; }, [] ); const hasConflictingSeoPlugin = conflictingSeoPlugins.length > 0; + const optInBanner = this.seoOptInBanner(); const frontPageMetaCharCountClasses = clsx( { 'jp-seo-front-page-description-count': true, @@ -286,7 +291,18 @@ export const SEO = withModuleSettingsFormHelpers( saveDisabled={ this.props.isSavingAnyOption( this.constants.moduleOptionsArray ) } hideButton={ hasConflictingSeoPlugin || ! hasSeoTools } > - { this.seoOptInBanner() } + { optInBanner &&

{ optInBanner }
} + { hasSeoTools && hasConflictingSeoPlugin && ( +
+ + { sprintf( + /* translators: %s is the name of conflicting SEO plugin */ + __( 'Your SEO settings are managed by the following plugin: %s', 'jetpack' ), + conflictingSeoPlugins[ 0 ].name + ) } + +
+ ) } { hasSeoTools && ( - { hasConflictingSeoPlugin && ( - - { sprintf( - /* translators: %s is the name of conflicting SEO plugin */ - __( 'Your SEO settings are managed by the following plugin: %s', 'jetpack' ), - conflictingSeoPlugins[ 0 ].name - ) } - - ) }

{ __( 'Take control of the way search engines represent your site. With Jetpack’s SEO tools you can preview how your content will look on popular search engines and change items like your site name and tagline in seconds.', diff --git a/projects/plugins/jetpack/changelog/update-simple-notice-wpds-wrapper b/projects/plugins/jetpack/changelog/update-simple-notice-wpds-wrapper new file mode 100644 index 000000000000..dc353b49b39e --- /dev/null +++ b/projects/plugins/jetpack/changelog/update-simple-notice-wpds-wrapper @@ -0,0 +1,4 @@ +Significance: minor +Type: enhancement + +Notices: Render Jetpack admin notices with the WordPress design system Notice component.