Created
January 17, 2021 06:27
-
-
Save doubleedesign/b78c810f2dc76505266db44f675e538c to your computer and use it in GitHub Desktop.
Override the output of the WooCommerce product categories widget to be a Bootstrap accordion
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Product Categories Widget | |
* Modifies the WooCommerce product categories widget to display as a Bootstrap accordion. | |
* | |
* @package WooCommerce/Widgets | |
* @version 2.3.0 | |
*/ | |
defined( 'ABSPATH' ) || exit; | |
/** | |
* Product categories widget class. | |
* | |
* @extends WC_Widget | |
*/ | |
class DE_Widget_Product_Categories extends WC_Widget { | |
/** | |
* Category ancestors. | |
* | |
* @var array | |
*/ | |
public $cat_ancestors; | |
/** | |
* Current Category. | |
* | |
* @var bool | |
*/ | |
public $current_cat; | |
/** | |
* Constructor. | |
*/ | |
public function __construct() { | |
$this->widget_cssclass = 'woocommerce widget_product_categories'; | |
$this->widget_description = __( 'An accordion list of product categories and subcategories.', 'woocommerce' ); | |
$this->widget_id = 'woocommerce_product_categories--accordion'; | |
$this->widget_name = __( 'Product Categories (Accordion)', 'woocommerce' ); | |
$this->settings = array( | |
'title' => array( | |
'type' => 'text', | |
'std' => __( 'Product Categories', 'woocommerce' ), | |
'label' => __( 'Title (not shown visually)', 'woocommerce' ), | |
), | |
'orderby' => array( | |
'type' => 'select', | |
'std' => 'name', | |
'label' => __( 'Order by', 'woocommerce' ), | |
'options' => array( | |
'order' => __( 'Category order', 'woocommerce' ), | |
'name' => __( 'Name', 'woocommerce' ), | |
), | |
), | |
'count' => array( | |
'type' => 'checkbox', | |
'std' => 0, | |
'label' => __( 'Show product counts', 'woocommerce' ), | |
), | |
'hide_empty' => array( | |
'type' => 'checkbox', | |
'std' => 0, | |
'label' => __( 'Hide empty categories', 'woocommerce' ), | |
), | |
); | |
parent::__construct(); | |
} | |
/** | |
* Output widget. | |
* | |
* @see WP_Widget | |
* @param array $args Widget arguments. | |
* @param array $instance Widget instance. | |
*/ | |
public function widget( $args, $instance ) { | |
global $wp_query, $post; | |
$count = isset( $instance['count'] ) ? $instance['count'] : $this->settings['count']['std']; | |
$hierarchical = isset( $instance['hierarchical'] ) ? $instance['hierarchical'] : $this->settings['hierarchical']['std']; | |
$show_children_only = isset( $instance['show_children_only'] ) ? $instance['show_children_only'] : $this->settings['show_children_only']['std']; | |
$dropdown = isset( $instance['dropdown'] ) ? $instance['dropdown'] : $this->settings['dropdown']['std']; | |
$orderby = isset( $instance['orderby'] ) ? $instance['orderby'] : $this->settings['orderby']['std']; | |
$hide_empty = isset( $instance['hide_empty'] ) ? $instance['hide_empty'] : $this->settings['hide_empty']['std']; | |
$dropdown_args = array( | |
'hide_empty' => $hide_empty, | |
); | |
$list_args = array( | |
'show_count' => $count, | |
'hierarchical' => $hierarchical, | |
'taxonomy' => 'product_cat', | |
'hide_empty' => $hide_empty, | |
); | |
$max_depth = absint( isset( $instance['max_depth'] ) ? $instance['max_depth'] : $this->settings['max_depth']['std'] ); | |
$list_args['menu_order'] = false; | |
$dropdown_args['depth'] = $max_depth; | |
$list_args['depth'] = $max_depth; | |
if ( 'order' === $orderby ) { | |
$list_args['orderby'] = 'meta_value_num'; | |
$dropdown_args['orderby'] = 'meta_value_num'; | |
$list_args['meta_key'] = 'order'; | |
$dropdown_args['meta_key'] = 'order'; | |
} | |
$this->current_cat = false; | |
$this->cat_ancestors = array(); | |
if ( is_tax( 'product_cat' ) ) { | |
$this->current_cat = $wp_query->queried_object; | |
$this->cat_ancestors = get_ancestors( $this->current_cat->term_id, 'product_cat' ); | |
} elseif ( is_singular( 'product' ) ) { | |
$terms = wc_get_product_terms( | |
$post->ID, | |
'product_cat', | |
apply_filters( | |
'woocommerce_product_categories_widget_product_terms_args', | |
array( | |
'orderby' => 'parent', | |
'order' => 'DESC', | |
) | |
) | |
); | |
if ( $terms ) { | |
$main_term = apply_filters( 'woocommerce_product_categories_widget_main_term', $terms[0], $terms ); | |
$this->current_cat = $main_term; | |
$this->cat_ancestors = get_ancestors( $main_term->term_id, 'product_cat' ); | |
} | |
} | |
// Show Siblings and Children Only. | |
if ( $show_children_only && $this->current_cat ) { | |
if ( $hierarchical ) { | |
$include = array_merge( | |
$this->cat_ancestors, | |
array( $this->current_cat->term_id ), | |
get_terms( | |
'product_cat', | |
array( | |
'fields' => 'ids', | |
'parent' => 0, | |
'hierarchical' => true, | |
'hide_empty' => false, | |
) | |
), | |
get_terms( | |
'product_cat', | |
array( | |
'fields' => 'ids', | |
'parent' => $this->current_cat->term_id, | |
'hierarchical' => true, | |
'hide_empty' => false, | |
) | |
) | |
); | |
// Gather siblings of ancestors. | |
if ( $this->cat_ancestors ) { | |
foreach ( $this->cat_ancestors as $ancestor ) { | |
$include = array_merge( | |
$include, | |
get_terms( | |
'product_cat', | |
array( | |
'fields' => 'ids', | |
'parent' => $ancestor, | |
'hierarchical' => false, | |
'hide_empty' => false, | |
) | |
) | |
); | |
} | |
} | |
} else { | |
// Direct children. | |
$include = get_terms( | |
'product_cat', | |
array( | |
'fields' => 'ids', | |
'parent' => $this->current_cat->term_id, | |
'hierarchical' => true, | |
'hide_empty' => false, | |
) | |
); | |
} | |
$list_args['include'] = implode( ',', $include ); | |
$dropdown_args['include'] = $list_args['include']; | |
if ( empty( $include ) ) { | |
return; | |
} | |
} elseif ( $show_children_only ) { | |
$dropdown_args['depth'] = 1; | |
$dropdown_args['child_of'] = 0; | |
$dropdown_args['hierarchical'] = 1; | |
$list_args['depth'] = 1; | |
$list_args['child_of'] = 0; | |
$list_args['hierarchical'] = 1; | |
} | |
$this->widget_start( $args, $instance ); | |
include_once WC()->plugin_path() . '/includes/walkers/class-wc-product-cat-list-walker.php'; | |
$list_args['walker'] = new WC_Product_Cat_List_Walker(); | |
$list_args['title_li'] = ''; | |
$list_args['pad_counts'] = 1; | |
$list_args['show_option_none'] = __( 'No product categories exist.', 'woocommerce' ); | |
$list_args['current_category'] = ( $this->current_cat ) ? $this->current_cat->term_id : ''; | |
$list_args['current_category_ancestors'] = $this->cat_ancestors; | |
// Check which category we're currently viewing | |
$queried_object = get_queried_object(); | |
$current_cat_id = 0; | |
if(isset($queried_object->term_id)) { | |
$current_cat_id = $queried_object->term_id; | |
} | |
// Get the top level categories | |
$top_level_categories = get_terms(array( | |
'taxonomy' => 'product_cat', | |
'hide_empty' => $list_args['hide_empty'], | |
'parent' => 0, | |
'exclude' => array(15), // exclude uncategorised | |
)); | |
// Check if the caregory we're on has ancestors, and get the top-level one | |
$ancestors = get_ancestors($current_cat_id, 'product_cat'); // Get a list of ancestors | |
$ancestors = array_reverse($ancestors); //Reverse the array to put the top level ancestor first | |
$top_level_ancestor = 0; | |
if($ancestors) { | |
$top_level_ancestor = $ancestors[0]; | |
} | |
// Start widget HTML output | |
echo '<ul class="product-categories">'; | |
foreach($top_level_categories as $category) { | |
$cat_id = 'collapse-' . $category->slug; | |
$count = ''; | |
if($list_args['pad_counts']) { | |
$count = '<span class="count">('.$category->count.')</span>'; | |
} | |
$subcategories = get_terms(array( | |
'taxonomy' => 'product_cat', | |
'hide_empty' => $list_args['hide_empty'], | |
'parent' => $category->term_id, | |
)); | |
if($subcategories) { | |
// If this is the current category or a child of it, set up to open by default and be bold | |
$aria_expanded = 'false'; | |
$current_class = ''; | |
$panel_class = ''; | |
$button_class = ''; | |
if(($category->term_id == $current_cat_id) || ($category->term_id == $top_level_ancestor)) { | |
$aria_expanded = 'true'; | |
$current_class = 'current'; | |
$panel_class = 'show'; | |
$button_class = 'open'; | |
} | |
echo '<li class="product-categories__category">'; | |
echo '<span class="widget__title">'; | |
echo '<a href="'.get_term_link($category->term_id, 'product_cat').'">'; | |
echo '<h3 class="widget__title__heading '.$current_class.'">' . ucfirst($category->name) . $count . '</h3>'; | |
echo '</a>'; | |
echo '<button class="widget__collapse-button '.$button_class.'" data-toggle="collapse" data-target="#'.$cat_id.'" aria-expanded="'.$aria_expanded.'" aria-controls="'.$cat_id.'">'; | |
echo '<i class="fa far fa-chevron-down"></i>'; | |
echo '</button>'; | |
echo '</span>'; | |
echo '<ul id="'.$cat_id.'" class="collapse product-categories__children '.$panel_class.'">'; | |
foreach ($subcategories as $subcategory) { | |
$url = get_term_link($subcategory->term_id, 'product_cat'); | |
$sub_count = ''; | |
$sub_current_class = ''; | |
$current_term = get_term($current_cat_id); | |
if(isset($current_term->term_id)) { // checks if we're on a category page, to prevent errors on the shop page | |
if (($subcategory->term_id == $current_cat_id) || ($subcategory->term_id == $current_term->parent)) { | |
$sub_current_class = 'current'; | |
} | |
} | |
if($list_args['pad_counts']) { | |
$sub_count = '<span class="count">('.$subcategory->count.')</span>'; | |
} | |
echo '<li class="product-categories__children__subcategory">'; | |
echo '<a href="'.$url.'" class="'.$sub_current_class.'">'.ucfirst($subcategory->name) . $sub_count . '</a>'; | |
echo '<li>'; | |
// Third level categories | |
$third_level_categories = get_terms(array( | |
'taxonomy' => 'product_cat', | |
'hide_empty' => $list_args['hide_empty'], | |
'parent' => $subcategory->term_id, | |
)); | |
if($third_level_categories) { | |
echo '<ul class="product-categories__grandchildren">'; | |
foreach($third_level_categories as $third_level_category) { | |
$third_current_class = ''; | |
if($third_level_category->term_id == $current_cat_id) { | |
$third_current_class = 'current'; | |
} | |
$url = get_term_link($third_level_category->term_id, 'product_cat'); | |
echo '<li class="product-categories__grandchildren__subcategory">'; | |
echo '<a href="'.$url.'" class="'.$third_current_class.'">'.ucfirst($third_level_category->name).'</a>'; | |
echo '<li>'; | |
} | |
echo '</ul>'; | |
} | |
} | |
echo '</ul>'; | |
echo '</li>'; | |
} | |
// No subcategories | |
else { | |
$url = get_term_link($category->term_id); | |
echo '<li class="product-categories__category">'; | |
echo '<a class="widget__collapse-button" href="'.$url.'">'; | |
echo '<h3 class="widget__title">' . ucfirst($category->name) . $count . '</h3>'; | |
echo '</a>'; | |
echo '</li>'; | |
} | |
} | |
echo '</ul>'; | |
// End widget HTML output | |
$this->widget_end( $args ); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Register custom widgets | |
*/ | |
function doublee_register_widgets() { | |
if(is_woocommerce_active()) { | |
require 'woocommerce/widget-product-categories.php'; | |
register_widget('DE_Widget_Product_Categories'); | |
} | |
} | |
add_action('widgets_init', 'doublee_register_widgets'); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment