Get subscription ID from Woocommerce order - woocommerce

I have added some fields during checkout process and I need to store it in my DB and connect them to the order.
Right now my code works but it add the data to the subscription, not the connected order.
This is my code:
foreach($this->fields as $key=>$value){
if (!empty($_POST[$key]) && trim($_POST[$key]) != '') {
update_post_meta($order_id, $this->prepare_field_name($value['label']), sanitize_text_field($_POST[$key]));
}
}
And this is the action:
add_action('woocommerce_checkout_update_order_meta', [$this,'zerouno_customise_checkout_field_update_order_meta_for_subscriptions']);
How can I get the parent order and add the same data to it?

Related

WooCommerce REST API - filter what meta_data is sent in orders

Problem
We are using Zapier to fetch orders from WooCommerce, through the REST Api. We encountered an error that Zapier can't recieve some orders because of the data sent by WooCommerce is to large (more than 7MB).
This is caused by the plugin Fancy Product Designer, which sends a PNG image as a base64 string in the line_items meta_data (see example of this in the image above).
Can't find any documentation or hooks on how to filter the order data being sent by the Api.
Suggested solution
We need to filter the order data that WooCommerce is sending, and avoid sending the line_items -> meta_data -> field where the key is _fpd_product_thumbnail.
(We can't delete the field, since its used internally for other cases.)
With the example provided by #VijayHardaha I was able to put together a working code.
For anyone facing the same issue with Fancy Product Designer sending to large data to Zapier, you can use the following code to remove the image data from the REST API for Zapier only.
add_filter('woocommerce_rest_prepare_shop_order_object', 'filter_order_response', 10, 3);
function filter_order_response($response, $post, $request){
global $wpdb;
$zapier_user_id = 1320; // User ID of the "Zapier" account in WordPress
if(get_current_user_id() == $zapier_user_id) {
$i = 0;
$lineItemsCount = count($response->data["line_items"]);
while($i < $lineItemsCount) {
$j = 0;
$metaDataCount = count($response->data["line_items"][$i]["meta_data"]);
while($j < $metaDataCount) {
if($response->data["line_items"][$i]["meta_data"][$j]["key"] == "_fpd_product_thumbnail") {
$response->data["line_items"][$i]["meta_data"][$j]["value"] = "";
$response->data["line_items"][$i]["meta_data"][$j]["display_value"] = "";
}
$j++;
}
$i++;
}
}
return $response;
}

How to copy an order item meta from the parent item to the child order item in a Woocommerce Subscription?

I'm running a function hooked to woocommerce_order_status_completed that uses an API to get a phone number and pin from an external source and save that in a meta key on some order items. Some of these order items are subscriptions.
With the current code, when a Woocommerce subscription renewal order runs automatically, it fires the API and gets a new set of call-in data, but I want to stop it from doing that.
I need to check if a completed order is a subscription renewal and if so, skip the API call and instead get the renewed item's parent meta data and insert it into the that child items meta.
The top portion of the code I have tried here is not working. The API call portion of the code within else{} is working so I have truncated it.
add_action ( 'woocommerce_order_status_completed', 'add_item_meta_or_run_api', 10 , 1);
function add_item_meta_or_run_api( $order_id ) {
$order = wc_get_order( $order_id );
// if (wcs_order_contains_subscription( $order, 'renewal' )){ //check if the order contains a renewal subscription
if (wcs_order_contains_renewal( $order_id)){ //Updated: a better way to do this.
foreach ($order->get_items() as $item_id => $item_obj) { //loop through each rewnewal item
$parent_id = $item_obj->get_parent_id(); // Get the parent order ID for the subscriptions.
$parentSubscriptions = wcs_get_subscriptions_for_order( $parent_id );//get parent order subscriptions
foreach ( $parentSubscriptions->get_items() as $parent_item_id => $subscription_item_obj) { //loop through parent order items and get the meta.
$ParentCallinData = $subscription_item_obj->get_meta('call_in_data');
// Store parenent item call in data in renewal order item meta
wc_update_order_item_meta($item_id,'call_in_data', $ParentCallinData, true);
}
}
}
else {//if there is not a subscription renewal in the order then we run the API
foreach ($order->get_items() as $item_id => $item_obj) {
//Code here has been removed that builds and runs the API call to dynamically get the call-in data and store it in $APIresponse
wc_update_order_item_meta($item_id,'call_in_data', $APIresponse, true); //the APIresponse is added to an order item meta key. I need to insert this meta in each child subscription.
}
}
}

Woo-commerce: allow checkout only if the customer is living in a certain city

I am making a woocommerce website for my supermarket which delivers only to one city(Ras Tanura).
Since it is a supermarket store, I replaced Shipping with Delivery. I'm trying to restrict checking out to allow only customers how live in Ras Tanura to choose a payment method. I don't want people to pay for something that can't be delivered to them. Here is what I tried.
add_filter( 'default_checkout_billing_country', 'change_default_checkout_country' );
add_filter( 'default_checkout_shipping_country', 'change_default_checkout_country' );
function change_default_checkout_country() {
return 'SA'; // country code
}
// default checkout state
add_filter( 'default_checkout_billing_state', 'change_default_checkout_state' );
add_filter( 'default_checkout_shipping_state', 'change_default_checkout_state' );
function change_default_checkout_state() {
return 'RT'; // state code
}
// Setting one state only
add_filter( 'woocommerce_states', 'custom_woocommerce_state', 10, 1 );
function custom_woocommerce_state( $states ) {
// Returning a unique state
return array('SA' => array('RT' => 'Ras Tanura'));
}
// Only one country at checkout
add_filter( 'woocommerce_checkout_fields', 'custom_checkout_fields', 10, 1 );
function custom_checkout_fields( $fields ) {
$fields['billing']['billing_city']['type'] = 'select';
$fields['billing']['billing_city']['options'] = array('Ras Tanura' => 'Ras Tanura');
$fields['shipping']['shipping_city']['type'] = 'select';
$fields['shipping']['shipping_city']['options'] = array('Ras Tanura' => 'Ras Tanura');
return $fields;
}
I have added this code to my functions.php under oceanWP theme.
This code does half of the job. It sure sets the default city to Ras Tanura and it can't be changed by customers, but I tried to order from another city and it accepted my order the only thing that this code has done is writing that the order is coming from Ras Tanura even though it wasn't.
how can I make my website knows the location of the user and prevent or accept checkout based on that?
(accepts if the person is in Ras Tanura and prevents if he lives elsewhere)
Note that I have already set the selling location under woocommerce> setting> general to sell to specific countries and I have chosen this country to SA.
Note: this method make use of third party api "https://ip-api.com/" to
request customer data based on ip address, which allow limited request
(as per website documentation it allow 45 HTTP requests per minute
from an IP address.)
Woocommerce provide geolocate customer setting by default,I have make use of some part of Woocommerce Geolocate code to fix issue.
What below code do : It will locate customer based on ip address and if customer is not belongs to specific location(country and city), it will not allow the customer to go to checkout page, redirect customer to cart error page.
Kindly note that in general setting of woocommerce "Default customer location" is set to Geolocate.
Keep your code as it is , and additionally put below code in your functions.php file,
/*
* This function is used to retrieve location data based on ip address,
* note that each service/api has different response format
*/
function geolocate_customer() {
$ip_address = WC_Geolocation::get_external_ip_address();
$geoipdata = get_transient('geoip_' . $ip_address);
if (false === $geoipdata) {
// you can add more service key : service name, value : service-endpoint
$geoip_services = array(
'ip-api.com' => 'http://ip-api.com/json/%s',
);
$geoip_services_keys = array_keys($geoip_services);
shuffle($geoip_services_keys);
foreach ($geoip_services_keys as $service_name) {
$service_endpoint = $geoip_services[$service_name];
$response = wp_safe_remote_get(sprintf($service_endpoint, $ip_address), array('timeout' => 2));
if (!is_wp_error($response) && $response['body']) {
switch ($service_name) {
case 'ipinfo.io':
$geoipdata = json_decode($response['body']);
//this flag is used for error
$flag = ($geoipdata->error) ? true : false;
break;
case 'ip-api.com':
$geoipdata = json_decode($response['body']);
//this flag is used for error, each api may have different response format
$flag = ($geoipdata->status == 'success') ? false : true;
break;
default:
$geoipdata = '';
break;
}
if ($geoipdata && !$flag) {
break;
}
}
}
// This will store geolocation data so that frequent call to api can be reduced.
set_transient('geoip_' . $ip_address, $geoipdata, WEEK_IN_SECONDS);
}
return $geoipdata;
}
Note : replace 'PUT CITY NAME HERE' with city name you got in $geoipdata variable in below function.
/*
* This function is attached to 'woocommerce_before_checkout_form_cart_notices' hook,
* It will check country,city criteria and if criteria is not matched it will add error
* notice so checkout page is loaded with error message(load cart-errors.php template)
*
*/
function add_cart_notice() {
$geoipdata = geolocate_customer();
if (!empty($geoipdata)) {
if ($geoipdata->city != 'PUT CITY NAME HERE' && $geoipdata->countryCode != 'SA') {
wc_add_notice(__('Add your message here', 'woocommerce'), 'error');
add_action('woocommerce_cart_has_errors', 'print_notices');
}
}
}
add_action('woocommerce_before_checkout_form_cart_notices','add_cart_notice');
/*
* This function is used to show error message on cart page.
*/
function print_notices(){
wc_print_notice('Add your message here', 'error');
}
For testing purpose, you can put below code in functions.php file to get city and other details based on ip address.City name can be accessed using $geoipdata->city. This will output data on website.
$geoipdata = geolocate_customer();
var_dump($geoipdata);

gravity forms to update previously entered entry

following this article:
http://techslides.com/editing-gravity-forms-entries-on-the-front-end
trying to get gravity forms to update a submission rather than create a new one.
problem is that in the
/* https://www.gravityhelp.com/documentation/article/gform_pre_submission */
add_action("gform_pre_submission", "pre_submission_handler");
function pre_submission_handler($form){
if ( strpos($_SERVER['REQUEST_URI'], 'application-edit', 0) !== false ) {
//Get original entry id
parse_str($_SERVER['QUERY_STRING']); //will be stored in $entry
//get the actual entry we want to edit
$editentry = GFAPI::get_entry($entry);
//make changes to it from new values in $_POST, this shows only the first field update
$editentry[1]=$_POST['input_1'];
//update it
$updateit = GFAPI::update_entry($editentry);
header("Location: http://yourdomain.com/apply/application-thank-you/");
//dont process and create new entry
die();
}
}
section of the code, the header redirect is not functioning. Any suggestions?

Drupal - Hide block with PHP code

I've installed the module - http://drupal.org/project/formblock (Enables the presentation of node creation forms in blocks)
I've enabled it for a particular content type and then exposed that block, to show when an Organic Group node is being viewed.
What I would like to do is hide that block if the current logged in user, is not the author of the Organic Group node being viewed. i.o.w I only want the organic group author to see that block.
thanks in advance :)
You can use 'PHP block visibility settings' to achieve what you want here. Using PHP you can query the database, and check whether the logged in user is the same user that created the node in the organic group.
There is an example already on drupal.org that I have adapted (you will probably need to customise this further) -
<?php
// check og module exists
if (module_exists('og')){
// check user is logged in
global $user;
if ($user->uid) {
// check we've got a group, rights to view the group,
// and of type "group_type" - change this to whichever group you want to restrict the block to
// or remove the condition entirely
if (($group = og_get_group_context()) && node_access('view', $group) && ($group->type == 'group_type') ) {
// check current user is a team admin as they should get access
if (og_is_node_admin($group)) {
return TRUE;
}
// check to see if the current user is the node author
if (arg(0) == 'node' && is_numeric(arg(1))) {
$nid = arg(1);
$node = node_load(array('nid' => $nid));
if ($node->uid == $user->uid) {
return TRUE;
}
}
}
}
}
return FALSE;
?>

Resources