editing usermeta when field is an array

This code is your problem:

$s2_custom=get_user_meta($u->ID, 'wp_s2member_custom_fields');
$real = $s2_custom[0];
$real['loomsong_del']='email';
update_user_meta($u->ID,  'wp_s2member_custom_fields',$real);

get_user_meta returns an array of the meta values. Since in this case there’s only a single value with the array, you need to pass the single parameter to it.

Try this:

$s2_custom=get_user_meta($u->ID, 'wp_s2member_custom_fields', true);
$s2_custom['loomsong_del']='email';
update_user_meta($u->ID,  'wp_s2member_custom_fields',$s2_custom);

This won’t fix your already broken data in the DB, BTW. You’ll need to fix that by hand or by code to read the broken array and rebuild the correct one.

Edit: To clarify what I’m talking about…

Meta data can be stored independently as separate rows in the Database, and all the meta functions assume that’s what you’re doing, even when you’re not.

So if I call add_user_meta(1, 'foo', 'value1'); and add_user_meta(1, 'foo', 'value2');, then I actually have two rows in the database there.

If I were to then call get_user_meta(1, 'foo'); then the code actually returns an array with value1 and value2 in it. It makes those separate rows into an array for me.

Now, if I actually only have 1 entry, then I don’t necessarily need it wrapped in an array. In which case I can call get_user_meta(1, 'foo', true); to only return the first result, one row, by itself, no array wrapping. That hidden array wrapping is what got you the first time, because it sent back an array within an array that you didn’t expect.

Undoing the problem basically means going through and reading out the meta, finding the actual data you want in the array of arrays, then modifying it properly and updating it back into the database.