“I’m sick & tired of all the PHP hate. You can write sh*tty code in any language.”
That’s our only PHP defender in the team, ranting.
“Most times, problem’s the programmer, not the programming language.”
Him again — mostly right.
“Ever tried building something with Laravel? Awesome framework & community.”
PHP’s made gigantic leaps since my early programming days. And I haven’t taken the time to jump back into its modern environment (been busy dabbling in Vue.js refactoring & prototyping).
So today, that’s exactly what I’m going to do.
How? By creating a Laravel e-commerce site.
I’ll use Laravel-powered PyroCMS & Snipcart to help me do just that.
It just so happens that I made a huge batch of spaghetti sauce this weekend. I’ll never be able to eat all of it, so why not sell the surplus online!
In this tutorial, I’ll show you:
Let’s see if my rusty PHP skills can outshine my cooking skills.
For those who didn’t know already: Laravel is an open source PHP web framework used to build sites & web apps.
It has a smooth learning curve, removes some quirks of building with PHP, has many modern built-in libraries. Some say it’s the Ruby on Rails PHP equivalent.
Want to familiarize yourself with Laravel before starting this tuts? Check out this post — shows you how to build a simple MVC app < 10 min.
With Laravel, you can leverage Composer to manage dependencies & packages. Many useful packages will allow you to fast-track your Laravel app or site development. Think stuff like debugging, authentication, API interactions, etc. Sites like Packagist & Packalyst are great resources to find helpful Laravel packages.
And of course, there are e-commerce packages for Laravel. Popular ones like Mage2 and Aimeos can help set up e-commerce functionalities on your Laravel app.
So your e-commerce options with Laravel are pretty much:
First one? Time-consuming. I could’ve done a whole e-commerce app in Laravel. But I didn’t have time to code everything from scratch — I needed an MVP to test the spaghetti sauce market ASAP!
Second one? Actually interesting. We might do it in another post!
Third one? This is what we’re doing here. It’ll fast-track our development with useful shortcuts (PyroCMS scaffolding the site; Snipcart abstracting e-comm. logic & backend).
I’m really glad to be operating inside a Laravel project for this demo. Unlike many of our JAMstack/static site tuts, it’ll be easy to handle any backend logic for our store.
Editor’s note: if you’re building a simple subscription business with Laravel, check out Laravel Cashier, or our own subscription feature.
My previous experience with a PHP CMS wasn’t that great. However, I’d heard good stuff about Pyro here and there. And since I needed a Laravel-powered tool for this tuts, picking it was a no-brainer.
PyroCMS is a PHP CMS built specifically for Laravel. It’s open source under the MIT license and comes equipped with a bunch of useful features.
In the spirit of transparency, here are other Laravel-based CMS to consider:
For this tutorial, you’ll need:
Start by scaffolding a PyroCMS project with Composer.
composer create-project pyrocms/pyrocms pyro_demo
Set the root folder of your webserver to the project’s public
folder. Make sure it can write to public/app
, bootstrap/cache
and storage
folders. Those familiar with Laravel you'll recognize the directory structure. If you're new to PyroCMS, prepare to be impressed by how fast it is to have something up and running.
Visit your website and use the built-in installer to configure Pyro with your site info and database settings.
You can now remove the anomaly/installer-module
dependency from composer.json
, then run composer update
.
Although we have a Laravel project to play with, PyroCMS suggests slicing new functionalities into addons. For a big project, making a few addons for non-related features would be a good idea. Here, we’ll create a products module using the artisan command:
php artisan make:addon snipcart.module.products
That will generate the folder addons/{your site slug}/snipcart/products-module
. Most of the path from now on will be relative to this folder.
At the core of Pyro is a concept of stream — essentially a collection of content. Our addon defines a products
stream that we scaffold with artisan:
php artisan make:stream products snipcart.module.products
Those commands have generated some new elements. Let’s first look at the migrations
folder in our addon, where we only need to add a few things to have a complete product management backend.
Go ahead and define the fields of a product inside {date}_snipcart.module.products__create_products_fields.php
. They are defined using the built-in field types of Pyro.
Our products will have a SKU, name, price, description, image and tags:
We must also add them to the $assignments
parameter inside {date}_snipcart.module.products__create_products_stream.php
so they show up in our admin form.
We can type php artisan addon:install products
in the console to install the addon. That's enough to be able to add/edit products in the CMS admin!
Should you make changes to the migrations later on, you can refresh them using
_php artisan migrate:refresh --addon=products_
.
But there’s a lot more we can do to improve the editing experience.
Let’s add the product image in the product listing. Edit $columns
in src/Product/Table/ProductTableBuilder.php
:
We can show the stored value of the field by using its name, or format it by using valuation. The latter evaluates the string and allows us to call presenter methods for our fields’ values (here: currency
to show a dollar sign and preview
to show a resized image).
Looking good!
We’ll add a view using Twig’s templating engine, then wire it with a controller and route. Create the product view that uses the default layout with a few Bootstrap classes in resources/views/products/index.twig
:
Followed by a really simple controller in src/Http/Controller/ProductsController.php
:
For the route, add the products
route into src/ProductsModuleServiceProvider.php
to the ones generated for the admin:
There we go! Looks nice if we visit /products
:
We also need a link to this page. Override the navigation template by creating the file {project root}/resources/{site slug}/addons/pyrocms/starter-theme/views/partials/navigation.twig
:
Here we copied the original template and simply added:
Just a few more steps to transform those buy buttons into properly defined Snipcart products.
First we need somewhere to store our API Key. Add a setting entry for the module by creating the file resources/config/setting.php
:
This setting is accessible in the admin under Settings Module > Modules > Products Module.
We’re ready to override the scripts
template in {project root}/resources/{site slug}/addons/pyrocms/starter-theme/views/partials/scripts.twig
to add Snipcart's required files:
To inject Snipcart’s item attributes to buy buttons, modify ProductPresenter
to add a buyButton
method inside src/Product/ProductPresenter.php
:
There’s a lot going on in this file (especially if you’re new to Pyro):
HtmlBuilder
through dependency injection in the Presenter's constructor$this->object
FilesModule
<a ...>
) elementWe can now update our product view in resources/views/products/index.twig
to call the presenter:
{{ product.buyButton('Buy for '~product.price.currency(), {'class': 'btn btn-primary'})|raw }}
Aaaand my delicious spaghetti sauce is now buyable!
Selling food online — or anything else for that matter — often comes with various challenges. Frozen stuff can’t be shipped over long distances, for instance. Extra spicy stuff must come with a warning. And so on.
So first let’s add a few dummy checks by using our new custom validation feature. We’ll prevent customers from ordering products too spicy for them:
That code filters for validation events on the cart-content
page and adds an error to products with a spicy
tag. It goes into resources/js/validation.js
and we add another line to scripts.twig
: {{ asset_add("scripts.js", "snipcart.module.products::js/validation.js") }}
.
On to Frozen stuff checks and Laravel land now
The ProductsController we made earlier actually extends a Laravel controller with a few goodies from PyroCMS added. When you look at the sources of BaseController
from PyroCMS, you'll see all the stuff from the Illuminate
namespace wired to the controller. Now let's create a simple shipping webhook by extending the base Laravel controller directly and adding only the stuff we need.
Create this controller in src/Http/Controller/ShippingController.php
:
So ShippingController
only uses classes from Illuminate
. It's a plain old Laravel controller that checks Snipcart's input data and determines if we must return an error message or a shipping rate. Like for the ProductsController
, we add a route inside our module's service provider: 'webhooks/shipping' => 'Snipcart\ProductsModule\Http\Controller\ShippingController@webhook',
.
And we’re done!
We covered lots of stuff here. But it should give you a broad overview of how to integrate Snipcart with PyroCMS + use more regular features of Laravel.
The project and the admin interface were running in less than 3 hours, without any prior experience with Pyro on my end. The whole tuts ended up taking two days. Mostly because I really wanted to integrate Snipcart by injecting our scripts tags from the module instead of having to edit theme templates.
I had a blast building the admin for this tuts. I don’t think that process can be made easier, so kudos to Pyro!
Not knowing Laravel much, it was a bit hard for me to differentiate where PyroCMS ends and Laravel begins. You have to get familiar with PyroCMS’ source code to picture ways of how to accomplish things that aren’t easy to understand from only looking at the documentation.
If I had more time to spend on this demo, I’d explore the many content management features of the admin. Lots can be accomplished directly from the admin without much code. A cool test would be to assign products to specifically tagged blog posts!
Originally published this post on the Snipcart blog and in our newsletter.