Integration hooks for 2.1

Started by Night09, December 22, 2014, 07:25:06 PM

Previous topic - Next topic

Suki

But that depends on what you need to do, a hook not only can be used to add more buttons, for example, I pretty often use the menu hook to replace existing buttons and on my site I used it to remove the help and some other buttons I don't really need.

To insert a button on x place I often just copy/paste some code from another mod of mine, I know it works so I don't have to worry about it.

As for helper functions, yeah, I'm currently on that path but then again, it all depends on my needs and how I code, the current class I use for my mods is hardly an efficient one or even helpful but it does help me to normalize all my code between mods which in the end allows me to code mods faster and keep em fully maintained.
Disclaimer: unless otherwise stated, all my posts are personal and does not represent any views or opinions held by Simple Machines.

vbgamer45

Yeah I have helper libraries in my code some functions that use over and over again just thinking some probably should be added to SMF itself to make hooks easier.  Arrays can be tricky for people to work with.
Community Suite for SMF - Take your forum to the next level built for SMF, Gallery,Store,Classifieds,Downloads,more!

SMFHacks.com -  Paid Modifications for SMF

Mods:
EzPortal - Portal System for SMF
SMF Gallery Pro
SMF Store SMF Classifieds Ad Seller Pro

Suki

We wouldn't be able to add support to everything a mod author can do with an array though.
Disclaimer: unless otherwise stated, all my posts are personal and does not represent any views or opinions held by Simple Machines.

Night09

Ok so I made a script to run some hook installs but when I run it the hook function page in admin dies and will not show hooks. I remove a hook and the page reappears. Its not simply telling me the hooks broken it cant access the page. It defaults back to 'Routine' until the hook is removed then can access the hooks page again.

I may have a dodgy hook but is it normal for the page to be inaccessable if it doesnt like the hook applied? I thought it would just show the hooks but flag anything it knows is wrong.

Hj Ahmad Rasyid Hj Ismail

That shows some code are broken and needs fixing. If you are using subs.yourmod.php, simply open it, fix the code and save. No need install and uninstall during testing. Install only once. Unless you are trying another integrate hook. Then, you may need to reinstall. If you are not sure, the trick is, put several hook until you decide which one you want to really use or which one is really working. Well, at least that is how I do it.

Night09

I tried to add two. One works and shows a function name and the file path but the second one trying to call the function is where it goes wrong. Im not sure if what im doing is right. I have a sub menu and associated arrays contained in my subs file. Does the menu function need to be in a seperate file or can I contain all the information as functions within one file?

I didnt write any hook based mods for 2.0 so have been playing catchup tbh so I am sorry if im missing something, the guides are all as old as noahs ark. ;)

PS The hook says its active that works.

Illori

instead of us guessing what you may be doing. can you post the code so that someone that understands can help you with the exact example you are using?

vbgamer45

Night09 check out SMF Gallery or SMF Articles I have updated them to use hooks for 2.1
Community Suite for SMF - Take your forum to the next level built for SMF, Gallery,Store,Classifieds,Downloads,more!

SMFHacks.com -  Paid Modifications for SMF

Mods:
EzPortal - Portal System for SMF
SMF Gallery Pro
SMF Store SMF Classifieds Ad Seller Pro

Night09

Quote from: Illori on December 24, 2014, 09:14:22 AM
instead of us guessing what you may be doing. can you post the code so that someone that understands can help you with the exact example you are using?

This is the exact piece of code adding the hooks used last.

<?php
// If SSI.php is in the same place as this file, and SMF isn't defined, this is being run standalone.
if (file_exists(dirname(__FILE__) . '/SSI.php') && !defined('SMF'))
    require_once(
dirname(__FILE__) . '/SSI.php');
// Hmm... no SSI.php and no SMF?
elseif (!defined('SMF'))
    die(
'<b>Error:</b> Cannot install - please verify you put this in the same place as SMF\'s index.php.');

add_integration_function('integrate_pre_include''$sourcedir/Subs-Managewowsettings.php');
add_integration_function('integrate_admin_areas''Managewowsettings');
?>


After applying it the hooks menu fails to show. If I remove one the menu works again.
Quote from: vbgamer45 on December 24, 2014, 10:06:54 AM
Night09 check out SMF Gallery or SMF Articles I have updated them to use hooks for 2.1

Thanks, ive been looking on the mod site for a few working examples. ;)

Arantor

If you're using that file only in admin, might I suggest using integrate_admin_include instead of integrate_pre_include; no need to load the settings code every single page load.

Anyway, if it's breaking, that's implying it's set up properly at the hook level because the hook won't be called if the function doesn't exist, so presumably it must exist.

The real question: what's Subs-Managewowsettings.php looking like?

Night09

Quote from: Arantor on December 24, 2014, 11:09:02 AM
The real question: what's Subs-Managewowsettings.php looking like?

The Subs file is this:

<?php

if (!defined('SMF'))
    die(
'No direct access...');

function 
Managewowsettings()
{
    global 
$context$txt;

    
// Make sure you can be here.
    
isAllowedTo('admin_forum');
    

    
$subActions = array(
        
'char_settings' => 'char_settings',
        
'trade_settings' => 'trade_settings',
        
'achi_settings' => 'achi_settings',
        
'config_settings' => 'config_settings',
    );

    
// Default the sub-action to 'char_settings'.
    
$_REQUEST['sa'] = isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']]) ? $_REQUEST['sa'] : 'char_settings';

    
$context['page_title'] = $txt['wowchar'];

    
// Tabs for browsing the different Warcraft functions.
    
$context[$context['admin_menu_name']]['tab_data'] = array(
        
'title' => $txt['wowchar'],
        
'help' => $txt['wowchar_help'],
        
'description' => $txt['wowchar'],
        
'tabs' => array(
            
'char_settings' => array(
                
'description' => $txt['char_settings'],
            ),
            
'trade_settings' => array(
                
'description' => $txt['trade_settings'],
            ),
            
'achi_settings' => array(
                
'description' => $txt['achi_settings'],
            ),
            
'config_settings' => array(
                
'description' => $txt['config_settings'],
            ),
        ),
    );



    
// Call the right function for this sub-action.
    
call_helper($subActions[$_REQUEST['sa']]);
}

function 
char_settings($return_config false)
{
    global 
$context$txt$sourcedir$scripturl;

    
// Here are all the wowcharacter settings.
    
$config_vars = array(
            
// Are characters allowed?.
            
array('check''char_active'),
            array(
'int''char_maxlevel''postinput' => $txt['char_maxlevel'], 'subtext' => $txt['char_maxlevel2']),
        
'',
            
// Are all character stats allowed?.
            
array('check''char_race'), 
            array(
'check''char_level'),
            array(
'check''char_guild'),
            array(
'check''char_class'),
            array(
'check''char_server'),
            array(
'check''char_gender'),
        
'',
            
// Updating Characters.
            
            
array('check''char_update'),
            array(
'check''char_user_update'),
            array(
'int''char_update2''postinput' => $txt['char_update2'], 'subtext' => $txt['char_update3']),
        
    );



    if (
$return_config)
        return 
$config_vars;

    
// Get the settings template ready.
    
require_once($sourcedir '/ManageServer.php');

    
// Setup the template.
    
$context['page_title'] = $txt['char_settings'];
    
$context['sub_template'] = 'show_settings';

    
// Are we saving them - are we??
    
if (isset($_GET['save']))
    {
        
checkSession();
        
call_integration_hook('char_settings');

        
saveDBSettings($config_vars);
        
$_SESSION['adm-save'] = true;
        
redirectexit('action=admin;area=wowchar;sa=char_settings');
    }

    
// Final settings...
    
$context['post_url'] = $scripturl '?action=admin;area=wowchar;save;sa=char_settings';
    
$context['settings_title'] = $txt['char_settings'];

    
// Prepare the settings...
    
prepareDBSettingContext($config_vars);
}
 function 
trade_settings($return_config false)
{
    global 
$context$txt$sourcedir$scripturl;

    
// Here are all the wowtrade settings.
    
$config_vars = array(
            
// Are characters allowed?.
            
array('check''show_trades'),
            array(
'int''max_trades''postinput' => $txt['max_trades'], 'subtext' => $txt['max_trades']),
        
'',
            
// Are all character stats allowed?.
            
array('check''secondary_trades'), 
        
        
'',
            
// Updating Characters.
            
            
array('check''update_trades'),
            array(
'check''user_update_trades'),
            array(
'int''trade_update''postinput' => $txt['trade_update'], 'subtext' => $txt['char_update3']),
        
    );



    if (
$return_config)
        return 
$config_vars;

    
// Get the settings template ready.
    
require_once($sourcedir '/ManageServer.php');

    
// Setup the template.
    
$context['page_title'] = $txt['trade_settings'];
    
$context['sub_template'] = 'show_settings';

    
// Are we saving them - are we??
    
if (isset($_GET['save']))
    {
        
checkSession();
        

        
saveDBSettings($config_vars);
        
$_SESSION['adm-save'] = true;
        
redirectexit('action=admin;area=wowchar;sa=trade_settings');
    }

    
// Final settings...
    
$context['post_url'] = $scripturl '?action=admin;area=wowchar;save;sa=trade_settings';
    
$context['settings_title'] = $txt['trade_settings'];

    
// Prepare the settings...
    
prepareDBSettingContext($config_vars);
}

//achi settings

function achi_settings($return_config false)
{
    global 
$context$txt$sourcedir$scripturl;

    
// Here are all the wowcharacter settings.
    
$config_vars = array(
            
// Are achhievments allowed?.
            
array('check''show_achi'),
            
        
'',
            
// Are all achievment stats allowed?.
            
array('check''Total_Completed_achi'), 
            array(
'check''General_achi'),
            array(
'check''Quests_achi'),
            array(
'check''Exploration_achi'),
            array(
'check''Player_vs._Player_achi'),
            array(
'check''Dungeons_&_Raids_achi'),
            array(
'check''Professions_achi'), 
            array(
'check''Reputation_achi'),
            array(
'check''Scenarios_achi'),
            array(
'check''World_Events_achi'),
            array(
'check''Pet_Battles_achi'),
            array(
'check''Collections_achi'),
            array(
'check''Garrisons_achi'), 
            array(
'check''Legacy_achi'),
            array(
'check''Feats_of_Strength_achi'),
            
        
'',
            
// Updating acheivments.
            
            
array('check''achi_update'),
            array(
'check''char_achi_update'),
            array(
'int''achi_update2''postinput' => $txt['achi_update2'], 'subtext' => $txt['char_update3']),
        
    );

    

    if (
$return_config)
        return 
$config_vars;

    
// Get the settings template ready.
    
require_once($sourcedir '/ManageServer.php');

    
// Setup the template.
    
$context['page_title'] = $txt['achi_settings'];
    
$context['sub_template'] = 'show_settings';

    
// Are we saving them - are we??
    
if (isset($_GET['save']))
    {
        
checkSession();
        

        
saveDBSettings($config_vars);
        
$_SESSION['adm-save'] = true;
        
redirectexit('action=admin;area=wowchar;sa=achi_settings');
    }

    
// Final settings...
    
$context['post_url'] = $scripturl '?action=admin;area=wowchar;save;sa=achi_settings';
    
$context['settings_title'] = $txt['achi_settings'];

    
// Prepare the settings...
    
prepareDBSettingContext($config_vars);
}

//General settings

function config_settings($return_config false)
{
    global 
$context$txt$sourcedir$scripturl;

    
// Here are all the wowcharacter settings.
    
$config_vars = array(
            
            
// Main settings
            
            
array('text''wowchar_defaultRealmName''35'),
            array(
'check''wowchar_allowCustomRealm'),
            array(
'check''wowchar_europeanRealm'),
            
        
    );

    

    if (
$return_config)
        return 
$config_vars;

    
// Get the settings template ready.
    
require_once($sourcedir '/ManageServer.php');

    
// Setup the template.
    
$context['page_title'] = $txt['config_settings'];
    
$context['sub_template'] = 'show_settings';

    
// Are we saving them - are we??
    
if (isset($_GET['save']))
    {
        
checkSession();
        

        
saveDBSettings($config_vars);
        
$_SESSION['adm-save'] = true;
        
redirectexit('action=admin;area=wowchar;sa=config_settings');
    }

    
// Final settings...
    
$context['post_url'] = $scripturl '?action=admin;area=wowchar;save;sa=config_settings';
    
$context['settings_title'] = $txt['config_settings'];

    
// Prepare the settings...
    
prepareDBSettingContext($config_vars);
}


?>


If I add the menu block directly to the admin template it works ok. The menu block is this:

// Warcraft Modification Settings Menu Array
                'wowchar' => array(
                  'label' => ($txt['wowchar']),
                  'file' => 'Subs-Managewowsettings.php',
                  'function' => 'Managewowsettings',
                  'icon' => 'wowicon',
                  'subsections' => array(
                        'char_settings' => array($txt['char_settings']),                       
                        'trade_settings' => array($txt['trade_settings']),
                        'achi_settings' => array($txt['achi_settings']),
                        'config_settings' => array($txt['config_settings']),
                    ),
                ),     


That placed under the modify message gives me full menu function, icon and links to each of the four sections correctly. It goes wrong when I remove the menu section and try to use a hook instead to place it in the admin menu. I get no menu and the hook issues posted above.

Arantor

Well, the function called directly from the hook is only supposed to deal with changing the menu structure - and NOT any of the other stuff, those should be a separate function... and it's supposed to receive &$admin_areas to modify it.

Night09

Should I contain the menu in a seperate file and call to that instead? I dont get how to make it appear in the correct place though.

Ive been going off this http://wiki.simplemachines.org/smf/Integration_hooks#integrate_admin_areas and http://wiki.simplemachines.org/smf/Add_a_custom_action_using_integration_hooks to get the idea so maybe I need to look again.

Arantor

It's... complicated as to whether it should be a separate file or not.

The way this part must work on some level:
* integrate_admin_include specifies a file that contains a function to extend the menu
* said function accepts the menu array via &$admin_areas (the & indicates 'this function is going to change this variable') and adds to it, indicating another function to be called if the user goes to that section
* this extra function can live in the same file as the menu-changing function if it's small but if it's big or there's a lot of it, it generally should be another file (which you load with the 'file' parameter when extending the menu)

Hj Ahmad Rasyid Hj Ismail

I did something similar in AlternativeMenu Mod. You can take a look on how admin button is added here in its subs file. I reproduce it here:


function AlternativeMenu_Admin(&$admin_areas)
{
global $txt;

// Load the AlternativeMenu language
loadLanguage('AlternativeMenu');

// Add our menu item
$admin_areas['config']['areas']['modsettings']['subsections']['alternativemenu'] = array($txt['AlternativeMenu'],);
}

function AlternativeMenu_Settings(&$subActions)
{
global $txt, $scripturl, $context, $modSettings, $settings;

// Load the AlternativeMenu language
loadLanguage('AlternativeMenu');

// Add AlternativeMenu Settings
$subActions['alternativemenu'] = 'AlternativeMenu';
}

function AlternativeMenu($return_config = false)
{
global $txt, $scripturl, $context, $settings, $sc, $modSettings;

$config_vars = array(
// Mod authors, feel free to modify this alternative menu but don't remove this statement and basic menu!!
array('check', 'alternativemenu'),
'',
array('check', 'altmenu_remove_help'),
array('check', 'altmenu_remove_search'),
array('check', 'altmenu_remove_profile'),
array('check', 'altmenu_remove_pm'),
array('check', 'altmenu_remove_calendar'),
array('check', 'altmenu_remove_mlist'),
array('check', 'altmenu_remove_register'),
'',
array('check', 'altmenu_replace_with_icon'),
);

// Make it even easier to add new settings.
call_integration_hook('integrate_alternative_menu_settings', array(&$config_vars));

if ($return_config)
return $config_vars;

$context['post_url'] = $scripturl . '?action=admin;area=modsettings;save;sa=alternativemenu';
$context['settings_title'] = $txt['altmenu_description'];

// Saving?
if (isset($_GET['save']))
{
checkSession();

$save_vars = $config_vars;

// This line is to help mod authors do a search/add after if you want to add something here. Keyword: FOOT TAPPING SUCKS!
saveDBSettings($save_vars);

// This line is to help mod authors do a search/add after if you want to add something here. Keyword: I LOVE TEA!
redirectexit('action=admin;area=modsettings;sa=alternativemenu');
}

// This line is to help mod authors do a search/add after if you want to add something here. Keyword: RED INK IS FOR TEACHERS AND THOSE WHO LIKE PAIN!
prepareDBSettingContext($config_vars);
}


And for the hook:


'integrate_pre_include' => '$sourcedir/AlternativeMenu.subs.php',
'integrate_menu_buttons' => 'AlternativeMenu_Buttons',
'integrate_admin_areas' => 'AlternativeMenu_Admin',
'integrate_modify_modifications' => 'AlternativeMenu_Settings',


Some globals are actually not needed. This is far from perfect but others can guide you more.

Night09

Thanks for the help guys I think I get what is supposed to be happening now. I will do some testing and let you know how it goes. :)

Night09

Its a strange thing setting this up I must say. Ive had a few drinks so likely gonna kick myself when I find whats up!

I have an admin menu hooked in and it shows the admin button in the right place but no subsections show. If I name an admin template function the same as in the subsection file it throws an error and says already declared. So if it knows to look there and sees the error why isnt the menu showing?  Does the format (subsection code a few posts up)ive used above not work as I figured I should be able to just call the function from the admin file.

How I see it is the admin file shows the menu then the subsections file shows the rest. If the admin menu is hardcoded into the admin template the subsection file works perfectly. Anyway thats where im at for the moment. Ive looked at the other mods files for ideas and dont see any major differences.

Arantor

What is the exact code you are using?

Night09

This code makes the Admin Menu main Menu title appear in the right place. When its clicked though it just gives 'the template cannot be loaded'

<?php
require_once($sourcedir '/Subs-Managewowsettings.php');
function 
Managewowsettings_Admin(&$admin_areas)
{
    global 
$txt$modSettings$scripturl;
    
    
// Load the wow language
    
loadLanguage('Admin');
    
    
// Add our menu item    
    
$admin_areas['config']['areas']['wowchar'] = array($txt['wowchar'],);
}
function 
Managewowsettings_Settings(&$subActions)
{
    global 
$txt$scripturl$context$modSettings$settings;
    
    
// Load the wow language
    
loadLanguage('Admin');
    
    
// Add wow Settings
    
$subActions['Managewowsettings'] = 'Managewowsettings';
}    
?>

Arantor

So, what's the require statement actually doing? Surely, the file should be being loaded by the hook and not explicitly at that point?

Additionally your problem is that you don't set it up correctly in any case.

You're declaring config->areas->wowchar (which would manifest itself as action=admin;area=wowchar) but missing all the stuff you actually need for a first level item like Core Features or Modification Settings.

In fact, if I look back to your previous code... what you actually need is:

function Managewowsettings_Admin(&$admin_areas)
{
    global $txt, $modSettings, $scripturl;
   
    // Load the wow language
    loadLanguage('Admin');
   
    // Add our menu item   
    $admin_areas['config']['areas']['wowchar'] = array(
                  'label' => $txt['wowchar'],
                  'file' => 'Subs-Managewowsettings.php', // this will load the file if not already loaded
                  'function' => 'Managewowsettings', // this is the function that will be called to carry out the dreaded deed itself
                  'icon' => 'wowicon',
                  'subsections' => array(
                        'char_settings' => array($txt['char_settings']),                       
                        'trade_settings' => array($txt['trade_settings']),
                        'achi_settings' => array($txt['achi_settings']),
                        'config_settings' => array($txt['config_settings']),
                    ),
                ),
    );

Advertisement: