Kindle and Calibre

I’ve always said I would never buy an ebook reader, as I dislike reading from a screen – possibly as a result of having jobs for the past 10 years that mean I’ve spent much of the day looking at multiple monitors on my desk. But since buying a Kindle back in 2012 I’m somewhat of a reluctant convert. I say reluctant because I haven’t always agreed with Amazon’s business practices, and it doesn’t make a lot of sense that many books have been more expensive to buy in the ebook format, than getting the printed version (even with the additional postage costs).

However I’ve found the contrast of the Kindle’s “e ink” display is really just as good as any printed book, so that’s one stumbling block gone, and being able to access a book from your Mobile Phone/Kindle/PC/Laptop – in fact from any internet connected web browser using Kindle Cloud Reader really does mean you can take your library everywhere; So when you do find yourself with 5 spare minutes, you can take the opportunity to read a chapter of your latest book. Comparing books I’ve either bought, or borrowed from the library, I’ve had much more success with the ones read on the Kindle.

One piece of software I would recommend to any Kindle owner is Calibre. It has many features, but the one I find most useful is it’s ability to access a news / blog source on a scheduled basis, process all the latest articles and generate an ebook which it can send to your kindle by email. It’s very easy to set-up, with a lot of news sources (eg BBC news and sport) to choose from, and it will happily just take the url to an RSS feed for a blog.

The fact it automatically sends the data is great because when you find the time to have a read, you’ll find it’s already downloaded for you. You could access all the same stories from browsing the web, but on the Kindle it just seems more organised, plus with all the adverts stripped and other distractions taken out, which is a definite bonus.

Hosting Magento Images on an External Web Server

I’ve been interested to know for some time if it might be possible to host the product images of a magento website on an external server. The server I’m using to host a magento site (acting as both web and database server) is coming under ever increasing load, despite having some upgrades, and putting plenty of caching in place.

The medium/long term solution is to upgrade the infrastructure, but I’m interested as an interim step whether it might be possible to move the hosting of the imagery to a 3rd party cloud solution (like Amazon web services) to take some of the load/traffic off the magento server, and improve the performance and experience for customers visiting the site.

Signing up to AWS (Amazon Web Services) is a pretty straight forward affair. The EC2 Service (Amazon Elastic Compute Cloud) allows you to create a server instance in various locations around the world (Dublin being the closest to the UK). You can choose from different Amazon Machine Images (AMIs), which offer different performance levels and operating systems.

As part of the set-up of the instance you create ssh certificates which allow you to ssh/scp/rsync to/from the server. There are also a few other settings to adjust:

Security groups – these allow you to choose which ports are open (and from where)

Elastic ips – these allow you to create a static ip, which can then be pointed at your server instance (when you stop/terminate an instance its hostname and ip address changes each time it’s started again).

I tarred up the /media directory of the magento site, and scp’d it across to the new server instance…

scp -i **location of key file** media.tar ec2-user@**ipaddress of AWS instance**:**location to place file**

I started apache on the new server instance, and untarred the media directory into the web root, so it has a /media directory with all the various sub directories.

When a customer requested a product image from the live web server I want apache to tell them to go off to the AWS server to download the image. This is achieved by editing the .htaccess file on the live server within the media directory, and adding this entry…

RewriteCond %{HTTPS} !on
RewriteRule ^(.*)\.(jpg)$ http://**AWS IP Address here**/media/$1.jpg

Basically this says that if a jpg file within the media directory is requested (on a non https request) then redirect the browser to get the image from the AWS server instance. The $1 contains any sub directory location path. I wanted to only redirect http requests because the AWS instance doesn’t have a SSL certificate and this might cause alerts when customers were using a secure connection to the site.

To keep the AWS server instance imagery up-to-date I set up a cron job on the magento server to regularly update any changes using rsync…

rsync -vazOe "ssh -i **path to key**" **path to media directory on magento server** ec2-user@**ip of AWS Server**:**path to media directory on AWS server** -u --exclude ".htaccess"

I monitored the apache access and error logs on the AWS server instance to make sure all the images were getting requested ok, and all looked good. Amazon charges using a credit system based on use, so I’ll have to keep an eye on the bills – but so far so good.

ebizmarts Sage Pay Suite PRO, Error: MALFORMED. 3055 : The CardType field is required.

Having recently introduced the ebizmarts Sage Pay Suite PRO integration to hook a magento website up to Sagepay, using the direct method I was periodically getting the error “Error: MALFORMED. 3055 : The CardType field is required”.

After a bit of detective work, I believe this error is getting caused by:

a) The customer going through the onepage checkout, entering their payment details and checking out. They are then passed to their providers 3D secure page. They somehow get back to the website (possibly back button) because the page hasn’t loaded or an error. When they go through the checkout for the second time the payment method is already selected (on the radio button) but the details have cleared (and the form is hidden). They can click continue (probably assuming the details have been stored), but they won’t get passed to the 3D secure page, and instead get the error “MALFORMED. 3055 : The CardType field is required”.

b) They’ve almost completed the checkout (including the payment details), but then exited the checkout perhaps to edit the basket. When they go back to checkout, again the payment method is now pre-selected but the details have cleared (and the form is hidden). They click continue (again probably assuming the details have been stored) but they won’t get passed to the 3D secure page and instead get the error “MALFORMED. 3055 : The CardType field is required”.

I’ve fixed it by removing the default checked status of the radio button in:

Basically removing: checked="checked", so if the customer returns to the payment screen no payment method is pre-selected, and they then must select a method to continue. The payment form appears and it must be filled in, and so the error shouldn’t occur.

Chartwell Visit

We visited Chartwell in Kent at the weekend, the house where Winston Churchill lived with his family for most of his adult life. It’s now a National Trust property, and the house, studio, gardens and estate are open to the public for part of the year to visit. The layout of the house was how it would have looked during the 1920s, and the studio has a display of many pictures painted by Churchill himself. I can definitely recommend it as somewhere to visit, and hope we can go back in the summer when it will be a better time to see the gardens.

2014-10-18 15.28.03

2014-10-18 15.30.35

2014-10-18 15.54.14

Testing ebizmarts Magento Abandoned Cart Module

The abandoned cart module is designed so that the minimum amount of time between a cart being abandoned, and an email going out is 1 hour. Which makes testing a bit tricky having to wait so long before the email gets sent out.

I created a page that would reset the abandoned basket in the database, forcing the email to go out within a min…

Within /app/code/community/Ebizmarts/AbandonedCart/etc/config.xml

Update the value for cron_expr so that it reads “*/1 * * * *” (ie checks once a minute, rather than once per hour)

Update your magento cron job so that it also runs once per minute, on a linux server it might be something like:
*/1 * * * * /bin/sh /srv/www/htdocs/magento_root/

I then created a page that updated the sales_flat_quote table for a certain customer email address, and reset the ebizmarts fields:

    ebizmarts_abandonedcart_counter = 0,
    ebizmarts_abandonedcart_flag = 0,
    ebizmarts_abandonedcart_token = NULL,
    created_at = DATE_SUB(NOW(), INTERVAL 3 HOUR),
    updated_at = DATE_SUB(NOW(), INTERVAL 2 HOUR)
    customer_email = 'my email address here'

Whenever the page is visited the quote is updated, and a new email gets sent out.

London Marathon 2014

Another year, another London Marathon – training went pretty well this year, and I ran my second quickest time, finishing 421st in 2:46:15. I wasn’t feeling great at half way, but seem to improve at about 19/20 miles, and ground out the last 10K.

The London Marathon has 3 starts which all join after about 3 or 4 miles. At my start I bumped into another local runner who I’d run with in a half marathon earlier in the year. As we had similar targets we agreed to work together, and he was hoping to meet up with a club mate going off another start. So we ran for 4 miles, and would you believe it as the two roads converged we met James coming down the other road 🙂

You always meet interesting people at running events – walking back to the station I was chatting to another finisher, who turned out to be in the Government of St Georgia (an island south east of the Falklands).

Magento Freezing on Currency Change

I’ve recently been looking at introducing multi-currency options on a Magento website (so the customer can see the price in pounds, dollars, euros etc). The problem I’ve been finding was that the website would freeze after I made a new choice of currency, and eventually the web server time out the request.

Today I had a chance to see what’s going on…

By adding mysql database logging I could see magento was making repeated SQL statements like this…

SELECT `sales_flat_quote`.* FROM `sales_flat_quote` WHERE (`sales_flat_quote`.`entity_id`='321') AND (store_id IN ('1')) AND (is_active = 1)

In fact there were over 8K requests to the sales_flat* tables in a very short space of time!

Eventually with a bit of googling I narrowed down the problem to a rogue bit of code in a custom module used for quantity based discounts across multiple different colour/size variations of the same configurable product.

The line of code causing the problem was:
if($items = Mage::getSingleton('checkout/session')->getQuote()->getItemsCollection())

This caused an infinite loop where the getting of the items in the collection caused it to get the prices again, which in turn fired this piece of code off once again, and so on…

Changing the code to:

$quoteId = Mage::getSingleton('checkout/session')->getQuoteId();
$quote = Mage::getModel('sales/quote')->load($quoteId);
if($items = $quote->getItemsCollection())

has solved the problem.

Linking to a Page from Magento Category Navigation

To create a new page on Magento, which you can link to from the Category navigation, you can try the following:

Create a new directory inside your chosen template, for example:

Then create a new file in there called content.phtml

and add some content for the new page.

In magento admin go to:
CMS->Static Blocks

Add New Block (top right)

Block Title: Block Name
Identifier: block_identifier

In the white content space paste in:
{{block type=”core/template” template=”NewDirectoryName/content.phtml”}}

Save Block (top right)

Catalogue->Manage Categories

Create the Category

Display Settings Tab

Display Mode: Static Block Only

CMS Block: Chose the one you created earlier

Custom Design Tab

Page Layout: 1 Column

Save Category

You should now have a link in the navigation, which will load the content from content.phtml

Magento Google Product Feed

I’ve beeen working on producing a new google product feed, using the product data from a Magento database.

This has been made more complex because google requires additional attributes for clothes/shoes, and wants the data at colour/size level, including a unique image for every colour variation.

The code I’m developing iterates through the “live” products in certain categories. Pulling out the data and producing an RSS2 feed.

Most of the products are Configurable products, so in order to access the child products I used this code, which iterates through each child, and then gets the colour and size attribute values…

  #Get Configurable Product ($obj is the product from a collection)
  $product_tmp = Mage::getModel('catalog/product')->load($obj->entity_id);

  #Get Children
  $conf = Mage::getModel('catalog/product_type_configurable')->setProduct($product_tmp);
  $col = $conf->getUsedProductCollection()->addAttributeToSelect('*')->addFilterByRequiredOptions();
  foreach($col as $simple_product) {
    $attributes = $simple_product->getAttributes();
    foreach ($attributes as $attribute) {
      $value = $attribute->getFrontend()->getValue($simple_product);
      if ($value != "" && $attribute->getName() == 'color' && $value != "No") { 			
        echo "      " . $value . "\n"; 
        $thisColour = $value;
      if ($value != "" && $value != 'No' && strpos(strtolower($simple_product->getResource()->getAttribute($attribute->getName())->getFrontendLabel()), 'size')) { 
        echo "      " . $value . "\n"; 
        $thisSize = $value;

Double Order Totals in Magento

I’ve been having a problem in magento for a small number of customers where the order total is double what it should be – although everything looks correct in the basket. I haven’t been able to find the underlying cause, but hopefully have found a link to a fix which might help others having the same problem.

The fix is on this website here:

The problem seems to be that magento is creating duplicate entries for a quote in the table: sales_flat_quote_address

It’s obviously not a very clean fix, but adding code to:

in the init() function after line: $this->getQuote()->setCheckoutMethod(”);

$addresses = $this->getQuote()->getAllAddresses();
if (count($addresses) > 2) {
  for($i = 2; $i < count($addresses); $i++) {
    $address = $addresses[$i];

The verdict is out so far, but hopefully that should do the trick.

If you are allowing multiple shipping addresses for an order, this probably won’t work for you.