Add a custom action using integration hooks

From Online Manual

Jump to: navigation, search

Introduction

Starting with SMF 2.0 adding a custom action does not need any change to the "core" code, it is sufficient to use the appropriate integration hook.

Just for the sake of learning how SMF works, let's take a look at how actions are handled internally. Opening index.php in SMF's main directory it's possible to find an array called $actionArray where are defined all the default action of SMF (e.g. calendar, post, etc.).

The structure of the elements of the array is the following:

'myaction' => array('myaction_file.php', 'myaction_function'),

Where:

  • myaction - is the action as specified in the URL
    (e.g. http://www.yourdomain.tld/forum/index.php?action=myaction),
  • myaction_function - is the function that SMF will call once the myaction is used,
  • myaction_file.php - is the file that contains the function myaction_function.

The first thing to do is decide the name of the action we want to have, the name of the function the action will trigger and the name of the file that will contain this function. In this tutorial we will use:

  • action - youraction
  • function - YourActionMain
  • file - YourAction.php

Prepare to use the hook

Adding an integration hook to SMF is like modifying an entry in the database. It only needs to be done once, then SMF will know to look for your new integration hook every time afterwards. In order to facilitate this procedure, a function named add_integration_function is available in SMF. In order to use this function we can create a simple php file, it can be called for example add_action_hook.php and the content can be:

<?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-YourAction.php');
add_integration_function('integrate_actions', 'youraction_add_hook');
?>

Analysing the code provided two are the hooks used:

Prepare the 'YourAction' files

Source File

./Sources/Subs-YourAction.php

This file is meant to contain the function youraction_add_hook used every time SMF loads in order to add the action to the list of available. It must be placed in the /Sources/ directory.

The code contained in this file is:

<?php
if (!defined('SMF'))
	die('Hacking attempt...');

function youraction_add_hook(&$actionArray)
{
	$actionArray['youraction'] = array('YourAction.php', 'YourActionMain');
}

?>

./Sources/YourAction.php

This file is meant to contain the function YourActionMain, triggered by the youraction action. It must be placed in the /Sources/ directory.

So to start it must at least contains the function:

<?php
if (!defined('SMF'))
	die('Hacking attempt...');

function YourActionMain()
{

}
?>

This function could be used to load a template, for example the YourAction template, in order to do so we can add the instruction:

loadTemplate('YourAction');

In this case YourAction is the first part of the name of the template file, that will be YourAction.template.php.

It is also possible and encouraged to set several options that could be used later in the template, like for example the page title or the link tree.

So, the final YourAction.php should look like:

<?php

// First of all, we make sure we are accessing the source file via SMF so that people can not directly access the file. 
if (!defined('SMF'))
	die('Hack Attempt...');

function YourActionMain()
{

	// Second, give ourselves access to all the global variables we will need for this action
	global $context, $scripturl, $txt, $smcFunc;

	// Third, Load the specialty template for this action.
	loadTemplate('YourAction');

	//Fourth, Come up with a page title for the main page
	$context['page_title'] = $txt['youraction_PageTitle'];
	$context['page_title_html_safe'] = $smcFunc['htmlspecialchars'](un_htmlspecialchars($context['page_title']));


	//Fifth, define the navigational link tree to be shown at the top of the page.
	$context['linktree'][] = array(
  		'url' => $scripturl. '?action=youraction',
 		'name' => $txt['your_action'],
	);

	//Sixth, begin doing all the stuff that we want this action to display
	//    Store the results of this stuff in the $context array.  
	//    This action's template(s) will display the contents of $context.
	$context['youraction_Head'] = $txt['youraction'];
	$context['youraction_Body'] = 'Hello World';
              
}

?>

Template File

./Themes/default/YourAction.template.php

As previously explained the YourAction.template.php file must contain the template function, in this case template_main:

<?php
function template_main()
{

}
?>

This is the function called to display an output when the youraction action is used and the one that will create the html output with the echo statements.


Assuming the intention is to create a header and a content section the following code could be used:

<?php

function template_main()
{

	// Make sure we have all the global variables we need
	global $context;

	// Catbg header
	echo '<div class="cat_bar">
   			<h3 class="catbg">', $context['youraction_Head'], '</h3>
	</div>';

	// Windowbg2 Content
	echo '<div class="windowbg2">
  			<span class="topslice"><span></span></span>
  		  		<div class="content">', $context['youraction_Body'], '</div>
  			<span class="botslice"><span></span></span>
	</div><br />';

}

?>

The file YourAction.template.php must be placed in the /Themes/default/ directory.

Language Strings

./Themes/default/languages/Modifications.english.php

The Modifications.languages.php files are commonly used by modifications in order to add new strings to the $txt array. In this way it is possible to easily translate SMF and its mods in several languages. All these files can be found in /Themes/default/languages/.

In order to add our new string to the $txt array it is enough to add this code:

// Your Action Language Strings
$txt['youraction'] = 'Your Action';
$txt['youraction_PageTitle'] = 'This is your page title';

to the Modification.english.php file and save it.

./Themes/default/languages/Who.english.php

The strings present in Modification.language.php are available everywhere in SMF's code. In certain cases it could be more appropriate to have the strings available only where they are really needed, for this reason it is possible to add strings also to other language files. The Who.english.php is a special case, it is used when someone is accessing the ?action=who page and here can be added a description for the new action that will so be visible in the page.

Once the file is opened it is enough to add the following code at the end:

// Your Action Who String
$txt['whoall_youraction'] = 'Viewing <a href="' . $scripturl . '?action=youraction">Your Action</a>.';

Finally it is necessary to clear the file cache for the language strings to take effect. This can be done in Admin > Maintenance > Forum Maintenance > Routine, and it's the last option.

Add the hook

Upload the file add_action_hook.php, previously prepared, in the root directory of your forum (the same directory that contains SSI.php), then point your browser to http://www.yourdomain.tld/forum/add_action_hook.php.

If you do not get any error and you see a blank page everything should be fine and you can remove the add_action_hook.php from the server.

See the results

In your browser go to
http://www.yourdomain.tld/forum/index.php?action=youraction
and you should see result of the action displayed on the screen!

Removing the action

In order to remove the action two are the things to do:

  1. remove all the involved files;
  2. remove the integration hooks.

In order to remove the integration hooks a file similar to add_action_hook.php can be used, it can be called remove_action_hook.php and it should contain this code:

<?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.');

remove_integration_function('integrate_pre_include', '$sourcedir/Subs-YourAction.php');
remove_integration_function('integrate_actions', 'youraction_add_hook');
?>

The file must be uploaded to the root directory of the forum, executed pointing to the
http://www.yourdomain.tld/forum/remove_action_hook.php
url and then removed from the server the same way add_action_hook.php was.

Alternative methods

Add_a_custom_action