• This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn more.
  • As we have now upgraded the main XenForo community, this forum is now being retired. It will remain open in a mostly read only state. Any further feedback, suggestions or bug reports should be posted on the main forum. We will still process the existing bug reports from this forum.

    When we approach a stable release, this forum will become inaccessible. If there is any content you wish to save, please do so before then.

Would it be possible to have avatar output template?

CyberAP

Well-Known Member
#1
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?
 

Chris D

XenForo Developer
Staff member
#2
Technically possible, yes, but not something we're targeting for XF 2.0 so a suggestion over at XF.com will be preferable.
 

Chris D

XenForo Developer
Staff member
#4
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.
 

CyberAP

Well-Known Member
#5
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.
 

CyberAP

Well-Known Member
#6
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.
 

Kier

XenForo Developer
Staff member
#7
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);
}
 

CyberAP

Well-Known Member
#8
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:

CyberAP

Well-Known Member
#9
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:

CyberAP

Well-Known Member
#10
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: