I need to hide products with same title from shop page.
I have many products with different SKU but same name.
Is it possible to achieve that with a distinct function like this or should i create a custom loop?
add_filter( 'posts_distinct', function ( $distinct ) {
//if same name update_post_meta( $product_id, '_visibility', '_visibility_search' );
return 'DISTINCT'; });
Ok so i've found the solution by using a function, in case anyone in the future needs it.
add_filter( 'posts_groupby', 'custom_posts_groupby', 10, 2 );
function custom_posts_groupby( $groupby, $query ) {
global $wpdb;
if ( is_main_query() && (is_shop() || is_product_category() || is_search() )) {
$groupby = "{$wpdb->posts}.post_title";
}
return $groupby;
}
Related
I would like to only show wholesale_customers orders from Germany and Austrian (DE / AT) to a certain shop manager with the ID: 136. I have found some code here. I have found and made the following, but its not working?
function before_checkout_create_order($order, $data) {
$country = $order->billing_country;
$store_manager_id = '136';
$german_region = ['DE', 'AT'];
if (in_array($country, $german_region)) {
$store_manager_id = 136;
}
$order->update_meta_data('_store_manager_id', $store_manager_id);
}
add_action('woocommerce_checkout_create_order', 'before_checkout_create_order', 20, 2);
UPDATE: Simplified solution without custom post_meta (works with previously created orders as well).
You can use pre_get_posts action directly to alter meta_query based on order billing country codes. If you would like to use this solution, you can safely remove the before_checkout_create_order function as it is no longer needed.
function store_manager_orders_query( $query ) {
global $pagenow, $typenow;
$store_manager_id = 136;
$store_manager_countries = array('DE', 'AT');
if( !$query->is_main_query() ) {
return;
}
if( get_current_user_id() === $store_manager_id && $query->is_admin && 'edit.php' === $pagenow && 'shop_order' === $typenow ){
// Get and alter meta query
$meta_query = (array)$query->get('meta_query');
$meta_query[] = array(
'key' => '_billing_country',
'value' => $store_manager_countries,
'compare' => 'IN',
);
// Set altered meta query
$query->set('meta_query',$meta_query);
}
}
add_action( 'pre_get_posts', 'store_manager_orders_query', 20 );
OLD SOLUTION: (uses redundant custom order meta from your original question)
Your code basically adds _store_manager_id meta to every created order, because your if condition does nothing (it only re-assign the store manager ID to the same value as specified before), and then you update the order meta of every order, without any conditional logic. You should run update_meta_data function inside that if condition:
function before_checkout_create_order( $order, $data ) {
$country = $order->billing_country;
$german_region = ['DE', 'AT'];
if( in_array( $country, $german_region ) ) {
$store_manager_id = 136;
$order->update_meta_data('_store_manager_id', $store_manager_id);
}
}
add_action( 'woocommerce_checkout_create_order', 'before_checkout_create_order', 20, 2 );
Now only desired (DE, AT) orders have the _store_manager_id meta set to 136. Now you need to limit queried orders for that store manager:
function store_manager_orders_query( $query ) {
global $pagenow, $typenow;
$store_manager_id = 136;
if( !$query->is_main_query() ) {
return;
}
if( get_current_user_id() === $store_manager_id && $query->is_admin && 'edit.php' === $pagenow && 'shop_order' === $typenow ){
// Get and alter meta query
$meta_query = (array)$query->get('meta_query');
$meta_query[] = array(
'key' => '_store_manager_id',
'value' => $store_manager_id,
'compare' => '=',
);
// Set altered meta query
$query->set('meta_query',$meta_query);
}
}
add_action( 'pre_get_posts', 'store_manager_orders_query', 20 );
Tested and works. Both portions of the code go in functions.php of your active theme or child-theme.
Please note that your current code probably assigned this meta value to every created order (not only german orders), so there are probably non-german orders with the _store_manager_id meta set to 136 already. You should clean up these database records, change your meta_key, or just ignore past orders.
TIP: You can make this code more versatile if there will be more restricted locations for specific store managers in the future (e.g. enable/disable restriction on user level and then automatically show orders with _store_manager_id meta with the same value as get_current_user_id(). Whatever suits your scenario.
I am trying to change the query of the shop (archive) of Woocommerce. I searched and found a lot of snippets but didn't find my solution yet. So I hope someone here can help me out.
What I want is to hide a selection of products which are defined by a separate function. The function returns an array of product/post id's. I can't find out why this is not working...
function shop_show_products_by_id( $meta_query, $query ) {
// Only on shop archive pages
if( is_admin() || is_search() || ! is_shop() ) return $meta_query;
$meta_query[] = array(
'post__not_in' => gives_product_ids_not_to_show()
);
return $meta_query;
}
add_filter( 'woocommerce_product_query_meta_query', 'shop_show_products_by_id', 10, 2 );
post__not_in isn't a meta_query...
You can exclude products like this, using the woocommerce_product_query which is essentially pre_get_posts. If gives_product_ids_not_to_show() returns an array of integers, you can replace the array() after the post__not_in
function shop_hide_products_by_id( $q ) {
// Only on shop archive pages
if( is_shop() ){
$q->set('post__not_in' , array(89,2182)); // use integers
}
}
add_filter( 'woocommerce_product_query', 'shop_hide_products_by_id' );
How can I display the product variations for each product within a loop such as the one on the Shop page? Is there any function that I can add to the content-product template that retrieves the list of variations and displays them?
You can use this code to add product variation to the shop/product category loops
// Load our function when hook is set
add_action( 'pre_get_posts', 'custom_modify_query_get_posts_by_date' );
// Modify the current query
function custom_modify_query_get_posts_by_date( $query ) {
// Check if on frontend and main query is modified and if its shop or product category loop
if( (! is_admin() && $query->is_main_query()) && ( is_shop() || is_product_category() ) ) {
$query->set( 'order', 'ASC' );
add_filter( 'posts_where', 'rc_filter_where' );
}
return $query;
}
// Add products variation post type to the loop
function rc_filter_where( $where = '' ) {
$type = 'product_variation';
$where .= " OR post_type = '$type'";
return $where;
}
Best way to do this is alter the loop. Something like that will help:
function filter_wc_query($query_args){
if(is_archive()){ //here you can use any conditional function to show variations on
$query_args[] = ['post_parent'=> '*'];
}
return $query_args;
}
add_filter('woocommerce_get_query_vars','filter_wc_query');
Or if you want to this on view level:
https://gist.github.com/lukecav/2470d9fe6337e13da4faae2f6d5fe15f
In this solution image you can grab by standard WP function:
get_post_thumbnail($product->ID,'shop_list');
But remeber that variation link will bring user to parent product and force him to select variation once more.
So far I've figured out I need to use the following hook to change the WooCommerce products query:
add_action( 'woocommerce_product_query', 'xxxx_product_query' );
function xxxx_product_query( $q ){
...do something here...
}
But how do I:
1.make the query sort all products randomly;
2.keep the randomly sorted products in that order for 30 days and then change it again when the 30 days expire;
3.make all products with the custom field "_new" always appear at the beginning of the query (these should not be sorted randomly).
Thanks in advance for any help!
You can add an extra sorting option to the Default Sorting Order combobox in the WooCommerce settings page under the Products/Display tab by using this code in your functions.php file.
add_filter( 'woocommerce_get_catalog_ordering_args', 'custom_woocommerce_get_catalog_ordering_args' );
function custom_woocommerce_get_catalog_ordering_args( $args ) {
$orderby_value = isset( $_GET['orderby'] ) ? woocommerce_clean( $_GET['orderby'] ) : apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby' ) );
if ( 'random_list' == $orderby_value ) {
$args['orderby'] = 'rand';
$args['order'] = '';
$args['meta_key'] = '';
}
return $args;
}
add_filter( 'woocommerce_default_catalog_orderby_options', 'custom_woocommerce_catalog_orderby' );
add_filter( 'woocommerce_catalog_orderby', 'custom_woocommerce_catalog_orderby' );
function custom_woocommerce_catalog_orderby( $sortby ) {
$sortby['random_list'] = 'Random';
return $sortby;
}
Why are you using a '_new' custom field? You can probably just use the time stamp of when the product was added to establish if the product is new or not.
In my WooCommerce store, I have "Hide out of stock items from the catalogue" enabled. This option causes product variations on individual pages to become invisible.
I want to apply "Hide out of stock items from the catalogue" option only on archive pages (search, categories).
Here is my code:
function featured_posts( $query ) {
if ( ! $query->is_main_query() ) return;
//What goes in here?
}
add_action( 'pre_get_posts', 'featured_posts' );
How can I achieve this?
Thanks
Try This
You have to check page for do this as follow
function featured_posts( $query ) {
if(is_product_category() || is_search()){
if ( ! $query->is_main_query() ){
return;
}
}
....
}
add_action( 'pre_get_posts', 'featured_posts' );