I am trying to clean up my woocommerce shop. We have 13,000 customers. I would like to delete all customers who have not ordered within the last year.
I'm running into several problems though. (mostly, ignorance!)
In the Woocommerce/customers section I can filter by last active but there is no way to delete users from this area.
I tried using this code:
add_filter( 'manage_users_columns', 'prefix5487_modify_user_columns' );
function prefix5487_modify_user_columns( $column ) {
$column['orders'] = __( 'Order count' );
return $column;
}
add_filter( 'manage_users_custom_column', 'prefix5487_user_order_column_value', 10, 3 );
function prefix5487_user_order_column_value( $val, $column_name, $user_id ) {
switch ($column_name) {
case 'orders' :
return wc_get_customer_order_count( $user_id );
default:
}
return $val;
}
add_filter( 'manage_users_sortable_columns', 'prefix5487_make_registered_column_sortable' );
function prefix5487_make_registered_column_sortable( $columns ) {
return wp_parse_args( array( 'orders' => 'orders' ), $columns );
}
which works to add the amount of orders a customer has made in total. This is the closest I've found so far. It doesn't sort correctly though.
The problem is that if I delete users in the Users section, they are still in the woocommerce Customers section of the backend. I'm also not sure if this is deleting the orders that those customers made (I don't necessarily care if it does or not). Not to mention that this function adds the column and shows order count but it doesn't actually SORT so I still have to go through one by one)
On another site I saw that I would have to delete the users from wp_wc_customer_lookup table as well.
It seems like there would be an easy way to do this
Related
I would like to add a function that is triggered every time that the stock quantity of a product will be changed in the admin product page, such that this function will not allow any reduce of the stock value - but only increase.
This is to prevent an admin user to reduce the stock quantity of the products.
Of course, this function should not be triggered if a product will be in an order, since then of course I would like the stock quantity to be reduced.
I tried the following function in the functions.php but unfortunately did not work.
Since I'm new to woocommerce and php, any ideas that could provide a solid solution to the problem?
// get old and new product stock quantity
function get_old_and_new_product_quantity_stock( $sql, $product_id_with_stock, $new_stock, $operation ) {
$product = wc_get_product( $product_id_with_stock );
$old_stock_quantity = $product->get_stock_quantity();
$new_stock_quantity = $new_stock;
echo $old_stock_quantity, $new_stock_quantity;
if ($new_stock_quantity < $old_stock_quantity) {
$new_stock = $old_stock_quantity;
$new_stock_quantity = $old_stock_quantity;
}
return $sql;
}
add_filter( 'woocommerce_update_product_stock_query', 'get_old_and_new_product_quantity_stock', 10, 4 );
You can use the update_post_meta action hook to check if the new value is less than the previous value and display error message.
This will work for quick edit and for product edit page. But the wp_die on product page will look bad so use the javascript to prevent submitting on product edit page (there was another question about it yesterday)
Be sure to test this snippet and create some orders that will reduce the stock automatically. I added is_admin() check but please do a good test.
add_action( 'update_post_meta', 'prevent_reducing_stock_metadata', 10, 4 );
function prevent_reducing_stock_metadata( $meta_id, $post_id, $meta_key, $meta_value ) {
// Check if the meta key is _stock and the new value is less than the previous value
if ( '_stock' == $meta_key && $meta_value < get_post_meta( $post_id, '_stock', true ) ) {
// Check if this is an update from the WordPress admin area
if ( is_admin() ) {
wp_die( __( 'Error: You cannot reduce the stock level for this product.' ), 'error' );
}
}
}
In WooCommerce, I understand well that woocommerce_get_order_item_totals filter kook is used to customize order total rows like reordering them.
add_filter( 'woocommerce_get_order_item_totals', 'custom_order_of_from_order_table', 10, 2 );
function woocommerce_get_order_item_totals( $total_rows, $order ) {
// code here
return $total_rows;
}
I have tried to reorder the subtotal over the total, and the payment method below the total without success on WooCommerce ThankYou page. My PHP knowledge is very limited and I appreciate any help.
How to customize total rows from order table, reordering them on WooCommerce thankyou page?
The following will reorder items totals as desired on Woocommerce thankyou (order received) page only:
add_filter( 'woocommerce_get_order_item_totals', 'reordering_order_item_totals', 10, 3 );
function reordering_order_item_totals( $total_rows, $order, $tax_display = '' ){
// Only on "order received" thankyou page
if ( ! is_wc_endpoint_url('order-received') )
return $total_rows;
$sorted_items_end = array('cart_subtotal', 'order_total', 'payment_method');
$sorted_total_rows = array(); // Initializing
// Loop through sorted totals item keys
foreach( $sorted_items_end as $item_key ) {
if( isset($total_rows[$item_key]) ) {
$sorted_total_rows[$item_key] = $total_rows[$item_key]; // Save sorted data in a new array
unset($total_rows[$item_key]); // Remove sorted data from default array
}
}
return array_merge( $total_rows, $sorted_total_rows); // merge arrays
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
To make that work everywhere for customer orders and email notifications, just remove:
// Only on "order received" thankyou page
if ( ! is_wc_endpoint_url('order-received') )
return $total_rows;
I added a new column to Woocommerce orders's screen, that indicates who is the order's creator (in that site, service representatives have the ability to create order for customer's in the backend).The problem is that when I search for that data in the orders screen, I can't find any.
The order's creator is set to the order with add_post_meta()
So I tried something like this:
function include_search( $query ) {
if ( is_admin() && $query->is_search() && $query->query['post_type'] == 'shop_order' ) {
$query->set( 'meta_query', array('key' => 'representative', 'value' => $query->query['s'], 'compare' => '=') );
}
}
add_action( 'pre_get_posts', 'include_search' );
But it doesn't work.
For example, If an order created by "Ben X", then I can see his name appears in the right column in the orders screen, but if I search for "Ben X" in the search box, I don't find that order.
Any help with that?
Thanks!
If anyone need help with that, I found the answer:
function filter_woocommerce_shop_order_search_fields( $array ) {
$array[] = 'representative'; //The order meta key that needs to be include in the search
return $array;
};
add_filter( 'woocommerce_shop_order_search_fields', 'filter_woocommerce_shop_order_search_fields', 10, 1 );
I have a really weird behavior on Woocommerce with the stock management. On a product with stock management enabled, a stock of 100 items and stock status "available", every time I do an order the product stock go to negative and get out of stock.
For example, if I do an order of 2 items of the product, the stock go to -2 right after the order, even if the stock was at 100 right before.
The product is a simple one, without any attribute. I use the following hooks to alter some label and stuffs, but none seems related to this issue:
add_filter('woocommerce_product_single_add_to_cart_text', array(&$this->wc, 'add_to_cart_text'), 11);
add_filter('woocommerce_add_to_cart', array(&$this->wc, 'add_to_cart'), 10, 1);
add_action('woocommerce_cart_item_removed', array(&$this->wc, 'cart_item_removed'), 10, 1);
add_action('woocommerce_order_status_completed', array(&$this->wc, 'order_status_completed'), 10, 1);
add_action('woocommerce_after_shop_loop_item', array(&$this->wc, 'replace_add_to_cart'));
In short, woocommerce_product_single_add_to_cart_text change the add to cart button label, woocommerce_add_to_cart place some vars in session, woocommerce_cart_item_removed remove those session var on item removal from cart, woocommerce_order_status_completed do some stuffs with the session vars (update a CPT from those session vars - I don't touch the order or the product at all) and woocommerce_after_shop_loop_item display a button on product listing. I tried to disable the woocommerce_order_status_completed hook, it didn't change anything.
I will paste any code of those function if any of you think some could be related to this stock issue.
I'm using latest version of Woocommerce and Wordpress.
I found out the culprit, as helgatheviking suggested I disabled all the plugins one by one and found out that the plugin Progression One Click Import provided by the theme and marked as "recommended for theme use" was doing this.
My guess is that it is related to this filter in the plugin code:
add_filter( 'add_post_metadata', array( $this, 'check_previous_meta' ), 10, 5 );
Which is doing this:
public function check_previous_meta( $continue, $post_id, $meta_key, $meta_value, $unique ) {
$old_value = get_metadata( 'post', $post_id, $meta_key );
if ( count( $old_value ) == 1 ) {
if ( $old_value[0] === $meta_value ) {
return false;
} elseif ( $old_value[0] !== $meta_value ) {
update_post_meta( $post_id, $meta_key, $meta_value );
return false;
}
}
}
The flaw in this is that it is inserting the stock meta value raw (-2) instead of decrementing the existing meta value, which Woocommerce seems to do with some filter on his end - a behavior that is overwrited by this filter.
I guess this could be fixed by changing the filter priority but just disabling the plugin was good for me as I don't need to import preview data.
I have 2 questions regarding Woocommerce for Wordpress.
I'm working on a site that sells speakers to the Danish market.
Question one:
Can I detect the IP of a visitor and detect which country the person is from? I guess this can be done with some ClientLocation api.
Can I then disable all shopping relatet pages and buttons if a person is not from Denmark. Fx: hiding the add to cart, cart and checkout.
I still want the persons to be able to see the prices, they should just not have the option to buy them.
Question 2:
Lets say that question one was sucessfull made. Then I would like to show different prices for other contries than Denmark. So if you are visiting the site from one country, the price is XXX and from another country the price is XXXX.
Let's say:
In USA the price is = $500
And in UK the price = £400
(This has nothing to do with currency. The market price is just different in different countries.)
I've looked at this plugin: http://wordpress.org/plugins/woocomerce-price-by-country/
It allowed me to write different prices for each product, but when I testet it with http://geopeeker.com/ I hadn't worked at all.
Can you give me some pointets or some links to some plugins that you know of?
UPDATE
I managed to solve question 1. I store the visitors country in a cookie with IP location XML API And then I could just create an if statement, saying that if the country was not equal to Denmark, then the add to cart, cart etc. should be removed.
So yeah, I would really appreciate it if anyknow could give me an idea on how I can solve question 2.
I'm able to detect country, but not able to specify a price of each product to the given country.
2'nd update:
Just to let any interested readers know, I ended up buying this plugin. which is working perfectly!
For the 2nd part of your question: If you are only using simple product types (without variations) then you can add custom price fields to the product data page and filter the price using woocommerce_get_price_html.
add_filter('woocommerce_get_price_html','so24863612_custom_price');
function so24863612_custom_price(){
global $post;
$_postID = $post->ID;
$product = get_product( $_postID );
$UK_price = get_post_meta($_postID, '_UK_price', true); //loads custom meta data
$return_price = $product->get_regular_price(); //default to regular price
if (!empty($UK_price)) {
$return_price = $UK_price;
}
return $return_price;
}
You can create and save custom fields on the product page like this:
//Display custom fields on product data page in admin
add_action( 'woocommerce_product_options_general_product_data', 'so24963039_display_custom_general_tab_fields' );
function so24963039_display_custom_general_tab_fields() {
global $woocommerce, $post;
$UK_price = get_post_meta( $post->ID, '_UK_price', true );
woocommerce_wp_text_input(
array(
'id' => '_UK_price',
'label' => __( 'UK Price (£)', 'woocommerce' ),
'value' => $UK_price,
'desc_tip' => 'false'
)
);
}
//Save custom fields to access via get_post_meta
add_action( 'woocommerce_process_product_meta', 'so24963039_save_custom_general_tab_fields' );
function so24963039_save_custom_general_tab_fields ($post_id) {
$woocommerce_UK_price = $_POST['_UK_price'];
if( !empty( $woocommerce_UK_price ) )
update_post_meta( $post_id, '_UK_price', esc_attr( $woocommerce_UK_price ) );
}
-----------------For products with Variations----------------------------
WARNING: Variable products are much more complicated and I'm not nearly as confident in this answer as I am with the simple products part above, but here's my current understanding either way. I had some mini-cart display issues that I had to hack around when using this method (which I will explain at the end), but the totals are calculated correctly in both the mini-cart and the regular cart.
First we want to add new fields to each variant on the variation tab of existing products:
add_action( 'woocommerce_product_after_variable_attributes', 'so24963039_variable_fields', 10, 2 ); //Display Fields
function so24963039_variable_fields( $loop, $variation_data ) {
echo '<tr><td>';
woocommerce_wp_text_input(
array(
'id' => '_variant_UK_price['.$loop.']',
'label' => __( 'UK Price (£)', 'woocommerce' ),
'desc_tip' => 'false',
'value' => $variation_data['_variant_UK_price'][0]
)
);
echo '</td></tr>';
}
We also need to add them dynamically whenever the user adds new variants on the edit product page:
add_action( 'woocommerce_product_after_variable_attributes_js', 'so24963039_variable_fields_js' ); //JS to add fields for dynamically added new variations
function so24963039_variable_fields_js(){ //add fields to new variations that get added
echo '<tr><td>';
woocommerce_wp_text_input(
array(
'id' => '_variant_UK_price[ + loop + ]',
'label' => __( 'UK Price (£)', 'woocommerce' ),
'desc_tip' => 'false',
'value' => $variation_data['_variant_UK_price'][0]
)
);
echo '</td></tr>';
}
Then we save changes to the custom fields in the variation meta data:
add_action( 'woocommerce_process_product_meta_variable', 'so24963039_save_variable_fields', 10, 1 ); //Save variation fields
function so24963039_save_variable_fields( $post_id ) {
if (isset( $_POST['variable_sku'] ) ) {
$variable_sku = $_POST['variable_sku'];
$variable_post_id = $_POST['variable_post_id'];
// Variant Tier 1 Price
$_variant_UK_price = $_POST['_variant_UK_price'];
for ( $i = 0; $i < sizeof( $variable_sku ); $i++) {
$variation_id = (int) $variable_post_id[$i];
if ( isset( $_variant_UK_price[$i] ) ) {
update_post_meta( $variation_id, '_variant_UK_price', stripslashes($_variant_UK_price[$i] ) );
}
}
}
}
Now that we have our custom variation meta data, we can access it in the custom price module like so:
add_filter('woocommerce_get_price_html','so24863612_custom_price');
function so24863612_custom_price(){
global $post;
$_postID = $post->ID;
$product = get_product( $_postID );
$product_type = $product->product_type;
$UK_price = get_post_meta($_postID, '_UK_price', true); //covers simple products
if($product_type == 'variation'){ //override with variant prices
$UK_price = get_post_meta($_postID, '_variant_$UK_price', true);
}
$return_price = $product->get_regular_price(); //default to regular price
if (!empty($UK_price)) {
$return_price = $UK_price;
}
return $return_price;
}
Now, I believe that part should have everything working except for the mini-cart display. For some reason it seems like I just couldn't figure out how to get access to the variation meta data to force it to display properly in the mini cart - like I found where the mini-cart display was being generated but I was having trouble getting the right context path to access the custom variable so I ended up having to do that in the template-tags.php and pass an array of custom values to an optional parameter in my custom price function. This feels very 'wrong' in terms of how we should do things, but it gets the job done. I'm very open to hearing the 'correct' solution to this part of the problem.
In template-tags.php:
<div class="small-7 large-7 columns"><?php
$product_title = $_product->get_title();
echo '<a class="cart_list_product_title" href="'.get_permalink($cart_item['product_id']).'">' . apply_filters('woocommerce_cart_widget_product_title', $product_title, $_product) . '</a>';
echo '<div class="cart_list_product_price">';
//original line: echo woocommerce_price($_product->get_price());
/*Custom Price Override Block*/
$_productID = $_product->id;
$product_type = $_product->product_type;
if($product_type == 'variation') {
$custom_field_data = $_product->product_custom_fields;
$regular_price = $custom_field_data['_regular_price'];
$custom_UK_price = $custom_field_data['_variant_UK_price'];
$custom_variant_prices = [$regular_price[0], $custom_UK_price[0]];
echo so24863612_get_custom_price($_productID, $custom_variant_prices );
} else {
echo so24863612_get_custom_price($_productID );
}
/*End Custom Price Override Block*/
echo ' /</div>';
echo '<div class="cart_list_product_quantity">'.__('Quantity', 'woocommerce').': '.$cart_item['quantity'].'</div>';
?></div>
I see your update that you did manage to get the visitor's country and that you can use this to create the if statement to remove the cart. (which is freaking cool, by the way)
Doesn't that answer your question 2, about changing the prices for each visitor? All you have to do is make sure that both prices are stored somewhere, and then just have it echo the Denmark or the UK one.
Prices are specific - custom fields
You mentioned this is NOT currency conversion - so you need to store both values. Add a custom field to the product entry that you edit with that new price, and name it "denmarkprice" or something
I'm not 100% familiar enough with WooCommerce to say what custom field plugin might work, but you could use http://www.advancedcustomfields.com/ if you don't want to just create the custom field yourself and call the variable with the_meta() when you want to display it inside your if else statement.
http://codex.wordpress.org/Custom_Fields