cURL & Shell Command Converter

Turns a copied curl command into WordPress HTTP API, fetch or PHP cURL code, with the method curl inferred and the content type it implied both stated.

Enable JavaScript to customise; default output below.

In a browser's network panel, right-click a request and choose Copy as cURL. Line continuations and shell quoting are handled.

Convert to

wordpress is wp_remote_request, which is the right one inside a plugin or theme: it uses whatever transport the host has and respects the site's filters.

Live preview request.php
Target        WordPress HTTP API
Method        POST
URL           https://api.example.com/v1/orders
Headers       3
Body          23 characters
Content type  application/json (from the command)

PHP
$response = wp_remote_request(
	'https://api.example.com/v1/orders',
	array(
		'method'  => 'POST',
		'timeout' => 15,
		'headers' => array(
			'Content-Type' => 'application/json',
			'Accept' => 'application/json',
			'Authorization' => 'Basic YXBpX3VzZXI6YXBpX3NlY3JldA==',
		),
		'body'    => '{"sku":"BWP-1","qty":2}',
	)
);

if ( is_wp_error( $response ) ) {
	return $response; // A transport failure, not an HTTP error.
}

$code = wp_remote_retrieve_response_code( $response );
$body = wp_remote_retrieve_body( $response );

The -u credentials became an Authorization header, which is what curl
sends. Move the value into a constant or an environment variable before
this goes anywhere near a repository.

wp_remote_request returns a WP_Error for a transport failure, not for an
HTTP error status, so both have to be checked: is_wp_error for the first
and the response code for the second. That distinction is the most
common bug in WordPress HTTP code.

Output is valid and updates as you type.

Copy a request out of a browser’s network panel and you get a curl command. Turning it into code by hand goes wrong in the same three places every time, and all three are things curl did quietly on your behalf.

The method. -d with no -X is a POST. -I is a HEAD. -G moves the data into the query string and leaves it a GET. Assuming GET because there is no -X sends a body with a GET, which some servers ignore without telling you.

The content type. curl -d '{"a":1}' does not send JSON. With no Content-Type header, curl sends application/x-www-form-urlencoded, whatever the body looks like. If the API reads JSON, that request was failing or working by accident.

Redirects. curl does not follow them unless you pass -L. WordPress and fetch both follow by default. A faithful conversion of a command without -L has to turn following off, which is a line most conversions do not include.

How to use

  1. Paste the command. Line continuations, quoted header values and bundled flags such as -sSLk are all handled.
  2. Pick the target: WordPress, fetch, or PHP cURL.
  3. Read the summary above the code, then copy the code.

Example

$response = wp_remote_request(
	'https://api.example.com/v1/orders',
	array(
		'method'  => 'POST',
		'timeout' => 15,
		'headers' => array(
			'Content-Type' => 'application/json',
			'Accept' => 'application/json',
			'Authorization' => 'Basic YXBpX3VzZXI6YXBpX3NlY3JldA==',
		),
		'body'    => '{"sku":"BWP-1","qty":2}',
	)
);

if ( is_wp_error( $response ) ) {
	return $response; // A transport failure, not an HTTP error.
}

$code = wp_remote_retrieve_response_code( $response );
$body = wp_remote_retrieve_body( $response );

The -u api_user:api_secret became an Authorization header, because that is what curl sends. The error handling is there because wp_remote_request returns a WP_Error for a transport failure and a perfectly ordinary response array for a 500, and code that checks only one of those is the most common bug in WordPress HTTP calls.

Pitfalls

-k means TLS verification is off. It is translated to 'sslverify' => false with a comment saying not to ship it, because the alternative is carrying it across silently. With verification off, anything on the network path can read and rewrite the request, which is most of what TLS was for. It belongs in a one-off debugging command.

Credentials in a copied command are real credentials. A command copied from a network panel contains your session cookie or your bearer token. Move them into a constant, an environment variable or a stored option before the code goes anywhere near a repository, and remember that the command in your shell history has them too.

-F is a multipart upload and this flattens it. The generated body is an approximation. For a real file upload, build the multipart body with the library’s own helper: the boundary and the per-part headers are fiddly and a hand-built string will not do.

wp_remote_get and wp_remote_post are wrappers. They call wp_remote_request with the method set, which is why this generates the general form. If your method is fixed, the shorter wrapper reads better.

Timeouts matter in WordPress. The default is five seconds, which is short for a slow API and long for a request in a page load. The generated code uses 15, or whatever -m said. Anything in a page request should be well under that or moved to cron.

fetch resolves for a 404. It rejects only when the request never completed at all, so response.ok has to be checked before the body is read.

A shell variable cannot be converted. curl "$API_BASE/orders" has no URL in it as far as this tool is concerned, and it says so rather than generating code with a dollar sign in the URL. Substitute the value in first.

Compatibility

Everything runs in the browser: nothing is uploaded and nothing is stored. That matters here more than usual, because a copied curl command routinely contains a session cookie or an API key.

The command is tokenised the way a shell does: single quotes literal, double quotes with escapes, backslash line continuations joined, bundled short flags split, and --flag=value handled. Splitting on spaces, which is what most converters do, breaks on the first header value that contains one.

Every PHP variant the tool can produce was checked with php -l, including commands containing apostrophes, backslashes and embedded quotes, since a generated snippet that does not parse is worse than no snippet.

Flags that only affect curl’s own behaviour, such as -s, -v and --compressed, do not appear in the output because they have no equivalent: they control what curl prints, and the libraries here do not print. Anything the parser does not recognise is listed at the end rather than dropped in silence.

Frequently asked questions

Which WordPress function should I use?
wp_remote_request for anything with a method that varies, wp_remote_get and wp_remote_post when it does not. All three go through the same HTTP API, respect the site’s filters and use whatever transport the host provides, which is why they are the right choice inside a plugin rather than raw cURL.
Why does the generated code set 'redirection' => 0?
Because the command had no -L, so curl was not following redirects, and WordPress follows five by default. If the original request was meant to follow them, add -L to the command and convert again.
Does it handle cookies?
-b becomes a Cookie header, which is what curl sends. WordPress also has a cookies option that takes WP_Http_Cookie objects, and that is the better form if you are managing a session rather than replaying one request.
Can it go the other way, from code to curl?
Not yet. In the meantime, the browser network panel’s “Copy as cURL” is the fastest route for anything a browser sent.
Why is my --data body form-encoded in the output?
Because that is what curl sent. If the API wants JSON, add -H "Content-Type: application/json" to the command, which is also the fix for the original request.
Weekly drops

New tools, when there are new tools

One email when something worth using ships. No schedule to fill, so no filler.

Your address goes nowhere else, and one click unsubscribes.