Remove content-length header from wp_remote_post - wordpress

I am having big issues doing a POST request from wordpress backend.
This is the request I try to make. The AppsSCript is a doPost() endpoint echo-ing the request. It gives me a 400 error.
$body = array(
'firstName' => 'WhyWontYouWork'
);
$args = array(
'method' => 'POST',
'timeout' => 45,
'redirection' => 5,
//'httpversion' => '1.0',
'blocking' => true,
'headers' => array(
'Content-Type' => 'application/json'
),
'body' => $body
);
$request = wp_remote_post ($url, $args);
$response = wp_remote_retrieve_body( $request );
I found out with insomnia, that having a content-length header in the POST request is making Apps Script go crazy. If I remove it, all works.

Hope this helps,
$url = 'https://example.com/api/endpoint';
$args = array(
'method' => 'POST',
'timeout' => 30,
'headers' => array(
'Content-Type' => 'application/json',
),
'body' => json_encode( array( 'data' => 'value' ) ),
);
// Remove the Content-Length header
unset( $args['headers']['Content-Length'] );
// Or Change it
$args['headers']['Content-Length'] = 20166 // in decimal bytes
// Make the remote post request
$response = wp_remote_post( $url, $args );
// Check for errors
if ( is_wp_error( $response ) ) {
// Handle error
} else {
// Handle success
}

Related

Using woocommerce API

I have an online shop that uses woocommerce, wordpress.
We use a shared warehouse facilities of a firm that handles our products. They dont have a dedicated plugin for wordpress, but they sent me some API code that i have to inject in my site, in order to send them the order details to know what to goods to prepare.
They have sent me JS code
var myHeaders = new Headers();
myHeaders.append("SOAPAction", "http://tempuri.org/ImportOrders");
myHeaders.append("Content-Type", "text/xml; charset=utf-8");
var payload = "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ns1=\"http://tempuri.org/\"><SOAP-ENV:Body> <ns1:ImportOrders> <ns1:livrare> <CrosspointInboundMessage> <Order> ... </Order> </CrosspointInboundMessage></ns1:livrare></ns1:ImportOrders></SOAP-ENV:Body></SOAP-ENV:Envelope>";
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: payload
};
fetch("http://ws.qeops.ro/crosspointimportstandard.asmx?WSDL", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));`
fetch("http://ws.qeops.ro/health", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
I need to use XML not json
Please see a sample remote get request when an order is placed successfully.
add_action( 'woocommerce_payment_complete', 'do_api_call' );
function do_api_call( $order_id ) {
$order = new WC_Order( $order_id );
$items = $order->get_items();
foreach ( $items as $item ) {
$product_id = $item[ 'product_id' ];
$product = new WC_Product( $product_id );
$name = $order->billing_first_name;
$surname = $order->billing_last_name;
$email = $order->billing_email;
$sku = $product->get_sku();
// API Callout to URL
$url = 'http://ws.qeops.ro/health';
$response = wp_remote_get( $url, array(
'headers' => array( 'Content-Type' => 'application/json; charset=utf-8' ),
'method' => 'GET',
'redirect' => 'follow',
'timeout' => 75,
'sku' => $sku,
"name" => $name,
"surname" => $surname,
"email" => $email,
)
);
}
}

How to store and log for all http request and response in wordpress?

I want to store all outgoing http request from my wordpress site. I want to store all internal and external http request and response also request made with curl. Any help should be useful to me.
Hook into WP_Http::_dispatch_request()
function fn_log_http_request_response( $wp_http_response, $request, $url ) {
$request = [
'method' => $request['method'],
'url' => $url,
'headers' => $request['headers'],
'body' => $request['body'],
];
if($wp_http_response instanceof WP_Error) {
$response = [
'errors' => $wp_http_response->errors,
'error_data' => $wp_http_response->error_data,
];
} else {
$response = [
'status' => [
'code' => wp_remote_retrieve_response_code($wp_http_response),
'message' => wp_remote_retrieve_response_message($wp_http_response),
],
'headers' => wp_remote_retrieve_headers($wp_http_response)->getAll(),
'body' => wp_remote_retrieve_body($wp_http_response),
];
}
error_log(print_r([
'request' => $request,
'response' => $response,
], true));
return $wp_http_response;
}
// hook into WP_Http::_dispatch_request()
add_filter('http_response', 'fn_log_http_request_response', 10, 3 );
Adopted from hinnerk-a
You can also try the following plugin as well
https://wordpress.org/plugins/log-http-requests

Create an Image Share over LinkedIn API V2 not working

I use the api version 2.0 and want to create an image share.
LinkedIn describes your image binary file upload process here:
https://learn.microsoft.com/en-us/linkedin/consumer/integrations/self-serve/share-on-linkedin?context=linkedin/consumer/context#create-a-text-share
If you follow the instructions you will get a 400 HTTP error.
I add the Content-Type in the header and get a 201 HTTP status with the X-RestLi-Id in the header. So far so good!
If I want to show my created post on LinkedIn (https://www.linkedin.com/in/me/detail/recent-activity/) I can't find the post with image.
How to fix it? Anybody got an idea?
PHP code:
$imageRequestData = array(
"registerUploadRequest" => array(
"recipes" => array(
"urn:li:digitalmediaRecipe:feedshare-image"
),
"owner" => $urn, // Person URN === urn:li:person:XXXX
"serviceRelationships" => array(
array(
"relationshipType" => "OWNER",
"identifier" => "urn:li:userGeneratedContent"
)
)
)
);
$image_request = $this->post('v2/assets?action=registerUpload', $imageRequestData);
$headers = array();
$headers[] = 'Authorization: Bearer ' . $this->accessToken;
$headers[] = 'X-Restli-Protocol-Version: 2.0.0';
$headers[] = 'Content-Type: ' . mime_content_type($image_path); //ex. image/png
$ch = curl_init();
$options = array(
CURLOPT_HEADER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_URL => $image_request['message']['value']['uploadMechanism']
['com.linkedin.digitalmedia.uploading.MediaUploadHttpRequest']['uploadUrl'],
CURLOPT_HTTPHEADER => $headers,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_POST => true,
CURLOPT_CONNECTTIMEOUT => $this->connectTimeout,
CURLOPT_TIMEOUT => $this->timeout,
CURLOPT_POSTFIELDS => array("upload-file" => new CURLFile($image_path))
);
curl_setopt_array($ch, $options);
$response = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$content = array(
'author' => $urn, // Person URN === urn:li:person:XXX
'lifecycleState' => 'PUBLISHED',
'specificContent' => array(
"com.linkedin.ugc.ShareContent" => array(
'shareCommentary' => array(
"text" => $comment,
),
'shareMediaCategory' => 'IMAGE',
// NONE - The share does not contain any media, only text.
// ARTICLE - The share contains a URL.
// IMAGE - The Share contains an image.
'media' => array(
"status" => "READY",
"media" => $image_request['message']['value']['asset']
)
)
),
"visibility" => array(
"com.linkedin.ugc.MemberNetworkVisibility" => "PUBLIC"
)
);
$postfields = json_encode($content);
$headers = array();
$headers[] = 'x-li-format: json';
$headers[] = 'Authorization: Bearer ' . $this->accessToken;
$headers[] = 'Content-Type: application/json';
$headers[] = 'Content-Length: ' . strlen($postfields);
$headers[] = 'X-Restli-Protocol-Version: 2.0.0';
$ch = curl_init();
$options = array(
CURLOPT_HEADER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_URL => 'https://api.linkedin.com/v2/ugcPosts',
CURLOPT_HTTPHEADER => $headers,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_POST => true,
CURLOPT_CONNECTTIMEOUT => $this->connectTimeout,
CURLOPT_TIMEOUT => $this->timeout,
CURLOPT_POSTFIELDS => $postfields
);
curl_setopt_array($ch, $options);
$response = curl_exec($ch);
You need to change your request to PUT and keep default for SSL VerifyPeer:
$headers = array();
$headers[] = 'Authorization: Bearer ' . $this->accessToken;
$headers[] = 'X-Restli-Protocol-Version: 2.0.0';
$headers[] = 'Content-Type: multipart/form-data';
$ch = curl_init();
$options = array(
CURLOPT_HEADER => true,
CURLOPT_CUSTOMREQUEST => 'PUT', //need to set custom request to PUT instead of post
CURLOPT_RETURNTRANSFER => true,
CURLOPT_URL => $image_request['message']['value']['uploadMechanism']
['com.linkedin.digitalmedia.uploading.MediaUploadHttpRequest']['uploadUrl'],
CURLOPT_HTTPHEADER => $headers,
// CURLOPT_SSL_VERIFYPEER => false, //keep default options
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_POST => true,
CURLOPT_CONNECTTIMEOUT => $this->connectTimeout,
CURLOPT_TIMEOUT => $this->timeout,
CURLOPT_POSTFIELDS => array("upload-file" => new CURLFile($image_path))
);
curl_setopt_array($ch, $options);
$response = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
Or use GuzzleHttp\Client to simplify the upload:
$client =new \GuzzleHttp\Client();
$client->request('PUT',
$image_request['message']['value']['uploadMechanism'] // ↵
['com.linkedin.digitalmedia.uploading.MediaUploadHttpRequest']['uploadUrl'],
[
'headers' => [
'Authorization' => 'Bearer ' . $this->accessToken
],
'body' => fopen($image_path, 'r'),
]

How to hit the url in WordPress rest_api_init

I have set up the API end points in WordPress in theme functions.php.
add_action( 'rest_api_init', function () {
register_rest_route( 'myplugin/v1', '/author/(?P<id>\d+)', array(
'methods' => 'GET',
'callback' => 'my_awesome_func',
'args' => array(
'id' => array(
'validate_callback' => function($param, $request, $key) {
return is_numeric( $param );
}
),
),
));
});
And the callback function is like:
function my_awesome_func( $data ) {
$posts = get_posts( array(
'author' => $data['id'],
) );
if ( empty( $posts ) ) {
return new WP_Error( 'awesome_no_author', 'Invalid author', array( 'status' => 404 ) );
}
return $posts[0]->post_title;
}
I want to know what will be the url for this API and how can I hit that url?
Please help me out. I know this is simple thing but couldn't figure it out.

Batching with Google Places: Is it possible?

I was wondering if it's possible to send batched requests to maps.googleapis.com. As far as I can tell, it isn't.
I was using the Google API Client Library with supports batching, but it's only for www.googleapis.com. I went ahead and hacked it so that I could call the Places API, and it worked fine for normal calls, but when I actually tried to batch them, I got a 404 error:
"The requested URL /batch was not found on this server. That’s all we know."
So it appears that maps.googleapis.com does not support batching, but I wanted to be sure this is true. If anyone knows otherwise, please tell me how. Thanks!
inside google-api-php-client/src/Google/Config.php:
- 'base_path' => 'https://www.googleapis.com',
+ 'base_path' => 'https://maps.googleapis.com',
google-api-php-client/src/Google/Service/Maps.php:
(I added this file to make Places calls possible.)
<?php
class Google_Service_Maps extends Google_Service
{
const MAPS = "https://maps.googleapis.com/auth/maps";
public function __construct(Google_Client $client)
{
parent::__construct($client);
$this->servicePath = 'maps/api/';
$this->version = 'v3';
$this->serviceName = 'maps';
$this->places = new Google_Service_Maps_Places_Resource(
$this,
$this->serviceName,
'places',
array(
'methods' => array(
'autocomplete' => array(
'path' => 'place/autocomplete/json',
'httpMethod' => 'GET',
'parameters' => array(
'input' => array(
'location' => 'query',
'type' => 'string',
'required' => true,
),
'sensor' => array(
'location' => 'query',
'type' => 'boolean',
'required' => true,
),
'location' => array(
'location' => 'query',
'type' => 'string',
),
'radius' => array(
'location' => 'query',
'type' => 'integer',
),
),
),
)
)
);
}
}
class Google_Service_Maps_Places_Resource extends Google_Service_Resource
{
public function autocomplete($input, $lat, $lng, $radius, $optParams = array())
{
$params = array('input' => $input, 'location' => "$lat,$lng", 'radius' => $radius, 'sensor' => false);
$params = array_merge($params, $optParams);
return $this->call('autocomplete', array($params));
}
}
API batch calling code:
<?php
const API_KEY = 'MY_API_KEY';
set_include_path("google-api-php-client/src/" . PATH_SEPARATOR . get_include_path());
require_once 'Google/Client.php';
require_once 'Google/Service/Maps.php';
require_once 'Google/Http/Batch.php';
$client = new Google_Client();
$client->setApplicationName("Client_Library_Examples");
$client->setDeveloperKey(API_KEY);
$client->setUseBatch(true);
$batch = new Google_Http_Batch($client);
$service = new Google_Service_Maps($client);
$inputs = array(
'Dolore',
'MacAl',
'App Aca'
);
foreach($inputs as $input) {
$req = $service->places->autocomplete($input, 37.7833, -122.4167, 500);
$batch->add($req, $input);
}
$results = $batch->execute();
print_r($results);
print_r($req);

Resources