Friday, November 29th 2013


Magento: The order of translations
posted @ 7:45 am in [ Magento -Magento Certified Developer ]

Magento supports localised translations of text used within the site, using a number of translation methods which are perfect for localising the text used within your e-commerce website.

However it is often confusing what order they are prioritised in and where to look to find out which files should be translating your text, so here’s the orders and a little explanation for reference:

The order of checking translation files by Magento is:

1. Extension translation files
2. Theme translation files
3. Database translation table


        foreach ($this->getModulesConfig() as $moduleName=>$info) {
            $info = $info->asArray();
            $this->_loadModuleTranslation($moduleName, $info['files'], $forceReload);
        }

        $this->_loadThemeTranslation($forceReload);
        $this->_loadDbTranslation($forceReload);

1. Extension translation files

Extension translation files are defined in your (or other 3rd party) extensions using the extension’s etc/config.xml file.

Here is an example for our made-up extension, Skywire_Translation

/app/code/local/Skywire/Translation/etc/config.xml




    
        
            0.1.0
        
    
    
        
            
                
                    
                        Skywire_Translation.csv
                    
                
            
        
    


Extension translation files are stored in:

/app/locale/your_LOCALE/Your_Translation_File.csv

so in our case as we are using en_GB as our locale and our above config.xml, this would be:

/app/locale/en_GB/Skywire_Translation.csv

and the contents has the usual Magento format of “Thing to translate”,”What you want it to be instead”, for example

"Add to Cart","Add to Bag"

2. Theme translation files

Theme translation files are applied after Extension translation files so will not get used if text is already re-defined in the extension translation files.

These files reside in:

/app/design/frontend/PACKAGE/THEME/locale/your_LOCALE/translate.csv

so in our case would be

/app/design/frontend/skywire/default/locale/en_GB/translate.csv

and are the same format as all other Magento translate files, namely:

"Add to Cart","Add to Bag"

3. Database translation table

The Database translation table, core_translate, can also be used to store translations, but seems to be largely not used by core or other extensions.

The table structure is:


mysql> desc core_translate;
+-----------+----------------------+------+-----+------------------+----------------+
| Field     | Type                 | Null | Key | Default          | Extra          |
+-----------+----------------------+------+-----+------------------+----------------+
| key_id    | int(10) unsigned     | NO   | PRI | NULL             | auto_increment |
| string    | varchar(255)         | NO   |     | Translate String |                |
| store_id  | smallint(5) unsigned | NO   | MUL | 0                |                |
| translate | varchar(255)         | YES  |     | NULL             |                |
| locale    | varchar(20)          | NO   |     | en_US            |                |
+-----------+----------------------+------+-----+------------------+----------------+

so we would use the ‘string’ field for our source text, and the ‘translate’ string for our desired text.

Interestingly this is used by the Magento inline translation system – which is something I didn’t even know existed (did you?!)

There’s a video of it here and it appears to allow you to translate all the text on your website, using your browser from the frontend.

4. Debugging

If you want to see what extension is claiming what text on your page, a quick check is to echo out the $code for each translate object as the page is rendered.

A quick way to do this (only for testing mind you) is to edit

Mage_Core_Model_Translate

and around line 405 in function translate, echo out the $code value after it is set.

For example:


    /**
     * Translate
     *
     * @param   array $args
     * @return  string
     */
    public function translate($args)
    {
...
        if ($text instanceof Mage_Core_Model_Translate_Expr) {
            $code = $text->getCode(self::SCOPE_SEPARATOR);
            $module = $text->getModule();
            $text = $text->getText();
            $translated = $this->_getTranslatedString($text, $code);
        }
        else {
            if (!empty($_REQUEST['theme'])) {
                $module = 'frontend/default/'.$_REQUEST['theme'];
            } else {
                $module = 'frontend/default/default';
            }
            $code = $module.self::SCOPE_SEPARATOR.$text;
            $translated = $this->_getTranslatedString($text, $code);
        }
        // debug line below
        echo $code;
...
        return $result;
    }

5. One Final Tip…

Magento Translation Files are cached which means after you have changed them or added new files, you have to clear the Translations cache in order to see the effects

System -> Cache Management -> Cache Storage Management -> Translations [select] -> Actions [Referesh] -> Submit

You’ll be happy you read this line 🙂

References:

What is the difference between translate.csv translations and the database method via the table core_translate?

How to add your own translations to Extensions?

Usefull tools:

Exports the DB translations in Magento to CSV files

Magento in-line translations




Thursday, July 4th 2013


Magento: calculating Total Paid 1 penny out £0.01
posted @ 6:45 am in [ Fixing Things -Magento ]

We have a strange issue with a Magento / eBay install for a client where occasionally the orders are being stored with the Total Paid for the order showing in Magento as being £0.01 less than the real total paid by the customer.

MagentoeBayIncorrectTotalPaidCalculation

Looking at the order in the Magento database it appears to be an incosistency in the way that the tax for shipping is calculated.

Amount of shipping charged = £3.95

Magento Values:

Base Shipping Amount = £3.29

Base Shipping Tax Amount = £0.65

Total of these = £3.94

What these values should be:

Base Shipping Amount = (£3.95 – 20% tax) = (£3.95 / 1.2) = £3.29166666

Base Shipping Tax Amount = (20% tax of £3.95) = (£3.95 / (1.2 * 5)) = £0.65833333

Total of these = £3.95 (notice the extra £0.01 difference)

So Magento seems to occasionally NOT correctly round-up the Base Shipping Tax Amount as the value should be £0.66 if the full value is £0.658333333

Now to find out why, where and fix it!

Here’s the tables for reference of two sequential orders – the first that is calculated incorrectly then the second that is calculated correctly!:


mysql> select base_shipping_amount, base_shipping_tax_amount, base_shipping_incl_tax from sales_flat_order where entity_id like '%298';
+----------------------+--------------------------+------------------------+
| base_shipping_amount | base_shipping_tax_amount | base_shipping_incl_tax |
+----------------------+--------------------------+------------------------+
| 3.2900 | 0.6500 | 3.9500 |
+----------------------+--------------------------+------------------------+
1 row in set (0.00 sec)

mysql> select base_shipping_amount, base_shipping_tax_amount, base_shipping_incl_tax from sales_flat_order where entity_id like '%299';

+----------------------+--------------------------+------------------------+
| base_shipping_amount | base_shipping_tax_amount | base_shipping_incl_tax |
+----------------------+--------------------------+------------------------+
| 3.2900 | 0.6600 | 3.9500 |
+----------------------+--------------------------+------------------------+
1 row in set (0.00 sec)




Wednesday, December 5th 2012


Magento: Show out of stock configurable product options and notifications
posted @ 11:13 am in [ Magento -Technology -Web Design ]

Configurable products in Magento are difficult to handle, as they consist of multiple “Simple” products that have their own stock levels, prices etc.

These notes talk through how to add “Out of Stock” options to each of these on the Magento product page, and some extensions to provide Out of Stock Notifications when they are:

Programming: Show out of stock configurable options

http://www.mindgeek.net/magento/magento-show-out-of-stock-configurable-options/

Programming: How to show out of stock configurable options with Magento

http://www.ayasoftware.com/content/how-show-out-stock-configurable-options-magento

Extension: Aheadworks – Product Updates Notifications ($89)

http://ecommerce.aheadworks.com/magento-extensions/product-updates-notifications.html

Extension: Amasty – Out of Stock Notifications ($79)

http://amasty.com/out-of-stock-notification.html

Extension: Apptha – Out of Stock Notification ($79)

http://www.apptha.com/category/extension/Magento/out-of-stock-notification




Wednesday, October 24th 2012


Decoding $_F=__FILE__;$_X= Encoded PHP Files
posted @ 7:27 am in [ Decryption -Fixing Things -Magento -PHP -Technology -Web Design ]

Some PHP files we get from Extension developers for Magento have Bytecode encoding on them, which means if we want to change the functionality or layout of certain parts of the code, even if we’ve paid for it, we can’t.

Obviously this is rather frustrating, however it is possible to reverse engineer the files as follows to make the changes you need.

1. The three component parts

Each file has 3 main parts to it:


$_F=__FILE__;

$_X='a-string-of-text-and-numbers';

eval(base64_decode('a-string-of-text-and-numbers');

These parts are as follows:


$_F - a holder to do the ereg_replace of the obfuscater code with the unencryption keys

$_X - the encrypted PHP code

eval(base64_decode() - the decryption code for $_X

2. Getting the decryption code

To get the decryption code, we need to change the eval(base64_decode()); code to be an echo instead.

In our case above this would be:

echo(base64_decode(‘a-string-of-text-and-numbers’);

and this gives us the decryption code for the main $_X values;


$_X=base64_decode($_X);$_X=strtr($_X,'123456aouie','aouie123456');$_R=ereg_replace('__FILE__',"'".$_F."'",$_X);eval($_R);$_R=0;$_X=0;

If we break this apart into it’s core lines we have:


//decode our main string with base64_decode
$_X=base64_decode($_X);

//replace obfuscater characters in the result with the correct ones
$_X=strtr($_X,'123456aouie','aouie123456');

//replace the contents of $_R with our unencrypted file/PHP code
$_R=ereg_replace('__FILE__',"'".$_F."'",$_X);

//run the contents of the unencrypted file/PHP code
eval($_R);

//clear the contents of $_R so you can't access it
$_R=0;

//clear the contents of $_X so you can't access it
$_X=0;

3. Decrypting the encoded code

So now we just need to run the decryption code as far as it replacing the contents of $_R with the un-encrypted result, and echo that out to the screen.

Here’s the code:


//decode our main string with base64_decode
$_X=base64_decode($_X);

//replace obfuscater characters in the result with the correct ones
$_X=strtr($_X,'123456aouie','aouie123456');

//replace the contents of $_R with our unencrypted file/PHP code
$_R=ereg_replace('__FILE__',"'".$_F."'",$_X);

//print the contents of the unencrypted file/PHP code
echo($_R);

4. Final code

So we end up with:



And we can now make the changes we need




Monday, July 16th 2012


Magento: Extend/Rewrite Block
posted @ 7:11 am in [ Magento -Technology -Web Design ]

To extend/rewrite an existing Block, you need to create your new extension, and your extended block and then rewrite the current block using your config.xml file.

1. Create your new extension

1.1 Folder for your blocks

/app/code/local/Zuneta/Review/Block

1.2 Folder for your configuration file

/app/code/local/Zuneta/Review/etc

2. Extend the block you want to extend/rewrite

2.1 Extended block

/app/code/local/Zuneta/Review/Block/Product/View/List.php

/**
* Detailed Product Reviews
*
* @category Zuneta
* @package Zuneta_Review
* @author Alex Judd
*/
class Zuneta_Review_Block_Product_View_List extends Mage_Review_Block_Product_View_List
{
public function getReviewUrlSection($id, $section)
{
return Mage::getUrl($section . '/*/view', array('id' => $id));
}
}

Notes:

Here we have extended the core block, namely /app/code/core/Mage/Review/Block/Product/View/List.php with our own local version to add a new function allowing us to specify which section we would like to refer to when you view a review.

3. Extend/Rewrite the current block using our XML config.xml file

3.1 /app/code/local/Zuneta/Rewrite/etc/config.xml






0.1.0






Zuneta_Review_Block_Product_View_List




Notes:

The trick here is to specify within the ‘global’ section that we want to talk to the ‘blocks’ section.

Then when in the ‘blocks’ section we want the ‘review’ block to be the one begin rewritten, and as our code is 3 levels deep, we want to rewrite the ‘product_view_list’ block as that relates to /app/code/core/Mage/Review/Block/Product/View/List.php

Then we simply specify the whole structure of our block in the rewrite contents

4. Enabling our block

4.1 /app/etc/modules/Zuneta_Review.xml

We need a /app/etc/modules/Zuneta_Review.xml file in order to enable our module





true
local



5. Done!

We should now be good to go and our new function can be called, for example in my case I am modifying the product template

/app/design/frontend/default/zuneta/template/review/product/view/list.phtml

to specify that I want to use the ‘review’ rewrite for all my detailed review links

htmlEscape($_review->getTitle()) ?> __('Review by %s', $this->htmlEscape($_review->getNickname())) ?>




Monday, November 7th 2011


NGinx not compressing CSS and Javascript
posted @ 8:11 am in [ Fixing Things -Javascript -Magento -PHP -Web Design ]

Another challenge to catch-out the unwary, is that the latest CentOS/RedHat YUM repository version of NGinx, the fantastically fast web server we use for Magento, has some case scenarios where even though it should be compressing CSS and Javascript, it simply doesn’t!

The reason why seems to be that most definitions for what types of files NGinx should compress posted across the forums of the web, include the “text/html” type, such as:

gzip_types text/plain text/html text/css application/json application/x-javascript text/xml application/javascript text/x-js;

Now the problem with this seems to be that NGinx throws a simple warning that it has already got “text/html” defined as it does this by default, however what it then doesn’t tell you is that it IGNORES all the other definitions that come after it in the same line.

So what that means is that if you have the line above in your config file, even though you are defining for example “text/css” as being a file type to compress, NGinx will ignore this as it stops reading the line as soon as it hits the “text/html” double definition.

To fix, remove “text/html” from your line (*and while you are there you might as well just define the types we are using) and it will all work again.

Here’s my line for reference:

gzip_types text/css application/x-javascript;




Friday, September 23rd 2011


Upgrading Magento 1.5 to 1.6 – the gotchas
posted @ 3:46 am in [ Magento -PHP -Web Design ]

Magento upgrade time again, and as normal it should be really easy, but there are as expected a number of snags that come across the way so here’s the (pretty much) definitive way of how to do it and how to fix the problems/errors/snags that happen as you do!

1. Start with the official Magento upgrade guide at the link below

http://www.magentocommerce.com/wiki/1_-_installation_and_configuration/magento_1.5_to_1.6_upgrade

2. If when running your ./mage mage-setup you receive the following error message:

PHP Fatal error: Uncaught exception ‘Exception’ with message ‘Invalid login credentials’ in /path-to-your-website/downloader/lib/Mage/Connect/Ftp.php

then you have the incorrect ftp details for your site configured.

To fix this edit /path-to-your-website/downloader/connnect.cfg and change magento_root to your webserver/downloader directory and remote_config to you username/password and webserver root directory

3. If you initial page load after upgrade fails with the following error:

SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry during upgrade

Then you need to remove constraints from your database as per the advice here which for reference involves changing your app/etc/config.xml file so that the existing initstatements change from:

<initstatements>SET NAMES utf8</initstatements>

to:

<initstatements>SET NAMES utf8; SET FOREIGN_KEY_CHECKS=0; SET UNIQUE_CHECKS=0;</initstatements>

Another alternative is to remove the problematic line from the SQL upgrade script which is probably much neater [and we did both just in case]. Details of how to do that here and for reference you have to:

edit “app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-1.5.9.9-1.6.0.0.php” and comment out the command starting on line 753.

4. Final ‘gotcha’ is that your JS and CSS files can refuse to load, and instead start trying to use your path-to-your-website as their root path, rather than the / path that they should do.

This seems to be due to permissions on the /path-to-your-website/media/ directory which Magento wants to write to, so make sure that the web server has write access here (normally a recursive permission change to allow group writes should do the thing and for reference that is:)

chmod -R g+w media

5. Clear your cache (safe way to do this is to change directory into your var directory and remove *, else if you include a /var in your statement you’ve wiped half your operating system if your dangerously logged in as root or su’d up!!)

cd var
rm -rf cache/* session/*

6. Good to go

Now the final thing is to fix any bugs in your themes – we found some new fatals in the Navigation skin due to not checking for parent/children objects being null – so you may get a few of those too. You can fix those with a

if($_categories != NULL) {

and matching closing } for the if statement

7. More references

A good support thread for this is on the Magento boards here




Tuesday, June 21st 2011


Tuning mySQL for Magento
posted @ 10:07 am in [ Apache -Fixing Things -Magento -mySQL -Technology -Web Design ]

Magento loves using lots of mySQL processes, so therefore mySQL needs to finely tuned to achieve this.

We ran some benchmarking tests today using mysqlreport as the benchmarking tool and as you can see from the results below, mySQL caching following some of the tips in the articles below can really make a difference

1. First test

As you can see with basic caching turned on and no massive tuning we get a cache insert to prune rate of 1.31:1 and no real cache hits

query_cache_size = 8M
table_cache = 128
innodb_buffer_pool_size = 8M

__ Query Cache _________________________________________________________
Memory usage 5.89M of 8.00M %Used: 73.58
Block Fragmnt 14.66%
Hits 1.21M 157.7/s
Inserts 389.92k 50.7/s
Insrt:Prune 1.31:1 11.9/s
Hit:Insert

2. Second test with recommendations from mysqltuner.pl and mysqlreport-3.5

Bigger cache better results

query_cache_size = 32M
table_cache = 512
innodb_buffer_pool_size = 256M

__ Query Cache _________________________________________________________
Memory usage 23.79M of 32.00M %Used: 74.33
Block Fragmnt 12.43%
Hits 3.50M 184.3/s
Inserts 681.81k 35.9/s
Insrt:Prune 2.55:1 21.8/s
Hit:Insert 5.13:1

Hit versus Insert of 5.13 to 1 – now that should make the world a much faster place 🙂

References:

http://www.mysqlperformanceblog.com/2007/11/01/innodb-performance-optimization-basics/
http://www.mysqlperformanceblog.com/2007/11/03/choosing-innodb_buffer_pool_size/
http://www.techiecorner.com/45/turn-on-mysql-query-cache-to-speed-up-mysql-query-performance/
http://webcache.googleusercontent.com/search?q=cache:wVQfPOsS3t0J:www.debianhelp.co.uk/mysqlperformance.htm+mysql+optomise&cd=10&hl=en&ct=clnk&gl=uk&client=firefox-a&source=www.google.co.uk




Wednesday, June 15th 2011


7 Magento projects to watch on GitHub
posted @ 10:28 am in [ Magento -Technology -Web Design ]

Inspired by the great presentations at the Magento Developers Paradise 2011 I’ve been following some of the code created there on GitHub and some of the presenters own projects and here’s 7 great Magento projects you should be following on GitHub:

Magento GitHub Sites

1. 2Boys1Shop / Twoboysoneshop_Configr

Multi-shop configurator shown at MDP 2011

https://github.com/2Boys1Shop/Twoboysoneshop_Configr

2. alistairstead / MageTool

Tool to quickly create now Mage extension frameworks

https://github.com/alistairstead/MageTool

3. dankocherga / MTool

Auto creates files for new Magento module

https://github.com/dankocherga/MTool
https://github.com/dankocherga/MTool/wiki/Manual

4. jirafe / magento-plugin

Magento plugin for Jirafe stats

https://github.com/jirafe/magento-plugin/wiki/Overview

5. firegento / firegento-dynamiccategory

Dynamic category

https://github.com/firegento/firegento-dynamiccategory

6. More Vanish options

http://www.kalenyuk.com.ua/magento-performance-optimization-with-varnish-cache-47.html
http://jirafeinc.tumblr.com/post/6392764424/varnish-caching-with-magento

7. Firegento

FireGento extension with core functionality for debugging Magento

https://github.com/firegento/firegento




Friday, August 20th 2010


Magento Site Performance
posted @ 8:57 am in [ Apache -Fixing Things -Hosting -Magento -Media Temple -PHP -Technology -Web Design ]

Magento the nice Community Version available e-commerce platform that we are using at Skywire for a number of our client builds is incredibly feature rich, but with all of these features comes the trade-off that to get any kind of speed out of the system you either need SERIOUS server hardware, or an awful lot of performance tuning.

To be honest it can run like a real dog if you don’t really work at it!

Well we like to make things work hard at Skywire so went on a journey of discovery on how to make Magento fly, and here’s our understandings to share with everyone else.

1. Server software selection and tuning

Lots of articles out there about this around the web, but you can sum it up in a few points really.

– What webserver (Apache vs. Lighttpd vs. Nginx) and how many threads for that webserver you need. Interestingly, against every article out there, Apache 2 was faster for us that Lighttpd and NginX but I think this was to do with the PHP CGI access the other two were using being slower on our Media Temple server

– Fine tune your mySQL database – we found that the two great scripts mysqlreport and mysqltuner are your friends here

– Get rid of any other processes you don’t need that get in the way (xinetd, spam assassin etc.)

2. Turn on lots of Caching

Magento has caching so turn that on for starts, and then get a minify type plugin (there’s lots of them out there but ) to complement that and join all of your CSS and JS into a single compressed file.

Install a PHP Byte Code caching system to cache any code generated by PHP – we used XCache as it was available via yum but eAccellerator gets good reviews too [although it just hung in our environment].

3. Turn on the Page Compilation feature in Magento!

Yes, I know it’s labelled as Beta, and yes I know it falls over most of the time you run it, but if you run it from the command line, as the same user that owns your web files then it works just great creating a new single directory in /includes/src containing flattened files of all your Magento files with the naming format directory_directory_etc_filename.php

This shaved at least 1 second off of every page load for us (amazing but true) however was a job to install as it ignores any modules installed in /app/code/community.

No worries though, you can work around this by just copying the whole module directory to the /app/code/local directory and rerunning the compiler and then it works great.

4. Load you Magento cache directories into a memory filesystem

Sounds a strange thing to do but you can load your /var/cache/ directory into a memory based ‘tmpfs’ which makes it much faster. Also you can move your sessions to your database instead however this slowed things down for us so we left them as files.

Summary:

So once you’ve done this on a mid-spec Media Temple DV server you can reduce page times from about 10 seconds down to just over a second, which believe me seems fast compared to how clunky Magento can be when running. Have fun!

References:

Magento performance and optimization

http://www.magentocommerce.com/group/view/168/

How do I use the inbuilt magento profiler to see bottlenecks?

http://www.magentocommerce.com/group/blog/action/viewpost/1405/group/168/

Magento Compiler – Improve your performance

http://www.magentocommerce.com/group/blog/action/viewpost/1243/group/168/

9 Methods to Speed Up Magento – A Guide to Making Magento Faster

http://www.blastedthing.com/magento/questions/mag-9-methods-to-speed-up-magento-a-guide-to-making-magento-faster/

Magento performance hosting

http://yoast.com/magento-performance-hosting/

Magento Site Performance Optimization

http://www.yireo.com/tutorials/magento/magento-spo#compress-output-in-general

Performance is Key! – Notes on Magento’s Performance

http://www.magentocommerce.com/blog/comments/performance-is-key-notes-on-magentos-performance/