Open key88sf opened 6 months ago
Is there any way to enable AJAX requests in the blueprint JSON?
Would you be able to provide an example blueprint to help us better understand your issue?
@bgrgicak Yes - so I was testing with our plugin using this Blueprint JSON below (plugin name redacted here):
{
"$schema": "https://playground.wordpress.net/blueprint-schema.json",
"landingPage": "/wp-admin/index.php",
"preferredVersions": {
"php": "8.3",
"wp": "latest"
},
"phpExtensionBundles": [
"kitchen-sink"
],
"features": {
"networking": true
},
"steps": [
{
"step": "login",
"username": "admin",
"password": "password"
},
{
"step": "installPlugin",
"pluginZipFile": {
"resource": "wordpress.org/plugins",
"slug": "my-plugin-slug-name"
},
"options": {
"activate": true
}
}
]
}
Our plugin calls admin-ajax.php
on various pages, for example from the media library edit page. But in the Playground instance, this is giving a 404:
URL: /wp-admin/post.php?post=5&action=edit
Chrome console:
POST https://playground.wordpress.net/scope:0.9331797754628046/wp-admin/admin-ajax.php 404 (Not Found)
Is there any way to enable AJAX requests in the blueprint JSON?
Ajax requests are enabled by default. You can see it by loading wp-admin in Playground and checking the network tab.
I assume that something else related to Playground is causing the issue for you.
If you can't share the plugin with us, you could debug it yourself by taking a look at the Playground logs (browser console, or click on View Logs in the upper right menu).
This is really strange -- the URL is exactly the same between what the plugin is posting to and what the wp-admin page is posting to.
The only difference I see is in some of the network headers. There are additional security headers which are sent when the plugin javascript makes the request (via jQuery.ajax()
):
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
This is the JS code which makes the call:
jQuery.ajax({
type: 'post',
dataType: 'json',
async: false,
data: {
'action': 'alax_check_image',
'security': wp_alax.security_check_image,
'attachment_id': attachmentId,
},
url: wp_alax.ajax_url, // this is set to: admin_url( 'admin-ajax.php' )
success: function (response) {
status = response.status;
}
});
Does that help at all?
I don't think it's the security headers. I tried adding them to a heartbeat request and it kept working.
The code you provided doesn't work for me because I don't have the alax_check_image
endpoint. Would you be able to provide instructions on how to recreate this in Playground? I would love to help, but first I need to be able to recreate the issue.
To debug it further you could rewrite the request to use fetch
and see if this resolves the issue. If yes, compare the two requests to see what happened.
Example:
fetch(
wp.src.match(/(^[^\/]*\/\/[^\/]*\/[^\/]*)\/.*/)[1] +
"/wp-admin/admin-ajax.php",
{
headers: {
accept: "application/json, text/javascript, */*; q=0.01",
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"x-requested-with": "XMLHttpRequest",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
},
referrer:
"https://playground.wordpress.net/scope:0.8893762696707332/wp-admin/edit-comments.php",
referrerPolicy: "strict-origin-when-cross-origin",
body: "interval=60&_nonce=1c0d4e2483&action=heartbeat&screen_id=edit-comments&has_focus=false",
method: "POST",
mode: "cors",
credentials: "omit",
}
)
.then((response) => response.json())
.then((data) => console.log(data.text()))
.catch((error) => console.log(error));
The code you provided doesn't work for me because I don't have the
alax_check_image
endpoint. Would you be able to provide instructions on how to recreate this in Playground? I would love to help, but first I need to be able to recreate the issue.
This isn't an endpoint, it's just a part of the JSON data being sent -- so not really important. We just use that to ensure the request is coming from Wordpress.
Is there any way to test changes to the plugin code in playground without actually committing new code to SVN?
Is there any way to test changes to the plugin code in playground without actually committing new code to SVN?
Yes, you can use the device storage option inside Playground. Alternatively, you could use WP-NOW as a development environment. WP-NOW is slightly different from the web version, so in case your code works with WP-NOW, this would be a Playground web issue.
Is there any way to test changes to the plugin code in playground without actually committing new code to SVN?
Or you could:
It would be handy to document different workflow options for plugin preview development. Let's link this issue with https://github.com/WordPress/wordpress-playground/issues/772 for the upcoming doc overhaul
@bgrgicak I figured out what is causing the problem. It is the async: false
setting in the jQuery.ajax()
call.
If I set this to true
, the POST to admin-ajax.php works fine (200 response). Setting to false
results in a 404 Not Found error. I'm not sure why using synchronous results in a 404 though?
The jQuery docs (https://api.jquery.com/Jquery.ajax/) only say that if you make a synchronous request via cross-domain, it is not supported -- but the call works fine on "real" WP instances, just not in the Playground.
Any ideas?
If I set this to true, the POST to admin-ajax.php works fine (200 response). Setting to false results in a 404 Not Found error. I'm not sure why using synchronous results in a 404 though?
Great find, I can confirm that async false triggers a 404.
Here is an example that returns a 404, but it returns 200 if async is true.
jQuery = import('https://code.jquery.com/jquery-3.7.1.min.js');
jQuery.ajax({
url: wp.src.match(/(^[^\/]*\/\/[^\/]*\/[^\/]*)\/.*/)[1] + "/wp-admin/admin-ajax.php",
type: 'post',
headers: { "Accept-Encoding" : "gzip" },
dataType: 'json',
async: false,
data: {
action: 'heartbeat',
},
}).done(function(data) {
console.log(data);
});
From looking at the ajax documentation this part stands out Note that synchronous requests may temporarily lock the browser, disabling any actions while the request is active.
.
I assume that when a sync request is sent, Playground is blocked from running and accepting the request.
@adamziel please correct me if I'm wrong.
@key88sf I would suggest that you to rewrite the code to be async. I'm not sure if Playground would be able to support sync requests, and in general they are a bad practice because they block the browser while running.
@bgrgicak Cool we can try to rewrite as an async call. I'm sure there are other plugins out there which make sync requests so if possible to support this, that would be great!
I assume that when a sync request is sent, Playground is blocked from running and accepting the request.
PHP runs in a worker, the only relevant part that would get blocked part is this event listener relaying messages between the service worker and PHP web worker: https://github.com/WordPress/wordpress-playground/blob/16293ba57cea96e0f7f3eca12b0e6aef8f3b2f8e/packages/php-wasm/web/src/lib/register-service-worker.ts#L47
The service worker used to talk directly to the web worker via a BroadcastChannel
, but it wasn't working consistently across web browser and there were also issues with CORS/embedding Playground:
If this, or any other communication technique would work consistently these days, we could refactor that part.
Relevant article: https://web.dev/articles/two-way-communication-guide
It looks like any calls by plugins to
admin-ajax.php
result in a 404 Not Found error when running inside a playground instance.Is there any way to enable AJAX requests in the blueprint JSON?