如何在 WooCommerce 的可变产品页面中将选择选项(产品属性)转换为可点击的 div?

时间:2021-04-18 18:47:10

标签: php html wordpress woocommerce

我正在尝试重新设计 woocommerce 单个产品页面,而不是显示变体选项的下拉列表,我希望它们被放置在单独的 div 中并并排显示在 flex 框中。我不明白是什么部分使数据采用“下拉列表”形式?

说明我想要实现的目标:

enter image description here




这是 html 部分(取自包含文件夹内的 wc-template-functions.php),我需要将每个变体插入单独的 div 中,而不是选择和选项标签。我真的需要这个。有什么帮助吗?

这是我在 woocommerce -> includes -> wc-template-functions.php 中的尝试,在 function wc_dropdown_variation_attribute_options 中。它显示了变体,但它们不可点击,并且无法在添加到购物车/立即购买事件时提取数据以进行选择和转发:

function wc_dropdown_variation_attribute_options( $args = array() ) {
        $args = wp_parse_args(
            apply_filters( 'woocommerce_dropdown_variation_attribute_options_args', $args ),
            array(
                'options'          => false,
                'attribute'        => false,
                'product'          => false,
                'selected'         => false,
                'name'             => '',
                'id'               => '',
                'class'            => '',
            )
        );

        // Get selected value.
        if ( false === $args['selected'] && $args['attribute'] && $args['product'] instanceof WC_Product ) {
            $selected_key = 'attribute_' . sanitize_title( $args['attribute'] );
            // phpcs:disable WordPress.Security.NonceVerification.Recommended
            $args['selected'] = isset( $_REQUEST[ $selected_key ] ) ? wc_clean( wp_unslash( $_REQUEST[ $selected_key ] ) ) : $args['product']->get_variation_default_attribute( $args['attribute'] );
            // phpcs:enable WordPress.Security.NonceVerification.Recommended
        }

        $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 ) && ! empty( $product ) && ! empty( $attribute ) ) {
            $attributes = $product->get_variation_attributes();
            $options    = $attributes[ $attribute ];
        }

    

        if ( ! empty( $options ) ) {
            if ( $product && taxonomy_exists( $attribute ) ) {
                // Get terms if this is a taxonomy - ordered. We need the names too.
                $terms = wc_get_product_terms(
                    $product->get_id(),
                    $attribute,
                    array(
                        'fields' => 'all',
                    )
                );

                foreach ( $terms as $term ) {
                    if ( in_array( $term->slug, $options, true ) ) {
                        $html .= '<div value="' . esc_attr( $term->slug ) . '" ' . selected( sanitize_title( $args['selected'] ), $term->slug, false ) . '>' . esc_html( apply_filters( 'woocommerce_variation_option_name', $term->name, $term, $attribute, $product ) ) . '</div>';
                    }
                }
            } else {
                foreach ( $options as $option ) {
                    // This handles < 2.4.0 bw compatibility where text attributes were not sanitized.
                    $selected = sanitize_title( $args['selected'] ) === $args['selected'] ? selected( $args['selected'], sanitize_title( $option ), false ) : selected( $args['selected'], $option, false );
                    $html    .= '<div value="' . esc_attr( $option ) . '" ' . $selected . '>' . esc_html( apply_filters( 'woocommerce_variation_option_name', $option, null, $attribute, $product ) ) . '</div>';
                }
            }
        }

        $html .= '</div>';

        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
        echo apply_filters( 'woocommerce_dropdown_variation_attribute_options_html', $html, $args );
    }

1 个答案:

答案 0 :(得分:1)

我想过不使用任何钩子将属性选择选项转换为单独的 div。我宁愿使用 jQuery。

<块引用>

原因很简单。 WooCommerce 使用几个基于 选择选项元素,并用 div 替换选项可以 产生意外冲突。

想法是这样的:创建选择选项产品属性的副本 (对用户隐藏) 并替换 div 中的所有选择选项通过 jQuery unwrap() 函数。我的灵感来自这个答案:Is it possible to convert a select menu to buttons?

每个产品属性的所有select选项都会转成div(甚至不止一个)。

更新

之前的代码不允许自动隐藏与任何产品变体不对应的属性选项 (div)。代码现已更新,允许用户:

  • 通过单击同一元素选择和取消选择 div
  • 自动隐藏与任何产品变体不对应的属性(基于一个或多个选定的 div)
<块引用>

该代码适用于产品页面上的任意数量的属性

JQUERY

add_action( 'wp_footer', 'converts_product_attributes_from_select_options_to_div' );
function converts_product_attributes_from_select_options_to_div() {

    ?>
        <script type="text/javascript">

            jQuery(function($){

                // clones select options for each product attribute
                var clone = $(".single-product div.product table.variations select").clone(true,true);

                // adds a "data-parent-id" attribute to each select option
                $(".single-product div.product table.variations select option").each(function(){
                    $(this).attr('data-parent-id',$(this).parent().attr('id'));
                });

                // converts select options to div
                $(".single-product div.product table.variations select option").unwrap().each(function(){
                    if ( $(this).val() == '' ) {
                        $(this).remove();
                        return true;
                    }
                    var option = $('<div class="custom_option is-visible" data-parent-id="'+$(this).data('parent-id')+'" data-value="'+$(this).val()+'">'+$(this).text()+'</div>');
                    $(this).replaceWith(option);
                });
                
                // reinsert the clone of the select options of the attributes in the page that were removed by "unwrap()"
                $(clone).insertBefore('.single-product div.product table.variations .reset_variations').hide();

                // when a user clicks on a div it adds the "selected" attribute to the respective select option
                $(document).on('click', '.custom_option', function(){
                    var parentID = $(this).data('parent-id');
                    if ( $(this).hasClass('on') ) {
                        $(this).removeClass('on');
                        $(".single-product div.product table.variations select#"+parentID).val('').trigger("change");
                    } else {
                        $('.custom_option[data-parent-id='+parentID+']').removeClass('on');
                        $(this).addClass('on');
                        $(".single-product div.product table.variations select#"+parentID).val($(this).data("value")).trigger("change");
                    }
                    
                });

                // if a select option is already selected, it adds the "on" attribute to the respective div
                $(".single-product div.product table.variations select").each(function(){
                    if ( $(this).find("option:selected").val() ) {
                        var id = $(this).attr('id');
                        $('.custom_option[data-parent-id='+id+']').removeClass('on');
                        var value = $(this).find("option:selected").val();
                        $('.custom_option[data-parent-id='+id+'][data-value='+value+']').addClass('on');
                    }
                });

                // when the select options change based on the ones selected, it shows or hides the respective divs
                $('body').on('check_variations', function(){
                    $('div.custom_option').removeClass('is-visible');
                    $('.single-product div.product table.variations select').each(function(){
                        var attrID = $(this).attr("id");
                        $(this).find('option').each(function(){
                            if ( $(this).val() == '' ) {
                                return;
                            }
                            $('div[data-parent-id="'+attrID+'"][data-value="'+$(this).val()+'"]').addClass('is-visible');
                        });
                    });
                });

            });

        </script>
    <?php

}

代码已经过测试并且可以工作。将它添加到您的活动主题的functions.php。

CSS

/* adds style to divs */
/* by default all divs are hidden */
div.custom_option {
    display: none;
    border: 2px solid #ccc;
    margin-right: 5px;
    padding: 2px 5px;
    cursor: pointer;
}

/* show only divs with class "is-visible" */
div.custom_option.is-visible {
    display:inline-block;
}

/* adds the style to the selected div */
div.custom_option.on {
    background-color: #777;
    color: white;
}

在活动主题的样式表中添加 CSS。

之前

enter image description here


之后

enter image description here


用法

enter image description here