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

标签 php html wordpress woocommerce

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

我要实现的目标的说明:

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 );
    }

最佳答案

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

The reason is simple. WooCommerce uses several scripts based on the select options elements, and replacing the options with divs could generate unexpected conflicts.

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

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

已更新

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

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

The code works with any number of attributes on the product page.

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

关于php - 如何将选择选项(产品属性)转换为 WooCommerce 可变产品页面中的可点击 div?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67152237/

相关文章:

php - 刷新 div,但前提是 php 文件中有新内容

php - Wordpress - 将 wp_redirect url 更改为动态链接

php - 独立 Wamp 服务器 ssl 身份验证设置

php - 将数组拆分为多个部分并输出带有值列表的字符串

php - 如何通过php调用api并从中获取json文件

php - foreach 语句强制 while/for 循环太多次

html - 添加文本元素会破坏 div 布局

css - 如何从 Transposh 中删除 'Edit Translation' 文本

wordpress - 我在哪里可以找到我的 Google 字体 API key ? (新手)

php - 通过 AJAX 和 PHP 进行简单的实时 HTML 编辑