最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

woocommerce offtopic - Custom URL for each product variation - rewrite rules

programmeradmin3浏览0评论

I would like to have a separate url for each of my product variations. For that I would need to create a rewrite rule, that will work on the product URLs

Ie, my product URL is /

The product has two variations - size and color. I would like to be able to access the product on url like

This clearly has something to do with the add_rewrite_rule function. I don't know how to build the url structure to be able to access the variations part of url

function custom_rewrite_basic() {
  add_rewrite_rule('^product/([0-9]+)/([0-9]+)?', 'index.php?page_id=$matches[1]&variations=$matches[2]', 'top');
}
add_action('init', 'custom_rewrite_basic');

Anyone?

I would like to have a separate url for each of my product variations. For that I would need to create a rewrite rule, that will work on the product URLs

Ie, my product URL is https://example/product/tshirt/

The product has two variations - size and color. I would like to be able to access the product on url like https://example/product/tshirt/size-s-color-black

This clearly has something to do with the add_rewrite_rule function. I don't know how to build the url structure to be able to access the variations part of url

function custom_rewrite_basic() {
  add_rewrite_rule('^product/([0-9]+)/([0-9]+)?', 'index.php?page_id=$matches[1]&variations=$matches[2]', 'top');
}
add_action('init', 'custom_rewrite_basic');

Anyone?

Share Improve this question asked Sep 15, 2017 at 11:09 user1049961user1049961 4552 gold badges8 silver badges22 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 6

Ok, for anyone looking for this, here's a complete plugin that I came up with, that solves the issue:

<?php
/*
Plugin Name: WooCommerce Variations URL
Description: Adds support for variation-specific URL's for WooCommerce product variations
Author: Václav Greif
Version: 1.0
Author URI: https://wp-programator.cz
*/

namespace WCVariationsUrl;

final class Init
{
    /**
     * Call this method to get singleton
     *
     * @return Init
     */
    public static function Instance()
    {
        static $inst = null;
        if ($inst === null) {
            $inst = new Init();
        }
        return $inst;
    }

    /**
     * Private ctor so nobody else can instance it
     *
     */
    private function __construct()
    {
        $this->add_actions();
    }

    /**
     * Add actions
     */
    function add_actions() {
        add_filter('woocommerce_dropdown_variation_attribute_options_args',array($this,'variation_dropdown_args'));
        add_action('init', array($this,'add_rewrite_rules'));
        add_action('wp_head', array($this,'add_js_to_head'));

    }

    function variation_dropdown_args($args) {
        // Get the WooCommerce atts
        $attributes =  wc_get_attribute_taxonomies();
        $atts = [];
        foreach ($attributes as $attribute) {
            $atts[] = $attribute->attribute_name;
        }

        // Get the variations part of URL
        $url_string = get_query_var('variation');

        if ($url_string) {
            $array = [];
            preg_replace_callback(
                "/(\w++)(?>-(\w+-?(?(?!" . implode("|", $atts) . ")(?-1))*))/",
                function($matches) use (&$array) {
                    $array[$matches[1]] = rtrim($matches[2], '-');
                },
                $url_string
            );

            if (!empty($array)) {
                $attribute_key = str_replace('pa_','',$args['attribute']);

                if (array_key_exists($attribute_key,$array)) {
                    $args['selected'] = $array[$attribute_key];
                }
            }
        }

        return $args;

    }

    function add_rewrite_rules() {
        add_rewrite_rule('^product/([^/]*)/([^/]*)/?','index.php?product=$matches[1]&variation=$matches[2]','top');
        add_rewrite_tag('%variation%', '([^&]+)');
    }

    function add_js_to_head() {
        if (!function_exists('is_product') || !is_product())
            return;

        global $post;
        ?>

        <script type="text/javascript">
            var url = '<?php echo get_permalink($post->ID);?>';
            jQuery( document ).ready(function($) {
                setTimeout(
                    function() {
                        $('table.variations select').on('change',function() {
                            var attributes = [];
                            var allAttributesSet = true;
                            $('table.variations select').each(function() {
                                var value = $(this).val();
                                if (value) {
                                    attributes.push({
                                        id: $(this).attr('name'),
                                        value: value
                                    });
                                } else {
                                    allAttributesSet = false;
                                }
                            });

                            if (allAttributesSet) {
                                $.each(attributes,function(key, val) {
                                    var attributeSlug = val.id.replace('attribute_pa_','');
                                    url = url + attributeSlug + '-' + val.value
                                    if($(this)[0] !== $(attributes).last()[0]) {
                                        url = url + '-';
                                    }
                                });
                                window.location.replace(url);
                            }
                        });

                    }, 1000
                )
            });
        </script>
    <?php }
}

Init::Instance();

My intention: On change reload page, pass the ID as URL?attribute so i can get it on next page as GET. I had simmilar intention. But I wanted to pass this into the URL as an better attribute. The advice here did not really suited my intention so I a bit modified it for my purpose. The shop I needed this was really using intentionally and specifically only single variations, no 2-3 mixed together.

<script>
        jQuery(function($){
            setTimeout( function(){
                $( ".single_variation_wrap" ).on( "show_variation", function ( event, variation ) {
                    //alert( variation.variation_id );
                    console.log( variation.variation_id );


                    var url = '<?php echo get_permalink($post->ID);?>';
                    //$('input.variation_id').change( function(){


                    console.log('You just selected variation #' + variation.variation_id);
                    var attributes = [];
                    var allAttributesSet = true;
                    $('table.variations select').each(function() {
                        var value = $(this).val();
                        if (value) {
                            attributes.push({
                                id: $(this).attr('name'),
                                value: value
                            });
                        } else {
                            allAttributesSet = false;
                        }
                    });
                    if (allAttributesSet) {
                        $.each(attributes,function(key, val) {
                            var attributeSlug = val.id.replace('attribute_pa_','');
                            url = url +'?variation_id='+ variation.variation_id +'&'+attributeSlug+'=' + val.value;
                        });
                        console.log('Relocating #' + variation.variation_id);
                        //window.location.replace(url);
                        window.location.href = url;
                    }

                } );
            }, 400 );

        });
    </script>

Not sure if this is the best and good approach, but this is what is working for me, and it even keeps the selected values in Variation dropdown since it is only single one.

I am calling the script above in this action:

add_action( 'woocommerce_before_add_to_cart_quantity', 'destone_variation_modification' );

发布评论

评论列表(0)

  1. 暂无评论