I generally put the php in the external script, and then have the HTML rendered using a custom template. For example, in my "Profile Reporter" product, I use the following external script to render the custom page:
PHP Code:
<?php
// ####################### SET PHP ENVIRONMENT ###########################
error_reporting(E_ALL & ~E_NOTICE);
$vbulletin->options['mypage'] = $_SERVER['HTTP_REFERER'];
// #################### DEFINE IMPORTANT CONSTANTS #######################
define('THIS_SCRIPT', 'reportprofile');
define('CSRF_PROTECTION', true);
// ################### PRE-CACHE TEMPLATES AND DATA ######################
// get special phrase groups
$phrasegroups = array();
// get special data templates from the datastore
$specialtemplates = array();
// pre-cache templates used by all actions
$globaltemplates = array('markfl_reportprofile_form');
// pre-cache templates used by specific actions
$actiontemplates = array();
// ######################### REQUIRE BACK-END ############################
require_once('./global.php');
// #######################################################################
// ######################## START MAIN SCRIPT ############################
// #######################################################################
// ###### YOUR CUSTOM CODE GOES HERE #####
$navbits = construct_navbits(array('' => $vbphrase['markfl_rp_pagetitle']));
$navbar = render_navbar_template($navbits);
$pagetitle = $vbphrase['markfl_rp_pagetitle'];
$reporteduserid = $_REQUEST['userid'];
$reporteruserid = $vbulletin->userinfo['userid'];
if ($reporteruserid AND $reporteduserid)
{
$user_data = $vbulletin->db->query_read_slave("
SELECT user.*
FROM " . TABLE_PREFIX . "user AS user
WHERE userid = " . intval($reporteduserid)
);
$user_stats = $db->fetch_array($user_data);
$reportedusername = $user_stats['username'];
$all_reasons = $vbphrase['markfl_rp_reasons'] . ',' . $vbphrase['markfl_rp_reasonsother'];
$reasons = array_filter(explode(',', $all_reasons));
$text_height = count($reasons) * 16;
$rp_checkboxes = '';
$rp_conditional = array();
foreach ($reasons as $reason)
{
$elname = strtolower(str_replace(' ', '', $reason));
$rp_checkboxes .= '<div>' . $reason . '</div><input type="checkbox" name="' . $elname . '" /><br>';
$rp_conditional[] = 'document.getElementsByName("' . $elname . '")[0].checked';
}
$rp_condition = implode(' || ', $rp_conditional);
// ###### NOW THE TEMPLATES ARE BEING RENDERED ######
$templater = vB_Template::create('markfl_reportprofile_form');
$templater->register_page_templates();
$templater->register('navbar', $navbar);
$templater->register('pagetitle', $pagetitle);
$templater->register('reporteduserid', $reporteduserid);
$templater->register('reporteruserid', $reporteruserid);
$templater->register('reportedusername', $reportedusername);
$templater->register('rp_checkboxes', $rp_checkboxes);
$templater->register('text_height', $text_height);
$templater->register('rp_condition', $rp_condition);
print_output($templater->render());
}
else
{
print_no_permission();
}
?>
And this script renders the custom template:
HTML Code:
{vb:stylevar htmldoctype}
<html xmlns="http://www.w3.org/1999/xhtml" dir="{vb:stylevar textdirection}" lang="{vb:stylevar languagecode}" id="vbulletin_html">
<head>
<title>{vb:raw vboptions.bbtitle} - {vb:raw pagetitle}</title>
<vb:if condition="$vboptions['storecssasfile']">
{vb:cssfile forumhome-rollup.css}
<vb:else />
{vb:cssfile forumbits.css,forumhome.css,options.css}
</vb:if>
{vb:raw headinclude}
{vb:raw headinclude_bottom}
<style type="text/css">
#report_profile form {
margin-bottom: 2.5em;
}
.wgo_block {
border: {vb:stylevar formrow_border};
}
#rpform {
padding: 5px;
margin-bottom: 1em;
}
#rpform fieldset {
border: {vb:stylevar formrow_border};
padding: 5px;
}
#rpform fieldset:first-of-type {
display: inline-block;
width: 25%;
}
#rpform fieldset:last-of-type {
float: right;
width: 70%;
}
#rpform fieldset div {
display: inline-block;
min-height: 16px;
}
#rpform fieldset div::after {
content: ":";
}
#rpform fieldset input {
float: right;
margin-top: 2px;
}
legend::before {
content: "\00a0";
}
legend::after {
content: ":\00a0";
}
textarea {
resize: none;
height: {vb:raw text_height}px;
width: 100%;
font-size: 14px;
font-family: Arial;
}
#fbuttons {
float: right;
margin-top: 10px;
}
#fbuttons input {
cursor: pointer;
}
#explain {
padding: 5px;
text-align: justify;
}
</style>
<script>
function checkEmpty() {
if (!({vb:raw rp_condition}))
{
return 0;
}
else if (document.getElementsByName("other")[0].checked && !document.getElementsByName("comment")[0].value)
{
return 1;
}
else
{
return 2;
}
}
</script>
</head>
<body>
{vb:raw header}
{vb:raw navbar}
<div id="report_profile" class="wgo_block">
<h2 class="blockhead">
{vb:rawphrase markfl_rp_header, {vb:raw reportedusername}}
</h2>
<form name="reportprofile_form" method="post" action="reportprofilethread.php">
<input type="hidden" name="url" value="{vb:raw $_SERVER['HTTP_REFERER']}" />
<input type="hidden" name="reporteduser" value="{vb:raw reportedusername}" />
<input type="hidden" name="reporteruserid" value="{vb:raw reporteruserid}" />
<input type="hidden" name="reporteduserid" value="{vb:raw reporteduserid}" />
<div id="rpform">
<fieldset>
<legend>{vb:rawphrase markl_rp_legendreasons}</legend>
{vb:raw rp_checkboxes}
</fieldset>
<fieldset>
<legend>{vb:rawphrase markl_rp_legendcomments}</legend>
<textarea name="comment"></textarea>
</fieldset>
<div id="fbuttons">
<input title="{vb:rawphrase markfl_rp_formresettitle}" class="button" type="reset" name="rpreset" value="{vb:rawphrase markfl_rp_formreset}" />
<input title="{vb:rawphrase markfl_rp_form_submittitle}" class="button" type="submit" name="rpsubmit" value="{vb:rawphrase markfl_rp_form_submit}" onclick="var state = checkEmpty(); if (state == 0){alert('{vb:rawphrase markfl_rp_form_submitemptyalert}'); return false;} else if (state == 1) {alert('{vb:rawphrase markfl_rp_form_submitotheralert}'); return false;}" />
</div>
</div>
</form>
<div id="explain">
{vb:rawphrase markfl_rp_formexplain}
</div>
</div>
{vb:raw footer}
</body>
</html>