Update any index in CodeIgniter Cart class

If you use the Cart class that was introduced in CodeIgniter 1.7.2 very often, you’ll notice that it has some shortcomings. In particular, the update() method will only update the quantity of the item in the cart; it will not update other indexes.

This is troublesome because sometimes you may want to update the price, for example, if the quantity goes above a certain threshold. Suppose you want to give a 10% discount on an item to anyone who orders 10 or more of that item. As it stands, you would have to remove the item from the cart, calculate the discount for the item, and re-add the item with a different price. I have also ran into the problem when I added a flag index to items in the cart to which I needed to do additional processing during checking depending on its status. I’ve found in both cases that the better solution is to extend the cart class. Here is how we can do it.

class MY_Cart extends CI_Cart
{
    function __construct()
    {
        parent::CI_Cart();
    }

    function update_all($items = array())
    {
        // Was any cart data passed?
        if ( ! is_array($items) OR count($items) == 0)
        {
            return false;
        }

        // You can either update a single product using a one-dimensional array,
        // or multiple products using a multi-dimensional one.  The way we
        // determine the array type is by looking for a required array key named "rowid".
        // If it's not found we assume it's a multi-dimensional array
        if (isset($items['rowid']))
        {
            $this->_update_item($items);
        }
        else
        {
            foreach($items as $item)
            {
                $this->_update_item($item);
            }
        }

        $this->_save_cart();
    }

    /*
     * Function: _update_item
     * Param: Array with a rowid and information about the item to be updated
     *             such as qty, name, price, custom fields.
     */
    function _update_item($item)
    {
        foreach($item as $key => $value)
        {
            //don't allow them to change the rowid
            if($key == 'rowid')
            {
                continue;
            }

            //do some processing if qty is
            //updated since it has strict requirements
            if($key == "qty")
            {
                // Prep the quantity
                $item['qty'] = preg_replace('/([^0-9])/i', '', $item['qty']);

                // Is the quantity a number?
                if ( ! is_numeric($item['qty']))
                {
                    continue;
                }

                // Is the new quantity different than what is already saved in the cart?
                // If it's the same there's nothing to do
                if ($this->_cart_contents[$item['rowid']]['qty'] == $item['qty'])
                {
                    continue;
                }

                // Is the quantity zero?  If so we will remove the item from the cart.
                // If the quantity is greater than zero we are updating
                if ($item['qty'] == 0)
                {
                    unset($this->_cart_contents[$item['rowid']]);
                    continue;
                }
            }

            $this->_cart_contents[$item['rowid']][$key] = $value;
        }
    }
}

Copy and paste the previous code into a file named MY_Cart.php and place it in the library folder in your application folder. To use the extension to the cart class is as easy as using the normal update method from the cart class. You can pass an array to update one item, or you may pass a multi-dimensional array to update multiple items.

$data = array(
    'rowid' => 'rowid_from_post',
    'qty' => 10,
    'name' => 'hello'
);

$this->cart->update_all($data);

OR

$data = array(
    array(
        'rowid' => 'rowid_from_post',
        'name' => 'world'
    ),
    array(
        'rowid' => 'rowid_from_post',
        'price' => 25.50
    )
);

$this->cart->update_all($data);

Limitations

There is one thing I forgot to mention. When updating an item or items, this extension will not work with the ‘options’ index or any user-defined index that is an array. If you need to edit the options array index in-cart, then you’ll have to think of another solution.

I plan on adding features to this cart extension, and if it gets robust enough, I will re-write the extension into the cart itself. You can follow my progress, as well as contribute to the extension, by following me and the project on BitBucket.

In the mean time, feel free to offer suggestions or comments! I look forward to hearing from you.

  1. 1 product in your shopping cart, the number 2 quantity. When we add the same product then we get 1 instead of 3. How to upgrade the cart?

  2. Sanyame, how are you adding the same product to the cart? Whatever you pass in the array to update_all will be updated on the item in question? If the item exists in the cart and you pass qty = 1 in the array, the item will be updated to quantity 1. You need logic in your code to either set the quantity to the new total (2 + 1 = 3) or you could also just omit the qty property in the array.

    If you need more information or have questions, you can post your code here or contact me directly through the contact form.

  3. Hi, I solved the problem so
    function add_to_cart()
    {

    $cart_now = $this->cart->contents();

    if(empty($cart_now))
    {

    $data = array(
    ‘id’ => $this->input->post(‘product_id’),
    ‘qty’ => $this->input->post(‘qty’),
    ‘price’ => $this->input->post(‘product_price’),
    ‘name’ => $this->input->post(‘product_name’),
    ‘options’ => array()
    );

    }
    else
    {

    $i=0;
    $cart_rowid = $this->input->post(‘product_id’);

    foreach($cart_now as $el)
    {

    $arr[$i] = $el[“id”];

    if($cart_rowid == $arr[$i])
    {
    $cart_qty=$el[‘qty’];
    }
    else
    {
    $cart_qty=0;
    }
    $i++;
    }
    //print_r($arr);
    //echo $cart_qty;

    $data = array(
    ‘id’ => $this->input->post(‘product_id’),
    ‘qty’ => $this->input->post(‘qty’)+$cart_qty,
    ‘price’ => $this->input->post(‘product_price’),
    ‘name’ => $this->input->post(‘product_name’),
    ‘options’ => array()
    );

    }

    $this->cart->insert($data);
    redirect(‘shop/show_cart’);

    }

  4. Nice… This helped a lot.

    It’s worth noting that the MY in MY_Cart must be uppercase. I spent a little time trying to figure out how codeigniter knows to load my custom library. Turns out it just magically knows as long as you get the name of the file and class correct.

  5. I am trying to use this method on a project. However, when I use it as per your instructions, I get the error : Fatal error: Call to undefined method CI_Cart::CI_Cart() in C:\xampp\htdocs\benta-pos\application\libraries\MY_Cart.php on line 9.

    When I change the constructor to:

    function __construct()
    {
    parent::__construct();
    }

    Then the cart does not update and I get the same cart contents.

    I am using CI 2.0.3
    Do you have any solution for this?

  6. Otuoma, as you’ve found, the reason for the undefined function CI_Cart is that CodeIgniter 2+ is built for PHP5 and has removed older PHP4 functionality. You did the correct thing by changing parent::CI_Cart(); to parent::__construct();

    With that said, I do not know why the cart is not updating as expected. I have just updated the extended cart class to CI 2.1.0 and had no problems getting the sample application to work. During the upgrade, the only things I changed were the parent call in the controller and the class itself. Maybe you could review my use of the class in the updated sample application and identify what you are doing differently?

  7. Sorry for the bother but the script works fine, I had included an array value and that is why I was having the trouble. Again, thank you!

Leave a Comment


NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>