Remove Already Displayed WooCommerce Related Products - woocommerce

When using 2 related product loops on the same single product page, is it possible to exclude the products in 1 loop from being duplicated in the 2nd loop.
By default, the related products display after the single product however what if you also want to display another loop before the single product with different related products that aren't already displayed in the other related products loop
I was thinking about adding custom code like this to the related products loop but don't know how or whether there's already code included that can be used to do this.
$exclude[] = $post->ID;
And then this :
'post__not_in' => $exclude,
I also tried this code but i don;t know how to add the code to the loop so i can use the filter.
add_filter( 'woocommerce_related_products', 'exclude_related_products', 10, 3 );
function exclude_related_products( $related_posts, $product_id, $args ){
$exclude_ids = array($exclude);
return array_diff( $related_posts, $exclude_ids );
}
So i guess i also need to find out how to add the code to store the already displayed product id's to the related products loop.
Or maybe i just need to filter and add a custom query arg to :
woocommerce_product_related_posts_query

Related

Show product variations on the product category and shop pages

I'd like to display product variations for some (not all) variable products on the shop and product-category pages based on a custom field I'm planning to add to each variable product. To keep pagination working, I can hook in to the woocommerce_product_query hook in WC_Query::product_query($q) but I can't figure out how to modify the query to give me what I'm after.
The logic I want to apply is:
//Pseudo-code
$loop = $query->get_all_products // i.e. not just for one page
foreach ( $loop as $product) {
if ($product->is_simple) {
display_simple($product)
} else {
$variations = wc_get_products($product->get_children());
foreach ($variations as $product) {
if ($product->custom_show_on_archive_pages) {
display_variation($product)
}
}
}
}
The problem with the above (apart from being pseudo-code) is that it assumes we have an array called $loop but actually we have a query object.
My ideal would be to modify the query so that it generates the results as per the pseudo-code, and then my archive-product.php template can use an if/else to display simple vs variable products.
Something like this in my functions.php:
add_action( 'woocommerce_product_query', 'show_variable_products');
function show_variable_products( $q ) {
$meta_query = $q->get('meta_query');
// Do something
$q->set('meta_query', $meta_query);
}
I'm wondering if I need to actually run multiple queries somehow:
The original query but filtered to parent products
The children of these parent products (i.e. the variations), filtered to those with custom field checked
The original query but filtered to simple products
Merge (2) and (3)
Would this be possible?
Alternatively, is there another solution (that does not involve buying a plugin)?

Add amount option for each variation

I am building a website that sells products with different variation. I created some variations to the products. However, the variations on the single product show up in a select box.
I want the customer to be able to choose an amount they want for each variation on the same page.
For example:
Chocolate 2x (customer chooses 2 Chocolate variations)
Vanille 3x
I want the customer to be able to buy those 5 flavours in 1 go and that they can select the amount for each variation of the product.
How can we reach this?
You should use Grouped Product.
It will look something like this on the frontend.
if you insist on using the variable product and treat it like it's a group, we can do that too.
First we have to remove the hook for the add to cart form of the variable product like so:
remove_action( 'woocommerce_variable_add_to_cart', 'woocommerce_variable_add_to_cart', 30 );
then we have to change it to use the add to cart form of the grouped variable like so:
add_action( 'woocommerce_variable_add_to_cart', 'woocommerce_grouped_add_to_cart', 30 );
in doing so, you'll end up something like this on the front end:
take note of the dashes after the quantity input. It's in format Title - Variation
So this must be it. Then when you're about to do an add to cart it shows like this:
It says "Please choose product options…". Why so? This is because the product is of type variable, and we are expected to choose on option. Remember select box.
However, we can fixed it like this:
add_filter( 'woocommerce_add_to_cart_handler', 'woocommerce_add_to_cart_handler', 10, 2 );
function woocommerce_add_to_cart_handler( $product_type, $product ) {
// if ( in_array( $product->get_id(), array( 100, 99, 504 ) ) ) {
$product_type = 'grouped';
// }
return $product_type;
}
We'll change the product type of the form handler. This way, we're using the grouped form handler and not the variable. Just be careful to put a conditional statements like if to only apply to specific products. Or else you'll end up confused between grouped products and variable products if you know what I mean. I've also recklessly did an add_action( 'woocommerce_variable_add_to_cart', 'woocommerce_grouped_add_to_cart', 30 ); without conditional statement, I suggest you do.
But once everything is in place, it will look something like this:

Excluding specific posts from Wordpress search results in sync with found_posts

I have a search results page which simply displays a list of wordpress page URL's. I want to exclude specific page URL's from appearing in this list. The list looks something like this: ( The total count is taken from ->found_post ).
Page Results (10 in total):
http://example.com/bill
http://example.com/cheese
http://example.com/moo
To make sure my found_posts total was correct, I thought I'd make a global filter like this and place it in functions.php :
function search_filter( $query ) {
if ( !is_admin() ) {
$exclude = array(
16,
261,
260
);
$query->set( 'post__not_in', $exclude );
}
}
add_action( 'pre_get_posts', 'search_filter' );
this would work fine if it wasn't for the fact that the search results page is one I don't want to appear in the search results. Adding this to the exclude array results in the search results page itself 404'ing.
So I thought then I could just put a check in the actual template loop like so:
if(!in_array(get_the_ID(), $exclude)):
but then my found_posts count is wrong, it counts the post but doesn't show it.
Is there a way to exclude the post, from the displayed results, and also reflect this in the found_posts count?

Woocommerce Add Product To Cart Multiple Times But As Different items

I have some custom code that adds an item to the cart, a variable product. If i add the same product twice it just increases the quantity. I would like it to add the product again as a different item in the cart.
How would i go about doing that? The item is being added to the cart using a link like domain.com?add-to-cart=3434&variation_id=4434 and so on.
The system i have developed is a product designer. So i may want to pick the same product but design it in different ways, and then add the same variation to the cart.
Is there also a way to send a unique identifier in the url to split these items up?
I want to do it by using add_to_cart but every time i do that with the variation attributes, the shipping ends up with a bug, it basically can't seem to find shipping methods:
$woocommerce->cart->add_to_cart(522,1, 523,array("attribute_colour" => "colour","attribute_size" => "a3", "attribute_invoice-numbering" => "yes", "attribute_quantity-column" => "yes", "attribute_cc-type" => "duplicate"));
While that code adds the item to the cart, it causes the following:
Warning: Invalid argument supplied for foreach() in /home/****/public_html/wp-content/plugins/woocommerce/includes/class-wc-shipping.php on line 291
There doesn‘t seem to be any available shipping methods. Please double check your address, or contact us if you need any help.
It doesn't make any sense, because the standard add to cart code in woocommerce uses add_to_cart and has none of these issues. The same if i use a URL, it works fine!
Try this !
/*
* #desc Force individual cart item
*/
function force_individual_cart_items( $cart_item_data, $product_id ){
$unique_cart_item_key = md5( microtime().rand() );
$cart_item_data['unique_key'] = $unique_cart_item_key;
return $cart_item_data;
}
add_filter( 'woocommerce_add_cart_item_data','force_individual_cart_items', 10, 2 );
/*
* #desc Remove quantity selector in all product type
*/
function remove_all_quantity_fields( $return, $product ) {
return true;
}
add_filter( 'woocommerce_is_sold_individually', 'remove_all_quantity_fields', 10, 2 );
I can't tell yet if the shipping array issue is related. But, if you take a look at the beginning of the add_to_cart() method in the cart class:
// Generate a ID based on product ID, variation ID, variation data, and other cart item data
$cart_id = $this->generate_cart_id( $product_id, $variation_id, $variation, $cart_item_data );
// See if this product and its options is already in the cart
$cart_item_key = $this->find_product_in_cart( $cart_id );
Basically, what we're seeing here is that the item must be completely unique in order to add it to the cart again. Otherwise, it will just up the quantity of the item already in the cart. So, to get around this, you will want to make the add_to_cart() parameters unique... probably via the final, $cart_item_data array.

Restrict Related Products by Product Categories Woocommerce

I have done a fair bit of searching on this but to no avail.
My question is that i wish to narrow the term by which woocommerce defines a related product. It currently uses Categories & Tags to define related products, but i wish to remove tags and just link by product categories. The result of this would be only products in my store with the same category would be defined as a related product. Note i am not using subcategories.
Can someone help me out with the code i would need to use to achieve this?
Thanks!
In the abstract-wc-product.php file in the woocommerce/includes/abstracts/ folder remove the following line (on line ~1154):
// Get tags
$terms = wp_get_post_terms( $this->id, 'product_tag' );
foreach ( $terms as $term ) {
$tags_array[] = $term->term_id;
}
Removing the above should work.

Resources