Jump to content
Jonathan Lahijani

iBuildMacs Website (ecommerce site)

Recommended Posts

I recently created an ecommerce website, iBuildMacs, that I built with ProcessWire.  Given that there's been quite a bit activity on combining ecommerce with ProcessWire, I feel many people would be interested in the approach I took.

Feel free to visit it at:

http://ibuildmacs.com/

The requirements for this site were:

  • a computer configurator, much like the Apple website; example product page here
  • cart
  • checkout
  • payment methods: paypal or check/cash
  • shipping methods: the cost of shipping is based on a fixed cost that is related to the country being shipped.  no live quotes

The requirements did NOT include:

  • tax rules
  • inventory management
  • coupons, gift certificates
  • different product types: simple products, variable products, digital/downloadable products, etc.
  • user accounts, address management
  • a fancy ajax driven checkout

So, I had a bit of flexibility for this site given the specific feature set.  I then thought about how I wanted to develop the site.  The options I considered included:

  • WooCommerce: I've built several intricate websites with WooCommerce, the most recent being caviar.com.  It was good fit that website, but for iBuildMacs, which has less requirements and a very unique product configurator, which WooCommerce could do but with a tremendous amount of overrides and working backward, I decided this wouldn't but the right fit.  Plus, I'm trying to become as WordPress-free as possible.
  • FoxyCart: A ProcessWire favorite, however I wanted to challenge myself a little bit with this site, and also keep things under one roof.
  • Magento, Shopify, (insert some specific heavy or cloud-based ecommerce system you like): No.  Overkill and making a product configurator would be a pain.

After considering my options, I felt just rolling it entirely with ProcessWire and programming the catalog, payment methods, shipping methods and checkout tailored to the site's specific needs was the way to go.  This would definitely reduce the time and headache needed in bending anyone of the above systems I mentioned to behave exactly the way I wanted it to.

Products

This was one of the complicated parts of the website, but ProcessWire, with its infintely flexible custom fields, made this a breeze.  I have a product template (product.php).  It has some general fields like Title, Body, Image and Base Price.  It also has a PageTable field called Features.  These features are child pages of the product and use feature template (feature.php), so the Features PageTable field just grabs its data from there.

Then, the feature template has some general fields like Title, Body, Image and PageTable field called Feature Options.  These feature options are child pages of the feature template using the feature option template (feature_option.php).  So, what I ended up having is a 3 level deep structure, with two nested PageTable fields.

Here's a video of what it looks like, which is quite slick is very easy to manage:

https://vid.me/kjDW

Cart

When a user adds a configured product to their cart, it must be stored somehow and I thought of a variety of ways to do this.  Ultimately, I decided that cart data is handled as a page (using the order.php template) undernearth /orders/.

This order.php template has a page name that is based on the session id of the user, so it'll remain unique and not cause a conflict with other people's carts (as well as obscure from people trying to guess it's url, which is used for the order confirmation page).  One of the fields in this order.php template is called "products_ordered", which utilizes the Table fieldtype (a Profields table).

Video:

https://vid.me/MIRl

Checkout

The checkout is a straight forward form with the basic questions.  However, the shipping section is where it gets tricky.

The requirements for this site were that each computer has a fixed shipping price depending on the method being used to ship.  The shipping methods available to a customer are dependent on their country.

I think WooCommerce could manage rules like that, but directly coding it wasn't that difficult.  I create an array that stored the 2 payment methods, and another array that stored the 6 total shipping methods.  I also have an array for all the countries.

I then wrote some JavaScript that managed the relationships between the country chosen and the shipping methods available for the chosen country.  When choosing a method, it will update the Shipping cost line item on the car to the right.  Just basic JavaScript going on here.  All nice and on one page.

bF0CpcO.png

When the submit button is pressed, it will run through some logic and validate all the data and save it to the same page that stored the cart data.   An order confirmation email is sent to the customer, and one is also sent to the admin (SwiftMailer).

If Check/Cash was chosen, the user is then simply forwarded to the order confirmation page, which is at /orders/whatever-their-page-name-was-saved-as/.  The email they are sent also has a link referencing this page.

If PayPal was chosen, a URI is built and the user is taken to PayPal complete payment with PayPal Payments Standard using the Cart Upload command.  Documentation here.  After they complete Payment on PayPal, they are then taken to the order confirmation page as described previously.

Video:

https://vid.me/hwfB

I will eventually be using ListerPro for a nicer admin orders list display and build a few custom actions to allow administrators to quickly send general emails from the system (like, when the order is shipped).

Modules Used

Enjoy!

  • Like 23

Share this post


Link to post
Share on other sites

it could be good to make a installation profile for others for learning

+1 for this idea...

On topic:

Very nice job!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By louisstephens
      So I ran into a very strange issue today. I have a template with a pagetable and I went to add an item to it, when I went to select an image (for an image field) the page instantly threw up an error
      "ProcessPageSearchLive: No search specified"
      The page's content also switched to the image attached. This all worked perfectly last week (local mamp box). Has anyone experienced this before, and how did you solve it?
       

    • By jploch
      Hey folks,
      I have a question regarding rendering of template files that are in a subfolder of the template folder.
      How would I for example render these PageTable items, when their template files are inside templates/blocks/:
      <div class="grid"> <?php foreach($page->grid_ext as $item): ?> <div id="pteg_<?= $item->id ?>"> <?php echo $item->render(); ?> </div> <?php endforeach; ?> </div> I tried this, but get an error:
      <?php echo $item->render(wire('config')->paths->templates . '/blocks/'); ?>  
    • By Jeannette
      Hello Fellows,

      I have a wonderful webshop, using PL and Padopt, a module developed by Julien Vaubourg and highlighted in ProcessWire Newsletter. Here is our shop: cheval-ami.fr
      I am looking for a new developer, helping me to keep the shop smooth and up to date.
      We would like to improve automated invoicing and worldwide shipping, getting DHL integrated and give people the possibility to create their personal accounts and be the nicest shop in the equine industry. We are still a young company, working all in german, english and french. We are very interested in a long time, kind and friendly relationship without any stress, but reliable reactivity in case of urgency. 
      We are based in Hamburg and near Paris and would prefere to work with somebody who is available to catch up around a table, at least sometimes.
      Contact: mail@cheval-ami.fr or +33 626 22 1000 or +49 170 20 28 215
      Thank you, Have a beautiful day,
      Jeannette
    • By ngrmm
      I have a page with a table. Each table row has a page-reference field and a checkbox.
      The Page sends emails to all users (page-refrence->email-field) and change the value of the checkbox in a row to 1.
      It works with this:
      <?php // event ID fron url query $eventID = $input->get('eventID','int'); // get event-page $event = $pages->get($eventID); // config $fromEmail = $event->event_mail_from; $fromName = $event->event_mail_from_name; $emailSubject = $event->event_subject; // email html body ob_start(); include('./_inc/emailbody.inc'); $emailBody = ob_get_clean(); // make event-page editable $event->of(false); // loop through table and send out emails foreach($event->event_clients_list as $event_table_row) { // get client page $clientPage = $event_table_row->client_name; // get client email $clientEmail = $clientPage->email; // if client isn't invited yet (checkbox not checked) if($event_table_row->client_invited == '') { // send email $m = new WireMail(); $m->to($clientEmail); $m->from($fromEmail, $fromName); $m->subject($emailSubject); $m->bodyHTML($emailBody); $m->send(); // mark client as invited $event_table_row->client_invited = 1; $event->save('event_clients_list'); } } ?> But i have to use a variable in my emailbody.inc which i'm able to get in the table-loop.
      So i do the including of the body inside my loop. But this doesn't work anymore. Page sends out the emails but is unable to change the value of the checkbox.
      I get no errors!
      I'm using ProTable
      <?php // event ID fron url query $eventID = $input->get('eventID','int'); // get event-page $event = $pages->get($eventID); // config $fromEmail = $event->event_mail_from; $fromName = $event->event_mail_from_name; $emailSubject = $event->event_subject; // loop through table and send out emails foreach($event->event_clients_list as $event_table_row) { // get client page $clientPage = $event_table_row->client_name; // get client email $clientEmail = $clientPage->email; // email html body ob_start(); include('./_inc/emailbody.inc'); $emailBody = ob_get_clean(); // make event-page editable $event->of(false); // if client isn't invited yet (checkbox not checked) if($event_table_row->client_invited == '') { // send email $m = new WireMail(); $m->to($clientEmail); $m->from($fromEmail, $fromName); $m->subject($emailSubject); $m->bodyHTML($emailBody); $m->send(); // mark client as invited $event_table_row->client_invited = 1; $event->save('event_clients_list'); } } ?>  
    • By maba
      Hello,
      I need to import regularly - every 15 or 30 days - a big .xslx file into my PW installation.
      This file now has 14 columns, 5.000 rows and grows every month.
      I'll need to group, order and work with these data to:
      analyse User monthly costs analyse User costs per Asset ... User (real AD account) has to match with a PW user - I can't join to the domain - but as you can see I have some services users (start with sca_*) or no user at all. Those rows have to be assigned to a specific user, e.g. account100.
      And:
      I would like to be able to have a kind of diff function to compare User assets between this and last month (and so on) other request is to have a notification when something change for a User between actual and latest import First request: which is the best solution to store those data in your opinion? Page, Table, Repeater Matrix, ...?
      Those are very repetitive data and I think a page reference is better than to import all the data every time but I have to understand how to manage those "dynamic" groups of software (AccType Det), hardware (Asset), ... For example Price will be imported and not stored with the description because it could be change in the future and I'll not have any control on it.
      Thanks!
      User,OE,productNmr,AccType1,AccType Det,Count,Price (€),Sum,ASNA,CC,AccType Info,Asset,AccGroup,,,,,,,,,,,,,
×
×
  • Create New...