@wp-playground/blueprints 0.1.28 → 0.1.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/index.ts +4 -5
- package/src/lib/blueprint.ts +28 -0
- package/src/lib/{run.spec.ts → compile.spec.ts} +1 -2
- package/src/lib/compile.ts +86 -71
- package/src/lib/resources.ts +2 -2
- package/src/lib/steps/activate-plugin.ts +9 -5
- package/src/lib/steps/apply-wordpress-patches/index.ts +6 -11
- package/src/lib/steps/client-methods.ts +76 -11
- package/src/lib/steps/common.ts +4 -0
- package/src/lib/steps/define-site-url.ts +7 -5
- package/src/lib/steps/handlers.ts +21 -0
- package/src/lib/steps/import-export.ts +34 -26
- package/src/lib/steps/index.ts +45 -78
- package/src/lib/steps/install-plugin.ts +114 -97
- package/src/lib/steps/install-theme.ts +70 -60
- package/src/lib/steps/login.ts +11 -11
- package/src/lib/steps/run-wp-installation-wizard.ts +6 -8
- package/src/lib/steps/site-data.ts +20 -25
- package/src/lib/run.ts +0 -152
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PHPResponse, UniversalPHP } from '@php-wasm/universal';
|
|
2
2
|
import { phpVars } from '@php-wasm/util';
|
|
3
|
-
import {
|
|
3
|
+
import { StepHandler } from '.';
|
|
4
4
|
|
|
5
5
|
// @ts-ignore
|
|
6
6
|
import migrationsPHPCode from './migration.php?raw';
|
|
@@ -9,17 +9,6 @@ import migrationsPHPCode from './migration.php?raw';
|
|
|
9
9
|
* Full site export support:
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
export interface ReplaceSiteStep<ResourceType> extends BaseStep {
|
|
13
|
-
step: 'replaceSite';
|
|
14
|
-
fullSiteZip: ResourceType;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface UnzipStep extends BaseStep {
|
|
18
|
-
step: 'unzip';
|
|
19
|
-
zipPath: string;
|
|
20
|
-
extractToPath: string;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
12
|
/**
|
|
24
13
|
* Export the current site as a zip file.
|
|
25
14
|
*
|
|
@@ -44,13 +33,21 @@ export async function zipEntireSite(playground: UniversalPHP) {
|
|
|
44
33
|
return new File([fileBuffer], zipName);
|
|
45
34
|
}
|
|
46
35
|
|
|
36
|
+
export interface ReplaceSiteStep<ResourceType> {
|
|
37
|
+
step: 'replaceSite';
|
|
38
|
+
fullSiteZip: ResourceType;
|
|
39
|
+
}
|
|
40
|
+
|
|
47
41
|
/**
|
|
48
42
|
* Replace the current site with the contents of a full site zip file.
|
|
49
43
|
*
|
|
50
44
|
* @param playground Playground client.
|
|
51
45
|
* @param fullSiteZip Zipped WordPress site.
|
|
52
46
|
*/
|
|
53
|
-
export
|
|
47
|
+
export const replaceSite: StepHandler<ReplaceSiteStep<File>> = async (
|
|
48
|
+
playground,
|
|
49
|
+
{ fullSiteZip }
|
|
50
|
+
) => {
|
|
54
51
|
const zipPath = '/import.zip';
|
|
55
52
|
await playground.writeFile(
|
|
56
53
|
zipPath,
|
|
@@ -61,7 +58,7 @@ export async function replaceSite(playground: UniversalPHP, fullSiteZip: File) {
|
|
|
61
58
|
const documentRoot = await playground.documentRoot;
|
|
62
59
|
|
|
63
60
|
await playground.rmdir(documentRoot);
|
|
64
|
-
await unzip(playground, zipPath, '/');
|
|
61
|
+
await unzip(playground, { zipPath, extractToPath: '/' });
|
|
65
62
|
|
|
66
63
|
const js = phpVars({ absoluteUrl });
|
|
67
64
|
await updateFile(
|
|
@@ -75,6 +72,12 @@ export async function replaceSite(playground: UniversalPHP, fullSiteZip: File) {
|
|
|
75
72
|
}
|
|
76
73
|
?>${contents}`
|
|
77
74
|
);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export interface UnzipStep {
|
|
78
|
+
step: 'unzip';
|
|
79
|
+
zipPath: string;
|
|
80
|
+
extractToPath: string;
|
|
78
81
|
}
|
|
79
82
|
|
|
80
83
|
/**
|
|
@@ -84,17 +87,19 @@ export async function replaceSite(playground: UniversalPHP, fullSiteZip: File) {
|
|
|
84
87
|
* @param zipPath The zip file to unzip.
|
|
85
88
|
* @param extractTo The directory to extract the zip file to.
|
|
86
89
|
*/
|
|
87
|
-
export async
|
|
88
|
-
playground
|
|
89
|
-
zipPath
|
|
90
|
-
|
|
91
|
-
) {
|
|
90
|
+
export const unzip: StepHandler<UnzipStep> = async (
|
|
91
|
+
playground,
|
|
92
|
+
{ zipPath, extractToPath }
|
|
93
|
+
) => {
|
|
92
94
|
const js = phpVars({
|
|
93
95
|
zipPath,
|
|
94
|
-
|
|
96
|
+
extractToPath,
|
|
95
97
|
});
|
|
96
|
-
await phpMigration(
|
|
97
|
-
|
|
98
|
+
await phpMigration(
|
|
99
|
+
playground,
|
|
100
|
+
`unzip(${js.zipPath}, ${js.extractToPath});`
|
|
101
|
+
);
|
|
102
|
+
};
|
|
98
103
|
|
|
99
104
|
/**
|
|
100
105
|
* WXR and WXZ files support:
|
|
@@ -128,7 +133,7 @@ export async function exportWXZ(playground: UniversalPHP) {
|
|
|
128
133
|
return new File([databaseExportResponse.bytes], 'export.wxz');
|
|
129
134
|
}
|
|
130
135
|
|
|
131
|
-
export interface ImportFileStep<ResourceType>
|
|
136
|
+
export interface ImportFileStep<ResourceType> {
|
|
132
137
|
step: 'importFile';
|
|
133
138
|
file: ResourceType;
|
|
134
139
|
}
|
|
@@ -141,7 +146,10 @@ export interface ImportFileStep<ResourceType> extends BaseStep {
|
|
|
141
146
|
* @param playground Playground client.
|
|
142
147
|
* @param file The file to import.
|
|
143
148
|
*/
|
|
144
|
-
export
|
|
149
|
+
export const importFile: StepHandler<ImportFileStep<File>> = async (
|
|
150
|
+
playground,
|
|
151
|
+
{ file }
|
|
152
|
+
) => {
|
|
145
153
|
const importerPageOneResponse = await playground.request({
|
|
146
154
|
url: '/wp-admin/admin.php?import=wordpress',
|
|
147
155
|
});
|
|
@@ -177,12 +185,12 @@ export async function submitImporterForm(playground: UniversalPHP, file: File) {
|
|
|
177
185
|
}
|
|
178
186
|
}
|
|
179
187
|
|
|
180
|
-
|
|
188
|
+
await playground.request({
|
|
181
189
|
url: importForm.action,
|
|
182
190
|
method: 'POST',
|
|
183
191
|
formData: data,
|
|
184
192
|
});
|
|
185
|
-
}
|
|
193
|
+
};
|
|
186
194
|
|
|
187
195
|
function DOM(response: PHPResponse) {
|
|
188
196
|
return new DOMParser().parseFromString(response.text, 'text/html');
|
package/src/lib/steps/index.ts
CHANGED
|
@@ -1,38 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
exportWXZ,
|
|
5
|
-
replaceSite,
|
|
6
|
-
submitImporterForm,
|
|
7
|
-
} from './import-export';
|
|
8
|
-
export { login } from './login';
|
|
9
|
-
export { installTheme } from './install-theme';
|
|
10
|
-
export type { InstallThemeOptions } from './install-theme';
|
|
11
|
-
export { installPlugin } from './install-plugin';
|
|
12
|
-
export type { InstallPluginOptions } from './install-plugin';
|
|
13
|
-
export { activatePlugin } from './activate-plugin';
|
|
14
|
-
export { setSiteOptions, updateUserMeta } from './site-data';
|
|
15
|
-
export type { SiteOptions, UserMeta } from './site-data';
|
|
16
|
-
export { defineSiteUrl } from './define-site-url';
|
|
17
|
-
export { applyWordPressPatches } from './apply-wordpress-patches';
|
|
18
|
-
export type { PatchOptions } from './apply-wordpress-patches';
|
|
19
|
-
export { runWpInstallationWizard } from './run-wp-installation-wizard';
|
|
20
|
-
export type { WordPressInstallationOptions } from './run-wp-installation-wizard';
|
|
21
|
-
|
|
1
|
+
import { ProgressTracker } from '@php-wasm/progress';
|
|
2
|
+
import { UniversalPHP } from '@php-wasm/universal';
|
|
3
|
+
import { FileReference } from '../resources';
|
|
22
4
|
import { ActivatePluginStep } from './activate-plugin';
|
|
23
5
|
import { ApplyWordPressPatchesStep } from './apply-wordpress-patches';
|
|
24
|
-
import {
|
|
25
|
-
RunPHPStep,
|
|
26
|
-
RunPHPWithOptionsStep,
|
|
27
|
-
SetPhpIniEntryStep,
|
|
28
|
-
RequestStep,
|
|
29
|
-
CpStep,
|
|
30
|
-
RmStep,
|
|
31
|
-
RmdirStep,
|
|
32
|
-
MvStep,
|
|
33
|
-
MkdirStep,
|
|
34
|
-
WriteFileStep,
|
|
35
|
-
} from './client-methods';
|
|
36
6
|
import { DefineSiteUrlStep } from './define-site-url';
|
|
37
7
|
import { ImportFileStep, ReplaceSiteStep, UnzipStep } from './import-export';
|
|
38
8
|
import { InstallPluginStep } from './install-plugin';
|
|
@@ -40,59 +10,56 @@ import { InstallThemeStep } from './install-theme';
|
|
|
40
10
|
import { LoginStep } from './login';
|
|
41
11
|
import { RunWpInstallationWizardStep } from './run-wp-installation-wizard';
|
|
42
12
|
import { SetSiteOptionsStep, UpdateUserMetaStep } from './site-data';
|
|
43
|
-
|
|
44
|
-
|
|
13
|
+
import {
|
|
14
|
+
RmStep,
|
|
15
|
+
CpStep,
|
|
16
|
+
MkdirStep,
|
|
17
|
+
RmdirStep,
|
|
18
|
+
MvStep,
|
|
19
|
+
SetPhpIniEntryStep,
|
|
20
|
+
RunPHPStep,
|
|
21
|
+
RunPHPWithOptionsStep,
|
|
22
|
+
RequestStep,
|
|
23
|
+
WriteFileStep,
|
|
24
|
+
} from './client-methods';
|
|
25
|
+
|
|
26
|
+
export type Step = GenericStep<FileReference>;
|
|
27
|
+
export type StepDefinition = Step & {
|
|
45
28
|
progress?: {
|
|
46
29
|
weight?: number;
|
|
47
30
|
caption?: string;
|
|
48
31
|
};
|
|
49
|
-
}
|
|
32
|
+
};
|
|
50
33
|
|
|
51
|
-
export type
|
|
52
|
-
| InstallPluginStep<ResourceType>
|
|
53
|
-
| InstallThemeStep<ResourceType>
|
|
54
|
-
| LoginStep
|
|
55
|
-
| ImportFileStep<ResourceType>
|
|
34
|
+
export type GenericStep<Resource> =
|
|
56
35
|
| ActivatePluginStep
|
|
57
|
-
| ReplaceSiteStep<ResourceType>
|
|
58
|
-
| UnzipStep
|
|
59
|
-
| DefineSiteUrlStep
|
|
60
36
|
| ApplyWordPressPatchesStep
|
|
61
|
-
| RunWpInstallationWizardStep
|
|
62
|
-
| SetSiteOptionsStep
|
|
63
|
-
| UpdateUserMetaStep
|
|
64
|
-
| RunPHPStep
|
|
65
|
-
| RunPHPWithOptionsStep
|
|
66
|
-
| SetPhpIniEntryStep
|
|
67
|
-
| RequestStep
|
|
68
37
|
| CpStep
|
|
38
|
+
| DefineSiteUrlStep
|
|
39
|
+
| ImportFileStep<Resource>
|
|
40
|
+
| InstallPluginStep<Resource>
|
|
41
|
+
| InstallThemeStep<Resource>
|
|
42
|
+
| LoginStep
|
|
43
|
+
| MkdirStep
|
|
44
|
+
| MvStep
|
|
45
|
+
| RequestStep
|
|
46
|
+
| ReplaceSiteStep<Resource>
|
|
69
47
|
| RmStep
|
|
70
48
|
| RmdirStep
|
|
71
|
-
|
|
|
72
|
-
|
|
|
73
|
-
|
|
|
49
|
+
| RunPHPStep
|
|
50
|
+
| RunPHPWithOptionsStep
|
|
51
|
+
| RunWpInstallationWizardStep
|
|
52
|
+
| SetPhpIniEntryStep
|
|
53
|
+
| SetSiteOptionsStep
|
|
54
|
+
| UnzipStep
|
|
55
|
+
| UpdateUserMetaStep
|
|
56
|
+
| WriteFileStep<Resource>;
|
|
74
57
|
|
|
75
|
-
export type
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
DefineSiteUrlStep,
|
|
84
|
-
ApplyWordPressPatchesStep,
|
|
85
|
-
RunWpInstallationWizardStep,
|
|
86
|
-
SetSiteOptionsStep,
|
|
87
|
-
UpdateUserMetaStep,
|
|
88
|
-
RunPHPStep,
|
|
89
|
-
RunPHPWithOptionsStep,
|
|
90
|
-
SetPhpIniEntryStep,
|
|
91
|
-
RequestStep,
|
|
92
|
-
CpStep,
|
|
93
|
-
RmStep,
|
|
94
|
-
RmdirStep,
|
|
95
|
-
MvStep,
|
|
96
|
-
MkdirStep,
|
|
97
|
-
WriteFileStep,
|
|
98
|
-
};
|
|
58
|
+
export type StepHandler<S extends GenericStep<File>> = (
|
|
59
|
+
php: UniversalPHP,
|
|
60
|
+
args: Omit<S, 'step'>,
|
|
61
|
+
progressArgs?: {
|
|
62
|
+
tracker: ProgressTracker;
|
|
63
|
+
initialCaption?: string;
|
|
64
|
+
}
|
|
65
|
+
) => any;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { UniversalPHP } from '@php-wasm/universal';
|
|
2
|
-
import {
|
|
3
|
-
import { asDOM } from './common';
|
|
2
|
+
import { StepHandler } from '.';
|
|
3
|
+
import { asDOM, zipNameToHumanName } from './common';
|
|
4
4
|
|
|
5
|
-
export interface InstallPluginStep<ResourceType>
|
|
5
|
+
export interface InstallPluginStep<ResourceType> {
|
|
6
6
|
step: 'installPlugin';
|
|
7
7
|
pluginZipFile: ResourceType;
|
|
8
8
|
options?: InstallPluginOptions;
|
|
@@ -24,105 +24,122 @@ export interface InstallPluginOptions {
|
|
|
24
24
|
* @param pluginZipFile The plugin zip file.
|
|
25
25
|
* @param options Optional. Set `activate` to false if you don't want to activate the plugin.
|
|
26
26
|
*/
|
|
27
|
-
export async
|
|
28
|
-
playground
|
|
29
|
-
pluginZipFile
|
|
30
|
-
|
|
31
|
-
) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
// Upload it to WordPress
|
|
35
|
-
const pluginForm = await playground.request({
|
|
36
|
-
url: '/wp-admin/plugin-install.php?tab=upload',
|
|
37
|
-
});
|
|
38
|
-
const pluginFormPage = asDOM(pluginForm);
|
|
39
|
-
const pluginFormData = new FormData(
|
|
40
|
-
pluginFormPage.querySelector('.wp-upload-form')! as HTMLFormElement
|
|
41
|
-
) as any;
|
|
42
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
43
|
-
const { pluginzip, ...postData } = Object.fromEntries(
|
|
44
|
-
pluginFormData.entries()
|
|
27
|
+
export const installPlugin: StepHandler<InstallPluginStep<File>> = async (
|
|
28
|
+
playground,
|
|
29
|
+
{ pluginZipFile, options = {} },
|
|
30
|
+
progress?
|
|
31
|
+
) => {
|
|
32
|
+
progress?.tracker.setCaption(
|
|
33
|
+
`Installing the ${zipNameToHumanName(pluginZipFile?.name)} plugin`
|
|
45
34
|
);
|
|
35
|
+
try {
|
|
36
|
+
const activate = 'activate' in options ? options.activate : true;
|
|
46
37
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
38
|
+
// Upload it to WordPress
|
|
39
|
+
const pluginForm = await playground.request({
|
|
40
|
+
url: '/wp-admin/plugin-install.php?tab=upload',
|
|
41
|
+
});
|
|
42
|
+
const pluginFormPage = asDOM(pluginForm);
|
|
43
|
+
const pluginFormData = new FormData(
|
|
44
|
+
pluginFormPage.querySelector('.wp-upload-form')! as HTMLFormElement
|
|
45
|
+
) as any;
|
|
46
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
47
|
+
const { pluginzip, ...postData } = Object.fromEntries(
|
|
48
|
+
pluginFormData.entries()
|
|
49
|
+
);
|
|
53
50
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
.attributes.getNamedItem('href')!.value;
|
|
60
|
-
const activatePluginUrl = new URL(
|
|
61
|
-
activateButtonHref,
|
|
62
|
-
await playground.pathToInternalUrl('/wp-admin/')
|
|
63
|
-
).toString();
|
|
64
|
-
await playground.request({
|
|
65
|
-
url: activatePluginUrl,
|
|
51
|
+
const pluginInstalledResponse = await playground.request({
|
|
52
|
+
url: '/wp-admin/update.php?action=upload-plugin',
|
|
53
|
+
method: 'POST',
|
|
54
|
+
formData: postData,
|
|
55
|
+
files: { pluginzip: pluginZipFile },
|
|
66
56
|
});
|
|
67
|
-
}
|
|
68
57
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
(
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
contents
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
58
|
+
// Activate if needed
|
|
59
|
+
if (activate) {
|
|
60
|
+
const pluginInstalledPage = asDOM(pluginInstalledResponse);
|
|
61
|
+
const activateButtonHref = pluginInstalledPage
|
|
62
|
+
.querySelector('#wpbody-content .button.button-primary')!
|
|
63
|
+
.attributes.getNamedItem('href')!.value;
|
|
64
|
+
const activatePluginUrl = new URL(
|
|
65
|
+
activateButtonHref,
|
|
66
|
+
await playground.pathToInternalUrl('/wp-admin/')
|
|
67
|
+
).toString();
|
|
68
|
+
await playground.request({
|
|
69
|
+
url: activatePluginUrl,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Pair the site editor's nested iframe to the Service Worker.
|
|
75
|
+
*
|
|
76
|
+
* Without the patch below, the site editor initiates network requests that
|
|
77
|
+
* aren't routed through the service worker. That's a known browser issue:
|
|
78
|
+
*
|
|
79
|
+
* * https://bugs.chromium.org/p/chromium/issues/detail?id=880768
|
|
80
|
+
* * https://bugzilla.mozilla.org/show_bug.cgi?id=1293277
|
|
81
|
+
* * https://github.com/w3c/ServiceWorker/issues/765
|
|
82
|
+
*
|
|
83
|
+
* The problem with iframes using srcDoc and src="about:blank" as they
|
|
84
|
+
* fail to inherit the root site's service worker.
|
|
85
|
+
*
|
|
86
|
+
* Gutenberg loads the site editor using <iframe srcDoc="<!doctype html">
|
|
87
|
+
* to force the standards mode and not the quirks mode:
|
|
88
|
+
*
|
|
89
|
+
* https://github.com/WordPress/gutenberg/pull/38855
|
|
90
|
+
*
|
|
91
|
+
* This commit patches the site editor to achieve the same result via
|
|
92
|
+
* <iframe src="/doctype.html"> and a doctype.html file containing just
|
|
93
|
+
* `<!doctype html>`. This allows the iframe to inherit the service worker
|
|
94
|
+
* and correctly load all the css, js, fonts, images, and other assets.
|
|
95
|
+
*
|
|
96
|
+
* Ideally this issue would be fixed directly in Gutenberg and the patch
|
|
97
|
+
* below would be removed.
|
|
98
|
+
*
|
|
99
|
+
* See https://github.com/WordPress/wordpress-playground/issues/42 for more details
|
|
100
|
+
*/
|
|
101
|
+
if (
|
|
102
|
+
(await playground.isDir(
|
|
103
|
+
'/wordpress/wp-content/plugins/gutenberg'
|
|
104
|
+
)) &&
|
|
105
|
+
!(await playground.fileExists('/wordpress/.gutenberg-patched'))
|
|
106
|
+
) {
|
|
107
|
+
await playground.writeFile('/wordpress/.gutenberg-patched', '1');
|
|
108
|
+
await updateFile(
|
|
109
|
+
playground,
|
|
110
|
+
`/wordpress/wp-content/plugins/gutenberg/build/block-editor/index.js`,
|
|
111
|
+
(contents) =>
|
|
112
|
+
contents.replace(
|
|
113
|
+
/srcDoc:("[^"]+"|[^,]+)/g,
|
|
114
|
+
'src:"/wp-includes/empty.html"'
|
|
115
|
+
)
|
|
116
|
+
);
|
|
117
|
+
await updateFile(
|
|
118
|
+
playground,
|
|
119
|
+
`/wordpress/wp-content/plugins/gutenberg/build/block-editor/index.min.js`,
|
|
120
|
+
(contents) =>
|
|
121
|
+
contents.replace(
|
|
122
|
+
/srcDoc:("[^"]+"|[^,]+)/g,
|
|
123
|
+
'src:"/wp-includes/empty.html"'
|
|
124
|
+
)
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
} catch (error) {
|
|
128
|
+
console.error(
|
|
129
|
+
`Proceeding without the ${pluginZipFile.name} theme. Could not install it in wp-admin. ` +
|
|
130
|
+
`The original error was: ${error}`
|
|
126
131
|
);
|
|
132
|
+
console.error(error);
|
|
127
133
|
}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
async function updateFile(
|
|
137
|
+
playground: UniversalPHP,
|
|
138
|
+
path: string,
|
|
139
|
+
callback: (contents: string) => string
|
|
140
|
+
) {
|
|
141
|
+
return await playground.writeFile(
|
|
142
|
+
path,
|
|
143
|
+
callback(await playground.readFileAsText(path))
|
|
144
|
+
);
|
|
128
145
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { asDOM } from './common';
|
|
1
|
+
import { StepHandler } from '.';
|
|
2
|
+
import { asDOM, zipNameToHumanName } from './common';
|
|
4
3
|
|
|
5
|
-
export interface InstallThemeStep<ResourceType>
|
|
4
|
+
export interface InstallThemeStep<ResourceType> {
|
|
6
5
|
step: 'installTheme';
|
|
7
6
|
themeZipFile: ResourceType;
|
|
8
7
|
options?: InstallThemeOptions;
|
|
@@ -24,66 +23,77 @@ export interface InstallThemeOptions {
|
|
|
24
23
|
* @param themeZipFile The theme zip file.
|
|
25
24
|
* @param options Optional. Set `activate` to false if you don't want to activate the theme.
|
|
26
25
|
*/
|
|
27
|
-
export async
|
|
28
|
-
playground
|
|
29
|
-
themeZipFile
|
|
30
|
-
|
|
31
|
-
) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
// Upload it to WordPress
|
|
35
|
-
const themeForm = await playground.request({
|
|
36
|
-
url: '/wp-admin/theme-install.php',
|
|
37
|
-
});
|
|
38
|
-
const themeFormPage = asDOM(themeForm);
|
|
39
|
-
const themeFormData = new FormData(
|
|
40
|
-
themeFormPage.querySelector('.wp-upload-form')! as HTMLFormElement
|
|
41
|
-
) as any;
|
|
42
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
43
|
-
const { themezip, ...postData } = Object.fromEntries(
|
|
44
|
-
themeFormData.entries()
|
|
26
|
+
export const installTheme: StepHandler<InstallThemeStep<File>> = async (
|
|
27
|
+
playground,
|
|
28
|
+
{ themeZipFile, options = {} },
|
|
29
|
+
progress
|
|
30
|
+
) => {
|
|
31
|
+
progress?.tracker.setCaption(
|
|
32
|
+
`Installing the ${zipNameToHumanName(themeZipFile.name)} theme`
|
|
45
33
|
);
|
|
34
|
+
try {
|
|
35
|
+
const activate = 'activate' in options ? options.activate : true;
|
|
46
36
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
37
|
+
// Upload it to WordPress
|
|
38
|
+
const themeForm = await playground.request({
|
|
39
|
+
url: '/wp-admin/theme-install.php',
|
|
40
|
+
});
|
|
41
|
+
const themeFormPage = asDOM(themeForm);
|
|
42
|
+
const themeFormData = new FormData(
|
|
43
|
+
themeFormPage.querySelector('.wp-upload-form')! as HTMLFormElement
|
|
44
|
+
) as any;
|
|
45
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
46
|
+
const { themezip, ...postData } = Object.fromEntries(
|
|
47
|
+
themeFormData.entries()
|
|
48
|
+
);
|
|
53
49
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
50
|
+
const themeInstalledResponse = await playground.request({
|
|
51
|
+
url: '/wp-admin/update.php?action=upload-theme',
|
|
52
|
+
method: 'POST',
|
|
53
|
+
formData: postData,
|
|
54
|
+
files: { themezip: themeZipFile },
|
|
55
|
+
});
|
|
57
56
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if (
|
|
62
|
-
messageContainer?.textContent?.includes(
|
|
63
|
-
'Theme installation failed.'
|
|
64
|
-
)
|
|
65
|
-
) {
|
|
66
|
-
console.error(messageContainer?.textContent);
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
57
|
+
// Activate if needed
|
|
58
|
+
if (activate) {
|
|
59
|
+
const themeInstalledPage = asDOM(themeInstalledResponse);
|
|
69
60
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
61
|
+
const messageContainer = themeInstalledPage.querySelector(
|
|
62
|
+
'#wpbody-content > .wrap'
|
|
63
|
+
);
|
|
64
|
+
if (
|
|
65
|
+
messageContainer?.textContent?.includes(
|
|
66
|
+
'Theme installation failed.'
|
|
67
|
+
)
|
|
68
|
+
) {
|
|
69
|
+
console.error(messageContainer?.textContent);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
78
72
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
73
|
+
const activateButton = themeInstalledPage.querySelector(
|
|
74
|
+
'#wpbody-content .activatelink, ' +
|
|
75
|
+
'.update-from-upload-actions .button.button-primary'
|
|
76
|
+
);
|
|
77
|
+
if (!activateButton) {
|
|
78
|
+
console.error('The "activate" button was not found.');
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const activateButtonHref =
|
|
83
|
+
activateButton.attributes.getNamedItem('href')!.value;
|
|
84
|
+
const activateThemeUrl = new URL(
|
|
85
|
+
activateButtonHref,
|
|
86
|
+
await playground.pathToInternalUrl('/wp-admin/')
|
|
87
|
+
).toString();
|
|
88
|
+
await playground.request({
|
|
89
|
+
url: activateThemeUrl,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
} catch (error) {
|
|
93
|
+
console.error(
|
|
94
|
+
`Proceeding without the ${themeZipFile.name} theme. Could not install it in wp-admin. ` +
|
|
95
|
+
`The original error was: ${error}`
|
|
96
|
+
);
|
|
97
|
+
console.error(error);
|
|
88
98
|
}
|
|
89
|
-
}
|
|
99
|
+
};
|