Skip to content
14 changes: 14 additions & 0 deletions src/lib/version-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,17 @@ export function isDevRelease( version: string ): boolean {
export function isWordPressDevVersion( version: string ): boolean {
return /^\d+\.\d+-[a-zA-Z0-9]+-\d+$/.test( version );
}

/**
* Gets the latest stable WordPress version from a list of WordPress versions
* Filters out 'latest', beta, and development versions to find the first stable release
* @param versions Array of WordPress version objects
* @returns The version string of the latest stable release, or undefined if none found
*/
export function getLatestStableWpVersion(
versions: Array< { value: string; isBeta: boolean; isDevelopment: boolean } >
): string | undefined {
return versions.find(
( version ) => version.value !== 'latest' && ! version.isBeta && ! version.isDevelopment
)?.value;
}
7 changes: 3 additions & 4 deletions src/modules/preview-site/components/create-preview-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import { Tooltip } from 'src/components/tooltip';
import { useGetWpVersion } from 'src/hooks/use-get-wp-version';
import { useOffline } from 'src/hooks/use-offline';
import { useSiteSize } from 'src/hooks/use-site-size';
import { getLatestStableWpVersion } from 'src/lib/version-utils';
import { hasVersionMismatch } from 'src/modules/preview-site/lib/version-comparison';
import { useRootSelector } from 'src/stores';
import { selectMinimumWordPressVersion } from 'src/stores/provider-constants-slice';
import { snapshotSelectors } from 'src/stores/snapshot-slice';
import { useGetWordPressVersions } from 'src/stores/wordpress-versions-api';
import { useGetSnapshotUsage } from 'src/stores/wpcom-api';
Expand Down Expand Up @@ -42,16 +42,15 @@ export function CreatePreviewButton( { onClick, selectedSite, user }: CreatePrev
const { isOverLimit } = useSiteSize( selectedSite.id );
const isOffline = useOffline();
const [ wpVersion ] = useGetWpVersion( selectedSite );
const minimumWordPressVersion = useRootSelector( selectMinimumWordPressVersion );
const { data: wpVersions = [] } = useGetWordPressVersions( {
minimumVersion: minimumWordPressVersion,
minimumVersion: '',
} );

const isAnySiteArchiving = !! activeOperationsForAnySite.length;
const isCurrentSiteArchiving = !! activeOperationsForCurrentSite;
const isOtherSiteArchiving = isAnySiteArchiving && ! isCurrentSiteArchiving;

const latestWpVersion = wpVersions.find( ( version ) => version.value === 'latest' )?.value;
const latestWpVersion = getLatestStableWpVersion( wpVersions );
const shouldShowMismatchTooltip = hasVersionMismatch( {
wpVersion,
latestWpVersion,
Expand Down
42 changes: 38 additions & 4 deletions src/modules/sync/components/sync-dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,20 @@ import { TwoColorProgressBar } from 'src/components/progress-bar';
import { Tooltip } from 'src/components/tooltip';
import { TreeView, TreeNode, updateNodeById } from 'src/components/tree-view';
import { SYNC_PUSH_SIZE_LIMIT_GB } from 'src/constants';
import { useGetWpVersion } from 'src/hooks/use-get-wp-version';
import { cx } from 'src/lib/cx';
import { getIpcApi } from 'src/lib/get-ipc-api';
import { getLocalizedLink } from 'src/lib/get-localized-link';
import { getLatestStableWpVersion } from 'src/lib/version-utils';
import { hasVersionMismatch } from 'src/modules/preview-site/lib/version-comparison';
import { SiteNameBox } from 'src/modules/sync/components/site-name-box';
import { useSelectedItemsPushSize } from 'src/modules/sync/hooks/use-selected-items-push-size';
import { useSyncDialogTexts } from 'src/modules/sync/hooks/use-sync-dialog-texts';
import { useTopLevelSyncTree } from 'src/modules/sync/hooks/use-top-level-sync-tree';
import { getSiteEnvironment } from 'src/modules/sync/lib/environment-utils';
import { useI18nLocale } from 'src/stores';
import { useLatestRewindId, useRemoteFileTree, useLocalFileTree } from 'src/stores/sync';
import { useGetWordPressVersions } from 'src/stores/wordpress-versions-api';
import { TreeViewLoadingSkeleton } from './tree-view-loading-skeleton';
import type { SyncSite } from 'src/hooks/use-fetch-wpcom-sites/types';

Expand Down Expand Up @@ -154,6 +158,19 @@ export function SyncDialog( {
const { fetchChildren, rewindId, isLoadingRewindId, isErrorRewindId, isLoadingLocalFileTree } =
useDynamicTreeState( type, localSite.id, remoteSite.id, setTreeState );

const [ wpVersion ] = useGetWpVersion( localSite );
const { data: wpVersions = [] } = useGetWordPressVersions( {
minimumVersion: '',
} );
const latestWpVersion = getLatestStableWpVersion( wpVersions );
const shouldShowVersionMismatch =
type === 'push' &&
hasVersionMismatch( {
wpVersion,
latestWpVersion,
phpVersion: localSite.phpVersion,
} );

const localSiteName = <SiteNameBox siteName={ localSite.name } envType="studio" />;
const remoteSiteName = <SiteNameBox siteName={ remoteSite.name } envType={ siteEnv } />;

Expand Down Expand Up @@ -227,10 +244,18 @@ export function SyncDialog( {
if ( type === 'pull' ) {
return 'pb-[70px]'; // Original padding for pull
}
if ( isPushSelectionOverLimit ) {
return 'pb-[200px]'; // Progress bar + warning notice
// Calculate dynamic padding based on number of notices shown
const noticeCount = [ isPushSelectionOverLimit, shouldShowVersionMismatch ].filter(
Boolean
).length;

if ( noticeCount === 0 ) {
return 'pb-[140px]'; // Just progress bar
}
return 'pb-[110px]'; // Just progress bar
if ( noticeCount === 1 ) {
return 'pb-[220px]'; // Progress bar + one notice
}
return 'pb-[300px]'; // Progress bar + two notices
};

return (
Expand Down Expand Up @@ -336,7 +361,7 @@ export function SyncDialog( {
</div>
</Tooltip>

<div className="px-8 py-4 absolute left-0 right-0 bottom-0 bg-white z-10 border-t border-a8c-gray-5">
<div className="px-8 py-4 absolute left-0 right-0 bottom-0 bg-white/[0.8] backdrop-blur-sm z-10 border-t border-a8c-gray-5">
{ type === 'push' && (
<div className="mb-4">
<TwoColorProgressBar
Expand All @@ -361,6 +386,15 @@ export function SyncDialog( {
</p>
</Notice>
) }
{ shouldShowVersionMismatch && (
<Notice status="warning" isDismissible={ false } className="mb-4">
<p data-testid="push-version-mismatch-notice">
{ __(
'Your Studio site is using a different WordPress or PHP version than your WordPress.com site. The remote site will keep on using the newest supported versions.'
) }
</p>
</Notice>
) }
<div className="flex justify-between items-center">
<div>
{ createInterpolateElement( syncTexts.envSync, {
Expand Down
1 change: 1 addition & 0 deletions src/modules/sync/tests/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ describe( 'ContentTabSync', () => {
getConnectedWpcomSites: jest.fn().mockResolvedValue( [] ),
getDirectorySize: jest.fn().mockResolvedValue( 0 ),
connectWpcomSites: jest.fn(),
getWpVersion: jest.fn().mockResolvedValue( '6.4.3' ),
listLocalFileTree: jest.fn().mockResolvedValue( [
{
name: 'plugins',
Expand Down