@wp-playground/blueprints 0.1.40 → 0.1.43

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 (51) hide show
  1. package/index.cjs +140 -0
  2. package/index.d.ts +7 -0
  3. package/index.js +2106 -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 +9 -0
  11. package/lib/steps/define-site-url.d.ts +12 -0
  12. package/lib/steps/define-virtual-wp-config-consts.d.ts +19 -0
  13. package/lib/steps/define-wp-config-consts.d.ts +16 -0
  14. package/{src/lib/steps/handlers.ts → lib/steps/handlers.d.ts} +2 -12
  15. package/lib/steps/import-export.d.ts +67 -0
  16. package/lib/steps/index.d.ts +28 -0
  17. package/lib/steps/install-plugin.d.ts +46 -0
  18. package/lib/steps/install-theme.d.ts +22 -0
  19. package/lib/steps/login.d.ts +16 -0
  20. package/lib/steps/migration.d.ts +2 -0
  21. package/lib/steps/run-wp-installation-wizard.d.ts +16 -0
  22. package/lib/steps/site-data.d.ts +12 -0
  23. package/package.json +4 -3
  24. package/.eslintrc.json +0 -18
  25. package/LICENSE +0 -339
  26. package/README.md +0 -11
  27. package/project.json +0 -58
  28. package/src/index.ts +0 -31
  29. package/src/lib/blueprint.ts +0 -28
  30. package/src/lib/compile.spec.ts +0 -34
  31. package/src/lib/compile.ts +0 -262
  32. package/src/lib/resources.ts +0 -417
  33. package/src/lib/steps/activate-plugin.ts +0 -35
  34. package/src/lib/steps/apply-wordpress-patches/index.ts +0 -113
  35. package/src/lib/steps/apply-wordpress-patches/wp-content/mu-plugins/1-show-admin-credentials-on-wp-login.php +0 -15
  36. package/src/lib/steps/client-methods.ts +0 -121
  37. package/src/lib/steps/common.ts +0 -30
  38. package/src/lib/steps/define-site-url.ts +0 -25
  39. package/src/lib/steps/define-wp-config-consts.ts +0 -45
  40. package/src/lib/steps/import-export.ts +0 -225
  41. package/src/lib/steps/index.ts +0 -67
  42. package/src/lib/steps/install-plugin.ts +0 -145
  43. package/src/lib/steps/install-theme.ts +0 -99
  44. package/src/lib/steps/login.ts +0 -37
  45. package/src/lib/steps/migration.ts +0 -63
  46. package/src/lib/steps/run-wp-installation-wizard.ts +0 -38
  47. package/src/lib/steps/site-data.ts +0 -58
  48. package/tsconfig.json +0 -23
  49. package/tsconfig.lib.json +0 -10
  50. package/tsconfig.spec.json +0 -19
  51. package/vite.config.ts +0 -58
@@ -1,145 +0,0 @@
1
- import { UniversalPHP } from '@php-wasm/universal';
2
- import { StepHandler } from '.';
3
- import { asDOM, zipNameToHumanName } from './common';
4
-
5
- export interface InstallPluginStep<ResourceType> {
6
- step: 'installPlugin';
7
- pluginZipFile: ResourceType;
8
- options?: InstallPluginOptions;
9
- }
10
-
11
- export interface InstallPluginOptions {
12
- /**
13
- * Whether to activate the plugin after installing it.
14
- */
15
- activate?: boolean;
16
- }
17
-
18
- /**
19
- * Installs a WordPress plugin in the Playground.
20
- * Technically, it uses the same plugin upload form as a WordPress user
21
- * would, and then activates the plugin if needed.
22
- *
23
- * @param playground The playground client.
24
- * @param pluginZipFile The plugin zip file.
25
- * @param options Optional. Set `activate` to false if you don't want to activate the plugin.
26
- */
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`
34
- );
35
- try {
36
- const activate = 'activate' in options ? options.activate : true;
37
-
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
- );
50
-
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 },
56
- });
57
-
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}`
131
- );
132
- console.error(error);
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
- );
145
- }
@@ -1,99 +0,0 @@
1
- import { StepHandler } from '.';
2
- import { asDOM, zipNameToHumanName } from './common';
3
-
4
- export interface InstallThemeStep<ResourceType> {
5
- step: 'installTheme';
6
- themeZipFile: ResourceType;
7
- options?: InstallThemeOptions;
8
- }
9
-
10
- export interface InstallThemeOptions {
11
- /**
12
- * Whether to activate the theme after installing it.
13
- */
14
- activate?: boolean;
15
- }
16
-
17
- /**
18
- * Installs a WordPress theme in the Playground.
19
- * Technically, it uses the same theme upload form as a WordPress user
20
- * would, and then activates the theme if needed.
21
- *
22
- * @param playground The playground client.
23
- * @param themeZipFile The theme zip file.
24
- * @param options Optional. Set `activate` to false if you don't want to activate the theme.
25
- */
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`
33
- );
34
- try {
35
- const activate = 'activate' in options ? options.activate : true;
36
-
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
- );
49
-
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
- });
56
-
57
- // Activate if needed
58
- if (activate) {
59
- const themeInstalledPage = asDOM(themeInstalledResponse);
60
-
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
- }
72
-
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);
98
- }
99
- };
@@ -1,37 +0,0 @@
1
- import { StepHandler } from '.';
2
-
3
- export type LoginStep = {
4
- step: 'login';
5
- username?: string;
6
- password?: string;
7
- };
8
-
9
- /**
10
- * Logs in to the Playground.
11
- * Under the hood, this function submits the wp-login.php form
12
- * just like a user would.
13
- *
14
- * @param playground The playground client.
15
- * @param user The user to log in as. Defaults to 'admin'.
16
- * @param password The password to log in with. Defaults to 'password'.
17
- */
18
- export const login: StepHandler<LoginStep> = async (
19
- playground,
20
- { username = 'admin', password = 'password' } = {},
21
- progress
22
- ) => {
23
- progress?.tracker.setCaption(progress?.initialCaption || 'Logging in');
24
- await playground.request({
25
- url: '/wp-login.php',
26
- });
27
-
28
- await playground.request({
29
- url: '/wp-login.php',
30
- method: 'POST',
31
- formData: {
32
- log: username,
33
- pwd: password,
34
- rememberme: 'forever',
35
- },
36
- });
37
- };
@@ -1,63 +0,0 @@
1
- export default `<?php
2
-
3
- function zipDir($dir, $output, $additionalFiles = array())
4
- {
5
- $zip = new ZipArchive;
6
- $res = $zip->open($output, ZipArchive::CREATE);
7
- if ($res === TRUE) {
8
- foreach ($additionalFiles as $file) {
9
- $zip->addFile($file);
10
- }
11
- $directories = array(
12
- rtrim($dir, '/') . '/'
13
- );
14
- while (sizeof($directories)) {
15
- $dir = array_pop($directories);
16
-
17
- if ($handle = opendir($dir)) {
18
- while (false !== ($entry = readdir($handle))) {
19
- if ($entry == '.' || $entry == '..') {
20
- continue;
21
- }
22
-
23
- $entry = $dir . $entry;
24
-
25
- if (is_dir($entry)) {
26
- $directory_path = $entry . '/';
27
- array_push($directories, $directory_path);
28
- } else if (is_file($entry)) {
29
- $zip->addFile($entry);
30
- }
31
- }
32
- closedir($handle);
33
- }
34
- }
35
- $zip->close();
36
- chmod($output, 0777);
37
- }
38
- }
39
-
40
- function unzip($zipPath, $extractTo, $overwrite = true)
41
- {
42
- if(!is_dir($extractTo)) {
43
- mkdir($extractTo, 0777, true);
44
- }
45
- $zip = new ZipArchive;
46
- $res = $zip->open($zipPath);
47
- if ($res === TRUE) {
48
- $zip->extractTo($extractTo);
49
- $zip->close();
50
- chmod($extractTo, 0777);
51
- }
52
- }
53
-
54
-
55
- function delTree($dir)
56
- {
57
- $files = array_diff(scandir($dir), array('.', '..'));
58
- foreach ($files as $file) {
59
- (is_dir("$dir/$file")) ? delTree("$dir/$file") : unlink("$dir/$file");
60
- }
61
- return rmdir($dir);
62
- }
63
- `;
@@ -1,38 +0,0 @@
1
- import { StepHandler } from '.';
2
-
3
- export interface RunWpInstallationWizardStep {
4
- step: 'runWpInstallationWizard';
5
- options: WordPressInstallationOptions;
6
- }
7
-
8
- export interface WordPressInstallationOptions {
9
- adminUsername?: string;
10
- adminPassword?: string;
11
- }
12
-
13
- /**
14
- * Installs WordPress
15
- *
16
- * @param playground The playground client.
17
- * @param options Installation options.
18
- */
19
- export const runWpInstallationWizard: StepHandler<
20
- RunWpInstallationWizardStep
21
- > = async (playground, { options }) => {
22
- await playground.request({
23
- url: '/wp-admin/install.php?step=2',
24
- method: 'POST',
25
- formData: {
26
- language: 'en',
27
- prefix: 'wp_',
28
- weblog_title: 'My WordPress Website',
29
- user_name: options.adminPassword || 'admin',
30
- admin_password: options.adminPassword || 'password',
31
- // The installation wizard demands typing the same password twice
32
- admin_password2: options.adminPassword || 'password',
33
- Submit: 'Install WordPress',
34
- pw_weak: '1',
35
- admin_email: 'admin@localhost.com',
36
- },
37
- });
38
- };
@@ -1,58 +0,0 @@
1
- import { PHPResponse } from '@php-wasm/universal';
2
- import { phpVar } from '@php-wasm/util';
3
- import { StepHandler } from '.';
4
-
5
- export type SetSiteOptionsStep = {
6
- step: 'setSiteOptions';
7
- options: Record<string, unknown>;
8
- };
9
-
10
- export const setSiteOptions: StepHandler<SetSiteOptionsStep> = async (
11
- client,
12
- { options }
13
- ) => {
14
- const code = `<?php
15
- include 'wordpress/wp-load.php';
16
- $site_options = ${phpVar(options)};
17
- foreach($site_options as $name => $value) {
18
- update_option($name, $value);
19
- }
20
- echo "Success";
21
- `;
22
- const result = await client.run({
23
- code,
24
- });
25
- assertSuccess(result);
26
- return { code, result };
27
- };
28
-
29
- export interface UpdateUserMetaStep {
30
- step: 'updateUserMeta';
31
- meta: Record<string, unknown>;
32
- userId: number;
33
- }
34
- export const updateUserMeta: StepHandler<UpdateUserMetaStep> = async (
35
- client,
36
- { meta, userId }
37
- ) => {
38
- const code = `<?php
39
- include 'wordpress/wp-load.php';
40
- $meta = ${phpVar(meta)};
41
- foreach($meta as $name => $value) {
42
- update_user_meta(${phpVar(userId)}, $name, $value);
43
- }
44
- echo "Success";
45
- `;
46
- const result = await client.run({
47
- code,
48
- });
49
- assertSuccess(result);
50
- return { code, result };
51
- };
52
-
53
- async function assertSuccess(result: PHPResponse) {
54
- if (result.text !== 'Success') {
55
- console.log(result);
56
- throw new Error(`Failed to run code: ${result.text} ${result.errors}`);
57
- }
58
- }
package/tsconfig.json DELETED
@@ -1,23 +0,0 @@
1
- {
2
- "extends": "../../../tsconfig.base.json",
3
- "compilerOptions": {
4
- "module": "ES2022",
5
- "forceConsistentCasingInFileNames": true,
6
- "strict": true,
7
- "noImplicitOverride": true,
8
- "noPropertyAccessFromIndexSignature": true,
9
- "noImplicitReturns": true,
10
- "noFallthroughCasesInSwitch": true,
11
- "types": ["vitest"]
12
- },
13
- "files": [],
14
- "include": [],
15
- "references": [
16
- {
17
- "path": "./tsconfig.lib.json"
18
- },
19
- {
20
- "path": "./tsconfig.spec.json"
21
- }
22
- ]
23
- }
package/tsconfig.lib.json DELETED
@@ -1,10 +0,0 @@
1
- {
2
- "extends": "./tsconfig.json",
3
- "compilerOptions": {
4
- "outDir": "../../../dist/out-tsc",
5
- "declaration": true,
6
- "types": ["node"]
7
- },
8
- "include": ["src/**/*.ts"],
9
- "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"]
10
- }
@@ -1,19 +0,0 @@
1
- {
2
- "extends": "./tsconfig.json",
3
- "compilerOptions": {
4
- "outDir": "../../dist/out-tsc",
5
- "types": ["vitest/globals", "vitest/importMeta", "vite/client", "node"]
6
- },
7
- "include": [
8
- "vite.config.ts",
9
- "src/**/*.test.ts",
10
- "src/**/*.spec.ts",
11
- "src/**/*.test.tsx",
12
- "src/**/*.spec.tsx",
13
- "src/**/*.test.js",
14
- "src/**/*.spec.js",
15
- "src/**/*.test.jsx",
16
- "src/**/*.spec.jsx",
17
- "src/**/*.d.ts"
18
- ]
19
- }
package/vite.config.ts DELETED
@@ -1,58 +0,0 @@
1
- /// <reference types="vitest" />
2
- import { defineConfig } from 'vite';
3
-
4
- import viteTsConfigPaths from 'vite-tsconfig-paths';
5
- import dts from 'vite-plugin-dts';
6
- import { join } from 'path';
7
-
8
- export default defineConfig({
9
- cacheDir: '../../../node_modules/.vite/playground-blueprints',
10
-
11
- plugins: [
12
- dts({
13
- entryRoot: 'src',
14
- tsConfigFilePath: join(__dirname, 'tsconfig.lib.json'),
15
- skipDiagnostics: true,
16
- }),
17
-
18
- viteTsConfigPaths({
19
- root: '../../../',
20
- }),
21
- ],
22
-
23
- // Uncomment this if you are using workers.
24
- // worker: {
25
- // plugins: [
26
- // viteTsConfigPaths({
27
- // root: '../../../',
28
- // }),
29
- // ],
30
- // },
31
-
32
- // Configuration for building your library.
33
- // See: https://vitejs.dev/guide/build.html#library-mode
34
- build: {
35
- lib: {
36
- // Could also be a dictionary or array of multiple entry points.
37
- entry: 'src/index.ts',
38
- name: 'playground-blueprints',
39
- fileName: 'index',
40
- // Change this to the formats you want to support.
41
- // Don't forgot to update your package.json as well.
42
- formats: ['es', 'cjs'],
43
- },
44
- rollupOptions: {
45
- // External packages that should not be bundled into your library.
46
- external: [],
47
- },
48
- },
49
-
50
- test: {
51
- globals: true,
52
- cache: {
53
- dir: '../../../node_modules/.vitest',
54
- },
55
- environment: 'jsdom',
56
- include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
57
- },
58
- });