Problem using wp_remote_post to parse JSON response from external API - wordpress

I am using wp_remote_post() to post products to a third party site. First I get these products via API from a site called Mercado Libre. But when I carry out the mass publication, the products are published without a name, without a price, and without respecting the parameters provided. They only have the name "Product".
function publish_products_in_woocommerce()
{
$respuesta = wp_remote_get('https://api.mercadolibre.com/sites/MLA/search?q=Motorola%20G6', array(
'headers' => array(
'Authorization' => 'Bearer APP_USR-2778915669536100-052221-0f3a39361bdcea9bc3de0df8ab619f66-370993848'
)
));
$respuesta = json_decode($respuesta['body'], true);
print_r($respuesta);
foreach ($respuesta['results'] as $value) {
$product_data = array(
'name' => $value['title'],
'status' => 'draft',
'type' => 'simple',
'regular_price' => $value['price'],
'description' => $value['title'],
'short_description' => $value['title'],
'categories' => [
[
'id' => $value['category_id'],
]
],
'images' => [
[
'src' => $value['thumbnail']
]
]
);
$woocommerce_api_ck = 'ck_b2a0f58d07590e8283302eca04fbc1b66a9ff653';
$woocommerce_api_cs = 'cs_b4d91662590be47416f663fc9f0d1c49f600e394';
$url = 'http://nuevo.labisbal.com.ar/wp-json/wc/v3/products';
wp_remote_post('http://nuevo.labisbal.com.ar/wp-json/wc/v3/products', array(
'headers' => array(
'Authorization ' => 'Basic ' . base64_encode($woocommerce_api_ck . ':' . $woocommerce_api_cs),
),
'body' => $ProductToWooCommerce = json_encode($product_data),
'method' => 'POST',
'timeout' => 145,
'blocking' => false,
'sslverify' => false,
'stream' => true,
'data_format' => 'json'
));
print_r($ProductToWooCommerce);
if (wp_remote_retrieve_response_message($respuesta) === 'Created') {
echo 'The product has been created';
}
}
}
publish_products_in_woocommerce();
?>
It's strange because when I display the json already converted (using json_encode) the data is displayed correctly... (using print_r)

I take a look at this and the issue is on how you sent the data to the API, when you use wp_remote_post you need to send the body as an array, and the method handles that information for you, so you don't need to convert it to JSON.
Below is a small test plugin that saves products using the WC REST API, the plugin adds a new endpoint to your site to trigger the scrapper https://yoursite.com/wp-json/wpapi/v1/fetch, I hope that helps.
Note: Please double check the code, is not fully tested.
<?php
/**
* Plugin Name: A WC API test
* Plugin URI: https://enriquechavez.co
* Description: Just a test.
* Version: 1.0.0
* Requires at least: 5.2
* Requires PHP: 7.4
* Author: Enrique Chavez
* Author URI: https://enriquechavez.co/
* License: GPL v2 or later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Update URI: https://example.com/my-plugin/
* Text Domain: my-basics-plugin
* Domain Path: /languages
*/
add_action('rest_api_init', function () {
register_rest_route('wpapi/v1', 'fetch', [
'methods' => WP_REST_Server::READABLE,
'callback' => 'fetch_ml_products',
'permissions_callback' => '__return_true',
]);
});
function fetch_ml_products(WP_REST_Request $request)
{
$ml_api = 'https://api.mercadolibre.com/sites/MLM/search?q=Motorola%20G6&limit=5';
$wc_ck = 'ck_1f2e32852403a1701c1adxxxxxxxxxxxxxxxxxxx';
$wc_cs = 'cs_6fd5feedd2a25b73eebc9xxxxxxxxxxxxxxxxxxx';
$request = wp_safe_remote_get($ml_api);
if (is_wp_error($request)) {
return $request;
}
$response = json_decode(wp_remote_retrieve_body($request));
$new_products = [];
foreach ($response->results as $product) {
$wc_api_url = 'https://wp.test/wp-json/wc/v3/products/';
$request_data = [
'headers' => [
'Authorization' => 'Basic ' . base64_encode($wc_ck . ':' . $wc_cs),
],
'body' => [
'name' => $product->title,
'status' => 'draft',
'regular_price' => $product->price,
],
'sslverify' => false,
];
$request = wp_remote_post($wc_api_url, $request_data);
if (is_wp_error($request)) {
// TODO: validate the error.
print_r($request);
die('Something is wrong');
}
$new_products[] = json_decode(wp_remote_retrieve_body($request));
}
return $new_products;
}

Related

Custom elementor forms extension - Not redirecting after submit

This is an extension for elementor pro forms that sends the form data to an API.
This first API will return a success or failure message.
If successful, the response will also contain an ID number.
That ID number should then be used in a second API request where the number is appended to the URL. This second API will return a login URL.
The plugin should then redirect the user to the returned URL.
Currently I am receiving a response from the first API. the response I've received is as follows:
{"code":201,"data":{"id":133714},"message":"Success"}
The second API Response I get is the following:
{"code": 200,"request_method":"GET","autologin":"https://www.exampleurl.com/login" }
But it is not redirecting the user. Can you help me discover why?
`
<?php
/*
Plugin Name: Elementor Custom form
Plugin URI:
Description:
Version:
Author:
Author URI:
License:
License URI:
*/
/*
This plugin adds a custom form action to Elementor Pro forms.
The new action sends an API Request to a custom endpoint.
After receiving a valid response, the form will send another API Request to a different endpoint.
The response from the second API Request is used to redirect the user to a different page.
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class Bpd_Custom_Form_Action extends \ElementorPro\Modules\Forms\Classes\Action_Base {
public function get_name() {
return 'custom_form_action';
}
public function get_label() {
return __( 'Custom Form Action', 'elementor-pro' );
}
public function register_settings_section( $widget ) {
$widget->start_controls_section(
'section_custom_form_action',
[
'label' => $this->get_label(),
'condition' => [
'submit_actions' => $this->get_name(),
],
]
);
//////////////////////////////////////////////
//
// FIRST API - SETTINGS & AUTHORIZATION
//
//////////////////////////////////////////////
$widget->add_control(
'custom_form_action_api_url',
[
'label' => __( 'URL', 'elementor-pro' ),
'type' => \Elementor\Controls_Manager::TEXT,
'placeholder' => 'https://example.com/api/',
'description' => __( 'Enter the URL of the API endpoint you want to send the form data to.', 'elementor-pro' ),
'label_block' => true,
'separator' => 'before',
]
);
$widget->add_control(
'custom_form_action_application_token',
[
'label' => __( 'Application Token', 'elementor-pro' ),
'type' => \Elementor\Controls_Manager::TEXT,
'placeholder' => 'https://example.com/api/',
'label_block' => true,
'description' => __( 'Enter the application token for your API request.', 'elementor-pro' ),
'separator' => 'before',
]
);
//////////////////////////////////////////////
//
// FIRST API - Body & Response Options
//
//////////////////////////////////////////////
$widget->add_control(
'custom_form_action_api_body',
[
'label' => __( 'Body', 'elementor-pro' ),
'type' => \Elementor\Controls_Manager::TEXTAREA,
'placeholder' => '{ "name": "{{{ name }}}", "email": "{{{ email }}}" "ip": "{{{ USERIP }}}" }',
'description' => __( 'Enter the body of the API request. You can use the form fields as placeholders. For example: { "name": "{{{ name }}}", "email": "{{{ email }}}" }', 'elementor-pro' ),
'label_block' => true,
'separator' => 'before',
]
);
//////////////////////////////////////////////
//
// Second API - SETTINGS & AUTHORIZATION
//
//////////////////////////////////////////////
$widget->add_control(
'custom_form_action_second_api_url',
[
'label' => __( 'Second API URL', 'elementor-pro' ),
'type' => \Elementor\Controls_Manager::TEXT,
'placeholder' => 'https://example.com/thank-you/',
'description' => __( 'Enter the URL of the page you want to redirect the user to after the form is submitted.', 'elementor-pro' ),
'label_block' => true,
'separator' => 'before',
]
);
$widget->add_control(
'custom_form_action_second_application_token',
[
'label' => __( 'Second Application Token', 'elementor-pro' ),
'type' => \Elementor\Controls_Manager::TEXT,
'placeholder' => 'https://example.com/api/',
'label_block' => true,
'description' => __( 'Enter the application token for your API request.', 'elementor-pro' ),
'separator' => 'before',
]
);
$widget->end_controls_section();
}
public function register_form_action( $widget ) {
$widget->add_form_action(
'custom_form_action',
[
'label' => __( 'Custom Form Action', 'elementor-pro' ),
'event' => \ElementorPro\Modules\Forms\Classes\Form_Record::get_form_settings( 'custom_form_action_event' ),
'callback' => [ $this, 'custom_form_action' ],
]
);
}
public function run( $record, $ajax_handler ) {
$debugLog = '';
$settings = $record->get( 'form_settings' );
// create the first api request
$first_api_url = $settings['custom_form_action_api_url'];
$first_api_body = $settings['custom_form_action_api_body'];
// set up the first header request
$first_api_header_authorization = 'Bearer ' . $settings['custom_form_action_application_token'];
// get the form fields
$fields = $record->get( 'fields' );
// replace the placeholders with the form field values
$first_api_body = $this->replace_placeholders( $first_api_body, $fields );
//////////////////////////////////////////
//
// Make the first API request
//
//////////////////////////////////////////
//if the method is post
// send the post request
$first_api_response = wp_remote_post( $first_api_url, [
'method' => 'POST',
'headers' => array(
'Authorization' => 'Bearer ' . $settings['custom_form_action_application_token'],
'content-type' => 'application/json',
),
'body' => $first_api_body,
'timeout' => 20,
'redirection' => 5,
'httpversion' => '1.0',
//SET BLOCKING TO TRUE TO WAIT FOR A RESPONSE - 5 hours wasted for this.
'blocking' => true,
'data_format' => 'body',
] );
if ( ! is_wp_error( $first_api_response ) ) {
$response_data = json_decode( $first_api_response['body'], true );
if ( isset( $response_data['data']['id'] ) ) {
$new_lead_id = $response_data['data']['id'];
}
else{
$new_lead_id = '';
}
}
//////////////////////////////////////////
//
// Make the second API request
//
//////////////////////////////////////////
// create the second api request
$second_api_url = $settings['custom_form_action_second_api_url'];
// set up the second header request
$second_api_header_authorization = 'Bearer ' . $settings['custom_form_action_second_application_token'];
if (!empty($first_api_response_body)){
$new_lead_id = $first_api_response_body->data->id;
}
$new_api_url = $second_api_url . $new_lead_id;
$new_api_body = '{ "lead_id": ' . $new_lead_id . '}';
// send the second api request
$second_api_response = wp_remote_post( $new_api_url, [
'method' => 'POST',
'headers' => array(
'Authorization' => 'Bearer ' . $second_api_header_authorization,
'content-type' => 'application/json',
),
'body' => $new_api_body,
'timeout' => 20,
'redirection' => 5,
'httpversion' => '1.0',
'blocking' => true,
'data_format' => 'body',
] );
//Check for errors in the Second api response.
if ( ! is_wp_error( $second_api_response ) ) {
$response_data = json_decode( $second_api_response['body'], true );
if ( isset( $response_data['autologin'] ) ) {
$autologin = $response_data['autologin'];
}
else{
$autologin = 'https://google.com';
}
}
//redirect the user
if ( ! empty( $autologin ) ) {
wp_redirect( $autologin );
exit;
}
else{
wp_redirect( 'https://www.google.com' );
exit;
}
if ( is_wp_error( $first_api_response ) ) {
wp_remote_retrieve_response_code( $second_api_response );
if ( wp_remote_retrieve_response_code( $second_api_response ) == 201 ) {
//add success message
$ajax_handler->add_success_message( __( 'First API Response: ' . $second_api_response['body'], 'elementor-pro' ) );
}
elseif ( wp_remote_retrieve_response_code( $second_api_response ) == 202 ) {
//add error message
$ajax_handler->add_error_message( __( 'First API Response: ' . $second_api_response['body'], 'elementor-pro' ) );
}
}
if ( is_wp_error( $second_api_response ) ) {
$ajax_handler->add_error_message( __( '<br><br>Data ID From First Response: '. $first_api_response_body->data->id
. '<br>Second API Body: ' . json_encode($second_api_body)
. '<br> First API Response Selector: ' . $first_api_body_response_selector
. '<br>Second API Response: ' . $second_api_response['body']
. '<br>Redirect URL: ' . $redirect_response_url
. '<br><br>',
'elementor-pro'
)
);
return;
}
if ( ! empty( $redirect_response_url ) && filter_var( $redirect_response_url, FILTER_VALIDATE_URL ) ) {
$ajax_handler->add_response_data( 'redirect_url', $redirect_response_url );
}
}//end run function
public function on_export( $element ) {
unset( $element['custom_form_action_message_redirect_url'] );
return $element;
}
public function replace_placeholders( $string, $fields ) {
$ip_of_current_user = $this->bpd_get_user_ip();
foreach ( $fields as $id => $field ) {
$string = str_replace( '{{{ USERIP }}}', $ip_of_current_user, $string );
$string = str_replace( '{{{ ' . $id . ' }}}', $field['value'], $string );
}
return $string;
}
public function bpd_get_user_ip() {
/*
if ( ! empty( $_SERVER['HTTP_CLIENT_IP'] ) ) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
return $ip;
} elseif ( ! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
return $ip;
} else {
$ip = $_SERVER['REMOTE_ADDR'];
return $ip;
}
*/
$ip = $_SERVER['REMOTE_ADDR'];
return $ip;
}
}
`

how to retrieve post response variable outside in reactphp

My code is as follows:
require __DIR__.'/vendor/autoload.php';
use Psr\Http\Message\ResponseInterface;
$loop = React\EventLoop\Factory::create();
$client = new React\Http\Browser($loop);
$data = [
'name' => [
'first' => 'Alice',
'name' => 'Smith',
],
'email' => 'alice#example.com',
'userid' => 'alice',
];
$client->post(
'https://httpbin.org/post',
[
'Content-Type' => 'application/json',
],
json_encode($data)
)->then(function (ResponseInterface $response) {
$response = (string) $response->getBody();
return $response;
});
**echo $response;**
$loop->run();
I am able to get the response inside then function(). but I cannot retrieve the response value outside.
I like to send multiple asynchronous POST requests and collect each responses and echo all of them at once.
How can I access the response variable from outside of post()->then()?
I could get the response when I need a response with deferred and promise method.
First, I assigned the request and response method to $promise.
And I was able to simply get the response with $deferred->resolve();
require __DIR__.'/vendor/autoload.php';
use Psr\Http\Message\ResponseInterface;
$loop = React\EventLoop\Factory::create();
$client = new React\Http\Browser($loop);
$deferred = new React\Promise\Deferred();
$promise = $deferred->promise();
$data = [
'name' => [
'first' => 'Alice',
'name' => 'Smith',
],
'email' => 'alice#example.com',
'userid' => 'alice',
];
$promise = $client->post(
'https://httpbin.org/post',
[
'Content-Type' => 'application/json',
],
json_encode($data)
)->then(function (ResponseInterface $response) {
$response = (string) $response->getBody();
return $response;
});
echo $deferred->resolve();
$loop->run();

Integrating wordpress and laravel login

I am developing three area for my website.. using WordPress (Front Page), XenForo (Forum), and Laravel (Member Area) ... i already succeed integrating my laravel and XenForo, so when XenForo user login to Member Area my function will check if the user already exist (If XenForo user exist then laravel will create the user in database using XenForo user data, if not exist then login failed)
Now i want to do the same for WordPress .. when user login to member area the function will check if WordPress user is exist or not .. if exist then new user will be created using wordpress user data (name, email, password, and token if possible) if not exist then login failed, but how do i do this? unlike XenForo .. i can't find WordPress API documentation for getting user data
Edit 1 :
This is my login function
public function login_post(Request $request){
// XENFORO API AUTH START
$http = Http::withHeaders([
'XF-Api-Key' => 'SECRET'
])->asForm()->post('http://forum.mywebsite.com/api/auth', [
'login' => $request->email,
'password' => $request->password
]);
if(isset($http['errors'])){
return redirect('login')->with('error', 'Username and Password Error');
}
$name = $http['user']['username'];
$email = $http['user']['email'];
$password = $request->password;
$is_admin = $http['user']['is_admin'];
$user_id = $http['user']['user_id'];
// XENFORO API AUTH END
// WordPress API AUTH START
$client = new \GuzzleHttp\Client([
// Base URI is used with relative requests
'base_uri' => 'http://mywebsite.com/',
'headers' => ['Content-Type' => 'application/json', "Accept" => "application/json", 'Authorization' => 'Basic ' . base64_encode( 'ADMIN' . ':' . 'PASSWORD' ),],
]);
$response = $client->get('users/', [
'query' => [
'email' => $request->email,
]
]);
return json_decode($response->getBody());
// WordPress API AUTH END
if (Auth::attempt(['email' => $email, 'password' => $password])) {
# code...
if(Auth::user()->role == 0){
return redirect('dashboard');
}
return redirect('login');
} else {
$newUser = new User;
$newUser->name = $name ;
$newUser->email = $email;
$newUser->password = bcrypt($password);
$newUser->role = $is_admin;
$newUser->save();
auth()->login($newUser, true);
return redirect('dashboard');
}
}
Edit 2 :
$client = new \GuzzleHttp\Client([
// Base URI is used with relative requests
'base_uri' => 'http://mywebsite.com/wp-json/wp/v2/',
'headers' => ['Content-Type' => 'application/json', "Accept" => "application/json", 'Authorization' => 'Basic ' . base64_encode( 'ADMIN' . ':' . 'PASSWORD' ),],
]);
$response = $client->get('users/', [
'query' => [
'email' => $request->email,
]
]);
$response = json_decode($response->getBody());
$name = $response['username'];
$email = $response['email'];
$password = $request->password;
$is_admin = $response['role'];
$user_id = $response['id'];
The Response :
array:3 [▼
0 => {#287 ▼
+"id": 1
+"name": "Admin"
+"url": "http://www.mywebsite.com"
+"description": ""
+"link": "http://mywebsite.com/author/admin/"
+"slug": "admin"
+"avatar_urls": {#285 ▶}
+"meta": []
+"_links": {#281 ▶}
}
1 => {#274 ▼
+"id": 2
+"name": "Prima"
+"url": ""
+"description": ""
+"link": "http://mywebsite.com/author/prima/"
+"slug": "prima"
+"avatar_urls": {#272 ▶}
+"meta": []
+"_links": {#279 ▶}
}
2 => {#288 ▼
+"id": 3
+"name": "TEST ER"
+"url": ""
+"description": ""
+"link": "http://mywebsite.com/author/testing/"
+"slug": "testing"
+"avatar_urls": {#289 ▶}
+"meta": []
+"_links": {#291 ▶}
}
]
WordPress doesn't provide API to check user exists or not, however you can check this by using List Users API.
Here is what I have done in Laravel:
$client = new \GuzzleHttp\Client([
// Base URI is used with relative requests
'base_uri' => 'http://www.example.com',
'headers' => ['Content-Type' => 'application/json', "Accept" => "application/json"],
]);
$response = $client->get('users/', [
'query' => [
'search' => 'example#email.com',
]
]);
return json_decode($response->getBody());
With Authorization:
Install this https://github.com/WP-API/Basic-Auth plugin and update headers, $username & $password refers to WP admin credentials.
$client = new \GuzzleHttp\Client([
// Base URI is used with relative requests
'base_uri' => 'http://www.example.com',
'headers' => ['Content-Type' => 'application/json', "Accept" => "application/json", 'Authorization' => 'Basic ' . base64_encode( $username . ':' . $password ),],
]);

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

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