Closed dd10-e closed 3 years ago
Hi @dd10-e,
Thank you for this detailed issue, it makes complete sense! Reworking the options and variants is on the table for a while, but we always had a more urgent fix, feature to do.
I really like the way you described the problem, I understand this might be a real need for others as well. Hopefully, in v0.5 or v0.6 we can work on this and find an implementation that works well.
I keep this issue open until we can turn on this task, so this can provide a good base idea.
Thanks again, we really appreciate it!
I think we need table options and pivot option_variant table. Each variant is combine of option.
Hey @dd10-e,
We've released v0.5, so I think it's time to turn on this one. I'm collecting some resources based on your issue and trying to find a simple and flexible solution. Hopefully, we can manage to implement this.
I'll create a new branch for this feature, so we can target any further related discussion there.
Thanks for your patience!
The first step for managing to doing this, is to adding two new concepts into Bazar :
ConfigurationStep
is grouping Configuration
. In a user view it's the configuration with a name, description, some useful infos, etc... For example, a color or product specific attributes that we can customize, telling what is the best for you.
System76 is doing it beautifully : https://system76.com/laptops/galp5/configure
The goal is the same as variants, but in Bazar, a "Variant" is lazy loaded. A variant is fetched depending on some options like ['Color' => 'Blue']
and ['Width' => '200'
belonging to a product. Bazar have OptionGroup
like a "Color", and OptionsValues
for values depanding of an OptionGroup
.
So in fact ConfigurationStep
is like an attempt to do the same but with more customization. I will show some work I've done experimenting in this.
My goal here is to be able adding a maximum of aspects of a product that we can sell with explanations, descriptions, calculations, this option is more expensive,you can't select this color with this blue, it does not go together, etc...
Configuration
, is an option of a configuration. Like values of an option in variants.ConfigurationStep
works the same way as Category
. For now I just added a field into bazar_categories
:
$table->string('type')->default('market'); // can be `market` (visible on market website) or `configuration_step` for queries
Adding this allowed me to separate real categories and configurations that are groups of custom variants.
A little note for this :
I was thinking we can maybe doing like Wordpress taxonomies. But it might me less performant and more complex... In any case, I should probably use 2 tables, `bazar_categories` and `bazar_configuration_steps`.
Where it started to be more interesting is that I found it more easy and flexible to use Product
for Configuration
.
For example, a color is a ConfigurationStep
having some Configuration
s like yellow and blue.
This way I'm able to set a lot more data like a name, images, prices, variants, etc...
For example, if I select blue. I want to show some variants of the blue like dark or light in a dropdown for example.
Product
already handles that for us ! Instead of using extending product's options as I was initially thinking of.
For doing this, I added fields into products for knowing if a product is configurable or not :
// Table : bazar_product
$table->boolean('is_configuration')->default(false); // True if the product will be in a configuration step
$table->boolean('is_configurable')->default(false); // True if the product has some configuration step
If yes, this product can be INSERTED in a ConfigurationStep
. Otherwise it can HAVE some ConfigurationStep
.
This way I can create a product called "Blue" shown in a ConfigurationStep
called "Color".
The product "Configure that awesome product" will have "Choose your color" ConfigurationStep
with a blue as Configuration
.
With that, I want know be able to adding more stuff !
For example, a step called "Choose a dimension", or allowing me to select multiple choices or only one, or even select this step in a popup because I know they will have a lot of options, etc.
For doing this, I added a field (in bazar_product
but that's only used if the type
is configuration_step
), allowing me to change dynamically how data is shown and fetched :
$table->string('selection_type')->nullable(); // Can be for example `dimensions` or `unique_selection` or even `popup_selection`
Below, an example of how I've used a configuration asking for dimensions. It uses some Laravel Livewire and Blade components with TailwindCSS, in addition to Bazar. (that's really nice stuff!)
@props([
'product' => null,
'configuration' => null,
])
@php
$quantity = $product->inventory->quantity < 10 ? $product->inventory->quantity : 10;
$isSelectedProductIdExist = isset($this->configuration[$configuration->name]['selected']);
$selectedProductId = $isSelectedProductIdExist? $this->configuration[$configuration->name]['selected'] : null;
@endphp
<div class="bg-white">
<div class="space-y-4">
<div class="max-w-sm space-y-2">
@foreach ($product->options as $option => $values)
<div>
<label for="height" class="block text-sm font-normal leading-5 text-gray-700">
<span class="font-semibold">{{ $option }}</span>
between
<span class="font-medium">{{ $product->options[$option][array_key_first($product->options[$option])] }}</span>
and
<span class="font-medium">{{ $product->options[$option][array_key_last($product->options[$option])] }}</span>
({{ config('bazar.dimension_unit') }})
</label>
<div class="mt-1 relative rounded-md shadow-sm">
<input
wire:model.lazy="configuration.{{ $configuration->name }}.{{ $option }}.{{ $product->slug }}"
type="text"
class="shadow-sm focus:ring-red-500 focus:border-red-500 block w-full sm:text-sm border-gray-300 rounded-md"
placeholder="{{ $product->options[$option][array_key_last($product->options[$option])] }}"
>
</div>
</div>
@endforeach
<button
wire:click="chooseDimensionProduct('{{$configuration->name}}', '{{ $product->slug }}')"
type="button"
class="inline-flex items-center px-2.5 py-1.5 border border-gray-300 shadow-sm text-xs font-medium rounded text-white bg-red-600 hover:bg-red-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500"
>
Choose dimensions
</button>
</div>
@error('dimension_' . $configuration->name)
<div class="mt-2 text-red-600">{{ $message }}</div>
@enderror
</div>
</div>
For dimensions I wasn't displaying name or description, I've mainly used Variants
of Bazar. See $product->options
.
In this case, the Configuration
had 2 variants height
and width
because internally it is a product as described before.
I customized the query in chooseDimensionProduct
for selecting only superior or equal dimensions than selected by users and some extra stuff.
Writing is really interesting, writing this post just make me realize about how configurations and variants can be unify. Basically, i've did the same as variants but data is structured differently (similar of what @vanthao03596 described) . Anyway, I need to continue working on it for leaning more...
I'm very far from Tesla or System76 configurators. It missing 2 crucials features :
ConfigurationProduct
or ConfigurationStep
I'm not talking about how it can be elegantly included in carts...
So I have a lot more to do.
But the good news is that is a lot of fun to work with Bazar, and for now I'm pretty happy because I feel it's a good start a lot more clean way that I in the past. It's very pleasant to use your package.
I'm not 100% convinced it will be useful for you because I haven't been very far for now. But wanted to let you know I saw your message @iamgergo and thank you !
Hey @dd10-e,
Returning here, after a long time!
So, I prepared the next release, which contains some rework of the current option/variant management.
I was struggling with how to achieve a simple solution, and I decide I'll make that in two steps – because PR #124 became a bit bigger than originally planned...
As the first step, I decided to rename the attributes: $product->options
now is $product->properties
, $variant->option
now is $variant->variation
. Names in migrations and front-end changed as well.
Also, I flattened the $item->properties
attribute, now every property is on the same level, variable properties are not wrapped in the option
array.
// Old
{
"options": {
"Size": "L",
"Material": "gold"
},
"Custom Text": "This is another prop"
}
// New
{
"Size": "L",
"Material": "gold",
"Custom Text": "This is another prop"
}
With this structure – and with some custom property classes – we'll be able to make validation rules and conditional values easier, as a next step.
What I'm planning now, is having a Property
class that holds some basic information about the property – for example, Size
or Material
, and some custom resolution logic based on the Product
, the Item
, and the Cart/Order
models.
These properties could be registered on the Product
model, for example, so when a product is added to the cart if the Item model contains a property that is registered on the product, we call the resolution logic, validation, etc.
use Bazar\Models\Product;
use Bazar\Properties\Size;
Product::resolvePropertyUsing('size', Size::class);
It's very similar to what we have with the
Item::resolvePropertyUsing
, but instead of a callable, we pass a class, so we have much more flexibility.
My problem is, the front-end basically can be anything, so it's hard to find a convenient way to make this solution easy to use and widely compatible with any front-store solution.
Hopefully, soon we can nail it!
Thanks!
Hello !
I wonder how it is possible to use
Variants
database structure to do configurable products like :I'm thinking more at Tesla website or a window configurator (this one seems to do pretty good things : https://fensternorm.com/en/configurator/windows/upvc/trocal-70-eco/c1)
Pretty hard !
I've done some research with the current implementation, and it was wonderful. I really liked the way you did this, simple and clean API.
The first thing I need to do is to add some attributes (something like a description and step order) and prices to this option, like you're doing on Variants. I can maybe add some attributes on
options
columns since it's a JSON column, but this might not be a very clean way to do this because I will lose all prices and stock handling of variants, and i don't think i can handle all this things listed above.So I've considered to requested directly variations this way :
Implementation look like this (unfinished) :
This way, I can add more attributes and have pricing, but I wouldn't be able to query : "Select me all variants when there is Size to XS selected" for example.
I think the best way to do this, and for having the more flexibility should be to have a separate table that we can name
configurations
with columnsoption_name|string
,value|string
,description|string
,prices|json
,inventory|json
,product_id
.Data will look this way (note that i've added some extra columns for illustrate application logic used by the application after Bazar Framework) :
Using another table should be more flexible, right ? But it really looks like variations in fact, except that we don't use the options column of products for query variations. In the other side configurations will be query using $product->configurations()->where('order', 1)->andGetMeArrayValuesWithStepName().
Not tested at all ! But it should be more flexible. I think I described the idea correctly.
So the response seems to be "No.". But I wanted to share my reflection and ask if it's something that should be added on Bazar Framework ? I'm mainly curious about the roadmap where you mention
More flexible option/property management
. Are you thinking of something similar or another way ?Perfect occasion to say that you did an amazing clean work. I learn a lot !
Pretty big question ! Thank you for reading and feel free to close if it's out of the scope.