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 badges2 Answers
Reset to default 6Ok, 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' );