Manually Sorting Commerce Products
Craft Commerce adds powerful products elements that don’t natively support manual drag-and-drop sorting like Craft’s structure entries or categories.
You can, however, create a custom field that allows store managers to hand sort products.
Add a Commerce Products field to a Global Set #
1. Create a Commerce Products field. #
Navigate to Settings → Fields and press New field to create a new field, selecting Commerce Products for its Field Type.
The name, handle, and sources can be whatever you’d like, just remember the handle—orderedProducts
here—because we’ll need it again in a moment.
When you’re finished, press Save.
2. Add your field to a Global Set. #
Next, we’ll add our newly-created field to a Global Set. You can add the field to an existing Global Set if you’d like, but we’ll create a new one called “Store Customization”.
Navigate to Settings → Globals and press New global set, choosing a name and handle and dragging the field from step #1 into the Field Layout for the Global Set.
Press Save.
Now you can navigate to Globals and see this new field in the Global Set we just created.
Press Add a product and select all of your products to that field.
You can then drag the products into whatever order you’d like and press Save.
3. Use your field in templates. #
Anywhere you’d like to use this custom sort on the front end, replace craft.products()
queries with your custom Global Set handle and field handle:
{# Fetch products from our custom field #}
{% set products = storeCustomization.orderedProducts.all() %}
<ol>
{% for product in products %}
<li><a href="{{ product.url }}">{{ product.title }}</a></li>
{% endfor %}
</ol>
Once you’ve fetched the products from this custom field, they’ll be returned in exactly the order that’s set in the control panel.
Automatically Add New Products #
If we stopped here, store managers would still need to update this field to add each newly-created product.
We can use a custom module to listen for new Commerce products and append them to that field automatically.
See Using Events in a Custom Module for an example of setting up a custom module for the first time.
In your module’s init()
method, add the following code to listen for Product::EVENT_AFTER_SAVE
and update the Global Set field with a newly-saved product:
use craft\commerce\elements\Product;
use craft\events\ModelEvent;
use yii\base\Event;
use Craft;
Event::on(
Product::class,
Product::EVENT_AFTER_SAVE,
static function(ModelEvent $event) {
$globalSet = Craft::$app
->getGlobals()
->getSetByHandle('storeCustomization');
// Make sure our Global Set exists and we have a new product
if ($globalSet && $event->isNew) {
// Get “Ordered Products” field’s existing product IDs
$productIds = $globalSet->orderedProducts->ids();
// Append the new product ID
$productIds[] = $event->sender->id;
// Set “Ordered Products” field value
$globalSet->setFieldValue('orderedProducts', $productIds);
// Save “Ordered Products” field with its updated values
Craft::$app->getElements()->saveElement($globalSet);
}
}
);
Navigate to Commerce → Products and press New product. Enter required fields and press Save.
That new product should now be added to the product list under Globals → Store Customization → Ordered Products, ready to be sorted into whatever position you’d prefer.
Deleted products will automatically be removed from the custom field.