From 5d7f047c945d1f4b7ea30a1cdc0ddfc4677319ea Mon Sep 17 00:00:00 2001 From: Richard Ortiz Date: Tue, 16 Jul 2024 16:18:53 +0200 Subject: [PATCH 1/9] WPCom Themes on Atomic: Fix WP_CLI errors when working with themes (#38351) * Disabled WPCom Themes on WP_CLI context * changelog --- .../changelog/fix-wp-cli-theme-install-displays-warning | 4 ++++ projects/plugins/wpcomsh/wpcomsh.php | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 projects/plugins/wpcomsh/changelog/fix-wp-cli-theme-install-displays-warning diff --git a/projects/plugins/wpcomsh/changelog/fix-wp-cli-theme-install-displays-warning b/projects/plugins/wpcomsh/changelog/fix-wp-cli-theme-install-displays-warning new file mode 100644 index 0000000000000..b1b330d475fca --- /dev/null +++ b/projects/plugins/wpcomsh/changelog/fix-wp-cli-theme-install-displays-warning @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +Removed access to WPCom Themes to WP_CLI diff --git a/projects/plugins/wpcomsh/wpcomsh.php b/projects/plugins/wpcomsh/wpcomsh.php index 06c60ba49a996..deb1ac2c10458 100644 --- a/projects/plugins/wpcomsh/wpcomsh.php +++ b/projects/plugins/wpcomsh/wpcomsh.php @@ -141,7 +141,11 @@ require_once __DIR__ . '/wpcom-migration-helpers/site-migration-helpers.php'; require_once __DIR__ . '/wpcom-plugins/plugins.php'; -require_once __DIR__ . '/wpcom-themes/themes.php'; + +// We include WPCom Themes results and installation on non-WP_CLI context. +if ( ! defined( 'WP_CLI' ) || ! WP_CLI ) { + require_once __DIR__ . '/wpcom-themes/themes.php'; +} require_once __DIR__ . '/class-jetpack-plugin-compatibility.php'; Jetpack_Plugin_Compatibility::get_instance(); From 836f14700ae44c98ee778fd82cb8a56c25264b44 Mon Sep 17 00:00:00 2001 From: Miguel Lezama Date: Tue, 16 Jul 2024 13:00:48 -0300 Subject: [PATCH 2/9] Newsletters: Add appSource to modal and navigation subscribe blocks (#38349) * add appSource to subscribe overlay * add appSource * changelog --- .../plugins/jetpack/changelog/update-subscribe-block-tracks | 5 +++++ .../blocks/subscriptions/class-jetpack-subscription-site.php | 1 + .../subscribe-modal/class-jetpack-subscribe-modal.php | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 projects/plugins/jetpack/changelog/update-subscribe-block-tracks diff --git a/projects/plugins/jetpack/changelog/update-subscribe-block-tracks b/projects/plugins/jetpack/changelog/update-subscribe-block-tracks new file mode 100644 index 0000000000000..0e8cddbcec24d --- /dev/null +++ b/projects/plugins/jetpack/changelog/update-subscribe-block-tracks @@ -0,0 +1,5 @@ +Significance: patch +Type: other +Comment: Adds internal subscription source to understand how users subscribe to sites + + diff --git a/projects/plugins/jetpack/extensions/blocks/subscriptions/class-jetpack-subscription-site.php b/projects/plugins/jetpack/extensions/blocks/subscriptions/class-jetpack-subscription-site.php index c3077bdd3953f..bbd03d24da285 100644 --- a/projects/plugins/jetpack/extensions/blocks/subscriptions/class-jetpack-subscription-site.php +++ b/projects/plugins/jetpack/extensions/blocks/subscriptions/class-jetpack-subscription-site.php @@ -155,6 +155,7 @@ function ( $hooked_block, $hooked_block_type, $relative_position, $anchor_block : 'is-style-button'; $hooked_block['attrs']['className'] = $class_name; + $hooked_block['attrs']['appSource'] = 'subscribe-block-navigation'; } return $hooked_block; diff --git a/projects/plugins/jetpack/modules/subscriptions/subscribe-modal/class-jetpack-subscribe-modal.php b/projects/plugins/jetpack/modules/subscriptions/subscribe-modal/class-jetpack-subscribe-modal.php index f15455f4d7339..df1a12210a0ee 100644 --- a/projects/plugins/jetpack/modules/subscriptions/subscribe-modal/class-jetpack-subscribe-modal.php +++ b/projects/plugins/jetpack/modules/subscriptions/subscribe-modal/class-jetpack-subscribe-modal.php @@ -189,7 +189,7 @@ public function get_subscribe_template_content() {

$subscribe_text

- +

$continue_reading

From c657adc0b4eef30c36b1c2672946b9cc32bb3c46 Mon Sep 17 00:00:00 2001 From: Dylan Munson <65001528+CodeyGuyDylan@users.noreply.github.com> Date: Tue, 16 Jul 2024 11:47:00 -0600 Subject: [PATCH 3/9] Add/segmentation to jetpack products my jetpack (#38283) * Segment products by owned and unowned * Changelog * changelog * Update styling * Update lockfiles and versions * changelog * Fix project version * Rework markup to make My Products the only off-white section * Strict type items array * changelog * Fix project version * Design tweaks * Update lockfiles * Update userIsAdmin check * Address nitpicks * Mark all plugins with standalone plugins as such on backend --- ...egmentation-to-jetpack-products-my-jetpack | 4 + .../components/admin-section/types.ts | 1 + projects/js-packages/components/package.json | 2 +- .../jitm/changelog/update-my-jetpack-jitm-css | 4 + projects/packages/jitm/src/class-jitm.php | 2 +- .../jitm/src/css/jetpack-admin-jitm.scss | 3 +- .../components/my-jetpack-screen/index.jsx | 78 ++++------ .../my-jetpack-screen/styles.module.scss | 5 + .../product-cards-section/index.jsx | 64 -------- .../product-cards-section/index.tsx | 145 ++++++++++++++++++ .../product-cards-section/style.module.scss | 11 +- ...egmentation-to-jetpack-products-my-jetpack | 4 + projects/packages/my-jetpack/global.d.ts | 6 +- .../my-jetpack/src/class-initializer.php | 2 + .../my-jetpack/src/class-products.php | 73 +++++++++ .../src/products/class-anti-spam.php | 7 + .../my-jetpack/src/products/class-boost.php | 7 + .../my-jetpack/src/products/class-crm.php | 7 + .../my-jetpack/src/products/class-protect.php | 7 + ...egmentation-to-jetpack-products-my-jetpack | 5 + ...egmentation-to-jetpack-products-my-jetpack | 5 + ...egmentation-to-jetpack-products-my-jetpack | 5 + ...egmentation-to-jetpack-products-my-jetpack | 5 + ...egmentation-to-jetpack-products-my-jetpack | 5 + ...egmentation-to-jetpack-products-my-jetpack | 5 + ...egmentation-to-jetpack-products-my-jetpack | 5 + ...egmentation-to-jetpack-products-my-jetpack | 5 + ...egmentation-to-jetpack-products-my-jetpack | 5 + 28 files changed, 354 insertions(+), 123 deletions(-) create mode 100644 projects/js-packages/components/changelog/add-segmentation-to-jetpack-products-my-jetpack create mode 100644 projects/packages/jitm/changelog/update-my-jetpack-jitm-css delete mode 100644 projects/packages/my-jetpack/_inc/components/product-cards-section/index.jsx create mode 100644 projects/packages/my-jetpack/_inc/components/product-cards-section/index.tsx create mode 100644 projects/packages/my-jetpack/changelog/add-segmentation-to-jetpack-products-my-jetpack create mode 100644 projects/plugins/backup/changelog/add-segmentation-to-jetpack-products-my-jetpack create mode 100644 projects/plugins/boost/changelog/add-segmentation-to-jetpack-products-my-jetpack create mode 100644 projects/plugins/jetpack/changelog/add-segmentation-to-jetpack-products-my-jetpack create mode 100644 projects/plugins/migration/changelog/add-segmentation-to-jetpack-products-my-jetpack create mode 100644 projects/plugins/protect/changelog/add-segmentation-to-jetpack-products-my-jetpack create mode 100644 projects/plugins/search/changelog/add-segmentation-to-jetpack-products-my-jetpack create mode 100644 projects/plugins/social/changelog/add-segmentation-to-jetpack-products-my-jetpack create mode 100644 projects/plugins/starter-plugin/changelog/add-segmentation-to-jetpack-products-my-jetpack create mode 100644 projects/plugins/videopress/changelog/add-segmentation-to-jetpack-products-my-jetpack diff --git a/projects/js-packages/components/changelog/add-segmentation-to-jetpack-products-my-jetpack b/projects/js-packages/components/changelog/add-segmentation-to-jetpack-products-my-jetpack new file mode 100644 index 0000000000000..dbda2687742d8 --- /dev/null +++ b/projects/js-packages/components/changelog/add-segmentation-to-jetpack-products-my-jetpack @@ -0,0 +1,4 @@ +Significance: patch +Type: added + + diff --git a/projects/js-packages/components/components/admin-section/types.ts b/projects/js-packages/components/components/admin-section/types.ts index 22a81369344b3..333ec9c90bf49 100644 --- a/projects/js-packages/components/components/admin-section/types.ts +++ b/projects/js-packages/components/components/admin-section/types.ts @@ -3,4 +3,5 @@ export type AdminSectionBaseProps = { * The section content */ children: React.ReactNode; + className?: string; }; diff --git a/projects/js-packages/components/package.json b/projects/js-packages/components/package.json index 1ee1f5b78e415..63a37b72eab0a 100644 --- a/projects/js-packages/components/package.json +++ b/projects/js-packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@automattic/jetpack-components", - "version": "0.54.3", + "version": "0.54.4-alpha", "description": "Jetpack Components Package", "author": "Automattic", "license": "GPL-2.0-or-later", diff --git a/projects/packages/jitm/changelog/update-my-jetpack-jitm-css b/projects/packages/jitm/changelog/update-my-jetpack-jitm-css new file mode 100644 index 0000000000000..ae68b7c731bd7 --- /dev/null +++ b/projects/packages/jitm/changelog/update-my-jetpack-jitm-css @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Update margins on jitms in my jetpack diff --git a/projects/packages/jitm/src/class-jitm.php b/projects/packages/jitm/src/class-jitm.php index 6138a060982cb..d740bcc2bb513 100644 --- a/projects/packages/jitm/src/class-jitm.php +++ b/projects/packages/jitm/src/class-jitm.php @@ -20,7 +20,7 @@ */ class JITM { - const PACKAGE_VERSION = '3.1.13'; + const PACKAGE_VERSION = '3.1.14-alpha'; /** * The configuration method that is called from the jetpack-config package. diff --git a/projects/packages/jitm/src/css/jetpack-admin-jitm.scss b/projects/packages/jitm/src/css/jetpack-admin-jitm.scss index f36beefef851b..fd096fa0bde72 100644 --- a/projects/packages/jitm/src/css/jetpack-admin-jitm.scss +++ b/projects/packages/jitm/src/css/jetpack-admin-jitm.scss @@ -173,7 +173,8 @@ $jp-gray-20: #a7aaad; .my-jetpack-jitm-card { .jitm-card { margin-right: 0; - margin-bottom: 0; + margin-bottom: 1.5rem; + margin-top: 1.5rem; } } diff --git a/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/index.jsx b/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/index.jsx index b152060794a17..716aa396a3864 100644 --- a/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/index.jsx +++ b/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/index.jsx @@ -3,23 +3,19 @@ */ import { AdminSection, - AdminSectionHero, AdminPage, Container, Col, Notice, - Text, ZendeskChat, useBreakpointMatch, ActionButton, } from '@automattic/jetpack-components'; -import { __ } from '@wordpress/i18n'; import clsx from 'clsx'; import { useContext, useEffect, useLayoutEffect, useState } from 'react'; /* * Internal dependencies */ -import { PRODUCT_STATUSES } from '../../constants'; import { NoticeContext } from '../../context/notices/noticeContext'; import { REST_API_CHAT_AUTHENTICATION_ENDPOINT, @@ -27,7 +23,6 @@ import { QUERY_CHAT_AVAILABILITY_KEY, QUERY_CHAT_AUTHENTICATION_KEY, } from '../../data/constants'; -import useProduct from '../../data/products/use-product'; import useSimpleQuery from '../../data/use-simple-query'; import { getMyJetpackWindowInitialState } from '../../data/utils/get-my-jetpack-window-state'; import useWelcomeBanner from '../../data/welcome-banner/use-welcome-banner'; @@ -38,7 +33,6 @@ import IDCModal from '../idc-modal'; import JetpackManageBanner from '../jetpack-manage-banner'; import PlansSection from '../plans-section'; import ProductCardsSection from '../product-cards-section'; -import StatsSection from '../stats-section'; import WelcomeBanner from '../welcome-banner'; import styles from './styles.module.scss'; @@ -81,7 +75,6 @@ const GlobalNotice = ( { message, title, options } ) => { export default function MyJetpackScreen() { useNotificationWatcher(); const { redBubbleAlerts } = getMyJetpackWindowInitialState(); - const { showFullJetpackStatsCard = false } = getMyJetpackWindowInitialState( 'myJetpackFlags' ); const { jetpackManage = {}, adminUrl } = getMyJetpackWindowInitialState(); const { isWelcomeBannerVisible } = useWelcomeBanner(); @@ -95,7 +88,6 @@ export default function MyJetpackScreen() { name: QUERY_CHAT_AVAILABILITY_KEY, query: { path: REST_API_CHAT_AVAILABILITY_ENDPOINT }, } ); - const { detail: statsDetails } = useProduct( 'stats' ); const { data: authData, isLoading: isJwtLoading } = useSimpleQuery( { name: QUERY_CHAT_AUTHENTICATION_KEY, query: { path: REST_API_CHAT_AUTHENTICATION_ENDPOINT }, @@ -133,52 +125,40 @@ export default function MyJetpackScreen() { return ( +
+ - - { ! isNewUser && ( - - -
- - - ) } - - - - - { __( 'Discover all Jetpack Products', 'jetpack-my-jetpack' ) } - + { ! isNewUser && ( + + +
+ + + ) } + + { noticeMessage && ! isWelcomeBannerVisible && ( + + + { + + } - { noticeMessage && ! isWelcomeBannerVisible && ( - - { - - } - - ) } - { showFullJetpackStatsCard && ( - - - - ) } + + ) } + + + + { jetpackManage.isEnabled && ( + - + - { jetpackManage.isEnabled && ( - - - - ) } - + ) } diff --git a/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/styles.module.scss b/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/styles.module.scss index 1ee529e9f9a15..46505f57e5d93 100644 --- a/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/styles.module.scss +++ b/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/styles.module.scss @@ -98,3 +98,8 @@ } } } + +.separator { + margin: 0; + border-bottom: none; +} \ No newline at end of file diff --git a/projects/packages/my-jetpack/_inc/components/product-cards-section/index.jsx b/projects/packages/my-jetpack/_inc/components/product-cards-section/index.jsx deleted file mode 100644 index 5757d718aa3d3..0000000000000 --- a/projects/packages/my-jetpack/_inc/components/product-cards-section/index.jsx +++ /dev/null @@ -1,64 +0,0 @@ -import { Container, Col } from '@automattic/jetpack-components'; -import React from 'react'; -import { getMyJetpackWindowInitialState } from '../../data/utils/get-my-jetpack-window-state'; -import AiCard from './ai-card'; -import AntiSpamCard from './anti-spam-card'; -import BackupCard from './backup-card'; -import BoostCard from './boost-card'; -import CreatorCard from './creator-card'; -import CrmCard from './crm-card'; -import ProtectCard from './protect-card'; -import SearchCard from './search-card'; -import SocialCard from './social-card'; -import StatsCard from './stats-card'; -import styles from './style.module.scss'; -import VideopressCard from './videopress-card'; - -/** - * Product cards section component. - * - * @returns {object} ProductCardsSection React component. - */ -const ProductCardsSection = () => { - const { isAtomic = false, userIsAdmin = false } = getMyJetpackWindowInitialState(); - const { showFullJetpackStatsCard = false } = getMyJetpackWindowInitialState( 'myJetpackFlags' ); - - const items = { - backups: BackupCard, - protect: ProtectCard, - antispam: AntiSpamCard, - boost: BoostCard, - search: SearchCard, - videopress: VideopressCard, - // If we aren't showing the big stats card, we show the smaller one with the rest. - stats: ! showFullJetpackStatsCard ? StatsCard : null, - crm: CrmCard, - creator: ! isAtomic ? CreatorCard : null, - social: SocialCard, - ai: AiCard, - }; - - return ( - - { Object.entries( items ).map( ( [ key, Item ] ) => { - if ( ! Item ) { - return null; - } - - return ( - - - - ); - } ) } - - ); -}; - -export default ProductCardsSection; diff --git a/projects/packages/my-jetpack/_inc/components/product-cards-section/index.tsx b/projects/packages/my-jetpack/_inc/components/product-cards-section/index.tsx new file mode 100644 index 0000000000000..f88ef76980941 --- /dev/null +++ b/projects/packages/my-jetpack/_inc/components/product-cards-section/index.tsx @@ -0,0 +1,145 @@ +import { Container, Col, Text, AdminSectionHero } from '@automattic/jetpack-components'; +import { __ } from '@wordpress/i18n'; +import { useMemo } from 'react'; +import { getMyJetpackWindowInitialState } from '../../data/utils/get-my-jetpack-window-state'; +import StatsSection from '../stats-section'; +import AiCard from './ai-card'; +import AntiSpamCard from './anti-spam-card'; +import BackupCard from './backup-card'; +import BoostCard from './boost-card'; +import CreatorCard from './creator-card'; +import CrmCard from './crm-card'; +import ProtectCard from './protect-card'; +import SearchCard from './search-card'; +import SocialCard from './social-card'; +import StatsCard from './stats-card'; +import styles from './style.module.scss'; +import VideopressCard from './videopress-card'; +import type { FC, ReactNode } from 'react'; + +type DisplayItemsProps = { + slugs: JetpackModule[]; +}; + +type DisplayItemType = Record< + // We don't have a card for Security or Extras, and scan is displayed as protect. + Exclude< JetpackModule, 'extras' | 'scan' | 'security' >, + FC< { admin: boolean } > +>; + +const DisplayItems: FC< DisplayItemsProps > = ( { slugs } ) => { + const { showFullJetpackStatsCard = false } = getMyJetpackWindowInitialState( 'myJetpackFlags' ); + const { isAtomic = false, userIsAdmin = false } = getMyJetpackWindowInitialState(); + + const items: DisplayItemType = { + backup: BackupCard, + protect: ProtectCard, + 'anti-spam': AntiSpamCard, + boost: BoostCard, + search: SearchCard, + videopress: VideopressCard, + stats: StatsCard, + crm: CrmCard, + creator: ! isAtomic ? CreatorCard : null, + social: SocialCard, + 'jetpack-ai': AiCard, + }; + + const filteredSlugs = slugs.filter( slug => { + if ( slug === 'stats' && showFullJetpackStatsCard ) { + return false; + } + + if ( ! items[ slug ] ) { + return false; + } + + return true; + } ); + + return ( + <> + { slugs.includes( 'stats' ) && showFullJetpackStatsCard && ( + + + + ) } + + { filteredSlugs.map( product => { + const Item = items[ product ]; + + return ( + + + + ); + } ) } + + + ); +}; + +interface ProductCardsSectionProps { + noticeMessage: ReactNode; +} + +const ProductCardsSection: FC< ProductCardsSectionProps > = ( { noticeMessage } ) => { + const { ownedProducts = [], unownedProducts = [] } = + getMyJetpackWindowInitialState( 'lifecycleStats' ); + + const unownedSectionTitle = useMemo( () => { + return ownedProducts.length > 0 + ? __( 'Discover more', 'jetpack-my-jetpack' ) + : __( 'Discover all Jetpack Products', 'jetpack-my-jetpack' ); + }, [ ownedProducts.length ] ); + + const filterProducts = ( products: JetpackModule[] ) => { + return products.filter( product => { + if ( product === 'scan' || product === 'security' || product === 'extras' ) { + return false; + } + return true; + } ); + }; + + const filteredOwnedProducts = filterProducts( ownedProducts ); + const filteredUnownedProducts = filterProducts( unownedProducts ); + + return ( + <> + { filteredOwnedProducts.length > 0 && ( + + + + + { __( 'My products', 'jetpack-my-jetpack' ) } + + + + + + + ) } + + { filteredUnownedProducts.length > 0 && ( + + + + { unownedSectionTitle } + + + + + + ) } + + ); +}; + +export default ProductCardsSection; diff --git a/projects/packages/my-jetpack/_inc/components/product-cards-section/style.module.scss b/projects/packages/my-jetpack/_inc/components/product-cards-section/style.module.scss index db4702284b42c..f9653ffc91264 100644 --- a/projects/packages/my-jetpack/_inc/components/product-cards-section/style.module.scss +++ b/projects/packages/my-jetpack/_inc/components/product-cards-section/style.module.scss @@ -47,12 +47,13 @@ } } -.loading-placeholder { - margin-top: calc( var( --spacing-base ) / 2 ); // 4px -} - .cardlist { > li { margin-bottom: 0; // Reset base style } -} \ No newline at end of file +} + +.cardListTitle, +.fullStatsCard { + margin-bottom: 1.5rem; +} diff --git a/projects/packages/my-jetpack/changelog/add-segmentation-to-jetpack-products-my-jetpack b/projects/packages/my-jetpack/changelog/add-segmentation-to-jetpack-products-my-jetpack new file mode 100644 index 0000000000000..173c366160888 --- /dev/null +++ b/projects/packages/my-jetpack/changelog/add-segmentation-to-jetpack-products-my-jetpack @@ -0,0 +1,4 @@ +Significance: minor +Type: changed + +Display My Jetpack products segemented by ownership diff --git a/projects/packages/my-jetpack/global.d.ts b/projects/packages/my-jetpack/global.d.ts index e8fc1136d62a1..09d9ff47545ce 100644 --- a/projects/packages/my-jetpack/global.d.ts +++ b/projects/packages/my-jetpack/global.d.ts @@ -24,8 +24,7 @@ type JetpackModule = | 'security' | 'protect' | 'videopress' - | 'stats' - | 'ai'; + | 'stats'; type ThreatItem = { // Protect API properties (free plan) @@ -94,6 +93,8 @@ interface Window { isSiteConnected: boolean; isUserConnected: boolean; jetpackPlugins: Array< string >; + ownedProducts: JetpackModule[]; + unownedProducts: JetpackModule[]; modules: Array< string >; purchases: Array< string >; }; @@ -288,6 +289,7 @@ interface Window { }; }; topJetpackMenuItemUrl: string; + isAtomic: boolean; userIsAdmin: string; userIsNewToJetpack: string; }; diff --git a/projects/packages/my-jetpack/src/class-initializer.php b/projects/packages/my-jetpack/src/class-initializer.php index 34bdb6dbcc6cc..1ec32e8773655 100644 --- a/projects/packages/my-jetpack/src/class-initializer.php +++ b/projects/packages/my-jetpack/src/class-initializer.php @@ -243,6 +243,8 @@ public static function enqueue_scripts() { 'lifecycleStats' => array( 'jetpackPlugins' => self::get_installed_jetpack_plugins(), 'historicallyActiveModules' => \Jetpack_Options::get_option( 'historically_active_modules', array() ), + 'ownedProducts' => Products::get_products_by_ownership( 'owned' ), + 'unownedProducts' => Products::get_products_by_ownership( 'unowned' ), 'brokenModules' => self::check_for_broken_modules(), 'isSiteConnected' => $connection->is_connected(), 'isUserConnected' => $connection->is_user_connected(), diff --git a/projects/packages/my-jetpack/src/class-products.php b/projects/packages/my-jetpack/src/class-products.php index b12dcdf15acfc..7dfa561b61728 100644 --- a/projects/packages/my-jetpack/src/class-products.php +++ b/projects/packages/my-jetpack/src/class-products.php @@ -55,6 +55,17 @@ class Products { self::STATUS_USER_CONNECTION_ERROR, ); + /** + * List of statuses that display the module as needing attention with a warning + * + * @var array + */ + public static $warning_module_statuses = array( + self::STATUS_SITE_CONNECTION_ERROR, + self::STATUS_USER_CONNECTION_ERROR, + self::STATUS_PLUGIN_ABSENT_WITH_PLAN, + ); + /** * List of statuses that display the module as active * @@ -152,6 +163,68 @@ public static function get_products() { return $products; } + /** + * Get a list of products sorted by whether or not the user owns them + * An owned product is defined as a product that is any of the following + * - Active + * - Has historically been active + * - The user has a plan that includes the product + * - The user has the standalone plugin for the product installed + * + * @param string $type The type of ownership to return ('owned' or 'unowned'). + * + * @return array + */ + public static function get_products_by_ownership( $type ) { + $historically_active_modules = \Jetpack_Options::get_option( 'historically_active_modules', array() ); + $owned_active_products = array(); + $owned_warning_products = array(); + $owned_inactive_products = array(); + $unowned_products = array(); + + foreach ( self::get_products_classes() as $class ) { + $product_slug = $class::$slug; + $standalone_info = $class::get_standalone_info(); + $status = $class::get_status(); + + if ( + in_array( $status, self::$active_module_statuses, true ) || + $standalone_info['is_standalone_installed'] || + in_array( $product_slug, $historically_active_modules, true ) || + $class::has_any_plan_for_product() + ) { + // This sorts the the products in the order of active -> warning -> inactive. + // This enables the frontend to display them in that order. + // This is not needed for unowned products as those will always have a status of 'inactive' + if ( in_array( $status, self::$active_module_statuses, true ) ) { + array_push( $owned_active_products, $product_slug ); + } elseif ( in_array( $status, self::$warning_module_statuses, true ) ) { + array_push( $owned_warning_products, $product_slug ); + } else { + array_push( $owned_inactive_products, $product_slug ); + } + continue; + } + + array_push( $unowned_products, $product_slug ); + } + + $data = array( + 'owned' => array_values( + array_unique( + array_merge( + $owned_active_products, + $owned_warning_products, + $owned_inactive_products + ) + ) + ), + 'unowned' => array_unique( $unowned_products ), + ); + + return $data[ $type ]; + } + /** * Get all plugin filenames associated with the products. * diff --git a/projects/packages/my-jetpack/src/products/class-anti-spam.php b/projects/packages/my-jetpack/src/products/class-anti-spam.php index b18bb5b1a9582..968a2e95e8cba 100644 --- a/projects/packages/my-jetpack/src/products/class-anti-spam.php +++ b/projects/packages/my-jetpack/src/products/class-anti-spam.php @@ -50,6 +50,13 @@ class Anti_Spam extends Product { */ public static $has_free_offering = true; + /** + * Akismet has a standalone plugin + * + * @var bool + */ + public static $has_standalone_plugin = true; + /** * Get the product name * diff --git a/projects/packages/my-jetpack/src/products/class-boost.php b/projects/packages/my-jetpack/src/products/class-boost.php index 922403dee0385..25d023adcd9f5 100644 --- a/projects/packages/my-jetpack/src/products/class-boost.php +++ b/projects/packages/my-jetpack/src/products/class-boost.php @@ -44,6 +44,13 @@ class Boost extends Product { */ public static $plugin_slug = 'jetpack-boost'; + /** + * Boost has a standalone plugin + * + * @var bool + */ + public static $has_standalone_plugin = true; + /** * Whether this product requires a user connection * diff --git a/projects/packages/my-jetpack/src/products/class-crm.php b/projects/packages/my-jetpack/src/products/class-crm.php index 052633c94d61c..f63d90f1e7f87 100644 --- a/projects/packages/my-jetpack/src/products/class-crm.php +++ b/projects/packages/my-jetpack/src/products/class-crm.php @@ -53,6 +53,13 @@ class Crm extends Product { */ public static $has_free_offering = true; + /** + * CRM has a standalone plugin + * + * @var bool + */ + public static $has_standalone_plugin = true; + /** * Get the product name * diff --git a/projects/packages/my-jetpack/src/products/class-protect.php b/projects/packages/my-jetpack/src/products/class-protect.php index 70624db3a0526..1e8d683ebfbe8 100644 --- a/projects/packages/my-jetpack/src/products/class-protect.php +++ b/projects/packages/my-jetpack/src/products/class-protect.php @@ -61,6 +61,13 @@ class Protect extends Product { */ public static $has_free_offering = true; + /** + * Protect has a standalone plugin + * + * @var bool + */ + public static $has_standalone_plugin = true; + /** * Get the product name * diff --git a/projects/plugins/backup/changelog/add-segmentation-to-jetpack-products-my-jetpack b/projects/plugins/backup/changelog/add-segmentation-to-jetpack-products-my-jetpack new file mode 100644 index 0000000000000..9aa70e3ec1f75 --- /dev/null +++ b/projects/plugins/backup/changelog/add-segmentation-to-jetpack-products-my-jetpack @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Updated composer.lock. + + diff --git a/projects/plugins/boost/changelog/add-segmentation-to-jetpack-products-my-jetpack b/projects/plugins/boost/changelog/add-segmentation-to-jetpack-products-my-jetpack new file mode 100644 index 0000000000000..9aa70e3ec1f75 --- /dev/null +++ b/projects/plugins/boost/changelog/add-segmentation-to-jetpack-products-my-jetpack @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Updated composer.lock. + + diff --git a/projects/plugins/jetpack/changelog/add-segmentation-to-jetpack-products-my-jetpack b/projects/plugins/jetpack/changelog/add-segmentation-to-jetpack-products-my-jetpack new file mode 100644 index 0000000000000..a1c1831fa1ef7 --- /dev/null +++ b/projects/plugins/jetpack/changelog/add-segmentation-to-jetpack-products-my-jetpack @@ -0,0 +1,5 @@ +Significance: patch +Type: other +Comment: Updated composer.lock. + + diff --git a/projects/plugins/migration/changelog/add-segmentation-to-jetpack-products-my-jetpack b/projects/plugins/migration/changelog/add-segmentation-to-jetpack-products-my-jetpack new file mode 100644 index 0000000000000..9aa70e3ec1f75 --- /dev/null +++ b/projects/plugins/migration/changelog/add-segmentation-to-jetpack-products-my-jetpack @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Updated composer.lock. + + diff --git a/projects/plugins/protect/changelog/add-segmentation-to-jetpack-products-my-jetpack b/projects/plugins/protect/changelog/add-segmentation-to-jetpack-products-my-jetpack new file mode 100644 index 0000000000000..9aa70e3ec1f75 --- /dev/null +++ b/projects/plugins/protect/changelog/add-segmentation-to-jetpack-products-my-jetpack @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Updated composer.lock. + + diff --git a/projects/plugins/search/changelog/add-segmentation-to-jetpack-products-my-jetpack b/projects/plugins/search/changelog/add-segmentation-to-jetpack-products-my-jetpack new file mode 100644 index 0000000000000..9aa70e3ec1f75 --- /dev/null +++ b/projects/plugins/search/changelog/add-segmentation-to-jetpack-products-my-jetpack @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Updated composer.lock. + + diff --git a/projects/plugins/social/changelog/add-segmentation-to-jetpack-products-my-jetpack b/projects/plugins/social/changelog/add-segmentation-to-jetpack-products-my-jetpack new file mode 100644 index 0000000000000..9aa70e3ec1f75 --- /dev/null +++ b/projects/plugins/social/changelog/add-segmentation-to-jetpack-products-my-jetpack @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Updated composer.lock. + + diff --git a/projects/plugins/starter-plugin/changelog/add-segmentation-to-jetpack-products-my-jetpack b/projects/plugins/starter-plugin/changelog/add-segmentation-to-jetpack-products-my-jetpack new file mode 100644 index 0000000000000..9aa70e3ec1f75 --- /dev/null +++ b/projects/plugins/starter-plugin/changelog/add-segmentation-to-jetpack-products-my-jetpack @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Updated composer.lock. + + diff --git a/projects/plugins/videopress/changelog/add-segmentation-to-jetpack-products-my-jetpack b/projects/plugins/videopress/changelog/add-segmentation-to-jetpack-products-my-jetpack new file mode 100644 index 0000000000000..9aa70e3ec1f75 --- /dev/null +++ b/projects/plugins/videopress/changelog/add-segmentation-to-jetpack-products-my-jetpack @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Updated composer.lock. + + From 7412aa7f54cb2d49f3368cb780544e1cb2521186 Mon Sep 17 00:00:00 2001 From: Kev Date: Tue, 16 Jul 2024 15:21:47 -0400 Subject: [PATCH 4/9] Add _deprecated_class to patterns recognized by replace-next-version-tag.sh (#38353) --- tools/replace-next-version-tag.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/replace-next-version-tag.sh b/tools/replace-next-version-tag.sh index 93498376b7184..72681fe4b8b30 100755 --- a/tools/replace-next-version-tag.sh +++ b/tools/replace-next-version-tag.sh @@ -85,7 +85,7 @@ for FILE in $(git ls-files "projects/$SLUG/"); do sed -i.bak -E -e 's!(@since|@deprecated( +[sS]ince)?)( +)\$\$next-version\$\$!\1\3'"$VE"'!g' "$FILE" rm "$FILE.bak" # We need a backup file because macOS requires it. - sed -i.bak -E -e $'s!(^\t*_deprecated_(function|constructor|file|argument|hook)\\( .*, \'[^\']*)\\$\\$next-version\\$\\$\'!\\1'"$VE"$'\'!g' "$FILE" + sed -i.bak -E -e $'s!(^\t*_deprecated_(function|constructor|file|argument|hook|class)\\( .*, \'[^\']*)\\$\\$next-version\\$\\$\'!\\1'"$VE"$'\'!g' "$FILE" rm "$FILE.bak" # We need a backup file because macOS requires it. if grep -F -q '$$next-version$$' "$FILE"; then From ac89aacf6b1eff582f530a1b38cb824acbc0049b Mon Sep 17 00:00:00 2001 From: Igor Zinovyev Date: Tue, 16 Jul 2024 22:45:15 +0300 Subject: [PATCH 5/9] Added PHP 7.0 testing in WordPress previous. (#38356) With the release of WordPress 6.6, which drops support for PHP 7.0 and 7.1, we need to switch our PHP 7.0 test to use WordPress "previous" (currently 6.4, soon 6.5) instead of "latest". This also needed code to downgrade the roots/wordpress package used with WorDBless when running with WordPress previous, which we hadn't needed before. Then that picked up one test that had been updated for WordPress 6.5 back when that was released and now fails in the "previous" run. And also the Jetpack Legacy Full Sync tests need to be bumped to run with PHP 7.2, since 7.0 is on its way out. --------- Co-authored-by: Brad Jorsch --- .github/files/generate-ci-matrix.php | 12 ++++++- .github/files/setup-wordpress-env.sh | 24 +++++++++++--- .github/workflows/tests.yml | 32 +++++++++++-------- .../changelog/add-manual-previous-70-testing | 5 +++ .../class-verbum-block-utils-test.php | 10 ++++-- .../changelog/add-manual-previous-70-testing | 5 +++ .../plugins/jetpack/tests/action-test-php.sh | 2 +- 7 files changed, 67 insertions(+), 23 deletions(-) create mode 100644 projects/packages/jetpack-mu-wpcom/changelog/add-manual-previous-70-testing create mode 100644 projects/plugins/jetpack/changelog/add-manual-previous-70-testing diff --git a/.github/files/generate-ci-matrix.php b/.github/files/generate-ci-matrix.php index ce67ff260078d..fb470f485d935 100755 --- a/.github/files/generate-ci-matrix.php +++ b/.github/files/generate-ci-matrix.php @@ -58,7 +58,7 @@ $matrix = array(); // Add PHP tests. -foreach ( array( '7.0', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3' ) as $php ) { +foreach ( array( '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3' ) as $php ) { $matrix[] = array( 'name' => "PHP tests: PHP $php WP latest", 'script' => 'test-php', @@ -68,6 +68,16 @@ ); } +// TODO: When WordPress 6.5 is no longer supported, this can be removed. +$matrix[] = array( + 'name' => 'PHP tests: PHP 7.0 WP previous', + 'script' => 'test-php', + 'php' => '7.0', + 'wp' => 'previous', + 'timeout' => 20, // 2023-08-17: Successful runs seem to take up to ~12 minutes. + 'force-package-tests' => true, +); + foreach ( array( 'previous', 'trunk' ) as $wp ) { $phpver = $versions['PHP_VERSION']; $matrix[] = array( diff --git a/.github/files/setup-wordpress-env.sh b/.github/files/setup-wordpress-env.sh index 1b233f1095790..be37da51e0766 100755 --- a/.github/files/setup-wordpress-env.sh +++ b/.github/files/setup-wordpress-env.sh @@ -32,30 +32,31 @@ echo "::endgroup::" echo "::group::Preparing WordPress from \"$WP_BRANCH\" branch"; case "$WP_BRANCH" in trunk) - TAG=trunk + WORDPRESS_TAG=trunk ;; latest) - TAG=$(php ./tools/get-wp-version.php) + WORDPRESS_TAG=$(php ./tools/get-wp-version.php) ;; previous) # We hard-code the version here because there's a time near WP releases where # we've dropped the old 'previous' but WP hasn't actually released the new 'latest' - TAG=6.4 + WORDPRESS_TAG=6.4 ;; *) echo "Unrecognized value for WP_BRANCH: $WP_BRANCH" >&2 exit 1 ;; esac -git clone --depth=1 --branch "$TAG" git://develop.git.wordpress.org/ "/tmp/wordpress-$WP_BRANCH" +git clone --depth=1 --branch "$WORDPRESS_TAG" git://develop.git.wordpress.org/ "/tmp/wordpress-$WP_BRANCH" # We need a built version of WordPress to test against, so download that into the src directory instead of what's in wordpress-develop. rm -rf "/tmp/wordpress-$WP_BRANCH/src" -git clone --depth=1 --branch "$TAG" git://core.git.wordpress.org/ "/tmp/wordpress-$WP_BRANCH/src" +git clone --depth=1 --branch "$WORDPRESS_TAG" git://core.git.wordpress.org/ "/tmp/wordpress-$WP_BRANCH/src" echo "::endgroup::" if [[ -n "$GITHUB_ENV" ]]; then echo "WORDPRESS_DEVELOP_DIR=/tmp/wordpress-$WP_BRANCH" >> "$GITHUB_ENV" echo "WORDPRESS_DIR=/tmp/wordpress-$WP_BRANCH/src" >> "$GITHUB_ENV" + echo "WORDPRESS_TAG=$WORDPRESS_TAG" >> "$GITHUB_ENV" fi # Don't symlink, it breaks when copied later. @@ -123,6 +124,19 @@ for PLUGIN in projects/plugins/*/composer.json; do fi cd "$BASE" + # Upgrade/downgrade WorDBless if necessary. + if [[ ( "$WP_BRANCH" == 'trunk' || "$WP_BRANCH" == 'previous' ) && "$TEST_SCRIPT" == "test-php" ]]; then + VER=$(composer --format=json --working-dir="$DIR" show | jq -r '.installed[] | select( .name == "roots/wordpress" ) | .version') + if [[ -n "$VER" ]]; then + INSVER=$WORDPRESS_TAG + [[ "$WORDPRESS_TAG" == 'trunk' ]] && INSVER="dev-main as $VER" + echo "Supposed to run tests against WordPress $WORDPRESS_TAG, so setting roots/wordpress and roots/wordpress-no-content to \"$INSVER\"" + # Composer seems to sometimes have issues with deleting the wordpress dir on its own, so do it manually first. + rm -rf "$DIR/wordpress" + composer --working-dir="$DIR" require --dev roots/wordpress="$INSVER" roots/wordpress-no-content="$INSVER" + fi + fi + cp -r "$DIR" "/tmp/wordpress-$WP_BRANCH/src/wp-content/plugins/$NAME" # Plugin dir for tests in WP >= 5.6-beta1 ln -s "/tmp/wordpress-$WP_BRANCH/src/wp-content/plugins/$NAME" "/tmp/wordpress-$WP_BRANCH/tests/phpunit/data/plugins/$NAME" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 78082fc0f54dc..5face1f9d875e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -78,6 +78,14 @@ jobs: pnpm install echo "::endgroup::" + # If we're going to be making WorDBless use WP "nightlies", remove the relevant package from Composer's cache to get the latest version. + if [[ "$WP_BRANCH" == 'trunk' && "$TEST_SCRIPT" == "test-php" ]]; then + echo "::group::Clear composer cache for roots/wordpress" + DIR=$(composer config cache-files-dir) + rm -rf "$DIR/roots/wordpress" "$DIR/roots/wordpress-no-content" + echo "::endgroup::" + fi + - name: Detect changed projects id: changed run: | @@ -105,12 +113,6 @@ jobs: FORCE_PACKAGE_TESTS: ${{ matrix.force-package-tests && 'true' || 'false' }} CHANGED: ${{ steps.changed.outputs.projects }} run: | - # If we're going to be making WorDBless use WP "nightlies", remove the relevant package from Composer's cache to get the latest version. - if [[ "$WP_BRANCH" == 'trunk' && ( "$TEST_SCRIPT" == "test-php" ) ]]; then - DIR=$(composer config cache-files-dir) - rm -rf "$DIR/roots/wordpress" - fi - EXIT=0 mkdir artifacts for P in composer.json projects/*/*/composer.json; do @@ -165,15 +167,17 @@ jobs: echo 'Platform reqs failed, running `composer update`' composer --working-dir="$DIR" update fi - fi - if [[ "$WP_BRANCH" == 'trunk' && "$TEST_SCRIPT" == "test-php" ]]; then - VER=$(composer --format=json --working-dir="$DIR" show | jq -r '.installed[] | select( .name == "roots/wordpress" ) | .version') - if [[ -n "$VER" ]]; then - echo 'Supposed to run tests against WordPress trunk, so upgrading roots/wordpress and roots/wordpress-no-content to dev-main' - # Composer seems to sometimes have issues with deleting the wordpress dir on its own, so do it manually first. - rm -rf "$DIR/wordpress" - composer --working-dir="$DIR" require --dev roots/wordpress="dev-main as $VER" roots/wordpress-no-content="dev-main as $VER" + if [[ "$WP_BRANCH" == 'trunk' || "$WP_BRANCH" == 'previous' ]]; then + VER=$(composer --format=json --working-dir="$DIR" show | jq -r '.installed[] | select( .name == "roots/wordpress" ) | .version') + if [[ -n "$VER" ]]; then + INSVER=$WORDPRESS_TAG + [[ "$WORDPRESS_TAG" == 'trunk' ]] && INSVER="dev-main as $VER" + echo "Supposed to run tests against WordPress $WORDPRESS_TAG, so setting roots/wordpress and roots/wordpress-no-content to \"$INSVER\"" + # Composer seems to sometimes have issues with deleting the wordpress dir on its own, so do it manually first. + rm -rf "$DIR/wordpress" + composer --working-dir="$DIR" require --dev roots/wordpress="$INSVER" roots/wordpress-no-content="$INSVER" + fi fi fi diff --git a/projects/packages/jetpack-mu-wpcom/changelog/add-manual-previous-70-testing b/projects/packages/jetpack-mu-wpcom/changelog/add-manual-previous-70-testing new file mode 100644 index 0000000000000..50cd36eddae57 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/changelog/add-manual-previous-70-testing @@ -0,0 +1,5 @@ +Significance: patch +Type: fixed +Comment: Fix a test to work with both WP 6.4 and 6.5. + + diff --git a/projects/packages/jetpack-mu-wpcom/tests/php/features/verbum-comments/class-verbum-block-utils-test.php b/projects/packages/jetpack-mu-wpcom/tests/php/features/verbum-comments/class-verbum-block-utils-test.php index a3ea95d1cfd44..35cc2e567c63e 100644 --- a/projects/packages/jetpack-mu-wpcom/tests/php/features/verbum-comments/class-verbum-block-utils-test.php +++ b/projects/packages/jetpack-mu-wpcom/tests/php/features/verbum-comments/class-verbum-block-utils-test.php @@ -45,8 +45,14 @@ public function test_comment_text_block_sanitization_sanity_check() { $comment_content = '

test

  • 1
  • 2
  • 3

something

someone
'; $filtered_content = preg_replace( '/\R+/', '', Verbum_Block_Utils::render_verbum_blocks( $comment_content ) ); - $expected_content = '

test

  • 1
  • 2
  • 3

something

someone
'; - $this->assertEquals( $expected_content, $filtered_content ); + // Once we drop WP 6.4, we can change this back to assertSame(). + $expected_content = $this->logicalOr( + // WP 6.4 + $this->identicalTo( '

test

  • 1
  • 2
  • 3

something

someone
' ), + // WP 6.5+ + $this->identicalTo( '

test

  • 1
  • 2
  • 3

something

someone
' ) + ); + $this->assertThat( $filtered_content, $expected_content ); } /** diff --git a/projects/plugins/jetpack/changelog/add-manual-previous-70-testing b/projects/plugins/jetpack/changelog/add-manual-previous-70-testing new file mode 100644 index 0000000000000..5278e48862393 --- /dev/null +++ b/projects/plugins/jetpack/changelog/add-manual-previous-70-testing @@ -0,0 +1,5 @@ +Significance: patch +Type: other +Comment: Run Legacy Full Sync tests with PHP 7.2, now that 7.0 is on its way out. + + diff --git a/projects/plugins/jetpack/tests/action-test-php.sh b/projects/plugins/jetpack/tests/action-test-php.sh index eb82fd51d98cd..ce33f626c37a8 100755 --- a/projects/plugins/jetpack/tests/action-test-php.sh +++ b/projects/plugins/jetpack/tests/action-test-php.sh @@ -25,7 +25,7 @@ if [[ "$WP_BRANCH" == "trunk" ]]; then echo "::endgroup::" fi -if [[ "$WP_BRANCH" == "latest" && "$PHP_VERSION" == "7.0" ]]; then +if [[ "$WP_BRANCH" == "latest" && "$PHP_VERSION" == "7.2" ]]; then echo "::group::Jetpack Legacy Full Sync tests" LEGACY_FULL_SYNC=1 phpunit --group=legacy-full-sync echo "::endgroup::" From b06a029eaaec276ae47fa11b46d3b3d6671b21b4 Mon Sep 17 00:00:00 2001 From: Renato Augusto Gama dos Santos Date: Tue, 16 Jul 2024 17:10:36 -0300 Subject: [PATCH 6/9] AI Proofread: Improve Popover UX (#38342) * AI Proofread: Improve Popover UX * changelog * AI Proofread: Improve offset * :AI Proofread: Improve offset * AI Proofread: Improve offset * AI Proofread: Only point to cursor if long sentence * change sentence check * fix types --------- Co-authored-by: Douglas --- .../changelog/update-ai-proofread-popover-ux | 4 ++ .../components/breve/features/events.ts | 68 +++++++++++++------ .../components/breve/highlight/index.tsx | 15 ++-- .../components/breve/highlight/style.scss | 3 +- .../components/breve/store/actions.ts | 15 +--- .../components/breve/store/reducer.ts | 27 +------- .../components/breve/store/selectors.ts | 13 +--- .../components/breve/types.ts | 15 ++-- 8 files changed, 78 insertions(+), 82 deletions(-) create mode 100644 projects/plugins/jetpack/changelog/update-ai-proofread-popover-ux diff --git a/projects/plugins/jetpack/changelog/update-ai-proofread-popover-ux b/projects/plugins/jetpack/changelog/update-ai-proofread-popover-ux new file mode 100644 index 0000000000000..a321157afcce1 --- /dev/null +++ b/projects/plugins/jetpack/changelog/update-ai-proofread-popover-ux @@ -0,0 +1,4 @@ +Significance: minor +Type: other + +Improve Popover UX on AI Proofread diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/events.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/events.ts index d4838209f0e8e..143891bd085fd 100644 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/events.ts +++ b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/events.ts @@ -1,7 +1,7 @@ /** * External dependencies */ -import { dispatch, select } from '@wordpress/data'; +import { dispatch } from '@wordpress/data'; /** * Internal dependencies */ @@ -10,31 +10,55 @@ import features from './index'; /** * Types */ -import type { BreveDispatch, BreveSelect } from '../types'; +import type { BreveDispatch, Anchor } from '../types'; let highlightTimeout: number; +let anchorTimeout: number; -function handleMouseEnter( e: React.MouseEvent ) { - e.stopPropagation(); +function handleMouseEnter( e: MouseEvent ) { clearTimeout( highlightTimeout ); - ( dispatch( 'jetpack/ai-breve' ) as BreveDispatch ).increasePopoverLevel(); - ( dispatch( 'jetpack/ai-breve' ) as BreveDispatch ).setHighlightHover( true ); - ( dispatch( 'jetpack/ai-breve' ) as BreveDispatch ).setPopoverAnchor( e.target ); -} + clearTimeout( anchorTimeout ); -function handleMouseLeave( e: React.MouseEvent ) { - e.stopPropagation(); - ( dispatch( 'jetpack/ai-breve' ) as BreveDispatch ).decreasePopoverLevel(); + anchorTimeout = setTimeout( () => { + const el = e.target as HTMLElement; + let virtual = el; - highlightTimeout = setTimeout( () => { - // If the mouse is still over any highlight, don't hide the popover - const { getPopoverLevel } = select( 'jetpack/ai-breve' ) as BreveSelect; - if ( getPopoverLevel() > 0 ) { - return; + const shouldPointToCursor = el.getAttribute( 'data-type' ) === 'long-sentences'; + + if ( shouldPointToCursor ) { + const rect = el.getBoundingClientRect(); + const diff = e.clientY - Math.floor( rect.top ); + const offset = diff === 0 ? 10 : 0; + + virtual = { + getBoundingClientRect() { + return { + top: e.clientY + offset, + left: e.clientX, + bottom: e.clientY, + right: e.clientX, + width: 0, + height: 0, + x: e.clientX, + y: e.clientY, + } as DOMRect; + }, + contextElement: e.target as HTMLElement, + } as unknown as HTMLElement; } + ( dispatch( 'jetpack/ai-breve' ) as BreveDispatch ).setHighlightHover( true ); + ( dispatch( 'jetpack/ai-breve' ) as BreveDispatch ).setPopoverAnchor( { + target: e.target as HTMLElement, + virtual: virtual, + } as Anchor ); + }, 100 ); +} + +function handleMouseLeave() { + highlightTimeout = setTimeout( () => { ( dispatch( 'jetpack/ai-breve' ) as BreveDispatch ).setHighlightHover( false ); - }, 50 ); + }, 100 ); } export default function registerEvents( clientId: string ) { @@ -43,12 +67,14 @@ export default function registerEvents( clientId: string ) { const block = container?.querySelector?.( `#${ id }` ); features.forEach( ( { config } ) => { - const items = block?.querySelectorAll?.( `[data-type='${ config.name }']` ) || []; + const items: NodeListOf< HTMLElement > | undefined = block?.querySelectorAll?.( + `[data-type='${ config.name }']` + ); - if ( items?.length > 0 ) { + if ( items && items?.length > 0 ) { items.forEach( highlightEl => { - highlightEl?.removeEventListener?.( 'mouseenter', handleMouseEnter ); - highlightEl?.addEventListener?.( 'mouseenter', handleMouseEnter ); + highlightEl?.removeEventListener?.( 'mouseover', handleMouseEnter ); + highlightEl?.addEventListener?.( 'mouseover', handleMouseEnter ); highlightEl?.removeEventListener?.( 'mouseleave', handleMouseLeave ); highlightEl?.addEventListener?.( 'mouseleave', handleMouseLeave ); } ); diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/highlight/index.tsx b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/highlight/index.tsx index 738e648361bcb..07942dc3f2da9 100644 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/highlight/index.tsx +++ b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/highlight/index.tsx @@ -32,11 +32,16 @@ export default function Highlight() { return isHighlightHover || isPopoverHover; }, [] ); - const anchor = useSelect( select => { - return ( select( 'jetpack/ai-breve' ) as BreveSelect ).getPopoverAnchor(); + const { target: anchor, virtual } = useSelect( select => { + return ( + ( select( 'jetpack/ai-breve' ) as BreveSelect ).getPopoverAnchor() ?? { + target: null, + virtual: null, + } + ); }, [] ); - const isPopoverOpen = popoverOpen && anchor; + const isPopoverOpen = popoverOpen && virtual; const selectedFeatured = anchor ? ( anchor as HTMLElement )?.getAttribute?.( 'data-type' ) : null; @@ -60,10 +65,10 @@ export default function Highlight() { <> { isPopoverOpen && ( - ).reduceRight( ( acc, anchor ) => acc ?? anchor, null ); +export function getPopoverAnchor( state: BreveState ): Anchor | null { + return state?.popover?.anchor ?? null; } export function getPopoverLevel( state: BreveState ) { diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/types.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/types.ts index 33171a1426311..63332f02f4007 100644 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/types.ts +++ b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/types.ts @@ -1,12 +1,19 @@ export type BreveControls = () => React.JSX.Element; +export type Anchor = { + target: HTMLElement; + virtual: { + getBoundingClientRect: () => DOMRect; + contextElement?: HTMLElement; + }; +}; + export type BreveState = { popover?: { isHighlightHover?: boolean; isPopoverHover?: boolean; - anchors?: Array< HTMLElement | EventTarget >; + anchor?: Anchor; level?: number; - frozenAnchor?: HTMLElement | EventTarget; }; configuration?: { enabled?: boolean; @@ -17,7 +24,7 @@ export type BreveState = { export type BreveSelect = { isHighlightHover: () => boolean; isPopoverHover: () => boolean; - getPopoverAnchor: () => HTMLElement | EventTarget; + getPopoverAnchor: () => Anchor | null; getPopoverLevel: () => number; isProofreadEnabled: () => boolean; isFeatureEnabled: ( feature: string ) => boolean; @@ -27,7 +34,7 @@ export type BreveSelect = { export type BreveDispatch = { setHighlightHover: ( isHover: boolean ) => void; setPopoverHover: ( isHover: boolean ) => void; - setPopoverAnchor: ( anchor: HTMLElement | EventTarget ) => void; + setPopoverAnchor: ( anchor: Anchor ) => void; increasePopoverLevel: () => void; decreasePopoverLevel: () => void; toggleProofread: ( force?: boolean ) => void; From 7cc96a0b87de3167a9486a1b89ee7563b5661675 Mon Sep 17 00:00:00 2001 From: arthur791004 Date: Wed, 17 Jul 2024 11:11:48 +0800 Subject: [PATCH 7/9] Nav Redesign i3: Hotfix the order of the admin menu items for WP 6.6 (#38347) * Admin Bar: Hotfix the order of the admin menu items for WP 6.6 * changelog * Change styles to keep the search at the rightmost --- .../changelog/fix-admin-menu-order | 4 ++++ .../wpcom-admin-bar/wpcom-admin-bar.php | 21 +++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 projects/packages/jetpack-mu-wpcom/changelog/fix-admin-menu-order diff --git a/projects/packages/jetpack-mu-wpcom/changelog/fix-admin-menu-order b/projects/packages/jetpack-mu-wpcom/changelog/fix-admin-menu-order new file mode 100644 index 0000000000000..fc0a444bb802a --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/changelog/fix-admin-menu-order @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +Admin Bar: Hotfix the order of the admin menu items for WP 6.6 diff --git a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-admin-bar/wpcom-admin-bar.php b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-admin-bar/wpcom-admin-bar.php index 210d8d6072c92..a2cc36ac0d8b4 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-admin-bar/wpcom-admin-bar.php +++ b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-admin-bar/wpcom-admin-bar.php @@ -23,6 +23,27 @@ function wpcom_enqueue_admin_bar_assets() { array(), Jetpack_Mu_Wpcom::PACKAGE_VERSION ); + + /** + * Hotfix the order of the admin menu items due to WP 6.6 + * See https://core.trac.wordpress.org/ticket/61615. + */ + $wp_version = get_bloginfo( 'version' ); + if ( version_compare( $wp_version, '6.6', '<=' ) && version_compare( $wp_version, '6.6.RC', '>=' ) ) { + wp_add_inline_style( + 'wpcom-admin-bar', + << Date: Wed, 17 Jul 2024 10:09:20 +0200 Subject: [PATCH 8/9] WP.com admin bar: Use WordPress.com logo (#38354) --- .../changelog/update-wpcom-admin-bar-wp-logo | 5 ++++ .../wpcom-admin-bar/wpcom-admin-bar.scss | 23 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 projects/packages/jetpack-mu-wpcom/changelog/update-wpcom-admin-bar-wp-logo diff --git a/projects/packages/jetpack-mu-wpcom/changelog/update-wpcom-admin-bar-wp-logo b/projects/packages/jetpack-mu-wpcom/changelog/update-wpcom-admin-bar-wp-logo new file mode 100644 index 0000000000000..24772aa389f47 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/changelog/update-wpcom-admin-bar-wp-logo @@ -0,0 +1,5 @@ +Significance: patch +Type: fixed +Comment: Minor image replacement + + diff --git a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-admin-bar/wpcom-admin-bar.scss b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-admin-bar/wpcom-admin-bar.scss index 0ff39df6c82b1..7d137f0930703 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-admin-bar/wpcom-admin-bar.scss +++ b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-admin-bar/wpcom-admin-bar.scss @@ -14,6 +14,29 @@ display: none !important; } +/** + * WP logo menu + */ +#wpadminbar #wp-admin-bar-wp-logo>.ab-item .ab-icon:before { + display: flex; + content: ""; + width: 20px; + height: 20px; + background-color: currentColor; + // SVG is from https://github.com/Automattic/gridicons/blob/f5b4c69fafc2a395aebce4500cb4f22d7c005745/php/gridicons.php#L380 + mask-image: url("data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iZ3JpZGljb24gZ3JpZGljb25zLW15LXNpdGVzIiBoZWlnaHQ9IjI0IiB3aWR0aD0iMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDI0IDI0Ij48Zz48cGF0aCBkPSJNMTIgMkM2LjQ3NyAyIDIgNi40NzcgMiAxMnM0LjQ3NyAxMCAxMCAxMCAxMC00LjQ3NyAxMC0xMFMxNy41MjMgMiAxMiAyek0zLjUgMTJjMC0xLjIzMi4yNjQtMi40MDIuNzM2LTMuNDU5TDguMjkxIDE5LjY1QTguNSA4LjUgMCAwMTMuNSAxMnptOC41IDguNTAxYy0uODM0IDAtMS42NC0uMTIyLTIuNDAxLS4zNDZsMi41NTEtNy40MTEgMi42MTMgNy4xNThhLjcxOC43MTggMCAwMC4wNjEuMTE3IDguNDk3IDguNDk3IDAgMDEtMi44MjQuNDgyem0xLjE3Mi0xMi40ODZjLjUxMi0uMDI3Ljk3My0uMDgxLjk3My0uMDgxLjQ1OC0uMDU0LjQwNC0uNzI3LS4wNTQtLjcwMSAwIDAtMS4zNzcuMTA4LTIuMjY2LjEwOC0uODM1IDAtMi4yMzktLjEwOC0yLjIzOS0uMTA4LS40NTktLjAyNi0uNTEyLjY3NC0uMDU0LjcwMSAwIDAgLjQzNC4wNTQuODkyLjA4MWwxLjMyNCAzLjYyOS0xLjg2IDUuNTc5LTMuMDk2LTkuMjA4Yy41MTItLjAyNy45NzMtLjA4MS45NzMtLjA4MS40NTgtLjA1NC40MDMtLjcyNy0uMDU1LS43MDEgMCAwLTEuMzc2LjEwOC0yLjI2NS4xMDgtLjE2IDAtLjM0Ny0uMDA0LS41NDctLjAxQTguNDkxIDguNDkxIDAgMDExMiAzLjVjMi4yMTMgMCA0LjIyOC44NDYgNS43NCAyLjIzMi0uMDM3LS4wMDItLjA3Mi0uMDA3LS4xMS0uMDA3LS44MzUgMC0xLjQyNy43MjctMS40MjcgMS41MDkgMCAuNzAxLjQwNCAxLjI5My44MzUgMS45OTQuMzIzLjU2Ni43MDEgMS4yOTMuNzAxIDIuMzQ0IDAgLjcyNy0uMjggMS41NzItLjY0NyAyLjc0OGwtLjg0OCAyLjgzMy0zLjA3Mi05LjEzOHptMy4xMDEgMTEuMzMybDIuNTk2LTcuNTA2Yy40ODUtMS4yMTMuNjQ2LTIuMTgyLjY0Ni0zLjA0NSAwLS4zMTMtLjAyMS0uNjAzLS4wNTctLjg3NEE4LjQ1NSA4LjQ1NSAwIDAxMjAuNSAxMmE4LjQ5MyA4LjQ5MyAwIDAxLTQuMjI3IDcuMzQ3eiIvPjwvZz48L3N2Zz4="); + mask-position: center; + mask-repeat: no-repeat; + + @media (max-width: 782px) { + width: 36px; + height: 36px; + margin: 0 8px; + mask-size: cover; + top: 5px; + } +} + /** * Reader menu */ From f80e0a5776ff9bd4be492022460bec0cab7517ec Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Wed, 17 Jul 2024 11:27:09 +0200 Subject: [PATCH 9/9] Staging Sites: Remove a filter that disables Jetpack staging mode for WPCOM staging sites (#38355) * Remove `wpcomsh_disable_jetpack_staging_mode_for_wpcom_staging_site` hook Reverts changes from https://github.com/Automattic/wpcomsh/commit/882d1cab3287489cc7ba969bed595892f4fcedc5. * Add changelog * Improve wording of changelog --- ...wpcomsh-staging-sites-disable-staging-mode | 4 +++ .../wpcomsh/feature-plugins/staging-sites.php | 24 -------------- .../wpcomsh/tests/test-staging-sites.php | 33 ------------------- 3 files changed, 4 insertions(+), 57 deletions(-) create mode 100644 projects/plugins/wpcomsh/changelog/remove-wpcomsh-staging-sites-disable-staging-mode delete mode 100644 projects/plugins/wpcomsh/tests/test-staging-sites.php diff --git a/projects/plugins/wpcomsh/changelog/remove-wpcomsh-staging-sites-disable-staging-mode b/projects/plugins/wpcomsh/changelog/remove-wpcomsh-staging-sites-disable-staging-mode new file mode 100644 index 0000000000000..b84e5e2f00fc6 --- /dev/null +++ b/projects/plugins/wpcomsh/changelog/remove-wpcomsh-staging-sites-disable-staging-mode @@ -0,0 +1,4 @@ +Significance: patch +Type: removed + +Removed code that disables Jetpack staging mode for WordPress.com staging sites. diff --git a/projects/plugins/wpcomsh/feature-plugins/staging-sites.php b/projects/plugins/wpcomsh/feature-plugins/staging-sites.php index b084910dad0cc..78cc6344c6301 100644 --- a/projects/plugins/wpcomsh/feature-plugins/staging-sites.php +++ b/projects/plugins/wpcomsh/feature-plugins/staging-sites.php @@ -5,11 +5,6 @@ * @package wpcomsh */ -/** - * Name of option that shows if the site is a staging site. - */ -const WPCOM_IS_STAGING_SITE_OPTION_NAME = 'wpcom_is_staging_site'; - /** * Returns Atomic persistent data value for wpcom_is_staging_site. * @@ -30,22 +25,3 @@ function wpcomsh_is_staging_site_get_atomic_persistent_data( $wpcom_is_staging_s // need to hook to default_option_* too because if this option doesn't exist, the hook wouldn't run. add_filter( 'default_option_wpcom_is_staging_site', 'wpcomsh_is_staging_site_get_atomic_persistent_data' ); add_filter( 'option_wpcom_is_staging_site', 'wpcomsh_is_staging_site_get_atomic_persistent_data' ); - -/** - * Disable Jetpack staging mode for wpcom staging sites. - * - * We set WP_ENVIRONMENT_TYPE constant to 'staging' for WPCOM staging sites, but we don't want - * Jetpack working in staging mode to let us use Jetpack sync and other features for staging sites. - * - * @param bool $is_staging If the current site is a staging site. - * - * @return false|mixed - */ -function wpcomsh_disable_jetpack_staging_mode_for_wpcom_staging_site( $is_staging ) { - if ( get_option( WPCOM_IS_STAGING_SITE_OPTION_NAME ) ) { - return false; - } - - return $is_staging; -} -add_filter( 'jetpack_is_staging_site', 'wpcomsh_disable_jetpack_staging_mode_for_wpcom_staging_site' ); diff --git a/projects/plugins/wpcomsh/tests/test-staging-sites.php b/projects/plugins/wpcomsh/tests/test-staging-sites.php deleted file mode 100644 index 75716d52448c0..0000000000000 --- a/projects/plugins/wpcomsh/tests/test-staging-sites.php +++ /dev/null @@ -1,33 +0,0 @@ -assertFalse( apply_filters( 'jetpack_is_staging_site', false ) ); - $this->assertTrue( apply_filters( 'jetpack_is_staging_site', true ) ); - } - - /** - * Ensure that the filter always returns false when the site is a staging site. - * - * @return void - */ - public function test_wpcomsh_disable_jetpack_staging_mode_always_false_staging_site() { - add_option( WPCOM_IS_STAGING_SITE_OPTION_NAME, 1 ); - $this->assertFalse( apply_filters( 'jetpack_is_staging_site', false ) ); - $this->assertFalse( apply_filters( 'jetpack_is_staging_site', true ) ); - } -}