271 lines
9.8 KiB
PHP
271 lines
9.8 KiB
PHP
<?php
|
|
/**
|
|
* Plugin Name: Woo Brand Widget
|
|
* Plugin URI: https://informatiq.services
|
|
* Description: Brand filter widget and shortcode for WooCommerc with Shoptimizer
|
|
* Version: 1.0.0
|
|
* Author: Mălin Cenușă
|
|
* Author URI: https://mălin.ro
|
|
* License: GPL v2 or later
|
|
* Text Domain: shoptimizer-brand-filter
|
|
*/
|
|
|
|
if (!defined('ABSPATH')) exit;
|
|
|
|
class Shoptimizer_Brand_Filter_Fixed {
|
|
|
|
public function __construct() {
|
|
add_action('plugins_loaded', array($this, 'init'));
|
|
}
|
|
|
|
public function init() {
|
|
// Register shortcode
|
|
add_shortcode('brand_filter', array($this, 'shortcode'));
|
|
|
|
// Register widget
|
|
add_action('widgets_init', array($this, 'register_widget'));
|
|
|
|
// Enqueue styles
|
|
add_action('wp_enqueue_scripts', array($this, 'enqueue_styles'));
|
|
}
|
|
|
|
public function enqueue_styles() {
|
|
wp_add_inline_style('wp-block-library', '
|
|
.brand-filter-widget {
|
|
margin-bottom: 30px;
|
|
}
|
|
.brand-filter-widget h3 {
|
|
margin-top: 0;
|
|
margin-bottom: 15px;
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
color: #333;
|
|
}
|
|
.brand-list {
|
|
list-style: none;
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
.brand-list li {
|
|
font-size: 10.5px; /* 14px * 0.75 = 10.5px (25% smaller) */
|
|
line-height: 1.09; /* 1.45 * 0.75 = 1.09 (25% smaller) */
|
|
margin-bottom: 6px;
|
|
}
|
|
.brand-list li.brand-parent {
|
|
font-weight: 600;
|
|
margin-bottom: 8px;
|
|
}
|
|
.brand-list li.brand-family {
|
|
padding-left: 15px;
|
|
font-weight: 400;
|
|
margin-bottom: 4px;
|
|
}
|
|
.brand-list a {
|
|
color: #222;
|
|
text-decoration: none;
|
|
display: block;
|
|
transition: color 0.2s;
|
|
background-color: transparent;
|
|
}
|
|
.brand-list a:hover {
|
|
color: #d43a8e;
|
|
text-decoration: underline;
|
|
text-decoration-thickness: 0.5px;
|
|
text-underline-offset: 0.18em;
|
|
}
|
|
.brand-list a:active,
|
|
.brand-list a:focus {
|
|
outline: 0;
|
|
}
|
|
.brand-count {
|
|
color: #666;
|
|
font-size: 0.9em;
|
|
font-weight: normal;
|
|
}
|
|
.brand-list li.brand-family a {
|
|
color: #555;
|
|
padding-left: 0;
|
|
}
|
|
.brand-list li.brand-family a:hover {
|
|
color: #d43a8e;
|
|
}
|
|
');
|
|
}
|
|
|
|
public function shortcode($atts) {
|
|
$atts = shortcode_atts(array(
|
|
'title' => 'Filter by Brand',
|
|
'show_count' => 'yes'
|
|
), $atts);
|
|
|
|
// Check if WooCommerce is active
|
|
if (!class_exists('WooCommerce')) {
|
|
return '<p>WooCommerce is not active</p>';
|
|
}
|
|
|
|
// First, let's check what taxonomies exist
|
|
$taxonomies = get_object_taxonomies('product');
|
|
|
|
// Try different possible brand taxonomy names
|
|
$brand_taxonomy = '';
|
|
$possible_names = array('product_brand', 'pa_brand', 'pwb-brand', 'yith_product_brand');
|
|
|
|
foreach ($possible_names as $tax_name) {
|
|
if (in_array($tax_name, $taxonomies)) {
|
|
$brand_taxonomy = $tax_name;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (empty($brand_taxonomy)) {
|
|
return '<div class="brand-filter-widget">
|
|
<h3>' . esc_html($atts['title']) . '</h3>
|
|
<p>No brand taxonomy found. Available taxonomies: ' . implode(', ', $taxonomies) . '</p>
|
|
</div>';
|
|
}
|
|
|
|
// Get terms hierarchically - get ALL terms first, then filter manually
|
|
$all_terms = get_terms(array(
|
|
'taxonomy' => $brand_taxonomy,
|
|
'hide_empty' => false, // Get all terms, we'll filter manually
|
|
'orderby' => 'name',
|
|
'order' => 'ASC'
|
|
));
|
|
|
|
if (is_wp_error($all_terms) || empty($all_terms)) {
|
|
return '<div class="brand-filter-widget">
|
|
<h3>' . esc_html($atts['title']) . '</h3>
|
|
<p>No brands found for taxonomy: ' . $brand_taxonomy . '</p>
|
|
</div>';
|
|
}
|
|
|
|
// Organize terms hierarchically - only include terms with products
|
|
$parent_terms = array();
|
|
$child_terms = array();
|
|
|
|
foreach ($all_terms as $term) {
|
|
// Check if term has published products and get accurate count (regardless of stock status)
|
|
$product_query = new WP_Query(array(
|
|
'post_type' => 'product',
|
|
'post_status' => 'publish',
|
|
'posts_per_page' => -1, // Get all to count them
|
|
'fields' => 'ids', // Only get IDs for performance
|
|
'tax_query' => array(
|
|
array(
|
|
'taxonomy' => $brand_taxonomy,
|
|
'field' => 'term_id',
|
|
'terms' => $term->term_id,
|
|
'include_children' => false
|
|
)
|
|
)
|
|
));
|
|
|
|
$actual_count = $product_query->found_posts;
|
|
wp_reset_postdata();
|
|
|
|
if ($actual_count > 0) {
|
|
// Store the actual count in the term object
|
|
$term->actual_count = $actual_count;
|
|
|
|
if ($term->parent == 0) {
|
|
$parent_terms[] = $term;
|
|
} else {
|
|
if (!isset($child_terms[$term->parent])) {
|
|
$child_terms[$term->parent] = array();
|
|
}
|
|
$child_terms[$term->parent][] = $term;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Filter out parent terms that have no products themselves AND no child terms with products
|
|
$filtered_parent_terms = array();
|
|
foreach ($parent_terms as $parent) {
|
|
$has_products = isset($parent->actual_count) && $parent->actual_count > 0;
|
|
$has_children_with_products = isset($child_terms[$parent->term_id]) && !empty($child_terms[$parent->term_id]);
|
|
|
|
// Include parent if it has products OR if it has children with products
|
|
if ($has_products || $has_children_with_products) {
|
|
$filtered_parent_terms[] = $parent;
|
|
}
|
|
}
|
|
$parent_terms = $filtered_parent_terms;
|
|
|
|
ob_start();
|
|
?>
|
|
<div class="brand-filter-widget">
|
|
<h3><?php echo esc_html($atts['title']); ?></h3>
|
|
<ul class="brand-list">
|
|
<?php foreach ($parent_terms as $parent): ?>
|
|
<li class="brand-parent">
|
|
<a href="<?php echo esc_url(get_term_link($parent)); ?>">
|
|
<?php echo esc_html($parent->name); ?>
|
|
<?php if ($atts['show_count'] === 'yes'): ?>
|
|
<span class="brand-count">(<?php echo isset($parent->actual_count) ? $parent->actual_count : 0; ?>)</span>
|
|
<?php endif; ?>
|
|
</a>
|
|
|
|
<?php if (isset($child_terms[$parent->term_id])): ?>
|
|
<?php foreach ($child_terms[$parent->term_id] as $child): ?>
|
|
<li class="brand-family">
|
|
<a href="<?php echo esc_url(get_term_link($child)); ?>">
|
|
<?php echo esc_html($child->name); ?>
|
|
<?php if ($atts['show_count'] === 'yes'): ?>
|
|
<span class="brand-count">(<?php echo isset($child->actual_count) ? $child->actual_count : 0; ?>)</span>
|
|
<?php endif; ?>
|
|
</a>
|
|
</li>
|
|
<?php endforeach; ?>
|
|
<?php endif; ?>
|
|
</li>
|
|
<?php endforeach; ?>
|
|
</ul>
|
|
</div>
|
|
<?php
|
|
return ob_get_clean();
|
|
}
|
|
|
|
public function register_widget() {
|
|
register_widget('Shoptimizer_Brand_Widget_Fixed');
|
|
}
|
|
}
|
|
|
|
class Shoptimizer_Brand_Widget_Fixed extends WP_Widget {
|
|
|
|
public function __construct() {
|
|
parent::__construct(
|
|
'shoptimizer_brand_widget_fixed',
|
|
'Brand Filter Widget',
|
|
array('description' => 'Display product brands for filtering')
|
|
);
|
|
}
|
|
|
|
public function widget($args, $instance) {
|
|
$title = !empty($instance['title']) ? $instance['title'] : 'Filter by Brand';
|
|
|
|
echo $args['before_widget'];
|
|
echo do_shortcode('[brand_filter title="' . esc_attr($title) . '"]');
|
|
echo $args['after_widget'];
|
|
}
|
|
|
|
public function form($instance) {
|
|
$title = !empty($instance['title']) ? $instance['title'] : 'Filter by Brand';
|
|
?>
|
|
<p>
|
|
<label for="<?php echo $this->get_field_id('title'); ?>">Title:</label>
|
|
<input class="widefat" id="<?php echo $this->get_field_id('title'); ?>"
|
|
name="<?php echo $this->get_field_name('title'); ?>" type="text"
|
|
value="<?php echo esc_attr($title); ?>">
|
|
</p>
|
|
<?php
|
|
}
|
|
|
|
public function update($new_instance, $old_instance) {
|
|
return array(
|
|
'title' => sanitize_text_field($new_instance['title'])
|
|
);
|
|
}
|
|
}
|
|
|
|
// Initialize
|
|
new Shoptimizer_Brand_Filter_Fixed();
|