Almost all the guides to implement price sorting on woocommerce site are the same. I've tried two main ways. 1st - hooked up my query args from functions.php like this:
add_filter('woocommerce_get_catalog_ordering_args', 'my_custom_woocommerce_catalog_orderby');
function my_custom_woocommerce_catalog_orderby( $args ) {
if(isset($_GET['sort'])){
if($_GET['sort_by'] == 'by_rating'){
$args['meta_key'] = '_wc_average_rating';
} else if($_GET['sort_by'] == 'by_price') {
$args['meta_key'] = '_price';
}
$args['orderby'] = 'meta_value_num';
$args['order'] = strtoupper($_GET['sort']);
}
return $args;
}
var_dump shows that it has been catched:
array(3) { ["orderby"]=> string(14) "meta_value_num" ["order"]=> string(4) "DESC" ["meta_key"]=> string(6) "_price" }
But products are still sorted by default woocommerce setting (price, asc).
Then i implemented my filter plugin (which is working pretty well) and tried to add this sorting query to it.
class My_blah_blah_filter {
public static $instance;
public $productquery;
public static function init() {
if ( is_null( self::$instance ) ) {
self::$instance = new My_blah_blah_filter ();
}
return self::$instance;
}
private function __construct() {
add_action( 'woocommerce_product_query', [ $this, 'filter_by_current_range' ] );
}
public function filter_by_current_range( $query ) {
$this->productquery = $query;
$query->set('tax_query', $this->get_tax_query());
if(isset($_GET['sort'])){
if($_GET['sort_by'] == 'by_rating'){
$query->set('meta_key', '_wc_average_rating');
} else if($_GET['sort_by'] == 'by_price') {
$query->set('meta_key', '_price');
} else {
$query->set('meta_key', '_price');
}
$query->set('orderby', 'meta_value_num');
$query->set('order', strtoupper($_GET['sort']));
}
}
public function get_tax_query() {
// pa_space-overall
$tax_query = [];
if( isset( $_GET['max_so'] ) && isset( $_GET['min_so'] ) ) {
$terms = get_terms([
'taxonomy' => 'pa_space-overall',
]);
$rlt = [];
foreach( $terms as $term ) {
if( (int) $term->name <= (int) $_GET['max_so'] && (int) $term->name >= (int) $_GET['min_so'] ) {
$rlt[] = $term->term_id;
}
}
$tax_query = [
'relation' => 'AND',
[
'taxonomy' => 'pa_space-overall',
'terms' => $rlt,
'operator' => 'IN',
],
];
}
if( isset( $this->productquery->tax_query ) ) {
$tax_query = array_merge( $this->productquery->query_vars['tax_query'], $tax_query );
}
return $tax_query;
}
Some stuff here is hardcoded, but its not the case, its working. But not the ordering. Its still being catched, added to query, but order is default anyways (price, asc - from woocommerce settings)
The only plugin except woocommerce - is advanced custom fields, which has nothing to do with it.
Cant find any solution anywhere else. Any suggestions? Thanks in advance.
Sorry for poor english or not-perfectly-formatted code
Related
I am trying to hide product attributes in woocommerce based on product title. currently I have code that removes the attributed based on category. It works fine for what it is, but I would prefer to use title and a strpos array instead.
Here is the code that allows me to remove attributes based on categories
add_action( 'wp', 'remove_product_content11' );
function remove_product_content11() {
if ( has_term( array('Flush Mount', 'Semi Flush'), 'product_cat' ) ) {
function mycode_hide_attributes_from_additional_info_tabs( $attributes, $product ) {
$hidden_attributes = [
'pa_item-length-or-depth',
'pa_item-minimum-height',
];
foreach ( $hidden_attributes as $hidden_attribute ) {
if ( ! isset( $attributes[ $hidden_attribute ] ) ) {
continue;
}
$attribute = $attributes[ $hidden_attribute ];
$attribute->set_visible( false );
}
return $attributes;
}
add_filter( 'woocommerce_product_get_attributes', 'mycode_hide_attributes_from_additional_info_tabs', 20, 2 );
}
}
I would just like to change this code so It uses strpos to search though the product title, instead of using category.
check this code, tell me if it helps.
add_action( 'wp', 'remove_product_content11' );
function remove_product_by_strpos_title() {
global $post;
// check if its a product page, so the code is not executed for every page
// and check if title contains 'my-title'
if ( is_product() && strpos('my-title', $post->post_title) ) {
function mycode_hide_attributes_from_additional_info_tabs( $attributes, $product ) {
$hidden_attributes = [
'pa_item-length-or-depth',
'pa_item-minimum-height',
];
foreach ( $hidden_attributes as $hidden_attribute ) {
if ( ! isset( $attributes[ $hidden_attribute ] ) ) {
continue;
}
$attribute = $attributes[ $hidden_attribute ];
$attribute->set_visible( false );
}
return $attributes;
}
add_filter( 'woocommerce_product_get_attributes', 'mycode_hide_attributes_from_additional_info_tabs', 20, 2 );
}
}
Could someone please explain why the first section of code works but not the second. I am trying to filter the content on a website based on what values have been selected in the backend on each post using Advanced Custom Fields.
function my_pre_get_posts( $query ) {
// do not modify queries in the admin
if( is_admin() ) {
return $query;
}
// only modify queries for 'event' post type
if( isset($query->query_vars['post_type']) && $query->query_vars['post_type'] == 'property' ) {
// allow the url to alter the query
if( isset($_GET['bedrooms']) ) {
$query->set('meta_key', 'bedrooms');
$query->set('meta_value', $_GET['bedrooms']);
}
}
// return
return $query;
}
add_action('pre_get_posts', 'my_pre_get_posts');
non working:
add_action('pre_get_posts', 'my_pre_get_posts');
function my_pre_get_posts( $query ) {
// bail early if is in admin
if( is_admin() ){
return;
}
// get meta query
$meta_query = $query->get('meta_query');
if( isset($_GET['bedrooms']) ){
$meta_query[] = array(
'key' => 'bedrooms',
'value' => $_GET['bedrooms'],
'compare' => '=',
);
}
// update meta query
$query->set('meta_query', $meta_query);
return;
}
I am trying to modify Woocommerce sorting option to get a customized one by adding the following code to Avada child function.php file:
// add custom sorting option
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'] = 'menu_order Date';
$args['order'] = 'ASC';
$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'] = 'Menu_order_date';
return $sortby;
}
//end custom ordering code
this code work fine if i didn't enable WooCommerce Shop Page Ordering Boxes and actually i wanted the ordering box to be displayed on my shop page and product category, so i contact Avada Support for this issue and it turn out Avada use thier own hook for WooCommerce Shop Page Ordering Boxes with the following code:
/**
* Controls the actions adding the ordering boxes.
*
* #access public
* #since 5.0.4
* #param object $query The main query.
* #return void
*/
public function product_ordering( $query ) {
// We only want to affect the main query.
if ( ! $query->is_main_query() || $query->is_search() ) {
return;
}
if ( $query->get( 'page_id' ) ) {
$page_id = absint( $query->get( 'page_id' ) );
} else {
$page_id = absint( Avada()->fusion_library->get_page_id() );
}
if ( wc_get_page_id( 'shop' ) === $page_id || $query->is_post_type_archive( 'product' ) || $query->is_tax( get_object_taxonomies( 'product' ) ) ) {
if ( Avada()->settings->get( 'woocommerce_avada_ordering' ) ) {
remove_action( 'woocommerce_before_shop_loop', 'woocommerce_catalog_ordering', 30 );
add_action( 'woocommerce_before_shop_loop', array( $this, 'catalog_ordering' ), 30 );
add_action( 'woocommerce_get_catalog_ordering_args', array( $this, 'get_catalog_ordering_args' ), 20 );
}
}
}
Avada Support said I can remove Avada function from this hook and add my own using child theme.
add_action( 'woocommerce_get_catalog_ordering_args', array( $this,
'get_catalog_ordering_args' ), 20 );
I searched all over the interent seeking help and I found many pepole asked about almost same question but without answer.
if anyone could help removing avada function that will be very helpful for me and other pepole who's looking for that as well.
How I can remove Avada hooked function from woocommerce_get_catalog_ordering_args action hook?
after several test i disocoverd the following code which added by Avada team as follow:
/**
* Modified the ordering of products.
*
* #access public
* #since 5.1.0
*/
public function catalog_ordering() {
get_template_part( 'templates/wc-catalog-ordering' );
}
/**
* Gets the catalogue ordering arguments.
*
* #access public
* #since 5.1.0
* #param array $args The arguments.
* #return array
*/
function get_catalog_ordering_args( $args ) {
global $woocommerce;
$woo_default_catalog_orderby = get_option( 'woocommerce_default_catalog_orderby' );
// Get the query args.
if ( isset( $_SERVER['QUERY_STRING'] ) ) {
parse_str( sanitize_text_field( wp_unslash( $_SERVER['QUERY_STRING'] ) ), $params );
}
// Get order by.
$pob = ( ! empty( $params['product_orderby'] ) ) ? $params['product_orderby'] : $woo_default_catalog_orderby;
// Get order.
$po = 'asc';
if ( isset( $params['product_order'] ) ) {
// Dedicated ordering.
$po = $params['product_order'];
} else {
// Get the correct default order.
$po = 'asc';
if ( 'date' === $pob || 'popularity' === $pob || 'rating' === $pob || 'price-desc' === $pob ) {
$po = 'desc';
}
}
// Remove posts_clause filter, if default ordering is set to rating or popularity to make custom ordering work correctly.
if ( 'default' !== $pob ) {
if ( 'popularity' === $woo_default_catalog_orderby || 'rating' === $woo_default_catalog_orderby ) {
WC()->query->remove_ordering_args();
}
}
$orderby = 'date';
$order = strtoupper( $po );
$meta_key = '';
switch ( $pob ) {
case 'menu_order':
case 'default':
$orderby = $args['orderby'];
break;
case 'date':
$orderby = 'date';
break;
case 'price':
case 'price-desc':
add_filter( 'posts_clauses', array( $this, 'order_by_price_post_clauses' ) );
add_action( 'wp', array( $this, 'remove_ordering_args_filters' ) );
break;
case 'popularity':
$meta_key = 'total_sales';
add_filter( 'posts_clauses', array( $this, 'order_by_popularity_post_clauses' ) );
add_action( 'wp', array( $this, 'remove_ordering_args_filters' ) );
break;
case 'rating':
$meta_key = '_wc_average_rating';
$orderby = array(
'meta_value_num' => strtoupper( $po ),
'ID' => 'ASC',
);
break;
case 'name':
$orderby = 'title';
break;
}
$args['orderby'] = $orderby;
$args['order'] = $order;
$args['meta_key'] = $meta_key;
return $args;
}
if i just modify the following:
// Remove posts_clause filter, if default ordering is set to rating or popularity to make custom ordering work correctly.
if ( 'default' !== $pob ) {
if ( 'popularity' === $woo_default_catalog_orderby || 'rating' === $woo_default_catalog_orderby ) {
WC()->query->remove_ordering_args();
}
}
$orderby = 'date';
$order = strtoupper( $po );
$meta_key = '';
to
// Remove posts_clause filter, if default ordering is set to rating or popularity to make custom ordering work correctly.
if ( 'default' !== $pob ) {
if ( 'popularity' === $woo_default_catalog_orderby || 'rating' === $woo_default_catalog_orderby ) {
WC()->query->remove_ordering_args();
}
}
$orderby = 'menu_order Date';
$order = strtoupper( $po );
$meta_key = '';
$orderby = 'menu_order Date'; instead of $orderby = 'date';
it's simply am forcing the avada to use my own custom ordering instead of date.
but that not really practical solution as i modified class-avada-woocommerce.php
is there any suggestion to do find solution by add some code to avada child them instead
There is nothing wrong with the Avada Code.
Avada intentionally unhooks the filter 'woocommerce_get_catalog_ordering_args' and writes its own filter "catalog_ordering" in
'/wp-content/themes/Avada/includes/class-avada-woocommerce.php'
That calls
'/wp-content/themes/Avada/templates/wc-catalog-ordering.php'
Please overwrite the template by using your child theme and copying the contents of wc-catalog-ordering.php.
i.e. "/wp-content/themes/Avada-Child-Theme/templates/wc-catalog-ordering.php"
You'll be able to handle the orders however you'd like once complete.
Previously mentioned, the function "remove_avada_function" is hooked on 'after_setup_theme' and is used to remove the hook. However since 'remove_avada_function' is called before the action 'pre_get_post' is called, 'remove_avada_function' won't remove the action that does not currently exist.
Update 2:
I think that if you add a highest priority than Avada's theme hook it will work (here I have set it to 100), and the only change to do in this function is $args['orderby'] = 'menu_order date'; to get the similar change you have done on Avada's files.
The code:
add_filter( 'woocommerce_get_catalog_ordering_args', 'custom_catalog_ordering_args', 100 );
function custom_woocommerce_get_catalog_ordering_args( $args ) {
$args['orderby'] = 'menu_order date';
return $args;
}
This code goes in function.php file of your active child theme.
It should work
The very strange thing is that woocommerce_get_catalog_ordering_args is a filter hook, but NOT an action hook (so I have changed my code)…
Then something is wrong in the Avada's theme code and you should report it to the support.
You just need to increase your hooked function, so it will override Avada's:
add_action('after_setup_theme', 'remove_avada_function' );
function remove_avada_function(){
remove_action( 'woocommerce_before_shop_loop', 'catalog_ordering', 30 );
add_action( 'woocommerce_before_shop_loop', 'custom_catalog_ordering', 30 );
}
You can use this code to set Avada catalog sort hook back to woocommerce default.
function avada_remove_ordering() {
global $avada_woocommerce;
remove_action('pre_get_posts', array( $avada_woocommerce, 'product_ordering' ), 5);
add_action( 'woocommerce_before_shop_loop', 'woocommerce_catalog_ordering', 30 );
}
add_action( 'init', 'avada_remove_ordering' );
add_filter( 'woocommerce_get_catalog_ordering_args', 'custom_woocommerce_get_catalog_ordering_args' , 12);
function custom_woocommerce_get_catalog_ordering_args( $args ) {
$orderby_value = isset( $_GET['orderby'] ) ? wc_clean( $_GET['orderby'] ) : apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby' ) );
if ( 'sale_price' == $orderby_value ) {
$args['orderby'] = 'meta_value_num';
$args['order'] = 'ASC';
$args['meta_key'] = '_sale_price';
}
return $args;
}
add_filter( 'woocommerce_default_catalog_orderby_options', 'custom_woocommerce_catalog_orderby', 12 );
add_filter( 'woocommerce_catalog_orderby', 'custom_woocommerce_catalog_orderby', 12 );
function custom_woocommerce_catalog_orderby( $sortby ) {
$sortby['sale_price'] = 'Sale';
return $sortby;
}
I've been bouncing my head of a brick wall trying to hide a custom tab depending on grouped_products->child_products attributes so I was wondering is there a simple way to check if my custom tab contains a $product element? if it does not contain a $product then hide the tab?
I can't hide the tab if empty as my custom PHP file (grouped.php) spits out the table even if there is no content (products) with in it.
Currently the function I'm using is not working and the tab shows either way for some reason. This function is supposed to check the child products of the group and then determine if an attribute is present 'PAYG' if so return the custom tab if not do not return the custom tab but it is showing on pages it's not supposed to be at the minute so it is not working.
add_filter( 'woocommerce_product_tabs', 'woo_simfree_product_tab' );
function woo_simfree_product_tab( $tabs ) {
global $post;
if (function_exists( 'get_product' )) {
$product = get_product( $post->ID );
if ($product->is_type( 'grouped' )) {
$PAYG = false;
foreach ($product->get_children() as $child_id) {
$child = get_product($child_id);
$attr = $child->get_attribute('contract-type');
if ($attr == 'PAYG') {
$PAYG = true;
}
}
if ($PAYG = true) {
$tabs['simfree-plans'] = array( 'title' => __( 'SIM Free', 'woocommerce' ), 'priority' => 20, 'callback' => 'woo_simfree_product_tab_content' );
} else {
return $tabs;
}
} else {
return $tabs;
}
}
}
Is there anyway to just check weather the tab contains a $grouped_product that would be so much easier to code then if there is no product there just hide the tab.
My tab contents are calling a custom grouped.php..
// Function below creates an add to cart function which fetches a custom template from child theme. To add more custom add to cart templates just copy and change the path.
function woocommerce_grouped_simfree() {
global $product;
wc_get_template( 'single-product/add-to-cart/grouped-simfree.php', array(
'grouped_product' => $product,
'grouped_products' => $product->get_children(),
'quantites_required' => false
) );
}
// Tab content for custom tab
function woo_simfree_product_tab_content() {
woocommerce_grouped_simfree();
}
Please help thanks
try this
function woo_simfree_product_tab( $tabs ) {
global $post;
$PAYG = false;
if (function_exists( 'get_product' )) {
$product = get_product( $post->ID );
if ($product->is_type( 'grouped' )) {
foreach ($product->get_children() as $child_id) {
$child = get_product($child_id);
$attr = $child->get_attribute('contract-type');
if ($attr == 'PAYG') {
$PAYG = true;
break;
}
}
}
}
if ($PAYG == true) {
$tabs['simfree-plans'] = array( 'title' => __( 'SIM Free', 'woocommerce' ), 'priority' => 20, 'callback' => 'woo_simfree_product_tab_content' );
}
return $tabs;
}
also, make sure $attr = $child->get_attribute('contract-type'); is getting the right value... try checking it.
I'm trying to hide the related products on single product pages in a category (using Woocommerce). This is what I have so far, and it hides related products on ALL categories:
function wc_remove_related_products( $args )
{
if (is_product() && has_term( 'Donations', 'product_cat'))
{
return array();
}
}
add_filter('woocommerce_related_products_args','wc_remove_related_products', 10);
I believe you need to return the original, supplied $args if your conditional isn't true:
function wc_remove_related_products( $args )
{
if (is_product() && has_term( 'Donations', 'product_cat'))
{
return array();
}
return $args;
}
add_filter('woocommerce_related_products_args','wc_remove_related_products', 10);
Do it like this:
function wc_remove_related_products( $args ) {
return array();
}
add_filter('woocommerce_related_products_args','wc_remove_related_products', 10);