I am able to inspect my cart using commerce_orders.onOrderComplete.

Next I loop through each line item & check for a specific product type. I need to be able to get the specific product, as there are attributes (values) within that product that I am saving to my plugin's records.

For example, if a user purchases "My Product", "My Product" has attributes that include things like "Follow-Up Meetings Qty" Where the admin is allowed to choose the number of meetings are included with "My Product".

Here is what I have that is close, I am stumbling getting the correct criteria model back. I know I'm not working with an entry, so I need to use the purchasable element type.

craft()->on('commerce_orders.onOrderComplete', function (Event $event) {
    user = $event->params['order']->getCustomer()->getUser();
    $orderNumber = $event->params['order']->number;

    foreach ($event->params['order']->lineItems as $item) {
        if ($item->snapshot['product']['typeId'] == 123) {
             $productId = $item->snapshot['id'];

            // Get order details.
            switch ($productId) {
                case 456:
                    error_log('---- My Product Was Purchased ----');
                    error_log('user id: ' . $user->id);
                    error_log('order number: ' . $orderNumber);
                    error_log('product id: ' . $productId);

                    // Get the specific product that was purchased.
                    $criteria = craft()->commerce_purchasables->getCriteria(ElementType::Purchasable);
                    $criteria->limit = 1;


                    $products = $criteria->find();

                    if ($products) {
                        foreach ($products as $product) {
                          // Access the products' attributes
                          // $product->meetings_qty  (3)
                          // $product->foo_qty  (2)
                          // $product->bar_qty


                          // Save the values to my plugin record.
                    } else {
                        error_log('no products found that match criteria!');


Thank you for any suggestions!


Thank you Brad!

Here is what the solution looks like after I removed the over-complication "stuff". Hope this helps anyone who comes across this thread.

craft()->on('commerce_orders.onOrderComplete', function (Event $event) {
        $user = $event->params['order']->getCustomer()->getUser();
        $orderNumber = $event->params['order']->number;

        foreach ($event->params['order']->lineItems as $item) {
            error_log('User id: ' . $user->id);
            error_log('Order number: ' . $orderNumber);
            error_log('Product title: ' . $item->purchasable->title);
            error_log('Product id: ' . $item->purchasable->id);
            error_log('Meetings qty: ' . $item->purchasable->product->myFieldHandle);

            do some other stuff...
            Save the record.

1 Answer 1


I think you have direct access to the purchasable already via a simple


E.g. I do things like this

foreach ($event->params['order']->lineItems as $item) {

You should really just be able to access the fields directly on the purchasable via


So I don't think you need to use the snapshot side of things at all as long as you're doing this at this stage anyway - the snapshot is something you use if you're dealing with an order when the product data may have since changed etc. as I understand it.

  • Who would have thought. Me over-complicating things...again. Thanks Brad!
    – Damon
    Commented May 2, 2016 at 1:11
  • 2
    Look at that he fixes a typo and gets all the credit ;) Commented May 2, 2016 at 1:18
  • 1
    lol - that one is all @JeremyDaalder!
    – Brad Bell
    Commented May 2, 2016 at 3:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.