Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WooCommerce: How to display fields from the "Product Add-ons" extension?

I'm using the [Product Add-ons][1] extension for WooCommerce, which allows custom fields for products. This automatically displays on the single product template.

By some trial and error with the single product template, it appears to hook in somewhere in woocommerce_single_product_summary (single_meta?).

I need to get this same set of form fields to display on the archive-product template (the list of products). In my case, this is a field for a card request and one for delivery date. Both are needed before the product can be added to the cart from the product archive. I'm not sure if there is a function I can call for this, if it involves some more advanced coding.


Per Pelmered's answer, I was able to get the add-on fields to show up with adding this to functions.php:

add_action( 'woocommerce_after_shop_loop_item_title', array($GLOBALS['Product_Addon_Display'], 'display'), 10);

1ST ATTEMPT

Then, the problem was that the product archive was not creating a form element, only an anchor link for the add to cart button. So I've tried manually putting in a form. Code from content-product.php:

<?php do_action( 'woocommerce_before_shop_loop_item' ); ?>
<h2><?php the_title(); ?></h2>

<?php // MANUALLY PUT IN FORM, BECAUSE HOOKS ONLY PUT IN A BUTTON AND NO FORM. NEEDED FOR ADD-ON FIELDS ?>
<form class="cart" method="post" enctype='multipart/form-data'>
    <?php
        /**
         * woocommerce_after_shop_loop_item_title hook
         *
         * @hooked woocommerce_template_loop_rating - 5
         * @hooked woocommerce_template_loop_price - 10
         */
        do_action( 'woocommerce_after_shop_loop_item_title' );
    ?>          
    <div itemprop="description">
        <?php the_content(); ?>
    </div>
    <input type="hidden" name="add-to-cart" value="<?php echo esc_attr( $product->id ); ?>" />
    <button type="submit" class="single_add_to_cart_button button alt"><?php echo $product->single_add_to_cart_text(); ?></button>
</form>

<?php //do_action( 'woocommerce_after_shop_loop_item' ); ?>

This worked, but kind of messes up the AJAX submission and flash messages. After clicking the add to cart button, the page appears to refresh, and then it looks like nothing happened. But when you go to another page, it displays the messages (and multiple can stack).

2ND ATTEMPT

So I saw that the original AJAX cart button (not within a form) was using a query string to send the product ID. So I am now attempting to tack on additional parameters by modifying the add to cart JS. This worked. What I did added as the accepted answer.

like image 328
jwinn Avatar asked Aug 29 '14 23:08

jwinn


3 Answers

If anyone want to display woocommerce product addons fields everywhere, you can do this:

$custom_field = get_post_meta( $product_id, '_product_addons', false );

foreach( $custom_field as $field => $value) { 
    foreach( $value as $val => $v) {         
        echo $v["name"]; // or other field that you want!
    }            
}

Enjoy!

like image 189
Pedram Avatar answered Nov 14 '22 16:11

Pedram


I've found a solution that works, using jQuery to add the form field values to the AJAX request. This requires overriding add-to-cart.js with your own version, so future updates to that file may need to be merged.

In functions.php

// display add-on fields in woocommerce_after_shop_loop_item_title
add_action( 'woocommerce_after_shop_loop_item_title', array($GLOBALS['Product_Addon_Display'], 'display'), 10);

// Our custom cart JS to allow for product add-on fields on product archive
add_action( 'wp_enqueue_scripts', 'load_woo_scripts', 9 );
function load_woo_scripts() { 
    wp_enqueue_script( 'wc-add-to-cart', get_template_directory_uri() . '/js/add-to-cart.js', array( 'jquery' ), WC_VERSION, true );
}

Duplicate /assets/add-to-cart.js from the woocommerce plugin folder, and add to the folder referenced in load_woo_scripts. Then add the following after the var date = { statement (line 21).

// =========================================================================
// ADD PRODUCT ADD-ON FIELDS TO SUBMISSION (to allow from product archive)
// Store name and value of fields in object.
var addonfields = {}; 
$(this).parent().find(".after-shop-loop-item-title :input").each(function() { 
    addonfields[this.name] = $(this).val(); 
}); 

// Merge new fields and existing data
data = $.extend(data, addonfields);

// Testing: final value of data
console.log( data );
// =========================================================================

This adds the names and values of all input fields within the .after-shop-loop-item-title div. I've added this div/class to my theme's woocommerce/content-product.php template:

<?php do_action( 'woocommerce_before_shop_loop_item' ); ?>
<h2><?php the_title(); ?></h2>
<div itemprop="description">
    <?php the_content(); ?>
</div>

<div class="after-shop-loop-item-title">
    <?php
        /**
         * woocommerce_after_shop_loop_item_title hook
         *
         * @hooked woocommerce_template_loop_rating - 5
         * @hooked woocommerce_template_loop_price - 10
         */
        do_action( 'woocommerce_after_shop_loop_item_title' );
    ?>  
</div>

<?php do_action( 'woocommerce_after_shop_loop_item' ); ?>

Note that in my case, I am only using a textarea and a text input. Neither of which changes the price. More advanced usage of the extension may require more work.

I really hope that WooCommerce makes this easier in the future...

like image 25
jwinn Avatar answered Nov 14 '22 16:11

jwinn


It's impossible to give you an exact copy-paste solution without access to the code, but it should be possible to attach the same function that is being hooked.

The hook that adds this to the single product page probably looks like this:

add_action( 'woocommerce_single_product_summary', array($this, 'woocommerce_product_add_ons_something'));

To attach this action to the achive template as well you should probably be able to do something like this:

add_action( 'woocommerce_after_shop_loop_item_title', array('WC_Product_Add_On', 'woocommerce_product_add_ons_something')); 

WC_Product_Add_On is the class name of the plguin and needs to be changed to match the class that has the function/method in the action. Put this code in the functions.php file in your theme.

See if it works. If not, give me more information and I can expand my answer.

like image 4
Pelmered Avatar answered Nov 14 '22 15:11

Pelmered