• 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)

Status
Not open for further replies.

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.webp

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

2.webp

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.webp

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:

Called whenever a template hook is encountered (via <xen:hook> tags). You may use this event to modify the final output of that portion of the template. A template hook may pass a block of final template output with it; you may either adjust this text (such as with regular expressions) or add additional output before or after the contents. Some blocks will not pass contents with them; they are primarily designed to allow you to add additional components in those positions.

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 $hookParams, XenForo_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.webp

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.webp

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.
 
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 $hookParams, XenForo_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.webp

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 $hookParams, XenForo_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.

Called whenever the template object constructor is called. You may use this event to modify the name of the template being called, to modify the params being passed to the template, or to pre-load additional templates as needed.

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 &$params, XenForo_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 &$params, XenForo_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 $hookParams, XenForo_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
 
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).
 
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).

You're welcome. Next tutorial i will teach how to use some parameters in the tabs contents. If you have any doubts, just ask! :)
 
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.
 
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 :)
 
Status
Not open for further replies.
Top Bottom