• This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn more.
  • Welcome to the XenForo 2 demo. This is a work in progress and you may find some rough edges. See more about what to expect.

Would it be possible to have avatar output template?

Well-Known Member
AFAIK avatar code is generated purely on server-side. There is no way of changing avatars markup without digging into code. Is it technically possible to move its markup to the templates?
 
XenForo Developer
Staff member
Technically possible, yes, but not something we're targeting for XF 2.0 so a suggestion over at XF.com will be preferable.
 
Likes: CyberAP
Well-Known Member
Thanks!
 
XenForo Developer
Staff member
FWIW, if this is something you have the need in the short-term and you wanted to build it yourself, extending functions inside the Templater is a lot easier than it was in XF1.
 
Well-Known Member
FWIW, if this is something you have the need in the short-term and you wanted to build it yourself, extending functions inside the Templater is a lot easier than it was in XF1.
That might be a nice homework for me, since I want to learn PHP and only have a very basic idea of how things work in XF 1 under the hood. But for the things I want to do it should be in the final package. I'll post a suggestion with examples on XF.com.
 
Likes: Steve
Well-Known Member
I gave it a shot it and was not disappointed. Provided that I have no PHP coding background I was able to do that after 4-5 hours of googling and reading official docs. The hardest part was to find a way to render a template. With a power of search in PHP Storm I found out it could be done with renderTemplate() function. Now I have a template that simply accepts all the variables from my code and essentially prints the exact output of the default fnAvatar() function. Next step is to put all the possible variables inside that template, including expanded $unhandledAttrs, which can be manipulated later with CSS variables (for dynamic avatars).

One question though: is there a way to decrease code duplication? 95% of my code is just a copy of fnAvatar() with just a new $params variable and a different return which now uses renderTemplate(). So I just can simply collect all the desired variables and change the return of the function.
 
XenForo Developer
Staff member
You could always use fnAvatar() itself, passing the appropriate params directly to it:

PHP:
// something like this...

public function renderAvatarTemplate(\XF\Entity\User $user, $size = 'm')
{
    /** @var \XF\Template\Templater $templater */
    $templater = \XF:app()->templater();
    $escape = false;
    
    $avatarHtml = $templater->fnAvatar($this->templater, $escape, $user, $size);
    
    $viewParams = [
        'avatarHtml' => $avatarHtml
    ];
    
    return $templater->renderTemplate('public:my_avatar_template', $viewParams);
}
 
Well-Known Member
Thanks for the help, @Kier. Unfortunately that outputs exactly what does fnAvatar() right now, which is a predetermined HTML on the server side. I try to put as many variables as possible into my template. So my changed code looked like this:
PHP:
        $params = [
            'tag' => $tag,
            'hrefAttr' => $hrefAttr,
            'size' => $size,
            'updateLinkClass' => $updateLinkClass,
            'class' => $class,
            'userId' => $userId,
            'xfInitAttr' => $xfInitAttr,
            'unhandledAttrs' => $unhandledAttrs,
            'innerContent' => $innerContent,
            'updateLink' => $updateLink,
        ];

        return $this->renderTemplate("public:avatar", $params);
And the template is mimicking the old fnAvatar() output:
HTML:
<{$tag}{$hrefAttr} class="avatar avatar--{$size} {$updateLinkClass} {$class}" data-user-id="{$userId}"{$xfInitAttr|raw}{$unhandledAttrs|raw}>
    {$innerContent|raw} {$updateLink|raw}
</{$tag}>
So I thought that somehow calling it like this would give me all variables (like $avatarHtml.tag) but it just prints a string, unfortunately:
PHP:
        $avatarHtml = parent::fnAvatar($templater, $escape, $user, $size);

        $viewParams = [
            'avatarHtml' => $avatarHtml
        ];

        return $this->renderTemplate("public:avatar", $viewParams);
If only we could access variables inside parent fnAvatar().
 
Last edited:
Likes: Kier
Well-Known Member
After a couple of days I finally did it, the full template has all the variables possible:

HTML:
<xf:if is="{$href}">
    <a href="{$href}"
       class="avatar avatar--{$size} {$class}"
       {{ $stylingBgColor ? 'style="background-color: ' . {$stylingBgColor} . '; color: ' . {$stylingColor} . ';"' : '' }}
       {{ $xfInit ? 'data-xf-init="{$xfInit}"' : '' }}
       data-user-id="{$userId}">  
        <xf:if is="{$src} && {$forceType} != 'default'">  
            <img src="{$src}"
                 alt="{$alt}"
                 class="avatar-u{$userId}-{$actualSize} {$innerClass}"
                 {{ $srcSet ? 'srcset="' . $srcSet . ' 2x"' : '' }}
                 {{ $itemprop ? ' itemprop="' . $itemprop . '"' : '' }}
                 />
        <xf:else />
            <span class="avatar-u{$userId}-{$actualSize} {$innerClass}">{$innerContent|raw}</span>
        </xf:if>
    </a>
<xf:else />
    <span class="avatar avatar--{$size}{{ $canUpdate ? ' avatar--updateLink' : '' }}{{ $fallbackAvatar ? ' avatar--default' : '' }} {$class}"
          {{ $stylingBgColor ? 'style="background-color: ' . {$stylingBgColor} . '; color: ' . {$stylingColor} . ';"' : '' }}
          data-user-id="{$userId}">
        <xf:if is="{$src} && {$forceType} != 'default'">  
            <img src="{$src}"
                 alt="{$alt}"
                 class="avatar-u{$userId}-{$actualSize} {$innerClass}"
                 {{ $srcSet ? 'srcset="' . $srcSet . ' 2x"' : '' }}
                 {{ $itemprop ? ' itemprop="' . $itemprop . '"' : '' }}
                 />
        <xf:else />
            <span class="avatar-u{$userId}-{$actualSize} {$innerClass}">{$innerContent|raw}</span>
        </xf:if>
        <xf:if is="{$canUpdate}">
            <div class="avatar-update">
                <a href="{$updateLink}" class="avatar--updateLink" data-xf-click="overlay">{{ phrase('edit_avatar') }}</a>
            </div>
        </xf:if>
    </span>
</xf:if>
For anyone interested I attached the add-on itself.
 

Attachments

Last edited:
Likes: Kier
Well-Known Member
So I finally finished the initial task that was to add gradients to dynamic avatars, based on their color. And here it is!

img-2017-06-21-00-40-07-1.png

This may not be the perfect solution for production, as with every page request there is LESS doing calculations, but it gets the job done. And the LESS function is configured in style properties, which is super convenient and can work on a per style basis.
 

Attachments

Last edited:
Likes: Kier and Russ