4

In WooCommerce, I would like to create a function which outputs a simple "list" of data, for each variation or a variable product. Or, if a simple product, then the details of that product itself. The details I need to include for each are: regular price, size attribute (used for the variations) sale price, stock.

This is for a "catalog" version of WooCommerce product pages, so there will be no actual Add To Cart button or Variation dropdown. Instead, I want to present the information of each product/variation to the user.

I need to output the data of each, as list items within a <ul>. A new <ul> for each variation.

Example of a product with 3 variations:

<div class="fs-product-data-wrapper">
  <ul>
    <li class="fs-data-price">$49.98 ea.</li>
    <li class="fs-data-size">Size: 15-18"</li>
    <li class="fs-data-sale">$49.98 ea. Preferred Customer Price</li>
    <li class="fs-data-stock">Quantity in Stock: 40</li>
  </ul>
  <ul>
    <li class="fs-data-price">$799.98 ea.</li>
    <li class="fs-data-size">Size: 2-2.5'</li>
    <li class="fs-data-sale">$67.98 ea. Preferred Customer Price</li>
    <li class="fs-data-stock">Quantity in Stock: 15</li>
  </ul>
  <ul>
    <li class="fs-data-price">$29.98 ea.</li>
    <li class="fs-data-size">Size: 12"</li>
    <li class="fs-data-sale">$19.98 ea. Preferred Customer Price</li>
    <li class="fs-data-stock">Quantity in Stock: 0</li>
  </ul>
</div>

Example of a product with no variations, but is just a simple product:

<div class="fs-product-data-wrapper">
  <ul>
    <li class="fs-data-price">$99.98 ea.</li>
    <li class="fs-data-size">Size: 15-18"</li>
    <li class="fs-data-sale">$99.98 ea. Preferred Customer Price</li>
    <li class="fs-data-stock">Quantity in Stock: 32</li>
  </ul>
</div>

Screenshot of example:

Screenshot of example

I can manage the CSS of it. I just need the ability to produce this data within a ul for each "option". Ideally this would be done via shortcode too, since I will be populating it via a page builder template. But I could make due if it hooks into an existing product page hook. Perhaps woocommerce_after_single_product.

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
Garconis
  • 773
  • 11
  • 31

2 Answers2

1

Here is a way to display some specific formatted product data for simple and variable products:

// Utility funtion: getting and formtting product data
function format_product_data_output( $the_id ){
    $empty =  __( '<em>(empty)</em>', 'woocommerce' );

    // Get an instance of the WC_Product_Variation object
    $product = wc_get_product( $the_id );

    // Only wc_get_price_to_display() respect if product is to be displayed with or without including taxes
    $price = wc_price( wc_get_price_to_display( $product, array( 'price' => $product->get_regular_price() ) ) );
    $sale_price = wc_get_price_to_display( $product, array( 'price' => $product->get_sale_price() ) );
    $sale_price = ! empty( $sale_price ) ? wc_price($sale_price) : $empty;

    $size = $product->get_attribute( 'pa_size' );
    $size = ! empty( $size ) ? get_term_by( 'slug', $size, 'pa_size' )->name : $empty;

    $stock_qty = $product->get_stock_quantity();
    $stock_qty = ! empty( $stock_qty ) ? $stock_qty : $empty;

    $output = '
    <ul>
        <li class="fs-data-price">'.$price.'</li>
        <li class="fs-data-size">Size: '.$size.'</li>
        <li class="fs-data-sale">'.$sale_price.' Preferred Customer Price</li>
        <li class="fs-data-stock">Quantity in Stock: '.$stock_qty.'</li>
    </ul>';

    return $output;
}

//
add_action( 'woocommerce_after_single_product', 'custom_table_after_single_product' );
function custom_table_after_single_product(){
    global $product;

    $output = '<div class="fs-product-data-wrapper">';

    // Variable products
    if( $product->is_type('variable'))
    {
        // Get available variations in the variable product
        $available_variations = $product->get_available_variations();

        if( count($available_variations) > 0 ){
            foreach( $available_variations as $variation )
                $output .= format_product_data_output( $variation['variation_id'] );
        }
    }
    // Simple products
    elseif( $product->is_type('simple'))
    {
        $output .= format_product_data_output( $product->get_id() );
    }
    else return; // Exit

    echo $output .= '</div>'; // Display
}

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

You will have to manage CSS (and may be some little details). Anything needed is mostly there.

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
  • Thanks, this works well too. But for the dimensions, do you have any idea how to output the Size attribute term(s)? I have `pa_size` attribute that needs to be where your current dimensions is. I need it to output the Size's term. – Garconis Mar 30 '18 at 17:45
  • Please update. I prefer your code, but I couldn't use it for my needs, because it didn't work for the variable size attribute. If you update and it works, I would accept yours as the answer. – Garconis Mar 30 '18 at 23:10
  • 1
    I will test and implement on Monday and mark as answer if it's good. I like your code, as it's easier to read and manipulate if needed. Thanks! – Garconis Mar 31 '18 at 00:36
  • @Garconis Thanks… I have maid some final improvements regarding **displayed prices** and compacting code a bit more, avoiding repetitions… – LoicTheAztec Mar 31 '18 at 01:16
  • Works perfectly. Thanks! – Garconis Apr 02 '18 at 13:45
1

If you set size attribute like on my screen

enter image description here

And then create simple or variable product with attribute size, than you can add code to functions.php file of your active child theme (or active theme)

/**
 * Display list data after single product
 */
function display_list_after_single_product() {
    $product_data = get_product_data();

    ?>
    <div class="fs-product-data-wrapper">
    <?php
        if ( isset( $product_data['price'] ) ) {
            ?>
            <ul>
            <?php
                ?>
                <li class="fs-data-price"><?php echo $product_data['price'] ?></li>
                <li class="fs-data-size"><?php echo $product_data['size'] ?></li>
                <li class="fs-data-sale"><?php echo $product_data['sale_price'] ?></li>
                <li class="fs-data-stock"><?php echo $product_data['stock'] ?></li>
            </ul>
            <?php
        } else {
            foreach ( $product_data as $data ) {
                ?>
                <ul>
                <?php
                    ?>
                    <li class="fs-data-price"><?php echo $data['price'] ?></li>
                    <li class="fs-data-size"><?php echo $data['size'] ?></li>
                    <li class="fs-data-sale"><?php echo $data['sale_price'] ?></li>
                    <li class="fs-data-stock"><?php echo $data['stock'] ?></li>
                </ul>
                <?php
            }
        }
    ?>
    </div>
    <?php

}
add_action( 'woocommerce_after_single_product', 'display_list_after_single_product' );

/**
 * Collect product data depending on product type
 *
 * @return array $product_arr
 */
function get_product_data() {
    global $product;
    if( $product->is_type( 'variable' ) ) {
        $variation_arr = [];
        $imp_variations = $product->get_available_variations();
        foreach ( $imp_variations as $key => $prod_var_arr ) {

            $variation_obj = new WC_Product_variation($prod_var_arr["variation_id"]);
            // collect reqired variation data to array
            $product_arr[] = [
                'price'      => $variation_obj->get_regular_price(),
                'sale_price' => $variation_obj->get_sale_price(),
                'size'       => $prod_var_arr['attributes']['attribute_pa_size'],
                'stock'      => $variation_obj->get_stock_quantity(),
            ];
        }
    } else if( $product->is_type( 'simple' ) ) {
        $terms = $product->get_attributes()["pa_size"]->get_terms();

        $product_arr = [
            'price'      => $product->get_regular_price(),
            'sale_price' => $product->get_sale_price(),
            'size'       => $terms[0]->name,
            'stock'      => $product->get_stock_quantity(),
        ];
    }

    return $product_arr;
}

And you will get list below of product page exactly like you asking about.

Oleg Apanovich
  • 666
  • 6
  • 14
  • Thanks, this seems to work for the most part, but the Size data doesn't populate for Variable products. – Garconis Mar 30 '18 at 17:32
  • I had to update yours from `'size' => $prod_var_arr['attributes']['attribute_pa_size'],` to instead be `'size' => $prod_var_arr['attributes']['attribute_size'],` for the variable type – Garconis Mar 30 '18 at 20:06
  • By default attribute is taxonomy and has pa_ prefix. It difficult to me understand why your attribute do not has pa_ prefix. I leave my answer without edit because I tested it in a clear wordpress and woocommerce installation. Anyway if my answer was helpfull for you please mark it as right answer, thanks. – Oleg Apanovich Mar 30 '18 at 22:53