diff --git a/.github/files/e2e-tests/notification-rules.enc b/.github/files/e2e-tests/notification-rules.enc index efd553cb8b6a3..2aa0882859a42 100644 Binary files a/.github/files/e2e-tests/notification-rules.enc and b/.github/files/e2e-tests/notification-rules.enc differ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8f4f749c60b44..1fd3b1f59a9a0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2233,8 +2233,8 @@ importers: specifier: ^1.2.2 version: 1.3.0(preact@10.22.1) '@sentry/browser': - specifier: 7.80.1 - version: 7.80.1 + specifier: 8.33.0 + version: 8.33.0 '@tanstack/react-query': specifier: ^5.15.5 version: 5.20.5(react@18.3.1) @@ -6731,29 +6731,37 @@ packages: zen-observable: optional: true - '@sentry-internal/tracing@7.80.1': - resolution: {integrity: sha512-5gZ4LPIj2vpQl2/dHBM4uXMi9OI5E0VlOhJQt0foiuN6JJeiOjdpJFcfVqJk69wrc0deVENTtgKKktxqMwVeWQ==} - engines: {node: '>=8'} + '@sentry-internal/browser-utils@8.33.0': + resolution: {integrity: sha512-zwjmD+XI3pgxxiqKGLXYDGSd+zfO7az9zzbLn1le8Vv9cRL2lZyMLcwiwEaTpwz3B0pPONeDZMT8+bzMGRs8zw==} + engines: {node: '>=14.18'} - '@sentry/browser@7.80.1': - resolution: {integrity: sha512-1dPR6vPJ9vOTzgXff9HGheb178XeEv5hyjBNhCO1f6rjCgnVj99XGNZIgO1Ee1ALJbqlfPWaeV+uSWbbcmgJMA==} - engines: {node: '>=8'} + '@sentry-internal/feedback@8.33.0': + resolution: {integrity: sha512-KSW/aiNgmJc8PDl2NsM+ONvGure4tPaluj7O1Nw+947Dh8W6CJnQ9srB7xPyoYYWyQW8Hyl1vzxY9W0J+fjlhA==} + engines: {node: '>=14.18'} - '@sentry/core@7.80.1': - resolution: {integrity: sha512-3Yh+O9Q86MxwIuJFYtuSSoUCpdx99P1xDAqL0FIPTJ+ekaVMiUJq9NmyaNh9uN2myPSmxvEXW6q3z37zta9ZHg==} - engines: {node: '>=8'} + '@sentry-internal/replay-canvas@8.33.0': + resolution: {integrity: sha512-9fEhMP+gQYQrtn/SQd1Vd7U7emTSGBpLKc5h5f0iV0yDmjYAhNVbq4RgPTYAgnBEcdVo3qgboL6UIz9Dv+dYRQ==} + engines: {node: '>=14.18'} - '@sentry/replay@7.80.1': - resolution: {integrity: sha512-yjpftIyybQeWD2i0Nd7C96tZwjNbSMRW515EL9jwlNxYbQtGtMs0HavP9Y7uQvQrzwSHY0Wp+ooe9PMuvzqbHw==} - engines: {node: '>=12'} + '@sentry-internal/replay@8.33.0': + resolution: {integrity: sha512-GFBaDA4yhlEf3wTXOVXnJVG/diuKxeqZuXcuhsAwJb+YcFR0NhgsRn3wIGuYOZZF8GBXzx9PFnb9yIuFgx5Nbw==} + engines: {node: '>=14.18'} - '@sentry/types@7.80.1': - resolution: {integrity: sha512-CVu4uPVTOI3U9kYiOdA085R7jX5H1oVODbs9y+A8opJ0dtJTMueCXgZyE8oXQ0NjGVs6HEeaLkOuiV0mj8X3yw==} - engines: {node: '>=8'} + '@sentry/browser@8.33.0': + resolution: {integrity: sha512-qu/g20ZskywEU8BWc4Fts1kXFFBtw1vS+XvPq7Ta9zCeRG5dlXhhYDVQ4/v4nAL/cs0o6aLCq73m109CFF0Kig==} + engines: {node: '>=14.18'} - '@sentry/utils@7.80.1': - resolution: {integrity: sha512-bfFm2e/nEn+b9++QwjNEYCbS7EqmteT8uf0XUs7PljusSimIqqxDtK1pfD9zjynPgC8kW/fVBKv0pe2LufomeA==} - engines: {node: '>=8'} + '@sentry/core@8.33.0': + resolution: {integrity: sha512-618PQGHQLBVCpAq1s+e/rpIUaLUnj19IPUgn97rUGXLLna8ETIAoyQoG70wz4q9niw4Z4GlS5kZNrael2O3+2w==} + engines: {node: '>=14.18'} + + '@sentry/types@8.33.0': + resolution: {integrity: sha512-V/A+72ZdnfGtXeXIpz1kUo3LRdq3WKEYYFUR2RKpCdPh9yeOrHq6u/rmzTWx49+om0yhZN+JhVoxDzt75UoFRg==} + engines: {node: '>=14.18'} + + '@sentry/utils@8.33.0': + resolution: {integrity: sha512-TdwtGdevJij2wq2x/hDUr+x5TXt47ZhWxZ8zluai/lnIDTUB3Xs/L9yHtj1J+H9hr8obkMASE9IanUrWXzrP6Q==} + engines: {node: '>=14.18'} '@sideway/address@4.1.5': resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==} @@ -16747,37 +16755,52 @@ snapshots: transitivePeerDependencies: - zenObservable - '@sentry-internal/tracing@7.80.1': + '@sentry-internal/browser-utils@8.33.0': + dependencies: + '@sentry/core': 8.33.0 + '@sentry/types': 8.33.0 + '@sentry/utils': 8.33.0 + + '@sentry-internal/feedback@8.33.0': + dependencies: + '@sentry/core': 8.33.0 + '@sentry/types': 8.33.0 + '@sentry/utils': 8.33.0 + + '@sentry-internal/replay-canvas@8.33.0': dependencies: - '@sentry/core': 7.80.1 - '@sentry/types': 7.80.1 - '@sentry/utils': 7.80.1 + '@sentry-internal/replay': 8.33.0 + '@sentry/core': 8.33.0 + '@sentry/types': 8.33.0 + '@sentry/utils': 8.33.0 - '@sentry/browser@7.80.1': + '@sentry-internal/replay@8.33.0': dependencies: - '@sentry-internal/tracing': 7.80.1 - '@sentry/core': 7.80.1 - '@sentry/replay': 7.80.1 - '@sentry/types': 7.80.1 - '@sentry/utils': 7.80.1 + '@sentry-internal/browser-utils': 8.33.0 + '@sentry/core': 8.33.0 + '@sentry/types': 8.33.0 + '@sentry/utils': 8.33.0 - '@sentry/core@7.80.1': + '@sentry/browser@8.33.0': dependencies: - '@sentry/types': 7.80.1 - '@sentry/utils': 7.80.1 + '@sentry-internal/browser-utils': 8.33.0 + '@sentry-internal/feedback': 8.33.0 + '@sentry-internal/replay': 8.33.0 + '@sentry-internal/replay-canvas': 8.33.0 + '@sentry/core': 8.33.0 + '@sentry/types': 8.33.0 + '@sentry/utils': 8.33.0 - '@sentry/replay@7.80.1': + '@sentry/core@8.33.0': dependencies: - '@sentry-internal/tracing': 7.80.1 - '@sentry/core': 7.80.1 - '@sentry/types': 7.80.1 - '@sentry/utils': 7.80.1 + '@sentry/types': 8.33.0 + '@sentry/utils': 8.33.0 - '@sentry/types@7.80.1': {} + '@sentry/types@8.33.0': {} - '@sentry/utils@7.80.1': + '@sentry/utils@8.33.0': dependencies: - '@sentry/types': 7.80.1 + '@sentry/types': 8.33.0 '@sideway/address@4.1.5': dependencies: diff --git a/projects/js-packages/publicize-components/changelog/fix-social-share-status-tooltip-text-overflow b/projects/js-packages/publicize-components/changelog/fix-social-share-status-tooltip-text-overflow new file mode 100644 index 0000000000000..9a6eda0cf22bb --- /dev/null +++ b/projects/js-packages/publicize-components/changelog/fix-social-share-status-tooltip-text-overflow @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +Social: Fixed share status tooltip text overflow diff --git a/projects/js-packages/publicize-components/src/components/share-status/share-status-label.tsx b/projects/js-packages/publicize-components/src/components/share-status/share-status-label.tsx index 86cab5ffc97e0..bf2384e4dc0fe 100644 --- a/projects/js-packages/publicize-components/src/components/share-status/share-status-label.tsx +++ b/projects/js-packages/publicize-components/src/components/share-status/share-status-label.tsx @@ -26,7 +26,9 @@ export function ShareStatusLabel( { status, message } ) { title={ __( 'Sharing failed with the following message:', 'jetpack' ) } className={ styles[ 'share-status-icon-tooltip' ] } > - { message } + + { message } + ); diff --git a/projects/js-packages/publicize-components/src/components/share-status/styles.module.scss b/projects/js-packages/publicize-components/src/components/share-status/styles.module.scss index 0cd241f349d0d..37ae6871549f4 100644 --- a/projects/js-packages/publicize-components/src/components/share-status/styles.module.scss +++ b/projects/js-packages/publicize-components/src/components/share-status/styles.module.scss @@ -56,6 +56,10 @@ } } +.tooltip-text { + word-break: break-word; +} + .share-status-icon { fill: var(--jp-green-50); } diff --git a/projects/packages/image-cdn/changelog/add-photon-url-check-method b/projects/packages/image-cdn/changelog/add-photon-url-check-method new file mode 100644 index 0000000000000..5242de078c618 --- /dev/null +++ b/projects/packages/image-cdn/changelog/add-photon-url-check-method @@ -0,0 +1,4 @@ +Significance: minor +Type: added + +Added a public method to check if a URL is CDN url diff --git a/projects/packages/image-cdn/src/class-image-cdn-core.php b/projects/packages/image-cdn/src/class-image-cdn-core.php index d577eeb68dfe2..377a92682976c 100644 --- a/projects/packages/image-cdn/src/class-image-cdn-core.php +++ b/projects/packages/image-cdn/src/class-image-cdn-core.php @@ -156,17 +156,12 @@ public static function cdn_url( $image_url, $args = array(), $scheme = null ) { } } - /** This filter is documented below. */ - $custom_photon_url = apply_filters( 'jetpack_photon_domain', '', $image_url ); - $custom_photon_url = esc_url( $custom_photon_url ); - // You can't run a Photon URL through Photon again because query strings are stripped. // So if the image is already a Photon URL, append the new arguments to the existing URL. // Alternately, if it's a *.files.wordpress.com url or an image on a private WordPress.com Simple site, // then keep the domain as is. if ( - in_array( $image_url_parts['host'], array( 'i0.wp.com', 'i1.wp.com', 'i2.wp.com' ), true ) - || wp_parse_url( $custom_photon_url, PHP_URL_HOST ) === $image_url_parts['host'] + self::is_cdn_url( $image_url ) || $is_wpcom_image || $is_wpcom_private_site ) { @@ -245,6 +240,28 @@ public static function cdn_url( $image_url, $args = array(), $scheme = null ) { return self::cdn_url_scheme( $photon_url, $scheme ); } + /** + * Checks if a given URL is a Photon URL. + * + * @since $$next-version$$ + * @param string $url The URL to check. + * @return bool True if the URL is a Photon URL, false otherwise. + */ + public static function is_cdn_url( $url ) { + $parsed_url = wp_parse_url( $url ); + + if ( ! $parsed_url ) { + return false; + } + + // See usage in ::cdn_url for documentation of this filter + $custom_photon_url = apply_filters( 'jetpack_photon_domain', '', $url ); + $custom_photon_url = esc_url( $custom_photon_url ); + + return in_array( $parsed_url['host'], array( 'i0.wp.com', 'i1.wp.com', 'i2.wp.com' ), true ) + || wp_parse_url( $custom_photon_url, PHP_URL_HOST ) === $parsed_url['host']; + } + /** * Parses WP.com-hosted image args to replicate the crop. * diff --git a/projects/packages/image-cdn/tests/php/test_class.image_cdn_core.php b/projects/packages/image-cdn/tests/php/test_class.image_cdn_core.php index 204075146cd8c..66490b1d9854f 100644 --- a/projects/packages/image-cdn/tests/php/test_class.image_cdn_core.php +++ b/projects/packages/image-cdn/tests/php/test_class.image_cdn_core.php @@ -265,6 +265,24 @@ public function test_photon_url_filter_network_path_photonized_to_https() { $this->assertEquals( 'https://photon.test/example.com/img.jpg', $url ); } + /** + * @covers ::Image_CDN_Core::is_cdn_url + * @since $$next-version$$ + * @group jetpack_photon_filter_network_path + */ + public function test_is_cdn_url_method() { + $this->apply_custom_domain( '//photon.test' ); + $this->assertTrue( Image_CDN_Core::is_cdn_url( '//photon.test/example.com/img.jpg' ) ); + + $this->assertTrue( Image_CDN_Core::is_cdn_url( 'https://i0.wp.com/example.com/img.jpg' ) ); + $this->assertTrue( Image_CDN_Core::is_cdn_url( 'http://i1.wp.com/example.com/img.jpg' ) ); + $this->assertTrue( Image_CDN_Core::is_cdn_url( '//i2.wp.com/example.com/img.jpg' ) ); + $this->assertFalse( Image_CDN_Core::is_cdn_url( '//i3.wp.com/example.com/img.jpg' ) ); + $this->assertFalse( Image_CDN_Core::is_cdn_url( 'http://example.com/img.jpg' ) ); + $this->assertFalse( Image_CDN_Core::is_cdn_url( 'https://example.com/img.jpg' ) ); + $this->assertFalse( Image_CDN_Core::is_cdn_url( '//example.com/img.jpg' ) ); + } + /** * @author aduth * @covers ::Image_CDN_Core::cdn_url_scheme diff --git a/projects/packages/jetpack-mu-wpcom/changelog/profile-link-improvements b/projects/packages/jetpack-mu-wpcom/changelog/profile-link-improvements new file mode 100644 index 0000000000000..8b2f6f13f30ef --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/changelog/profile-link-improvements @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +profile.php: Make wpcom links more concise diff --git a/projects/packages/jetpack-mu-wpcom/changelog/renovate-npm-sentry-browser-vulnerability b/projects/packages/jetpack-mu-wpcom/changelog/renovate-npm-sentry-browser-vulnerability new file mode 100644 index 0000000000000..c47cb18e82997 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/changelog/renovate-npm-sentry-browser-vulnerability @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Updated package dependencies. diff --git a/projects/packages/jetpack-mu-wpcom/package.json b/projects/packages/jetpack-mu-wpcom/package.json index 6ff8c9e6286c6..25fc971b66496 100644 --- a/projects/packages/jetpack-mu-wpcom/package.json +++ b/projects/packages/jetpack-mu-wpcom/package.json @@ -56,7 +56,7 @@ "@automattic/typography": "1.0.0", "@popperjs/core": "^2.11.8", "@preact/signals": "^1.2.2", - "@sentry/browser": "7.80.1", + "@sentry/browser": "8.33.0", "@tanstack/react-query": "^5.15.5", "@wordpress/api-fetch": "7.8.2", "@wordpress/base-styles": "5.8.1", diff --git a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-profile-settings/profile-settings-link-to-wpcom.php b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-profile-settings/profile-settings-link-to-wpcom.php index 32c1b96dcfdba..81acaabe0df9f 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-profile-settings/profile-settings-link-to-wpcom.php +++ b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-profile-settings/profile-settings-link-to-wpcom.php @@ -41,19 +41,27 @@ function wpcom_profile_settings_add_links_to_wpcom() { array( 'language' => array( 'link' => esc_url( 'https://wordpress.com/me/account' ), - 'text' => __( 'Your admin interface language is managed on WordPress.com Account settings', 'jetpack-mu-wpcom' ), + 'text' => __( 'Manage your WordPress.com account language ↗', 'jetpack-mu-wpcom' ), ), - 'synced' => array( + 'name' => array( 'link' => esc_url( 'https://wordpress.com/me' ), - 'text' => __( 'You can manage your profile on WordPress.com Profile settings (First / Last / Display Names, Website, and Biographical Info)', 'jetpack-mu-wpcom' ), + 'text' => __( 'Manage your WordPress.com profile ↗', 'jetpack-mu-wpcom' ), + ), + 'website' => array( + 'link' => esc_url( 'https://wordpress.com/me' ), + 'text' => __( 'Manage your WordPress.com profile website ↗', 'jetpack-mu-wpcom' ), + ), + 'bio' => array( + 'link' => esc_url( 'https://wordpress.com/me' ), + 'text' => __( 'Manage your WordPress.com profile bio ↗', 'jetpack-mu-wpcom' ), ), 'email' => array( 'link' => esc_url( 'https://wordpress.com/me/account' ), - 'text' => __( 'Your WordPress.com email is managed on WordPress.com Account settings', 'jetpack-mu-wpcom' ), + 'text' => __( 'Manage your WordPress.com account email ↗', 'jetpack-mu-wpcom' ), ), 'password' => array( 'link' => esc_url( 'https://wordpress.com/me/security' ), - 'text' => __( 'Your WordPress.com password is managed on WordPress.com Security settings', 'jetpack-mu-wpcom' ), + 'text' => __( 'Manage your WordPress.com password ↗', 'jetpack-mu-wpcom' ), ), 'isWpcomAtomicClassic' => $is_wpcom_atomic_classic, ) diff --git a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-profile-settings/profile-settings-link-to-wpcom.ts b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-profile-settings/profile-settings-link-to-wpcom.ts index 621c213633e06..cd09ea23fa1b0 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-profile-settings/profile-settings-link-to-wpcom.ts +++ b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-profile-settings/profile-settings-link-to-wpcom.ts @@ -1,95 +1,140 @@ -/** - * Disable the email field except on Atomic Classic sites. - */ -const wpcom_profile_settings_disable_email_field = () => { - if ( window.wpcomProfileSettingsLinkToWpcom?.isWpcomAtomicClassic ) { - return; +const wpcom_profile_settings_modify_language_section = () => { + const section = document.querySelector( '.user-language-wrap' )?.querySelector( 'td' ); + const select = document.getElementById( 'locale' ); + const settingsLink = window.wpcomProfileSettingsLinkToWpcom?.language?.link; + const settingsLinkText = window.wpcomProfileSettingsLinkToWpcom?.language?.text; + if ( settingsLink && settingsLinkText ) { + const notice = document.createElement( 'p' ); + notice.className = 'description'; + notice.innerHTML = `${ settingsLinkText }`; + section?.appendChild( notice ); + select?.remove(); } - const emailField = document.getElementById( 'email' ) as HTMLInputElement; - if ( emailField ) { - emailField.readOnly = true; +}; + +const wpcom_profile_settings_modify_name_section = () => { + const table = document.querySelector( '.user-user-login-wrap' )?.parentElement; + + const tr = document.createElement( 'tr' ); + const th = document.createElement( 'th' ); + const td = document.createElement( 'td' ); + + const settingsLink = window.wpcomProfileSettingsLinkToWpcom?.name?.link; + const settingsLinkText = window.wpcomProfileSettingsLinkToWpcom?.name?.text; + if ( table && settingsLink && settingsLinkText ) { + const h2 = document.createElement( 'h2' ); + h2.innerHTML = 'Name'; + h2.style = 'font-size: 1.2em'; + th.appendChild( h2 ); + + const notice = document.createElement( 'p' ); + notice.className = 'description'; + notice.innerHTML = `${ settingsLinkText }`; + td.appendChild( notice ); + + tr.appendChild( th ); + tr.appendChild( td ); + table?.appendChild( tr ); + table?.parentElement?.previousElementSibling?.remove(); } - const emailDescription = document.getElementById( 'email-description' ) as HTMLInputElement; - emailDescription?.remove(); + [ + '.user-user-login-wrap', + '.user-first-name-wrap', + '.user-last-name-wrap', + '.user-nickname-wrap', + '.user-display-name-wrap', + ].forEach( selector => { + const field = document.querySelector( selector ); + if ( field ) { + field.classList.add( 'hidden' ); + } + } ); }; -/** - * Add a link to the WordPress.com profile settings page. - */ -const wpcom_profile_settings_add_links_to_wpcom = () => { - const userSessionSection = document.querySelector( '.user-sessions-wrap' ); - userSessionSection?.remove(); +const wpcom_profile_settings_modify_email_section = () => { + // Hide the email field except on Atomic Classic sites. + if ( ! window.wpcomProfileSettingsLinkToWpcom?.isWpcomAtomicClassic ) { + const field = document.getElementById( 'email' ) as HTMLInputElement; + if ( field ) { + field.classList.add( 'hidden' ); + } - // We cannot set a password in wp-admin except on Atomic Classic sites. - const newPasswordSection = document.getElementById( 'password' )?.querySelector( 'td' ); - if ( ! window.wpcomProfileSettingsLinkToWpcom?.isWpcomAtomicClassic && newPasswordSection ) { - newPasswordSection.innerHTML = ''; + const description = document.getElementById( 'email-description' ) as HTMLInputElement; + description?.remove(); } - const languageSection = document.querySelector( '.user-language-wrap' )?.querySelector( 'td' ); - const languageSelect = document.getElementById( 'locale' ); - const languageSettingsLink = window.wpcomProfileSettingsLinkToWpcom?.language?.link; - const languageSettingsLinkText = window.wpcomProfileSettingsLinkToWpcom?.language?.text; - if ( languageSettingsLink && languageSettingsLinkText ) { + const section = document.querySelector( '.user-email-wrap' )?.querySelector( 'td' ); + const settingsLink = window.wpcomProfileSettingsLinkToWpcom?.email?.link; + const settingsLinkText = window.wpcomProfileSettingsLinkToWpcom?.email?.text; + if ( section && settingsLink && settingsLinkText ) { const notice = document.createElement( 'p' ); notice.className = 'description'; - notice.innerHTML = `${ languageSettingsLinkText }.`; - languageSection?.appendChild( notice ); - languageSelect?.remove(); + notice.innerHTML = `${ settingsLinkText }`; + section.appendChild( notice ); } +}; - const emailSection = document.querySelector( '.user-email-wrap' )?.querySelector( 'td' ); - const emailSettingsLink = window.wpcomProfileSettingsLinkToWpcom?.email?.link; - const emailSettingsLinkText = window.wpcomProfileSettingsLinkToWpcom?.email?.text; - if ( emailSection && emailSettingsLink && emailSettingsLinkText ) { +const wpcom_profile_settings_modify_website_section = () => { + const section = document.querySelector( '.user-url-wrap' )?.querySelector( 'td' ); + const settingsLink = window.wpcomProfileSettingsLinkToWpcom?.website?.link; + const settingsLinkText = window.wpcomProfileSettingsLinkToWpcom?.website?.text; + if ( section && settingsLink && settingsLinkText ) { const notice = document.createElement( 'p' ); notice.className = 'description'; - notice.innerHTML = `${ emailSettingsLinkText }.`; - emailSection.appendChild( notice ); + notice.innerHTML = `${ settingsLinkText }`; + section.appendChild( notice ); } - const passwordSettingsLink = window.wpcomProfileSettingsLinkToWpcom?.password?.link; - const passwordSettingsLinkText = window.wpcomProfileSettingsLinkToWpcom?.password?.text; - if ( newPasswordSection && passwordSettingsLink && passwordSettingsLinkText ) { - const notice = document.createElement( 'p' ); - notice.className = 'description'; - notice.innerHTML = `${ passwordSettingsLinkText }.`; - newPasswordSection.appendChild( notice ); + const field = section?.querySelector( 'input' ); + if ( field ) { + field.classList.add( 'hidden' ); } +}; - const usernameSection = document.querySelector( '.user-user-login-wrap' )?.querySelector( 'td' ); - const syncedSettingsLink = window.wpcomProfileSettingsLinkToWpcom?.synced?.link; - const syncedSettingsLinkText = window.wpcomProfileSettingsLinkToWpcom?.synced?.text; - if ( usernameSection && syncedSettingsLink && syncedSettingsLinkText ) { +const wpcom_profile_settings_modify_bio_section = () => { + const section = document.querySelector( '.user-description-wrap' )?.querySelector( 'td' ); + const settingsLink = window.wpcomProfileSettingsLinkToWpcom?.bio?.link; + const settingsLinkText = window.wpcomProfileSettingsLinkToWpcom?.bio?.text; + if ( section && settingsLink && settingsLinkText ) { const notice = document.createElement( 'p' ); notice.className = 'description'; - notice.innerHTML = `${ syncedSettingsLinkText }.`; - usernameSection.appendChild( notice ); + notice.innerHTML = `${ settingsLinkText }`; + section.appendChild( notice ); } + + const field = section?.querySelector( 'textarea' ); + if ( field ) { + field.classList.add( 'hidden' ); + } + section?.querySelector( 'p' )?.remove(); }; -/** - * Hide the fields that are synced from /me. - */ -const wpcom_profile_settings_hide_synced_fields = () => { - [ - '.user-first-name-wrap', - '.user-last-name-wrap', - '.user-nickname-wrap', - '.user-display-name-wrap', - '.user-url-wrap', - '.user-description-wrap', - ].forEach( selector => { - const field = document.querySelector( selector ); - if ( field ) { - field.classList.add( 'hidden' ); - } - } ); +const wpcom_profile_settings_modify_password_section = () => { + const userSessionSection = document.querySelector( '.user-sessions-wrap' ); + userSessionSection?.remove(); + + // We cannot set a password in wp-admin except on Atomic Classic sites. + const newPasswordSection = document.getElementById( 'password' )?.querySelector( 'td' ); + if ( ! window.wpcomProfileSettingsLinkToWpcom?.isWpcomAtomicClassic && newPasswordSection ) { + newPasswordSection.innerHTML = ''; + } + + const settingsLink = window.wpcomProfileSettingsLinkToWpcom?.password?.link; + const settingsLinkText = window.wpcomProfileSettingsLinkToWpcom?.password?.text; + if ( newPasswordSection && settingsLink && settingsLinkText ) { + const notice = document.createElement( 'p' ); + notice.className = 'description'; + notice.innerHTML = `${ settingsLinkText }`; + newPasswordSection.appendChild( notice ); + } }; document.addEventListener( 'DOMContentLoaded', () => { - wpcom_profile_settings_add_links_to_wpcom(); - wpcom_profile_settings_disable_email_field(); - wpcom_profile_settings_hide_synced_fields(); + wpcom_profile_settings_modify_language_section(); + wpcom_profile_settings_modify_name_section(); + wpcom_profile_settings_modify_email_section(); + wpcom_profile_settings_modify_website_section(); + wpcom_profile_settings_modify_bio_section(); + wpcom_profile_settings_modify_password_section(); } ); diff --git a/projects/packages/videopress/changelog/update-jetpack-blocks-confusing-connection-nudges b/projects/packages/videopress/changelog/update-jetpack-blocks-confusing-connection-nudges new file mode 100644 index 0000000000000..0a41d686ca108 --- /dev/null +++ b/projects/packages/videopress/changelog/update-jetpack-blocks-confusing-connection-nudges @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Update connection nudge for VideoPress connection banner in blocks diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/components/banner/connect-banner.tsx b/projects/packages/videopress/src/client/block-editor/blocks/video/components/banner/connect-banner.tsx index a4ec01bab7afd..3e3422c1c563e 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/components/banner/connect-banner.tsx +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/components/banner/connect-banner.tsx @@ -31,15 +31,22 @@ export default function ConnectBanner( { isConnected, isConnecting, }: ConnectBannerProps ): React.ReactElement { - if ( isConnected ) { + if ( isConnected && isModuleActive ) { return null; } - let connectButtonText = __( 'Connect', 'jetpack-videopress-pkg' ); + const needsActivation = isConnected && ! isModuleActive; + + let connectButtonText = __( 'Connect Jetpack', 'jetpack-videopress-pkg' ); if ( isConnecting ) { connectButtonText = __( 'Redirecting…', 'jetpack-videopress-pkg' ); } + let activateButtonText = __( 'Activate VideoPress', 'jetpack-videopress-pkg' ); + if ( isConnecting ) { + activateButtonText = __( 'Activating…', 'jetpack-videopress-pkg' ); + } + const connectYourAccountMessage = __( 'Connect your account to continue using VideoPress', 'jetpack-videopress-pkg' @@ -58,11 +65,12 @@ export default function ConnectBanner( { disabled={ isConnecting } isBusy={ isConnecting } > - { connectButtonText } + { needsActivation ? activateButtonText : connectButtonText } } + icon={ '' } > - { isModuleActive ? connectYourAccountMessage : connectJetpackModuleMessage } + { needsActivation ? connectJetpackModuleMessage : connectYourAccountMessage } ); } diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/components/banner/index.tsx b/projects/packages/videopress/src/client/block-editor/blocks/video/components/banner/index.tsx index e6501db60bd1b..1676198043f76 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/components/banner/index.tsx +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/components/banner/index.tsx @@ -34,7 +34,7 @@ export default function BlockBanner( { }: BlockBannerProps ): React.ReactElement { return (
- + { icon && }
{ children }
{ isLoading && } { action &&
{ action }
} diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/components/banner/style.scss b/projects/packages/videopress/src/client/block-editor/blocks/video/components/banner/style.scss index 3cf78ee0e8ce9..8964f84b82a95 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/components/banner/style.scss +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/components/banner/style.scss @@ -1,15 +1,39 @@ .block-banner { display: flex; - height: 48px; + justify-content: space-between; font-size: 14px; align-self: center; align-items: center; - background: #F6F7F7; - padding: 0 16px; + background: black; + border-radius: 2px; + padding: 0 20px; + box-shadow: 0 0 1px inset white; .block-banner__content { - color: #01283d; - flex-grow: 2; - margin: 0 8px; + color: white; + margin: 10px 10px 10px 0; + } + + .block-banner__action { + padding: 0; + + .components-button.is-primary { + background: white; + color: black; + font-weight: 600; + font-size: 14px; + padding: 4px 8px; + height: 28px; + margin: 8px 0 8px auto; + + &:hover:not(:disabled) { + background: #F6F7F7; + } + } + + .components-button.is-primary.is-busy { + background-size: 100px 100%; + background-image: linear-gradient(-45deg, #e34c84 28%, #ab235a 28%, #ab235a 72%, #e34c84 72%); + } } } diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/components/videopress-uploader/index.js b/projects/packages/videopress/src/client/block-editor/blocks/video/components/videopress-uploader/index.js index e7c2b99039535..660e7833e7721 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/components/videopress-uploader/index.js +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/components/videopress-uploader/index.js @@ -10,6 +10,7 @@ import { __ } from '@wordpress/i18n'; /** * Internal dependencies */ +import { usePermission } from '../../../../../admin/hooks/use-permission'; import useResumableUploader from '../../../../../hooks/use-resumable-uploader'; import { uploadFromLibrary } from '../../../../../hooks/use-uploader'; import { buildVideoPressURL, pickVideoBlockAttributesFromUrl } from '../../../../../lib/url'; @@ -29,12 +30,15 @@ const VideoPressUploader = ( { fileToUpload, isReplacing, onReplaceCancel, + isActive, } ) => { const [ uploadPaused, setUploadPaused ] = useState( false ); const [ uploadedVideoData, setUploadedVideoData ] = useState( false ); const [ isUploadingInProgress, setIsUploadingInProgress ] = useState( false ); const [ isVerifyingLocalMedia, setIsVerifyingLocalMedia ] = useState( false ); + const { hasConnectedOwner } = usePermission(); + /* * When the file to upload is set, start the upload process * just after the component is mounted. @@ -314,6 +318,24 @@ const VideoPressUploader = ( { ); } + if ( ! isActive ) { + const needsConnectionText = __( + 'Connect your WordPress.com account to enable high-quality, ad-free video.', + 'jetpack-videopress-pkg' + ); + + const needsActivationText = __( + 'Activate the VideoPress module to enable high-quality, ad-free video.', + 'jetpack-videopress-pkg' + ); + + return ( + + { ! hasConnectedOwner ? needsConnectionText : needsActivationText } + + ); + } + // Default view to select file to upload return ( { if ( ! errorMessage ) { @@ -87,6 +89,7 @@ export const PlaceholderWrapper = withNotices( function ( { label={ title } instructions={ disableInstructions ? null : instructions } notices={ noticeUI } + className={ className } > { children } @@ -148,6 +151,7 @@ export default function VideoPressEdit( { // Get the redirect URI for the connection flow. const [ isRedirectingToMyJetpack, setIsRedirectingToMyJetpack ] = useState( false ); + const { hasConnectedOwner } = usePermission(); // Detect if the chapter file is auto-generated. const chapter = tracks?.filter( track => track.kind === 'chapters' )?.[ 0 ]; @@ -395,15 +399,15 @@ export default function VideoPressEdit( {
<> { setIsRedirectingToMyJetpack( true ); - if ( ! isStandalonePluginActive ) { - return ( window.location.href = jetpackVideoPressSettingUrl ); + if ( ! hasConnectedOwner ) { + return ( window.location.href = myJetpackConnectUrl ); } - window.location.href = myJetpackConnectUrl; + window.location.href = jetpackVideoPressSettingUrl; } } /> @@ -414,6 +418,7 @@ export default function VideoPressEdit( { fileToUpload={ fileToUpload } isReplacing={ isReplacingFile?.isReplacing } onReplaceCancel={ cancelReplacingVideoFile } + isActive={ isActive } />
@@ -592,15 +597,15 @@ export default function VideoPressEdit( { { setIsRedirectingToMyJetpack( true ); - if ( ! isStandalonePluginActive ) { - return ( window.location.href = jetpackVideoPressSettingUrl ); + if ( ! hasConnectedOwner ) { + return ( window.location.href = myJetpackConnectUrl ); } - window.location.href = myJetpackConnectUrl; + window.location.href = jetpackVideoPressSettingUrl; } } /> diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/editor.scss b/projects/packages/videopress/src/client/block-editor/blocks/video/editor.scss index 6dfbaa03c6fb1..a75c2c96c1592 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/editor.scss +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/editor.scss @@ -52,6 +52,10 @@ } } +.components-placeholder.disabled { + min-height: 0; +} + .loading-wrapper { display: flex; width: 100%; diff --git a/projects/packages/waf/changelog/add-waf-body-processor b/projects/packages/waf/changelog/add-waf-body-processor new file mode 100644 index 0000000000000..df675355a4f53 --- /dev/null +++ b/projects/packages/waf/changelog/add-waf-body-processor @@ -0,0 +1,4 @@ +Significance: minor +Type: added + +Firewall Runtime: Added support for rule files to specify body parser type. diff --git a/projects/packages/waf/src/class-waf-request.php b/projects/packages/waf/src/class-waf-request.php index 5017a2e25f46c..bbb8bcf3e17f9 100644 --- a/projects/packages/waf/src/class-waf-request.php +++ b/projects/packages/waf/src/class-waf-request.php @@ -328,28 +328,59 @@ public function get_get_vars() { return flatten_array( $_GET ); } + /** + * Returns the POST variables from a JSON body + * + * @return array{string, scalar}[] + */ + private function get_json_post_vars() { + $decoded_json = json_decode( $this->get_body(), true ) ?? array(); + return flatten_array( $decoded_json, 'json', true ); + } + + /** + * Returns the POST variables from a urlencoded body + * + * @return array{string, scalar}[] + */ + private function get_urlencoded_post_vars() { + parse_str( $this->get_body(), $params ); + return flatten_array( $params ); + } + /** * Returns the POST variables * + * @param string $body_processor Manually specifiy the method to use to process the body. Options are 'URLENCODED' and 'JSON'. + * * @return array{string, scalar}[] */ - public function get_post_vars() { + public function get_post_vars( string $body_processor = '' ) { $content_type = $this->get_header( 'content-type' ); + + // If the body processor is specified by the rules file, trust it. + if ( 'URLENCODED' === $body_processor ) { + return $this->get_urlencoded_post_vars(); + } + if ( 'JSON' === $body_processor ) { + return $this->get_json_post_vars(); + } + + // Otherwise, use $_POST if it's not empty. if ( ! empty( $_POST ) ) { - // If $_POST is populated, use it. return flatten_array( $_POST ); - } elseif ( strpos( $content_type, 'application/json' ) !== false ) { - // Attempt to decode JSON requests. - $decoded_json = json_decode( $this->get_body(), true ) ?? array(); - return flatten_array( $decoded_json, 'json', true ); - } elseif ( strpos( $content_type, 'application/x-www-form-urlencoded' ) !== false ) { - // Attempt to decode url-encoded data - parse_str( $this->get_body(), $params ); - return flatten_array( $params ); - } else { - // Don't try to parse any other content types - return array(); } + + // Lastly, try to parse the body based on the content type. + if ( strpos( $content_type, 'application/json' ) !== false ) { + return $this->get_json_post_vars(); + } + if ( strpos( $content_type, 'application/x-www-form-urlencoded' ) !== false ) { + return $this->get_urlencoded_post_vars(); + } + + // Don't try to parse any other content types. + return array(); } /** diff --git a/projects/packages/waf/src/class-waf-runtime.php b/projects/packages/waf/src/class-waf-runtime.php index 394d46aa5a6f1..19300ea804582 100644 --- a/projects/packages/waf/src/class-waf-runtime.php +++ b/projects/packages/waf/src/class-waf-runtime.php @@ -38,6 +38,14 @@ class Waf_Runtime { */ const NORMALIZE_ARRAY_MATCH_VALUES = 2; + /** + * The version of this runtime class. Used by rule files to ensure compatibility. + * + * @since $$next-version$$ + * + * @var int + */ + public $version = 1; /** * Last rule. * @@ -68,6 +76,12 @@ class Waf_Runtime { * @var string */ public $matched_var_name = ''; + /** + * Body Processor. + * + * @var string 'URLENCODED' | 'JSON' | '' + */ + private $body_processor = ''; /** * State. @@ -438,7 +452,7 @@ public function meta( $key ) { $value = $this->args_names( $this->meta( 'args_get' ) ); break; case 'args_post': - $value = $this->request->get_post_vars(); + $value = $this->request->get_post_vars( $this->get_body_processor() ); break; case 'args_post_names': $value = $this->args_names( $this->meta( 'args_post' ) ); @@ -488,6 +502,28 @@ private function state_values( $prefix ) { return $output; } + /** + * Get the body processor. + * + * @return string + */ + private function get_body_processor() { + return $this->body_processor; + } + + /** + * Set the body processor. + * + * @param string $processor Processor to set. Either 'URLENCODED' or 'JSON'. + * + * @return void + */ + public function set_body_processor( $processor ) { + if ( $processor === 'URLENCODED' || $processor === 'JSON' ) { + $this->body_processor = $processor; + } + } + /** * Change a string to all lowercase and replace spaces and underscores with dashes. * diff --git a/projects/packages/waf/tests/php/unit/test-waf-request.php b/projects/packages/waf/tests/php/unit/test-waf-request.php index ce409a4b9e5ac..01c68e5aa5bea 100644 --- a/projects/packages/waf/tests/php/unit/test-waf-request.php +++ b/projects/packages/waf/tests/php/unit/test-waf-request.php @@ -301,6 +301,64 @@ public function testGetVarsPost() { $_POST = array(); } + /** + * Test that the Waf_Request class returns POST-ed data correctly decoded from JSON via Waf_Request::get_post_vars(). + */ + public function testGetVarsPostWithJsonBodyProcessor() { + $_SERVER['CONTENT_TYPE'] = 'irrelevant'; + + $request = $this->mock_request( + array( + 'body' => json_encode( + array( + 'str' => 'value', + 'arr' => array( 'a', 'b', 'c' ), + 'obj' => (object) array( 'foo' => 'bar' ), + ) + ), + ) + ); + $value = $request->get_post_vars( 'JSON' ); + $this->assertIsArray( $value ); + $this->assertContains( array( 'json.str', 'value' ), $value ); + $this->assertContains( array( 'json.arr.0', 'a' ), $value ); + $this->assertContains( array( 'json.arr.1', 'b' ), $value ); + $this->assertContains( array( 'json.arr.2', 'c' ), $value ); + $this->assertContains( array( 'json.obj.foo', 'bar' ), $value ); + + unset( $_SERVER['CONTENT_TYPE'] ); + } + + /** + * Test that the Waf_Request class returns POST-ed data correctly decoded from URLENCODED body via Waf_Request::get_post_vars(). + */ + public function testGetVarsPostWithUrlencodedBodyProcessor() { + $_SERVER['CONTENT_TYPE'] = 'irrelevant'; + + $request = $this->mock_request( + array( + 'body' => ( + http_build_query( + array( + 'str' => 'value', + 'arr' => array( 'a', 'b', 'c' ), + 'obj' => (object) array( 'foo' => 'bar' ), + ) + ) + ), + ) + ); + $value = $request->get_post_vars( 'URLENCODED' ); + $this->assertIsArray( $value ); + $this->assertContains( array( 'str', 'value' ), $value ); + $this->assertContains( array( 'arr[0]', 'a' ), $value ); + $this->assertContains( array( 'arr[1]', 'b' ), $value ); + $this->assertContains( array( 'arr[2]', 'c' ), $value ); + $this->assertContains( array( 'obj[foo]', 'bar' ), $value ); + + unset( $_SERVER['CONTENT_TYPE'] ); + } + /** * Test that the Waf_Request class returns POST-ed data correctly decoded from JSON via Waf_Request::get_post_vars(). */ diff --git a/projects/plugins/boost/app/modules/image-guide/Image_Guide_Proxy.php b/projects/plugins/boost/app/modules/image-guide/Image_Guide_Proxy.php index 4d6ef31835cb7..8b08c45ca41b3 100644 --- a/projects/plugins/boost/app/modules/image-guide/Image_Guide_Proxy.php +++ b/projects/plugins/boost/app/modules/image-guide/Image_Guide_Proxy.php @@ -36,10 +36,8 @@ public static function handle_proxy() { wp_send_json_error( 'Invalid URL', 400 ); } - $photon_url = Image_CDN_Core::cdn_url( $proxy_url ); - $photon_url_domain = wp_parse_url( $photon_url, PHP_URL_HOST ); - $photon_domain = wp_parse_url( apply_filters( 'jetpack_photon_domain', 'https://i0.wp.com' ), PHP_URL_HOST ); - if ( $photon_url_domain !== $photon_domain ) { + $photon_url = Image_CDN_Core::cdn_url( $proxy_url ); + if ( ! Image_CDN_Core::is_cdn_url( $proxy_url ) ) { wp_send_json_error( 'Failed to proxy the image.', 400 ); } diff --git a/projects/plugins/boost/changelog/improve-cdn-url-check b/projects/plugins/boost/changelog/improve-cdn-url-check new file mode 100644 index 0000000000000..691d511e8f3a3 --- /dev/null +++ b/projects/plugins/boost/changelog/improve-cdn-url-check @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +Image Guide: Improve check for Jetpack Image CDN URLs diff --git a/projects/plugins/jetpack/changelog/add-nice-fatal-message b/projects/plugins/jetpack/changelog/add-nice-fatal-message new file mode 100644 index 0000000000000..70f2483520a3d --- /dev/null +++ b/projects/plugins/jetpack/changelog/add-nice-fatal-message @@ -0,0 +1,5 @@ +Significance: patch +Type: other +Comment: Just adding a nicer error message that would only display in dev environments. + + diff --git a/projects/plugins/jetpack/changelog/fix-social-share-status-tooltip-text-overflow b/projects/plugins/jetpack/changelog/fix-social-share-status-tooltip-text-overflow new file mode 100644 index 0000000000000..c45f928f60d33 --- /dev/null +++ b/projects/plugins/jetpack/changelog/fix-social-share-status-tooltip-text-overflow @@ -0,0 +1,4 @@ +Significance: patch +Type: bugfix + +Social: Fixed share status tooltip text overflow diff --git a/projects/plugins/jetpack/changelog/update-e2e-encryption-key b/projects/plugins/jetpack/changelog/update-e2e-encryption-key new file mode 100644 index 0000000000000..e24693901dddf --- /dev/null +++ b/projects/plugins/jetpack/changelog/update-e2e-encryption-key @@ -0,0 +1,4 @@ +Significance: patch +Type: other + +e2e tests: update encryption key. diff --git a/projects/plugins/jetpack/class.jetpack-gutenberg.php b/projects/plugins/jetpack/class.jetpack-gutenberg.php index 7968f0452f7df..6fa4dd4ed04cf 100644 --- a/projects/plugins/jetpack/class.jetpack-gutenberg.php +++ b/projects/plugins/jetpack/class.jetpack-gutenberg.php @@ -674,6 +674,10 @@ public static function enqueue_block_editor_assets() { // wp-edit-post but wp-edit-post's styles break the Widget Editor and // Site Editor) until a real fix gets unblocked. // @todo Remove this once #20357 is properly fixed. + $wp_styles_fix = wp_styles()->query( 'jetpack-blocks-editor', 'registered' ); + if ( empty( $wp_styles_fix ) ) { + wp_die( 'Your installation of Jetpack is incomplete. Please run "jetpack build plugins/jetpack" in your dev env.' ); + } wp_styles()->query( 'jetpack-blocks-editor', 'registered' )->deps = array(); Assets::enqueue_script( 'jetpack-blocks-editor' ); diff --git a/projects/plugins/jetpack/tests/e2e/config/encrypted.enc b/projects/plugins/jetpack/tests/e2e/config/encrypted.enc index 19bbaca0ccd78..2b7a724cefde0 100644 --- a/projects/plugins/jetpack/tests/e2e/config/encrypted.enc +++ b/projects/plugins/jetpack/tests/e2e/config/encrypted.enc @@ -1,2 +1,2 @@ -Salted__E>'Xyٖ977ebs)۫ b}Z!%!#N=1BF Ju]0p -8Dt2 \ No newline at end of file +Salted__BHø߂Uj/XП_T3'AxM{( +J"FrA%&+GMNj|mFP \ No newline at end of file diff --git a/projects/plugins/social/changelog/fix-social-share-status-tooltip-text-overflow b/projects/plugins/social/changelog/fix-social-share-status-tooltip-text-overflow new file mode 100644 index 0000000000000..9a6eda0cf22bb --- /dev/null +++ b/projects/plugins/social/changelog/fix-social-share-status-tooltip-text-overflow @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +Social: Fixed share status tooltip text overflow diff --git a/projects/plugins/wpcomsh/changelog/test-redirect b/projects/plugins/wpcomsh/changelog/test-redirect new file mode 100644 index 0000000000000..e4f7362752dbe --- /dev/null +++ b/projects/plugins/wpcomsh/changelog/test-redirect @@ -0,0 +1,4 @@ +Significance: patch +Type: removed + +test remove redirection diff --git a/projects/plugins/wpcomsh/feature-plugins/hooks.php b/projects/plugins/wpcomsh/feature-plugins/hooks.php index 908c679a1f123..f049cf5673b66 100644 --- a/projects/plugins/wpcomsh/feature-plugins/hooks.php +++ b/projects/plugins/wpcomsh/feature-plugins/hooks.php @@ -307,11 +307,6 @@ function wpcomsh_maybe_redirect_to_calypso_plugin_pages() { wp_safe_redirect( 'https://wordpress.com/plugins/' . $site ); exit; } - - if ( 0 === strpos( $request_uri, '/wp-admin/plugins.php' ) ) { - wp_safe_redirect( 'https://wordpress.com/plugins/manage/' . $site ); - exit; - } } add_action( 'plugins_loaded', 'wpcomsh_maybe_redirect_to_calypso_plugin_pages' ); diff --git a/tools/e2e-commons/config/encrypted.enc b/tools/e2e-commons/config/encrypted.enc index 6e0d2a4b0f10f..7d473c171f2f9 100644 Binary files a/tools/e2e-commons/config/encrypted.enc and b/tools/e2e-commons/config/encrypted.enc differ