How to Show Related Products by Attribute - WooCommerce - php

WooCommerce provides documentation on how to change the number of related products shown on a product page. Is there a way to change how they are related? It seems they are currently being related by category. Is there a way to show related products based on a single attribute?
Filter Below:
<?php
/**
* WooCommerce Extra Feature
* --------------------------
*
* Change number of related products on product page
* Set your own value for 'posts_per_page'
*
*/
function woo_related_products_limit() {
global $product;
$args = array(
'post_type' => 'product',
'no_found_rows' => 1,
'posts_per_page' => 6,
'ignore_sticky_posts' => 1,
'orderby' => $orderby,
'post__in' => $related,
'post__not_in' => array($product->id)
);
return $args;
}
add_filter( 'woocommerce_related_products_args', 'woo_related_products_limit' );

The filter woocommerce_related_products_args does not exist anymore. You can look into the function wc_get_related_products() to find which filters are currently available.
To replace categories by a single product attribute, I used the following code in my functions.php:
add_filter( 'woocommerce_get_related_product_cat_terms', 'my_attribute_relation', 10, 2);
/** Find related products using the attribute `pa_myAttrib`, throw away product categories. */
function my_attribute_relation( $original_term_ids, $product_id ) {
return wc_get_product_term_ids( $product_id, 'pa_myAttrib' );
}
In this case, product related by tags are kept. If you want to alter those, add a filter for woocommerce_get_related_product_tag_terms, too.

You should be able to do it by the taxonomy feature in wp_query... link
The attribute you want to target is 'woocommerce_attributes', not tested but this should work:
$args = array(
'post_type' => 'product',
'no_found_rows' => 1,
'posts_per_page' => 6,
'ignore_sticky_posts' => 1,
'orderby' => $orderby,
'post__in' => $related,
'post__not_in' => array($product->id),
'woocommerce_attributes' => 'attribute_slug',
);
return $args;

Related

wc_get_products is not returning related product id's

I try to use wc_get_products in functions.php in WordPress. However, I have 2 problems. I only can see the data when using var_dump and the response is missing related_ids (relatable product id's).
The original WooCommerce api call /wp-json/wc/v3/products does return the related_ids (when calling from e.g. postman). BUT the wc_get_products()in PHP does not.
Code in functions.php
$productArgs = array(
'numberposts' => -1,
'post_status' => 'published',
'include' => array(108903),
);
$products = wc_get_products( $productArgs );
var_dump($products);
return $products;
I use the follow documentation: https://github.com/woocommerce/woocommerce/wiki/wc_get_products-and-WC_Product_Query, but I don't see any information about related product id's.
By default, only the API returns the related_ids. To get the related ids for a product you may need to use the function wc_get_related_products.
$productArgs = array(
'numberposts' => -1,
'post_status' => 'published',
'include' => array(108903),
);
$products = wc_get_products($productArgs);
$related_ids = array_map('absint', array_values(wc_get_related_products(108903)));

Show cross-sells before same category on related products in WooCommerce

I'm writing some code to modify the related products section as follows:
If a product has cross sell products, show those first, and fill up to 4 total products with others from the same category*
Or
If a product has no cross sell products, show 4 products from the same category*
Here's my function to filter the related products so far:
add_filter( 'woocommerce_related_products', 'fivem_add_linked_to_related_products', 9999, 3 );
function fivem_add_linked_to_related_products( $related_posts, $product_id, $args ) {
$product = wc_get_product( $product_id );
$cross_sell_ids = $product->get_cross_sell_ids();
$product_categories = $product->get_category_ids();
// Get cross sell products
$cross_sell_products = get_posts( array(
'post_type' => 'product',
'post_status' => 'publish',
'fields' => 'ids',
'post__in' => $cross_sell_ids,
'posts_per_page' => 4,
'exclude' => array( $product_id ),
));
// Calculate how many filler products are needed
$category_product_count = 4 - count( $cross_sell_products );
// Exclude main product and cross sell products
$excluded_products = array_push( $cross_sell_ids, $product_id );
// Get filler products from same category
$category_products = get_posts( array(
'post_type' => 'product',
'post_status' => 'publish',
'orderby' => 'rand',
'fields' => 'ids',
'post__not_in' => $excluded_products,
'posts_per_page' => $category_product_count,
'tax_query' => array(
array(
'taxonomy' => 'product_cat',
'field' => 'id',
'terms' => $product_categories,
'operator' => 'IN',
)
)
));
// Merge cross sell products with filler products
$related_products = array_merge( $cross_sell_products, $category_products );
// Return related products
return $related_products;
}
Currently, the above code mostly works.
If cross-sells are set, it only displays those cross-sell products- ie. does not fill out to 4 total
If no cross-sells are set, it displays products from the same category as expected.
There are two problems I'm trying to solve:
Code above doesn't fill with category products. If I remove the post__not_in and tax_query arguments, it fills out, but obviously not with products from the same category.
I want to show cross-sell products first, then the category-related products. There appears to be another randomization somewhere that mixes the order up, and I can't work out where that comes from.
Any ideas how I can fix this? Thanks in advance.
Code contains
If a product has cross sell products, show those first, and fill up to 4 total products with others from the same category
If a product has no cross sell products, show 4 products from the same category
function filter_woocommerce_related_products( $related_posts, $product_id, $args ) {
// Taxonomy
$taxonomy = 'product_cat';
// Show products
$show_products = 4;
// Get product
$product = wc_get_product( $product_id );
// Get cross sell IDs
$cross_sell_ids = $product->get_cross_sell_ids();
// Calculate how many filler products are needed
$category_product_needed_count = $show_products - count( $cross_sell_ids );
// If category product needed
if ( $category_product_needed_count >= 1 ) {
// Retrieves product term ids for a taxonomy.
$product_cats_ids = wc_get_product_term_ids( $product_id, $taxonomy );
// Get product id(s) from a certain category, by category-id
$product_ids_from_cats_ids = get_posts( array(
'post_type' => 'product',
'numberposts' => $category_product_needed_count,
'post_status' => 'publish',
'fields' => 'ids',
'tax_query' => array(
array(
'taxonomy' => $taxonomy,
'field' => 'id',
'terms' => $product_cats_ids,
'operator' => 'IN',
)
),
));
// Merge array
$related_posts = array_merge( $cross_sell_ids, $product_ids_from_cats_ids );
} else {
// Slice array until show products
$related_posts = array_slice( $cross_sell_ids, 0, $show_products );
}
// Return
return $related_posts;
}
add_filter( 'woocommerce_related_products', 'filter_woocommerce_related_products', 10, 3 );
// Order by
function filter_woocommerce_output_related_products_args( $args ) {
$args['orderby'] = 'id';
$args['order'] = 'ASC';
return $args;
}
add_filter( 'woocommerce_output_related_products_args', 'filter_woocommerce_output_related_products_args', 10, 1 );

WP Shortcode to display posts by ID

Currently, I have a shortcode that displays a specific set of posts by specifying the post ID inside the function. But I would like to change this so the user can specify the post IDs as shortcode attributes.
Currently
[fsgrid]
Desired:
[fsgrid id="1, 2, 3"]
Here is the current code
public function shortcode_handler($atts) {
$atts = shortcode_atts(
array(
'posts_per_page' => 100 ,
'orderby' => 'post__in',
'post__in' => array(1, 2, 3)
), $atts, 'fsgrid'
);
return $this->grid($atts);
}
How do I change it? Any help is much appreciated.
explode will be your best option. Firstly extract your shortcode ids attributes then explode the comma separated string to an array.
See: https://codex.wordpress.org/Function_Reference/shortcode_atts
public function shortcode_handler($atts) {
extract(shortcode_atts(array(
'id' => null
), $atts, 'fsgrid'));
$post_ids = explode(",", strval($id));
$args = array(
'posts_per_page' => 100 ,
'orderby' => 'post__in',
'post__in' => $post_ids
);
return $this->grid($args);
}
Then you call you shortcode [fsgrid id="1,2,3"]

Woocommerce related product array with user input

I am using the following code as the footer of my single-product.php page in Woocommerce (I've created a "Related Products" section) and I am wondering if there is a way that I can alter it to make it possible for admin to be able to add values from the product admin page; I want certain products to show closer related products instead of totally random ones.
Is there a way I can create a custom field for something like product ID or tag and then add that custom field as the orderby value so those products/tags have a better change of showing up vs. random products?
If not, is there anything else I can do? I am simply looking for a way to allow an admin to choose closer related products to appear.
$args = apply_filters( 'woocommerce_related_products_args', array(
'post_type' => 'product',
'ignore_sticky_posts' => 1,
'no_found_rows' => 1,
'posts_per_page' => 5,
'orderby' => rand,
'post__in' => $related,
'post__not_in' => array( $product->id )
) );
Here is my related-footer.php file with the complete code that includes the above snippet.
Yes you can achieve this task as with the following approach:
Create a custom field for the product you want to display a set of your desired related products say the custom field name be "wdm_related_products" set the value to a comma separated list of Product ids eg. 46,15,687,21,48.
Update the product.
Add the following code in functions.php of user child theme or a custom Plugin.
add_filter('woocommerce_related_products_args','wdm_custom_related_products',99,1);
function wdm_custom_related_products($array){
global $product;
if(get_post_meta($product->,'wdm_related_products',true)){
$related=get_post_meta($product->id,'wdm_related_products',true);
$array=array(
'post_type' => 'product',
'ignore_sticky_posts' => 1,
'no_found_rows' => 1,
'posts_per_page' => 5,
'orderby' => rand,
'post__in' => $related,
'post__not_in' => array( $product->id )
);
}
return $array;
}
Let me know it it resolved your issue.

How can I sort woocommerce grouped products by post date instead of menu order?

What code/filter can I add to my wordpress functions.php file to modify the order of grouped products by post date instead of menu_order? class-wc-product-grouped.php
$args = apply_filters( 'woocommerce_grouped_children_args', array(
'post_parent' => $this->id,
'post_type' => 'product',
'orderby' => 'menu_order',
'order' => 'ASC',
'fields' => 'ids',
'post_status' => 'publish',
'numberposts' => -1,
) );
I'm pretty sure you can hook into it but just not sure how to configure the following filter/hook woocommerce_grouped_children_args
As you have mentioned, you just need to filter the $args being passed through the woocommerce_grouped_children_args filter.
add_filter( 'woocommerce_grouped_children_args', 'so_29973708_grouped_children_args' );
function so_29973708_grouped_children_args( $args ){
$args['orderby'] = 'date';
$args['order'] = 'DESC';
return $args;
}
If you need help understanding filters, I wrote what I think is a pretty good tutorial on how to use filters
Update If you aren't seeing any changes, chances are that the grouped product's children have already been stored in a transient. You will need to delete this transient to see changes right away. You can clear all WooCommerce product transients via the Admin. Navigate to WooCommerce>System Status>Tools and click on the button to clear transients.

Categories