1.1. Start with the admin
panel.
As this is simply included in other templates this is a good starting point.
Take a copy of the admin menu template from the example module. Then edit this
replacing the function names and language constants with yours.
1.2. Create the admin menu
template
As this is simply included in other templates this is a good starting point.
Take a copy of the admin menu template from the example module. Then edit this
replacing the function names and language constants with yours.
1.3. Remove the admin menu function and
function calls from pnadmin.php
Now remove all traces of the old admin menu function from the php code. There
will be two sections here; firstly the admin menu function itself i.e.
example_adminmenu and the call to this function in all other GUI
functions.
1.4. Remove pnHTML usage from error
messages
We remove pnHTML usage from any error messages as this simplifies the module
somewhat. So code like
if (!pnSecAuthAction(0, 'Example::Item', '::', ACCESS_EDIT)) {
$output->Text(_EXAMPLENOAUTH);
return $output->GetOutput();
}
becomes
if (!pnSecAuthAction(0, 'Example::Item', '::', ACCESS_EDIT)) {
return pnvarPrepHTMLDisplay(_EXAMPLENOAUTH);
}
1.5. Transfer the output object
creator
Now transfer the creation of a pnHTML object to a pnRender object. So code
link becomes
// Create output object - this object will store all of our output so that
// we can return it easily when required
$output = new pnHTML();
becomes
// Create output object - this object will store all of our output so that
// we can return it easily when required
$pnRender =& new pnRender();
The use of & is important as it reduces the memory overhead of the
application. The old HTML style created a duplicate of the pnHTML class for our
module. The & indicates that a reference to the pnRender class is created
thus not duplicating the entire class in memory.
1.6. Caching in the admin
panel
For the admin panel is likely that you'll not want any caching so we turn
caching off for admin output i.e.
// As Admin output changes often, we do not want caching.
$pnRender->caching = false;
1.7. Transfer any headers
All admin pages have a series of page headers so we transfer these first.
We've already removed the admin menu code in step 1.3 so first we add the
menu to the template.
Code:
<!--[include file="example_admin_menu.htm"]-->
Each page should have a title that shows the user what action their currently
performing in the module.
Code:
// Title - putting a title ad the head of each page reminds the user what
// they are doing
$output->Title(_EXAMPLEEDIT);
becomes
Template:
<div class="pn-title"><!--[pnml name="_EXAMPLEEDIT"]--></div>
Any page that contains a form will have a form header. This header contains
the destination URL.
Code:
// Start form - note the use of pnModURL() to create the recipient URL of
// this form. All URLs should be generated through pnModURL() to ensure
// compatibility with future versions of PostNuke
$output->FormStart(pnModURL('Example', 'admin', 'create'));
becomes
Template:
<form action="<!--[pnmodurl modname="Example" type="admin" func="create"]-->" method="post" enctype="application/x-www-form-urlencoded">
Any page containing a form requires a form authorisation ID.
Code:
// Add an authorisation ID - this adds a hidden field in the form that
// contains an authorisation ID. The authorisation ID is very important in
// preventing certain attacks on the website
$output->FormHidden('authid', pnSecGenAuthKey());
becomes
Template:
<input type="hidden" name="authid" value="<!--[pnsecgenauthkey module="Example"]-->">
Note: we've added the module name here -
pnSenGenAuthKey takes an (optional) parameter so modules should start to make
actively make this of this parameter.
Lastly we have the form closing tag.
Code:
$output->FormEnd();
becomes
Template:
</form>
1.8. Work systematically though each output
function
I found it best to comment out the entire pnHTML output of a function and
then work on each 'chunk' of output one at a time until each 'chunk' is ported.
By 'chunk' I mean a code segment like:
// Name
$row = array();
$output->SetOutputMode(_PNH_RETURNOUTPUT);
$row[] = $output->Text(pnVarPrepForDisplay(_EXAMPLENAME));
$row[] = $output->FormText('name', '', 32, 32);
$output->SetOutputMode(_PNH_KEEPOUTPUT);
$output->SetInputMode(_PNH_VERBATIMINPUT);
$output->TableAddrow($row, 'left');
$output->SetInputMode(_PNH_PARSEINPUT);
Un comment each 'chuck' in turn. Firstly reduce the segment by removing the
pnHTML state modifiers so the code becomes:
// Name
$row[] = $output->Text(pnVarPrepForDisplay(_EXAMPLENAME));
$row[] = $output->FormText('name', '', 32, 32);
Now add the 'wrapping' table HTML into the template. e.g.
Template:
<tr>
<td></td>
<td></td>
</tr>
Now add the language define using the pnml plug in and remove the language
define .e.g.
Code:
// Name
$row[] = $output->FormText('name', '', 32, 32);
Template:
<tr>
<td><!--[pnml name="_EXAMPLENAME"]--></td>
<td></td>
</tr>
Now add in the control for the form and remove the last piece of code.
Template:
<tr>
<td><!--[pnml name="_EXAMPLENAME"]--></td>
<td><input name="name" type="text" size="32" maxlength="32"></td>
</tr>
Repeat this step for each pnHTML chuck in the current function.
1.9. Change the return of output
statement
Instead for returning the output of a pnHTML object we're returning the
output of a pnRender object. So the return of output statement
// Return the output that has been generated by this function
return $output->GetOutput();
becomes
// Return the output that has been generated by this function
return $pnRender->fetch(<template_name_including_extension>);
1.10. Assign data to
template
For those forms that contain data (modify, modifyconfig etc.) then we need to
assign the data to the template. Usually an API call would have got the item
from the database. i.e@:
// The user API function is called. This takes the item ID which we
// obtained from the input and gets us the information on the appropriate
// item. If the item does not exist we post an appropriate message and
// return
$item = pnModAPIFunc('Example', 'user', 'get', array('tid' => $tid));
Now we have the item we can simply assign it to the template i.e.
// Assign the item array to the template
$pnRender->assign('item', $item);
Similarly we assign module vars to the template in the same way i.e.
// Bold
$pnRender->assign('bold', pnModGetVar('Example', 'bold'));
1.11. Adding data output to the
template
We have a template structure and we have data being asssigned to the
template. The final step is to add the data output to the template should the
function (modify, view, modifyconfig etc.) need it.
Using the form element example from step 1.8 and the data assignment from
1.10
<tr>
<td><!--[pnml name="_EXAMPLENAME"]--></td>
<td><input name="name" type="text" size="32" maxlength="32"></td>
</tr>
would become
<tr>
<td><!--[pnml name="_EXAMPLENAME"]--></td>
<td><input name="name" type="text" size="32" maxlength="32" value="<!--[$name|pnvarprepfordisplay]-->"</td>
</tr>
Note: If your data value could contain
HTML code then change the pnvarprepfordisplay modifier to
pnvarprephtmldisplay.
Steps 1.7-1.11 need repeating for each function in the admin panel which
creates output. For the example module the functions are example_admin_new,
example_admin_modify, example_admin_view and example_admin_modifyconfig. At this
stage you should have ported across the admin panel. Now Test!, Test!,
Test!.
The user side of a module will likely be less formulaic so you'll need to
take each module as it comes but the previous steps give a idea of what
processes I've found to work. Additional work needs to be done to formulate a
caching strategy for the user interface. See the example module for a working
example of content caching.
Hopefully these notes will be found useful by a least one person ;). As
outlined in the intro these notes outline a procedure that has worked for me -
nothing more, nothing less. Each developer will, no doubt, find their own path
and their own methods. Any comments, suggestions, additions then please e-mail
me at markwest at postnuke dot com. Any complaints, insults then please e-mail
at b dot gates at Microsoft dot com.......
This section covers a few of the additional features that can be found in the
example module. Some features may only be found in CVS depending on the release
schedule of the example module code.