Integration hooks: Difference between revisions From Online Manual

Jump to: navigation, search
 
(67 intermediate revisions by 11 users not shown)
Line 1: Line 1:
=Integration Hooks and You=
{{TOCright}}
<!-- Summary: What is an integration hook.  Briefly -- the gist (without details) of how you hook into them) -->
<!-- First: What is an Integration Hook -->A SMF integration hook is a single line of code that calls one or more functions from a list stored in [[$modSettings]]. This means that a modder can cause some new code to be run at that point, without changing the core code. It means modders need not worry that some other mod might already have altered the code they want to change. The introduction of integration hooks to SMF has the potential to radically simplify the task of creating and installing many types of mods, and creating bridges to third-party code. '''Integration hooks are only available in SMF version 2.0 and onwards!''' A mod's installation package can permanently store its list of hook functions on the database, and specify files to load.  A mod can also add integration hook functions from within its code.


People hear the phrase "integration hook" and figure it's something SMF can do to bridge to third party code, and they're right.
==Using Integration Hooks==
Integration Hooks might seem subtle and mysterious, because it makes the code more dynamic. Anyone reading through the code will have to know the contents of $modSettings in order to know what code is going to be executed at a hook. The concept is simple, though. Just as $modSettings has been used to store all kinds of settings, it is now being used to store the names of functions to execute when an integration hook is called. <!--
  First: What is an Integration Hook-->Most integration hooks appear in the code as a call to '''call_integration_hook'''.
{{code|function call_integration_hook('name', array(&$param1, &$param2));}}
Where ''''name'''' is the name of the integration hook, as given in the list below, and the '''array''' contains all the parameters to be passed to any integration hook functions that may have been added to the named hook. Because these parameters are passed with the '''&$''' syntax, the parameters are available to be modified by the integration hook functions. In order to take advantage of this, the function definitions must also use the '''&$''' syntax for receiving the parameters
{{code|function my_integration_hook_function(&$param1, &$param2){.....} }}
Before calling each integration hook function, '''call_integration_hook''' will check whether that function is callable. If not, it will silently skip that function.


Sadly it's one of the more subtle and underused features, because actually it's kinda cool. This is one of the more powerful features of SMF, however, and you should not expect this to be particularly simple - because it's not a simple thing it's doing
The same function can be added to multiple hooks, but cannot be added more than once to the same hook. It is important to choose unique function names, perhaps by using the Mod name (or an abbreviation) as a prefix, in order to decrease the likelihood that some other mod writer will someday create a function of the same name.


----
Only one of the integration hooks is not implemented with call_integration_hook. This is the hook 'integrate_pre_load'. This hook simply includes all the files that have been added to the hook.


Most modders will be familiar with the idea of $modSettings, a store of various variables used by SMF. Well, the integration hooks as far as the modder/developer is concerned are just more entries in $modSettings, meaning you can reference them happily in the settings table, without touching the core code.
<!-- Second: HOW, WHEN, and WHERE is it actually possible to add an integration hook function, without altering any core code? -->
One of the first mods to take advantage of integration hooks, SlammedDime's SimpleSEF mod, makes only a few edits to the core code, simply to add admin options.  The rest of the work is done using integration hooks to load the main SimpleSEF file.


Why is that so important? Taking a specific example of the benefits. SlammedDime's SimpleSEF mod makes several edits to SMF's code - but if you look at the parsing instructions, they are limited to Admin.php and ManageSettings.php (and language files).
Mod writers would generally do this in an installation script that runs during mod install - like SimpleSEF does. To avoid overwriting any settings already there, use add_integration_function. If it's a one-off thing, use phpMyAdmin and add a new row to, or modify an existing row in the {db_prefix}settings table.  


Take another look at the parse instructions for the mod... it's only adding admin options, so how does the rest of it work?!
<!-- Third: Where can you store your functions, and how will the forum find them --><!-- preload, file names
-->The hook 'integrate_pre_load' is designed to pre-load files containing integration hook function definitions. By adding your file to this hook at install time, you can ensure that all your integration hook functions will be loaded on every page of the forum.


That's where integration hooks come in. SlammedDime calls the integration hooks to load the main SimpleSEF file and to make it work - and so it doesn't have to modify the core code, which if used carefully simplifies a lot of things for larger or more intricate mods! It's certainly a useful tool in the arsenal of modding and definitely if you plan to integrate with another system.
<!-- Fourth: Order, conflict, removal--><!-- Can I change the order in which multiple functions are executed on the same hook?  What happens when you try to add another function with the same name! What if the two functions are from different source files? What happens if you remove a function from a hook! What happens if you remove somebody else's function from a hook!  --><!--


----
--><!-- Fifth: Detecting and dealing with function hook problems--><!-- How can I find out if my function is not hooked? Can my mod detect if, say, the security part has gone missing, and disable itself? What if I accidentally remove another mod's hook function? What if someone else accidentally removes a hook function? Can I provide a way to check for and re-add my hook functions, if necessary? --><!--


Happy integrating!
-->
===Adding to hooks===
====add_integration_function====
{{code|add_integration_function ($hook_name, $hook_executes, $make_permanent);}}
Depending on the $hook_name used, the value of <code>$hook_executes</code> should be either <code>function_name</code> or a <code>file_path</code>. If $make_permanent is '''TRUE''', the change is saved on the database and the $modSettings cache (if caching is used). If $make_permanent is '''FALSE''', no changes are made to the database or the cache.
A modwriter working on a mod called SimplyPerfect might add something like the following to the mod's install.php file:
{{code
|add_integration_function('integrate_pre_include', '$sourcedir/Subs-SimplyPerfect.php',TRUE);
add_integration_function('integrate_actions','SimplyPerfect_actions',TRUE);
add_integration_function('integrate_bbc_codes','SimplyPerfect_bbc_codes',TRUE);}}
====remove_integration_function====
{{code|remove_integration_function($hook_name, $function_name);}}
This function removes an integration hook (temporary or permanent) from $modSettings, from the database, and from the $modSettings cache.
A mod which needs to temporarily add some novel BBC codes on a special page could use:
{{code
|add_integration_function('integrate_bbc_codes','SimplyTemporary_bbc_codes',FALSE);
...
remove_integration_function('integrate_bbc_codes','SimplyTemporary_bbc_codes');
}}
==List of Integration Hooks==
So, what are the hooks and how do you use them?  
So, what are the hooks and how do you use them?  


Line 35: Line 75:


For example if a hook states that it sends $value1, $value2 and you want to be able to modify those in your function myfunc(), the specification would be:
For example if a hook states that it sends $value1, $value2 and you want to be able to modify those in your function myfunc(), the specification would be:
                function myfunc(&$value1, &$value2)
{{code|function myfunc(&$value1, &$value2)}}
 
 
== General hooks ==
 
=== integrate_output_error ===
Called from: Errors.php, just after the error itself has been logged but before it has been output to the user.
 
Purpose: To allow reformatting of the error message, prior to notification to user, or perhaps to log or process in an outside system (e.g. sending an email to administrators on certain types of error occurring)
 
Accepts: 1 function name.
 
Sends: $message, $error_type, $error_level, $file, $line
 
$message is the message text itself.
$error_type is the SMF category of an error, e.g. General (general), undefined variables/indexes (undefined_vars), user errors like forgotten passwords (user), database/query errors (database).
$error_level is the PHP error level ident. See the PHP manual for the values this is.
$file is the filename this occurred in (full server path).
$line is the line number of the error.
 
=== integrate_pre_include ===
Called from: Load.php, just after $modSettings has been loaded, which is very, very early on in SMF processing.
 
Purpose: Allows you to load a single file of PHP source, of your own code. Can be used for other integration functions, as it will be loaded on every single page load.
 
Accepts: 1 filename. The string should contain a path to the file specified with $boarddir, e.g. a file called MyFile.php in Sources would normally be $boarddir/Sources/MyFile.php. Note that the function checks the file exists before it attempts to load it - silently aborting if not found.
 
Sends: No parameters, just looks for the file and if found, loads it.
 
=== integrate_pre_load ===
Called from: Load.php, just after $modSettings has been loaded, which is very, very early on in SMF processing - immediately after integrate_pre_include is checked.
 
Purpose: Allows you to call one or more functions before general SMF processing begins. These can be any defined functions, though it is entirely possible that they are defined in the file loaded by integrate_pre_include.
 
Accepts: 1 function name.
 
Sends: No variables, just calls the function - after verifying the function exists.
 
=== integrate_whos_online ===
Called from: Who.php, if index.php was the loaded page of the user but it's because something else with integration is happening.
 
Purpose: To be able to add listed actions to Who's Online from integrated apps.
 
Accepts: 1 function name.
 
Sends: $actions array from Who.php which will basically be the components of the URL, e.g. index.php?action=page;sa=something results in $actions being array('action' => 'page', 'sa' => 'something') which the integrated function can use to identify what the action really is.
 
=== integrate_egg_nog ===
Called from: ViewQuery.php, before the query log (full page) is built.
 
Purpose: To be able to add any pre-processing to the query log that may be necessary prior to outputting. Will be of limited use.
 
Accepts: 1 function name.
 
Sends: No variables, just calls the function(s) - after verifying the function exists.
 
=== integrate_load_theme ===
Called from: Load.php, at the end of loadTheme(), to load any information that potentially affects top level loading of the theme itself.
 
Purpose: Designed to modify the layers to be loaded during page generation, for example to avoid calling the 'html' layer if the page is part of a CMS output (where there will already be a similar layer). Orstio expands on it a little more, covering off my initial theory that it was for exporting data to a CMS, rather than its actual use of pulling from.
 
Accepts: 1 function name.
 
Sends: No variables, just calls the function - after verifying the function exists.
 
 
== Log in/log out ==


=== integrate_verify_user ===
=== Include files ===
Called from: Load.php, loadUserSettings(), as the first option.
==== integrate_admin_include ====
{{parmdesc
|sep=&#58; <!-- dont change to : -->
|Called from|d1=Admin.php, just after $admin_areas has been filled and before the call to the [[#integrate_admin_areas]] hook.
|Purpose|d2=Allows for example loading files that create new admin sections (used by the hook integrate_admin_areas) or more in general loading files that are needed only in the administration section.
|Accepts|d3=A string containing a path to a file to load. Certain identifiers can be used which include:{{parmdesc
  |highlight=no
  |$boarddir|d1=translates to the absolute path to your forum, such as /var/www/smf
  |$sourcedir|d2=points to the Sources directory which normally would reside inside SMF's home directory
  |$themedir|d3=points to the directory of the user's current theme}}
|Sends|d4=No parameters, just looks for the file and loads it if found. If the file does not exist, the function silently skips the call and no error is produced.
}}


Purpose: To attempt to log in from external app first, by reusing login credentials; this is taken in preference to either cookie or session details.
==== integrate_pre_include ====
{{parmdesc
|sep=&#58; <!-- dont change to : -->
|Called from|d1=Load.php, just after $modSettings has been loaded, which is very, very early on in SMF processing.
|Purpose|d2=Allows you to load a single file of PHP source of your own code. Can be used for other integration functions, as it will be loaded on every single page load.
|Accepts|d3=A string containing a path to a file to load. Certain identifiers can be used which include: {{parmdesc
  |highlight=no
  |$boarddir|d1=translates to the absolute path to your forum, such as /var/www/smf
  |$sourcedir|d2=points to the Sources directory which normally would reside inside SMF's home directory}}
|Sends|d4=No parameters, just looks for the file and loads it if found. If the file does not exist, the function silently skips the call and no error is produced.
|Example|d5=To include a file called MyFile.php in Sources, the syntax would be <code>$sourcedir/MyFile.php</code>.
}}


Accepts: 1 function name.
==== integrate_theme_include ====
{{parmdesc
|sep=&#58; <!-- dont change to : -->
|Called from|d1=Load.php, just after the theme has been initialized and before the call to the [[#integrate_load_theme]] hook.
|Purpose|d2=Allows loading files needed by the integrate_load_theme hook.
|Accepts|d3=A string containing a path to a file to load. Certain identifiers can be used which include:{{parmdesc
  |highlight=no
  |$boarddir|d1=translates to the absolute path to your forum, such as /var/www/smf
  |$sourcedir|d2=points to the Sources directory which normally would reside inside SMF's home directory
  |$themedir|d3=points to the directory of the user's current theme}}
|Sends|d4=No parameters, just looks for the file and loads it if found. If the file does not exist, the function silently skips the call and no error is produced.
}}


Sends: No variables, just calls the function - after verifying the function exists.
=== General hooks ===


Unlike other functions, this hook explicitly requires a return value - few other hook functions handle return values. The return value is cast to an integer to represent user id; 0 = not logged in and to refer to cookie then session, otherwise it represents the user id.
====integrate_actions====
{{parmdesc
|sep=&#58; <!-- dont change to : -->
|Called from|d1=index.php, just after the creation of the ''[[action]]'' array
|Purpose|d2=To allow add or remove actions from the action array.
|Accepts|d3=1 function name.
|Sends|d4=$actionArray, this is the array containing all the actions provided by SMF. The structure of the array is: {{code|1=<nowiki></nowiki> 'myaction' => array('ActionFile.php', 'action_function'),}}
where:{{parmdesc
  |sep=&nbsp;-
  |highlight=no
  |myaction|d1=is the action as it appears in the url (e.g. <nowiki>http://yourforum.tld/forum/index.php?action=myaction</nowiki>)
  |ActionFile.php|d2=is the file containing the function that is called when the action is requested
  |action_function|d3=is the name of the function that will be executed}}
}}


=== integrate_verify_password ===
==== integrate_egg_nog ====
Called from: multiple places
{{parmdesc
Profile.php, ModifyProfile(), to ensure password is valid before modifying profile details that require password confirmation.
|sep=&#58; <!-- dont change to : -->
Security.php, validateSession() twice - once, to ensure password is valid during a regular check, and once to ensure adminstrator's password is correct (i.e. even though we were logged in, we need to reauthenticate e.g. admin panel)
|Called from|d1=ViewQuery.php, before the query log (full page) is built.
|Purpose|d2=To be able to add any pre-processing to the query log that may be necessary prior to outputting. Will be of limited use.
|Accepts|d3=1 function name.
|Sends|d4=No variables, just calls the function(s) - after verifying the function exists.
}}


Purpose: To run any further tests to validate the user supplied password.
==== integrate_load_theme ====
{{parmdesc
|sep=&#58; <!-- dont change to : -->
|Called from|d1=Load.php, at the end of loadTheme(), to load any information that potentially affects top level loading of the theme itself.
|Purpose|d2=Designed to modify the layers to be loaded during page generation, for example to avoid calling the 'html' layer if the page is part of a CMS output (where there will already be a similar layer). Orstio expands on it a little more, covering off my initial theory that it was for exporting data to a CMS, rather than its actual use of pulling from.
|Accepts|d3=1 function name.
|Sends|d4=No variables, just calls the function - after verifying the function exists.
}}


Accepts: 1 function name.
====integrate_load_permissions====
{{parmdesc
|sep=&#58; <!-- dont change to : -->
|Called from|d1=ManagePermissions.php, just after the default permission arrays have been created and populated
|Purpose|d2=To allow modify permissions
|Accepts|d3=1 function name.
|Sends|d4=$permissionGroups, $permissionList, $leftPermissionGroups, $hiddenPermissions, $relabelPermissions
}}


Sends: two variables, representing user name and current unhashed password.
====integrate_menu_buttons====
{{parmdesc
|sep=&#58; <!-- dont change to : -->
|Called from|d1=Subs.php, just after having populated the $menu_buttons array with the standard entries.
|Purpose|d2=To allow modify SMF's [[main menu]]
|Accepts|d3=1 function name.
|Sends|d4=$menu_buttons
}}


Unlike other functions, this hook explicitly requires a return value - not all other hook functions handle return values. The return value is either exactly identical to true if acceptable, or anything else is a fail.
==== integrate_output_error ====
{{parmdesc
|sep=&#58; <!-- dont change to : -->
|Called from|d1=Errors.php, just after the error itself has been logged but before it has been output to the user.
|Purpose|d2=To allow reformatting of the error message, prior to notification to user, or perhaps to log or process in an outside system (e.g. sending an email to administrators on certain types of error occurring)
|Accepts|d3=1 function name.
|Sends|d4=$message, $error_type, $error_level, $file, $line{{parmdesc
  |sep=&nbsp;-
  |highlight=no
  |$message|d1=is the message text itself.
  |$error_type|d2=is the SMF category of an error, e.g. General (general), undefined variables/indexes (undefined_vars), user errors like forgotten passwords (user), database/query errors (database).
  |$error_level|d3=is the PHP error level ident. See the PHP manual for the values this is.
  |$file|d4=is the filename this occurred in (full server path).
  |$line|d5=is the line number of the error.
  }}
}}


=== integrate_validate_login ===
==== integrate_pre_load ====
Called from: LogInOut.php, Login2(), just before actually calling for the user's record in the database.
{{parmdesc
|sep=&#58; <!-- dont change to : -->
|Called from|d1=Load.php, just after $modSettings has been loaded, which is very, very early on in SMF processing - immediately after integrate_pre_include is checked.
|Purpose|d2=Allows you to call one or more functions before general SMF processing begins. These can be any defined functions, though it is entirely possible that they are defined in the file loaded by [[#integrate_pre_include]].
|Accepts|d3=1 function name.
|Sends|d4=No variables, just calls the function - after verifying the function exists.
}}


Purpose: To validate credentials in an external data source as well as with SMF.
==== integrate_whos_online ====
{{parmdesc
|sep=&#58; <!-- dont change to : -->
|Called from|d1=Who.php, if index.php was the loaded page of the user but it's because something else with integration is happening.
|Purpose|d2=To be able to add listed actions to Who's Online from integrated apps.
|Accepts|d3=1 function name.
|Sends|d4=$actions array from Who.php which will basically be the components of the URL, e.g. index.php?action=page;sa=something results in $actions being array('action' => 'page', 'sa' => 'something') which the integrated function can use to identify what the action really is.
}}


Accepts: 1 function name.
=== Log in/log out ===
 
==== integrate_login ====
Sends: three variables: string of user's username, string of password (hashed) or null if not supplied, length of cookie lifetime in minutes
{{parmdesc
 
|sep=&#58; <!-- dont change to : -->
Unlike other functions, this hook explicitly requires a return value - not all other hook functions handle return values. The return value is a string - either "retry" if there was an issue and user needs to try again, or anything else if the hooked function does not have an issue with the supplied details.
|Called from|d1=LogInOut.php, DoLogIn(), almost first instruction in the function - used during user actively logged in (session exists, more validating that than anything else)
 
=== integrate_login ===
Called from:
LogInOut.php, DoLogIn(), almost first instruction in the function - used during user actively logged in (session exists, more validating that than anything else)
Register.php, Register2(), once registration is completed, just before setting up user cookie - so registration will log them in to both SMF and integrated app
Register.php, Register2(), once registration is completed, just before setting up user cookie - so registration will log them in to both SMF and integrated app
|Purpose|d2=To log user in on both integrated code and in SMF at the same time.
|Accepts|d3=1 function name.
|Sends|d4=three variables: string of user's username, string of password (hashed) or null if not supplied, length of cookie lifetime in minutes
}}


Purpose: To log user in on both integrated code and in SMF at the same time.
==== integrate_logout ====
 
{{parmdesc
Accepts: 1 function name.
|sep=&#58; <!-- dont change to : -->
 
|Called from|d1=LogInOut.php, LogOut(), if the user is not a guest, after unsetting some session variables, but before clearing their entry in {db_prefix}log_online. They are, technically, still listed as online when the hook is called.
Sends: three variables: string of user's username, string of password (hashed) or null if not supplied, length of cookie lifetime in minutes
|Purpose|d2=To initiate logout in integrated code.
 
|Accepts|d3=1 function name.
=== integrate_logout ===
|Sends|d4=string representing user's name
Called from: LogInOut.php, LogOut(), if the user is not a guest, after unsetting some session variables, but before clearing their entry in {db_prefix}log_online. They are, technically, still listed as online when the hook is called.
}}
 
Purpose: To initiate logout in integrated code.
 
Accepts: 1 function name.
 
Sends: string representing user's name


=== integrate_reset_pass ===
==== integrate_reset_pass ====
Called from: Lots of places
{{parmdesc
|sep=&#58; <!-- dont change to : -->
|Called from|d1=Lots of places
Profile-Modify.php, authentication(), just before a new password is hashed and about to be inserted into the database (user modifying own password, I think)
Profile-Modify.php, authentication(), just before a new password is hashed and about to be inserted into the database (user modifying own password, I think)
Profile.php, ModifyProfile(), for admin modifying another user's password (I think)
Profile.php, ModifyProfile(), for admin modifying another user's password (I think)
Reminder.php, setPassword2(), for when a user resets their password from reminder email
Reminder.php, setPassword2(), for when a user resets their password from reminder email
Reminder.php, SecretAnswer2(), for when a user successfully posts their secret answer
Reminder.php, SecretAnswer2(), for when a user successfully posts their secret answer
Subs-Auth.php, resetPassword(), for when user has forgotten their password and a new one is emailed to them
Subs-Auth.php, resetPassword(), for when user has forgotten their password and a new one is emailed to them.
|Purpose|d2=For notifying external code when a user's password is modified outside of registration.
|Accepts|d3=1 function name.
|Sends|d4=$old_user, $user, $newPassword{{parmdesc
  |sep=&nbsp;-
  |highlight=no
  |$old_user|d1=frequently the same as $user, in some cases it can be an unsanitised version of the username
  |$user|d2=the user name
  |$newPassword|d3=the newly set password, from whatever source
  }}
}}


Purpose: For notifying external code when a user's password is modified outside of registration.
==== integrate_validate_login ====
{{parmdesc
|sep=&#58; <!-- dont change to : -->
|Called from|d1=LogInOut.php, Login2(), just before actually calling for the user's record in the database.
|Purpose|d2=To validate credentials in an external data source as well as with SMF.
|Accepts|d3=1 function name.
|Sends|d4=three variables: string of user's username, string of password (hashed) or null if not supplied, length of cookie lifetime in minutes
}}
Unlike other functions, this hook explicitly requires a return value - not all other hook functions handle return values. The return value is a string - either "retry" if there was an issue and user needs to try again, or anything else if the hooked function does not have an issue with the supplied details.


Accepts: 1 function name.
==== integrate_verify_password ====
{{parmdesc
|sep=&#58; <!-- dont change to : -->
|Called from|d1=multiple places
Profile.php, ModifyProfile(), to ensure password is valid before modifying profile details that require password confirmation.
Security.php, validateSession() twice - once, to ensure password is valid during a regular check, and once to ensure adminstrator's password is correct (i.e. even though we were logged in, we need to reauthenticate e.g. admin panel)
|Purpose|d2=To run any further tests to validate the user supplied password.
|Accepts|d3=1 function name.
|Sends|d4=two variables, representing user name and current unhashed password.
}}
Unlike other functions, this hook explicitly requires a return value - not all other hook functions handle return values. The return value is either exactly identical to true if acceptable, or anything else is a fail.


Sends: $old_user, $user, $newPassword
==== integrate_verify_user ====
 
{{parmdesc
$old_user - frequently the same as $user, in some cases it can be an unsanitised version of the username
|sep=&#58; <!-- dont change to : -->
$user - the user name
|Called from|d1=Load.php, loadUserSettings(), as the first option.
$newPassword - the newly set password, from whatever source
|Purpose|d2=To attempt to log in from external app first, by reusing login credentials; this is taken in preference to either cookie or session details.
 
|Accepts|d3=1 function name.
 
|Sends|d4=No variables, just calls the function - after verifying the function exists.
== Registration, and other user hooks ==
}}
 
Unlike other functions, this hook explicitly requires a return value - few other hook functions handle return values. The return value is cast to an integer to represent user id; 0 = not logged in and to refer to cookie then session, otherwise it represents the user id.
=== integrate_register ===
Called from: Subs-Members.php, just before a user is physically added to the members table. (Same route runs whether it is a conventional user signup or from the admin panel) Validation on details has been carried out by this time.
 
Purpose: Could be used to do further validation of a user, e.g. an external lookup service or other system that the user accounts are linked to. Alternatively could be used to export user details to an external app and sign them up at the same time.
 
Accepts: 1 function name.
 
Sends: $regOptions, $theme_vars
 
$regOptions is a complex array variable. While the full list is in Subs-Members, the most pertinent for most cases are:
$regOptions['username'] = username used to sign up
$regOptions['password'] = password supplied (unhashed!)
$regOptions['email'] = email address supplied on signup
$regOptions['require'] = whether the account is immediate registration ('normal'), email activation ('activation'), COPPA form ('coppa') or admin approval (anything else, notionally 'admin')
$regOptions['memberGroup'] = primary membergroup id to assign (not validated)
 
=== integrate_activate ===
Called from: Multiple places.
ManageMembers.php - during admin approval of members, immediately after approving a member
Profile-Actions.php - activating an account through the profile area
Register.php - activating an account from member activation, immediately after sending the message and immediately before actioning it.
 
Purpose: To ensure a member is activated in a separate system when activated in SMF itself.


Accepts: 1 function name.
=== Registration, and other user hooks ===
==== integrate_activate ====
{{parmdesc
|sep=&#58; <!-- dont change to : -->
|Called from|d1=Multiple places.{{parmdesc
  |sep=&nbsp;-
  |highlight=no
  |ManageMembers.php|d1=during admin approval of members, immediately after approving a member
  |Profile-Actions.php|d2=activating an account through the profile area
  |Register.php|d3=activating an account from member activation, immediately after sending the message and immediately before actioning it.
  }}
|Purpose|d2=To ensure a member is activated in a separate system when activated in SMF itself.
|Accepts|d3=1 function name.
|Sends|d4=string representing the member's name (since that is guaranteed to be consistent, member id is not)
}}


Sends: string representing the member's name (since that is guaranteed to be consistent, member id is not)
==== integrate_change_member_data ====
 
{{parmdesc
=== integrate_delete_member ===
|sep=&#58; <!-- dont change to : -->
Called from: Subs-Members.php, deleteMembers(), immediately before logging that the action has been done (which is before the SMF tables are all updated)
|Called from|d1=Subs.php, updateMemberData(), immediately before processing to add to SMF's own tables.
 
|Purpose|d2=To ensure data is migrated to an external system as well as updating SMF's own tables.
Purpose: To ensure that the external app is updated when a user's account is removed.
|Accepts|d3=1 function name.
 
|Sends|d4=$member_names, $var, $data[$var]{{parmdesc
Accepts: 1 function name.
  |sep=&nbsp;-
 
  |highlight=no
Sends: Number representing user id being deleted from SMF tables.
  |$member_names|d1=an array of the names of members
 
  |$var|d2=name of the variable being updated
=== integrate_change_member_data ===
  |$data[$var]|d3=the new value
Called from: Subs.php, updateMemberData(), immediately before processing to add to SMF's own tables.
  }}
 
}}
Purpose: To ensure data is migrated to an external system as well as updating SMF's own tables.
 
Accepts: 1 function name.
 
Sends: $member_names, $var, $data[$var]
 
$member_names - an array of the names of members
$var - name of the variable being updated
$data[$var] - the new value


NOTE: Not all values are exported through this hook. Only the following will be exported - any other values updated will not.
NOTE: Not all values are exported through this hook. Only the following will be exported - any other values updated will not.
'member_name' - user name
:'member_name' - user name
'real_name' - display name
:'real_name' - display name
'email_address' - email address
:'email_address' - email address
'id_group' - primary user group (only)
:'id_group' - primary user group (only)
'gender' - male/female
:'gender' - male/female
'birthdate' - date of birth
:'birthdate' - date of birth
'website_title' - name of website specified in profile
:'website_title' - name of website specified in profile
'website_url' - address of website specified in profile
:'website_url' - address of website specified in profile
'location' - the location stated in profile
:'location' - the location stated in profile
'hide_email' - whether the user's email address should be considered private (admin visible only)
:'hide_email' - whether the user's email address should be considered private (admin visible only)
'time_format' - the user's time format string for their own time format
:'time_format' - the user's time format string for their own time format
'time_offset' - the user's own time offset (from profile)
:'time_offset' - the user's own time offset (from profile)
'avatar' - gallery or URL specified avatar
:'avatar' - gallery or URL specified avatar
'lngfile' - user's language
:'lngfile' - user's language
 
 
 
== Posting and Personal Messages ==
 
=== integrate_outgoing_email ===
Called from: Subs-Post.php, once an email has been assembled, just before it is inserted into the master email queue.
 
Purpose: Allows you to process or otherwise do something with any email before it is actually sent out.
 
Accepts: 1 function name.
 
Sends: $subject, $message, $headers - listing the email's subject, its main message and the headers (which includes who it's to, who it's from, date, return path and other things)
 
=== integrate_personal_message ===
Called from: Subs-Post.php, sendpm() once the post is sanitised.
 
Purpose: To allow you to send or otherwise preprocess personal messages, you could export them to a third party CMS or similar.
 
Accepts: 1 function name.
 
Sends: $recipients, $from['username'], $subject, $message
 
$recipients - an array containing potentially two elements, 'to' and 'bcc', each of which will be an array of membernames that the message is going to.
$from['username'] - the username sending the message
$subject - PM's subject
$message - message body
 
=== integrate_create_topic ===
Called from: Subs-Post.php, if a post creates a new topic, once all other SMF processing has been done (like stats updates)
 
Purpose: Allows you to add topics to a CMS once they are posted. It would likely be better for something such as the Twitter mod to use this as a point to call, rather than modifying the code itself.
 
Accepts: 1 function name.
 
Sends: $msgOptions, $topicOptions, $posterOptions - the same three variables used to actually create a topic (see the Function Database for createPost for more), once the changes have been applied, so $topicOptions['id'] is the topic's id, $msgOptions['id'] is the id of its message, for example.
 


==== integrate_delete_member ====
{{parmdesc
|sep=&#58; <!-- dont change to : -->
|Called from|d1=Subs-Members.php, deleteMembers(), immediately before logging that the action has been done (which is before the SMF tables are all updated)
|Purpose|d2=To ensure that the external app is updated when a user's account is removed.
|Accepts|d3=1 function name.
|Sends|d4=Number representing user id being deleted from SMF tables.
}}


== Internal functions ==
==== integrate_register ====
{{parmdesc
|sep=&#58; <!-- dont change to : -->
|Called from|d1=Subs-Members.php, just before a user is physically added to the members table. (Same route runs whether it is a conventional user signup or from the admin panel) Validation on details has been carried out by this time.
|Purpose|d2=Could be used to do further validation of a user, e.g. an external lookup service or other system that the user accounts are linked to. Alternatively could be used to export user details to an external app and sign them up at the same time.
|Accepts|d3=1 function name.
|Sends|d4=$regOptions, $theme_vars<br>$regOptions is a complex array variable. While the full list is in Subs-Members, the most pertinent for most cases are:{{parmdesc
  |sep=&nbsp;-
  |highlight=no
  |$regOptions['username']|d1=username used to sign up
  |$regOptions['password']|d2=password supplied (unhashed!)
  |$regOptions['email']|d3=email address supplied on signup
  |$regOptions['require']|d4=whether the account is immediate registration ('normal'), email activation ('activation'), COPPA form ('coppa') or admin approval (anything else, notionally 'admin')
  |$regOptions['memberGroup']|d5=primary membergroup id to assign (not validated)}}
}}


=== integrate_fix_url ===
=== Posting and Personal Messages ===
Called from: News.php, during fix_possible_url().
====integrate_bbc_buttons====
{{parmdesc
|sep=&#58; <!-- dont change to : -->
|Called from|d1=Subs-Editor.php, during create_control_richedit(), just after the $context['bbc_tags'] array has been filled with the information regarding bbcode buttons.
|Purpose|d2=allows modify the appearance of the bbcode buttons in the rich editor (i.e. the editor with all the controls)
|Accepts|d3=1 function name.  
|Sends|d4=$context['bbc_tags']
}}


Purpose: To allow the RSS feeds to have adjustments made for queryless style URLs - and any other URL changes that may be required.
====integrate_bbc_codes====
{{parmdesc
|sep=&#58; <!-- dont change to : -->
|Called from|d1=Subs.php, after all the information regarding the default bbcode tags are loaded in the $codes array
|Purpose|d2=allows easily add or remove or change the behaviour of bbcode tags.
|Accepts|d3=1 function name.  
|Sends|d4=$codes
}}


Accepts: 1 function name.
==== integrate_create_topic ====
{{parmdesc
|sep=&#58; <!-- dont change to : -->
|Called from|d1=Subs-Post.php, if a post creates a new topic, once all other SMF processing has been done (like stats updates)
|Purpose|d2=Allows you to add topics to a CMS once they are posted. It would likely be better for something such as the Twitter mod to use this as a point to call, rather than modifying the code itself.
|Accepts|d3=1 function name.
|Sends|d4=$msgOptions, $topicOptions, $posterOptions - the same three variables used to actually create a topic (see the Function Database for createPost for more), once the changes have been applied, so $topicOptions['id'] is the topic's id, $msgOptions['id'] is the id of its message, for example.
}}


Sends: $val, the original URL
==== integrate_outgoing_email ====
{{parmdesc
|sep=&#58; <!-- dont change to : -->
|Called from|d1=Subs-Post.php, once an email has been assembled, just before it is inserted into the master email queue.
|Purpose|d2=Allows you to process or otherwise do something with any email before it is actually sent out.
|Accepts|d3=1 function name.
|Sends|d4=$subject, $message, $headers{{parmdesc
  |sep=&nbsp;-
  |$subject|d1=listing the email's subject
  |$message|d2=its main message
  |$headers|d3=the headers (which includes who it's to, who it's from, date, return path and other things)}}
}}


Unlike other functions, this hook explicitly requires a return value - almost no other hook function handles return values. The return value is the modified URL.
==== integrate_personal_message ====
{{parmdesc
|sep=&#58; <!-- dont change to : -->
|Called from|d1=Subs-Post.php, sendpm() once the post is sanitized.
|Purpose|d2=To allow you to send or otherwise preprocess personal messages, you could export them to a third party CMS or similar.
|Accepts|d3=1 function name.
|Sends|d4=$recipients, $from['username'], $subject, $message{{parmdesc
  |sep=&nbsp;-
  |highlight=no
  |$recipients|d1=an array containing potentially two elements, 'to' and 'bcc', each of which will be an array of membernames that the message is going to
  |$from['username']|d2=the username sending the message
  |$subject|d3=PM's subject
  |$message|d4=message body}}
}}


=== integrate_redirect ===
===Profile===
Called from: Subs.php, during redirectexit(), immediately prior to physically issuing redirect headers.
====integrate_profile_areas====
{{parmdesc
|sep=&#58; <!-- dont change to : -->
|Called from|d1=Profile.php, just after the definition of the default profile areas (i.e. the menu entries for the profile section)
|Purpose|d2=allows add or modify the menu in the profile area
|Accepts|d3=1 function name.  
|Sends|d4=$profile_areas
}}


Purpose: To allow code to modify the destination or duration before redirect, potentially of any redirect issued in the forum.
===Admin panel===
====integrate_admin_areas====
{{parmdesc
|sep=&#58; <!-- dont change to : -->
|Called from|d1=Admin.php, during AdminMain(), immediately after the default SMF admin areas have been defined.
|Purpose|d2=To allow code to modify the admin menu, adding or removing areas, sections or subsections from it.
|Accepts|d3=1 function name.
|Sends|d4=$admin_areas that is the array of admin areas.
}}


Accepts: 1 function name.
====integrate_core_features====
{{parmdesc
|Called from|d1=ManageSettings.php at the beginning of the function ModifyCoreFeatures, just after the $core_features has been populated with the default SMF's [[Core Features]].
|Purpose|d2=Allows adding new features to the Core Features list in the administration panel.
|Accepts|d3=1 function name
|Sends|d4=$core_features
}}


Sends: $setLocation, $refresh
====integrate_general_mod_settings====
{{parmdesc
|sep=&#58; <!-- dont change to : -->
|Called from|d1=ManageSettings.php, at the beginning of the function ModifyGeneralModSettings
|Purpose|d2=allows add new settings for mods to the page [[Modification Settings]]
|Accepts|d3=1 function name.
|Sends|d4=$config_vars
}}


$setLocation - the final URL it should redirect to, as a full URL.
====integrate_modify_modifications====
$refresh - boolean, whether to send a Refresh header, or more preferably a Location header.
{{parmdesc
|sep=&#58; <!-- dont change to : -->
|Called from|d1=ManageSettings.php, at the beginning of the function ModifyModSettings
|Purpose|d2=allows add new pages for mod settings to the [[Modification Settings]] section.
|Accepts|d3=1 function name.  
|Sends|d4=$subActions, an array where the key is the subaction and the value is the name of the function to be called for the corresponding subaction {{code|1=<nowiki>$subActions = array(
'general' => 'ModifyGeneralModSettings',
);</nowiki>}} To add a new subaction a mod using this hook should contain:{{code|1=<nowiki>$subActions['mysubaction'] = 'mysubaction_function';</nowiki>}}
}}


=== integrate_buffer ===
=== Internal functions ===
Called from: Subs.php, during obExit, used to add functions to be run on the content prior to it being sent to the user, in the spirit of last-minute widespread content changes.
 
Purpose: To allow you to modify the content globally before sending to the user, for example SimpleSEF uses this hook to actually replace links.
 
Accepts: 1+ function names. This function expects a single item or comma separated list, e.g. 'function' or 'function1,function2', the functions will be run in the order specified.
 
Sends: $buffer, a string representing the page as a whole.


==== integrate_buffer ====
{{parmdesc
|sep=&#58; <!-- dont change to : -->
|Called from|d1=Subs.php, during obExit, used to add functions to be run on the content prior to it being sent to the user, in the spirit of last-minute widespread content changes.
|Purpose|d2=To allow you to modify the content globally before sending to the user, for example SimpleSEF uses this hook to actually replace links.
|Accepts|d3=1 function name.
|Sends|d4=$buffer, a string representing the page as a whole.
}}
Unlike other functions, this hook explicitly requires a return value - not all other hook functions handle return values. The return value is the buffer contents.
Unlike other functions, this hook explicitly requires a return value - not all other hook functions handle return values. The return value is the buffer contents.


=== integrate_exit ===
==== integrate_exit ====
Called from: Subs.php, during obExit, used when finally leaving the theme system either in the event of normal execution or fatal errors (i.e. any time a full page is generated that isn't a redirect/attachment)
{{parmdesc
|sep=&#58; <!-- dont change to : -->
|Called from|d1=Subs.php, during obExit, used when finally leaving the theme system either in the event of normal execution or fatal errors (i.e. any time a full page is generated that isn't a redirect/attachment)
|Purpose|d2=To allow you to do final shutdown on external apps, close connections, free resources. Can also be used with portals or other output handling functions.
|Accepts|d3=1 function name.
|Sends|d4=boolean value whether the footer should be output (i.e. footer should be done and not in wireless template)
}}


Purpose: To allow you to do final shutdown on external apps, close connections, free resources. Can also be used with portals or other output handling functions.
==== integrate_fix_url ====
{{parmdesc
|sep=&#58; <!-- dont change to : -->
|Called from|d1=News.php, during fix_possible_url().
|Purpose|d2=To allow the RSS feeds to have adjustments made for queryless style URLs - and any other URL changes that may be required.
|Accepts|d3=1 function name.
|Sends|d4=$val, the original URL
}}


Accepts: 1 function name.
==== integrate_magic_quotes ====
This one isn't actually a function, it's a setting that's relevant. PHP's idea of magic quoting is one of the most irritating ideas it has ever had, to attempt to automatically be able to quote values that are incoming from userland. Unfortunately its behavior is somewhat unpredictable and therefore unreliable.


Sends: boolean value whether the footer should be output (i.e. footer should be done and not in wireless template)
In the process of sanitizing $_GET, SMF does its own clean-up of magic quotes, handling the various types that may be incoming, but other systems do not do this and rely on default PHP behavior. This setting overrides SMF's behavior and returns it to the default.


=== integrate_magic_quotes ===
==== integrate_redirect ====
This one isn't actually a function, it's a setting that's relevant. PHP's idea of magic quoting is one of the most irritating ideas it has ever had, to attempt to automatically be able to quote values that are incoming from userland. Unfortunately its behaviour is somewhat unpredictable and therefore unreliable.
{{parmdesc
|sep=&#58; <!-- dont change to : -->
|Called from|d1=Subs.php, during redirectexit(), immediately prior to physically issuing redirect headers.
|Purpose|d2=To allow code to modify the destination or duration before redirect, potentially of any redirect issued in the forum.
|Accepts|d3=1 function name.
|Sends|d4=$setLocation, $refresh{{parmdesc
  |sep=&nbsp;-
  |highlight=no
  |$setLocation|d1=the final URL it should redirect to, as a full URL.
  |$refresh|d2=boolean, whether to send a Refresh header, or more preferably a Location header.}}
}}


In the process of sanitising $_GET, SMF does its own clean-up of magic quotes, handling the various types that may be incoming, but other systems do not do this and rely on default PHP behaviour. This setting overrides SMF's behaviour and returns it to the default.
{{Developing SMF}}


 
[[Category:Customizing SMF]]
----
[[Category:Integrating SMF]]
 
Right, so that's the hooks. How do you get values into the settings table? How do you fill in the details for the above?
 
Actually, that's fairly easy. If it's a one-off thing, use phpMyAdmin and just add a new row to the smf_settings (or {db_prefix}settings) table. I'm not going to get into the mechanics of that because generally if you're at a level where you understand how these can be used, you probably understand the mechanics of that part too.
 
If it's for a mod, you would generally do this in an installation script that runs during mod install - like SimpleSEF does. Just be careful not to overwrite any settings already there.
 
If you need help on any of the above, please do create a new topic rather than replying here; this isn't meant to be a support thread.
 
Happy integrating!

Latest revision as of 22:58, 25 February 2015

A SMF integration hook is a single line of code that calls one or more functions from a list stored in $modSettings. This means that a modder can cause some new code to be run at that point, without changing the core code. It means modders need not worry that some other mod might already have altered the code they want to change. The introduction of integration hooks to SMF has the potential to radically simplify the task of creating and installing many types of mods, and creating bridges to third-party code. Integration hooks are only available in SMF version 2.0 and onwards! A mod's installation package can permanently store its list of hook functions on the database, and specify files to load. A mod can also add integration hook functions from within its code.

Using Integration Hooks

Integration Hooks might seem subtle and mysterious, because it makes the code more dynamic. Anyone reading through the code will have to know the contents of $modSettings in order to know what code is going to be executed at a hook. The concept is simple, though. Just as $modSettings has been used to store all kinds of settings, it is now being used to store the names of functions to execute when an integration hook is called. Most integration hooks appear in the code as a call to call_integration_hook.

function call_integration_hook('name', array(&$param1, &$param2));

Where 'name' is the name of the integration hook, as given in the list below, and the array contains all the parameters to be passed to any integration hook functions that may have been added to the named hook. Because these parameters are passed with the &$ syntax, the parameters are available to be modified by the integration hook functions. In order to take advantage of this, the function definitions must also use the &$ syntax for receiving the parameters

function my_integration_hook_function(&$param1, &$param2){.....}

Before calling each integration hook function, call_integration_hook will check whether that function is callable. If not, it will silently skip that function.

The same function can be added to multiple hooks, but cannot be added more than once to the same hook. It is important to choose unique function names, perhaps by using the Mod name (or an abbreviation) as a prefix, in order to decrease the likelihood that some other mod writer will someday create a function of the same name.

Only one of the integration hooks is not implemented with call_integration_hook. This is the hook 'integrate_pre_load'. This hook simply includes all the files that have been added to the hook.

One of the first mods to take advantage of integration hooks, SlammedDime's SimpleSEF mod, makes only a few edits to the core code, simply to add admin options. The rest of the work is done using integration hooks to load the main SimpleSEF file.

Mod writers would generally do this in an installation script that runs during mod install - like SimpleSEF does. To avoid overwriting any settings already there, use add_integration_function. If it's a one-off thing, use phpMyAdmin and add a new row to, or modify an existing row in the {db_prefix}settings table.

The hook 'integrate_pre_load' is designed to pre-load files containing integration hook function definitions. By adding your file to this hook at install time, you can ensure that all your integration hook functions will be loaded on every page of the forum.


Adding to hooks

add_integration_function

add_integration_function ($hook_name, $hook_executes, $make_permanent);

Depending on the $hook_name used, the value of $hook_executes should be either function_name or a file_path. If $make_permanent is TRUE, the change is saved on the database and the $modSettings cache (if caching is used). If $make_permanent is FALSE, no changes are made to the database or the cache.

A modwriter working on a mod called SimplyPerfect might add something like the following to the mod's install.php file:

add_integration_function('integrate_pre_include', '$sourcedir/Subs-SimplyPerfect.php',TRUE);
add_integration_function('integrate_actions','SimplyPerfect_actions',TRUE);
add_integration_function('integrate_bbc_codes','SimplyPerfect_bbc_codes',TRUE);

remove_integration_function

remove_integration_function($hook_name, $function_name);

This function removes an integration hook (temporary or permanent) from $modSettings, from the database, and from the $modSettings cache.

A mod which needs to temporarily add some novel BBC codes on a special page could use:

add_integration_function('integrate_bbc_codes','SimplyTemporary_bbc_codes',FALSE);
...
remove_integration_function('integrate_bbc_codes','SimplyTemporary_bbc_codes');


List of Integration Hooks

So, what are the hooks and how do you use them?

This list documents each of the hooks, what it does, and what it expects as input.

Each hook can be defined and set using the names below. e.g. integrate_pre_include would be referenced in $modSettings as $modSettings['integrate_pre_include'], and managed in the settings table under that name too.

Each integration hook has been described in the following manner:

* Called from: - lists which file it's called from, and at what point the hook will be called on your behalf.

* Purpose: - what the hook is designed for and what it can allow you to do.

* Accepts: - what type of input the hook is expecting. In almost every case this will simply be the name of a function to call, though can be a static method of a class. It should be obvious that the function will need to already be loaded and thus available to SMF already - if not, you may need to ensure integrate_pre_include loads it, the main SMF files contain it, or you otherwise ensure it is loaded.

* Sends: - the list of parameters in order that the hook will be sent from SMF. May be no variables, may be many. If the hook sends variables that you may want to modify before your function ends, make sure your function states it wants the variables by reference.


For example if a hook states that it sends $value1, $value2 and you want to be able to modify those in your function myfunc(), the specification would be:

function myfunc(&$value1, &$value2)

Include files

integrate_admin_include

  • Called from: Admin.php, just after $admin_areas has been filled and before the call to the #integrate_admin_areas hook.
  • Purpose: Allows for example loading files that create new admin sections (used by the hook integrate_admin_areas) or more in general loading files that are needed only in the administration section.
  • Accepts: A string containing a path to a file to load. Certain identifiers can be used which include:
    • $boarddir translates to the absolute path to your forum, such as /var/www/smf
    • $sourcedir points to the Sources directory which normally would reside inside SMF's home directory
    • $themedir points to the directory of the user's current theme
  • Sends: No parameters, just looks for the file and loads it if found. If the file does not exist, the function silently skips the call and no error is produced.


integrate_pre_include

  • Called from: Load.php, just after $modSettings has been loaded, which is very, very early on in SMF processing.
  • Purpose: Allows you to load a single file of PHP source of your own code. Can be used for other integration functions, as it will be loaded on every single page load.
  • Accepts: A string containing a path to a file to load. Certain identifiers can be used which include:
    • $boarddir translates to the absolute path to your forum, such as /var/www/smf
    • $sourcedir points to the Sources directory which normally would reside inside SMF's home directory
  • Sends: No parameters, just looks for the file and loads it if found. If the file does not exist, the function silently skips the call and no error is produced.
  • Example: To include a file called MyFile.php in Sources, the syntax would be $sourcedir/MyFile.php.


integrate_theme_include

  • Called from: Load.php, just after the theme has been initialized and before the call to the #integrate_load_theme hook.
  • Purpose: Allows loading files needed by the integrate_load_theme hook.
  • Accepts: A string containing a path to a file to load. Certain identifiers can be used which include:
    • $boarddir translates to the absolute path to your forum, such as /var/www/smf
    • $sourcedir points to the Sources directory which normally would reside inside SMF's home directory
    • $themedir points to the directory of the user's current theme
  • Sends: No parameters, just looks for the file and loads it if found. If the file does not exist, the function silently skips the call and no error is produced.


General hooks

integrate_actions

  • Called from: index.php, just after the creation of the action array
  • Purpose: To allow add or remove actions from the action array.
  • Accepts: 1 function name.
  • Sends: $actionArray, this is the array containing all the actions provided by SMF. The structure of the array is:
    		'myaction' => array('ActionFile.php', 'action_function'),
    
    where:
    • myaction - is the action as it appears in the url (e.g. http://yourforum.tld/forum/index.php?action=myaction)
    • ActionFile.php - is the file containing the function that is called when the action is requested
    • action_function - is the name of the function that will be executed


integrate_egg_nog

  • Called from: ViewQuery.php, before the query log (full page) is built.
  • Purpose: To be able to add any pre-processing to the query log that may be necessary prior to outputting. Will be of limited use.
  • Accepts: 1 function name.
  • Sends: No variables, just calls the function(s) - after verifying the function exists.


integrate_load_theme

  • Called from: Load.php, at the end of loadTheme(), to load any information that potentially affects top level loading of the theme itself.
  • Purpose: Designed to modify the layers to be loaded during page generation, for example to avoid calling the 'html' layer if the page is part of a CMS output (where there will already be a similar layer). Orstio expands on it a little more, covering off my initial theory that it was for exporting data to a CMS, rather than its actual use of pulling from.
  • Accepts: 1 function name.
  • Sends: No variables, just calls the function - after verifying the function exists.


integrate_load_permissions

  • Called from: ManagePermissions.php, just after the default permission arrays have been created and populated
  • Purpose: To allow modify permissions
  • Accepts: 1 function name.
  • Sends: $permissionGroups, $permissionList, $leftPermissionGroups, $hiddenPermissions, $relabelPermissions


integrate_menu_buttons

  • Called from: Subs.php, just after having populated the $menu_buttons array with the standard entries.
  • Purpose: To allow modify SMF's main menu
  • Accepts: 1 function name.
  • Sends: $menu_buttons


integrate_output_error

  • Called from: Errors.php, just after the error itself has been logged but before it has been output to the user.
  • Purpose: To allow reformatting of the error message, prior to notification to user, or perhaps to log or process in an outside system (e.g. sending an email to administrators on certain types of error occurring)
  • Accepts: 1 function name.
  • Sends: $message, $error_type, $error_level, $file, $line
    • $message - is the message text itself.
    • $error_type - is the SMF category of an error, e.g. General (general), undefined variables/indexes (undefined_vars), user errors like forgotten passwords (user), database/query errors (database).
    • $error_level - is the PHP error level ident. See the PHP manual for the values this is.
    • $file - is the filename this occurred in (full server path).
    • $line - is the line number of the error.


integrate_pre_load

  • Called from: Load.php, just after $modSettings has been loaded, which is very, very early on in SMF processing - immediately after integrate_pre_include is checked.
  • Purpose: Allows you to call one or more functions before general SMF processing begins. These can be any defined functions, though it is entirely possible that they are defined in the file loaded by #integrate_pre_include.
  • Accepts: 1 function name.
  • Sends: No variables, just calls the function - after verifying the function exists.


integrate_whos_online

  • Called from: Who.php, if index.php was the loaded page of the user but it's because something else with integration is happening.
  • Purpose: To be able to add listed actions to Who's Online from integrated apps.
  • Accepts: 1 function name.
  • Sends: $actions array from Who.php which will basically be the components of the URL, e.g. index.php?action=page;sa=something results in $actions being array('action' => 'page', 'sa' => 'something') which the integrated function can use to identify what the action really is.


Log in/log out

integrate_login

  • Called from: LogInOut.php, DoLogIn(), almost first instruction in the function - used during user actively logged in (session exists, more validating that than anything else) Register.php, Register2(), once registration is completed, just before setting up user cookie - so registration will log them in to both SMF and integrated app
  • Purpose: To log user in on both integrated code and in SMF at the same time.
  • Accepts: 1 function name.
  • Sends: three variables: string of user's username, string of password (hashed) or null if not supplied, length of cookie lifetime in minutes


integrate_logout

  • Called from: LogInOut.php, LogOut(), if the user is not a guest, after unsetting some session variables, but before clearing their entry in {db_prefix}log_online. They are, technically, still listed as online when the hook is called.
  • Purpose: To initiate logout in integrated code.
  • Accepts: 1 function name.
  • Sends: string representing user's name


integrate_reset_pass

  • Called from: Lots of places Profile-Modify.php, authentication(), just before a new password is hashed and about to be inserted into the database (user modifying own password, I think) Profile.php, ModifyProfile(), for admin modifying another user's password (I think) Reminder.php, setPassword2(), for when a user resets their password from reminder email Reminder.php, SecretAnswer2(), for when a user successfully posts their secret answer Subs-Auth.php, resetPassword(), for when user has forgotten their password and a new one is emailed to them.
  • Purpose: For notifying external code when a user's password is modified outside of registration.
  • Accepts: 1 function name.
  • Sends: $old_user, $user, $newPassword
    • $old_user - frequently the same as $user, in some cases it can be an unsanitised version of the username
    • $user - the user name
    • $newPassword - the newly set password, from whatever source


integrate_validate_login

  • Called from: LogInOut.php, Login2(), just before actually calling for the user's record in the database.
  • Purpose: To validate credentials in an external data source as well as with SMF.
  • Accepts: 1 function name.
  • Sends: three variables: string of user's username, string of password (hashed) or null if not supplied, length of cookie lifetime in minutes

Unlike other functions, this hook explicitly requires a return value - not all other hook functions handle return values. The return value is a string - either "retry" if there was an issue and user needs to try again, or anything else if the hooked function does not have an issue with the supplied details.

integrate_verify_password

  • Called from: multiple places Profile.php, ModifyProfile(), to ensure password is valid before modifying profile details that require password confirmation. Security.php, validateSession() twice - once, to ensure password is valid during a regular check, and once to ensure adminstrator's password is correct (i.e. even though we were logged in, we need to reauthenticate e.g. admin panel)
  • Purpose: To run any further tests to validate the user supplied password.
  • Accepts: 1 function name.
  • Sends: two variables, representing user name and current unhashed password.

Unlike other functions, this hook explicitly requires a return value - not all other hook functions handle return values. The return value is either exactly identical to true if acceptable, or anything else is a fail.

integrate_verify_user

  • Called from: Load.php, loadUserSettings(), as the first option.
  • Purpose: To attempt to log in from external app first, by reusing login credentials; this is taken in preference to either cookie or session details.
  • Accepts: 1 function name.
  • Sends: No variables, just calls the function - after verifying the function exists.

Unlike other functions, this hook explicitly requires a return value - few other hook functions handle return values. The return value is cast to an integer to represent user id; 0 = not logged in and to refer to cookie then session, otherwise it represents the user id.

Registration, and other user hooks

integrate_activate

  • Called from: Multiple places.
    • ManageMembers.php - during admin approval of members, immediately after approving a member
    • Profile-Actions.php - activating an account through the profile area
    • Register.php - activating an account from member activation, immediately after sending the message and immediately before actioning it.
  • Purpose: To ensure a member is activated in a separate system when activated in SMF itself.
  • Accepts: 1 function name.
  • Sends: string representing the member's name (since that is guaranteed to be consistent, member id is not)


integrate_change_member_data

  • Called from: Subs.php, updateMemberData(), immediately before processing to add to SMF's own tables.
  • Purpose: To ensure data is migrated to an external system as well as updating SMF's own tables.
  • Accepts: 1 function name.
  • Sends: $member_names, $var, $data[$var]
    • $member_names - an array of the names of members
    • $var - name of the variable being updated
    • $data[$var] - the new value


NOTE: Not all values are exported through this hook. Only the following will be exported - any other values updated will not.

'member_name' - user name
'real_name' - display name
'email_address' - email address
'id_group' - primary user group (only)
'gender' - male/female
'birthdate' - date of birth
'website_title' - name of website specified in profile
'website_url' - address of website specified in profile
'location' - the location stated in profile
'hide_email' - whether the user's email address should be considered private (admin visible only)
'time_format' - the user's time format string for their own time format
'time_offset' - the user's own time offset (from profile)
'avatar' - gallery or URL specified avatar
'lngfile' - user's language

integrate_delete_member

  • Called from: Subs-Members.php, deleteMembers(), immediately before logging that the action has been done (which is before the SMF tables are all updated)
  • Purpose: To ensure that the external app is updated when a user's account is removed.
  • Accepts: 1 function name.
  • Sends: Number representing user id being deleted from SMF tables.


integrate_register

  • Called from: Subs-Members.php, just before a user is physically added to the members table. (Same route runs whether it is a conventional user signup or from the admin panel) Validation on details has been carried out by this time.
  • Purpose: Could be used to do further validation of a user, e.g. an external lookup service or other system that the user accounts are linked to. Alternatively could be used to export user details to an external app and sign them up at the same time.
  • Accepts: 1 function name.
  • Sends: $regOptions, $theme_vars
    $regOptions is a complex array variable. While the full list is in Subs-Members, the most pertinent for most cases are:
    • $regOptions['username'] - username used to sign up
    • $regOptions['password'] - password supplied (unhashed!)
    • $regOptions['email'] - email address supplied on signup
    • $regOptions['require'] - whether the account is immediate registration ('normal'), email activation ('activation'), COPPA form ('coppa') or admin approval (anything else, notionally 'admin')
    • $regOptions['memberGroup'] - primary membergroup id to assign (not validated)


Posting and Personal Messages

integrate_bbc_buttons

  • Called from: Subs-Editor.php, during create_control_richedit(), just after the $context['bbc_tags'] array has been filled with the information regarding bbcode buttons.
  • Purpose: allows modify the appearance of the bbcode buttons in the rich editor (i.e. the editor with all the controls)
  • Accepts: 1 function name.
  • Sends: $context['bbc_tags']


integrate_bbc_codes

  • Called from: Subs.php, after all the information regarding the default bbcode tags are loaded in the $codes array
  • Purpose: allows easily add or remove or change the behaviour of bbcode tags.
  • Accepts: 1 function name.
  • Sends: $codes


integrate_create_topic

  • Called from: Subs-Post.php, if a post creates a new topic, once all other SMF processing has been done (like stats updates)
  • Purpose: Allows you to add topics to a CMS once they are posted. It would likely be better for something such as the Twitter mod to use this as a point to call, rather than modifying the code itself.
  • Accepts: 1 function name.
  • Sends: $msgOptions, $topicOptions, $posterOptions - the same three variables used to actually create a topic (see the Function Database for createPost for more), once the changes have been applied, so $topicOptions['id'] is the topic's id, $msgOptions['id'] is the id of its message, for example.


integrate_outgoing_email

  • Called from: Subs-Post.php, once an email has been assembled, just before it is inserted into the master email queue.
  • Purpose: Allows you to process or otherwise do something with any email before it is actually sent out.
  • Accepts: 1 function name.
  • Sends: $subject, $message, $headers
    • $subject - listing the email's subject
    • $message - its main message
    • $headers - the headers (which includes who it's to, who it's from, date, return path and other things)


integrate_personal_message

  • Called from: Subs-Post.php, sendpm() once the post is sanitized.
  • Purpose: To allow you to send or otherwise preprocess personal messages, you could export them to a third party CMS or similar.
  • Accepts: 1 function name.
  • Sends: $recipients, $from['username'], $subject, $message
    • $recipients - an array containing potentially two elements, 'to' and 'bcc', each of which will be an array of membernames that the message is going to
    • $from['username'] - the username sending the message
    • $subject - PM's subject
    • $message - message body


Profile

integrate_profile_areas

  • Called from: Profile.php, just after the definition of the default profile areas (i.e. the menu entries for the profile section)
  • Purpose: allows add or modify the menu in the profile area
  • Accepts: 1 function name.
  • Sends: $profile_areas


Admin panel

integrate_admin_areas

  • Called from: Admin.php, during AdminMain(), immediately after the default SMF admin areas have been defined.
  • Purpose: To allow code to modify the admin menu, adding or removing areas, sections or subsections from it.
  • Accepts: 1 function name.
  • Sends: $admin_areas that is the array of admin areas.


integrate_core_features

  • Called from ManageSettings.php at the beginning of the function ModifyCoreFeatures, just after the $core_features has been populated with the default SMF's Core Features.
  • Purpose Allows adding new features to the Core Features list in the administration panel.
  • Accepts 1 function name
  • Sends $core_features


integrate_general_mod_settings

  • Called from: ManageSettings.php, at the beginning of the function ModifyGeneralModSettings
  • Purpose: allows add new settings for mods to the page Modification Settings
  • Accepts: 1 function name.
  • Sends: $config_vars


integrate_modify_modifications

  • Called from: ManageSettings.php, at the beginning of the function ModifyModSettings
  • Purpose: allows add new pages for mod settings to the Modification Settings section.
  • Accepts: 1 function name.
  • Sends: $subActions, an array where the key is the subaction and the value is the name of the function to be called for the corresponding subaction
    $subActions = array(
    	'general' => 'ModifyGeneralModSettings',
    );
    
    To add a new subaction a mod using this hook should contain:
    $subActions['mysubaction'] = 'mysubaction_function';
    


Internal functions

integrate_buffer

  • Called from: Subs.php, during obExit, used to add functions to be run on the content prior to it being sent to the user, in the spirit of last-minute widespread content changes.
  • Purpose: To allow you to modify the content globally before sending to the user, for example SimpleSEF uses this hook to actually replace links.
  • Accepts: 1 function name.
  • Sends: $buffer, a string representing the page as a whole.

Unlike other functions, this hook explicitly requires a return value - not all other hook functions handle return values. The return value is the buffer contents.

integrate_exit

  • Called from: Subs.php, during obExit, used when finally leaving the theme system either in the event of normal execution or fatal errors (i.e. any time a full page is generated that isn't a redirect/attachment)
  • Purpose: To allow you to do final shutdown on external apps, close connections, free resources. Can also be used with portals or other output handling functions.
  • Accepts: 1 function name.
  • Sends: boolean value whether the footer should be output (i.e. footer should be done and not in wireless template)


integrate_fix_url

  • Called from: News.php, during fix_possible_url().
  • Purpose: To allow the RSS feeds to have adjustments made for queryless style URLs - and any other URL changes that may be required.
  • Accepts: 1 function name.
  • Sends: $val, the original URL


integrate_magic_quotes

This one isn't actually a function, it's a setting that's relevant. PHP's idea of magic quoting is one of the most irritating ideas it has ever had, to attempt to automatically be able to quote values that are incoming from userland. Unfortunately its behavior is somewhat unpredictable and therefore unreliable.

In the process of sanitizing $_GET, SMF does its own clean-up of magic quotes, handling the various types that may be incoming, but other systems do not do this and rely on default PHP behavior. This setting overrides SMF's behavior and returns it to the default.

integrate_redirect

  • Called from: Subs.php, during redirectexit(), immediately prior to physically issuing redirect headers.
  • Purpose: To allow code to modify the destination or duration before redirect, potentially of any redirect issued in the forum.
  • Accepts: 1 function name.
  • Sends: $setLocation, $refresh
    • $setLocation - the final URL it should redirect to, as a full URL.
    • $refresh - boolean, whether to send a Refresh header, or more preferably a Location header.




Advertisement: