Skip to content

Commit 215a44e

Browse files
authored
[Personal-WP] Fix ?plugin= URL parameter not installing plugins (#3218)
1 parent 6c6fac3 commit 215a44e

File tree

3 files changed

+96
-4
lines changed

3 files changed

+96
-4
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import { describe, it, expect, vi } from 'vitest';
2+
3+
// Set up browser globals before any imports that might need them
4+
// @ts-ignore - minimal mock for testing
5+
global.location = {
6+
origin: 'https://playground.wordpress.net',
7+
href: 'https://playground.wordpress.net/',
8+
};
9+
// @ts-ignore - minimal mock for testing
10+
global.window = global.window || {};
11+
// @ts-ignore
12+
global.window.self = global.window;
13+
// @ts-ignore
14+
global.window.top = global.window;
15+
16+
// Mock fetch for potential network requests
17+
global.fetch = vi.fn();
18+
19+
// Now we can import the module
20+
const { resolveUrlParamsForExistingSite } = await import('./index');
21+
22+
describe('resolveUrlParamsForExistingSite', () => {
23+
it('returns null when no actionable URL params are present', async () => {
24+
const url = new URL('https://playground.wordpress.net/');
25+
const result = await resolveUrlParamsForExistingSite(url);
26+
expect(result).toBeNull();
27+
});
28+
29+
it('returns null for non-actionable params like ?mode=', async () => {
30+
const url = new URL('https://playground.wordpress.net/?mode=seamless');
31+
const result = await resolveUrlParamsForExistingSite(url);
32+
expect(result).toBeNull();
33+
});
34+
35+
it('returns blueprint with plugins property for ?plugin= param', async () => {
36+
const url = new URL(
37+
'https://playground.wordpress.net/?plugin=woocommerce'
38+
);
39+
const result = await resolveUrlParamsForExistingSite(url);
40+
41+
expect(result).not.toBeNull();
42+
expect(result?.plugins).toEqual(['woocommerce']);
43+
});
44+
45+
it('returns blueprint with multiple plugins for multiple ?plugin= params', async () => {
46+
const url = new URL(
47+
'https://playground.wordpress.net/?plugin=woocommerce&plugin=jetpack'
48+
);
49+
const result = await resolveUrlParamsForExistingSite(url);
50+
51+
expect(result).not.toBeNull();
52+
expect(result?.plugins).toEqual(['woocommerce', 'jetpack']);
53+
});
54+
55+
it('returns blueprint with installTheme steps for ?theme= param', async () => {
56+
const url = new URL('https://playground.wordpress.net/?theme=flavor');
57+
const result = await resolveUrlParamsForExistingSite(url);
58+
59+
expect(result).not.toBeNull();
60+
expect(result?.steps).toBeDefined();
61+
62+
const themeStep = result?.steps?.find(
63+
(step: any) => step?.step === 'installTheme'
64+
);
65+
expect(themeStep).toBeDefined();
66+
expect((themeStep as any)?.themeData?.slug).toBe('flavor');
67+
});
68+
69+
it('sets landingPage from ?url= param via applyQueryOverrides', async () => {
70+
const url = new URL(
71+
'https://playground.wordpress.net/?plugin=woocommerce&url=/wp-admin/plugins.php'
72+
);
73+
const result = await resolveUrlParamsForExistingSite(url);
74+
75+
expect(result).not.toBeNull();
76+
expect(result?.landingPage).toBe('/wp-admin/plugins.php');
77+
});
78+
79+
it('returns null for ?gutenberg-pr= (not supported for existing sites)', async () => {
80+
const url = new URL(
81+
'https://playground.wordpress.net/?gutenberg-pr=12345'
82+
);
83+
const result = await resolveUrlParamsForExistingSite(url);
84+
expect(result).toBeNull();
85+
});
86+
});

packages/playground/personal-wp/src/lib/personalwp/index.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { BlueprintV1Declaration } from '@wp-playground/client';
22
import {
33
type ResolvedBlueprint,
44
resolveBlueprintFromURL,
5+
applyQueryOverrides,
56
} from '../state/url/resolve-blueprint-from-url';
67
import {
78
getBlueprintDeclaration,
@@ -79,9 +80,6 @@ const ACTIONABLE_URL_PARAMS = [
7980
'import-site',
8081
'import-wxr',
8182
'import-content',
82-
'gutenberg-pr',
83-
'gutenberg-branch',
84-
'core-pr',
8583
];
8684

8785
/**
@@ -109,9 +107,14 @@ export async function resolveUrlParamsForExistingSite(
109107
try {
110108
const resolved = await resolveBlueprintFromURL(url, undefined);
111109
// Extract the blueprint declaration from the bundle if needed
112-
const blueprint = isBlueprintBundle(resolved.blueprint)
110+
let blueprint = isBlueprintBundle(resolved.blueprint)
113111
? await getBlueprintDeclaration(resolved.blueprint)
114112
: (resolved.blueprint as BlueprintV1Declaration);
113+
// Apply query overrides (e.g., ?url= for landing page, ?login=, etc.)
114+
blueprint = (await applyQueryOverrides(
115+
blueprint,
116+
url.searchParams
117+
)) as BlueprintV1Declaration;
115118
return blueprint;
116119
} catch (e) {
117120
logger.error('Error resolving URL blueprint for existing site:', e);

packages/playground/personal-wp/src/lib/state/redux/boot-site-client.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,9 @@ export function bootSiteClient(
366366
const current = blueprint as BlueprintV1Declaration;
367367
blueprint = {
368368
...blueprint,
369+
...(resolved.plugins?.length
370+
? { plugins: resolved.plugins }
371+
: {}),
369372
landingPage: resolved.landingPage || current.landingPage,
370373
steps: [
371374
...(current.steps || []),

0 commit comments

Comments
 (0)