Skip to content

Commit d076231

Browse files
committed
Add support for Blueprints defineSiteUrl
1 parent d57a7d1 commit d076231

File tree

8 files changed

+183
-39
lines changed

8 files changed

+183
-39
lines changed

common/lib/blueprint-settings.ts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import type { Blueprint } from '@wp-playground/blueprints';
2+
import type { BlueprintSiteSettings } from 'common/types/site-settings';
3+
4+
/**
5+
* Extracts form-relevant values from a blueprint.
6+
*/
7+
export function extractFormValuesFromBlueprint( blueprintJson: Blueprint ): BlueprintSiteSettings {
8+
const values: BlueprintSiteSettings = {};
9+
10+
if ( blueprintJson.preferredVersions ) {
11+
if ( blueprintJson.preferredVersions.php && blueprintJson.preferredVersions.php !== 'latest' ) {
12+
values.phpVersion = blueprintJson.preferredVersions.php;
13+
}
14+
if ( blueprintJson.preferredVersions.wp && blueprintJson.preferredVersions.wp !== 'latest' ) {
15+
values.wpVersion = blueprintJson.preferredVersions.wp;
16+
}
17+
}
18+
19+
if ( blueprintJson.steps && Array.isArray( blueprintJson.steps ) ) {
20+
const defineSiteUrlStep = blueprintJson.steps.find(
21+
( step: { step?: string } ) => step.step === 'defineSiteUrl'
22+
);
23+
if ( defineSiteUrlStep?.siteUrl ) {
24+
try {
25+
const url = new URL( defineSiteUrlStep.siteUrl );
26+
values.customDomain = url.hostname;
27+
values.enableHttps = url.protocol === 'https:';
28+
} catch {
29+
// Invalid URL, skip
30+
}
31+
}
32+
}
33+
34+
return values;
35+
}
36+
37+
/**
38+
* Updates a blueprint with form values. Only updates properties that already exist.
39+
*/
40+
export function updateBlueprintWithFormValues(
41+
blueprintJson: Blueprint,
42+
formValues: BlueprintSiteSettings
43+
): Blueprint {
44+
const updated = { ...blueprintJson };
45+
46+
// Update preferred versions (only if they already exist)
47+
if ( updated.preferredVersions ) {
48+
updated.preferredVersions = { ...updated.preferredVersions };
49+
50+
if ( updated.preferredVersions.php !== undefined && formValues.phpVersion ) {
51+
updated.preferredVersions.php = formValues.phpVersion;
52+
}
53+
if ( updated.preferredVersions.wp !== undefined && formValues.wpVersion ) {
54+
updated.preferredVersions.wp = formValues.wpVersion;
55+
}
56+
}
57+
58+
// Update defineSiteUrl step (only if it already exists)
59+
if ( updated.steps && Array.isArray( updated.steps ) ) {
60+
const stepIndex = updated.steps.findIndex(
61+
( step: { step?: string } ) => step.step === 'defineSiteUrl'
62+
);
63+
64+
if ( stepIndex >= 0 && formValues.customDomain ) {
65+
const protocol = formValues.enableHttps ? 'https' : 'http';
66+
updated.steps = [ ...updated.steps ];
67+
updated.steps[ stepIndex ] = {
68+
...updated.steps[ stepIndex ],
69+
siteUrl: `${ protocol }://${ formValues.customDomain }`,
70+
};
71+
}
72+
}
73+
74+
return updated;
75+
}

common/lib/blueprint-validation.ts

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { __ } from '@wordpress/i18n';
2+
import { Blueprint } from '@wp-playground/blueprints';
23
import validateBlueprintSchema from '@wp-playground/blueprints/blueprint-schema-validator';
34

45
interface UnsupportedFeature {
@@ -21,13 +22,6 @@ const UNSUPPORTED_BLUEPRINT_FEATURES: UnsupportedFeature[] = [
2122
name: 'login',
2223
reason: __( 'Studio automatically creates and logs in the admin user during site creation.' ),
2324
},
24-
{
25-
type: 'step',
26-
name: 'defineSiteUrl',
27-
reason: __(
28-
'Custom site URLs in blueprints are ignored. You can set a custom site URL on the Settings tab.'
29-
),
30-
},
3125
];
3226

3327
/**
@@ -60,17 +54,14 @@ function getUnsupportedFeatureInfo( name: string ): UnsupportedFeature | undefin
6054
);
6155
}
6256

63-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
64-
type BlueprintData = Record< string, any >;
57+
export type { Blueprint as BlueprintData } from '@wp-playground/blueprints';
6558

6659
export type BlueprintPreferredVersions = {
6760
php?: string;
6861
wp?: string;
6962
};
7063

71-
export function scanBlueprintForUnsupportedFeatures(
72-
blueprint: BlueprintData
73-
): UnsupportedFeature[] {
64+
export function scanBlueprintForUnsupportedFeatures( blueprint: Blueprint ): UnsupportedFeature[] {
7465
const foundUnsupported: UnsupportedFeature[] = [];
7566

7667
if ( blueprint.steps && Array.isArray( blueprint.steps ) ) {
@@ -100,8 +91,8 @@ export function scanBlueprintForUnsupportedFeatures(
10091
}
10192

10293
export function filterUnsupportedBlueprintFeatures(
103-
blueprint: BlueprintData | undefined
104-
): BlueprintData | undefined {
94+
blueprint: Blueprint | undefined
95+
): Blueprint | undefined {
10596
if ( ! blueprint ) {
10697
return undefined;
10798
}
@@ -163,7 +154,7 @@ export async function validateBlueprintData(
163154
};
164155
}
165156

166-
const unsupportedFeatures = scanBlueprintForUnsupportedFeatures( blueprintJson as BlueprintData );
157+
const unsupportedFeatures = scanBlueprintForUnsupportedFeatures( blueprintJson as Blueprint );
167158
const warnings = unsupportedFeatures.map( ( feature ) => ( {
168159
feature: feature.name,
169160
reason: feature.reason,

common/types/site-settings.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export interface BlueprintSiteSettings {
2+
phpVersion?: string;
3+
wpVersion?: string;
4+
customDomain?: string;
5+
enableHttps?: boolean;
6+
}

src/hooks/use-add-site.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as Sentry from '@sentry/electron/renderer';
22
import { useI18n } from '@wordpress/react-i18n';
33
import { useCallback, useMemo, useState } from 'react';
4+
import { updateBlueprintWithFormValues } from 'common/lib/blueprint-settings';
45
import { BlueprintValidationWarning } from 'common/lib/blueprint-validation';
56
import { generateCustomDomainFromSiteName } from 'common/lib/domains';
67
import { useSyncSites } from 'src/hooks/sync-sites';
@@ -63,6 +64,9 @@ export function useAddSite() {
6364
const [ blueprintDeeplinkWarnings, setBlueprintDeeplinkWarnings ] = useState<
6465
BlueprintValidationWarning[] | undefined
6566
>();
67+
const [ blueprintSuggestedDomain, setBlueprintSuggestedDomain ] = useState<
68+
string | undefined
69+
>();
6670
const [ isDeeplinkFlow, setIsDeeplinkFlow ] = useState( false );
6771
const [ existingDomainNames, setExistingDomainNames ] = useState< string[] >( [] );
6872

@@ -75,6 +79,7 @@ export function useAddSite() {
7579
setSelectedBlueprint( undefined );
7680
setBlueprintPreferredVersions( undefined );
7781
setBlueprintDeeplinkWarnings( undefined );
82+
setBlueprintSuggestedDomain( undefined );
7883
}, [] );
7984

8085
// For blueprint deeplinks - we need temporary state for PHP/WP versions
@@ -88,6 +93,7 @@ export function useAddSite() {
8893
setSelectedBlueprint( undefined );
8994
setBlueprintPreferredVersions( undefined );
9095
setBlueprintDeeplinkWarnings( undefined );
96+
setBlueprintSuggestedDomain( undefined );
9197
setSelectedRemoteSite( undefined );
9298
setDeeplinkPhpVersion( defaultPhpVersion as AllowedPHPVersion );
9399
setDeeplinkWpVersion( defaultWordPressVersion );
@@ -229,13 +235,25 @@ export function useAddSite() {
229235
// For import/sync workflows, the respective handlers will start the server
230236
const shouldSkipStart = !! fileForImport || !! selectedRemoteSite;
231237

238+
const enableHttps = formValues.useCustomDomain ? formValues.enableHttps : false;
239+
let updatedBlueprint: Blueprint | undefined;
240+
if ( selectedBlueprint?.blueprint ) {
241+
const updatedJson = updateBlueprintWithFormValues( selectedBlueprint.blueprint, {
242+
phpVersion: formValues.phpVersion,
243+
wpVersion: formValues.wpVersion,
244+
customDomain: usedCustomDomain,
245+
enableHttps,
246+
} );
247+
updatedBlueprint = { ...selectedBlueprint, blueprint: updatedJson };
248+
}
249+
232250
await createSite(
233251
formValues.sitePath,
234252
formValues.siteName,
235253
formValues.wpVersion,
236254
usedCustomDomain,
237-
formValues.useCustomDomain ? formValues.enableHttps : false,
238-
selectedBlueprint,
255+
enableHttps,
256+
updatedBlueprint ?? selectedBlueprint,
239257
formValues.phpVersion,
240258
async ( newSite ) => {
241259
if ( fileForImport ) {
@@ -302,6 +320,8 @@ export function useAddSite() {
302320
setBlueprintPreferredVersions,
303321
blueprintDeeplinkWarnings,
304322
setBlueprintDeeplinkWarnings,
323+
blueprintSuggestedDomain,
324+
setBlueprintSuggestedDomain,
305325
selectedRemoteSite,
306326
setSelectedRemoteSite,
307327
existingDomainNames,
@@ -326,6 +346,7 @@ export function useAddSite() {
326346
selectedBlueprint,
327347
blueprintPreferredVersions,
328348
blueprintDeeplinkWarnings,
349+
blueprintSuggestedDomain,
329350
selectedRemoteSite,
330351
existingDomainNames,
331352
loadAllCustomDomains,

src/modules/add-site/components/create-site-form.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ export interface CreateSiteFormProps {
3939
existingDomainNames?: string[];
4040
/** Blueprint preferred versions for warning display */
4141
blueprintPreferredVersions?: BlueprintPreferredVersions;
42+
/** Blueprint suggested domain from defineSiteUrl step */
43+
blueprintSuggestedDomain?: string;
4244
/** Called when form is submitted */
4345
onSubmit: ( values: CreateSiteFormValues ) => void;
4446
/** Called when form validity changes */
@@ -151,6 +153,7 @@ export const CreateSiteForm = ( {
151153
onSiteNameChange,
152154
existingDomainNames = [],
153155
blueprintPreferredVersions,
156+
blueprintSuggestedDomain,
154157
onSubmit,
155158
onValidityChange,
156159
formRef,
@@ -206,6 +209,15 @@ export const CreateSiteForm = ( {
206209
}
207210
}, [ defaultValues.phpVersion, defaultValues.wpVersion ] );
208211

212+
useEffect( () => {
213+
if ( hasUserInteracted.current || ! blueprintSuggestedDomain ) {
214+
return;
215+
}
216+
setUseCustomDomain( true );
217+
setCustomDomain( blueprintSuggestedDomain );
218+
setAdvancedSettingsVisible( true );
219+
}, [ blueprintSuggestedDomain ] );
220+
209221
useEffect( () => {
210222
if ( useCustomDomain && isCertificateTrusted ) {
211223
setEnableHttps( true );

src/modules/add-site/components/create-site.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export interface CreateSiteProps {
2020
onSiteNameChange: ( name: string ) => Promise< PathValidationResult >;
2121
existingDomainNames?: string[];
2222
blueprintPreferredVersions?: BlueprintPreferredVersions;
23+
blueprintSuggestedDomain?: string;
2324
originalDefaultVersions?: {
2425
phpVersion?: AllowedPHPVersion;
2526
wpVersion?: string;
@@ -35,6 +36,7 @@ export default function CreateSite( {
3536
onSiteNameChange,
3637
existingDomainNames = [],
3738
blueprintPreferredVersions,
39+
blueprintSuggestedDomain,
3840
onSubmit,
3941
onValidityChange,
4042
formRef,
@@ -53,6 +55,7 @@ export default function CreateSite( {
5355
onSiteNameChange={ onSiteNameChange }
5456
existingDomainNames={ existingDomainNames }
5557
blueprintPreferredVersions={ blueprintPreferredVersions }
58+
blueprintSuggestedDomain={ blueprintSuggestedDomain }
5659
onSubmit={ onSubmit }
5760
onValidityChange={ onValidityChange }
5861
formRef={ formRef }

src/modules/add-site/hooks/use-blueprint-deeplink.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { useI18n } from '@wordpress/react-i18n';
22
import { useCallback } from 'react';
3+
import { extractFormValuesFromBlueprint } from 'common/lib/blueprint-settings';
34
import {
45
BlueprintValidationWarning,
56
BlueprintPreferredVersions,
@@ -20,6 +21,7 @@ interface UseBlueprintDeeplinkOptions {
2021
setWpVersion: ( version: string ) => void;
2122
setBlueprintPreferredVersions: ( versions: BlueprintPreferredVersions | undefined ) => void;
2223
setBlueprintDeeplinkWarnings: ( warnings: BlueprintValidationWarning[] | undefined ) => void;
24+
setBlueprintSuggestedDomain: ( domain: string | undefined ) => void;
2325
setIsDeeplinkFlow: ( isDeeplink: boolean ) => void;
2426
onModalOpen?: () => void;
2527
}
@@ -33,6 +35,7 @@ export function useBlueprintDeeplink( options: UseBlueprintDeeplinkOptions ): vo
3335
setWpVersion,
3436
setBlueprintPreferredVersions,
3537
setBlueprintDeeplinkWarnings,
38+
setBlueprintSuggestedDomain,
3639
setIsDeeplinkFlow,
3740
onModalOpen,
3841
} = options;
@@ -69,15 +72,21 @@ export function useBlueprintDeeplink( options: UseBlueprintDeeplinkOptions ): vo
6972

7073
setSelectedBlueprint( fileBlueprint );
7174

75+
const formValues = extractFormValuesFromBlueprint( blueprintJson );
76+
7277
if ( blueprintJson.preferredVersions ) {
73-
const preferredVersions = blueprintJson.preferredVersions as BlueprintPreferredVersions;
74-
setBlueprintPreferredVersions( preferredVersions );
75-
if ( preferredVersions.php && preferredVersions.php !== 'latest' ) {
76-
setPhpVersion( preferredVersions.php );
77-
}
78-
if ( preferredVersions.wp && preferredVersions.wp !== 'latest' ) {
79-
setWpVersion( preferredVersions.wp );
80-
}
78+
setBlueprintPreferredVersions(
79+
blueprintJson.preferredVersions as BlueprintPreferredVersions
80+
);
81+
}
82+
if ( formValues.phpVersion ) {
83+
setPhpVersion( formValues.phpVersion );
84+
}
85+
if ( formValues.wpVersion ) {
86+
setWpVersion( formValues.wpVersion );
87+
}
88+
if ( formValues.customDomain ) {
89+
setBlueprintSuggestedDomain( formValues.customDomain );
8190
}
8291

8392
setBlueprintDeeplinkWarnings( warnings );
@@ -94,6 +103,7 @@ export function useBlueprintDeeplink( options: UseBlueprintDeeplinkOptions ): vo
94103
setWpVersion,
95104
setBlueprintPreferredVersions,
96105
setBlueprintDeeplinkWarnings,
106+
setBlueprintSuggestedDomain,
97107
setIsDeeplinkFlow,
98108
onModalOpen,
99109
]

0 commit comments

Comments
 (0)