";});
// ...but this is a much leaner and more targeted approach!
// --------------------------
// === Setup Theme Tracer ===
// --------------------------
// --- set Theme Tracer values ---
// 2.1.1: moved THEMETRACE definition to functions.php
// note: vthemetracer = tracer options, $vthemetrace = trace data
global $vthemetracer, $vthemetrace;
$vthemetracer = array();
// --- check for load or call trace request ---
if (isset($_REQUEST['trace'])) {
$trace = trim($_REQUEST['trace']);
// 2.0.5: simplify to array check
$tracetypes = array('template', 'function', 'filter', 'action');
// --- help to forget about plurals if debugging as may already be annoyed... O_o
if (in_array($trace, $tracetypes)) {$trace .= 's';}
// 2.1.1: validate specified trace option
$valid = array('templates', 'functions', 'filters', 'actions', 'all');
if (in_array($trace, $valid)) {$vthemetracer['trace'] = $trace;} else {$vthemetracer['trace'] = false;}
} else {$vthemetracer['trace'] = 'all';}
// --- whether to trace number of function calls ---
$vthemetracer['calls'] = false;
if (isset($_REQUEST['tracecalls'])) {
if ( ($_REQUEST['tracecalls'] == '1') || ($_REQUEST['tracecalls'] == 'yes') ) {$vthemetracer['calls'] = true;}
}
// --- whether to trace function arguments ---
$vthemetracer['args'] = false;
if (isset($_REQUEST['traceargs'])) {
if ( ($_REQUEST['traceargs'] == '1') || ($_REQUEST['tracedisplay'] == 'yes') ) {$vthemetracer['args'] = true;}
}
// --- whether to trace a single function ---
$vthemetracer['function'] = false;
if (isset($_REQUEST['tracefunction']) && (trim($_REQUEST['tracefunction']) != '') ) {$vthemetracer['function'] = trim($_REQUEST['tracefunction']);}
elseif (isset($_REQUEST['tracefunc']) && (trim($_REQUEST['tracefunc']) != '') ) {$vthemetracer['function'] = trim($_REQUEST['tracefunc']);}
// --- whether to trace a single filter ---
$vthemetracer['filter'] = false;
if (isset($_REQUEST['tracefilter']) && (trim($_REQUEST['tracefilter']) != '') ) {$vthemetracer['filter'] = trim($_REQUEST['tracefilter']);}
// --- whether to trace a single template ---
// 2.1.1: activated tracetemplate variable
$vthemetracer['template'] = false;
if (isset($_REQUEST['tracetemplate']) && ($_REQUEST['tracetemplate'] != '') ) {
$tracetemplate = trim($_REQUEST['tracetemplate']);
$valid = array('loop', 'header', 'footer', 'sidebar', 'content');
if (in_array($tracetemplate, $valid)) {$vthemetracer['template'] = $tracetemplate;}
}
// --- whether to trace a single action ---
$vthemetracer['action'] = false;
// 2.1.1: activated traceaction variable
if (isset($_REQUEST['traceaction']) && (trim($_REQUEST['traceaction']) != '') ) {$vthemetracer['action'] = trim($_REQUEST['traceaction']);}
// --- whether to output trace inline ---
$vthemetracer['output'] = false;
if (isset($_REQUEST['tracedisplay'])) {
if ( ($_REQUEST['tracedisplay'] == '1') || (trim($_REQUEST['tracedisplay']) == 'yes') ) {$vthemetracer['output'] = true;}
}
if (isset($_REQUEST['traceoutput'])) {
if ( ($_REQUEST['traceoutput'] == '1') || (trim($_REQUEST['traceoutput']) == 'yes') ) {$vthemetracer['output'] = true;}
}
// --- setup empty trace data array ---
// 2.1.1: simplified empty data array
$vthemetrace = array(
'instance' => false,
'start' => date('Y-m-d--H-i-s', time()),
'end' => '',
'functions' => array(),
'templates' => array(),
'actions' => array(),
'filters' => array(),
'calls' => array(),
'lines' => array(),
);
// --- maybe set a trace instance ---
if (isset($_REQUEST['instance'])) {$vthemetracer['instance'] = $_REQUEST['instance'];}
// -----------------------
// === Tracer Function ===
// -----------------------
// 2.1.1: added missing function_exists wrapper
// 2.1.1: shortened arguments resourcetype, resourcename, functionargs
if (!function_exists('bioship_trace')) {
function bioship_trace($type, $name, $filepath, $args=false) {
global $vthemetracer, $vthemetrace, $vthemedebugdir;
// --- change trace type abbreviation to name ---
if ($type == 'F') {$type = 'function';}
elseif ($type == 'T') {$type = 'template';}
elseif ($type == 'V') {$type = 'filter';}
elseif ($type == 'A') {$type = 'action';}
else {return;}
// --- strip base file path ---
// (not used for filters)
if ($type != 'filter') {
$pos = strpos($filepath, 'themes') + strlen('themes');
$filepath = substr($filepath, $pos, strlen($filepath));
}
// --- check for single function / filter / template / action trace ---
// 2.1.1: added single template / action matching
if ($vthemetracer['function'] || $vthemetracer['filter'] || $vthemetracer['template'] || $vthemetracer['action']) {
if ( ($type != 'function') && ($type != 'filter') ) {return;}
if ( ($type == 'function') && ($name != $vthemetracer['function']) ) {return;}
if ( ($type == 'filter') && ($name != $vthemetracer['filter']) ) {return;}
if ( ($type == 'action') && ($name != $vthemetracer['action']) ) {return;}
// note: match via args (template slug) not full template name
if ( ($type == 'template') && ($args != $vthemetracer['template']) ) {return;}
}
// --- maybe add to resource counts ---
// 2.1.1: added return if not matching desired trace
if ($type == 'function') {
if ( ($vthemetracer['trace'] == 'functions') || ($vthemetracer['trace'] == 'all') ) {
if (!in_array($name, $vthemetrace['functions'])) {$vthemetrace['functions'][] = $name;}
if ($vthemetracer['output']) {echo '';}
// --- keeps track of all function calls ---
$vthemetrace['calls'][] = $name;
$tracecount = '('.count($vthemetrace['calls']).')';
} else {return;}
} elseif ($type == 'template') {
if ( ($vthemetracer['trace'] == 'templates') || ($vthemetracer['trace'] == 'all') ) {
$vthemetrace['templates'][] = $name;
$tracecount = '['.count($vthemetrace['templates']).']';
if ($vthemetracer['output']) {echo '';}
// 2.1.1: set current template filepath for action filepath tracing
$vthemetrace['currentfile'] = $filepath; return;
} else {return;}
} elseif ($type == 'action') {
// 2.0.5: added action tracing...
if ( ($vthemetracer['trace'] == 'actions') || ($vthemetracer['trace'] == 'all') ) {
$vthemetrace['actions'][] = $name;
$tracecount = '+'.count($vthemetrace['actions']).'+';
// 2.1.1: override filepath with current template filepath
if (isset($vthemetrace['currentfile'])) {$filepath = $vthemetrace['currentfile'];}
if ($vthemetracer['output']) {echo '';}
} else {return;}
} elseif ($type == 'filter') {
if ( ($vthemetracer['trace'] == 'filters') || ($vthemetracer['trace'] == 'all') ) {
$vthemetrace['filters'][] = $name;
$tracecount = '<'.count($themetrace['filters']).'>';
if ($vthemetracer['output']) {echo '';}
} else {return;}
}
// --- add the tracer line to the load record ---
// 1.9.8: fix to tracer line
// 2.0.5: reordered tracer line output for readability
$memoryusage = memory_get_usage(true);
$loadtime = bioship_timer_time();
$tracerline = $tracecount.'::'.$type.'::'.$name.'::'.$memoryusage.'::'.$loadtime.'::'.$filepath;
$vthemetrace['lines'][] = $tracerline;
// if ($vthemetracer['output']) {echo '';}
// --- write argument trace debug log ---
// 1.9.8: full trace logging of function/filter arguments passed
// (note: no arguments are passed for actions or templates)
if ( ($type == 'function') || ($type == 'filter') ) {
if ($vthemetracer['args'] && $args) {
$traceline = '';
if ($type == 'function') {
ob_start(); var_dump($args); $dump = ob_get_contents(); ob_end_clean();
if ($vthemetracer['output']) {echo '';}
$traceline = $type.': '.$name.PHP_EOL.$dump.PHP_EOL;
} elseif ($type == 'filter') {
ob_start(); var_dump($args['in']); $in = ob_get_contents(); ob_end_clean();
ob_start(); var_dump($args['out']); $out = ob_get_contents(); ob_end_clean();
$traceline = $type.': '.$name.PHP_EOL;
// 2.0.5: fix to concatenate properly here
$traceline .= 'Filter Value in: '.$in.PHP_EOL.'Filter Value out: '.$out;
}
// 2.1.1: fix check for undefined index warning
if (isset($vthemetracer['instance'])) {
if ($vthemetracer['instance'] == '') {$tracefile = '';} // no file writing
else {$tracefile = '_'.$instance.'--traceargs.txt';}
} else {$tracefile = $vthemetrace['start'].'--traceargs.txt';}
if ($tracefile != '') {
// 2.0.7: replace direct with WP file system writing
// 2.1.1: use bioship_write_file with append method
// 2.1.1: use method whether file exists already or not
bioship_write_debug_file($tracefile, $traceline);
}
}
}
}
}
// -----------------------
// === Trace Processor ===
// -----------------------
// 2.1.1: added missing function_exists wrappers
// 2.1.1: removed use of vthemetimestart in favour of vthemetracer['start']
if (!function_exists('bioship_trace_processor')) {
// --- run the trace processor on shutdown ---
add_action('shutdown', 'bioship_trace_processsor');
function bioship_trace_processsor() {
// 2.1.1: bug out if not tracing
if (!THEMETRACE) {return;}
global $vthemetracer, $vthemetrace, $vthemedebugdir;
// --- set trace end to shutdown time ---
$vthemetrace['end'] = date('Y-m-d--H-i-s', time());
// --- processor started message ---
if ($vthemetracer['output']) {echo "";}
// --- maybe get tracer instance ---
if (isset($_REQUEST['instance'])) {$instance = $_REQUEST['instance'];}
// --- write load log ---
if ($vthemetracer['trace'] && (count($vthemetrace['lines']) > 0)) {
// --- set trace loads debug filename ---
// 2.1.1: fix check for undefined index warning
if (isset($vthemetracer['instance'])) {
if ($vthemetracer['instance'] == '') {$traceloadsfile = '';} // no file writing
else {$traceloadsfile = '_'.$instance.'--traceload.txt';}
} else {$traceloadsfile = $vthemetrace['start'].'--traceload.txt';}
$tracercontents = implode(PHP_EOL, $vthemetrace['lines']);
// --- write trace loads debug file ---
if ($traceloadsfile != '') {
// 2.0.7: replace direct with file system debug writing
bioship_write_debug_file($traceloadsfile, $tracercontents);
if ($vthemetrace['output']) {echo "";}
}
}
// --- write call log ---
if ($vthemetracer['calls'] && (count($vthemetrace['calls']) > 0)) {
// -- parse the tracer call log into an occurrence log ---
// ...extract occurrence data from the tracer calls
$calls = array();
foreach ($vthemetrace['calls'] as $trace) {
if (isset($calls[$vtrace])) {
$calls[$trace] = (int)$calls[$trace] + 1;
} else {$calls[$trace] = 1;}
}
// reorder by occurrences
arsort($calls);
// --- gather the data into lines ---
$occurlines = array();
foreach ($calls as $functionname => $occurs) {$occurlines[] = $functionname.'::'.$occurs;}
// --- write the call occurences log file ---
$occurdata = implode(PHP_EOL, $occurlines);
$occurdata = __('Theme Function Call Occurrences','bioship').':'.PHP_EOL.$occurdata;
$orderedtraces = implode(PHP_EOL, $vthemetrace['calls']);
$occurdata .= PHP_EOL.PHP_EOL.__('All Function Calls Order','bioship').':'.PHP_EOL.$orderedtraces;
// --- set trace calls debug filename ---
if ($vthemetracer['instance']) {
if ($vthemetracer['instance'] == '') {$tracecallsfile = '';} // no file writing
else {$tracecallsfile = '_'.$instance.'--tracecalls.txt';}
} else {$tracecallsfile = $vthemetrace['start'].'--tracecalls.txt';}
// --- write trace calls debug file ---
if ($tracecallsfile != '') {
// 2.0.7: replace direct with WP file system debug writing
bioship_write_debug_file($tracecallsfile, $occurdata);
}
}
// --- maybe output at end of screen for source viewing ---
if ($vthemetracer['output']) {
// --- main trace results ---
echo "";
echo "";
// --- occurrences results ---
if (isset($occurdata)) {
$occurdata = str_replace('::', ' : ', $occurdata);
echo "";
}
}
}
}
// -----------------------
// Filter Processing Debug
// -----------------------
// 2.0.5: add this to help debug action load order
if (!function_exists('bioship_all_actions_filters')) {
// --- add to all actions / filters ---
add_action('all', 'bioship_all_actions_filters');
function bioship_all_actions_filters() {
// --- for theme debug mode only ---
if (!THEMEDEBUG) {return;}
// --- processing filter debug output ---
$filter = current_filter();
if (substr($filter, 0, strlen(THEMEPREFIX.'_')) == THEMEPREFIX.'_') {
if (substr($filter, -9, 9) != '_position') {
echo "".PHP_EOL;
}
}
}
}
// --------------------------------
// === Trace Included Templates ===
// --------------------------------
// ----------------------
// Check Templates Loader
// ----------------------
if (!function_exists('bioship_check_templates_loader')) {
add_action('init', 'bioship_check_templates_loader');
function bioship_check_templates_loader() {
if (THEMETRACE) {bioship_trace('F',__FUNCTION__,__FILE__);}
// --- for Debug Mode or for any Site Admin ---
// 2.1.1: added edit_theme_options capability
if (THEMEDEBUG || current_user_can('edit_theme_options') || current_user_can('manage_options')) {
// --- check included files on pageload ---
add_action('wp_loaded', 'bioship_check_theme_includes');
// --- check included templates after pageload ---
add_action('wp_footer', 'bioship_check_theme_templates');
}
}
}
// ----------------------------
// Get All Included Theme Files
// ----------------------------
// 1.8.5: added this debugging function
if (!function_exists('bioship_get_theme_includes')) {
function bioship_get_theme_includes() {
if (THEMETRACE) {bioship_trace('F',__FUNCTION__,__FILE__);}
// --- get included files ---
$includedfiles = get_included_files();
// --- normalize theme paths for matching ---
$vstyledirectory = str_replace("\\", "/", get_stylesheet_directory());
$vtemplatedirectory = str_replace("\\", "/", get_template_directory());
// --- loop included files ---
foreach ($includedfiles as $i => $includedfile) {
// --- normalize include path for match ---
$includedfile = str_replace("\\", "/", $includedfile);
// --- check if included file is in stylesheet directory ---
if (substr($includedfile, 0, strlen($vstyledirectory)) == $vstyledirectory) {
// --- strip stylesheet dir from include path ---
// 2.0.1: re-add full filepath to pathinfo array
// 2.1.1: just index via full file path
$pathinfo = pathinfo(str_replace($vstyledirectory, '', $includedfile));
$vthemeincludes[$includedfile] = $pathinfo;
} else {
// --- if stylesheet is same as template, this is not a child theme ---
// 2.1.1: use THEMECHILD constant and check in parent directory
if (THEMECHILD && (substr($includedfile, 0, strlen($vtemplatedirectory)) == $vtemplatedirectory)) {
// --- strip template directory from include path ---
// 2.0.7: fix to variable name (pathinfo)
// 2.1.1: just index via full file path
$pathinfo = pathinfo(str_replace($vtemplatedirectory, '', $includedfile));
$vthemeincludes[$includedfile] = $pathinfo;
} else {
// --- possibly a plugin template file ---
// 2.1.1: handle other included files
$pathinfo = pathinfo($includedfile);
$vthemeincludes[$includedfile] = $pathinfo;
// unset($includedfiles[$i]);
}
}
}
return $vthemeincludes;
}
}
// --------------------------
// Check Theme Included Files
// --------------------------
// 1.8.5: added this debugging function
if (!function_exists('bioship_check_theme_includes')) {
function bioship_check_theme_includes() {
if (THEMETRACE) {bioship_trace('F',__FUNCTION__,__FILE__);}
global $vthemeincludes;
$vthemeincludes = bioship_get_theme_includes();
// 2.1.1: added return value
return $vthemeincludes;
}
}
// --------------------------
// Get Included Template List
// --------------------------
// 1.8.5: added this debugging function
if (!function_exists('bioship_check_theme_templates')) {
function bioship_check_theme_templates() {
if (THEMETRACE) {bioship_trace('F',__FUNCTION__,__FILE__);}
// --- check template includes ---
// 2.1.1: change vtemplateincludes global to vthemetemplates
global $vthemeincludes, $vthemetemplates;
$vthemetemplates = bioship_get_theme_includes();
// --- strip out included theme files from template list ---
$includespath = str_replace("\\", "/", ABSPATH.WPINC);
foreach ($vthemetemplates as $filepath => $pathinfo) {
// 2.1.1: match with full file path instead
// 2.1.1: ignore standard wordpress includes files
if ( array_key_exists($filepath, $vthemeincludes)
|| strstr($filepath, $includespath)
|| strstr($filepath, 'wp-admin/includes') ) {
unset($vthemetemplates[$filepath]);
}
}
// echo "";
bioship_debug("Included Template Files", $vthemetemplates);
// IDEA: output a template array for use by jQuery/AJAX loading?
// ...what would it be the use case for it though?
// echo "";
// --- admin bar template dropdown list ---
// 2.0.1: maybe add list of included templates as dropdown menu in admin bar
if (is_user_logged_in() && current_user_can('manage_options')) {
// --- check filtered setting ---
// 2.1.1: added missing global declaration for vthemesettings
global $vthemesettings; $addmenu = false;
if (isset($vthemesettings['templatesdropdown'])) {$addmenu = $vthemesettings['templatesdropdown'];}
// 2.1.1: added theme debug override to display
if (THEMEDEBUG) {$addmenu = true;}
$addmenu = bioship_apply_filters('admin_template_list_dropdown', $addmenu);
if (!$addmenu) {return;}
// --- add template dropdown list ---
add_action('wp_before_admin_bar_render', 'bioship_admin_template_dropdown');
}
}
}
// ----------------------------
// Admin Bar Templates Dropdown
// ----------------------------
// 2.0.1: added dropdown template list to admin bar
if (!function_exists('bioship_admin_template_dropdown')) {
function bioship_admin_template_dropdown() {
global $wp_admin_bar, $vthemetemplates, $vthemename;
// --- set menu settings ---
$menu = array(
'id' => 'page-templates',
'title' => ''.__('Templates','bioship'),
'href' => 'javascript:void(0);',
'meta' => array(
'title' => __('Ordered list of included templates for this pageload.','bioship')
)
);
// --- add menu to admin bar ---
$wp_admin_bar->add_menu($menu);
// --- loop templates and add to menu ---
$i = 0;
foreach ($vthemetemplates as $filepath => $pathinfo) {
// --- get relative file path ---
// 2.1.1: fix for change to use full path index
$relfilepath = str_replace($vthemename, '', $pathinfo['dirname']);
$relfilepath = str_replace("\\", "/", $relfilepath);
while (substr($relfilepath, 0, 1) == '/') {
$relfilepath = substr($relfilepath, 1, strlen($relfilepath));
}
if (strlen($relfilepath) > 0) {$relfilepath = urlencode($relfilepath.'/'.$pathinfo['basename']);}
else {$relfilepath = urlencode($pathinfo['basename']);}
// --- create edit link ---
// 2.0.8: fix to duplicate theme parameter
// TODO: could make this a thickbox view link instead ?
$editlink = admin_url('theme-editor.php');
$editlink = add_query_arg('theme', $vthemename, $editlink);
$editlink = add_query_arg('file', $relfilepath, $editlink);
// --- set node arguments ---
$displayfile = substr($pathinfo['dirname'], 1, strlen($pathinfo['dirname'])).'/'.$pathinfo['basename'];
$args = array(
'id' => 'template-'.$i,
'title' => $displayfile,
'parent' => 'page-templates',
'href' => $editlink,
'meta' => array(
'title' => $filepath,
'class' => 'page-template'
)
);
// --- add admin bar node ---
$wp_admin_bar->add_node($args);
// --- increment submenu counter ---
$i++;
}
// --- add page menu template dashicon ---
echo '';
bioship_debug("Admin Bar", $wp_admin_bar);
}
}