Gamal Elwazeery
Gamal Elwazeery

Reputation: 128

Add the variation price to variable product dropdown item names in Woocommerce

I'm using this code to get the variable product options

$terms = wc_get_product_terms( $bundle_product_id, $name, array( 'fields' => 'all' ) );
foreach ( $terms as $term ) {
    if ( !in_array( $term->slug, $options ) ) {
        continue;
    }
    echo '<option value="' . esc_attr( $term->slug ) . '" ' . selected( sanitize_title( $selected_value ), sanitize_title( $term->slug ), false ) . '>' . apply_filters( 'woocommerce_variation_option_name', $term->name )  . '</option>';
}

Upvotes: 2

Views: 8155

Answers (3)

MaxTab
MaxTab

Reputation: 26

A slightly variation of LoicTheAztec's solution: If you are absolutely certain that the price of your products only varies on one of the attributes (For example several sizes available, each size has a different price, and several colors, but the color does not change the price), even if your products have several attributes, you can simply add a condition not on the number of attributes as LoicTheAztec did, but on the attribute identifier:

Change ATTRIBUTE_SLUG below, but keep the "pa_" before.

Works on Woocommerce 8.5.

/**
 * Utility function to get the HTML of the price for a specific product variation.
 * It iterates through all available variations of the product to find the matching variation based on attribute name and term slug.
 * Once found, it returns the HTML containing the price of the variation, with HTML tags stripped for clean text.
 *
 * @param WC_Product $product The WooCommerce product object.
 * @param string $name The name of the attribute.
 * @param string $term_slug The slug of the term for which price is needed.
 * @return string The HTML containing the price of the variation.
 */
function get_the_variation_price_html($product, $name, $term_slug) {
    foreach ($product->get_available_variations() as $variation) {
        if ($variation['attributes'][$name] == $term_slug) {
            return strip_tags($variation['price_html']);
        }
    }
}

/**
 * Modifies the HTML for dropdown attribute options in WooCommerce products.
 * This function hooks into WooCommerce to modify the dropdown HTML, adding price information to each option.
 * It specifically targets a custom attribute 'pa_ATTRIBUTE_SLUG' and inserts prices for each of its terms.
 *
 * @param string $html The original HTML for the dropdown.
 * @param array $args An array of arguments including the product, attribute information, and other settings.
 * @return string Modified HTML for the dropdown including the prices.
 */
add_filter('woocommerce_dropdown_variation_attribute_options_html', 'show_price_in_attribute_dropdown', 10, 2);
function show_price_in_attribute_dropdown($html, $args) {
    // Check if the current attribute is the targeted custom attribute
    if ($args['attribute'] === 'pa_ATTRIBUTE_SLUG') {

        // Extracting necessary data from the $args array
        $options               = $args['options'];
        $product               = $args['product'];
        $attribute             = $args['attribute'];
        $name                  = $args['name'] ? $args['name'] : 'attribute_' . sanitize_title($attribute);
        $id                    = $args['id'] ? $args['id'] : sanitize_title($attribute);
        $class                 = $args['class'];
        $show_option_none      = $args['show_option_none'] ? true : false;
        $show_option_none_text = $args['show_option_none'] ? $args['show_option_none'] : __('Choose an option', 'woocommerce');

        // Building the dropdown HTML
        $html = '<select id="' . esc_attr($id) . '" class="' . esc_attr($class) . '" name="' . esc_attr($name) . '" data-attribute_name="attribute_' . esc_attr(sanitize_title($attribute)) . '" data-show_option_none="' . ($show_option_none ? 'yes' : 'no') . '">';
        $html .= '<option value="">' . esc_html($show_option_none_text) . '</option>';

        // Iterate through each option and append the price HTML
        if (!empty($options)) {
            if ($product && taxonomy_exists($attribute)) {
                $terms = wc_get_product_terms($product->get_id(), $attribute, array('fields' => 'all'));

                foreach ($terms as $term) {
                    if (in_array($term->slug, $options)) {
                        $price_html = get_the_variation_price_html($product, $name, $term->slug);
                        $html .= '<option value="' . esc_attr($term->slug) . '" ' . selected(sanitize_title($args['selected']), $term->slug, false) . '>' . esc_html(apply_filters('woocommerce_variation_option_name', $term->name) . ' - ' . $price_html) . '</option>';
                    }
                }
            } else {
                foreach ($options as $option) {
                    $selected = sanitize_title($args['selected']) === $args['selected'] ? selected($args['selected'], sanitize_title($option), false) : selected($args['selected'], $option, false);
                    $price_html = get_the_variation_price_html($product, $name, $term->slug);
                    $html .= '<option value="' . esc_attr($option) . '" ' . $selected . '>' . esc_html(apply_filters('woocommerce_variation_option_name', $option) . ' - ' . $price_html) . '</option>';
                }
            }
        }
        $html .= '</select>';
    }

    // Return the modified (or unmodified) dropdown HTML
    return $html;
}

Upvotes: 0

Travis Wagner
Travis Wagner

Reputation: 469

Here is my simplified solution to this that is working with WooCommerce 4.7.0. Since we know there is only one attribute for each variation, we can just get the first value to show the correct price for each.

/**
 * Display price in variation options dropdown for products that have only one attribute.
 *
 * @param  string $term Existing option term value.
 * @return string $term Existing option term value or updated term value with price.
 */
function display_price_in_variation_options( $term ) {
    $product = wc_get_product();
    $id      = $product->get_id();
    if ( empty( $term ) || empty( $id ) ) {
        return $term;
    }
    if ( $product->is_type( 'variable' ) ) {
        $product_variations = $product->get_available_variations();
    } else {
        return $term;
    }
    foreach ( $product_variations as $variation ) {
        if ( count( $variation['attributes'] ) > 1 ) {
            return $term;
        }
        $attribute = array_values( $variation['attributes'] )[0];
        if ( $attribute === $term ) {
            $term .= ' (' . wp_strip_all_tags( wc_price( $variation['display_price'] ) ) . ')';
        }
    }
    return $term;
}
add_filter( 'woocommerce_variation_option_name', 'display_price_in_variation_options' );

Upvotes: 2

LoicTheAztec
LoicTheAztec

Reputation: 253901

It will only work if you have just one product attribute for variations set in the variable product (so only one dropdown).

If you have more than one dropdowns in your variable product, as the variations are a combination of the different product attributes values, it will not work logically.

So the following code will display the product variation price in a unique product attribute dropdown:

// Utility function to get the price of a variation from it's attribute value
function get_the_variation_price_html( $product, $name, $term_slug ){
    foreach ( $product->get_available_variations() as $variation ){
        if($variation['attributes'][$name] == $term_slug ){
            return strip_tags( $variation['price_html'] );
        }
    }
}

// Add the price  to the dropdown options items.
add_filter( 'woocommerce_dropdown_variation_attribute_options_html', 'show_price_in_attribute_dropdown', 10, 2);
function show_price_in_attribute_dropdown( $html, $args ) {
    // Only if there is a unique variation attribute (one dropdown)
    if( sizeof($args['product']->get_variation_attributes()) == 1 ) :

    $options               = $args['options'];
    $product               = $args['product'];
    $attribute             = $args['attribute'];
    $name                  = $args['name'] ? $args['name'] : 'attribute_' . sanitize_title( $attribute );
    $id                    = $args['id'] ? $args['id'] : sanitize_title( $attribute );
    $class                 = $args['class'];
    $show_option_none      = $args['show_option_none'] ? true : false;
    $show_option_none_text = $args['show_option_none'] ? $args['show_option_none'] : __( 'Choose an option', 'woocommerce' );

    if ( empty( $options ) && ! empty( $product ) && ! empty( $attribute ) ) {
        $attributes = $product->get_variation_attributes();
        $options    = $attributes[ $attribute ];
    }

    $html = '<select id="' . esc_attr( $id ) . '" class="' . esc_attr( $class ) . '" name="' . esc_attr( $name ) . '" data-attribute_name="attribute_' . esc_attr( sanitize_title( $attribute ) ) . '" data-show_option_none="' . ( $show_option_none ? 'yes' : 'no' ) . '">';
    $html .= '<option value="">' . esc_html( $show_option_none_text ) . '</option>';

    if ( ! empty( $options ) ) {
        if ( $product && taxonomy_exists( $attribute ) ) {
            $terms = wc_get_product_terms( $product->get_id(), $attribute, array( 'fields' => 'all' ) );

            foreach ( $terms as $term ) {
                if ( in_array( $term->slug, $options ) ) {
                    // Get and inserting the price
                    $price_html = get_the_variation_price_html( $product, $name, $term->slug );
                    $html .= '<option value="' . esc_attr( $term->slug ) . '" ' . selected( sanitize_title( $args['selected'] ), $term->slug, false ) . '>' . esc_html( apply_filters( 'woocommerce_variation_option_name', $term->name ) . ' ::: ' . $price_html ) . '</option>';
                }
            }
        } else {
            foreach ( $options as $option ) {
                $selected = sanitize_title( $args['selected'] ) === $args['selected'] ? selected( $args['selected'], sanitize_title( $option ), false ) : selected( $args['selected'], $option, false );
                // Get and inserting the price
                $price_html = get_the_variation_price_html( $product, $name, $term->slug );
                $html .= '<option value="' . esc_attr( $option ) . '" ' . $selected . '>' . esc_html( apply_filters( 'woocommerce_variation_option_name', $option ) . ' ::: ' . $price_html ) . '</option>';
            }
        }
    }
    $html .= '</select>';

    endif;

    return $html;
}

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

enter image description here

Upvotes: 5

Related Questions