How can I get a specific product via plugin? I am able to inspect my cart using commerce_orders.onOrderComplete.

Next I loop through each line item &amp; 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()-&gt;on('commerce_orders.onOrderComplete', function (Event $event) {
    user = $event-&gt;params['order']-&gt;getCustomer()-&gt;getUser();
    $orderNumber = $event-&gt;params['order']-&gt;number;

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

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

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

                    ...

                    $products = $criteria-&gt;find();

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

                          ...

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

                break;
                ...
            }
        }
    }
});


Thank you for any suggestions!

EDIT

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()-&gt;on('commerce_orders.onOrderComplete', function (Event $event) {
        $user = $event-&gt;params['order']-&gt;getCustomer()-&gt;getUser();
        $orderNumber = $event-&gt;params['order']-&gt;number;

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

            ...
            do some other stuff...
            ...
            Save the record.
        }
});
I think you have direct access to the purchasable already via a simple

$lineItem-&gt;purchasable

E.g. I do things like this

foreach ($event-&gt;params['order']-&gt;lineItems as $item) {
    BusinessLogicPlugin::log($item-&gt;purchasable-&gt;title);
}


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

$lineItem-&gt;purchasable-&gt;field

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.