Simple Commerce v3.0 comes with a bunch of new features, including some big quality of life improvements, for both developers and back-office users. In addition, there's a number of breaking changes, especially if you're doing custom 'things' with Simple Commerce.
To get started with the upgrade process, follow the below steps:
1. In your composer.json
file, update the doublethreedigital/simple-commerce
version constraint:
"doublethreedigital/simple-commerce": "3.0.*"
"doublethreedigital/simple-commerce": "3.0.*"
2. Then run:
composer update doublethreedigital/simple-commerce --with-dependencies
composer update doublethreedigital/simple-commerce --with-dependencies
3. You may also want to clear your route & view caches:
php artisan route:clearphp artisan view:clear
php artisan route:clearphp artisan view:clear
4. Simple Commerce will have attempted upgrading some things for you (config changes, blueprint updates, etc). However, it's highly likely you will need to make some manual changes, along with some testing. Please test before you push to production!
Internally, a lot has changed in terms of how things are structured, how you access data, etc. If you've written any kind of custom code at all, you'll need to make some manual code changes.
I've noted all of the changes below - however, this isn't by far everything - you may review the related PR for more information.
SC v3 changes the way 'content drivers' work. Instead of the driver being the Order/Customer class itself, it's a repository (which is inline with how Statamic does it). Essentially, if you need to use a database or third-party to store your data, you'd create a repository which implements the required methods, instead of creating an entire Order/Customer class - hopefully that explanation makes sense.
During the upgrade process, Simple Commerce should have updated your config to represent this change:
'content' => ['coupons' => ['repository' => \DuncanMcClean\SimpleCommerce\Coupons\EntryCouponRepository::class,'collection' => 'coupons',],'customers' => ['repository' => \DuncanMcClean\SimpleCommerce\Customers\EntryCustomerRepository::class,'collection' => 'customers',],'orders' => ['repository' => \DuncanMcClean\SimpleCommerce\Orders\EntryOrderRepository::class,'collection' => 'orders',],'products' => ['repository' => \DuncanMcClean\SimpleCommerce\Products\EntryProductRepository::class,'collection' => 'products',],],
'content' => ['coupons' => ['repository' => \DuncanMcClean\SimpleCommerce\Coupons\EntryCouponRepository::class,'collection' => 'coupons',],'customers' => ['repository' => \DuncanMcClean\SimpleCommerce\Customers\EntryCustomerRepository::class,'collection' => 'customers',],'orders' => ['repository' => \DuncanMcClean\SimpleCommerce\Orders\EntryOrderRepository::class,'collection' => 'orders',],'products' => ['repository' => \DuncanMcClean\SimpleCommerce\Products\EntryProductRepository::class,'collection' => 'products',],],
During the upgrade, SC will reset the 'repositories' to the new defaults. If you were using another content driver, you must re-configure this post-update.
If you were implementing a custom 'content driver' previously for something, you will need to review the changes and refactor your implementation. If it helps, here's a link to view the 'interfaces' behind SC's Data stuff.
Along with content drivers working differently - how you access/save data will have also changed:
Creating Products/Customers/Orders/Coupons
Previously:
$order = Order::create(['items' => [['product' => 'abc','quantity' => 1,'total' => 1255,],],'items_total' => 1255,'gift_note' => 'This is a very special note.',]);
$order = Order::create(['items' => [['product' => 'abc','quantity' => 1,'total' => 1255,],],'items_total' => 1255,'gift_note' => 'This is a very special note.',]);
Now:
$order = Order::make()->lineItems([['product' => 'abc','quantity' => 1,'total' => 1255,],])->itemsTotal(1255)->data(['gift_note' => 'This is a very special note.',]);$order->save();
$order = Order::make()->lineItems([['product' => 'abc','quantity' => 1,'total' => 1255,],])->itemsTotal(1255)->data(['gift_note' => 'This is a very special note.',]);$order->save();
A lot of 'things' on Data Models are now properties which can be modified using fluent getter/setters. Anything outside of a property can be set using ->data()
, ->set()
or ->merge()
. We're now using the same pattern for making/saving as Statamic itself.
Getting the 'grand total' from an order
Previously:
$order = Order::find('123');$order->get('grand_total');
$order = Order::find('123');$order->get('grand_total');
Now:
$order = Order::find('123');$order->grandTotal();
$order = Order::find('123');$order->grandTotal();
Getting the original entry
Previously:
$order = Order::find('123');$order->entry();
$order = Order::find('123');$order->entry();
Now:
$order = Order::find('123');$order->resource();
$order = Order::find('123');$order->resource();
When accessing Line Items, you'll no longer receive an array, you'll now receive an instance of the LineItem
class.
Previously:
$lineItem = $order->lineItems()->first();$product = Product::find($lineItem['product']);$quantity = $lineItem['quantity'];$giftNote = $lineItem['metadata']['gift_note'];
$lineItem = $order->lineItems()->first();$product = Product::find($lineItem['product']);$quantity = $lineItem['quantity'];$giftNote = $lineItem['metadata']['gift_note'];
Now:
$lineItem = $order->lineItems()->first();$product = $lineItem->product();$quantity = $lineItem->quantity();$giftNote = $lineItem->metdata()->get('gift_note');
$lineItem = $order->lineItems()->first();$product = $lineItem->product();$quantity = $lineItem->quantity();$giftNote = $lineItem->metdata()->get('gift_note');
If you were previously referencing any of these classes, you should update your references to their new namespaces:
DuncanMcClean\SimpleCommerce\Support\Currency
-> DuncanMcClean\SimpleCommerce\Currency
DuncanMcClean\SimpleCommerce\Support\Country
-> DuncanMcClean\SimpleCommerce\Country
DuncanMcClean\SimpleCommerce\Support\Regions
-> DuncanMcClean\SimpleCommerce\Regions
You should also note that any references to the Currency/Country/Region facades should now be updated to these new namespaces. The usage remains the same.
To improve the security of your site, we've introduced a 'whitelist' for the fields that will be saved from Simple Commerce's front-end forms.
Previously, Simple Commerce would save anything provided in a request (for example: on the request to add a product to the cart) to your order entry.
Now, Simple Commerce will only save the request data from the fields you've whitelisted in the Simple Commerce config.
// config/simple-commerce.php/*|--------------------------------------------------------------------------| Field Whitelist|--------------------------------------------------------------------------|| You may configure the fields you wish to be editable via front-end forms| below. Wildcards are not accepted due to security concerns.|| https://simple-commerce.duncanmcclean.com/tags#field-whitelisting|*/'field_whitelist' => ['orders' => ['shipping_name', 'shipping_address', 'shipping_address_line1', 'shipping_address_line2', 'shipping_city','shipping_region', 'shipping_postal_code', 'shipping_country', 'shipping_note', 'shipping_method','use_shipping_address_for_billing', 'billing_name', 'billing_address', 'billing_address_line2','billing_city', 'billing_region', 'billing_postal_code', 'billing_country',],'line_items' => [],'customers' => ['name', 'email'],],
// config/simple-commerce.php/*|--------------------------------------------------------------------------| Field Whitelist|--------------------------------------------------------------------------|| You may configure the fields you wish to be editable via front-end forms| below. Wildcards are not accepted due to security concerns.|| https://simple-commerce.duncanmcclean.com/tags#field-whitelisting|*/'field_whitelist' => ['orders' => ['shipping_name', 'shipping_address', 'shipping_address_line1', 'shipping_address_line2', 'shipping_city','shipping_region', 'shipping_postal_code', 'shipping_country', 'shipping_note', 'shipping_method','use_shipping_address_for_billing', 'billing_name', 'billing_address', 'billing_address_line2','billing_city', 'billing_region', 'billing_postal_code', 'billing_country',],'line_items' => [],'customers' => ['name', 'email'],],
This step should be partially automated during the upgrade process. After upgrading, you should see the field_whitelist
array appear in your simple-commerce.php
config file. Simple Commerce will have pulled any fields from your order blueprint that aren't 'reserved' (eg. fields like is_paid
, they're ones you probably don't want users to be able to fill).
Simple Commerce now allows for passing configuration arrays for shipping methods. However, for this to work, shipping methods must be updated to extend upon the BaseShippingMethod
class provided by Simple Commerce.
<?phpnamespace App\ShippingMethods;use DuncanMcClean\SimpleCommerce\Contracts\ShippingMethod;use DuncanMcClean\SimpleCommerce\Shipping\BaseShippingMethod;class FirstClass extends BaseShippingMethod implements ShippingMethod{//}
<?phpnamespace App\ShippingMethods;use DuncanMcClean\SimpleCommerce\Contracts\ShippingMethod;use DuncanMcClean\SimpleCommerce\Shipping\BaseShippingMethod;class FirstClass extends BaseShippingMethod implements ShippingMethod{//}
If you wish to start passing in config variables to your shipping methods, you may do it like so:
'sites' => ['default' => [...'shipping' => ['methods' => [\DuncanMcClean\SimpleCommerce\Shipping\StandardPost::class => ['config' => 'setting','foo' => 'bar',],],],],],
'sites' => ['default' => [...'shipping' => ['methods' => [\DuncanMcClean\SimpleCommerce\Shipping\StandardPost::class => ['config' => 'setting','foo' => 'bar',],],],],],
And inside the shipping method, you may do $this->config()->get('key')
to get a specific config value.
Previously, Simple Commerce would send a fairly basic email with a PDF receipt attached.
In v3, the receipt PDF has been removed from order emails. Instead, email body's contain a table with the order line items, along with any customer information which is displayed below.
If you wish to continue using the previous behaviour (where you get a simple email, along with a PDF receipt), follow these steps:
app/Notifications
folder. Keep the same filename.App
one:
<?phpnamespace DuncanMcClean\SimpleCommerce\Notifications;namespace App\Notifications;use Barryvdh\DomPDF\Facade as PDF;use DuncanMcClean\SimpleCommerce\Contracts\Order;use Illuminate\Bus\Queueable;use Illuminate\Notifications\Messages\MailMessage;use Illuminate\Notifications\Notification;class CustomerOrderPaid extends Notification{
<?phpnamespace DuncanMcClean\SimpleCommerce\Notifications;namespace App\Notifications;use Barryvdh\DomPDF\Facade as PDF;use DuncanMcClean\SimpleCommerce\Contracts\Order;use Illuminate\Bus\Queueable;use Illuminate\Notifications\Messages\MailMessage;use Illuminate\Notifications\Notification;class CustomerOrderPaid extends Notification{
composer require dompdf/dompdf
composer require dompdf/dompdf
// config/simple-commerce.php'notifications' => ['order_paid' => [\DuncanMcClean\SimpleCommerce\Notifications\CustomerOrderPaid::class => [\App\Notifications\CustomerOrderPaid::class => ['to' => 'customer',],],// ...],
// config/simple-commerce.php'notifications' => ['order_paid' => [\DuncanMcClean\SimpleCommerce\Notifications\CustomerOrderPaid::class => [\App\Notifications\CustomerOrderPaid::class => ['to' => 'customer',],],// ...],
Although not technically a breaking change, it's worth noting as it may help to cleaup your code.
On the 'Order Confirmation' page (the one after checking out), you'd previously have to use the {{ session:cart }}
tag in order to access the previous cart. However, now you may use Simple Commerce's cart tags like normal.
Previously:
{{ session:cart }}Thanks for your order ({{ title }}), {{ customer:title }}{{ /session:cart }}
{{ session:cart }}Thanks for your order ({{ title }}), {{ customer:title }}{{ /session:cart }}
Now:
{{ sc:cart }}Thanks for your order ({{ title }}), {{ customer:title }}{{ /sc:cart }}
{{ sc:cart }}Thanks for your order ({{ title }}), {{ customer:title }}{{ /sc:cart }}
Simple Commerce v3.0 drops the Sales Widget which could optionally be added to your Control Panel Dashboard. It's now recommended to take advantage of the Overview page for this same (and more) functionality.
During the upgrade process, Simple Commerce should have added two new fields to your Order blueprint. A Gateway field and a Shipping Method field. These fields should hopefully be useful for your CP users to be able to see the gateway/shipping method that's being used for an order.
The fields will automatically be pushed into the Sidebar of the Order blueprint, you may move it as you wish.
When using the Stripe Gateway, past orders will show 'Unknown' as the payment ID. Future orders will show the payment ID as expected - this is due to some data which was missing prior to v3.
Simple Commerce v3 requires you to be using PHP 8.0 (and above), along with Laravel 8 (and above) and Statamic 3.3. Adjusting the system requirements encourages developers to stay up to date and means Simple Commerce can take advantage of new features.
In the past, order numbers would be stored as part of the title on Order entries.
However, SC v3 has taken advantage of a Statamic feature called 'title formats'. This means we store the order number in it's own field, order_number
(hidden field, added during upgrade).
Then, Simple Commerce will configure the title format to be like so: #xxxx
.
Like I say, quite a lot has changed between v2.4 and v3.0 so if you're running into issues upgrading, please either open a GitHub Issue or send me an email. I'll try and help as best I can.