HackerOne users: Testing against this community violates our program's Terms of Service and will result in your bounty being denied.

How to create custom Smarty functions

R_JR_J Ex-FanboyMunich Admin

If you are creating your own theme, you might come to the point where you would need PHP code to achieve something that isn't possible with the existing Smarty functions in /library/vendors/SmartyPlugins/ - you will need your own custom function. Here is a way to create them as reusable files in a separate folder.

You may already have a theme hooks file for your custom theme. If not, create the file /themes/MyTheme/class.mythemethemehooks.php with that content:

<?php defined('APPLICATION') or die();

/**
 * Sample implementation of a theme hooks class to show
 * the use of custom Smarty plugins.
 */
class MyThemeThemeHooks implements Gdn_IPlugin {
    /**
     * Setup function is needed for this class, so don't delete it!
     *
     * @return bool Dummy return value.
     */
    public function setup() {
        return true;
    }

    /**
     * This function hooks the Smarty init to add our directory
     * containing our custom Smarty functions
     *
     * @param object $sender Smarty object.
     * @return void
     */
    public function gdn_smarty_init_handler($sender) {
        // add directory "/themes/MyTheme/SmartyPlugins/"
        $sender->plugins_dir[] = dirname(__FILE__).DS.'SmartyPlugins';
    }

    // whatever...
}

Now that we have told where to find our custom function, let's create one!
Do you know the plugin "Participated"? It adds a link to the menu showing all discussions that you have participated in. But what if you want to have that special link anywhere else? Yes, you'll need a custom Smarty function. Here is one possibility to create the function, save it as /themes/MyTheme/SmartyPlugins/function.participated_link.php:

<?php defined('APPLICATION') or die();

/**
 * Returns a link to "Participated Discussions" (for logged in users).
 * Accepts an associative array with following options:
 * By default the link is wrapped in an <li> element - you could specify another html here ("" will surpress any wrap).
 * "text" is the text that is displayed as the links text.
 * With "format" you could fine tune the html that is created.
 *
 * @param mixed $params Array: [wrap|text|format].
 * @param object $smarty Smarty object.
 * @return string HTML of the Participated Link or empty string.
 */
function smarty_function_participated_link($params, &$smarty) {
    // only makes sense for logged in users
    if (!Gdn::PluginManager()->CheckPlugin('Participated') || !Gdn::Session()->IsValid()) {
        return "";
    }

    // wrap link in <li> element by default
    if (array_key_exists('wrap', $params)) {
        $Wrap = $params['wrap'];
    } else {
        $Wrap = 'li';
    }

    // Sets default text for link
    if (array_key_exists('text', $params)) {
        $Text = $params['text'];
    } else {
        $Text = T('Participated Discussions');
    }

    // Specify default format for HTML link
    if (array_key_exists('format', $params)) {
        $Format = $params['format'];
    } else {
        $Format == Wrap('<a href="%url" class="%class">%text</a>', $Wrap);
    }

    // return a valid link to the plugins target from our input
    return Gdn_Theme::Link('discussions/participated', $Text, $Format);
}

(Yes, it is longer than /library/vendors/SmartyPlugins/function.discussions_link.php which does nearly the same, but my implementation is more easy to read, I think)

Now, with that function, you can do things like that in your theme (/themes/MyTheme/views/default.master.tpl):

< ul >
  {home_link}
  < li >{discussions_link wrap=""}
    < ul >
      {mydiscussions_link}
      {participated_link}
      {bookmarks_link}
      {drafts_link}
    < /ul >
  < /li >
  ...

Share your custom Smarty functions here if you are proud of your work! ;)

Comments

  • R_JR_J Ex-Fanboy Munich Admin

    I haven't found a way to show the users avatar alone, so I've created that function:

    <?php defined('APPLICATION') or die();
    
    /**
     * Encapsulates UserPhoto function.
     *
     * Returns the users avatar.
     * Valid params are "userid" to manually choose a user and "wrap" to
     * specify a tag that the output should be surrounded with.
     *
     * @param mixed  $params Array with function parameters.
     * @param object &$smarty Reference to Smarty template object.
     * @return string         HTML image link to user profile
     */
    function smarty_function_userphoto($params, &$smarty) {
        $UserID = (int)$params['userid'];
        if ($UserID > 0) {
            $User = Gdn::UserModel()->GetID($UserID);
        } elseif (Gdn::Session()->IsValid()) {
            $User = Gdn::Session()->User;
        } else {
            return;
        }
    
        $Wrap = $params['wrap'];
        return Wrap(UserPhoto($User), $Wrap);
    }
    
  • BleistivtBleistivt Moderator
    edited September 2014

    I always add this to my mobile themes to replace the standard profile link:

    function smarty_function_profile_link_notifications($Params, &$Smarty) {
       return Gdn_Theme::Link('profile',
          val('text', $Params, ''),
         '<li><a href="%url/notifications" class="%class">%text</a><li>');
    }
    

    so the link points to the notifications, which are, in my opinion, much more important on the mobile theme as there is no notifications popup.

    Could probably be improved to only do that, when there are notifications for that user.

  • Just wanted to point out a really elegant way of adding a function, that I just discovered through @Adrian's newest plugin:

    https://github.com/adrianspeyer/VanExtend/blob/master/Plugins/JustDucky/class.justducky.plugin.php

  • edited January 2018

    Hi @R_J, I am using vanilla 2.5, I have tried to use this guide but it does not work, I put the code to you please if you can guide me.

    Directory Theme Boostrap:

    • /theme/bootstrap/class.bootstrapthemehooks.php

      <?php defined('APPLICATION') or die();
      /**
       * Sample implementation of a theme hooks class to show
       * the use of custom Smarty plugins.
       */
      class BootstrapThemeHooks implements Gdn_IPlugin {
          /**
           * Setup function is needed for this class, so don't delete it!
           *
           * @return bool Dummy return value.
           */
          public function setup() {
              return true;
          }
          /**
           * This function hooks the Smarty init to add our directory
           * containing our custom Smarty functions
           *
           * @param object $sender Smarty object.
           * @return void
           */
          public function gdn_smarty_init_handler($sender) {
              // add directory "/themes/bootstrap/SmartyPlugins/"
              $sender->plugins_dir[] = dirname(__FILE__).DS.'SmartyPlugins';
          }
      }
      

    Thks,

  • R_JR_J Ex-Fanboy Munich Admin

    @terabytefrelance: the code looks good. Try deleting /cache/theme/bootstrap.php.

    Vanilla gathers information of the available plugins and themes and caches this information in
    /cache/addon.php
    /cache/theme-index.php
    /cache/theme/*.php

    If you change something in themes and addons and the result is not what you expect, it might be needed to delete those cache-files

  • Thks @r_j I have read the documentation 1000 times but it does not work, I really do not understand what I do wrong I add the error and the function maybe I am doing something wrong and I do not see it.

    /theme/bootstrap/SmartyPlugins/function.custom_discussions_link.php

    <?php
    /**
     * @copyright 2009-2017 Vanilla Forums Inc.
     * @license http://www.opensource.org/licenses/gpl-2.0.php GNU GPL v2
     * @package vanilla-smarty
     * @since 2.0
     */
    
    /**
     *
     *
     * @param array $params
     * @param object $smarty
     * @return string
     */
    function smarty_function_custom_discussions_link($params, &$smarty) {
        $wrap = val('wrap', $params, 'li');
        return Gdn_Theme::link('discussions',
            val('text', $params, t('Community')),
            val('format', $params, wrap('<a href="%url" class="%class">%text</a>', $wrap)));
    }
    

    Syntax error in template "file:/home/catatumbo/public_html/themes/bootstrap/views/default.master.tpl" on line 23 "{custom_discussions_link}" unknown tag "custom_discussions_link"
    The error occurred on or near: /home/catatumbo/public_html/vendor/smarty/smarty/libs/sysplugins/smarty_internal_templatecompilerbase.php

    19:  * @property Smarty_Internal_SmartyTemplateCompiler $postfixCompiledCode = ''
    20:  * @method registerPostCompileCallback($callback, $parameter = array(), $key = null, $replace = false)
    21:  * @method unregisterPostCompileCallback($key)
    22:  */
    23: abstract class Smarty_Internal_TemplateCompilerBase
    24: {
    25: 
    26:     /**
    27:      * Smarty object
    

    This is just an example that I want to put into operation to personalize some new things that I will place in the Forum.

    Regards,

  • R_JR_J Ex-Fanboy Munich Admin

    The part in the ThemeHooks file must be:

        public function gdn_smarty_init_handler($sender) {
            $sender->addPluginsDir(__DIR__.DS.'SmartyPlugins');
        }
    

    But I've tested it and I wasn't able to create a correct Smarty function...

  • Hi @r_j thanks for the help, work perfect.

    Regards,

Sign In or Register to comment.