[TIPS / TRICKS] - Replace Profile Menu Text With User Avatar

Started by Hj Ahmad Rasyid Hj Ismail, August 19, 2014, 09:25:10 AM

Previous topic - Next topic

Hj Ahmad Rasyid Hj Ismail

As stated, I am just gonna share a trick of replacing profile menu text with user avatar. You just need to add the following code to Modifications.english.php file (at its end).

For SMF 1.1.x:
$txt[79] = '<img src="'. $modSettings['avatar_url'] . '/' . htmlspecialchars($user_info['avatar']['url']). '" title="Profile" alt="Profile" width="20" height="20" />';

For SMF 2.0.x:
$txt['profile'] = '<img src="'. $modSettings['avatar_url'] . '/' . htmlspecialchars($user_info['avatar']['url']). '" title="Profile" alt="Profile" width="20" height="20" />';


You can change its width and height to the one that suite your menu size. You can add and use css class and stylings for it.

For SMF 2.0.x, you can even separate it from inside your current menu to the right side of your menu.

To move it to the right side and rectify its dropdown:
#main_menu .dropmenu li#button_profile
{
float:right;
}
#main_menu .dropmenu li#button_profile ul
{
background: url(../images/theme/menu_gfx.png) 100% -130px no-repeat;
right: 5px;
}


Similarly, you can use css id stylings to further enchance this trick.
So far other than my Default Menu On Top and/or Alternative Menu mod, I don't find any easy way to do that for SMF1.1.x. I have tested this and will make it available my Alternative Menu mod next version.


Edited with some enhancement added:
But the above code won't cover if the user doesn't have any avatar and the admin doesn't set any default avatar either. As highlighted by Yoshi, I added up the following code so that it will detect if there is any avatar. Otherwise, the original text will be used.

For SMF 1.1.x:
$txt[79] = ''. ($user_info['avatar']['url'] == '' ? 'Profile' : '<img src="'. $modSettings['avatar_url'] . '/' . htmlspecialchars($user_info['avatar']['url']). '" title="Profile" alt="Profile" width="20" height="20" />'). '';

For SMF 2.0.x:
$txt['profile'] = ''. ($user_info['avatar']['url'] == '' ? 'Profile' : '<img src="'. $modSettings['avatar_url'] . '/' . htmlspecialchars($user_info['avatar']['url']). '" title="Profile" alt="Profile" width="20" height="20" />'). '';


Edited again to add final enhancement:

For SMF 1.1.x:
$txt[79] = ''. ($user_info['avatar']['url'] == '' && !empty($user_info['avatar']['ID_ATTACH']) ? '<img src="'. $scripturl . '?action=dlattach;attach=' . $user_info['avatar']['ID_ATTACH'] . ';type=avatar' . '" title="Profile" alt="Profile" width="20" height="20" />' : (substr($user_info['avatar']['url'], 0, 7) == 'http://' ? '<img src="'. $user_info['avatar']['url']. '" title="Profile" alt="Profile" width="20" height="20" />' : ($user_info['avatar']['url'] != '' ? '<img src="'. $modSettings['avatar_url'] . '/' . htmlspecialchars($user_info['avatar']['url']). '" title="Profile" alt="Profile" width="20" height="20" />' : 'Profile'))). '';

For SMF 2.0.x:
$txt['profile'] = ''. ($user_info['avatar']['url'] == '' && !empty($user_info['avatar']['id_attach']) ? '<img src="'. $scripturl . '?action=dlattach;attach=' . $user_info['avatar']['id_attach'] . ';type=avatar' . '" title="Profile" alt="Profile" width="20" height="20" />' : (substr($user_info['avatar']['url'], 0, 7) == 'http://' ? '<img src="'. $user_info['avatar']['url']. '" title="Profile" alt="Profile" width="20" height="20" />' : ($user_info['avatar']['url'] != '' ? '<img src="'. $modSettings['avatar_url'] . '/' . htmlspecialchars($user_info['avatar']['url']). '" title="Profile" alt="Profile" width="20" height="20" />' : 'Profile'))). '';

As mentioned in post #12, it is tested and working for all four conditions whether:
1. No avatar.
2. Listed avatar.
3. Avatar from URL.
4. Uploaded avatar.

So, whoever is trying this trick, good luck!

NanoSector

This does not take users with no avatar into account, nor guests.
My Mods / Mod Builder - A tool to easily create mods / Blog
"I've heard from a reliable source that the Answer is 42. But, still no word on what the question is."

Arantor

Guests shouldn't see the profile button anyway. But if profiles are visible to guests, this could be interesting and awkward.

I'm also curious as to the necessity of htmlspecialchars() on the avatar URL...

NanoSector

Quote from: ‽ on August 19, 2014, 10:07:14 AM
Guests shouldn't see the profile button anyway. But if profiles are visible to guests, this could be interesting and awkward.

I'm also curious as to the necessity of htmlspecialchars() on the avatar URL...
Assuming that the strings are always loaded it might cause errors in the error log in both cases where the user is a guest or doesn't have an avatar.

htmlspecialchars isn't needed indeed, SMF should have validated the URL already.
My Mods / Mod Builder - A tool to easily create mods / Blog
"I've heard from a reliable source that the Answer is 42. But, still no word on what the question is."

Arantor

It shouldn't throw an error, $user_info['avatar'] is defined even for guests during loadUserSettings().

NanoSector

Oh, I didn't know that. In any case neither will show a working avatar, so that's something to be considered. Nice idea, though :)

Also I see typoz in the title. :P
My Mods / Mod Builder - A tool to easily create mods / Blog
"I've heard from a reliable source that the Answer is 42. But, still no word on what the question is."

Hj Ahmad Rasyid Hj Ismail

Great work Yoshi. I hope you find the "error(s)" you claimed as I didn't find any except for this topic typo. :P

I already have this in my code for Alternative Menu mod, so I thought I shared it here and I will update the first post for other users' sake.

For SMF 1.1.x
$txt[79] = ''. ($user_info['avatar']['url'] == '' ? 'Profile' : '<img src="'. $modSettings['avatar_url'] . '/' . htmlspecialchars($user_info['avatar']['url']). '" title="Profile" alt="Profile" width="20" height="20" />'). '';

For SMF 2.0.x
$txt['profile'] = ''. ($user_info['avatar']['url'] == '' ? 'Profile' : '<img src="'. $modSettings['avatar_url'] . '/' . htmlspecialchars($user_info['avatar']['url']). '" title="Profile" alt="Profile" width="20" height="20" />'). '';

As for "htmlspecialchars" those who don't think it is necessary can drop it. IMO it won't harm you though if you leave it just like that.

Arantor

Actually, now that I think about it, I can see a few possible issues.

Well, you don't need empty strings either side of the code, which will simplify it. You can also reuse $txt['profile'] to avoid having to retranslate it each time.

More interestingly, there are circumstances where $user_info['avatar'] won't actually tell you what you need, because of the different sets of circumstances where the avatar can be prepared (gallery vs external vs attachment as server-stored-not-in-attachments). As such, $context['user']['avatar']['href'] should be relied upon for being definitive, not $user_info for the current user's avatar.

Putting that all together might give you something like:

$txt['profile'] = !empty($context['user']['avatar']['href']) ? $txt['profile'] : '<img src="' . $context['user']['avatar']['href'] . '" title="' . $txt['profile'] . '" alt="' . $txt['profile'] . '" width="20" height="20" />';

(Can't use == '' there because $context['user']['avatar'] might actually be empty itself if there's no avatar.)

Biology Forums

ahrasis, you always seem to forget the most important part...

Pictures!

:)

Hj Ahmad Rasyid Hj Ismail

Thanks for the advice Shuban. But this trick should be understandable without any picture. Avatar will replace the word Profile in menu with the re-sized image of 20x20. As simple as that. Anyway, I will add that picture later as most people understand pictures better than text. Thank you again for reminding me. :)

Quote from: ‽ on August 19, 2014, 12:27:27 PM
Well, you don't need empty strings either side of the code, which will simplify it. You can also reuse $txt['profile'] to avoid having to retranslate it each time.
Well, IMO you cannot because this trick already changes $txt['profile']. You cannot call it again in its own string. You need a proper mod to do that. I will basically cover this in Alternative Menu mod as it creates and uses its own string in addition to $txt['profile'], so no conflict.

Quote from: ‽ on August 19, 2014, 12:27:27 PM
More interestingly, there are circumstances where $user_info['avatar'] won't actually tell you what you need, because of the different sets of circumstances where the avatar can be prepared (gallery vs external vs attachment as server-stored-not-in-attachments). As such, $context['user']['avatar']['href'] should be relied upon for being definitive, not $user_info for the current user's avatar.

Putting that all together might give you something like:

$txt['profile'] = !empty($context['user']['avatar']['href']) ? $txt['profile'] : '<img src="' . $context['user']['avatar']['href'] . '" title="' . $txt['profile'] . '" alt="' . $txt['profile'] . '" width="20" height="20" />';

(Can't use == '' there because $context['user']['avatar'] might actually be empty itself if there's no avatar.)

This is more confusing to me than helpful because I have actually gone through that road. But taking your words as an expert, I will look into it with no promise to implement (as IMO I do believe this trick is already correct).

NanoSector

Arantor's fix was what I was thinking about.

Quote from: ahrasis on August 19, 2014, 12:45:34 PM
Quote from: ‽ on August 19, 2014, 12:27:27 PM
Well, you don't need empty strings either side of the code, which will simplify it. You can also reuse $txt['profile'] to avoid having to retranslate it each time.
Well, IMO you cannot because this trick already changes $txt['profile']. You cannot call it again in its own string. You need a proper mod to do that. I will basically cover this in Alternative Menu mod as it creates and uses its own string in addition to $txt['profile'], so no conflict.
You mentioned adding a new string in the file. In that case, both strings already exist.
For the same reason you can do $i = $i + 1; (albeit not recommended) you can also do this.
My Mods / Mod Builder - A tool to easily create mods / Blog
"I've heard from a reliable source that the Answer is 42. But, still no word on what the question is."

Arantor

QuoteWell, IMO you cannot because this trick already changes $txt['profile']. You cannot call it again in its own string.

Yes you can. The result of the expression on the right is calculated before associated with the variable on the left. If it were not possible, you would not be able to say something like:

$x = 'string' . $x;

which is completely legal and does exactly what you would expect.

Quote(as IMO I do believe this trick is already correct)

It is not.

The path of execution is as follows in a stock installation: loadUserSettings loads the contents of smf_members for the current user into $user_settings. The avatar column is the one from smf_members at that point - the values for id_attach, filename and attachment_type for server-stored attachments in the attachments folder are not used at that point.

Then around line 480, $user_settings is transferred into $user_info. You will see the definition for avatar is an array primarily built of $user_settings - but ['avatar']['url'] is taken directly from $user_settings['avatar'], which is still the same as the row in smf_members.

avatar in smf_members is populated as follows:
* if it is an external avatar, it will be the full URL
* if it is a gallery avatar, it will be enough of the URL to be able to resolve that avatar
* if it is an uploaded avatar where the avatar folder is not the attachments folder, it will be the filename of the avatar
* if it is an uploaded avatar where the avatar folder *is* the attachments folder (the default), it will be blank

On standard installations, it will be blank for users who upload avatars themselves (or have external avatars downloaded).

Unfortunately, for anyone *not* using a gallery avatar it will be broken too because $modSettings['avatar_url'] is only the path to the gallery folder. Even external URLs won't apply to that.

$context['user']['avatar'] is correctly resolved in all cases as per Subs.php::setupThemeContext, around line 3235 where it identifies the type of avatar and builds the URL appropriately.


That said... I didn't test my code, as if I had, I would have realised a separate problem; that Modifications.language.php is loaded so much earlier than setupThemeContext is anyway, meaning that there are two choices: either cloning the code from setupThemeContext into the language files (which will also break the language editor), or modifying the menu to use $context['user']['avatar']['href'] itself anyway in 2.0.

Which means substituting:
'title' => $txt['profile'],

for:
'title' => empty($context['user']['avatar']['href'] ? $txt['profile'] : '<img src="' . $context['user']['avatar']['href'] . '" title="' . $txt['profile'] . '" alt="' . $txt['profile'] . '" width="20" height="20" />',

Doing that in 1.1.x is messier because of the fact that menus are coded directly into the theme makes it harder, but the same style of technique should generally work.

Hj Ahmad Rasyid Hj Ismail

No. What you are thinking is definitely not the same as mine as I added the code inside the Modifications.english.php as I have specifically mentioned. Doing it other way(s) is different trick or tip altogether.

The reason it was not called as suggested by Arantor is the respective code that he was advising will not be called earlier as he himself answered above. That path is what I have gone through as I mentioned in response to his advises. Not that I didn't care but I have tested this as I mentioned earlier.

As for further suggestion regarding the $txt string, may be you can test it on your own. I have no further comment on that.

By the way, the earlier code given is correct and this is true as it based on Subs.php code itself. I have never created my own codes except a little and most of them is what easily available inside SMF itself. Except that code was too short and it covers only the avatar from available selection. Avatar from URL or uploaded avatar, is not covered as yet. That, however, doesn't make the code wrong by itself.

The enhanced version of the code that covers all is as follows:

$txt['profile'] = ''. ($user_info['avatar']['url'] == '' && !empty($user_info['avatar']['id_attach']) ? '<img src="'. $scripturl . '?action=dlattach;attach=' . $user_info['avatar']['id_attach'] . ';type=avatar' . '" title="Profile" alt="Profile" width="20" height="20" />' : (substr($user_info['avatar']['url'], 0, 7) == 'http://' ? '<img src="'. $user_info['avatar']['url']. '" title="Profile" alt="Profile" width="20" height="20" />' : ($user_info['avatar']['url'] != '' ? '<img src="'. $modSettings['avatar_url'] . '/' . htmlspecialchars($user_info['avatar']['url']). '" title="Profile" alt="Profile" width="20" height="20" />' : 'Profile'))). '';


This is also taken from Subs.php and it is tested and working for all four conditions whether:
1. No avatar.
2. Listed avatar.
3. Avatar from URL.
4. Uploaded avatar.

Well, I know it is not bullet proof but it is working with no error whether on server side or on SMF side.

Thank you for your opinions, suggestions, critics etc. I do learn via all of them though I will finally decide my own way/path after I did my homework.

Arantor

*shrug* If you're happy with it, that's great. I was more pointing out the foibles for those who might try to use it afterwards, to reduce you having to deal with support issues.

Hj Ahmad Rasyid Hj Ismail

Dear Captain Arantor,

This is just a mere tip / trick and nothing more. User can see your ways of doing thing and may choose to follow  them. I have no problem with that. So long it works, everybody is happy.

Besides, everybody has his own way of doing things. Some may prefer not to edit the big Subs.php file and add a simple $txt string inside a smaller Modifications.english.php file. Some may be the other way around. They are just different ways of doing things, so no big deal.

I really appreciate your comments and helps. I really do. The fact that you are called as Captain, make me want to learn more from you. But as I said, finally, I will only choose my own way. Some may be the same as yours, some may not.

There is no one way in this life. That what makes it fun. I choose mine and others choose theirs. Cheers!

samborabora

I was looking about 4 months ago for a way of having the profile pic display in the profile dropdown menu, but at the time I wasn't sure how to use images instead of text for menus. I'm going to take a look at this soon and see if it's possible, basically, have the profile image above the "account settings" and "forum profile" links in the actual drop down. I'm presuming this would be able to do this? Well done again, ahrasis!

Hj Ahmad Rasyid Hj Ismail

Yes. That will be possible. But it will require editing Subs.php or use a mod that can modify menu in Subs.php without modifying it directly. For that, IMO Arantor suggestion is better as it is shorter and easier in its approach.

Advertisement: