[How-To] Plugins for Template Edits (Adv. Version) - What your mother didn't tell you
by
04 Jul 2007
Plugins for Template Edits (Advanced Version) - What your mother didn't tell you about templates In this tutorial we are going to tackle some of the more mysterious and tricky aspects of using the plugin system to perform automatic edits of templates in vBulletin. I've added the "what your mother didn't tell you about templates" to the title because I figured all this out after a lot of banging my head against the wall. I didn't find any information about this anywhere, so I figured the best thing to do was share what I've learned. Before we start This tutorial is going to build on material I covered in my earlier template tutorial - Using Plugins for Automatic Template Edits. Please read it and understand it before reading this tutorial. Even if you think you know everything, please at least go back and skim-read it. During this tutorial we are also going to use some of the tools and techniques I covered in the tutorial called Debugging Your Plugin - how to save time and frustration. There is an include file on that thread containing some functions that we'll be using. You should also go and read and understand the debugging tutorial before continuing with the current tutorial. Why do we need to know this stuff? Because you want to do automatic template edits, but you learned in the previous tutorial that you have to stay away from any conditional statements in a template, tab characters, new lines. That's not much fun! Maybe you've come to this tutorial because you've been scratching your head trying to wonder why you can't seem to get a conditional statement to work when you change a template with a plugin. You've come to the right place, because we are going to get our hands dirty in this tutorial! What's the main issue here? When you look at a template in the template editor you are not seeing what is really stored in the template, but rather a sanitised version which is easy for you to understand and edit. In reality, the template is converted into PHP code when it is stored or used. Therefore we need to look at the "wiring under the board" if we really want to be successful at using the plugin system to edit templates automatically. You may never look at a template the same way again... So what does a template really look like? OK, you already understand how to use str_replace and you know how to make a hex dump of a template (because you've read and understood the previous two tutorials), so you understand that unless we can correctly identify the exact string to replace and insert code that will actually work, there's little point in attempting this. The first thing we need to do is actually look at a template. We are going to use the dump_hex() function to do this. Since we want to make our life easy, we are probably also going to use the print_log() function to write the data to a log file for us to check. Remember that these functions are not part of PHP or vBulletin - but you already know that from the debugging tutorial and you downloaded the file attached to the debugging tutorial with those functions included. I know you want to look at the template, but first we have to set up our plugin and decide what to look for. Before we start - is your template cached? Remember to consider at which hook your str_replace is going to execute. If you run it at a hook like global_start, was it placed into the $globaltemplates array so that the template in question is put into the template cache? If you are performing a str_replace on built-in vBulletin templates this isn't an issue as they are always cached in the relevant places anyway. However, if you are changing other templates from other mods (or your own) with this method, then it will not work unless your template it is in the cache first! Create your plugin Create a plugin, and execute it at a sensible hook for the template we are going to work on. We will work with two templates, WHOSONLINE and whosonlinebit. Create your plugin at online_start. Our plugin is going to add a new column to our who's online display to display the country where a user is logging on from. The underlying variables used for this won't function (unless you have one of my forthcoming mods installed already), but we should be able to at least create an empty column. You'll remember that we started all our plugins with something like this: Code:
if ($vbulletin->userinfo['userid'] == 1) { // include some special functions we might want include_once(DIR . '/includes/devtools.php'); // Our code goes here. } Examine the template in the editor Now go and load the the WHOSONLINE template via the style manager. We are going to insert the code highlighted in bold. Locate the area around this insertion point and try to figure out which string we should try to match to make the replacement. Code:
<if condition="$show['ip']"><td class="thead">$vbphrase[ip_address]</td></if> <if condition="$show['country']"><td class="thead"> $vbphrase[show_country]</td></if> <if condition="$vboptions['showimicons']"><td class="thead" align="center">$vbphrase[instant_messaging]</td></if> </tr> $onlinebits </table> Dumping the template with dump_hex() Insert the following code in the middle of the plugin you just created: Code:
printlog(dump_hex($vbulletin->templatecache['WHOSONLINE'])); Code:
0000 24 73 74 79 6c 65 76 61 72 5b 68 74 6d 6c 64 6f $styleva r[htmldo 0010 63 74 79 70 65 5d 0d 0a 3c 68 74 6d 6c 20 64 69 ctype].. <html di 0020 72 3d 5c 22 24 73 74 79 6c 65 76 61 72 5b 74 65 r=\"$sty levar[te 0030 78 74 64 69 72 65 63 74 69 6f 6e 5d 5c 22 20 6c xtdirect ion]\" l 0040 61 6e 67 3d 5c 22 24 73 74 79 6c 65 76 61 72 5b ang=\"$s tylevar[ 0050 6c 61 6e 67 75 61 67 65 63 6f 64 65 5d 5c 22 3e language code]\"> 0060 0d 0a 3c 68 65 61 64 3e 0d 0a 24 68 65 61 64 69 ..<head> ..$headi 0070 6e 63 6c 75 64 65 0d 0a 24 6d 65 74 61 72 65 66 nclude.. $metaref 0080 72 65 73 68 0d 0a 3c 74 69 74 6c 65 3e 22 20 2e resh..<t itle>" . 0090 20 24 47 4c 4f 42 41 4c 53 5b 27 76 62 75 6c 6c $GLOBAL S['vbull Code:
printlog(dump_hex($vbulletin->templatecache['WHOSONLINE'], true)); Code:
1600 $vbphrase[location_temp]</a> $sortarrow[location]</td>...".(($show['ip']) ? ("<t 1680 d class=\"thead\">$vbphrase[ip_address]</td>") : (""))."...".(($GLOBALS['vbullet 1760 in']->options['showimicons']) ? ("<td class=\"thead\" align=\"center\">$vbphrase 1840 [instant_messaging]</td>") : (""))."..</tr>..$onlinebits..</table>....".(($show[ Code:
printlog(dump_hex($vbulletin->templatecache['WHOSONLINE'], false, 2, 16)); Code:
0660 72 74 61 72 72 6f 77 5b 6c 6f 63 61 74 69 6f 6e 5d 3c 2f 74 64 3e 0d 0a 09 22 2e 28 28 24 73 68 rtarrow[location ]</td>...".(($sh 0680 6f 77 5b 27 69 70 27 5d 29 20 3f 20 28 22 3c 74 64 20 63 6c 61 73 73 3d 5c 22 74 68 65 61 64 5c ow['ip']) ? ("<t d class=\"thead\ 06a0 22 3e 24 76 62 70 68 72 61 73 65 5b 69 70 5f 61 64 64 72 65 73 73 5d 3c 2f 74 64 3e 22 29 20 3a ">$vbphrase[ip_a ddress]</td>") : 06c0 20 28 22 22 29 29 2e 22 0d 0a 09 22 2e 28 28 24 47 4c 4f 42 41 4c 53 5b 27 76 62 75 6c 6c 65 74 (""))."...".(($ GLOBALS['vbullet 06e0 69 6e 27 5d 2d 3e 6f 70 74 69 6f 6e 73 5b 27 73 68 6f 77 69 6d 69 63 6f 6e 73 27 5d 29 20 3f 20 in']->options['s howimicons']) ? 0700 28 22 3c 74 64 20 63 6c 61 73 73 3d 5c 22 74 68 65 61 64 5c 22 20 61 6c 69 67 6e 3d 5c 22 63 65 ("<td class=\"th ead\" align=\"ce 0720 6e 74 65 72 5c 22 3e 24 76 62 70 68 72 61 73 65 5b 69 6e 73 74 61 6e 74 5f 6d 65 73 73 61 67 69 nter\">$vbphrase [instant_messagi 0740 6e 67 5d 3c 2f 74 64 3e 22 29 20 3a 20 28 22 22 29 29 2e 22 0d 0a 3c 2f 74 72 3e 0d 0a 24 6f 6e ng]</td>") : ("" ))."..</tr>..$on What can you see? You can see that we have a few changes. I'll list some statements that we had in the template, followed by what they actually become when they are stored in the template in green: Code:
<if condition="$show['ip']"> ".(($show['ip']) ? (" <if condition="$vboptions['showimicons']"> ".(($GLOBALS['vbulletin']->options['showimicons']) ? (" </if> ) ? (" The only other thing to note in this output is where you see 0d 0a - this is a new line. Where you see 09, this a tab. Since these are non-printable characters they will appear in the ASCII side as dots. Remember these are hex values, we'll be working with their decimal equivalents in a minute. Constructing the required strings Now we need to build some code to find and replace strings within our template. You'll remember we did the same thing in the first tutorial, but now we are going to get a little more complicated. Let start by entering the following code: Code:
$ifstart = '".(('; // equates to first half of if - <if condition=" $ifend = ') ? ("'; // equates to second half of if - "> $endif = '") : (""))."'; // equates to an endif - </if> $newline = chr(13) . chr(10); // equates to a new line Now that we've made a few variables to help us construct the string we are going to find, let's add another line: Code:
$find = $ifstart . '$GLOBALS[\'vbulletin\']->options[\'showimicons\']' . $ifend; Code:
".(($GLOBALS['vbulletin']->options['showimicons']) ? (" Now we can go ahead and built the string we would like to replace: Code:
$replace = $ifstart . '$show[\'country\']' . $ifend . '<td class=\"thead\">$vbphrase[show_country]</td>' . $endif; Code:
$vbulletin->templatecache['WHOSONLINE'] = str_replace($find, $replace . $find, $vbulletin->templatecache['WHOSONLINE']); The final code Let's just review the final code all in one block, without the hex dumps or the additional conditional: Code:
$endif = '") : (""))."'; $ifstart = '".(('; $ifend = ') ? ("'; $newline = chr(13) . chr(10); $find = $ifstart . '$GLOBALS[\'vbulletin\']->options[\'showimicons\']' . $ifend; $replace = $ifstart . '$show[\'country\']' . $ifend . '<td class=\"thead\">$vbphrase[show_country]</td>' . $endif; $vbulletin->templatecache['WHOSONLINE'] = str_replace($find, $replace . $find, $vbulletin->templatecache['WHOSONLINE']); $replace = $ifstart . '$show[\'country\']' . $ifend . addslashes('<td class="alt1">$userinfo[country]</td>') . $endif; $vbulletin->templatecache['whosonlinebit'] = str_replace("$find", "$replace$find", $vbulletin->templatecache['whosonlinebit']); Using these ideas in your own plugins What we have seen so far has not been an exhaustive list of techniques, but now you can use tools like dump_hex to discover the true variable names and conditional syntax in templates when developing your own plugins. There are many other things inside a template that we didn't list here. What about the <else /> tag? Remember that now you know how to include newlines and tabs in your searches - don't get carried away. If anybody has changed their template by removing or adding tabs or newlines, your search string may not match. Try to find the best possible insertion point by looking for a place where there is less chance of a change being made by someone else. The smallest possible strings, which are still unique, are best. For example, there would be little point in searching and replacing based on <td class= because this appears many times within most templates. The bottom line - use these techniques to employ a more structured and methodical approach to your automatic template edits. By actually checking the results before and afterwards and determining in advance exactly what you need to do, you can save yourself a lot of time by avoiding "trial and error". Alternative methods to see the template Of course there are other methods to look inside the template, I've just listed the ones I use the most. Rather than going to the template cache, you could display it in your log or to screen simply by accessing fetch_template('your_template_name'). You should be aware that this is only good for reading the template, if you want to change it, you'll still have to go directly to the template cache. Remember also that if you try to display the output in a browser it might not work so well since the template contains HTML formatting. If you are outputting to the command line this should be no problem. You could also go and look at the template directly in the database if you like. You'll need the appropriate tools, such as phpmyadmin, but if you look in the table called "template" you'll find two columns - "template" and "template_un". The first is the template as it appears to PHP (and the template cache), the second is the same template, but stored in the "human-readable" form that you see when using the style manager. Be careful though - depending on your tools, you will see newlines and tabs as they appear, rather than they actually are - you'll still need a hex dump to see exactly which non-printable characters have been stored. What's next? The good news is that there is an easier way. However, it is important for you to understand how this process works, which is why this was such a long and boring tutorial. There will be a third and final tutorial in this series which will show you a much easier way to do these automatic edits. |