Register Members List Search Today's Posts Mark Forums Read

Reply
 
Article Options
[How-To] Plugins for Template Edits (Adv. Version) - What your mother didn't tell you
mfyvie
Join Date: Mar 2007
Posts: 336

I run a forum for English-speaking people in Switzerland

Zurich, Switzerland
by mfyvie mfyvie is offline 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:

Block Disabled:      (Update License Status)  
Suspended or Unlicensed Members Cannot View Code.

Now we don't have to worry about other users seeing our changes and we have our extra debugging functions available. If your userid is not 1, change it now.

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.

Block Disabled:      (Update License Status)  
Suspended or Unlicensed Members Cannot View Code.

You'll remember from the first template tutorial that we were supposed to stay away from conditionals? We are about to find out why that is.

Dumping the template with dump_hex()

Insert the following code in the middle of the plugin you just created:

Block Disabled:      (Update License Status)  
Suspended or Unlicensed Members Cannot View Code.

Now login to your forum and load the who's online display. Nothing unusual will display, but when you go to your log file you should find that it now has something in it. Unless you've changed the path to the logfile in ./includes/devtools.php, you can find your logfile in ./stats/devlog.log. You'll see that you now have something that looks like this:

Block Disabled:      (Update License Status)  
Suspended or Unlicensed Members Cannot View Code.

This is the start of the template, if you keep looking you'll see the entire template is there. Personally I don't find it easy to locate the part I'm looking for when the display is listed in two columns of eight characters, so let's update our code to look like this:

Block Disabled:      (Update License Status)  
Suspended or Unlicensed Members Cannot View Code.

Adding the first parameter as "true" makes this function skip the hex part and show us just the ASCII. This is easier to read. Save your plugin, reload your who's online page and go back to your log. Locate the section of template code we examined earlier.

Block Disabled:      (Update License Status)  
Suspended or Unlicensed Members Cannot View Code.

But hang on - we were looking for something that started and ended with a conditional weren't we? But the section I've highlighted looks nothing the the <if> and </if> statements we saw in the template editor. More on this in a moment. Next we are going to switch back to the hex view, but it helps if we know where we are going to start looking. Let's calculate the offset (number in the column on the left) where we want to start. We want to start looking at approximately 1656 through to approximately 1878. When we use this function in ASCII it gives us the offsets in ASCII. If we want to find the same offsets in hexadecimal (which we use when dumping it as hex) we need to convert them. This means we are looking for the data between hex 678 and hex 756 (or 0x678 and 0x756 for the purists). Now let's change our dump_hex function call again slightly:

Block Disabled:      (Update License Status)  
Suspended or Unlicensed Members Cannot View Code.

Rather than the tiny view of two columns of eight characters we had earlier, I'd prefer to have two columns of sixteen. You'll notice that we now inserted "false" and two numbers into this function call. We have to insert false (hex display mode) because we want to specify the second and third parameters, which are the number of columns and column width. Let's look at our output and specifically check just the section between offsets 679 and 756 (in hexadecimal this time):
Block Disabled:      (Update License Status)  
Suspended or Unlicensed Members Cannot View Code.

I've highlighted the start and end of our text for you again, both in the hex and ASCII views.

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:

Block Disabled:      (Update License Status)  
Suspended or Unlicensed Members Cannot View Code.

Notice the dots here really are dots. We confirmed this by checking the corresponding hex value which was 2e. Remember that non-printable characters are displayed in the hex dump as dots, so when we see a dot on the ASCII side, we need to check what it really is in an ASCII table by checking the hex value on the hex side. Did you also notice that our single quote characters have not become escaped with backslashes? You'll remember we went over this in the first tutorial, but we learned that every double quote in the template is escaped. However, single quotes are not escaped, at least not when they are stored in the template. Ever noticed how we never actually use single quotes in the templates we see in the template editor? Now you can see the reason - they are only ever used in the parts we can never see in the template editor. Later on it will look as though we are escaping single quotes when we put certain strings into variables. Remember that in these cases we are only escaping them to get single quotes into a variable, they won't actually go to the template in their escaped form as the double quotes do. If you are totally confused at this point, don't worry - just follow the examples.

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:

Block Disabled:      (Update License Status)  
Suspended or Unlicensed Members Cannot View Code.

Remember the list with the translations in green a bit earlier? We are basically making short cuts for ourselves for the strings we are about to construct. This is because all those bracket and double quote characters can get confusing. Notice that we wrapped the strings in single quotes to get them into the variable, the single quotes don't actually get stored. Don't get confused with the names of the variables - $endif and $ifend, I've added some comments to the code so you can understand better. Notice $newline? We don't actually need it in this example, but I just wanted to show you how we might use it. The decimal values you see there equate to the hex values 0d 0a that we saw earlier in the hex dump. You could also generate a tab with chr(9).

Now that we've made a few variables to help us construct the string we are going to find, let's add another line:

Block Disabled:      (Update License Status)  
Suspended or Unlicensed Members Cannot View Code.

Looks quite straight-forward? Remember that we couldn't use the original $vboptions['showimicons'] because it's not stored in the template like that. You'll notice we escaped the single quotes inside that variable name. Otherwise PHP would have been confused because we used single quotes to enclose the string itself. Can you see that the variable above will equate to:

Block Disabled:      (Update License Status)  
Suspended or Unlicensed Members Cannot View Code.

This is the exact string we need to match, as it is stored in the database or template cache.

Now we can go ahead and built the string we would like to replace:

Block Disabled:      (Update License Status)  
Suspended or Unlicensed Members Cannot View Code.

Now all we need to do is actually run the str_replace() function, exactly like we did in the previous tutorial:

Block Disabled:      (Update License Status)  
Suspended or Unlicensed Members Cannot View Code.

Was our insertion of the new text into the template successful? We could either load the who's online page to check, or maybe it would be better to take another hex dump of the template after we've performed the str_replace()? This way we can check to see if our new text was inserted correctly. Hint: if you do this, use the ASCII mode of dump_hex, it's much easier. We aren't going to show you the replaced template because we've been showing quite enough hex dumps so far.

The final code

Let's just review the final code all in one block, without the hex dumps or the additional conditional:

Block Disabled:      (Update License Status)  
Suspended or Unlicensed Members Cannot View Code.

You'll notice that we also did some work on a second template there (to fill the column itself with our imaginary data). If you look carefully you'll see that we did things slightly differently. I'm not going to go into a lengthy detailed example, but you should be able to figure the second one out for yourself.

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.

Last edited by mfyvie; 07 Jul 2007 at 14:14.. Reason: Changing title
Views: 6813
Reply With Quote
Comments
  #2  
Old 12 Jul 2007, 20:52
cyberphr's Avatar
cyberphr cyberphr is offline
 
Join Date: Jul 2006
Helpful.
__________________
If you want me, find me.
Reply With Quote
  #3  
Old 07 Nov 2007, 17:44
KW802's Avatar
KW802 KW802 is offline
 
Join Date: Jul 2003
Real name: Kevin
Ah, this explains a problem I'm having trying to insert some code right before a conditional. Thanks for the writeup!
Originally Posted by mfyvie View Post
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.
I was looking around but didn't spot any subsequent parts. Has the 3rd or 4th part, saying how to do this easier, been posted anywhere?
__________________
Sci-Fi Forum / The Walking Dead & Horror Forum / CinVin

(Sorry, but I am no longer developing for vB; please do not PM. So long, and thanks for all the fish.)
Reply With Quote
  #4  
Old 23 Feb 2008, 15:28
Antivirus's Avatar
Antivirus Antivirus is offline
 
Join Date: Sep 2004
hardcore tuitorial mfyvie, very helpful - thanks for explaining how to do this, and preparing the useful devtools.php file
__________________
Please feel free to PM me about custom work, installations, and upgrades!

Eclipse Records - Streetcult Street Team
Reply With Quote
  #5  
Old 16 Jul 2008, 19:26
markp_2000 markp_2000 is offline
 
Join Date: Jul 2006
Don't forget the Standard template hooks

There are quite a few "Standard" template hooks in the standard templates

For example, I use this to auto insert the itrader template edit into the postbit and postbit_legacy template. It is fired at the postbit_display_complete hook.


Block Disabled:      (Update License Status)  
Suspended or Unlicensed Members Cannot View Code.

You can find these and other template hooks by viewing the template in an editor. I would do a search for them.

I went through and pulled the postbit and postbit_legacy and the navbar template hooks along with when they should be fired.

Block Disabled:      (Update License Status)  
Suspended or Unlicensed Members Cannot View Code.

Mark

Last edited by markp_2000; 16 Jul 2008 at 20:09.
Reply With Quote
  #6  
Old 24 Oct 2008, 22:22
Darkwaltz4's Avatar
Darkwaltz4 Darkwaltz4 is offline
 
Join Date: Oct 2002
Location: Chicago
Real name: John
Personally I find this works a bit easier, the catch is any special tags like conditionals need to be properly started and ended:


Block Disabled:      (Update License Status)  
Suspended or Unlicensed Members Cannot View Code.

Sticks one template's contents into a specific place of another one
__________________
I probably want my scripts to work on your site more than you do!
www.DragonByte-tech.com
Reply With Quote
  #7  
Old 31 Oct 2008, 19:24
KW802's Avatar
KW802 KW802 is offline
 
Join Date: Jul 2003
Real name: Kevin
Originally Posted by markp_2000 View Post
I went through and pulled the postbit and postbit_legacy and the navbar template hooks along with when they should be fired.
Mark, I'm working on some changes and "re-found" this thread. The list you compiled was very helpful, thank you.
__________________
Sci-Fi Forum / The Walking Dead & Horror Forum / CinVin

(Sorry, but I am no longer developing for vB; please do not PM. So long, and thanks for all the fish.)

Last edited by KW802; 31 Oct 2008 at 21:28.
Reply With Quote
Reply



Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Article Options

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off


New To Site? Need Help?

All times are GMT. The time now is 17:05.

Layout Options | Width: Wide Color: