1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.
  2. This forum has been archived. New threads and replies may not be made. All add-ons/resources that are active should be migrated to the Resource Manager. See this thread for more information.

Creating a add-on to insert tabs in profile page (using hooks)

Discussion in 'Development Tutorials [Archive]' started by Fuhrmann, Oct 10, 2011.

Thread Status:
Not open for further replies.
  1. Fuhrmann

    Fuhrmann Well-Known Member

    This tutorial will teach you how to insert new tabs in the profile page using the templates hooks. You can see a more detailed explanation here: http://xenforo.com/community/threads/how-to-use-template-hooks.13167/

    Step 1 - First of all

    You have to make sure that your XenForo is in debug mode. To do this, open your config.php (yourForum/library/config.php) and put this line into:

    Code:
    $config['debug'] = true;
    Save it. Close. Go to your AdminCP and you'll see a new tab. "Development".

    Step 2 - The Add-on

    Log into your AdminCP go to Development>Create Add-on

    Lets fill the fields with this information:

    Add-on ID: newProfileTabs
    Title: New Profile Tabs in profile page
    Version String: 1.0
    Version ID: 1

    Save it.

    Step 3 - The template hook

    This Add-on will use the template hooks system, so the new tabs always remained active even after an upgrade of XenForo.

    First of all let's find the template of the profile page. There is so many ways to do that, here is what i do:

    In my browser (Chrome), I go to the profile page and inspect it (F12) . I'm looking for some class that i can use to search in the "Search Template" AdminCP.
    Let's see:

    1.PNG

    Appears that we can use the class "profilePage" for the search. Ok, go to your AdminCP>Appearence>Search Templates and search for.

    2.PNG

    Well, We got it! The template is "member_view".

    If you look inside the template, you'll find:

    Code:
    <ul class="tabs mainTabs Tabs" data-panes="#ProfilePanes > li" data-history="on">
    <li><a href="{$requestPaths.requestUri}#profilePosts">{xen:phrase profile_posts}</a></li>
    <xen:if is="{$showRecentActivity}"><li><a href="{$requestPaths.requestUri}#recentActivity">{xen:phrase recent_activity}</a></li></xen:if>
    <li><a href="{$requestPaths.requestUri}#postings">{xen:phrase postings}</a></li>
    <li><a href="{$requestPaths.requestUri}#info">{xen:phrase information}</a></li>
    <xen:if is="{$warningCount}"><li><a href="{$requestPaths.requestUri}#warnings">{xen:phrase warnings} ({xen:number $warningCount})</a></li></xen:if>
    <xen:hook name="member_view_tabs_heading" params="{xen:array 'user={$user}'}" />
    </ul>
    
    That's what we were looking for! This code makes the current tabs, and there is the template hook. So far, we now the template name that make the tabs. Now we know too the name of the template hook! See this line:

    Code:
    <xen:hook name="member_view_tabs_heading" params="{xen:array 'user={$user}'}" />
    This is the hook name: "member_view_tabs_heading". Write down somewhere, we will use it.

    Step 4 - Creating the files for the add-on

    We need those files to make all works. Go to yourForum/library/

    Our add-on structure will be like this:

    yourForum
    --library
    ----newProfileTabs
    ------Listener.php

    Make sure you follow this structure, so this tutorial will work for you. Inside the folder "newProfileTabs" create a file called "Listener.php" and leave it there.

    Step 5 - The Code Event Listeners

    We can now create a new Code Event Listener and put this template hook into work. Let's see how.

    Go to your AdminCP>Development>Code Event Listeners. Click in the button "+Create New Code Event Listener".

    You'll see this:

    3.PNG

    Lets fill all the information.

    Listen to Event: Whenever you want to use the template hook system, you'll select in the "Listen to Event" the "template_hook". So, select "template_hook". This is the explanation you go it:

    Execute Callback:: Do not fill this yet.

    Callback Execution Order:: Leave the number in there. Do not change.

    Enable Callback Execution: Make sure this is checked. So your Callback function will work.

    Description: You can put whatever you want in here. Make sure you put something that you can undestand after. I will put "Listen to some template hooks".

    Add-on: Select our add-on, the "newProfileTabs"

    STOP! DONT HIT SAVE!

    We need to fill the information with the Execute Callback. But we need to create our method before, right? Ok. I made this tutorial this way to make sure that the method we need to create will be understood by you.

    In the page we are, we got the "Callback signature". Its located under the event description. See here:

    Code:
    $hookName, &$contents, array $hookParams, XenForo_Template_Abstract $template 
    That all is the parameters we need to use in our function. Write down in some place. We will use it in the next step.

    Leave the page open. Do not close.

    Step 6 - Our file Listener.php

    Remember in the begining of this tutorial we discover the name of the template hook?

    To help you:
    template hook:member_view_tabs_heading
    callback signature: $hookName, &$contents, array $hookParams, XenForo_Template_Abstract $template

    Open your file "Listener.php" and add:
    (you can ignore the comments)

    PHP:
    <?php
    //Look! The name of the class follow our directory structure!
    //nameOfTheAddon_File (without the ".php" for sure!)
    //This can be: nameOfTheAddon_Folder_File or nameOfTheAddon_Folder_Folder_File
    class newProfileTabs_Listener
    {
        
    //Our callback signature! We are using here! Look:
        
    public static function template_hook ($hookName, &$contents, array $hookParamsXenForo_Template_Abstract $template)
        {
            
    //Yey! its our template hook!
            
    if ($hookName == 'member_view_tabs_heading')
            {
                
    //Our tab! We will do somethin better, hang on.
                
    $contents .= '<li><a href="{$requestPaths.requestUri}#ourTab">Our Tab</a></li>';
            }
        }
    }
    ?>
    Save.

    Step 7 - Backing to the Code Event Listeners

    Open back the page of the Code Events Listeners we created before. Remember you didnt hit the button "Save Event Listener", so the event listener is not working yet.

    Now we have our method and class created we can fill the field "Execute Callback".

    See:

    Execute Callback: The first input is for the name of the class. Our class got the name "newProfileTabs_Listener". So put it on.
    The second input is the name of the method that we will use for callback. We gave the name of "template_hook". So put it on.

    Then, you will got something like this:

    4.PNG

    Click "Save Event Listener". Should be no errors. All right so far?

    Step 8 - Omg! Its working!

    Go to some profile in your forum. See, our new tab is created!

    5.PNG

    Try to click!

    ...

    Oh, nothing load, right? This is sad!

    "But but i want my tab working!"
    "want my money back"

    Wait! There is more!

    We have achieved our first goal: to create the tab. Now lets create the content.

    Step 9 - Creating the content

    Remember, there at the beginning of this tutorial we found the name of the template hook we want to use, right? Now we want some other template hook to put the content in!

    The template is the same: member_view. You can re-open this template (if you alredy have closed).

    Scroll to the bottom of the template (member_view) and you will find what we are looking for:

    Code:
    <xen:if is="{$warningCount}">
    <li id="warnings" class="profileContent" data-loadUrl="{xen:link members/warnings, $user}">
    {xen:phrase loading}...
    <noscript><a href="{xen:link members/warnings, $user}">{xen:phrase view}</a></noscript>
    </li>
    </xen:if>
    <xen:hook name="member_view_tabs_content" params="{xen:array 'user={$user}'}" />
    
    Saw? The hook:

    Code:
    <xen:hook name="member_view_tabs_content" params="{xen:array 'user={$user}'}" />
    Name: member_view_tabs_content

    We will use this hook to insert the content of our tab in the profile page. Write down somewhere, we will use it.
     
    Zmolahah, Trekkan, iXanon and 7 others like this.
  2. Fuhrmann

    Fuhrmann Well-Known Member

    Step 10 - Back to the Listener.php file

    In the Listener.php file, you will add some extra line.

    Remember this?

    PHP:
    if ($hookName == 'member_view_tabs_heading')
    {
        
    //We will do something later. Hang on.
        
    $contents .= '<li><a href="{$requestPaths.requestUri}#ourTab">Our Tab</a></li>';
    }
    We now will add other conditional to get the hook name. Below the first conditional, add this:

    PHP:
    //Our second template hook name!
    if ($hookName == 'member_view_tabs_content')
    {
        
    $contents .= '<li id="ourTab" class="profileContent">
                      <div class="section">Your content</div>
                      </li>'
    ;
    }
    Your file will contains this:

    PHP:
    <?php
    //Look! The name of the class follow our directory structure!
    //nameOfTheAddon_File (without the ".php" for sure!)
    //This can be: nameOfTheAddon_Folder_File or nameOfTheAddon_Folder_Folder_File
    class newProfileTabs_Listener
    {
        
    //Our callback signature! We are using here! Look:
        
    public static function template_hook ($hookName, &$contents, array $hookParamsXenForo_Template_Abstract $template)
        {
            
    //Yey! its our template hook!
            
    if ($hookName == 'member_view_tabs_heading')
            {
                    
    //We will do something later. Hang on.
                    
    $contents .= '<li><a href="{$requestPaths.requestUri}#ourTab">Our Tab</a></li>';
            }
            if (
    $hookName == 'member_view_tabs_content')
            {
                
    $contents .= '<li id="ourTab" class="profileContent">
                            <div class="section">This is the content of our tab</div>
                            </li>'
    ;
            }
        }
    }
    ?>
    Step 11 - Its working! Go to the profile page again, in your forum. Click the "Our Tab". We got this:

    6.PNG

    All done. That should do the job.

    Step 12 - Adittionals

    To make your code cleaner and your addon more organized, lets change some things.
    Instead of adding the code of our tab directly through the Listener.php file, we'll create two templates: one for the Tab Heading and other for the Content of the tab.

    Step 13 - Creating those templates (its easy!)

    Go to your AdminCP>Appearance>Templates and hit the button "+Create New Template".
    The name we will use in this tutorial for tab heading will be "newProfileTab_ourTab"
    So put the name.

    Next its the code for our template. We will add the code that is currently in the Listener.php file.
    So will be:

    PHP:
    <li><a href="{$requestPaths.requestUri}#ourTab">Our Tab</a></li>
    In the Add-on select the name of our add-on "New Profile Tabs". Hit "Save all changes".
    Now lets create the content.

    Same process:

    "+Create new Template"
    Fill with the name (we will use newProfileTab_ourTab_content)
    The template:

    PHP:
    <li id="ourTab" class="profileContent">
          <
    div class="section">This is the content of our tab</div>
    </
    li>
    Chose the Add-on.

    Hit Save all changes.

    Ok, so now we have to new templates, right?

    -> newProfileTab_ourTab
    -> newProfileTab_ourTab_content

    Lets use them!

    Step 14 - Lets use them!

    We have created the new templates for a reason. We will change the Listener.php file so instead of the direct code of our template is loaded from the Listener.php we will use the templates we have.
    This is what your file will looks like:
    (i have changed the conditionals "if" to "switch" i preferr)

    PHP:
    <?php
    class newProfileTabs_Listener
    {
        public static function 
    template_hook ($hookName, &$contents, array $hookParamsXenForo_Template_Abstract $template)
        {
            
    //Swiiitch!
            
    switch ($hookName//the hookname
            
    {
                
    //first template hook
                
    case 'member_view_tabs_heading':
                    
    //Get our template!
                    
    $ourTemplate $template->create('newProfileTab_ourTab'$template->getParams());
                    
    //Render
                    
    $rendered $ourTemplate->render();
                    
    //Put the rendered template in the contents.
                    
    $contents .= $rendered;
                    break;
                
    //second template hook
                
    case 'member_view_tabs_content':
                    
    //Get our template!
                    
    $ourTemplate $template->create('newProfileTab_ourTab_content'$template->getParams());
                    
    //Render
                    
    $rendered $ourTemplate->render();
                    
    //Put the rendered template in the contents.
                    
    $contents .= $rendered;
                    break;
            }
        }
    }
    ?>
    We are now using templates to make our own profile tabs! Thats so cool...
    ...but still not finished!
    Before we insert our templates in the forum using templates hooks, we need to pre load them.

    Next step you will learn how.

    Step 15 - Pre loading templates

    To pre load a template, we need to use a Code Event Listener called "template_create".
    So go to your AdminCP>Development>Code Event Listeners and hit "+Create New Code Event Listener".
    It should open the same screen we use to make the other Listener. So:

    Listen to Event: Here it is. We will use now the template_create event.

    See the Callback signature? Copy it. We will use in the next step.

    Fill Description and select the Add-On. The same thing before. Do not hit save because we do not have our function to listen this event yet. Leave the page open. Go to the next step.

    Step 16 - Creating the function

    Open the Listener.php and add this code:

    PHP:
    //Our callback signature!
    public static function template_create($templateName, array &$paramsXenForo_Template_Abstract $template)
    {
        switch (
    $templateName) {
            case 
    'member_view':
                
    $template->preloadTemplate('newProfileTab_ourTab');
                
    $template->preloadTemplate('newProfileTab_ourTab_content');
                break;
        }
    }
    Whenever the template "member_view" is created the system will pre load our two templates: the newProfileTab_ourTab and the newProfileTab_ourTab_content.
    This is what your file looks like:

    PHP:
    <?php
    class newProfileTabs_Listener
    {
        
    //Our callback signature!
        
    public static function template_create($templateName, array &$paramsXenForo_Template_Abstract $template)
        {
            switch (
    $templateName) {
                case 
    'member_view':
                
    $template->preloadTemplate('newProfileTab_ourTab');
                
    $template->preloadTemplate('newProfileTab_ourTab_content');
                break;
            }
        }

        
    //Our callback signature! We are using here! Look:
        
    public static function template_hook ($hookName, &$contents, array $hookParamsXenForo_Template_Abstract $template)
        {
            
    //Swiiitch!
            
    switch ($hookName//the hookname
            
    {
                
    //first hook
                
    case 'member_view_tabs_heading':
                    
    //Get our template!
                    
    $ourTemplate $template->create('newProfileTab_ourTab'$template->getParams());
                    
    //Render
                    
    $rendered $ourTemplate->render();
                    
    //Put the rendered template in the contents.
                    
    $contents .= $rendered;
                    break;
                
    //second hook
                
    case 'member_view_tabs_content':
                    
    //Get our template!
                    
    $ourTemplate $template->create('newProfileTab_ourTab_content'$template->getParams());
                    
    //Render
                    
    $rendered $ourTemplate->render();
                    
    //Put the rendered template in the contents.
                    
    $contents .= $rendered;
                    break;
            }
        }
    }
    ?>
    Save it!

    Step 17 - Saving the new event listener

    Go back to the page of the event listener that we didnt save (template_create).

    Fill the Execute Callback.

    First field: name of our class "newProfileTabs_Listener"

    Second field: name of our method "template_create"

    That's it! Our add-on to insert new tabs in the profile page is done!
    In the next tutorial i will be teaching how to add more tabs and use some params!
    Thanks!
    (I am stil learning so this tutorial is based in what i have learned so far)



    PART 2 HERE

    PART 3 HERE


    PART 4 HERE
     
  3. rowedf

    rowedf Active Member

    This is a great tutorial. I like the teaching process you implemented instead of just "do this, this, and this".

    Thanks. I look forward to seeing some parameters (i.e. membergroup secruity, etc).
     
    Fuhrmann likes this.
  4. Fuhrmann

    Fuhrmann Well-Known Member

    You're welcome. Next tutorial i will teach how to use some parameters in the tabs contents. If you have any doubts, just ask! :)
     
  5. Floris

    Floris Guest

    Excellent tutorial, thumbs up.
     
    Fuhrmann likes this.
  6. James

    James Well-Known Member

    Great tutorial. In step 3, you can find the template by looking for the div with an ID of content.
    template-find.png
     
    mrGTB and Fuhrmann like this.
  7. Russ

    Russ Well-Known Member

    Can't wait to try this, thanks alot, this is exactly what I've been looking for.
     
    Fuhrmann likes this.
  8. Floris

    Floris Guest

    I've turned this into a plugin so users can see the end result.
    I am ready to build it into a .zip and release it here.
     
    Fuhrmann likes this.
  9. Fuhrmann

    Fuhrmann Well-Known Member

    That's so good to hear! Thanks Floris.
     
  10. Floris

    Floris Guest

  11. ibnesayeed

    ibnesayeed Well-Known Member

    Yet another reason for me to start Xen coding. Very nicely done tutorial. :)
     
    Fuhrmann likes this.
  12. DaveL

    DaveL Well-Known Member

    Brilliant, thank you :)

    Kept reading over and over, but it wasnt until I sat down and actually done it that it all started to sink in :)
     
    Fuhrmann likes this.
Thread Status:
Not open for further replies.

Share This Page