How to customize bank details styles in Woocommerce order emails? - php

This section within Woocommerce order emails comes from the code in woocommerce/includes/gateways/class-wc-gateway-bacs.php
/**
* Get bank details and place into a list format.
*
* #param int $order_id Order ID.
*/
private function bank_details( $order_id = '' ) {
if ( empty( $this->account_details ) ) {
return;
}
// Get order and store in $order.
$order = wc_get_order( $order_id );
// Get the order country and country $locale.
$country = $order->get_billing_country();
$locale = $this->get_country_locale();
// Get sortcode label in the $locale array and use appropriate one.
$sortcode = isset( $locale[ $country ]['sortcode']['label'] ) ? $locale[ $country ]['sortcode']['label'] : __( 'Sort code', 'woocommerce' );
$bacs_accounts = apply_filters( 'woocommerce_bacs_accounts', $this->account_details, $order_id );
if ( ! empty( $bacs_accounts ) ) {
$account_html = '';
$has_details = false;
foreach ( $bacs_accounts as $bacs_account ) {
$bacs_account = (object) $bacs_account;
if ( $bacs_account->account_name ) {
$account_html .= '<h3 class="wc-bacs-bank-details-account-name">' . wp_kses_post( wp_unslash( $bacs_account->account_name ) ) . ':</h3>' . PHP_EOL;
}
$account_html .= '<ul class="wc-bacs-bank-details order_details bacs_details">' . PHP_EOL;
// BACS account fields shown on the thanks page and in emails.
$account_fields = apply_filters(
'woocommerce_bacs_account_fields',
array(
'bank_name' => array(
'label' => __( 'Bank', 'woocommerce' ),
'value' => $bacs_account->bank_name,
),
'account_number' => array(
'label' => __( 'Account number', 'woocommerce' ),
'value' => $bacs_account->account_number,
),
'sort_code' => array(
'label' => $sortcode,
'value' => $bacs_account->sort_code,
),
'iban' => array(
'label' => __( 'IBAN', 'woocommerce' ),
'value' => $bacs_account->iban,
),
'bic' => array(
'label' => __( 'BIC', 'woocommerce' ),
'value' => $bacs_account->bic,
),
),
$order_id
);
foreach ( $account_fields as $field_key => $field ) {
if ( ! empty( $field['value'] ) ) {
$account_html .= '<li class="' . esc_attr( $field_key ) . '">' . wp_kses_post( $field['label'] ) . ': <strong>' . wp_kses_post( wptexturize( $field['value'] ) ) . '</strong></li>' . PHP_EOL;
$has_details = true;
}
}
$account_html .= '</ul>';
}
if ( $has_details ) {
echo '<section class="woocommerce-bacs-bank-details"><h2 class="wc-bacs-bank-details-heading">' . esc_html__( 'Our bank details', 'woocommerce' ) . '</h2>' . wp_kses_post( PHP_EOL . $account_html ) . '</section>';
}
}
}
How can I override this section styles (headings + list) without it affecting all headings as recommended here: How to stylize bank details in WooCommerce email?
Any help appreciated.

Related

WooCommerce: How to change "Our Bank Details" heading?

In the email WooCommerce sends to customers if they ordered a product and picked bank transfer (BACS) as payment method, by default there is an h2 heading: "Our bank details". I want to change this wording.
I figure I best do this via functions.php, but I am not sure how to address this. Could someone please help me?
Alternative approaches to solve this problem are welcome, too.
The line I want to change is in this if-statement in class-wc-gateways-bacs.php:
if ( $has_details ) { echo '<section class="woocommerce-bacs-bank-details"><h2 class="wc-bacs-bank-details-heading">' . esc_html__( 'Our bank details', 'woocommerce' ) . '</h2>' . wp_kses_post( PHP_EOL . $account_html ) . '</section>';
Here is the complete function from within the class WC_Gateway_BACS extends WC_Payment_Gateway:
private function bank_details( $order_id = '' ) {
if ( empty( $this->account_details ) ) {
return;
}
// Get order and store in $order.
$order = wc_get_order( $order_id );
// Get the order country and country $locale.
$country = $order->get_billing_country();
$locale = $this->get_country_locale();
// Get sortcode label in the $locale array and use appropriate one.
$sortcode = isset( $locale[ $country ]['sortcode']['label'] ) ? $locale[ $country ]['sortcode']['label'] : __( 'Sort code', 'woocommerce' );
$bacs_accounts = apply_filters( 'woocommerce_bacs_accounts', $this->account_details, $order_id );
if ( ! empty( $bacs_accounts ) ) {
$account_html = '';
$has_details = false;
foreach ( $bacs_accounts as $bacs_account ) {
$bacs_account = (object) $bacs_account;
if ( $bacs_account->account_name ) {
$account_html .= '<h3 class="wc-bacs-bank-details-account-name">' . wp_kses_post( wp_unslash( $bacs_account->account_name ) ) . ':</h3>' . PHP_EOL;
}
$account_html .= '<ul class="wc-bacs-bank-details order_details bacs_details">' . PHP_EOL;
// BACS account fields shown on the thanks page and in emails.
$account_fields = apply_filters(
'woocommerce_bacs_account_fields',
array(
'bank_name' => array(
'label' => __( 'Bank', 'woocommerce' ),
'value' => $bacs_account->bank_name,
),
'account_number' => array(
'label' => __( 'Account number', 'woocommerce' ),
'value' => $bacs_account->account_number,
),
'sort_code' => array(
'label' => $sortcode,
'value' => $bacs_account->sort_code,
),
'iban' => array(
'label' => __( 'IBAN', 'woocommerce' ),
'value' => $bacs_account->iban,
),
'bic' => array(
'label' => __( 'BIC', 'woocommerce' ),
'value' => $bacs_account->bic,
),
),
$order_id
);
foreach ( $account_fields as $field_key => $field ) {
if ( ! empty( $field['value'] ) ) {
$account_html .= '<li class="' . esc_attr( $field_key ) . '">' . wp_kses_post( $field['label'] ) . ': <strong>' . wp_kses_post( wptexturize( $field['value'] ) ) . '</strong></li>' . PHP_EOL;
$has_details = true;
}
}
$account_html .= '</ul>';
}
if ( $has_details ) {
echo '<section class="woocommerce-bacs-bank-details"><h2 class="wc-bacs-bank-details-heading">' . esc_html__( 'Our bank details', 'woocommerce' ) . '</h2>' . wp_kses_post( PHP_EOL . $account_html ) . '</section>';
}
}
}
Please try this
function update_bank_details_heading($translated_text, $text, $domain) {
if ( did_action('woocommerce_email_before_order_table') ) {
switch ( $text ) {
case 'Our bank details' :
$translated_text = __( 'Bank Details Are...', 'woocommerce' );
break;
}
}
return $translated_text;
}
add_filter( 'gettext', 'update_bank_details_heading', 20, 3 );

Getting current active product filter

There is a widget called Active Product Filter in WooCommerce, I couldn't find a way to override it's designed so I tried making my own;
function abc_active_filter(){
$queryData = array();
parse_str($_SERVER['QUERY_STRING'], $queryData);
$active_filter = '';
foreach($queryData as $key => $value){
$active_filter = $active_filter.'<div>CLIK TO REMOVE - <span>'.$key.'</span><div>';
}
if(sizeof($queryData) > 0){
$active_filter = '<h3>Active Filter</h3>'.$active_filter;
}
return $active_filter;
}
add_shortcode('csx_active_filter', 'abc_active_filter');
This will output the query key of the current URL, for example;
min_price,
filter_size
whereas using the widget Active Product Filter the output is;
Min Price $589
Large
is there a way to achieve the output the same as the Active Product Filter? I found this the same question with me but the accepted answer is far different from what I'm trying to achieve and the one who asked the question is only looking for active filters by checking the query key.
Anyway, with the following code, I can achieve the same output of Active Product Filter;
if($key === 'min_price'){
$active_filter = $active_filter.'<div>CLIK TO REMOVE - <span>Min Price '.$value.'</span><div>';
}else if($key === 'filter_size'){
$active_filter = $active_filter.'<div>CLIK TO REMOVE - <span>'.$value.'</span><div>';
}else if .... and so on...
The problem is, filters are dynamic and I don't know all of them and it will take a lot of lines of codes to put them in conditional statements.
You can try using WC_Query::get_layered_nav_chosen_attributes();, simply print its value and see if the result is what you need.
print_r(WC_Query::get_layered_nav_chosen_attributes());
Otherwise, I wouldn't recommend to reinvent the wheel. You can override the widget by extending the class of WC_Widget_Layered_Nav_Filters.
In your functions.php, insert the below code. You can change its layout, elements depending on what design you wanted.
class Your_New_WC_Widget_Layered_Nav_Filters extends WC_Widget_Layered_Nav_Filters {
/**
* Constructor.
*/
public function __construct() {
$this->widget_cssclass = 'woocommerce widget_layered_nav_filters';
$this->widget_description = __( 'Display a list of active product filters.', 'woocommerce' );
$this->widget_id = 'woocommerce_layered_nav_filters';
$this->widget_name = __( 'Active Product Filters', 'woocommerce' );
$this->settings = array(
'title' => array(
'type' => 'text',
'std' => __( 'The Active filters', 'woocommerce' ),
'label' => __( 'Title', 'woocommerce' ),
),
);
parent::__construct();
}
/**
* Output widget.
*
* #see WP_Widget
* #param array $args Arguments.
* #param array $instance Widget instance.
*/
public function widget( $args, $instance ) {
if ( ! is_shop() && ! is_product_taxonomy() ) {
return;
}
$_chosen_attributes = WC_Query::get_layered_nav_chosen_attributes();
$min_price = isset( $_GET['min_price'] ) ? wc_clean( wp_unslash( $_GET['min_price'] ) ) : 0; // WPCS: input var ok, CSRF ok.
$max_price = isset( $_GET['max_price'] ) ? wc_clean( wp_unslash( $_GET['max_price'] ) ) : 0; // WPCS: input var ok, CSRF ok.
$rating_filter = isset( $_GET['rating_filter'] ) ? array_filter( array_map( 'absint', explode( ',', wp_unslash( $_GET['rating_filter'] ) ) ) ) : array(); // WPCS: sanitization ok, input var ok, CSRF ok.
$base_link = $this->get_current_page_url();
if ( 0 < count( $_chosen_attributes ) || 0 < $min_price || 0 < $max_price || ! empty( $rating_filter ) ) {
$this->widget_start( $args, $instance );
echo '<ul>';
// Attributes.
if ( ! empty( $_chosen_attributes ) ) {
foreach ( $_chosen_attributes as $taxonomy => $data ) {
foreach ( $data['terms'] as $term_slug ) {
$term = get_term_by( 'slug', $term_slug, $taxonomy );
if ( ! $term ) {
continue;
}
$filter_name = 'filter_' . wc_attribute_taxonomy_slug( $taxonomy );
$current_filter = isset( $_GET[ $filter_name ] ) ? explode( ',', wc_clean( wp_unslash( $_GET[ $filter_name ] ) ) ) : array(); // WPCS: input var ok, CSRF ok.
$current_filter = array_map( 'sanitize_title', $current_filter );
$new_filter = array_diff( $current_filter, array( $term_slug ) );
$link = remove_query_arg( array( 'add-to-cart', $filter_name ), $base_link );
if ( count( $new_filter ) > 0 ) {
$link = add_query_arg( $filter_name, implode( ',', $new_filter ), $link );
}
echo '<li class="chosen"><a rel="nofollow" aria-label="' . esc_attr__( 'Remove filter', 'woocommerce' ) . '" href="' . esc_url( $link ) . '">' . esc_html( $term->name ) . '</a></li>';
}
}
}
if ( $min_price ) {
$link = remove_query_arg( 'min_price', $base_link );
/* translators: %s: minimum price */
echo '<li class="chosen"><a rel="nofollow" aria-label="' . esc_attr__( 'Remove filter', 'woocommerce' ) . '" href="' . esc_url( $link ) . '">' . sprintf( __( 'Min %s', 'woocommerce' ), wc_price( $min_price ) ) . '</a></li>'; // WPCS: XSS ok.
}
if ( $max_price ) {
$link = remove_query_arg( 'max_price', $base_link );
/* translators: %s: maximum price */
echo '<li class="chosen"><a rel="nofollow" aria-label="' . esc_attr__( 'Remove filter', 'woocommerce' ) . '" href="' . esc_url( $link ) . '">' . sprintf( __( 'Max %s', 'woocommerce' ), wc_price( $max_price ) ) . '</a></li>'; // WPCS: XSS ok.
}
if ( ! empty( $rating_filter ) ) {
foreach ( $rating_filter as $rating ) {
$link_ratings = implode( ',', array_diff( $rating_filter, array( $rating ) ) );
$link = $link_ratings ? add_query_arg( 'rating_filter', $link_ratings ) : remove_query_arg( 'rating_filter', $base_link );
/* translators: %s: rating */
echo '<li class="chosen"><a rel="nofollow" aria-label="' . esc_attr__( 'Remove filter', 'woocommerce' ) . '" href="' . esc_url( $link ) . '">' . sprintf( esc_html__( 'Rated %s out of 5', 'woocommerce' ), esc_html( $rating ) ) . '</a></li>';
}
}
echo '</ul>';
$this->widget_end( $args );
}
}
}
Now, in your functions.php, insert the below code again. This will unregister the default widget and replace with the new one above where your custom design or layout exist.
function your_function_for_overriding_widgets() {
unregister_widget( 'WC_Widget_Layered_Nav_Filters' ); //unregistered the default widget
register_widget( 'Your_New_WC_Widget_Layered_Nav_Filters' ); //register your new widget
}
add_action( 'widgets_init', 'your_function_for_overriding_widgets' );

Show woocommerce product custom fields under the cart and order item name

I have a code that shows custom fields in the "General" tab on the product edit page.
After the manager has filled these fields, the data is displayed on the Archive/Category pages and in the Single Product page.
Also, these fields are in the cart and on the checkout page.
Here is my code:
// Display Fields using WooCommerce Action Hook
add_action( 'woocommerce_product_options_general_product_data', 'woocom_general_product_data_custom_field' );
function woocom_general_product_data_custom_field() {
// Create a custom text field
// Custom Weight Field
woocommerce_wp_text_input(
array(
'id' => '_custom_weight',
'label' => __( 'Weight dishes', 'woocommerce' ),
'placeholder' => '',
'desc_tip' => 'true',
'description' => __( '', 'woocommerce' )
)
);
// Calories Field
woocommerce_wp_text_input(
array(
'id' => '_сalories',
'label' => __( 'Calories', 'woocommerce' ),
'placeholder' => '',
'desc_tip' => 'false',
'description' => __( '', 'woocommerce' )
)
);
// Ingredients Field
woocommerce_wp_textarea_input(
array(
'id' => '_ingredients',
'label' => __( 'Ingredients', 'woocommerce' ),
'placeholder' => '',
'desc_tip' => 'true',
'description' => __( '', 'woocommerce' )
)
);
}
// Hook to save the data value from the custom fields
add_action( 'woocommerce_process_product_meta', 'woocom_save_general_proddata_custom_field' );
// Hook callback function to save custom fields information
function woocom_save_general_proddata_custom_field( $post_id ) {
// Save Custom Weight Field
$custom_weight = $_POST['_custom_weight'];
if( ! empty( $custom_weight ) ) {
update_post_meta( $post_id, '_custom_weight', esc_attr( $custom_weight ) );
} else {
delete_post_meta( $post_id, '_custom_weight' );
}
// Save Calories Field
$сalories = $_POST['_сalories'];
if( ! empty( $сalories ) ) {
update_post_meta( $post_id, '_сalories', esc_attr( $сalories ) );
} else {
delete_post_meta( $post_id, '_сalories' );
}
// Save Ingredients Field
$ingredients = $_POST['_ingredients'];
if( ! empty( $ingredients ) ) {
update_post_meta( $post_id, '_ingredients', esc_html( $ingredients ) );
} else {
delete_post_meta( $post_id, '_ingredients' );
}
}
// Displaying the custom field value (on single product pages under short description)
add_action('woocommerce_before_add_to_cart_form', 'display_custom_meta_field_value', 25 );
add_action('woocommerce_after_shop_loop_item', 'display_custom_meta_field_value', 25 );
function display_custom_meta_field_value() {
global $product;
$custom_weight = get_post_meta( $product->get_id(),'_custom_weight', true );
if( ! empty( $custom_weight ) )
echo '<p id="value-on-single-product">' . 'Weight: ' . $custom_weight . 'g' . '</p>';
$сalories = get_post_meta( $product->get_id(),'_сalories', true );
if( ! empty( $сalories ) )
echo '<p id="value-on-single-product">' . 'Calories: ' . $сalories . ' kcal.' . '</p>';
$ingredients = get_post_meta( $product->get_id(),'_ingredients', true );
if( ! empty( $ingredients ) )
echo '<p id="value-on-single-product">' . 'Ingredients: ' . $ingredients . '</p>';
}
// Render the custom product field in cart and checkout
add_filter( 'woocommerce_get_item_data', 'woocom_custom_fields_cart', 10, 2 );
function woocom_custom_fields_cart( $cart_data, $cart_item )
{
$custom_items = array();
if( !empty( $cart_data ) )
$custom_items = $cart_data;
// Get the product ID
$product_id = $cart_item['product_id'];
if( $custom_field_value = get_post_meta( $product_id, '_custom_weight', true ) )
$custom_items[] = array(
'name' => __( 'Weight', 'woocommerce' ),
'value' => $custom_field_value,
'display' => $custom_field_value . 'g',
);
return $custom_items;
}
But unfortunately, it’s impossible for me to add these custom fields after the product name on the Thank You page, in the E-mail and on the order editing page.
I also have doubts whether the above code is correct, although everything works.
I will be glad for your help!
I have revisited your code and made some changes, adding the necessary code to display your custom fields data on cart, checkout, order received, my account order view and on email notifications (for Woocommerce 3+):
// Backend: Display additional product fields
add_action( 'woocommerce_product_options_general_product_data', 'add_fields_to_options_general_product_data' );
function add_fields_to_options_general_product_data() {
// Custom Weight Field
woocommerce_wp_text_input( array(
'id' => '_custom_weight',
'label' => __( 'Weight dishes', 'woocommerce' ),
));
// Calories Field
woocommerce_wp_text_input( array(
'id' => '_сalories',
'label' => __( 'Calories', 'woocommerce' ),
));
// Ingredients Field
woocommerce_wp_textarea_input( array(
'id' => '_ingredients',
'label' => __( 'Ingredients', 'woocommerce' ),
));
}
// Backend: Save the data value from the custom fields
add_action( 'woocommerce_admin_process_product_object', 'save_admin_product_custom_fields_values' );
function save_admin_product_custom_fields_values( $product ) {
// Save Custom Weight Field
if( isset( $_POST['_custom_weight'] ) ) {
$product->update_meta_data( '_custom_weight', sanitize_text_field( $_POST['_custom_weight'] ) );
}
// Save Calories Field
if( isset( $_POST['_сalories'] ) ) {
$product->update_meta_data( '_сalories', sanitize_text_field( $_POST['_сalories'] ) );
}
// Save Ingredients Field
if( isset( $_POST['_ingredients'] ) ) {
$product->update_meta_data( '_ingredients', sanitize_textarea_field( $_POST['_ingredients'] ) );
}
}
// Display product custom fields values on single product pages under short description and on archive pages
add_action('woocommerce_before_add_to_cart_form', 'display_custom_meta_field_value', 25 );
add_action('woocommerce_after_shop_loop_item', 'display_custom_meta_field_value', 25 );
function display_custom_meta_field_value() {
global $product;
if( $custom_weight = $product->get_meta('_custom_weight') )
echo '<p id="value-on-single-product">' . __("Weight:", "woocommerce") . ' ' . $custom_weight . 'g' . '</p>';
if( $сalories = $product->get_meta('_сalories') )
echo '<p id="value-on-single-product">' . __("Calories:", "woocommerce") . ' ' . $сalories . ' kcal.' . '</p>';
if( $ingredients = $product->get_meta('_ingredients') )
echo '<p id="value-on-single-product">' . __("Ingredients:", "woocommerce") . ' ' . $ingredients . '</p>';
}
// Add custom fields values under cart item name in cart
add_filter( 'woocommerce_cart_item_name', 'custom_cart_item_name', 10, 3 );
function custom_cart_item_name( $item_name, $cart_item, $cart_item_key ) {
if( ! is_cart() )
return $item_name;
if( $value1 = $cart_item['data']->get_meta('_custom_weight') ) {
$item_name .= '<br><span class="custom-field"><strong>' . __("Weight", "woocommerce") . ':</strong> ' . $value1 . 'g</span>';
}
if( $value2 = $cart_item['data']->get_meta('_сalories') ) {
$item_name .= '<br><span class="custom-field"><strong>' . __("Calories", "woocommerce") . ':</strong> ' . $value2 . 'kcal</span>';
}
if( $value3 = $cart_item['data']->get_meta('_ingredients') ) {
$item_name .= '<br><span class="custom-field"><strong>' . __("Ingredients", "woocommerce") . ':</strong> <br>' . $value3 . '</span>';
}
return $item_name;
}
// Display custom fields values under item name in checkout
add_filter( 'woocommerce_checkout_cart_item_quantity', 'custom_checkout_cart_item_name', 10, 3 );
function custom_checkout_cart_item_name( $item_qty, $cart_item, $cart_item_key ) {
if( $value1 = $cart_item['data']->get_meta('_custom_weight') ) {
$item_qty .= '<br><span class="custom-field"><strong>' . __("Weight", "woocommerce") . ':</strong> ' . $value1 . 'g</span>';
}
if( $value2 = $cart_item['data']->get_meta('_сalories') ) {
$item_qty .= '<br><span class="custom-field"><strong>' . __("Calories", "woocommerce") . ':</strong> ' . $value2 . 'kcal</span>';
}
if( $value3 = $cart_item['data']->get_meta('_ingredients') ) {
$item_qty .= '<br><span class="custom-field"><strong>' . __("Ingredients", "woocommerce") . ':</strong> <br>' . $value3 . '</span>';
}
return $item_qty;
}
// Display custom fields values on orders and email notifications
add_filter( 'woocommerce_order_item_name', 'custom_order_item_name', 10, 2 );
function custom_order_item_name( $item_name, $item ) {
$product = $item->get_product();
if( $value1 = $product->get_meta('_custom_weight') ) {
$item_name .= '<br><span class="custom-field"><strong>' . __("Weight", "woocommerce") . ':</strong> ' . $value1 . 'g</span>';
}
if( $value2 = $product->get_meta('_сalories') ) {
$item_name .= '<br><span class="custom-field"><strong>' . __("Calories", "woocommerce") . ':</strong> ' . $value2 . 'kcal</span>';
}
if( $value3 = $product->get_meta('_ingredients') ) {
$item_name .= '<br><span class="custom-field"><strong>' . __("Ingredients", "woocommerce") . ':</strong> <br>' . $value3 . '</span>';
}
return $item_name;
}
Code goes on function.php file of your active child theme (or active theme). Tested and works.
On cart page:
On checkout page:
On order received page:
On email notifications:

Woocommerce Price Filter Php text wraps

On my woocommerce site I added the woocommerce price filter in the sidebar of the store. The problem is that the price is placed next to the Filter button and then the text wraps. How can I move the text above the button? Do I have to change the php code of the price filter?
I inspected the page with google chrome and I saw that moving a div further up I solved the problem, but how do I apply it?
look at the sidebar link
this is the php file
class WC_Widget_Price_Filter extends WC_Widget {
/**
* Constructor.
*/
public function __construct() {
$this->widget_cssclass = 'woocommerce widget_price_filter';
$this->widget_description = __( 'Display a slider to filter products in your store by price.', 'woocommerce' );
$this->widget_id = 'woocommerce_price_filter';
$this->widget_name = __( 'Filter Products by Price', 'woocommerce' );
$this->settings = array(
'title' => array(
'type' => 'text',
'std' => __( 'Filter by price', 'woocommerce' ),
'label' => __( 'Title', 'woocommerce' ),
),
);
$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
wp_register_script( 'accounting', WC()->plugin_url() . '/assets/js/accounting/accounting' . $suffix . '.js', array( 'jquery' ), '0.4.2' );
wp_register_script( 'wc-jquery-ui-touchpunch', WC()->plugin_url() . '/assets/js/jquery-ui-touch-punch/jquery-ui-touch-punch' . $suffix . '.js', array( 'jquery-ui-slider' ), WC_VERSION, true );
wp_register_script( 'wc-price-slider', WC()->plugin_url() . '/assets/js/frontend/price-slider' . $suffix . '.js', array( 'jquery-ui-slider', 'wc-jquery-ui-touchpunch', 'accounting' ), WC_VERSION, true );
wp_localize_script( 'wc-price-slider', 'woocommerce_price_slider_params', array(
'currency_format_num_decimals' => 0,
'currency_format_symbol' => get_woocommerce_currency_symbol(),
'currency_format_decimal_sep' => esc_attr( wc_get_price_decimal_separator() ),
'currency_format_thousand_sep' => esc_attr( wc_get_price_thousand_separator() ),
'currency_format' => esc_attr( str_replace( array( '%1$s', '%2$s' ), array( '%s', '%v' ), get_woocommerce_price_format() ) ),
) );
if ( is_customize_preview() ) {
wp_enqueue_script( 'wc-price-slider' );
}
parent::__construct();
}
/**
* Output widget.
*
* #see WP_Widget
*
* #param array $args
* #param array $instance
*/
public function widget( $args, $instance ) {
global $wp;
if ( ! is_shop() && ! is_product_taxonomy() ) {
return;
}
if ( ! wc()->query->get_main_query()->post_count ) {
return;
}
wp_enqueue_script( 'wc-price-slider' );
// Find min and max price in current result set.
$prices = $this->get_filtered_price();
$min = floor( $prices->min_price );
$max = ceil( $prices->max_price );
if ( $min === $max ) {
return;
}
$this->widget_start( $args, $instance );
if ( '' === get_option( 'permalink_structure' ) ) {
$form_action = remove_query_arg( array( 'page', 'paged', 'product-page' ), add_query_arg( $wp->query_string, '', home_url( $wp->request ) ) );
} else {
$form_action = preg_replace( '%\/page/[0-9]+%', '', home_url( trailingslashit( $wp->request ) ) );
}
$min_price = isset( $_GET['min_price'] ) ? esc_attr( $_GET['min_price'] ) : apply_filters( 'woocommerce_price_filter_widget_min_amount', $min );
$max_price = isset( $_GET['max_price'] ) ? esc_attr( $_GET['max_price'] ) : apply_filters( 'woocommerce_price_filter_widget_max_amount', $max );
echo '<form method="get" action="' . esc_url( $form_action ) . '">
<div class="price_slider_wrapper">
<div class="price_slider" style="display:none;"></div>
<div class="price_slider_amount">
<input type="text" id="min_price" name="min_price" value="' . esc_attr( $min_price ) . '" data-min="' . esc_attr( apply_filters( 'woocommerce_price_filter_widget_min_amount', $min ) ) . '" placeholder="' . esc_attr__( 'Min price', 'woocommerce' ) . '" />
<input type="text" id="max_price" name="max_price" value="' . esc_attr( $max_price ) . '" data-max="' . esc_attr( apply_filters( 'woocommerce_price_filter_widget_max_amount', $max ) ) . '" placeholder="' . esc_attr__( 'Max price', 'woocommerce' ) . '" />
<button type="submit" class="button">' . esc_html__( 'Filter', 'woocommerce' ) . '</button>
<div class="price_label" style="display:none;">
' . esc_html__( 'Price:', 'woocommerce' ) . ' <span class="from"></span> — <span class="to"></span>
</div>
' . wc_query_string_form_fields( null, array( 'min_price', 'max_price' ), '', true ) . '
<div class="clear"></div>
</div>
</div>
</form>';
$this->widget_end( $args );
}
/**
* Get filtered min price for current products.
* #return int
*/
protected function get_filtered_price() {
global $wpdb;
$args = wc()->query->get_main_query()->query_vars;
$tax_query = isset( $args['tax_query'] ) ? $args['tax_query'] : array();
$meta_query = isset( $args['meta_query'] ) ? $args['meta_query'] : array();
if ( ! is_post_type_archive( 'product' ) && ! empty( $args['taxonomy'] ) && ! empty( $args['term'] ) ) {
$tax_query[] = array(
'taxonomy' => $args['taxonomy'],
'terms' => array( $args['term'] ),
'field' => 'slug',
);
}
foreach ( $meta_query + $tax_query as $key => $query ) {
if ( ! empty( $query['price_filter'] ) || ! empty( $query['rating_filter'] ) ) {
unset( $meta_query[ $key ] );
}
}
$meta_query = new WP_Meta_Query( $meta_query );
$tax_query = new WP_Tax_Query( $tax_query );
$meta_query_sql = $meta_query->get_sql( 'post', $wpdb->posts, 'ID' );
$tax_query_sql = $tax_query->get_sql( $wpdb->posts, 'ID' );
$sql = "SELECT min( FLOOR( price_meta.meta_value ) ) as min_price, max( CEILING( price_meta.meta_value ) ) as max_price FROM {$wpdb->posts} ";
$sql .= " LEFT JOIN {$wpdb->postmeta} as price_meta ON {$wpdb->posts}.ID = price_meta.post_id " . $tax_query_sql['join'] . $meta_query_sql['join'];
$sql .= " WHERE {$wpdb->posts}.post_type IN ('" . implode( "','", array_map( 'esc_sql', apply_filters( 'woocommerce_price_filter_post_type', array( 'product' ) ) ) ) . "')
AND {$wpdb->posts}.post_status = 'publish'
AND price_meta.meta_key IN ('" . implode( "','", array_map( 'esc_sql', apply_filters( 'woocommerce_price_filter_meta_keys', array( '_price' ) ) ) ) . "')
AND price_meta.meta_value > '' ";
$sql .= $tax_query_sql['where'] . $meta_query_sql['where'];
if ( $search = WC_Query::get_main_search_query_sql() ) {
$sql .= ' AND ' . $search;
}
return $wpdb->get_row( $sql );
}
Replace the form code (widget function -> below $max_price variable) with this:
echo '<form method="get" action="' . esc_url( $form_action ) . '">
<div class="price_slider_wrapper">
<div class="price_slider" style="display:none;"></div>
<div class="price_slider_amount">
<input type="text" id="min_price" name="min_price" value="' . esc_attr( $min_price ) . '" data-min="' . esc_attr( apply_filters( 'woocommerce_price_filter_widget_min_amount', $min ) ) . '" placeholder="' . esc_attr__( 'Min price', 'woocommerce' ) . '" />
<input type="text" id="max_price" name="max_price" value="' . esc_attr( $max_price ) . '" data-max="' . esc_attr( apply_filters( 'woocommerce_price_filter_widget_max_amount', $max ) ) . '" placeholder="' . esc_attr__( 'Max price', 'woocommerce' ) . '" />
<div class="price_label" style="display:none;">
' . esc_html__( 'Price:', 'woocommerce' ) . ' <span class="from"></span> — <span class="to"></span>
</div>
' . wc_query_string_form_fields( null, array( 'min_price', 'max_price' ), '', true ) . '
<button type="submit" class="button">' . esc_html__( 'Filter', 'woocommerce' ) . '</button>
<div class="clear"></div>
</div>
</div>
</form>';

Woocommerce Product Quantity Filter Slider - Widget

I am trying to add a widget to Woocommerce to Filter Products by Quantity with a slider. I got this far by changing the open source code of woocommerce for the price filter slider. It print no errors once it's on the website but it does not filter the results. The output on the URL is also as expected. The slider does not work but it's fine if I cannot fix it. As of now it has two type-in fields: max and min stock quantity. Please help. I am sure others will benefit from this. I need it because the website is for wholesale and if a product is not available is a min quantity that a client wants, they can filter it out.
// Register and load the widget
function my_stock_widget() {
register_widget( 'WC_Widget_Stock_Filter' );
}
add_action( 'widgets_init', 'my_stock_widget' );
class WC_Widget_Stock_Filter extends WC_Widget {
/**
* Constructor.
*/
public function __construct() {
$this->widget_cssclass = 'woocommerce widget_stock_filter';
$this->widget_description = __( 'Shows a stock filter slider in a widget which lets you narrow down the list of shown products when viewing product categories.', 'woocommerce' );
$this->widget_id = 'woocommerce_stock_filter';
$this->widget_name = __( 'WooCommerce stock filter', 'woocommerce' );
$this->settings = array(
'title' => array(
'type' => 'text',
'std' => __( 'Filter by stock', 'woocommerce' ),
'label' => __( 'Title', 'woocommerce' ),
),
);
$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
wp_register_script( 'accounting', WC()->plugin_url() . '/assets/js/accounting/accounting' . $suffix . '.js', array( 'jquery' ), '0.4.2' );
wp_register_script( 'wc-jquery-ui-touchpunch', WC()->plugin_url() . '/assets/js/jquery-ui-touch-punch/jquery-ui-touch-punch' . $suffix . '.js', array( 'jquery-ui-slider' ), WC_VERSION, true );
wp_register_script( 'wc-stock-slider', WC()->plugin_url() . '/assets/js/frontend/price-slider' . $suffix . '.js', array( 'jquery-ui-slider', 'wc-jquery-ui-touchpunch', 'accounting' ), WC_VERSION, true );
wp_localize_script( 'wc-stock-slider', 'woocommerce_stock_slider_params', array(
'min_stock' => isset( $_GET['min_stock'] ) ? esc_attr( $_GET['min_stock'] ) : '',
'max_stock' => isset( $_GET['max_stock'] ) ? esc_attr( $_GET['max_stock'] ) : '',
'currency_format_num_decimals' => 0,
// 'currency_format_symbol' => get_woocommerce_currency_symbol(),
'currency_format_decimal_sep' => esc_attr( wc_get_price_decimal_separator() ),
'currency_format_thousand_sep' => esc_attr( wc_get_price_thousand_separator() ),
// 'currency_format' => esc_attr( str_replace( array( '%1$s', '%2$s' ), array( '%s', '%v' ), get_woocommerce_stock_format() ) ),
) );
parent::__construct();
}
/**
* Output widget.
*
* #see WP_Widget
*
* #param array $args
* #param array $instance
*/
public function widget( $args, $instance ) {
global $wp, $wp_the_query;
if ( ! is_post_type_archive( 'product' ) && ! is_tax( get_object_taxonomies( 'product' ) ) ) {
return;
}
if ( ! $wp_the_query->post_count ) {
return;
}
$min_stock = isset( $_GET['min_stock'] ) ? esc_attr( $_GET['min_stock'] ) : '';
$max_stock = isset( $_GET['max_stock'] ) ? esc_attr( $_GET['max_stock'] ) : '';
wp_enqueue_script( 'wc-stock-slider' );
// Find min and max stock in current result set
$stocks = $this->get_filtered_stock();
$min = floor( $stocks->min_stock );
$max = ceil( $stocks->max_stock );
if ( $min === $max ) {
return;
}
$this->widget_start( $args, $instance );
if ( '' === get_option( 'permalink_structure' ) ) {
$form_action = remove_query_arg( array( 'page', 'paged' ), add_query_arg( $wp->query_string, '', home_url( $wp->request ) ) );
} else {
$form_action = preg_replace( '%\/page/[0-9]+%', '', home_url( trailingslashit( $wp->request ) ) );
}
/**
* Adjust max if the store taxes are not displayed how they are stored.
* Min is left alone because the product may not be taxable.
* Kicks in when stocks excluding tax are displayed including tax.
*
if ( wc_tax_enabled() && 'incl' === get_option( 'woocommerce_tax_display_shop' ) && ! wc_stocks_include_tax() ) {
$tax_classes = array_merge( array( '' ), WC_Tax::get_tax_classes() );
$class_max = $max;
foreach ( $tax_classes as $tax_class ) {
if ( $tax_rates = WC_Tax::get_rates( $tax_class ) ) {
$class_max = $max + WC_Tax::get_tax_total( WC_Tax::calc_exclusive_tax( $max, $tax_rates ) );
}
}
$max = $class_max;
}*/
echo '<form method="get" action="' . esc_url( $form_action ) . '">
<div class="stock_slider_wrapper">
<div class="stock_slider" style="display:none;"></div>
<div class="stock_slider_amount">
<input type="text" id="min_stock" name="min_stock" value="' . esc_attr( $min_stock ) . '" data-min="' . esc_attr( apply_filters( 'woocommerce_stock_filter_widget_min_amount', $min ) ) . '" placeholder="' . esc_attr__( 'Min stock', 'woocommerce' ) . '" />
<input type="text" id="max_stock" name="max_stock" value="' . esc_attr( $max_stock ) . '" data-max="' . esc_attr( apply_filters( 'woocommerce_stock_filter_widget_max_amount', $max ) ) . '" placeholder="' . esc_attr__( 'Max stock', 'woocommerce' ) . '" />
<button type="submit" class="button">' . esc_html__( 'Filter', 'woocommerce' ) . '</button>
<div class="stock_label" style="display:none;">
' . esc_html__( 'Stock:', 'woocommerce' ) . ' <span class="from"></span> — <span class="to"></span>
</div>
' . wc_query_string_form_fields( null, array( 'min_stock', 'max_stock' ), '', true ) . '
<div class="clear"></div>
</div>
</div>
</form>';
$this->widget_end( $args );
}
/**
* Get filtered min stock for current products.
* #return int
*/
protected function get_filtered_stock() {
global $wpdb, $wp_the_query;
$args = $wp_the_query->query_vars;
$tax_query = isset( $args['tax_query'] ) ? $args['tax_query'] : array();
$meta_query = isset( $args['meta_query'] ) ? $args['meta_query'] : array();
if ( ! is_post_type_archive( 'product' ) && ! empty( $args['taxonomy'] ) && ! empty( $args['term'] ) ) {
$tax_query[] = array(
'taxonomy' => $args['taxonomy'],
'terms' => array( $args['term'] ),
'field' => 'slug',
);
}
foreach ( $meta_query + $tax_query as $key => $query ) {
if ( ! empty( $query['stock_filter'] ) || ! empty( $query['rating_filter'] ) ) {
unset( $meta_query[ $key ] );
}
}
$meta_query = new WP_Meta_Query( $meta_query );
$tax_query = new WP_Tax_Query( $tax_query );
$meta_query_sql = $meta_query->get_sql( 'post', $wpdb->posts, 'ID' );
$tax_query_sql = $tax_query->get_sql( $wpdb->posts, 'ID' );
$sql = "SELECT min( FLOOR( stock_meta.meta_value ) ) as min_stock, max( CEILING( stock_meta.meta_value ) ) as max_stock FROM {$wpdb->posts} ";
$sql .= " LEFT JOIN {$wpdb->postmeta} as stock_meta ON {$wpdb->posts}.ID = stock_meta.post_id " . $tax_query_sql['join'] . $meta_query_sql['join'];
$sql .= " WHERE {$wpdb->posts}.post_type IN ('" . implode( "','", array_map( 'esc_sql', apply_filters( 'woocommerce_stock_filter_meta_keys', array( 'product' ) ) ) ) . "')
AND {$wpdb->posts}.post_status = 'publish'
AND stock_meta.meta_key IN ('" . implode( "','", array_map( 'esc_sql', apply_filters( 'woocommerce_stock_filter_meta_keys', array( '_stock' ) ) ) ) . "')
AND stock_meta.meta_value > '' ";
$sql .= $tax_query_sql['where'] . $meta_query_sql['where'];
if ( $search = WC_Query::get_main_search_query_sql() ) {
$sql .= ' AND ' . $search;
}
return $wpdb->get_row( $sql );
}

Categories