New display location for custom user fields

abdfahim

Well-known member
Right now we have 3 locations to show custom user fields:
  • Personal Details
  • Contact Details
  • Preferences

I want to add another location, say "My Custom Fields" and add that section in the settings page. Also, would like to have a link to that page in the profile drop down.

upload_2017-7-26_15-59-18.png

upload_2017-7-26_15-57-52.png

upload_2017-7-26_16-59-46.png
 
Last edited:

Aayush

Well-known member
Posting here for people following this thread.

Here is what you have to do:

1. Extend the XenForo_ControllerPublic_Account class using Code Event Listeners. You can read more about extending XenForo classes here https://xenforo.com/community/threads/part-3-creating-a-add-on-to-insert-tabs-in-profile-page-using-hooks.21289/.
Although this uses template hooks. I would advise you not to use that and instead you should use Template modifications.

2. Add a custom method in your extended class with a signature like
Code:
public function actionCustomField()
Now try loading http://yourxfinstall.com/account/custom-field
If you see default XenForo page loaded with an error in between which indicates you that you need to return something then you are on the right track. You would need to return a response view from the function that you just created. You can read the XenForo_ControllerPublic_Account file to find out how other pages work.

3. You'll need to create a new template in XenForo Admin area. You can do that by going on the page which lists all the templates in Admin area and clicking the "Create a template" button there. You need to return this template from the function wrapped in a responseView method from the function you just created in the previous step.

4. Add Template modifications for public facing templates. You'd can do that from http://yourxfinstall.com/admin.php?template-modifications/
You need to add template modifications to the following templates:
account_wrapper - To add a link to your new page in the sidebar.
navigation_visitor_tab - To add a link to the popup when you hover over your username.

I think that should be it for your needs and you can figure the rest out once you get the basic idea of XF Structure.

Source: https://xenforo.com/community/threads/want-to-get-an-idea-of-an-add-on-development.131726/#post-1162699
 

abdfahim

Well-known member
I have done it! Now I have all my custom fields (that has display location = Personal) in a new page http://yourxfinstall.com/account/custom-field.

I also had to add below function to save the custom fields (based on actionPersonalDetailsSave)
Code:
 public function actionCustomFieldSave()
I have now one pending issue. The function actionPersonalDetailsSave in XenForo_ControllerPublic_Account already have code to save the custom fields. Now if I remove all the custom fields from the template account_personal_details (because they are now redundant), will that cause any issue? Obviously, I should not touch the main function actionPersonalDetailsSave to remove the unnecessary lines.

A perfect way would be to add a new display location (the first image of the original post) in the ACP for custom user fields so that I don't need to touch anything on Personal Settings template. Will that be too complex?

Thanks again for the help. I have now my first addon to show a page exactly how I wanted :).
 
Last edited:

abdfahim

Well-known member
Or, is it okay if I manually change the value of display_group in the xf_user_field database table to "mycustomfields" for my intended custom fields:

Code:
UPDATE xf_user_field SET display_group = 'mycustomfields' WHERE field_id IN ('custom_1', 'custom_2', 'custom_3')
And then change my function as

PHP:
public function actionCustomField(){
        .................................................
        .................................................
        $customFields = $this->_getFieldModel()->getUserFields(
            array('display_group' => 'mycustomfields'),
            array('valueUserId' => $visitor['user_id'])
        );
        .................................................
        .................................................
}
Is there any implication of this manual thing other than that it is an ugly solution?
 

Aayush

Well-known member
Or, is it okay if I manually change the value of display_group in the xf_user_field database table to "mycustomfields" for my intended custom fields:

Code:
UPDATE xf_user_field SET display_group = 'mycustomfields' WHERE field_id IN ('custom_1', 'custom_2', 'custom_3')
And then change my function as

PHP:
public function actionCustomField(){
        .................................................
        .................................................
        $customFields = $this->_getFieldModel()->getUserFields(
            array('display_group' => 'mycustomfields'),
            array('valueUserId' => $visitor['user_id'])
        );
        .................................................
        .................................................
}
Is there any implication of this manual thing other than that it is an ugly solution?

This is how I would've done it. It won't have any implications.
 

abdfahim

Well-known member
Hi,

I am facing slight issues with my addon. The display_group of a custom field is not showing the changed value as in database:
upload_2017-7-31_11-33-8.png

In Forum:
upload_2017-7-31_11-33-51.png
All I did was display custom field and type:
Code:
<xen:foreach loop="$userFieldsInfo" key="$fieldId" value="$fieldInfo">
                            {xen:helper userFieldTitle, $fieldId}:{$fieldInfo.display_group}<br>
                            </xen:foreach>
In the addon install.php file, I changed the display_group using following code
Code:
<?php

class AbdFahim_CustomField_Install
{
    public static function install()
    {
        $db = XenForo_Application::get('db');      
       
        try
        {  
            $db->query("ALTER TABLE `xf_user_field` CHANGE `display_group` `display_group` ENUM('personal','contact','preferences','mycustomfields')
                       CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'personal';");
            $db->query("UPDATE xf_user_field SET display_group = 'mycustomfields' WHERE field_id IN ('custom_1', 'custom_2',
                       'custom_3')");
        }
        catch (Zend_Db_Exception $e) {}
    }
}
Do I need to change it anywhere else? Or clear some cache?
 

Aayush

Well-known member
Hi,

I am facing slight issues with my addon. The display_group of a custom field is not showing the changed value as in database:
View attachment 155017

In Forum:
View attachment 155018
All I did was display custom field and type:
Code:
<xen:foreach loop="$userFieldsInfo" key="$fieldId" value="$fieldInfo">
                            {xen:helper userFieldTitle, $fieldId}:{$fieldInfo.display_group}<br>
                            </xen:foreach>
In the addon install.php file, I changed the display_group using following code
Code:
<?php

class AbdFahim_CustomField_Install
{
    public static function install()
    {
        $db = XenForo_Application::get('db');     
      
        try
        { 
            $db->query("ALTER TABLE `xf_user_field` CHANGE `display_group` `display_group` ENUM('personal','contact','preferences','mycustomfields')
                       CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'personal';");
            $db->query("UPDATE xf_user_field SET display_group = 'mycustomfields' WHERE field_id IN ('custom_1', 'custom_2',
                       'custom_3')");
        }
        catch (Zend_Db_Exception $e) {}
    }
}
Do I need to change it anywhere else? Or clear some cache?
Try running this line of code:

Code:
XenForo_Model::create('XenForo_Model_UserField')->rebuildUserFieldCache()
 

abdfahim

Well-known member
Thanks a lot, it worked perfectly after adding that line at the end of install.php and uninstall.php. This is now running in my live site, thanks for your awesome help.

One last thing, though I have not faced any issue so far, can you please have a glance at my save function and advise if I need to add any specific function (like rebuilding cache) for this?

Code:
public function actionCustomFieldSave()
    {
        $this->_assertPostOnly();

        if (!XenForo_Visitor::getInstance()->canEditProfile())
        {
            return $this->responseNoPermission();
        }

        
        $customFields = $this->_input->filterSingle('custom_fields', XenForo_Input::ARRAY_SIMPLE);
        $customFieldsShown = $this->_input->filterSingle('custom_fields_shown', XenForo_Input::STRING, array('array' => true));

        $writer = XenForo_DataWriter::create('XenForo_DataWriter_User');
        $writer->setExistingData(XenForo_Visitor::getUserId());
        $writer->setCustomFields($customFields, $customFieldsShown);

        $writer->preSave();

        if ($dwErrors = $writer->getErrors())
        {
            return $this->responseError($dwErrors);
        }

        $writer->save();

        $redirectParams = array();


        if ($this->_noRedirect())
        {
            $user = $writer->getMergedData();

        }

        return $this->responseRedirect(
            XenForo_ControllerResponse_Redirect::SUCCESS,
            XenForo_Link::buildPublicLink('account/custom-field'),
            null,
            $redirectParams
        );
    }
 

Aayush

Well-known member
Thanks a lot, it worked perfectly after adding that line at the end of install.php and uninstall.php. This is now running in my live site, thanks for your awesome help.

One last thing, though I have not faced any issue so far, can you please have a glance at my save function and advise if I need to add any specific function (like rebuilding cache) for this?

Code:
public function actionCustomFieldSave()
    {
        $this->_assertPostOnly();

        if (!XenForo_Visitor::getInstance()->canEditProfile())
        {
            return $this->responseNoPermission();
        }

       
        $customFields = $this->_input->filterSingle('custom_fields', XenForo_Input::ARRAY_SIMPLE);
        $customFieldsShown = $this->_input->filterSingle('custom_fields_shown', XenForo_Input::STRING, array('array' => true));

        $writer = XenForo_DataWriter::create('XenForo_DataWriter_User');
        $writer->setExistingData(XenForo_Visitor::getUserId());
        $writer->setCustomFields($customFields, $customFieldsShown);

        $writer->preSave();

        if ($dwErrors = $writer->getErrors())
        {
            return $this->responseError($dwErrors);
        }

        $writer->save();

        $redirectParams = array();


        if ($this->_noRedirect())
        {
            $user = $writer->getMergedData();

        }

        return $this->responseRedirect(
            XenForo_ControllerResponse_Redirect::SUCCESS,
            XenForo_Link::buildPublicLink('account/custom-field'),
            null,
            $redirectParams
        );
    }
Looks good to me.
 

NicolasZN

Member
Apologies for the epic bump here, but I haven't had much luck coming up with an add on that will do this.
I'm a bit intimidated diving in to editing Xenforo's core files myself, but am willing to give it a go. However, the linked to resource for extending the class ( https://xenforo.com/community/threads/part-3-creating-a-add-on-to-insert-tabs-in-profile-page-using-hooks.21289/ ) seems like it's part way through a larger tutorial. Should I just start at this step, or do I need to go from the beginning?
 

Aayush

Well-known member
Apologies for the epic bump here, but I haven't had much luck coming up with an add on that will do this.
I'm a bit intimidated diving in to editing Xenforo's core files myself, but am willing to give it a go. However, the linked to resource for extending the class ( https://xenforo.com/community/threads/part-3-creating-a-add-on-to-insert-tabs-in-profile-page-using-hooks.21289/ ) seems like it's part way through a larger tutorial. Should I just start at this step, or do I need to go from the beginning?
You shouldn't ever edit XenForo core files. You should always extend the classes so that in case of future security updates, you can easily upload the updated core files without worrying about the old code.

Also, it would be best to start from part 1. It shouldn't take you more than 1 hour to go through the 4 parts(I guess) and you'll have a sound understanding of how to extend XenForo functionalities.
 
Top