Pulling shipping details from one wordpress plugin into another - php

I believe I am close but entirely unsure as my limited php knowledge is based on trial and error. I am trying to pull data from a plugin that creates my shipping label into a plugin that tracks shipping. Specifically Elex EasyPost into Advanced Shipping Tracking.
I have an example snippet for shipstation integration from AST here:
<?php
add_action( 'woocommerce_shipstation_shipnotify', 'add_tracking_information_into_order', 10, 2 );
function add_tracking_information_into_order($order, $tracking_details){
$order_id = $order->get_id();
$args = array(
'tracking_provider' => $tracking_details['carrier'],
'tracking_number' => wc_clean( $tracking_details['tracking_number'] ),
'date_shipped' => wc_clean( $tracking_details['ship_date'] ),
'status_shipped' => 1,
);
$ast = new WC_Advanced_Shipment_Tracking_Actions;
$tracking_item = $ast->insert_tracking_item( $order_id, $args );
}
It should be similar but obviously I need to replace the hook and the items in the array. Here is what Elex sent me when asked for the hooks they are using.
get_post_meta($order_id, ‘wf_easypost_labels’);
Sample output:
array(
0=>(‘url’=>label_url,’tracking_number’=> (string)’tracking code’,’integrator_txn_id’=> ‘integerator_id’,’shipment_id’=>’package_shipment_id’,’order_date’=>order_date,’carrier’=>EX:USPS,”link”=>tracking_link,);//First package
1=>(‘url’=>label_url,’tracking_number’=> (string)’tracking code’,’integrator_txn_id’=> ‘integerator_id’,’shipment_id’=>’package_shipment_id’,’order_date’=>order_date,’carrier’=>EX:USPS,”link”=>tracking_link,);//Second package
)
So here is my attempt to use their array in my own snippet:
<?php
add_action( 'woocommerce_checkout_update_order_meta', 'add_tracking_information_into_order', 10, 2 );
function add_tracking_information_into_order($order, $myship_func){
$myship_func = get_post_meta($order_id, 'wf_easypost_labels');
$order_id = $order->get_id();
$args = array(
'tracking_provider' => $myship_func['carrier'],
'tracking_number' => wc_clean($myship_func['tracking code']),
'date_shipped' => wc_clean($myship_func['order_date']),
'status_shipped' => 1,
);
$ast = new WC_Advanced_Shipment_Tracking_Actions;
$tracking_item = $ast->insert_tracking_item( $order_id, $args );
}
When the order is initially filled and the label is generated Elex grabs all the data from and sticks it in the meta. I need to pull that meta either at the time of generation or post generation and stick it in the AST fields.
My main question is thus - Am I on the right track here? Do I just need to figure out the correct hook or is my method for accessing the Elex array incorrect? Again, I usually compare codes, slice and dice, and get things to "look right" and then they work (or not). I myself don't have too deep of knowledge about arrays or class functions (which I believe the Elex one is).
In this case the code is silently failing so I suspect it is the hook involved or a combination of the hook and my code.

Related

Woocommerce & Opayo: Add a custom field to the data sent to the API

Very specific issue but, I've been dragged onto an issue with our companies Payment Gateway on our Wordpress / Woocommerce website where we are using the Opayo Plugin (For Opayo Direct).
The issue is:
When originally setup, there was no template / option selected for the Reference field on the data / object sent to the API
The guys originally doing the website then tried contacting the original developer of this now unsupported plugin to which they was sent some code to put into another plugin named PHP Injection the code was similar to below:
add_filter( 'opayo_direct_custom_field_vendordata', 'my_opayo_direct_custom_field_vendordata', 10, 2 );
function my_opayo_direct_custom_field_vendordata ( $vendordata, $order ) {
// Get Order ID
$order_id = $order->get_order_number();
$reference = "test_" . $order_id;
// Get the reference field - set '_reference_field' to the meta_key from your order
if( isset( get_post_meta( $order_id, '_reference_field', TRUE ) ) ) {
$vendordata = get_post_meta( $order_id , '_reference_field', TRUE );
//$vendordata['_reference_field'] = $reference; ### Commented as I'm unsure if this is correct
}
return $vendordata;
}
After doing numerous testing and small changes, still nothing seems to be showing up in the Reference field in Opayo itself?
Please tell me someone has encountered this situation before or knows what I might be missing, it's been a while since I've touched PHP
First you mot use $order->get_order_number()when trying to get order meta data but use $order->get_id() with get_post_meta() function instead.
Now you can also use the WC_Data method get_meta() to be used on $order object variable.
What you need to find out is the key slug that you need to use to incorporate that custom field value to the vendor data via opayo_direct_custom_field_vendordata filter hook.
Try the following (where I use 'reference' as key slug, to be replaced with the right slug):
add_filter( 'opayo_direct_custom_field_vendordata', 'my_opayo_direct_custom_field_vendordata', 10, 2 );
function my_opayo_direct_custom_field_vendordata ( $vendor_data, $order ) {
$reference = $order->get_meta('_reference_field');
if ( ! empty($reference) ) {
$vendor_data['reference'] = $reference;
}
return $vendor_data;
}
or using get_post_meta() function:
add_filter( 'opayo_direct_custom_field_vendordata', 'my_opayo_direct_custom_field_vendordata', 10, 2 );
function my_opayo_direct_custom_field_vendordata ( $vendor_data, $order ) {
$reference = get_post_meta($order->get_id(), '_reference_field', true);
if ( ! empty($reference) ) {
$vendor_data['reference'] = $reference;
}
return $vendor_data;
}
It could better work…
Alright, so, I contacted Opayo myself to see what the Mapping was for the Reference column on the Opayo website and what data that is sent to the API is mapped to that Reference column in the table.
Apparently the value sent to the API that corresponds to this is the VendorData (Not required, 200 Char limit, free-text)
So, to fix this, I had to:
Open the Plugin Editor on Wordpress
Select the woocommerce-gateway-sagepay-form Plugin
Navigate and select the woocommerce-gateway-sagepay-form/classes/direct/sagepay-direct-request-class.php file
I then scrolled to Line 335 inside of the $end array, I then added the field of VendorData as seen by the code below:
$end = array(
"CustomerEMail" => $order->get_billing_email(),
"ClientIPAddress" => $this->get_ipaddress(),
"AccountType" => $this->accounttype,
"ReferrerID" => $this->referrerid,
"Website" => site_url(),
"VendorData" => '#######',
"Crypt" => MD5( $this->open_salt . $order->get_order_key() . $this->close_salt ),
);
And then set the ####### to the Value I needed to send to Opayo to show in the Reference column in the payments table.
Then just to be sure it wasn't going to get pruned (Again, not touched PHP for a while, I went to (NOW) Line 378 and commented it out, see below:
// Customiseable fields
$end['TransType'] = apply_filters( 'opayo_direct_custom_field_transtype', '01', $order );
//$end['VendorData'] = apply_filters( 'opayo_direct_custom_field_vendordata', '', $order );
Saving this, then when an Order / Purchase was made, the Reference field on Opayo's website was populated with what I set the VendorData to.
Quick Note: The VendorData field is max of 200 characters and only Aa or 0-9, I had a couple of failed attempts when I was trying to have _ until I searched the error I received on this page:
https://www.opayo.co.uk/support/error-codes?keyword=3189
I hope that my issue and resolution helps someone in the future and sorry for anyone's time I wasted!

Hide products published by certain users on Woocommerce

I'm trying to hide products in Woocommerce according to the user ID who published them.
I have created the following code but it doesn't work well.
function Products_for_vendor() {
$args = array( 'post_type' => 'product', 'post_author' => '2' );
$products = get_posts( $args );
foreach ($products as $product->ID) {
$post_id = $product->ID
$terms = array( 'exclude-from-catalog', 'exclude-from-search' );
wp_set_object_terms( $post_id, $terms, 'product_visibility', false );
}
}
add_action( 'init', 'Products_for_vendor' );
to hide the post I extracted the code mentioned in this query: Change product visibility via PHP on Woocommerce 3+
Any help or comment is well received.
Thanks in advance.
You shouldn't be changing things like this directly - WooCommerce has special functions to ensure future compatibility with any database structural changes, and to ensure that product data is properly synchronised within its internal caches.
Instead, inside of your foreach loop, use this:
// Get an instance of the product
$theproduct = wc_get_product($product->ID);
// Change the product visibility (options are: 'hidden', 'visible', 'search' and 'catalog'.
$theproduct->set_catalog_visibility('hidden');
// Finally, save and sync the product changes
$theproduct->save();

WooCommerce remove_cart_item not removing items when logged in

Playing around with WooCommerce, trying to call remove item in a custom api implementation.
I can successfully get a list of cart items and add items to the cart in similar fashion. Yet, despite the code being nearly identical on every guide I can find, I cannot get the cart item to be removed.
I get the cart items something like this:
$ret = array();
global $woocommerce;
$items = $woocommerce->cart->get_cart();
foreach($items as $item => $values) {
$product = $values['data'];
$p = array(
'cart_item_key' => $item,
'id' => $product->get_id(),
'name' => $product->get_name(),
'slug' => $product->get_slug(),
'price' => $product->get_price(),
'description' => $product->get_description(),
'short_description' => $product->get_short_description(),
'permalink' => get_permalink( $product->get_id() ),
'quantity' => $values['quantity']
);
$ret[] = $p;
}
return $ret;
Gives me a nice clean array back I can see in the response.
I then take the cart_item_key and pass it back in to another method like so:
$payload = $request->get_params();
$ret = array();
global $woocommerce;
if ($payload['cart_item_key']){
$cartItemKey = WC()->cart->find_product_in_cart( $payload['cart_item_key'] );
$woocommerce->cart->remove_cart_item( $cartItemKey );
unset( $woocommerce->cart->cart_contents[$cartItemKey] );
}
return $ret;
I can see that $payload['cart_item_key'] is indeed the string value I expect to see that passed into the call. I can also see that $cartItemKey is the identical string value, so I'm 99.8% certain that I have the right value to pass in.
The remove_cart_item and unset methods are two different implementations I've seen and neither seems to have an effect. I've also tried using WC() in place of the global $woocommerce to zero success. Whether I query the cart items again here and return them, or just refresh the page, all items are still in the cart.
There is zero server caching I'm aware of - everything I know about I have specifically turned off for this sandbox.
Update
This does appear to work as expected in a fresh session. For some reason, when I'm logged in as the admin for the site, I am unable to clear out my cart, and no errors are being logged for anything like this on the server.

Ordering related products by ID (DESC) in WooCommerce

So here's the problem that i ran into. I'm trying to show new products in the related products tab on a WooCommerce Store (WP 4.9.6, WooCommerce 3.3.5), but no matter what i try it returns the very same results, ordering them according to the arguments i have in the array. What i can't seem to make it do, is change the way the query works because it seems to me that it always runs the same thing and gives me the same rows from the database ordered according to my arguments.
add_filter( 'woocommerce_output_related_products_args', function( $args )
{
$args = wp_parse_args( array('orderby' => 'date','order' => 'DESC','posts_per_page' => 4), $args );
return $args;
});

Check for duplicate Wordpress Post with Custom Meta Data on Publish

I have a site that uses a custom meta-box with the following fields using Meta-Box plugin. Code is as follows
`
$meta_boxes[] = array(
'title' => 'MLS ID',
'pages' => array('property'),
'fields' => array(
array(
'name' => 'MLS ID',
'id' => "IntegratorPropertyID",
'desc' => 'MLS: e.g. 240091025-217',
'type' => 'text',
),
array(
'name' => 'Test MLS',
'id' => "mlsTest",
'desc' => 'Test MLS for Duplicate',
'type' => 'button',
),
),
'validation' => array(
'rules' => array(
"IntegratorPropertyID" => array(
'required' => true
),
),
'messages' => array(
"IntegratorPropertyID" => array(
'required' => 'MLS is required',
),
)
)
);
Now what im looking for is to add an 'add_action( 'save_post', 'checkMLS' );' function that checks all previous CPT property for MLS number to make sure it hasn't been input before. The code I used was:
function checkMLS( $post_id ) {
$slug = 'property';
if ( $slug != $_POST['post_type'] ) {
return;
}
$mls2 = rwmb_meta('IntegratorPropertyID', 'type=text', $post_id);
$args = array( 'post_type' => 'property' );
$loop = new WP_Query( $args );
while ( $loop->have_posts() ) : $loop->the_post();
$this1 = get_the_ID();
$mls1 = rwmb_meta('IntegratorPropertyID', 'type=text', $this1);
if ( $mls2 == $mls1 ) {
$my_post = array(
'ID' => $post_id,
'IntegratorPropertyID' => 'DUPLICATE!'
);
wp_update_post($my_post);
return;
}
endwhile;
}
add_action( 'save_post', 'checkMLS' );
That code is found in the functions.php and when I try to post the screen goes white. Debugging mode does not offer any help either. :/
I'm sure I'm making some programming Major mistake somewhere. Can someone point it out? or maybe point me in the right direction? or suggest something completely different?
Thanks
Keith
OK. Firstly, your white page with no indication of why, is probably either an 'out of memory' error, or a php 'max execution time' error. This stims from one major flaw in the way the checkMLS() function works. The flaw is that you are literally cycling through ALL 'property' posts in your database. Depending on the size of your dataset, this can be a LOT, especially considering you are dealing with MLS lists.
MY RECOMMENDATION:
Figure out how the rwmb_meta() function is grabbing it's information. It is probably just a wrapper function for the get_post_meta() function, but maybe not. Assuming that it is, I propose doing the following, which I will explain the details of after as well as in the comments:
// the save_post action runs after a post has been saved/created, and has two parameters
// param 1: the id of the post
// param 2: the post object
function checkMLS($post_id, $post) {
// use the post object post_type to determine if this is a property or not.
// it will be a lot more reliable
if ($post->post_type != 'property') return;
// meta_key should be equal to the 'meta_key' field in the wp_postmeta table, for the
// id you are trying to check against. your example used IntegratorPropertyID.
// again you may want to check rwmb_meta() function to figure out if there is a
// 'prefix' or 'suffix' added to this. despite that, it is almost certainly going to
// be looking in the wp_postmeta table, so this should work nicely
$meta_key = 'IntegratorPropertyID';
// look up the current mls id for this post, which you just saved/created
$mls_id = get_post_meta($post_id, $meta_key, true);
// lookup in the actual database table for any matching row, that has the same MLS id
// that is not this post.
global $wpdb;
$q = $wpdb->prepare('select post_id from '.$wpdb->postmeta.' where meta_key = %s and meta_value = %s and post_id != %d limit 1', $meta_key, $mls_id, $post_id);
$exists = $wpdb->get_var($q);
// if it already exists, mark the value as a duplicate
if ($exists) update_post_meta($post_id, $meta_key, 'DUPLICATE!');
}
// add your check function late in the actions, at priority 10000
add_action('save_post', 'checkMLS', 10000, 2);
From the top, we create a callback with two params, because the save_post action sends two, $post_id and $post. Since save_post runs after the post has been saved, you already have an object ($post) which has all the post info in it. We can then use that $post object to determine the type of the post, which is more reliable than looking at a $_REQUEST value, mainly because $post is pulled directly from the database and passed to you.
Now, as stated before I assume that rwmb_meta() is just a kinda wrapper function for get_post_meta(). It probably adds a prefix or suffix to the $meta_key, but a little research into the rwmb_meta() function should tell you how the $meta_key is changed when passing it to the get_post_meta() function, and you can modify $meta_key from there. With the correct $meta_key, we can now get the MLS id of the property you just saved.
With that MLS id, we need to do a direct lookup in the database, to determine if there is another property with that id already. While the way in your demo function does work on small sets of data, there is no way it would work on any appreciable amount of properties. Thus the direct approach is needed. Simply we craft some special SQL to look in the wp_postmeta table for any post_id that has an MLS id that is equal to the one entered for this property, that is not this property. If we find one match that is not this property, then it is a dupe. If it is a dupe, we need to mark it as a dupe.
Notice that this solution does not do any looping at all. There is no potential for it to loop over 10000 records to find a dup id. This is streamlined. It looks up the id directly in the db, to see if there are dups.
Hopefully this is helpful to you, and hopefully others find it helpful as well. My company does WordPress work, almost exclusively. Through our years of working with WordPress we have encountered problems from the super simple to the overly complex. This same problem, in different settings, has manifested with many of our clients. This solution is simple and to the point, though highly custom. It will however, work.

Categories