WooCommerce restrict product download by country or region - php

Is there a way/plugin in Wordpress WooCommerce to restrict a certain product from being DOWNLOADED in a certain region. Remember this is not suppose to be site wide, but on a product to product basis.
What I imagine is that on checkout if a product has download restrictions enabled a function pulls the current user's location (country) and compares it against an array of permitted countries for that product. If there is a match the check in proceeds if not, it returns a message informing the user that the product they requested is not available for download in their country. THE QUESTION IS, DOES SUCH A PLUGIN, FEATURE, FUNCTION or SNIPPET exist, if so where?
UPDATE: Seeing that there was no answer I have gone ahead and started creating something on my own. I have no previous PHP experience so please help me make this code concise. You can try it. IS THIS CORRECT?
UPDATE (SOLUTION): Woocommerce now has a built in functionality that checks user location and stores it for the shop owner to use in custom functions, go wild with it :)
The following code goes into your theme's functions.php file. It will add a "Region Settings" panel to your product page's add/edit page under the "General Tab". It has two options, "restriction type:" which can be set to "Allow" or "Deny" and the "Regions: " option where you specify the countries that will be affected. If a product's region settings are not set, it will allow everyone to access it.
/**
* Mazwi WooCommerce Region Control BETA
* ------------------------------------
*
*
*
* Execute code if the user's country (set for each product) is allowed
*
* Author: Taf Makura
* Thanks to Remi Corson's Tutorial
*/
// Display Fields
add_action( 'woocommerce_product_options_general_product_data', 'woo_add_custom_general_fields' );
// Save Fields
add_action( 'woocommerce_process_product_meta', 'woo_add_custom_general_fields_save' );
// Display Fields
function woo_add_custom_general_fields() {
global $woocommerce, $post;
echo '<div class="options_group">';
?>
<?php
// Select
woocommerce_wp_select(
array(
'id' => '_restriction-type',
'label' => __( 'Restriction type', 'woocommerce' ),
'options' => array(
'allow' => __( 'Allow', 'woocommerce' ),
'deny' => __( 'Deny', 'woocommerce' ),
)
)
);
// Create Textarea
woocommerce_wp_textarea_input(
array(
'id' => '_regions',
'label' => __( 'Regions', 'woocommerce' ),
'placeholder' => '',
'desc_tip' => 'true',
'description' => __( 'Please enter two letter country codes. Each country code should be followed by a coma Example: ZW, AU, ZA, US ', 'woocommerce' )
)
);
echo '</div>';
}
function woo_add_custom_general_fields_save( $post_id ){
// Select
$woocommerce_select = $_POST['_restriction-type'];
if( !empty( $woocommerce_select ) )
update_post_meta( $post_id, '_restriction-type', esc_attr( $woocommerce_select ) );
// Textarea
$woocommerce_textarea = $_POST['_regions'];
if( !empty( $woocommerce_textarea ) )
update_post_meta( $post_id, '_regions', esc_html( $woocommerce_textarea ) );
}
The following code goes into the template .php file where the conditional execution is suppose to happen. I can imagine if you place the add to cart loop (add to cart button) here it will allow you to control which products can be bought in certain countries. On a product by product basis.
<?php global $woocommerce;
// Get restriction type (deny or allow) for current product
$restriction_type = get_post_meta( $post->ID, '_restriction-type', true );
// Get region(s) the above restriction type is applied to
$regions = get_post_meta( $post->ID, '_regions', true );
// Turns this string into an array.
$regions_array = (explode(',', str_replace('/\s+/','', $regions)));
// Get users current IP location from WooCommerce
$base_country = (..... YOU NEED TO GET THE USER LOCATION ISO COUNTRY CODE ......)
// If user's current IP location is either allowed, is not denied or is not set in the region settings = success
if( $restriction_type == 'allow' && in_array($base_country , $regions_array) || $restriction_type == 'deny' && !in_array($base_country , $regions_array) || $restriction_type == '' || $regions == '' ) {
if ($restriction_type == '' || $regions == '') {
// Code to execute on success if a product is not set (NOTE: It will not be restricted)
echo('This product\'s region control has not been set, you can set it in WP Admin');
}
// Code to execute on success if a products region settings are set to allow access
echo('YOU ARE IN');
} else {
// Code to execute when region is restricted
echo(' you are restricted,');
}
?>

I'm not sure if you saw/tried this, but according to http://docs.woothemes.com/document/configuring-woocommerce-settings/ you can do what you are asking for.
To configure your shop go to WooCommerce > Settings. Then browse through the content below to get more information on the WooCommerce Options.
Allowed Countries
Here you can select whether you want to sell/ship to too countries, or
a select few – useful if only trading within your own country for
instance. Customers outside your allowed countries will not be able to
checkout.
Specific Countries
Define the countries you’re willing to sell/ship to. You must set the
“Allowed Countries” option to "Specific Countries".

Related

WordPress WooCommerce product attribute set_visible false via functions.php is not stored permanently

Problem
I want to hide all product attributes used for variation purpose in the 'Additional information' section of the product detail page.
Background
I use WordPress 5.5.1 with WooCommerce 4.6.1. I have a lot of products in my WooCommerce shop and nearly all of them have several custom product attributes. Those attributes are used for variations so customers can select e.g. gender and color of a product.
Unfortunately, most of those attributes are set to be visible in the frontend which does not make any sense since those attributes are already used for variation select boxes. Therefore, I want to hide all of those attributes used for variation purpose in the 'Additional information' section of the product detail page.
Possible solutions
Workaround
I found a workaround here https://datafeedrapi.helpscoutdocs.com/article/206-hide-specific-attributes-from-the-additional-information-tab. However, I want to make those changes permanent (in DB).
My current solution which does save visibility changes to DB
add_action( 'admin_init', 'custom_woocommerce_hide_product_attributes_in_descr' );
function custom_woocommerce_hide_product_attributes_in_descr() {
$args = array(
'status' => 'publish',
'type' => 'variable',
'limit' => -1,
'sku' => 'mySKU',
);
$products = wc_get_products( $args );
foreach ( $products as &$product ){
if ($product->has_attributes()) {
$currentProdAttributes = $product->get_attributes();
foreach ($currentProdAttributes as &$productAttribute ) {
$productAttribute->set_visible( false );
}
unset( $productAttribute );
$product->set_attributes($currentProdAttributes);
$id = $product->save();
error_log(wc_get_product($id));
}
}
unset( $product );
}
The main problem is that $id = $product->save(); does not save the changes to database. Did I forget something here?

Woocommerce display custom field data on admin order details

I am using a custom checkout field to give my customers a 'Ship to a business address' option on the checkout page of my woocommerce store. Most of the code is working properly, but I am unable to display whether or not they checked the box in the admin order details in the back end.
I have added a custom checkout field to my woocommerce shop, and saved the data to the order meta:
//add custom checkout field
add_filter( 'woocommerce_after_checkout_billing_form', 'gon_business_address_checkbox_field' );
function gon_business_address_checkbox_field( $checkout ){
woocommerce_form_field( 'business_address_checkbox', array(
'label' => __('<h3 id="business_address_label">Check this box if you are shipping to a business.</h3>', 'woocommerce'),
'required' => false,
'clear' => false,
'type' => 'checkbox'
), $checkout->get_value( 'business_address_checkbox' ));
}
//update order meta
add_action('woocommerce_checkout_update_order_meta', 'gon_update_order_meta_business_address');
function gon_update_order_meta_business_address( $order_id ) {
if ($_POST['business_address_checkbox']) update_post_meta( $order_id, 'Business Address?',
esc_attr($_POST['business_address_checkbox']));
}
Here's where I attempt to display this data on the admin order section. I have followed the previous topics on this as closely as possible, but to no avail.
// Display field value on the admin order edit page
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'my_custom_checkout_field_display_admin_order_meta', 10, 1 );
function my_custom_checkout_field_display_admin_order_meta($order){
echo '<p><strong>'.__('Ship to a Business Address', 'woocommerce').': </strong> ' . get_post_meta( $order->get_id(), '_business_address_checkbox', true ) . '</p>';
}
Is this issue possibly because I'm not using the checkbox in the correct way? The peculiar thing is that I am getting the info to print on the order emails as I wish by using this code:
add_filter( 'woocommerce_email_order_meta_keys', 'my_custom_checkout_field_order_meta_keys' );
function my_custom_checkout_field_order_meta_keys( ) {
if($_POST['business_address_checkbox']){
$ship_to = 'YES';
} else {
$ship_to = 'NO';
}
echo '<h3>Ship to a business address? : '.$ship_to.'</h3>';
}
As you are saving this custom field data, using the meta_key: 'Business Address?'… So you need to use this meta_key to retrieve the data this way:
// Display field value on the admin order edit page
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'custom_checkout_field_display_admin_order_meta', 10, 1 );
function custom_checkout_field_display_admin_order_meta( $order ){
$business_address = get_post_meta( $order->get_id(), 'Business Address?', true );
if( ! empty( $business_address ) )
echo '<p><strong>'.__('Ship to a Business Address', 'woocommerce').': </strong> ' . $business_address . '</p>';
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Tested on WooCommerce 3 and works.

How to disable or remove stock notes from showing in WooCommerce Order edit screen

I have stock management enabled on my WooCommerce store as this is critical being that we sell physical goods and products that we stock in our warehouse. Everything about the inventory management works as we need it to, but because we have it enabled, we're getting extra order notes displaying on the Edit Order screens of WooCommerce. This is causing extra data to be saved to our database and also gets based into QuickBooks as order notes that we just do not need to be there.
I've found in the core WooCommerce the function that is adding this order note, I'm just not sure how to remove it without modifying core files. I'm looking for some sort of way to disable or remove it with a hook, filter, or class extension that can be placed in my sites utility plugin.
Screenshot showing sidebar of Edit Order screen with numerous "stock reduced" messages displayed
The code is in the abstract-wc-order.php file (/woocommerce/abstracts/abstract-wc-order.php) starting at lines 2460:
if ( isset( $item['variation_id'] ) && $item['variation_id'] ) {
$this->add_order_note( sprintf( __( 'Item #%s variation #%s stock reduced from %s to %s.', 'woocommerce' ), $item['product_id'], $item['variation_id'], $new_stock + $qty, $new_stock) );
} else {
$this->add_order_note( sprintf( __( 'Item #%s stock reduced from %s to %s.', 'woocommerce' ), $item['product_id'], $new_stock + $qty, $new_stock) );
}
You can grab the comment id and content via the wp_insert_comment action hook and delete it, which would likely prevent it from being sent to Quickbooks. Using a simple strpos match for "stock reduced from" we can check if the comment is for stock reduction.
add_action('wp_insert_comment', 'remove_stock_comment', 10, 2);
function remove_stock_comment($id, $comment) {
if( strpos($comment->comment_content, 'stock reduced from') !== false ) {
wp_delete_comment( $id );
}
}
To further check whether the comment belongs to an order, you can get the comment's POST ID and check its post_type.
Note: I'm not sure whether this solution would break any other functionality, but this is the only solution I could come up with.

How to limit customers buy one product with woocommerce

I want that customer can purchase only one product from woo commerce whenever they came back to shop page they will be redirected to my account page.
<?php
/**
* Loop Add to Cart
*
* #author WooThemes
* #package WooCommerce/Templates
* #version 2.1.0
*/
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
global $product;
$current_user = wp_get_current_user();
if ( wc_customer_bought_product( $current_user->user_email, $current_user->ID, $product->id)) {
$redirect = $myaccount;
}
i am using the following code placed in loop folder but its not working.
i want that user can purchase product once in lifetime
note - its not about purchasing one product at one time
its like if someone purchased the product Then he/she will never able to purchase any other product.
The loop/add-to-cart.php template creates a link. Your template only lists some variables (where are $redirect and $myaccount defined?) and does not create a link so it doesn't do anything.
A better solution would be to filter the link that is created in the loop/add-to-cart.php template via the woocommerce_loop_add_to_cart_link filter. This way if the item hasn't been purchased you can leave the regular link in tact.
Add the following to your theme's functions.php file:
add_filter( 'woocommerce_loop_add_to_cart_link', 'so_add_to_cart_link', 10, 2 );
function so_add_to_cart_link( $link, $product ){
$current_user = wp_get_current_user();
if ( wc_customer_bought_product( $current_user->user_email, $current_user->ID, $product->id)) {
$link = sprintf( '%s',
esc_url( get_permalink( wc_get_page_id( 'myaccount' ) ) ),
esc_attr( $product->product_type ),
__( 'View my account', 'theme-text-domain' ),
),
}
return $link;
}
Note that the above hasn't been tested, so be wary of typos.
Open your theme functions.php, and put below code at the end.
add_filter( 'woocommerce_add_cart_item_data', 'woo_custom_add_to_cart' );
function woo_custom_add_to_cart( $cart_item_data ) {
global $woocommerce;
$woocommerce->cart->empty_cart();
return $cart_item_data;
}
Now you can test by adding new product to your existing cart with items, see whether it will added the latest product only and remove all previous products in the cart.
Here's how you can limit the purchase to 1 product in your entire life in the store. I'm not sure about the quantity allowed for that product for the first time so I'll keep it variable in the below code.
Task 1: Allow to purchase 1 product at a time.
This can be simply achieved by the standard Woocommerce settings:
Task 2: Allow users to buy a product only once in their entire lifetime.
This will ensure that any user can purchase any product from your store only once and then can't buy any other product
This code will go in your functions.php file of the child theme or you can use any snippets plugin to do so.
add_action( 'woocommerce_add_to_cart', 'remove_product_from_cart_redirect', 999);
function remove_product_from_cart_redirect() {
global $woocommerce;
//Only use this code if the user is logged in
if ( is_user_logged_in() ) {
$userId = get_current_user_id();
// Get the TOTAL number of orders for the User
$totalOrders = wc_get_customer_order_count( $userId );
// Get CANCELLED orders for customer
$args = array(
'customer_id' => $userId,
'post_status' => 'cancelled',
'post_type' => 'shop_order',
'return' => 'ids',
);
$cancelledOrders = count( wc_get_orders( $args ) );
//all orders except cancelled ones
$totalNotCancelled = $totalOrders - $cancelledOrders;
if ($totalNotCancelled > 1) { //if already purchased anything on the store.
//empty the cart
WC()->cart->empty_cart( true );
//Optionally displaying a notice for the removed item:
wc_add_notice( __( 'We have removed the product from your cart.', 'woocommerce' ), 'notice' );
//Redirect to a my-account page
wp_redirect( get_permalink(get_option('woocommerce_myaccount_page_id')));
}
}
}
Note: Above code will not work with Ajax add to cart so please turn that off from Woocommerce settings here:

Wordpress WooCommerce store - Subtitle under Products Titles

I've been reading WP forums and trying different plugins for over a week now with no luck, so I decided to give it a try here.
I'm creating a WP website with a premium theme, that supports a woocommerce. What I need to do is the following:
Create a subtitle area (which would be named REG. NO:), so I could not only write Title of the product, but subtitle also. So when you would open a single product page, it would be like:
This_is_my_product_title
REG.NO: this_is_my_reg_no
another issue is, I would need a REG.NO: (subtitle) to be an external hyperlink to a different website.
Greatest thanks to anyone who could help me out.
If you want to go pure WooCommerce way, here's the gist.
1 - Add custom field ( this code goes in functions.php )
add_action( 'woocommerce_product_options_general_product_data', 'my_custom_field' );
function my_custom_field() {
woocommerce_wp_text_input(
array(
'id' => '_subtitle',
'label' => __( 'Subtitle', 'woocommerce' ),
'placeholder' => 'Subtitle....',
'description' => __( 'Enter the subtitle.', 'woocommerce' )
)
);
}
The field will appear as shown in this screen grab : http://i.imgur.com/fGC86DA.jpg
2 - Save the field's data when product is saved. ( this code goes in functions.php )
add_action( 'woocommerce_process_product_meta', 'my_custom_field_save' );
function my_custom_field_save( $post_id ){
$subtitle = $_POST['_subtitle'];
if( !empty( $subtitle ) )
update_post_meta( $post_id, '_subtitle', esc_attr( $subtitle ) );
}
3 - Edit single product template and display the field's value
<?php
global $post;
echo get_post_meta( $post->ID, '_subtitle', true );
?>
Ok so for everyone else who might have the same problem. Although both of options posted already are worth considering and will definitely save them as favorites because I'm sure I will need this in the future, this is the solution that worked best for me.
Although I'm trying to use as few plugins as possible, I ultimately decided to go with KIA SUBTITLE plugin. Then, you have to write this code in your functions.php:
function kia_add_subtitle_link_to_woocommerce(){
if( function_exists( 'the_subtitle' ) ){
$link = the_subtitle( '<h2 class="subtitle">', '</h2>', false );
printf( $link, get_permalink(), sprintf( __( 'Permalink to %s', 'your-text-domain' ), get_the_title() ) );
}
}
add_action( 'some_custom_hook', 'kia_add_subtitle_link_to_woocommerce' );
I used the following hook:
add_action( 'woocommerce_single_product_summary', 'kia_add_subtitle_link_to_woocommerce' );
You can use Advanced custom field plugin to create extra field in add product for REG NO
and you simple get field value on single page using the_field('name_u_give')
or you can also add post meta for post type product

Categories