Change WooCommerce variation select to buttons

The PHP Code

 function bmwp_color_variation_buttons( $html, $args ) {

        // Extract array elements into variables
        $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' ];
    
        if( empty( $options ) || ! $product || !$product->is_type( 'variable' ) ) {
            return $html;
        }
    
        // Define button settings based on attribute
        $button_settings = [
            'pa_color' => [
                'class' => 'bmwp-color-button',
                'container' => 'bmwp-color-variations',
                'get_style' => function( $term ) {
                    $color_image_url = get_term_meta( $term->term_id, 'color_image', true );
                    $color = $color_image_url ? $color_image_url : get_term_meta( $term->term_id, 'color_color', true );
                    return $color_image_url ? "background-image: url('{$color_image_url}');" : "background-color: {$color};";
                },
                'display' => ''
            ],
            'pa_size' => [
                'class' => 'bmwp-size-button',
                'container' => 'bmwp-size-variations',
                'get_style' => function( $term ) { return ''; },
                'display' => function( $term ) { return esc_html( $term->name ); }
            ],
            'pa_extra-essence' => [
                'class' => 'bmwp-essence-button',
                'container' => 'bmwp-essence-variations',
                'get_style' => function( $term ) { return ''; },
                'display' => function( $term ) { return esc_html( $term->name ); }
            ],
        ];
    
        // Check if the attribute is in our settings
        if ( isset( $button_settings[ $attribute ] ) ) {
            $settings = $button_settings[ $attribute ];
            $selected_value = isset( $args['selected']) ? $args['selected'] : '';
            $terms = wc_get_product_terms( $product->get_id(), $attribute, array('fields' => 'all') );
    
            if ( ! empty( $terms ) ) {
                $buttons = '<div class="' . esc_attr( $settings['container'] ) . '">';
    
                foreach ( $terms as $term ) {
                    $term_name = esc_html( $term->name );
                    $term_slug = esc_attr( $term->slug );
                    $selected_class = ( $selected_value === $term_slug ) ? 'selected' : '';
                    $style = call_user_func( $settings['get_style'], $term );
                    $display = $settings['display'] ? call_user_func( $settings['display'], $term ) : '';
    
                    $buttons .= sprintf(
                        '<button type="button" class="%1$s %2$s" data-attribute_name="attribute_%3$s" data-value="%4$s" title="%5$s" style="%6$s">%7$s</button>',
                        esc_attr( $settings['class'] ),
                        $selected_class,
                        esc_attr( $attribute ),
                        $term_slug,
                        $term_name,
                        $style,
                        $display
                    );
                }
    
                $buttons .= '</div>';
                return $html . $buttons;
            }
        }
    
        return $html;
    }
    
    add_filter( 'woocommerce_dropdown_variation_attribute_options_html', 'bmwp_color_variation_buttons', 20, 2 );

The JavaScript Code

document.addEventListener('DOMContentLoaded', function() {
    // Generic function to handle button clicks
    function handleButtonClick(buttonClass, variationClass) {
        document.querySelectorAll(buttonClass).forEach(function(button) {
            button.addEventListener('click', function() {
                const attributeName = button.getAttribute('data-attribute_name');
                const attributeValue = button.getAttribute('data-value');

                // Update the corresponding select dropdown
                const selectElement = document.querySelector('select[name="' + attributeName + '"]');
                if (selectElement) {
                    selectElement.value = attributeValue;
                    const event = new Event('change', { bubbles: true });
                    selectElement.dispatchEvent(event);
                }

                // Update the selected state of the buttons
                const variationContainer = button.closest(variationClass);
                if (variationContainer) {
                    variationContainer.querySelectorAll(buttonClass).forEach(function(btn) {
                        btn.classList.remove('selected');
                    });
                    button.classList.add('selected');
                }
            });
        });
    }

    // Apply the function to different button types
    handleButtonClick('.bmwp-color-button', '.bmwp-color-variations');
    handleButtonClick('.bmwp-size-button', '.bmwp-size-variations');
    handleButtonClick('.bmwp-essence-button', '.bmwp-essence-variations');
});

The CSS code

Please be sure that you have disabled the select element and you have properly display and positioning the new buttons you have created. Enjoy!

select#pa_size,
select#pa_color {
    display: none;
}

.bmwp-color-variations,
.bmwp-size-variations,
.bmwp-essence-variations {
    display: flex;
    gap: 5px;
    flex-wrap: wrap;
}

.bmwp-color-button {
    width: 38px;
    height: 38px;
    padding: 3px;
    border-radius: 100px;
    border: 2px solid #929294;
    cursor: pointer;
    background-size: cover;
    background-position: center;
    background-clip: content-box; /* Ensure the background stays within the padding area */
    box-sizing: border-box; /* Include padding and border in the element's width and height */
    position: relative;
}

/* Highlight the selected color */
.bmwp-color-button.selected {
    border-color: var(--contrast-alt)!important;
}

/* Tooltip styling */
.bmwp-color-button::before {
    content: attr(title); /* Use the title attribute for the tooltip text */
    position: absolute;
    bottom: calc(100% + 10px); /* Position the tooltip above the button */
    left: 50%;
    transform: translateX(-50%);
    background-color: #333;
    color: #fff;
    padding: 5px;
    border-radius: 5px;
    white-space: nowrap;
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.3s ease, visibility 0.3s ease;
    font-size: 12px;
    z-index: 1000;
}

.bmwp-color-button:hover::before {
    opacity: 1;
    visibility: visible;
}

.bmwp-color-button::after {
    content: '';
    position: absolute;
    bottom: 100%; /* Position it at the bottom of the tooltip */
    left: 50%;
    transform: translateX(-50%);
    border-width: 5px;
    border-style: solid;
    border-color: #333 transparent transparent transparent;
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.3s ease, visibility 0.3s ease;
    z-index: 1000;
}

/* Show the tooltip arrow on hover */
.bmwp-color-button:hover::after {
    opacity: 1;
    visibility: visible;
}