Magento: Make New Customer Attributes Visible in Backend Forms

If you add a new attribute to the customer entity in a a setup script, using addAttribute(), gets a surprise starting from Magento 1.5. The setup runs and database entries in customer_eav_attribute are created correctly but in the backend there is no new form element.

Which works well with other entities like categories and until Magento 1.4 also with customers, needs an additional setup step now, to add the attribute explicitly to the admin form (and/or other forms, like the registration form).

There is a new table for it, customer_form_attribute, which defines for each attribute, in which forms it can be used:

mysql> select * from customer_form_attribute;
| form_code                  | attribute_id |
| adminhtml_customer         |            1 |
| adminhtml_customer         |            3 |
| adminhtml_customer         |            4 |
| checkout_register          |            4 |
| customer_account_create    |            4 |
| customer_account_edit      |            4 |
| adminhtml_customer         |            5 |
| checkout_register          |            5 |
| customer_account_create    |            5 |
| customer_account_edit      |            5 |
| adminhtml_customer         |            6 |
| checkout_register          |            6 |
| customer_account_create    |            6 |
| customer_account_edit      |            6 |
| adminhtml_customer         |            7 |
| checkout_register          |            7 |
| customer_account_create    |            7 |
| customer_account_edit      |            7 |
88 rows in set (0.00 sec)

So much to for a better understanding, of course you don’t need to (and should not!) modify the database manually, it is sufficient to add the following lines after the addAttribute() call in your setup script:

        ->getAttribute('customer', $attributeCode)
        ->setData('used_in_forms', array('adminhtml_customer'))

with $attributeCode being the unique code of the new attribute and 'adminhtml_customer' the code for the customer management form in the backend. To keep setup scripts more clear if you add multiple attributes, it helps to extend the entity setup class, like this:

class MyNamespace_ExtendableCustomer_Model_Entity_Setup
    extends Mage_Customer_Model_Entity_Setup
    public function addAttributeToForm($attributeCode, $formCode)
            ->getAttribute('customer', $attributeCode)
            ->setData('used_in_forms', (array) $formCode)

Now when you use this class for your setup scripts that add customer attributes, it’s as simple as:

$this->addAttribute('customer', 'new_attribute', array( /* ... */);
$this->addAttributeToForm('new_attribute', 'adminhtml_customer');

Of course you can add the attribute to other forms in the same way, for the codes see the list above.

Thank you to the Magento forums for the crucial hint.


Pay attention, on save the field eav_entity_attribute.sort_order gets set, regardless being specified before!

See my comment on StackOverflow.

Furthermore sort_order only applies if user_defined => 0 was specified in the attribute setup because Magento sorts by user_defined first and then by sort_order.

Anonymous function calls in PHP


But let me first introduce the pattern shortly:


(function() {
  var some, local, variables;
  // do something

Why should you want this in PHP?


Unfortunately the following is not posible with PHP Lambda Functions:

(function() {
  $localvar = 'foo';
  // do something


call_user_func(function() {
  $localvar = 'foo';
  // do something


Look at this example:

// test.php
function test() {
  $readMe = 'Hello';
  $writeMe = 'World';
  include 'include.php';

// include.php
  $temp = $readMe . ' ' . $writeMe;
  $readMe = 'Good Bye';
  $writeMe = 'Internet';

test.php results in the following output:
include.php: Hello World
index.php: Hello Internet

Let’s go through it step-by-step:







One step further


// test.php
// ...
  call_user_func(function() use (&$writeMe) {
    include 'include.php';
// ...







CSS: 3D Ribbon Generator

Inspired by this article on I recently created a generator for 3D CSS ribbons and made it available on It creates CSS and HTML code for a cross-browser compatible ribbon effect (not limited to CSS 3!) based on parameters for sizes and colors. The red headers you see in this screenshot are also generated like that:

Have fun with it and feel free to comment if you have any suggestions.

If you are interested in how it works, visit the aforementioned link or read about the CSS Triangle trick at

CSS: Pseudo Bold Fonts

Sometimes you want to emphasize text but the bold version of a font is too “big”. With CSS 3 there is a simple way to thicken the regular font.

.pseudo-bold {
  text-shadow: 1px 0 0;
  padding-right: 1px;
  letter-spacing: 1px;

It creates a duplication that is shifted 1 pixel to the right, the padding and letter-spacing properties prevent overlapping. Of course such hacks will never look as nice as a real typographic bold font, so there are always other possibilities to consider. A way to make wide bold fonts more unobstrusive is reducing the letter spacing:

.narrow-bold {
  letter-spacing: -1px;

Here is a complete example with the Georgia font-family

<style type="text/css">
	#pseudo-bold-example {
		font-family:Georgia; font-size: 24px;
	.bold {
		font-weight: bold;
	.pseudo-bold {
		text-shadow: 1px 0 0;
	.narrow-bold {
		font-weight: bold;
	.narrow-pseudo-bold {
		text-shadow: 1px 0 0;
<div id="pseudo-bold-example">
	<p>Lorem Ipsum - normal text<br />
	<span class="bold">
		Lorem Ipsum</span> - bold text<br />
	<span class="pseudo-bold">
		Lorem Ipsum</span> - pseudo-bold text</span><br />
	<span class="narrow-bold">
		Lorem Ipsum</span> - narrow bold text<br />
	<span class="narrow-pseudo-bold">
		Lorem Ipsum</span> - narrow pseudo-bold text</span></p>

This is how it should look like:


For my current project I eventually decided to go with the narrow bold version, instead of the pseudo bold one. Bonus points: It is fully compatible with CSS 2.

Propel 1.5.5: propel-gen fails

Recentyl I couldn’t get the Propel generator running anymore. First I suspected conflicts due to different versions that were installed at the same time but an update and forcing usage of the latest version did not help.

Turns out that Propel cannot work with the latest versions of Phing, everyghing starting from Phing 2.4.2. So unfortunately the following was necessary:

pear install -f phing/phing-2.4.2

(-f is the “force” parameter to overwrite newer versions)

Et voilà, no more errors.

PHP: Undefined constant __COMPILER_HALT_OFFSET__

This notice showed up in a file with __halt_compiler() occasionaly. It took me some time to get the problem… the error came only when I refreshed the page within short time, so after a while I suspected the opcode cache to be the problem. Actually it was related to APC and I found the following bug report:

Solution: Upgrade APC or just use other methods to store data than at the end of a PHP script 😉

CSS Top margin before out of nowhere

A typical CSS problem but I fall for it again and again. The whole site is shifted down 10-20 pixels in spite of every imaginable variant of margin:0 in the <html> and <body> elements.

So what was it? A <h1> somewhere in the floating layout whose margin-top pushed everything down.

Note to self: Always check for headings!

Useful link: Margin Collapsing

PHP Fatal Error Handler

Code snipped inspired by this article:


// report all but fatal errors 
error_reporting((E_ALL | E_STRICT) ^ (E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR));

// fatal error handler as shutdown function

function fatalErrorHandler() {
	$error = error_get_last();
	if ($error['type'] & (E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR)) {
		echo '<h1>Fatal Error, shutting down...</h1>';
		echo '<pre>' . var_export($error,true) . '</pre>';
	} else {
		echo 'Regular Shutdown, no fatal errors.';


require 'fatalerrorhandler.php';

// Fatal Error (E_ERROR)


require 'fatalerrorhandler.php';

trigger_error('...', E_USER_ERROR);


require 'fatalerrorhandler.php';

// Notice (E_NOTICE)
echo $unknown_var;