@wp-playground/blueprints 0.1.39 → 0.1.42

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.
Files changed (49) hide show
  1. package/index.cjs +133 -0
  2. package/index.d.ts +7 -0
  3. package/index.js +2081 -0
  4. package/lib/blueprint.d.ts +27 -0
  5. package/lib/compile.d.ts +37 -0
  6. package/lib/resources.d.ts +211 -0
  7. package/lib/steps/activate-plugin.d.ts +12 -0
  8. package/lib/steps/apply-wordpress-patches/index.d.ts +12 -0
  9. package/lib/steps/client-methods.d.ts +56 -0
  10. package/lib/steps/common.d.ts +7 -0
  11. package/lib/steps/define-site-url.d.ts +12 -0
  12. package/lib/steps/define-wp-config-consts.d.ts +12 -0
  13. package/{src/lib/steps/handlers.ts → lib/steps/handlers.d.ts} +2 -12
  14. package/lib/steps/import-export.d.ts +67 -0
  15. package/lib/steps/index.d.ts +26 -0
  16. package/lib/steps/install-plugin.d.ts +22 -0
  17. package/lib/steps/install-theme.d.ts +22 -0
  18. package/lib/steps/login.d.ts +16 -0
  19. package/lib/steps/migration.d.ts +2 -0
  20. package/lib/steps/run-wp-installation-wizard.d.ts +16 -0
  21. package/lib/steps/site-data.d.ts +12 -0
  22. package/package.json +4 -3
  23. package/.eslintrc.json +0 -18
  24. package/LICENSE +0 -339
  25. package/README.md +0 -11
  26. package/project.json +0 -49
  27. package/src/index.ts +0 -31
  28. package/src/lib/blueprint.ts +0 -28
  29. package/src/lib/compile.spec.ts +0 -34
  30. package/src/lib/compile.ts +0 -262
  31. package/src/lib/resources.ts +0 -417
  32. package/src/lib/steps/activate-plugin.ts +0 -35
  33. package/src/lib/steps/apply-wordpress-patches/index.ts +0 -113
  34. package/src/lib/steps/apply-wordpress-patches/wp-content/mu-plugins/1-show-admin-credentials-on-wp-login.php +0 -15
  35. package/src/lib/steps/client-methods.ts +0 -121
  36. package/src/lib/steps/common.ts +0 -26
  37. package/src/lib/steps/define-site-url.ts +0 -33
  38. package/src/lib/steps/import-export.ts +0 -225
  39. package/src/lib/steps/index.ts +0 -65
  40. package/src/lib/steps/install-plugin.ts +0 -145
  41. package/src/lib/steps/install-theme.ts +0 -99
  42. package/src/lib/steps/login.ts +0 -37
  43. package/src/lib/steps/migration.php +0 -62
  44. package/src/lib/steps/run-wp-installation-wizard.ts +0 -38
  45. package/src/lib/steps/site-data.ts +0 -58
  46. package/tsconfig.json +0 -23
  47. package/tsconfig.lib.json +0 -10
  48. package/tsconfig.spec.json +0 -19
  49. package/vite.config.ts +0 -58
@@ -1,113 +0,0 @@
1
- import { UniversalPHP } from '@php-wasm/universal';
2
- import { StepHandler } from '..';
3
- import { updateFile } from '../common';
4
-
5
- export interface ApplyWordPressPatchesStep {
6
- step: 'applyWordPressPatches';
7
- siteUrl: string;
8
- wordpressPath?: string;
9
- patchSqlitePlugin?: boolean;
10
- addPhpInfo?: boolean;
11
- patchSiteUrl?: boolean;
12
- disableSiteHealth?: boolean;
13
- disableWpNewBlogNotification?: boolean;
14
- }
15
-
16
- export const applyWordPressPatches: StepHandler<
17
- ApplyWordPressPatchesStep
18
- > = async (php, options) => {
19
- const patch = new WordPressPatcher(
20
- php,
21
- options.siteUrl,
22
- options.wordpressPath || '/wordpress'
23
- );
24
-
25
- if (options.patchSqlitePlugin !== false) {
26
- await patch.patchSqlitePlugin();
27
- }
28
- if (options.addPhpInfo !== false) {
29
- await patch.addPhpInfo();
30
- }
31
- if (options.patchSiteUrl !== false) {
32
- await patch.patchSiteUrl();
33
- }
34
- if (options.disableSiteHealth !== false) {
35
- await patch.disableSiteHealth();
36
- }
37
- if (options.disableWpNewBlogNotification !== false) {
38
- await patch.disableWpNewBlogNotification();
39
- }
40
- };
41
-
42
- class WordPressPatcher {
43
- php: UniversalPHP;
44
- scopedSiteUrl: string;
45
- wordpressPath: string;
46
-
47
- constructor(
48
- php: UniversalPHP,
49
- scopedSiteUrl: string,
50
- wordpressPath: string
51
- ) {
52
- this.php = php;
53
- this.scopedSiteUrl = scopedSiteUrl;
54
- this.wordpressPath = wordpressPath;
55
- }
56
-
57
- async patchSqlitePlugin() {
58
- // Upstream change proposed in https://github.com/WordPress/sqlite-database-integration/pull/28:
59
- await updateFile(
60
- this.php,
61
- `${this.wordpressPath}/wp-content/plugins/sqlite-database-integration/wp-includes/sqlite/class-wp-sqlite-translator.php`,
62
- (contents) => {
63
- return contents.replace(
64
- 'if ( false === strtotime( $value ) )',
65
- 'if ( $value === "0000-00-00 00:00:00" || false === strtotime( $value ) )'
66
- );
67
- }
68
- );
69
- }
70
-
71
- async addPhpInfo() {
72
- await this.php.writeFile(
73
- `${this.wordpressPath}/phpinfo.php`,
74
- '<?php phpinfo(); '
75
- );
76
- }
77
-
78
- async patchSiteUrl() {
79
- await updateFile(
80
- this.php,
81
- `${this.wordpressPath}/wp-config.php`,
82
- (contents) =>
83
- `<?php
84
- if(!defined('WP_HOME')) {
85
- define('WP_HOME', "${this.scopedSiteUrl}");
86
- define('WP_SITEURL', "${this.scopedSiteUrl}");
87
- }
88
- ?>${contents}`
89
- );
90
- }
91
-
92
- async disableSiteHealth() {
93
- await updateFile(
94
- this.php,
95
- `${this.wordpressPath}/wp-includes/default-filters.php`,
96
- (contents) =>
97
- contents.replace(
98
- /add_filter[^;]+wp_maybe_grant_site_health_caps[^;]+;/i,
99
- ''
100
- )
101
- );
102
- }
103
-
104
- async disableWpNewBlogNotification() {
105
- await updateFile(
106
- this.php,
107
- `${this.wordpressPath}/wp-config.php`,
108
- // The original version of this function crashes WASM PHP, let's define an empty one instead.
109
- (contents) =>
110
- `${contents} function wp_new_blog_notification(...$args){} `
111
- );
112
- }
113
- }
@@ -1,15 +0,0 @@
1
- <?php
2
- /**
3
- * Add a notice to wp-login.php offering the username and password.
4
- */
5
-
6
- add_action(
7
- 'login_message',
8
- function() {
9
- return <<<EOT
10
- <div class="message info">
11
- <strong>username:</strong> <code>admin</code><br /><strong>password</strong>: <code>password</code>
12
- </div>
13
- EOT;
14
- }
15
- );
@@ -1,121 +0,0 @@
1
- import { PHPRunOptions, PHPRequest } from '@php-wasm/universal';
2
- import { StepHandler } from '.';
3
- import { fileToUint8Array } from './common';
4
-
5
- export interface RunPHPStep {
6
- step: 'runPHP';
7
- code: string;
8
- }
9
-
10
- export const runPHP: StepHandler<RunPHPStep> = async (playground, { code }) => {
11
- return await playground.run({ code });
12
- };
13
-
14
- export interface RunPHPWithOptionsStep {
15
- step: 'runPHPWithOptions';
16
- options: PHPRunOptions;
17
- }
18
-
19
- export const runPHPWithOptions: StepHandler<RunPHPWithOptionsStep> = async (
20
- playground,
21
- { options }
22
- ) => {
23
- return await playground.run(options);
24
- };
25
-
26
- export interface SetPhpIniEntryStep {
27
- step: 'setPhpIniEntry';
28
- key: string;
29
- value: string;
30
- }
31
-
32
- export const setPhpIniEntry: StepHandler<SetPhpIniEntryStep> = async (
33
- playground,
34
- { key, value }
35
- ) => {
36
- await playground.setPhpIniEntry(key, value);
37
- };
38
-
39
- export interface RequestStep {
40
- step: 'request';
41
- request: PHPRequest;
42
- }
43
-
44
- export const request: StepHandler<RequestStep> = async (
45
- playground,
46
- { request }
47
- ) => {
48
- return await playground.request(request);
49
- };
50
-
51
- export interface CpStep {
52
- step: 'cp';
53
- fromPath: string;
54
- toPath: string;
55
- }
56
-
57
- export const cp: StepHandler<CpStep> = async (
58
- playground,
59
- { fromPath, toPath }
60
- ) => {
61
- await playground.writeFile(
62
- toPath,
63
- await playground.readFileAsBuffer(fromPath)
64
- );
65
- };
66
-
67
- export interface MvStep {
68
- step: 'mv';
69
- fromPath: string;
70
- toPath: string;
71
- }
72
-
73
- export const mv: StepHandler<MvStep> = async (
74
- playground,
75
- { fromPath, toPath }
76
- ) => {
77
- await playground.mv(fromPath, toPath);
78
- };
79
-
80
- export interface MkdirStep {
81
- step: 'mkdir';
82
- path: string;
83
- }
84
-
85
- export const mkdir: StepHandler<MkdirStep> = async (playground, { path }) => {
86
- await playground.mkdir(path);
87
- };
88
-
89
- export interface RmStep {
90
- step: 'rm';
91
- path: string;
92
- }
93
-
94
- export const rm: StepHandler<RmStep> = async (playground, { path }) => {
95
- await playground.unlink(path);
96
- };
97
-
98
- export interface RmdirStep {
99
- step: 'rmdir';
100
- path: string;
101
- }
102
-
103
- export const rmdir: StepHandler<RmdirStep> = async (playground, { path }) => {
104
- await playground.rmdir(path);
105
- };
106
-
107
- export interface WriteFileStep<ResourceType> {
108
- step: 'writeFile';
109
- path: string;
110
- data: ResourceType | string | Uint8Array;
111
- }
112
-
113
- export const writeFile: StepHandler<WriteFileStep<File>> = async (
114
- playground,
115
- { path, data }
116
- ) => {
117
- if (data instanceof File) {
118
- data = await fileToUint8Array(data);
119
- }
120
- await playground.writeFile(path, data);
121
- };
@@ -1,26 +0,0 @@
1
- import type { PHPResponse, UniversalPHP } from '@php-wasm/universal';
2
-
3
- export function asDOM(response: PHPResponse) {
4
- return new DOMParser().parseFromString(response.text, 'text/html')!;
5
- }
6
-
7
- export function zipNameToHumanName(zipName: string) {
8
- const mixedCaseName = zipName.split('.').shift()!.replace('-', ' ');
9
- return (
10
- mixedCaseName.charAt(0).toUpperCase() +
11
- mixedCaseName.slice(1).toLowerCase()
12
- );
13
- }
14
-
15
- type PatchFileCallback = (contents: string) => string | Uint8Array;
16
- export async function updateFile(
17
- php: UniversalPHP,
18
- path: string,
19
- callback: PatchFileCallback
20
- ) {
21
- await php.writeFile(path, callback(await php.readFileAsText(path)));
22
- }
23
-
24
- export async function fileToUint8Array(file: File) {
25
- return new Uint8Array(await file.arrayBuffer());
26
- }
@@ -1,33 +0,0 @@
1
- import { StepHandler } from '.';
2
- import { updateFile } from './common';
3
-
4
- export interface DefineSiteUrlStep {
5
- step: 'defineSiteUrl';
6
- siteUrl: string;
7
- }
8
-
9
- /**
10
- * Sets site URL of the WordPress installation.
11
- *
12
- * @param playground The playground client.
13
- * @param siteUrl
14
- */
15
- export const defineSiteUrl: StepHandler<DefineSiteUrlStep> = async (
16
- playground,
17
- { siteUrl }
18
- ) => {
19
- const documentRoot = await playground.documentRoot;
20
- await updateFile(
21
- playground,
22
- `${documentRoot}/wp-config.php`,
23
- (contents) =>
24
- `<?php
25
- if ( ! defined( 'WP_HOME' ) ) {
26
- define('WP_HOME', "${siteUrl}");
27
- }
28
- if ( ! defined( 'WP_SITEURL' ) ) {
29
- define('WP_SITEURL', "${siteUrl}");
30
- }
31
- ?>${contents}`
32
- );
33
- };
@@ -1,225 +0,0 @@
1
- import { PHPResponse, UniversalPHP } from '@php-wasm/universal';
2
- import { phpVars } from '@php-wasm/util';
3
- import { StepHandler } from '.';
4
-
5
- // @ts-ignore
6
- import migrationsPHPCode from './migration.php?raw';
7
-
8
- /**
9
- * Full site export support:
10
- */
11
-
12
- /**
13
- * Export the current site as a zip file.
14
- *
15
- * @param playground Playground client.
16
- */
17
- export async function zipEntireSite(playground: UniversalPHP) {
18
- const zipName = `wordpress-playground.zip`;
19
- const zipPath = `/${zipName}`;
20
-
21
- const js = phpVars({
22
- zipPath,
23
- documentRoot: await playground.documentRoot,
24
- });
25
- await phpMigration(
26
- playground,
27
- `zipDir(${js.documentRoot}, ${js.zipPath});`
28
- );
29
-
30
- const fileBuffer = await playground.readFileAsBuffer(zipPath);
31
- playground.unlink(zipPath);
32
-
33
- return new File([fileBuffer], zipName);
34
- }
35
-
36
- export interface ReplaceSiteStep<ResourceType> {
37
- step: 'replaceSite';
38
- fullSiteZip: ResourceType;
39
- }
40
-
41
- /**
42
- * Replace the current site with the contents of a full site zip file.
43
- *
44
- * @param playground Playground client.
45
- * @param fullSiteZip Zipped WordPress site.
46
- */
47
- export const replaceSite: StepHandler<ReplaceSiteStep<File>> = async (
48
- playground,
49
- { fullSiteZip }
50
- ) => {
51
- const zipPath = '/import.zip';
52
- await playground.writeFile(
53
- zipPath,
54
- new Uint8Array(await fullSiteZip.arrayBuffer())
55
- );
56
-
57
- const absoluteUrl = await playground.absoluteUrl;
58
- const documentRoot = await playground.documentRoot;
59
-
60
- await playground.rmdir(documentRoot);
61
- await unzip(playground, { zipPath, extractToPath: '/' });
62
-
63
- const js = phpVars({ absoluteUrl });
64
- await updateFile(
65
- playground,
66
- `${documentRoot}/wp-config.php`,
67
- (contents) =>
68
- `<?php
69
- if(!defined('WP_HOME')) {
70
- define('WP_HOME', ${js.absoluteUrl});
71
- define('WP_SITEURL', ${js.absoluteUrl});
72
- }
73
- ?>${contents}`
74
- );
75
- };
76
-
77
- export interface UnzipStep {
78
- step: 'unzip';
79
- zipPath: string;
80
- extractToPath: string;
81
- }
82
-
83
- /**
84
- * Unzip a zip file.
85
- *
86
- * @param playground Playground client.
87
- * @param zipPath The zip file to unzip.
88
- * @param extractTo The directory to extract the zip file to.
89
- */
90
- export const unzip: StepHandler<UnzipStep> = async (
91
- playground,
92
- { zipPath, extractToPath }
93
- ) => {
94
- const js = phpVars({
95
- zipPath,
96
- extractToPath,
97
- });
98
- await phpMigration(
99
- playground,
100
- `unzip(${js.zipPath}, ${js.extractToPath});`
101
- );
102
- };
103
-
104
- /**
105
- * WXR and WXZ files support:
106
- */
107
-
108
- /**
109
- * Exports the WordPress database as a WXR file using
110
- * the core WordPress export tool.
111
- *
112
- * @param playground Playground client
113
- * @returns WXR file
114
- */
115
- export async function exportWXR(playground: UniversalPHP) {
116
- const databaseExportResponse = await playground.request({
117
- url: '/wp-admin/export.php?download=true&content=all',
118
- });
119
- return new File([databaseExportResponse.bytes], 'export.xml');
120
- }
121
-
122
- /**
123
- * Exports the WordPress database as a WXZ file using
124
- * the export-wxz plugin from https://github.com/akirk/export-wxz.
125
- *
126
- * @param playground Playground client
127
- * @returns WXZ file
128
- */
129
- export async function exportWXZ(playground: UniversalPHP) {
130
- const databaseExportResponse = await playground.request({
131
- url: '/wp-admin/export.php?download=true&content=all&export_wxz=1',
132
- });
133
- return new File([databaseExportResponse.bytes], 'export.wxz');
134
- }
135
-
136
- export interface ImportFileStep<ResourceType> {
137
- step: 'importFile';
138
- file: ResourceType;
139
- }
140
-
141
- /**
142
- * Uploads a file to the WordPress importer and returns the response.
143
- * Supports both WXR and WXZ files.
144
- *
145
- * @see https://github.com/WordPress/wordpress-importer/compare/master...akirk:wordpress-importer:import-wxz.patch
146
- * @param playground Playground client.
147
- * @param file The file to import.
148
- */
149
- export const importFile: StepHandler<ImportFileStep<File>> = async (
150
- playground,
151
- { file }
152
- ) => {
153
- const importerPageOneResponse = await playground.request({
154
- url: '/wp-admin/admin.php?import=wordpress',
155
- });
156
-
157
- const firstUrlAction = DOM(importerPageOneResponse)
158
- .getElementById('import-upload-form')
159
- ?.getAttribute('action');
160
-
161
- const stepOneResponse = await playground.request({
162
- url: `/wp-admin/${firstUrlAction}`,
163
- method: 'POST',
164
- files: { import: file },
165
- });
166
-
167
- // Map authors of imported posts to existing users
168
- const importForm = DOM(stepOneResponse).querySelector(
169
- '#wpbody-content form'
170
- ) as HTMLFormElement;
171
-
172
- if (!importForm) {
173
- console.log(stepOneResponse.text);
174
- throw new Error(
175
- 'Could not find an importer form in response. See the response text above for details.'
176
- );
177
- }
178
-
179
- const data = getFormData(importForm);
180
- data['fetch_attachments'] = '1';
181
- for (const key in data) {
182
- if (key.startsWith('user_map[')) {
183
- const newKey = 'user_new[' + key.slice(9, -1) + ']';
184
- data[newKey] = '1'; // Hardcoded admin ID for now
185
- }
186
- }
187
-
188
- await playground.request({
189
- url: importForm.action,
190
- method: 'POST',
191
- formData: data,
192
- });
193
- };
194
-
195
- function DOM(response: PHPResponse) {
196
- return new DOMParser().parseFromString(response.text, 'text/html');
197
- }
198
-
199
- function getFormData(form: HTMLFormElement): Record<string, unknown> {
200
- return Object.fromEntries((new FormData(form) as any).entries());
201
- }
202
-
203
- async function updateFile(
204
- playground: UniversalPHP,
205
- path: string,
206
- callback: (contents: string) => string
207
- ) {
208
- await playground.writeFile(
209
- path,
210
- callback(await playground.readFileAsText(path))
211
- );
212
- }
213
-
214
- async function phpMigration(playground: UniversalPHP, code: string) {
215
- const result = await playground.run({
216
- code: migrationsPHPCode + code,
217
- });
218
- if (result.exitCode !== 0) {
219
- console.log(migrationsPHPCode + code);
220
- console.log(code + '');
221
- console.log(result.errors);
222
- throw result.errors;
223
- }
224
- return result;
225
- }
@@ -1,65 +0,0 @@
1
- import { ProgressTracker } from '@php-wasm/progress';
2
- import { UniversalPHP } from '@php-wasm/universal';
3
- import { FileReference } from '../resources';
4
- import { ActivatePluginStep } from './activate-plugin';
5
- import { ApplyWordPressPatchesStep } from './apply-wordpress-patches';
6
- import { DefineSiteUrlStep } from './define-site-url';
7
- import { ImportFileStep, ReplaceSiteStep, UnzipStep } from './import-export';
8
- import { InstallPluginStep } from './install-plugin';
9
- import { InstallThemeStep } from './install-theme';
10
- import { LoginStep } from './login';
11
- import { RunWpInstallationWizardStep } from './run-wp-installation-wizard';
12
- import { SetSiteOptionsStep, UpdateUserMetaStep } from './site-data';
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 & {
28
- progress?: {
29
- weight?: number;
30
- caption?: string;
31
- };
32
- };
33
-
34
- export type GenericStep<Resource> =
35
- | ActivatePluginStep
36
- | ApplyWordPressPatchesStep
37
- | CpStep
38
- | DefineSiteUrlStep
39
- | ImportFileStep<Resource>
40
- | InstallPluginStep<Resource>
41
- | InstallThemeStep<Resource>
42
- | LoginStep
43
- | MkdirStep
44
- | MvStep
45
- | RequestStep
46
- | ReplaceSiteStep<Resource>
47
- | RmStep
48
- | RmdirStep
49
- | RunPHPStep
50
- | RunPHPWithOptionsStep
51
- | RunWpInstallationWizardStep
52
- | SetPhpIniEntryStep
53
- | SetSiteOptionsStep
54
- | UnzipStep
55
- | UpdateUserMetaStep
56
- | WriteFileStep<Resource>;
57
-
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;