Woocommerce API - add additional images - woocommerce

I am trying to add another image to a product using the Woocommerce API.
However, the API overwrites the existing image(s). I have tried with no ID, no title, unique ID, etc.
Is there a way to have it append a new image, not touching the existing image?
{"images": [
{
"title": "temp1",
"position": 3,
"src": "https://www.example.com/myimage.jpg"
}]}
Turns out that you can use an existing image if you use the internal post ID of the image as the ID tag:
{ "images":
[ { "id" : 587 } ]
}
This will overwrite the existing image.
So, if I can figure out a way to get all the image ids of the product, I can re-add them all and append the new image onto the end...
see: WooCommerce API creates images in media even if they exist

So I couldn't figure out how to stop woocommerce from overwriting all the images when I wanted to add one, so I wrote code that appends a new image onto the list of images.
//GET CURRENT IMAGE IDs FOR A PRODUCT AND BUILD JSON OF THEM
$product_id = '652';
$product = new WC_product($product_id);
$attachment_ids = $product->get_gallery_image_ids();
array_unshift($attachment_ids, get_post_thumbnail_id($product_id));
//BUILD JSON OF EXISTING IMAGE IDS
foreach( $attachment_ids as $attachment_id ) {
$json_images .= '{"id":' . $attachment_id . '}';
$json_images .= ($i<count($attachment_ids) ? ',' : '');
}
echo "<br>" . $json_images;
//POST AN IMAGE TO AN AUCTION
$host = 'https://beta.blohbloh.com/wp-json/wc/v3/products/' . $product_id;
$consumer_key='ck_2364';
$consumer_secret='cs_12ce';
//NEEDS TO INCLUDE ALL PREVIOUS IMAGE IDS IN JSON FORMAT
$payload = '{"images": [';
$payload .= $json_images;
$payload .= '{"src":';
//sample image to append
$payload .= '"https://somesite.com/someimage.jpg"';
$payload .= '}]}';
$process = curl_init($host);
curl_setopt($process, CURLOPT_HTTPHEADER, array('Content-Type: application/json', $additionalHeaders));
curl_setopt($process, CURLOPT_HEADER, 1);
curl_setopt($process, CURLOPT_USERPWD, $consumer_key . ":" . $consumer_secret);
curl_setopt($process, CURLOPT_TIMEOUT, 30);
//curl_setopt($process, CURLOPT_POST, 1);
//curl_setopt($process, CURLOPT_POSTFIELDS, $payload);
curl_setopt($process, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($process, CURLOPT_POSTFIELDS,$payload);
curl_setopt($process, CURLOPT_RETURNTRANSFER, TRUE);
$return = curl_exec($process);
curl_close($process);

Related

How to save "text" from Twitter JSON data to a ACF field?

I need help with my code. What it's suppose to do is a user enter the full URL from twitter into a text field ('https://twitter.com/openbayou/status/1487977976033685506') and when the post is saved, it breaks down the url by using explode and then gets data from a tweet via Twitter API v2.
My code:
$tweet_url_raw = get_field('twitter_url');
$parts = explode('/', $tweet_url_raw);
$url = 'https://api.twitter.com/2/tweets/' . $parts[5] . '?expansions=author_id&tweet.fields=created_at&user.fields=username,verified';
$authorization = 'Authorization: Bearer ' . get_field_object('twitter_bearer_token', 'option')['value'];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json' , $authorization ));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
$result = curl_exec($ch);
curl_close($ch);
$tweet_data = json_encode($result);
$tweet_data2 = json_decode($tweet_data);
The code above does get the data:
{"data":{"text":"SEC Super Bowl!!","created_at":"2022-01-31T02:36:09.000Z","author_id":"1471331","id":"1487977976033685506"},"includes":{"users":[{"name":"OpenBayou","verified":false,"id":"1471331","username":"openbayou"}]}}
The problem I'm having is when I'm trying to get individual data from the output. I'm trying to update a text field called tweet with the text from text. I've tried to use update_field('tweet', $tweet_data2->data, $post_id); and it was blank. When I use update_field('tweet2', $tweet_data2["data"], $post_id); all it saves is {
Any idea what I'm doing wrong?
You are almost there.
Since you omitted the associative parameter for json_decode, it defaults to false so you get an object, not an array. You then need to reference it as such:
$tweet_data2 = json_decode($tweet_data);
echo 'Tweet text: ' . $tweet_data2->data->text;
If you prefer to work with arrays, simply pass true to json_decode:
$tweet_data2 = json_decode($tweet_data, true);
echo 'Tweet text: ' . $tweet_data2['data']['text'];
More info on json_decode can be found at the PHP Manual site:
https://www.php.net/manual/en/function.json-decode.php

Sending Order Details From WooCommerce To External System Over API

I am trying to send woocommerce order to netsuite via an external api I have written. I am nw to woocommerce and do not fully get how to add this functionality.
I have added the following code to the functions.php file in public_html/wp-content/themes/reverie-master/
add_action( 'woocommerce_payment_complete'', 'wdm_send_order_to_ext');
function wdm_send_order_to_ext( $order_id ){
// get order object and order details
$order = new WC_Order( $order_id );
$email = $order->billing_email;
$phone = $order->billing_phone;
//Create the data object
$orderData = array(
'customer_email' => $email,
'customer_phone' => $phone
);
$apiData = array(
'caller' => 'woocommerce',
'json' => $orderData,
'key' => 'MY_SECRET_KEY'
);
$jsonData =json_encode($orderData);
$url = "";
$api_mode = 'sandbox';
if($api_mode == 'sandbox'){
// sandbox URL example
$url = "https://forms.netsuite.com/app/site/hosting/scriptlet.nl?script=XXX&deploy=X&compid=XXXXXXX_SB1&h=XXXXXXXXXXXXXXXX";
}
else{
// production URL example
$url = "";
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($jsonData));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec ($ch);
curl_close ($ch);
// the handle response
if (strpos($response,'ERROR') !== false) {
print_r($response);
} else {
// success
}
}
I have tested the brunt of this code, just the parts that do not concern woocommerce in a different site and I can see the data showing up in NetSuite. However, when I go through my store and place an order, and take payment, I do not see the data come into NetSuite. Do I have this code in the right location? Is there something I am missing?
Update
I installed the plugin Code Snippets and added the code there instead. Set it to Run snippet everywhere. Still no luck.
Looks like you have a double quote on the first link
change
add_action( 'woocommerce_payment_complete'', 'wdm_send_order_to_ext');
to
add_action( 'woocommerce_payment_complete', 'wdm_send_order_to_ext');
Rather than use curl - you can always use the build in WordPress wp_remote_post() function
Also make sure you have WP_DEBUG set to true in wp-config.php while testing.

Need a custom function to be accessible throughout WordPress

I have this notification function and need to call it in different places of the code. I need to put it some where which be accessed by any files inside my child theme as well as in the plugins directory.
function send_notification($tokens, $message)
{
$url = 'https://fcm.googleapis.com/fcm/send';
$fields = array(
'registration_ids' => $tokens,
'data' => $message
);
$headers = array(
'Authorization:key = My_Token',
'Content-Type: application/json'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
$result = curl_exec($ch);
if ($result === FALSE) {
die('Curl failed: ' . curl_error($ch));
}
curl_close($ch);
return $result;
}
First question, Where to put it, currently it is in functions.php?
Second question, how to call it in different places?
Any solution and reference would be appreciated. Thank you.
Since you've got a function with a broad scope, consider giving it a more unique name to prevent naming conflicts, such as naser_send_notitification() instead of just send_notification, or if you can - consider using a namespace or class.
Now to answer your question, functions.php is actually usually a safe bet for "broad scope" functions that need to be accessible just about anywhere. If you look at the Action Reference you'll see that after_setup_theme is fired relatively early-on, allowing your function to be accessible from that hook or later - since it will be available during this moment. However, it does come after plugins_loaded, so if you need it before then, you'll need to turn it into a plugin with a File Header or an "MU Plugin".
If you need it be accessible at effectively the earliest momement, consider putting it in a file in /wp-content/mu-plugins/ and give it a name, even something like custom-functions.php. These files are called Must-Use Plugins. Files in this directory are always loaded, and always run before anything else, so functions declared in them are accessible incredibly early. This is typically where I put code I need to make sure is theme independent, is always on and can't be deactivated.
So effectively:
1) Rename your function to something a bit more unique, like naser_send_notitification()
2) Put this code in /wp-content/mu-plugins/custom-funtions.php
3) Now you should be able to call naser_send_notification( $tokens, $message ) in any function or hook that comes after the muplugins_loaded hook (which is just about anywhere)
Here is the Solution:
every thing is commented on each line
function do_something( $a = "", $b = "" ) { // create your function
echo '<code>';
print_r( $a ); // `print_r` the array data inside the 1st argument
echo '</code>';
echo '<br />'.$b; // echo linebreak and value of 2nd argument
}
add_action( 'danish', 'do_something', 10, 2 );
// create your own action with params('action name', 'callback funtion', priority, num_of params)
then Hook everywhere you need
$a = array(
'eye patch' => 'yes',
'parrot' => true,
'wooden leg' => 1
);
$b = __( 'And Hook said: "I ate ice cream with Peter Pan."', 'textdomain' );
// Executes the action hook named 'danish'
do_action('danish', $a, $b);
that's it.
I believe wordpress shortcodes would be the best approach to handle this. Because messing with wordpress core files is not good practice and leads to several issues like code removal on upgrade etc.
There are several benefits of shortcodes and for your specific problem it would be beneficial because:
can be placed in parent/child themes functions.php
can be accessible in php code files and in dashboard editor as well
Complete Code: (just place inside functions.php)
function send_notification( $atts )
{
extract(shortcode_atts(array(
"tokens" => '',
"message" => ''
), $atts));
$url = 'https://fcm.googleapis.com/fcm/send';
$fields = array(
'registration_ids' => $tokens,
'data' => $message
);
$headers = array(
'Authorization:key = My_Token',
'Content-Type: application/json'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
$result = curl_exec($ch);
if ($result === FALSE) {
die('Curl failed: ' . curl_error($ch));
}
curl_close($ch);
return $result;
}
add_shortcode('send-notification', 'send_notification');
Call it anywhere in theme or plugin: (like this)
wordpress editor:
[send-notification token=XXXX message="hello"]
theme/plugin files:
<?php echo do_shortcode('[send-notification token=XXXX message="hello"]'); ?>
Useful Resources:
WordPress Shortcode with Parameters
A tutorial on Wordpress Shortcodes
Creating Shortcode with different type of parameters
According to this question :
step 1: write your function into a class inside your plugin
step 2: create an object of that class into your theme
step 3: access your function by that object.
// inside your plugin
class foo {
public function send_notification() {
return "whatever you want";
}
}
// inside your themes functions.php
$foo_object = new foo();
// use the object to access your function:
$foo_object->send_notification();

LinkedIn API - how to post company update using Oauth2 & PHP

I am trying to modify LinkedIn's sample authorization code to post a company update.
Have the original code example working, meaning I can login to my user profile. So the next step would be posting the update.
Have found some info on the Internet and here at stackoverflow.com, and the result is the function PostUpdate() found in the code below. The rest of the code pretty much comes straight from the Linkedin code sample.
So this code seems to run, I get no errors reported, but I also get no update on the company page. There is one issue I notice, after successfully logging-in, the code prints "Hello $user->firstName $user->lastName." but my name does NOT show up on the screen. The "Hello" does, so perhaps this indicates where a problem might be found.
<?php
//config.php contains the API KEY, SECRET, AND COMPANY ID
//define('API_KEY', 'your key');
//define('API_SECRET', 'your secret');
//define('COMPANY_ID', 'your company id');
require_once('config.php');
// You must pre-register your redirect_uri at https://www.linkedin.com/secure/developer
define('REDIRECT_URI', 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['SCRIPT_NAME']);
define('SCOPE', 'r_basicprofile r_emailaddress w_share rw_company_admin');
// You'll probably use a database
session_name('linkedin');
session_start();
// OAuth 2 Control Flow
if (isset($_GET['error'])) {
// LinkedIn returned an error
print $_GET['error'] . ': ' . $_GET['error_description'];
exit;
} elseif (isset($_GET['code'])) {
// User authorized your application
if ($_SESSION['state'] == $_GET['state']) {
// Get token so you can make API calls
getAccessToken();
} else {
// CSRF attack? Or did you mix up your states?
exit;
}
} else {
if ((empty($_SESSION['expires_at'])) || (time() > $_SESSION['expires_at'])) {
// Token has expired, clear the state
$_SESSION = array();
}
if (empty($_SESSION['access_token'])) {
// Start authorization process
getAuthorizationCode();
}
}
// Congratulations! You have a valid token. Now fetch your profile
$user = fetch('GET', '/v1/people/~:(firstName,lastName)');
print "Hello $user->firstName $user->lastName.";
// temporary message content for test purposes
$xml_txt = "<?xml version='1.0' encoding='UTF-8'?>
<share>
<visibility>
<code>anyone</code>
</visibility>
<comment>Testing a full company share!!!!!</comment>
<content>
<submitted­-url>https://www.example.com/test-2.html</submitted-­url>
<title>Test Share with Content</title>
<description>content description</description>
<submitted-image-­url>https://www.example.com/img/internet.jpg</submitted­-image-­url>
</content>
</share>";
//Post the message
$result = PostUpdate($xml_txt);
//Done
exit;
function PostUpdate($message) {
print $_SESSION['access_token'];
$url = 'https://api.linkedin.com/v1/companies/'. COMPANY_ID . '/shares';
// build your message
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $message );
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/xml', 'Authorization: Bearer ' . $this->access_token));
$response = curl_exec($ch);
$http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
print_r($response);
echo $http_status;
}
function getAuthorizationCode() {
$params = array(
'response_type' => 'code',
'client_id' => API_KEY,
'scope' => SCOPE,
'state' => uniqid('', true), // unique long string
'redirect_uri' => REDIRECT_URI,
);
// Authentication request
$url = 'https://www.linkedin.com/uas/oauth2/authorization?' . http_build_query($params);
// Needed to identify request when it returns to us
$_SESSION['state'] = $params['state'];
// Redirect user to authenticate
header("Location: $url");
exit;
}
function getAccessToken() {
$params = array(
'grant_type' => 'authorization_code',
'client_id' => API_KEY,
'client_secret' => API_SECRET,
'code' => $_GET['code'],
'redirect_uri' => REDIRECT_URI,
);
// Access Token request
$url = 'https://www.linkedin.com/uas/oauth2/accessToken?' . http_build_query($params);
// Tell streams to make a POST request
$context = stream_context_create(
array('http' =>
array('method' => 'POST',
)
)
);
// Retrieve access token information
$response = file_get_contents($url, false, $context);
// Native PHP object, please
$token = json_decode($response);
// Store access token and expiration time
$_SESSION['access_token'] = $token->access_token; // guard this!
$_SESSION['expires_in'] = $token->expires_in; // relative time (in seconds)
$_SESSION['expires_at'] = time() + $_SESSION['expires_in']; // absolute time
return true;
}
function fetch($method, $resource, $body = '') {
print $_SESSION['access_token'];
$opts = array(
'http'=>array(
'method' => $method,
'header' => "Authorization: Bearer " . $_SESSION['access_token'] . "\r\n" . "x-li-format: json\r\n"
)
);
// Need to use HTTPS
$url = 'https://api.linkedin.com' . $resource;
// Append query parameters (if there are any)
if (count($params)) { $url .= '?' . http_build_query($params); }
// Tell streams to make a (GET, POST, PUT, or DELETE) request
// And use OAuth 2 access token as Authorization
$context = stream_context_create($opts);
// Hocus Pocus
$response = file_get_contents($url, false, $context);
// Native PHP object, please
return json_decode($response);
}
Finally posted a company update (share) successfully.
One issue that made the LinkedIn code sample (https://developer-programs.linkedin.com/documents/code-samples) non-functional was that file_get_contents() was not working, and this was because allow_url_fopen was not enabled in PHP.ini. I believe allow_url_fopen is not enabled by default, as it is a security issue. I found a work-around online use cUrl. See the code below.
//First, in getAccessToken() replace:
$response = file_get_contents($url, false, $context)
with
$response = curl_get_contents($url);
And here is the code added to the LinkedIn code sample, after the
'print "Hello $user->firstName $user->lastName.";'
// temporary message content for test purposes
$xml_txt = "<?xml version='1.0' encoding='UTF-8'?>
<share>
<visibility>
<code>anyone</code>
</visibility>
<comment>There are a lot of great career opportunities here!</comment>
</share>";
//Post the message
$result = PostUpdate($xml_txt);
//Done
exit;
function PostUpdate($message) {
print 'here in PostUpdate <br />';
print '$message = ' . $message .' <br />';
$url = 'https://api.linkedin.com/v1/companies/'. COMPANY_ID . '/shares';
// build your message
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $message );
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/xml', 'Authorization: Bearer ' . $_SESSION['access_token']));
$response = curl_exec($ch);
$http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
print_r($response);
echo '$http_status = '. $http_status;
}
function curl_get_contents($url)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_URL, $url);
$data = curl_exec($ch);
curl_close($ch);
return $data;
}
Maybe it aint pretty, but after a couple of days struggling with it, I feel surprisingly elated. And thank you LinkedIn for providing a lets-all-reinvent the-wheel code sample with a built-in "issue". If you folks wipe your tail-ends the same half-arsed way you provide code samples, yer walking around with three inches of dried skidmarks in yer undies. Crusty, you know whut I'm sayin.

How to save files to wordpress

I am running my wordpress on localhost, My code retrieves photos from urls and using file_put_contents add them to the current directory, but I need it to add them to /wordpress/wp-content/uploads where wordpress save the manually uploaded files.
$Address = "www.xxx.com/" . $file;
$ch = curl_init();
curl_setopt($ch, CURLOPT_POST, 0);
curl_setopt($ch, CURLOPT_URL, $file);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$url = curl_exec($ch);
curl_close($ch);
$location = "/wordpress/wp-content/uploads/2013/a.jpg";
file_put_contents($location, file_get_contents($url));
if(! function_exists('wp_upload_dir'))
{
define('WP_USE_THEMES',false);
require 'wordpress/wp-load.php';
}
$upload_dir = wp_upload_dir();
echo $upload_dir['path'];
echo $upload_dir['url'];
echo $upload_dir['subdir'];
http://codex.wordpress.org/Function_Reference/wp_upload_bits
// the curl thing from question...results in `$url`
$upload = wp_upload_bits('a.jpg', null, file_get_contents($url));
echo $upload['file'], $upload['url'], $upload['error'];
I think I understand the problem.
This or any equivalent statement should be at the top of the file to load WP:
require_once("path/to/wp-load.php");
The path/to/ is relative and depends on the position of your file. If, for example, your file is located in a folder at wordpress/here, the path should be something like "../wp-load.php", but that's something you have to figure out.
Try displaying errors so you know what's going on, with a code like this one:
ini_set( 'display_errors', TRUE );
error_reporting( E_ALL );
Then, add this code:
$UploadDir = wp_upload_dir();
$UploadURL = $UploadDir['baseurl'];
$location = $UploadURL . "/2013/a.jpg";
Remove:
$location = "/wordpress/wp-content/uploads/2013/a.jpg"; and all code from:
if(! function_exists('wp_upload_dir')) {
down to the last line.
Insert echo statements in the appropriate places to see the results.

Resources