This has bit me in the ass one too many times, so I thought I’d do a quick write-up of how I deal with CodeIgniter‘s otherwise wonderful Cart class and its refusal to accept accented “foreign” characters.

Important: The following assumes you are using PHP5+ and CI 2.0 or newer.

The problem

You have your product pages all nicely set up with an “Add to Basket” button. When that button gets clicked, via some jQuery $.get magic in my set-up, the product and its specifications gets added to the Cart object. If however your product’s name has any accents in it (e.g. “Verre à Bière”), CodeIgniter will by default silently refuse to add that product to the cart.

The solution

Create a file in application/libraries and call it “MY_cart.php”. In that file, paste the following code:

< ?php 
if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class MY_Cart extends CI_Cart {
    function __construct() {
        parent::__construct();
        $this->product_name_rules = '\d\D';
    }
}

This will override CodeIgniter’s default set of allowed characters, and extend it with whatever accent you can think of. If you’re not using Javascript to add items to the cart, that should do the trick and you can stop reading now.

However, as mentioned, I’m using jQuery’s $.get method to add items to the cart, so that the page doesn’t have to reload each time an item gets added (it’s what the cool kids refer to as “Ajax”). Here’s an example of the script I’m using for this:

$(function(){
	$('#addButton').click(function(){ 
		$.get("path/to/add_to_cart",
		{   
			id: $('input[name=id]').val(), 
			name: $('#name').val(), 
	   		qty: $('#qty').val(),
		       	price_option: $('#price_option').val()
		 }, 
		 function(data) {	
			$('#addedMsg').html(data.html).show();
			}, 'json'
		); // end get
		return false;   
	});		
});

Notice that I’m passing on the value of a hidden formfield with id “name” to this function. Now, here’s the pitfall: Javascript will convert accented characters to their equivalent Unicode string (while, for legacy reasons, I’m having to use the iso-8859-1 charset). As a result, CodeIgniter will gladly add my item to its cart, but since it’s passed through Javascript, the accented characters come out as “gibberish”, once you have to display them in your cart view.

The solution here is to pass the regular product name (accents and all) to the jQuery function, and then do the following in the php script which actually adds the item to the cart. Instead of something like:

$data['name'] = $this->input->get('name');
//proceed to insert in cart

Do this:

//run the name variable through the ascii_to_entities() function
$data['name'] = ascii_to_entities($this->input->get('name'));
//proceed to insert in cart

Note that for this you will have to have CodeIgniter’s Text helper loaded.

Almost there

What we’ve accomplished so far: CodeIgniter’s Cart class accepts our accented product names, and although we’ve passed the names through Javascript, the correct characters still show up within the Cart object. But how about displaying items in a cart overview? If you link back each item to its product page, you will have to construct that link such that it re-instates the ascii characters instead of their respective entities:

base_url().'/controller/'.sanitize_title_dashes(entities_to_ascii($items['name']));

Note that I’m using sanitize_title_dashes() (see the WordPress core) as a method to obtain URL’s which are restricted to an “a-z0-9” realm of characters – thereby omitting any characters that had previously been turned into entities! Using entities_to_ascii() allows them back into the url. Phew.

Wrapping up

While it may look a bit messy, the above solved the problem for me. I love CodeIgniter very much, and it’s sped up my webdevelopment significantly. It being mildly US-centric though in the way it handles accented characters in URL’s and Cart processing leaves a bit to be desired. The up side is that through its extensibility, you can make things work – allbeit with a bit of angry fist shaking. Having these workarounds present out of the box from within CodeIgniter would be nice. But that’s another can of worms…