skip to Main Content

We have a WooCommerce clothing store and want to create coupons that have certain categories excluded. Our category structure is as follows (simplified):

– Men
– – Shirts
– – Jeans
– – Sale
– Women
– – Shirts
– – Jeans
– – Sale

However when we want to select [Men » Sale] from the Exclude categories dropdown picker in [WooCommerce » Marketing » Coupons » Usage Restriction] the list is flattened:

– Jeans
– Men
– Sale
– Sale
– Shirts
– Shirts
– Women

Now it is not clear which categories are actually the one we want to exclude. Have in min, this is a very simplified structure, in the live environment this is even worse.

I hoped for an apply_filter but the get_terms() apparently does have none in code, see source code on github here » (line #233)

$categories = get_terms('product_cat', 'orderby=name&hide_empty=0');

Since this is not filtered, I don’t see a way to add a parent category to have this as the desired outcome:

- Men
- Men » Jeans
- Men » Shirts
- Men » Sale
- Women
- Women » Jeans
- Women » Shirts
- Women » Sale

Any idea how to get that list now that there is no filter in the code?

For example, this is what we use for a third party plugin that also uses the WooCommerce category terms, but that actually does have a filter on the get_terms and the native WooCommerce code on coupons does not…

Example:

if (!function_exists('yith_wcbep_add_parent_category_name')) {
    function yith_wcbep_add_parent_category_name($terms, $args) {
        $term_name = '';
        $taxonomy  = isset($args['taxonomy']) ? $args['taxonomy'] : '';
        foreach ($terms as $term_id => $term_name) {
            $term = get_term_by('id', $term_id, $taxonomy);
            $term_name = isset($term->name) ? $term->name : '';
            if (isset($term->parent) && $term->parent > 0) {
                $parent = get_term_by('id', $term->parent, $term->taxonomy);
                $term_name = $parent->name . ' > ' . $term_name;
                $terms[$term_id] = $term_name;
            }
        }
        return $terms;
    }
    add_filter('yith_plugin_fw_json_search_found_terms', 'yith_wcbep_add_parent_category_name', 10, 2);
}

2

Answers


  1. This was an interesting feature to solve, seems kind of strange Woocommerce doesn’t have hierarchy names in the coupons categories.
    So I did some digging and found that the only appropriate filter seems to be get_terms, after some trial and error I came up with this.

    if (!function_exists('btAddHierarchyNameToCouponsCat')) {
        function btAddHierarchyNameToCouponsCat($terms)
        {
            if (!is_admin()) {
                return $terms;
            }
        
            global $pagenow;
        
            if ($pagenow !== 'post-new.php' && $pagenow !== 'post.php') {
                return $terms;
            }
        
            if (
                (
                    !empty($_GET['post_type'])
                    && $_GET['post_type'] === 'shop_coupon'
                )
                || (
                    !empty($_GET['post'])
                    && get_post_type($_GET['post']) === 'shop_coupon'
                    && !empty($_GET['action'])
                    && $_GET['action'] === 'edit'
                )
            ) {
                foreach ($terms as &$term) {
                    $term->name = (function ($term) {
                        $fullName = array_map(function ($ancestorId) {
                            $ancestor = get_term_by('term_id', $ancestorId, 'product_cat');
        
                            return $ancestor->name;
                        }, array_reverse(get_ancestors($term->term_id, 'product_cat')));
        
                        $fullName[] = $term->name;
        
                        return implode(' -> ', $fullName);
                    })($term);
                }
        
                return $terms;
            }
        
            return $terms;
        }
    
        add_filter('get_terms', 'btAddHierarchyNameToCouponsCat');
    }
    

    Here is the before.

    enter image description here

    And here is the after.

    enter image description here

    The general idea of this filter is to specifically work only when creating or editing a coupon on the dashboard.
    Then it updates the category name to contain the whole hierarchy of the categories names.
    This might not be perfect but it’s a starting point

    Login or Signup to reply.
  2. To solve this issue, what you can do is to clone WooCommerce coupon product categories restrictions section, customizing the categories output as you like *(here I add the parent term name to the category name), removing with JavaScript the related HTML output from the default WooCommerce ones.

    So you will get the following:

    enter image description here

    Here is the hooked function code:

    // Prepend the parent term name to the term name output
    function prepend_parent_term_name( $term, $sep = ' > ' ) {
        if (isset($term->parent) && $term->parent > 0) {
            $parent_name = get_term_by('id', $term->parent, $term->taxonomy)->name;
            return esc_html( $parent_name ) . $sep . esc_html( $term->name );
        } else {
            return esc_html( $term->name );
        }
    }
    
    // Replace WooCommerce Admin Coupon product categories restictions section with a custom one
    add_action( 'woocommerce_coupon_options_usage_restriction', 'action_coupon_options_usage_restriction', 10, 2 );
    function action_coupon_options_usage_restriction( $coupon_id, $coupon ) {
        echo '<div class="options_group">';
    
        // Categories.
        ?>
        <p class="form-field">
            <label for="product_categories2"><?php _e( 'Product categories', 'woocommerce' ); ?></label>
            <select id="product_categories2" name="product_categories[]" style="width: 50%;"  class="wc-enhanced-select" multiple="multiple" data-placeholder="<?php esc_attr_e( 'Any category', 'woocommerce' ); ?>">
                <?php
                $category_ids = $coupon->get_product_categories( 'edit' );
                $categories   = get_terms( 'product_cat', 'orderby=name&hide_empty=0' );
    
                if ( $categories ) {
                    foreach ( $categories as $cat ) {
                        echo '<option value="' . esc_attr( $cat->term_id ) . '"' . wc_selected( $cat->term_id, $category_ids ) . '>' . prepend_parent_term_name( $cat ) . '</option>';
                    }
                }
                ?>
            </select> <?php echo wc_help_tip( __( 'Product categories that the coupon will be applied to, or that need to be in the cart in order for the "Fixed cart discount" to be applied.', 'woocommerce' ) ); ?>
        </p>
    
        <?php // Exclude Categories. ?>
        <p class="form-field">
            <label for="exclude_product_categories2"><?php _e( 'Exclude categories', 'woocommerce' ); ?></label>
            <select id="exclude_product_categories2" name="exclude_product_categories[]" style="width: 50%;"  class="wc-enhanced-select" multiple="multiple" data-placeholder="<?php esc_attr_e( 'No categories', 'woocommerce' ); ?>">
                <?php
                $category_ids = $coupon->get_excluded_product_categories( 'edit' );
                $categories   = get_terms( 'product_cat', 'orderby=name&hide_empty=0' );
    
                if ( $categories ) {
                    foreach ( $categories as $cat ) {
                        echo '<option value="' . esc_attr( $cat->term_id ) . '"' . wc_selected( $cat->term_id, $category_ids ) . '>' . prepend_parent_term_name( $cat ) . '</option>';
                    }
                }
                ?>
            </select>
            <?php echo wc_help_tip( __( 'Product categories that the coupon will not be applied to, or that cannot be in the cart in order for the "Fixed cart discount" to be applied.', 'woocommerce' ) ); ?>
        </p>
        <?php // Removing default product categories restrictions html  ?>
        <script>
        jQuery(function($){
            $('#product_categories').parent().parent().remove();
        });
        </script>
        <?php 
        echo '</div>';
    }
    

    Code goes in functions.php file of your active child theme (or active theme). Tested and works.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search