Skip to content

Commit 0bdb332

Browse files
authored
Browser: Disable the network support by default and add a UI control to enable it (#812)
Disables the network support by default and adds a UI control to enable it. Why? #724 introduced support for wp_safe_remote_get() request and enabled it by default on playground.wordpress.net. The problem is, all the requests block rendering of WordPress pages and noticeably slow down the site. Let's disable it by default for a lightweight user experience, and then add an easy way to enable it, for example in the configuration modal. Closes #755 ## Testing Instructions * Go to http://localhost:5400/website-server/?url=/wp-admin/plugin-install.php * Confirm the plugins aren't loaded and you see a communicative error message * Go to the settings modal * Enable the network support * Confirm the plugins are loaded now <img width="1121" alt="CleanShot 2023-11-27 at 17 10 45@2x" src="https://github.com/WordPress/wordpress-playground/assets/205419/ea95b783-d7a1-45c6-ab95-90b5c8ec6ce4">
1 parent 72d74fe commit 0bdb332

File tree

13 files changed

+175
-86
lines changed

13 files changed

+175
-86
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,14 @@ jobs:
3535
- uses: actions/checkout@v3
3636
- uses: ./.github/actions/prepare-playground
3737
- run: ./node_modules/.bin/cypress install --force
38-
- run: npx nx affected --target=e2e --configuration=ci
38+
- run: npx nx affected --target=e2e --configuration=ci --verbose
3939
build:
4040
runs-on: ubuntu-latest
4141
needs: [lint-and-typecheck]
4242
steps:
4343
- uses: actions/checkout@v3
4444
- uses: ./.github/actions/prepare-playground
45-
- run: npx nx affected --target=build --parallel=3
45+
- run: npx nx affected --target=build --parallel=3 --verbose
4646

4747
# Deploy documentation job
4848
deploy_docs:

packages/docs/site/docs/08-query-api/01-index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ You can go ahead and try it out. The Playground will automatically install the t
2727
| `wp` | `latest` | Loads the specified WordPress version. Supported values: `5.9`, `6.0`, `6.1`, `6.2`, `6.3`, `latest`, `nightly`, `beta` |
2828
| `blueprint-url` | | The URL of the Blueprint that will be used to configure this Playground instance. |
2929
| `php-extension-bundle` | | Loads a bundle of PHP extensions. Supported bundles: `kitchen-sink` (for gd, mbstring, iconv, libxml, xml, dom, simplexml, xmlreader, xmlwriter) |
30-
| `networking` | `yes` or `no` | Enables or disables the networking support for Playground. Defaults to `yes` |
30+
| `networking` | `yes` or `no` | Enables or disables the networking support for Playground. Defaults to `no` |
3131
| `plugin` | | Installs the specified plugin. Use the plugin name from the plugins directory URL, e.g. for a URL like `https://wordpress.org/plugins/wp-lazy-loading/`, the plugin name would be `wp-lazy-loading`. You can pre-install multiple plugins by saying `plugin=coblocks&plugin=wp-lazy-loading&…`. Installing a plugin automatically logs the user in as an admin |
3232
| `theme` | | Installs the specified theme. Use the theme name from the themes directory URL, e.g. for a URL like `https://wordpress.org/themes/disco/`, the theme name would be `disco`. Installing a theme automatically logs the user in as an admin |
3333
| `url` | `/wp-admin/` | Load the specified initial page displaying WordPress |

packages/docs/site/docs/09-blueprints-api/03-data-format.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,4 @@ The `phpExtensionBundles` property is an array of PHP extension bundles to load.
6363

6464
The `features` property is used to enable or disable certain features of the Playground. It can contain the following properties:
6565

66-
- `networking`: Defaults to `true`. Enables or disables the networking support for Playground. If enabled, `wp_safe_remote_get` and similar WordPress functions will actually use `fetch()` to make HTTP requests. If disabled, they will immediately fail instead.
66+
- `networking`: Defaults to `false`. Enables or disables the networking support for Playground. If enabled, `wp_safe_remote_get` and similar WordPress functions will actually use `fetch()` to make HTTP requests. If disabled, they will immediately fail instead.

packages/docs/site/docs/11-architecture/02-wasm-php-overview.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@ When it comes to networking, WebAssembly programs are limited to calling JavaScr
2020

2121
In Node.js, the answer involves a WebSocket to TCP socket proxy, [Asyncify](https://emscripten.org/docs/porting/asyncify.html), and patching deep PHP internals like php_select. It's complex, but there's a reward. The Node.js-targeted PHP build can request web APIs, install composer packages, and even connect to a MySQL server.
2222

23-
In the browser, networking is not supported yet. Initiating a HTTPS connection involves opening a raw TCP socket which is not possible in the browser. There is an [open GitHub issue](https://github.com/WordPress/wordpress-playground/issues/85) that explores possible ways of addressing this problem.
23+
In the browser, networking is supported to a limited extent. Network calls initiated using `wp_safe_remote_get`, like the ones in the plugin directory or the font library, are translated into `fetch()` calls and succeed if the remote server sends the correct CORS headers. However, a full support for arbitrary HTTPS connection involves opening a raw TCP socket which is not possible in the browser. There is an [open GitHub issue](https://github.com/WordPress/wordpress-playground/issues/85) that explores possible ways of addressing this problem.

packages/playground/blueprints/src/lib/compile.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,8 @@ export function compileBlueprint(
167167
blueprint.phpExtensionBundles || []
168168
),
169169
features: {
170-
// Enable networking by default
171-
networking: blueprint.features?.networking ?? true,
170+
// Disable networking by default
171+
networking: blueprint.features?.networking ?? false,
172172
},
173173
run: async (playground: UniversalPHP) => {
174174
try {

packages/playground/blueprints/src/lib/steps/apply-wordpress-patches/wp-content/mu-plugins/2-nice-error-messages-for-plugins-and-themes-directories.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
if($res instanceof WP_Error) {
1313
$res = new WP_Error(
1414
'plugins_api_failed',
15-
'Playground <a href="https://github.com/WordPress/wordpress-playground/issues/85">does not yet support</a> connecting to the plugin directory yet. You can still upload plugins or install them using the <a href="https://wordpress.github.io/wordpress-playground/query-api">Query API</a> (e.g. ?plugin=coblocks).'
15+
'Enable networking support in Playground settings to access the Plugins directory. Network access is an <a href="https://github.com/WordPress/wordpress-playground/issues/85">experimental, opt-in feature</a>. If you don\'t want to use it, you can still upload plugins or install them using the <a href="https://wordpress.github.io/wordpress-playground/query-api">Query API</a> (e.g. ?plugin=coblocks).'
1616
);
1717
}
1818
return $res;
@@ -29,7 +29,7 @@
2929
}
3030

3131
if($translation === 'An unexpected error occurred. Something may be wrong with WordPress.org or this server&#8217;s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.') {
32-
return 'Playground <a href="https://github.com/WordPress/wordpress-playground/issues/85">does not yet support</a> connecting to the themes directory yet. You can still upload a theme or install it using the <a href="https://wordpress.github.io/wordpress-playground/query-api">Query API</a> (e.g. ?theme=pendant).';
32+
return 'Enable networking support in Playground settings to access the Themes directory. Network access is an <a href="https://github.com/WordPress/wordpress-playground/issues/85">experimental, opt-in feature</a>. If you don\'t want to use it, you can still upload themes or install them using the <a href="https://wordpress.github.io/wordpress-playground/query-api">Query API</a> (e.g. ?theme=pendant).';
3333
}
3434
return $translation;
3535
} );

packages/playground/website/cypress/e2e/app.cy.ts

Lines changed: 122 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ describe('Query API', () => {
3333

3434
describe('option `wp`', () => {
3535
it('should load WordPress latest by default', () => {
36-
cy.visit('/?networking=no&url=/wp-admin/');
36+
cy.visit('/?url=/wp-admin/');
3737
const expectedBodyClass =
3838
'branch-' + LatestSupportedWordPressVersion.replace('.', '-');
3939
cy.wordPressDocument()
@@ -42,16 +42,14 @@ describe('Query API', () => {
4242
});
4343

4444
it('should load WordPress 6.3 when requested', () => {
45-
cy.visit('/?networking=no&wp=6.3&url=/wp-admin');
45+
cy.visit('/?wp=6.3&url=/wp-admin');
4646
cy.wordPressDocument().find(`body.branch-6-3`).should('exist');
4747
});
4848
});
4949

5050
describe('option `php-extension-bundle`', () => {
5151
it('should load the specified PHP extensions', () => {
52-
cy.visit(
53-
'/?networking=no&php-extension-bundle=kitchen-sink&url=/phpinfo.php'
54-
);
52+
cy.visit('/?php-extension-bundle=kitchen-sink&url=/phpinfo.php');
5553
cy.wordPressDocument()
5654
.its('body')
5755
.should('contain', '--enable-xmlwriter');
@@ -60,13 +58,10 @@ describe('Query API', () => {
6058

6159
describe('option `networking`', () => {
6260
it('should disable networking when requested', () => {
63-
cy.visit('/?networking=no&url=/wp-admin/plugin-install.php');
61+
cy.visit('/?url=/wp-admin/plugin-install.php');
6462
cy.wordPressDocument()
6563
.find('.notice.error')
66-
.should(
67-
'contain',
68-
'does not yet support connecting to the plugin directory'
69-
);
64+
.should('contain', 'Enable networking support in Playground');
7065
});
7166

7267
it('should enable networking when requested', () => {
@@ -97,7 +92,7 @@ describe('Query API', () => {
9792

9893
describe('option `url`', () => {
9994
it('should load the specified URL', () => {
100-
cy.visit('/?url=/wp-admin/&networking=no');
95+
cy.visit('/?url=/wp-admin/');
10196
cy.wordpressPath().should('contain', '/wp-admin/');
10297
cy.wordPressDocument()
10398
.find('#adminmenu')
@@ -107,11 +102,11 @@ describe('Query API', () => {
107102

108103
describe('option `mode`', () => {
109104
it('lack of mode=seamless should a WordPress in a simulated browser UI', () => {
110-
cy.visit('/?networking=no');
105+
cy.visit('/');
111106
cy.get('[data-cy="simulated-browser"]').should('exist');
112107
});
113108
it('mode=seamless should load a fullscreen WordPress', () => {
114-
cy.visit('/?networking=no&mode=seamless');
109+
cy.visit('/?mode=seamless');
115110
cy.get('[data-cy="simulated-browser"]').should('not.exist');
116111
});
117112
});
@@ -187,91 +182,149 @@ describe('Query API', () => {
187182
});
188183

189184
describe('playground-website', () => {
190-
beforeEach(() => cy.visit('/?networking=no'));
185+
beforeEach(() => cy.visit('/'));
191186

192187
it('should reflect the URL update from the navigation bar in the WordPress site', () => {
193188
cy.setWordPressUrl('/wp-admin');
194189
cy.wordpressPath().should('contain', '/wp-admin');
195190
});
196191

197192
// Test all PHP versions for completeness
198-
SupportedPHPVersions.forEach((version) => {
199-
it('should switch PHP version to ' + version, () => {
193+
describe('PHP version switcher', () => {
194+
SupportedPHPVersions.forEach((version) => {
195+
it('should switch PHP version to ' + version, () => {
196+
// Update settings in Playground configurator
197+
cy.get('button#configurator').click();
198+
cy.get('select#php-version').select(version);
199+
cy.get('#modal-content button[type=submit]').click();
200+
// Wait for the page to finish reloading
201+
cy.url().should('contain', `php=${version}`);
202+
cy.document().should('exist');
203+
204+
// Go to phpinfo
205+
cy.setWordPressUrl('/phpinfo.php');
206+
cy.wordPressDocument()
207+
.find('h1')
208+
.should('contain', 'PHP Version ' + version);
209+
});
210+
});
211+
});
212+
213+
// Only test the latest PHP version to save time
214+
describe('PHP extensions bundle', () => {
215+
it('should load additional PHP extensions when requested', () => {
200216
// Update settings in Playground configurator
201217
cy.get('button#configurator').click();
202-
cy.get('select#php-version').select(version);
218+
cy.get('select#php-version').select(LatestSupportedPHPVersion);
219+
cy.get('input[name=with-extensions]').check();
203220
cy.get('#modal-content button[type=submit]').click();
204-
// Wait for the page to finish reloading
205-
cy.url().should('contain', `&php=${version}`);
221+
// Wait for the page to finish loading
206222
cy.document().should('exist');
207223

208224
// Go to phpinfo
209225
cy.setWordPressUrl('/phpinfo.php');
210226
cy.wordPressDocument()
211-
.find('h1')
212-
.should('contain', 'PHP Version ' + version);
227+
.its('body')
228+
.should('contain', '--enable-xmlwriter');
229+
});
230+
231+
it('should not load additional PHP extensions when not requested', () => {
232+
// Update settings in Playground configurator
233+
cy.get('button#configurator').click();
234+
cy.get('select#php-version').select(LatestSupportedPHPVersion);
235+
cy.get('#modal-content button[type=submit]').click();
236+
// Wait for the page to finish loading
237+
cy.document().should('exist');
238+
239+
// Go to phpinfo
240+
cy.setWordPressUrl('/phpinfo.php');
241+
cy.wordPressDocument()
242+
.its('body')
243+
.should('contain', '--without-libxml');
213244
});
214245
});
215246

216-
// Only test the latest PHP version to save time
217-
it('should load additional PHP extensions when requested', () => {
218-
// Update settings in Playground configurator
247+
// Test all WordPress versions for completeness
248+
describe('WordPress version selector', () => {
249+
for (const version in SupportedWordPressVersions) {
250+
if (version === 'beta') {
251+
continue;
252+
}
253+
// @ts-ignore
254+
let versionMessage = 'Version ' + version;
255+
if (version === 'nightly') {
256+
versionMessage = 'You are using a development version';
257+
}
258+
259+
it('should switch WordPress version to ' + version, () => {
260+
// Update settings in Playground configurator
261+
cy.get('button#configurator').click();
262+
cy.get(`select#wp-version option[value="${version}"]`).should(
263+
'exist'
264+
);
265+
cy.get('select#wp-version').select(`${version}`);
266+
cy.get('#modal-content button[type=submit]').click();
267+
// Wait for the page to finish loading
268+
cy.url().should('contain', `&wp=${version}`);
269+
270+
// Go to phpinfo
271+
cy.setWordPressUrl('/wp-admin');
272+
cy.wordPressDocument()
273+
.find('#footer-upgrade')
274+
.should('contain', versionMessage);
275+
});
276+
}
277+
});
278+
});
279+
280+
/**
281+
* These tests only check if the modal UI updates the URL correctly.
282+
* The actual networking functionality is tested in the Query API tests.
283+
*/
284+
describe('Website UI – Networking support', () => {
285+
it('should display an unchecked networking checkbox by default', () => {
286+
cy.visit('/');
287+
219288
cy.get('button#configurator').click();
220-
cy.get('select#php-version').select(LatestSupportedPHPVersion);
221-
cy.get('input[name=with-extensions]').check();
222-
cy.get('#modal-content button[type=submit]').click();
223-
// Wait for the page to finish loading
224-
cy.document().should('exist');
289+
cy.get('input[name=with-networking]').should('not.be.checked');
290+
});
225291

226-
// Go to phpinfo
227-
cy.setWordPressUrl('/phpinfo.php');
228-
cy.wordPressDocument()
229-
.its('body')
230-
.should('contain', '--enable-xmlwriter');
292+
it('should display a checked networking checkbox when networking is enabled', () => {
293+
cy.visit('/?networking=yes');
294+
295+
cy.get('button#configurator').click();
296+
cy.get('input[name=with-networking]').should('be.checked');
231297
});
232298

233-
it('should not load additional PHP extensions when not requested', () => {
299+
it('should enable networking when requested', () => {
300+
cy.visit('/');
301+
234302
// Update settings in Playground configurator
235303
cy.get('button#configurator').click();
236-
cy.get('select#php-version').select(LatestSupportedPHPVersion);
304+
cy.get('input[name=with-networking]').check();
237305
cy.get('#modal-content button[type=submit]').click();
238-
// Wait for the page to finish loading
306+
307+
// Wait for the page to reload
239308
cy.document().should('exist');
309+
cy.get('#modal-content button[type=submit]').should('not.exist');
240310

241-
// Go to phpinfo
242-
cy.setWordPressUrl('/phpinfo.php');
243-
cy.wordPressDocument()
244-
.its('body')
245-
.should('contain', '--without-libxml');
311+
// Confirm the URL was updated correctly
312+
cy.relativeUrl().should('contain', 'networking=yes');
246313
});
247314

248-
// Test all WordPress versions for completeness
249-
for (const version in SupportedWordPressVersions) {
250-
if (version === 'beta') {
251-
continue;
252-
}
253-
// @ts-ignore
254-
let versionMessage = 'Version ' + version;
255-
if (version === 'nightly') {
256-
versionMessage = 'You are using a development version';
257-
}
315+
it('should disable networking when requested', () => {
316+
cy.visit('/?networking=yes');
258317

259-
it('should switch WordPress version to ' + version, () => {
260-
// Update settings in Playground configurator
261-
cy.get('button#configurator').click();
262-
cy.get(`select#wp-version option[value="${version}"]`).should(
263-
'exist'
264-
);
265-
cy.get('select#wp-version').select(`${version}`);
266-
cy.get('#modal-content button[type=submit]').click();
267-
// Wait for the page to finish loading
268-
cy.url().should('contain', `&wp=${version}`);
318+
// Update settings in Playground configurator
319+
cy.get('button#configurator').click();
320+
cy.get('input[name=with-networking]').uncheck();
321+
cy.get('#modal-content button[type=submit]').click();
269322

270-
// Go to phpinfo
271-
cy.setWordPressUrl('/wp-admin');
272-
cy.wordPressDocument()
273-
.find('#footer-upgrade')
274-
.should('contain', versionMessage);
275-
});
276-
}
323+
// Wait for the page to reload
324+
cy.document().should('exist');
325+
cy.get('#modal-content button[type=submit]').should('not.exist');
326+
327+
// Confirm the URL was updated correctly
328+
cy.relativeUrl().should('not.contain', 'networking=yes');
329+
});
277330
});

packages/playground/website/cypress/support/commands.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ declare namespace Cypress {
1717
setWordPressUrl(url: string): void;
1818
wordPressDocument(): Chainable<Element>;
1919
wordpressPath(): Chainable<string>;
20+
relativeUrl(): Chainable<string>;
2021
}
2122
}
2223

@@ -45,3 +46,12 @@ Cypress.Commands.add('wordpressPath', () => {
4546
.find('#wp')
4647
.its('0.contentWindow.location.pathname');
4748
});
49+
50+
Cypress.Commands.add('relativeUrl', () => {
51+
// relative part of the current top-level URL
52+
return cy.url().then((href) => {
53+
const url = new URL(href);
54+
console.log({ href });
55+
return href.substring(url.origin.length);
56+
});
57+
});

packages/playground/website/project.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@
3737
"mode": "development"
3838
},
3939
"production": {
40-
"mode": "production"
40+
"mode": "production",
41+
"logLevel": "info"
4142
}
4243
},
4344
"dependsOn": ["^build"]

0 commit comments

Comments
 (0)