Recently while building an eCommerce site using Breakdance, WooCommerce and the Smart Coupons plugins, I ran into an issue where the product we had set as the Gift Card would show both the “Select Options” link and the “Add To Cart” button.
This build was for a migration of an existing site (Moondance Jewelry), so I knew that it worked. It took about an hour of head-beating-against-a-wall to figure it out, but alas, I did.
Breakdance Modification to WooCommerce
Breakdance wraps a div around the “Add to Cart” button (which is called via the action woocommerce_after_shop_loop_item), and that screwed up the jQuery code that Smart Coupons uses to find the siblings(), since now it is nested within another div.
add_action('woocommerce_after_shop_loop_item', function () {
echo '<div class="bde-woo-product-footer">';
do_action('breakdance_shop_loop_footer');
echo '</div>';
});
// Move add to cart button inside footer div.
remove_action('woocommerce_after_shop_loop_item','woocommerce_template_loop_add_to_cart');
add_action('breakdance_shop_loop_footer','woocommerce_template_loop_add_to_cart');
The Smart Coupons JS
This code appears in the file includes/class-wc-sc-display-coupons.php around line 715. I’ve added the comments below to explain what each line is doing.
//Print the target class within PHP with the $product_id.
var target_class = 'wc_sc_loop_button_" . $product_id . "';
//The class of Smart Coupons link
var wc_sc_loop_button = jQuery('.' + target_class);
//The original Add to Cart button we're looking for, and this is the one that got lost because jQuery function is targeting siblings
var wc_sc_old_element = jQuery(wc_sc_loop_button).siblings('a[data-product_id=" . $product_id . "]');
//Classes from this button that Smart Coupons will copy and use on it's own link for styling
var wc_sc_loop_button_classes = wc_sc_old_element.attr('class');
//Remove the class that Smart Coupons link gave itself, and then remove "display:none;".
wc_sc_loop_button.removeClass(target_class).addClass(wc_sc_loop_button_classes).show();
//Get rid of the original "Add to Cart" button
wc_sc_old_element.remove();
The Code Snippet to Add to functions.php for Smart Coupons to work with Breakdance
This snippet will remove the action that Smart Coupons uses, and then add it back in the Breakdance action.
Why Doesn’t the Plugin Author Use Native WordPress Hooks Instead of a “Hacky” jQuery Solution?
After going through all of this, I have no idea why the plugin author opted to write their code this way. Why add extra JS to the page instead of simply using a WooCommerce hook? Maybe when the plugin was originally authored, a hook didn’t exist, or there was some other reason to do it this way.
My Proposed Better Solution
Instead of doing everything I did above, why doesn’t the plugin author just do this? I ended up removing the original Smart Coupons action, and using the WooCommerce filter:
The Result
My Gift Card product now renders like this in the loop:
Style the Number Input on the Product Page
While you’re noodling around, you’ll likely notice the input field styling looks bland. Well, that’s because there’s not a class on it that Breakdance styles. So, we can add some very basic JS to add the class.
Look around, and you’ll notice that the class “input-text” is one that Breakdance uses to style other input areas, like the quantity input. We can re-use that class (instead of writing more CSS) for this element.
Steps To Follow to Add the Class with Javascript
- Add a Code Block somewhere on your Single Product template
- Write the following JS in the Javascript input area:
let gc_amount_input = document.getElementById('credit_called');
if ( gc_amount_input ) {
gc_amount_input.classList.add('input-text');
}
Steps to Follow to Add the Class with PHP
As is the case in life, there’s often more than one way to skin a cat. So, I did some more digging, and found that there’s a filter in the Smart Coupons plugin we can use to add our class to the input field. You can add this code in functions.php or inside a Code Block in Breakdance before the input appears (if you do it after, it won’t work because the html from the plugin will already be printed).
<?php
add_filter( 'wc_sc_call_for_credit_template_input', function( $input, $args ) {
$input['class'] = 'input-text';
return $input;
}, 10, 2 );
PHP / WordPress Filters is My Preferred Method
I always like to use filters in WordPress over an JS method because they are cacheable. The JS method will load on every page, whereas the PHP method will get cached. Caching means faster page load, and as a result, better search ranking (and user experience).