Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import useCreateWPCOMSiteMutation from 'calypso/a8c-for-agencies/data/sites/use-
import FormSelect from 'calypso/components/forms/form-select';
import FormTextInputWithAffixes from 'calypso/components/forms/form-text-input-with-affixes';
import { useDataCenterOptions } from 'calypso/data/data-center/use-data-center-options';
import { usePhpVersions } from 'calypso/data/php-versions/use-php-versions';
import { getPHPVersions } from 'calypso/data/php-versions';
import { useDispatch } from 'calypso/state';
import { errorNotice } from 'calypso/state/notices/actions';
import { useSiteName } from './use-site-name';
Expand Down Expand Up @@ -42,7 +42,7 @@ export default function SiteConfigurationsModal( {
const [ isSubmitting, setIsSubmitting ] = useState( false );
const translate = useTranslate();
const dataCenterOptions = useDataCenterOptions();
const { phpVersions } = usePhpVersions();
const { phpVersions } = getPHPVersions();
const siteName = useSiteName( randomSiteName, isRandomSiteNameLoading );
const { mutate: createWPCOMSite } = useCreateWPCOMSiteMutation();
const { mutate: createWPCOMDevSite } = useCreateWPCOMDevSiteMutation();
Expand Down
4 changes: 4 additions & 0 deletions client/dashboard/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ module.exports = {
{
group: [
'calypso/*',
// Allowed: calypso/data/php-versions
'!calypso/data',
'calypso/data/*',
'!calypso/data/php-versions',
// Allowed: calypso/lib/wp
'!calypso/lib',
'calypso/lib/*',
Expand Down
10 changes: 10 additions & 0 deletions client/dashboard/app/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
fetchSiteMediaStorage,
fetchSiteMonitorUptime,
fetchPHPVersion,
updatePHPVersion,
fetchCurrentPlan,
fetchSiteEngagementStats,
fetchDomains,
Expand Down Expand Up @@ -72,6 +73,15 @@ export function sitePHPVersionQuery( siteIdOrSlug: string ) {
};
}

export function sitePHPVersionMutation( siteSlug: string ) {
return {
mutationFn: ( version: string ) => updatePHPVersion( siteSlug, version ),
onSuccess: () => {
queryClient.invalidateQueries( { queryKey: [ 'site', siteSlug, 'php-version' ] } );
},
};
}

export function siteWordPressVersionQuery( siteSlug: string ) {
return {
queryKey: [ 'site', siteSlug, 'wp-version' ],
Expand Down
20 changes: 20 additions & 0 deletions client/dashboard/app/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
createLazyRoute,
} from '@tanstack/react-router';
import { fetchTwoStep } from '../data';
import { canUpdatePHPVersion } from '../sites/settings-php/utils';
import { canUpdateWordPressVersion } from '../sites/settings-wordpress/utils';
import NotFound from './404';
import UnknownError from './500';
Expand All @@ -19,6 +20,7 @@ import {
siteCurrentPlanQuery,
siteEngagementStatsQuery,
siteWordPressVersionQuery,
sitePHPVersionQuery,
} from './queries';
import { queryClient } from './query-client';
import Root from './root';
Expand Down Expand Up @@ -180,6 +182,23 @@ const siteSettingsWordPressRoute = createRoute( {
)
);

const siteSettingsPHPRoute = createRoute( {
getParentRoute: () => siteRoute,
path: 'settings/php',
loader: async ( { params: { siteSlug } } ) => {
const site = await queryClient.ensureQueryData( siteQuery( siteSlug ) );
if ( canUpdatePHPVersion( site ) ) {
return await queryClient.ensureQueryData( sitePHPVersionQuery( siteSlug ) );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: no need to return anything

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressing it in #103702

}
},
} ).lazy( () =>
import( '../sites/settings-php' ).then( ( d ) =>
createLazyRoute( 'site-settings-php' )( {
component: () => <d.default siteSlug={ siteRoute.useParams().siteSlug } />,
} )
)
);

const siteSettingsTransferSiteRoute = createRoute( {
getParentRoute: () => siteRoute,
path: 'settings/transfer-site',
Expand Down Expand Up @@ -358,6 +377,7 @@ const createRouteTree = ( config: AppConfig ) => {
siteSettingsSubscriptionGiftingRoute,
siteSettingsDatabaseRoute,
siteSettingsWordPressRoute,
siteSettingsPHPRoute,
siteSettingsTransferSiteRoute,
] )
);
Expand Down
15 changes: 13 additions & 2 deletions client/dashboard/data/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,25 @@ export const fetchSiteMonitorUptime = async (
};

export const fetchPHPVersion = async ( id: string ): Promise< string | undefined > => {
// TODO: check request in different contexts.. Also do we show this only for atomic sites?
// TODO: find out what check is needed before this request to avoid 403 errors.
return wpcom.req.get( {
path: `/sites/${ id }/hosting/php-version`,
apiNamespace: 'wpcom/v2',
} );
};

export const updatePHPVersion = async (
siteIdOrSlug: string,
version: string
): Promise< void > => {
return wpcom.req.post(
{
path: `/sites/${ siteIdOrSlug }/hosting/php-version`,
apiNamespace: 'wpcom/v2',
},
{ version }
);
};

export const fetchWordPressVersion = async ( siteIdOrSlug: string ): Promise< string > => {
return wpcom.req.get( {
path: `/sites/${ siteIdOrSlug }/hosting/wp-version`,
Expand Down
120 changes: 120 additions & 0 deletions client/dashboard/sites/settings-php/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { DataForm } from '@automattic/dataviews';
import { useQuery, useMutation } from '@tanstack/react-query';
import {
Card,
CardBody,
__experimentalHStack as HStack,
__experimentalVStack as VStack,
Button,
} from '@wordpress/components';
import { useDispatch } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
import { store as noticesStore } from '@wordpress/notices';
import { useState } from 'react';
import { getPHPVersions } from 'calypso/data/php-versions';
import { siteQuery, sitePHPVersionQuery, sitePHPVersionMutation } from '../../app/queries';
import PageLayout from '../../components/page-layout';
import SettingsPageHeader from '../settings-page-header';
import { canUpdatePHPVersion } from './utils';
import type { Field } from '@automattic/dataviews';

export default function PHPVersionSettings( { siteSlug }: { siteSlug: string } ) {
const { data: site } = useQuery( siteQuery( siteSlug ) );
const canUpdate = site && canUpdatePHPVersion( site );

const { data: currentVersion } = useQuery( {
...sitePHPVersionQuery( siteSlug ),
enabled: canUpdate,
} );
const mutation = useMutation( sitePHPVersionMutation( siteSlug ) );
const { createSuccessNotice, createErrorNotice } = useDispatch( noticesStore );

const [ formData, setFormData ] = useState< { version: string } >( {
version: currentVersion ?? '',
} );

if ( ! site ) {
return null;
}

const { phpVersions } = getPHPVersions();

const fields: Field< { version: string } >[] = [
{
id: 'version',
label: __( 'PHP version' ),
Edit: 'select',
elements: phpVersions.filter( ( option ) => {
// Show disabled PHP version only if the site is still using it.
if ( option.disabled && option.value !== currentVersion ) {
return false;
}
return true;
} ),
},
];

const form = {
type: 'regular' as const,
fields: [ 'version' ],
};

const isDirty = formData.version !== currentVersion;
const { isPending } = mutation;

const handleSubmit = ( e: React.FormEvent ) => {
e.preventDefault();
mutation.mutate( formData.version, {
onSuccess: () => {
createSuccessNotice( __( 'Settings saved.' ), { type: 'snackbar' } );
},
onError: () => {
createErrorNotice( __( 'Failed to save settings.' ), {
type: 'snackbar',
} );
},
} );
};

const renderForm = () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this an inline function? I've always found these weird. Why not render it in canUpdate ? ... : ...? Or make a new component if it needs to be reusable?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's just a matter of taste; I just find it's easier to read / follow instead of a giant ternary :)

Maybe @taipeicoder can update it when you implement the upsell 🙈

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's fine, I just don't often see it I guess :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressing it in #103702

return (
<Card>
<CardBody>
<form onSubmit={ handleSubmit }>
<VStack spacing={ 4 }>
<DataForm< { version: string } >
data={ formData }
fields={ fields }
form={ form }
onChange={ ( edits: { version?: string } ) => {
setFormData( ( data ) => ( { ...data, ...edits } ) );
} }
/>
<HStack justify="flex-start">
<Button
variant="primary"
type="submit"
isBusy={ isPending }
disabled={ isPending || ! isDirty }
>
{ __( 'Save' ) }
</Button>
</HStack>
</VStack>
</form>
</CardBody>
</Card>
);
};

const renderCallout = () => {
return <p>TODO: callout</p>;
};

return (
<PageLayout size="small">
<SettingsPageHeader title="PHP" />
{ canUpdate ? renderForm() : renderCallout() }
</PageLayout>
);
}
34 changes: 34 additions & 0 deletions client/dashboard/sites/settings-php/summary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useQuery } from '@tanstack/react-query';
import { Icon } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { code } from '@wordpress/icons';
import { getPHPVersions } from 'calypso/data/php-versions';
import { sitePHPVersionQuery } from '../../app/queries';
import RouterLinkSummaryButton from '../../components/router-link-summary-button';
import { canUpdatePHPVersion } from './utils';
import type { Site } from '../../data/types';

export default function PHPSettingsSummary( { site }: { site: Site } ) {
const { data: version } = useQuery( {
...sitePHPVersionQuery( site.slug ),
enabled: canUpdatePHPVersion( site ),
} );

const { recommendedValue } = getPHPVersions();

const badge = {
text: version ?? __( 'Managed' ),
intent:
version && version !== recommendedValue ? ( 'warning' as const ) : ( 'success' as const ),
};

return (
<RouterLinkSummaryButton
to={ `/sites/${ site.slug }/settings/php` }
title="PHP"
density="medium"
decoration={ <Icon icon={ code } /> }
badges={ [ badge ] }
/>
);
}
5 changes: 5 additions & 0 deletions client/dashboard/sites/settings-php/utils.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { Site } from '../../data/types';

export function canUpdatePHPVersion( site: Site ) {
return site.is_wpcom_atomic;
}
6 changes: 3 additions & 3 deletions client/dashboard/sites/settings-wordpress/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ export default function WordPressVersionSettings( { siteSlug }: { siteSlug: stri
const { data: site } = useQuery( siteQuery( siteSlug ) );
const canUpdate = site && canUpdateWordPressVersion( site );

const { data: version } = useQuery( {
const { data: currentVersion } = useQuery( {
...siteWordPressVersionQuery( siteSlug ),
enabled: canUpdate,
} );
const mutation = useMutation( siteWordPressVersionMutation( siteSlug ) );
const { createSuccessNotice, createErrorNotice } = useDispatch( noticesStore );

const [ formData, setFormData ] = useState< { version: string } >( {
version: version ?? '',
version: currentVersion ?? '',
} );

if ( ! site ) {
Expand All @@ -61,7 +61,7 @@ export default function WordPressVersionSettings( { siteSlug }: { siteSlug: stri
fields: [ 'version' ],
};

const isDirty = formData.version !== version;
const isDirty = formData.version !== currentVersion;
const { isPending } = mutation;

const handleSubmit = ( e: React.FormEvent ) => {
Expand Down
2 changes: 2 additions & 0 deletions client/dashboard/sites/settings/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { siteQuery, siteSettingsQuery } from '../../app/queries';
import { PageHeader } from '../../components/page-header';
import PageLayout from '../../components/page-layout';
import DatabaseSettingsSummary from '../settings-database/summary';
import PHPSettingsSummary from '../settings-php/summary';
import SiteVisibilitySettingsSummary from '../settings-site-visibility/summary';
import SubscriptionGiftingSettingsSummary from '../settings-subscription-gifting/summary';
import WordPressSettingsSummary from '../settings-wordpress/summary';
Expand Down Expand Up @@ -37,6 +38,7 @@ export default function SiteSettings( { siteSlug }: { siteSlug: string } ) {
<VStack>
<DatabaseSettingsSummary site={ site } />
<WordPressSettingsSummary site={ site } />
<PHPSettingsSummary site={ site } />
</VStack>
</Card>
<SiteActions site={ site } />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import { useTranslate } from 'i18n-calypso';

export const usePhpVersions = () => {
const translate = useTranslate();
import { __, sprintf } from '@wordpress/i18n';

export const getPHPVersions = () => {
// PHP 8.3 is now the default recommended version
const recommendedValue = '8.3';
const recommendedLabel = translate( '%s (recommended)', {
args: recommendedValue,
comment: 'PHP Version for a version switcher',
} );
// translators: PHP Version for a version switcher
const recommendedLabel = sprintf( __( '%s (recommended)' ), recommendedValue );

const phpVersions = [
{
Expand All @@ -17,10 +13,8 @@ export const usePhpVersions = () => {
disabled: true, // EOL 6th December, 2021
},
{
label: translate( '%s (deprecated)', {
args: '7.4',
comment: 'PHP Version for a version switcher',
} ),
// translators: PHP Version for a version switcher
label: sprintf( __( '%s (deprecated)' ), '7.4' ),
value: '7.4',
disabled: true, // EOL 1st July, 2024
},
Expand All @@ -30,10 +24,8 @@ export const usePhpVersions = () => {
disabled: true, // EOL 26th November, 2023
},
{
label: translate( '%s (deprecated)', {
args: '8.1',
comment: 'PHP Version for a version switcher',
} ),
// translators: PHP Version for a version switcher
label: sprintf( __( '%s (deprecated)' ), '8.1' ),
value: '8.1',
disabled: false, // EOL 31st December, 2025
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useEffect, useRef, useState } from 'react';
import { useSearchParams } from 'react-router-dom';
import { usePhpVersions } from 'calypso/data/php-versions/use-php-versions';
import { getPHPVersions } from 'calypso/data/php-versions';
import { initializeWordPressPlayground } from '../../lib/initialize-playground';
import { PlaygroundError } from '../playground-error';
import type { PlaygroundClient } from '@wp-playground/client';
Expand All @@ -15,7 +15,7 @@ export function PlaygroundIframe( {
setPlaygroundClient: ( client: PlaygroundClient ) => void;
} ) {
const iframeRef = useRef< HTMLIFrameElement >( null );
const recommendedPHPVersion = usePhpVersions().recommendedValue;
const recommendedPHPVersion = getPHPVersions().recommendedValue;
const [ searchParams, setSearchParams ] = useSearchParams();
const [ playgroundError, setPlaygroundError ] = useState< string | null >( null );

Expand Down
Loading