PDA

View Full Version : Writing my first plug-in/product, several newbie questions.


Guest210212002
07-05-2006, 12:07 PM
Disclaimer: I've been reading the API and will continue to do so, just trying to get a feel for this and hopefully some folks will be patient enough to do a little hand-holding. :)

I'm trying to write my first plugin, something extremely basic, just to get the feel for how it works. I'm decent with template edits and variables, but I've never attempted writing a plugin before, and would really like to.

That said, I'm looking to write a simple plugin to drop a variable into a template.

In FORUMHOME, here's the default Who's Online:


<a href="online.php$session[sessionurl_q]" rel="nofollow">$vbphrase[currently_active_users]</a>: $totalonline (<phrase 1="$numberregistered" 2="$numberguest">$vbphrase[x_members_and_y_guests]</phrase>)

All I want to do is add the following code after the end parenthesis:


Invisible: $numberinvisible


So that the end result is:


<a href="online.php$session[sessionurl_q]" rel="nofollow">$vbphrase[currently_active_users]</a>: $totalonline (<phrase 1="$numberregistered" 2="$numberguest">$vbphrase[x_members_and_y_guests]</phrase>)
Invisible: $numberinvisible

I'm looking at This post on writing plug-ins (https://vborg.vbsupport.ru/showthread.php?t=82625) and the first thing I need is the hook location. So I opened up forum/index.php, and I *think* that the proper hook location is (from around line 407):

($hook = vBulletinHook::fetch_hook('forumhome_loggedinuser' )) ? eval($hook) : false;

Judging by that, the hook loction is forumhome_loggedinuser, correct?

So in using the basic code from the howto post, I come up with something like:


<?xml version="1.0" encoding="ISO-8859-1"?>
<plugins>
<plugin active="1">
<title>Chris's Newbie Plugin</title>
<hookname>forumhome_loggedinuser</hookname>
<phpcode>
<![CDATA[ ]]>
</phpcode>
</plugin>
</plugins>

If I'm correct so far, I'm not sure:

A: Where the actual code goes.
B: How I tell vB where to actually put it, (Eg: "directly following $vbphrase[x_members_and_y_guests]</phrase>) ".

I'm guessing that the code that I want to inject goes inside the CDATA brackets, like this:


<![CDATA[Invisible: $numberinvisible]]>


But from there, I'm stumped, and that's assuming I'm even close to correct this far.

If anyone could shed some light on where I should go from here, I'd really appreciate the help. :) In the meantime I'll keep scouring the docs. :bunny:

Update #1

Here's what I have so far, but I don't think I'm going about it correctly:


<?xml version="1.0" encoding="ISO-8859-1"?>

<product productid="chris777_showinvisible" active="1">
<title>Show Invisible Users</title>
<description>Will add a count of invisible users in WGO.</description>
<version>1.0.0</version>
<codes>
</codes>
<templates>
</templates>
<plugins>
<plugin active="1">
<title>Show Invisible Users</title>
<hookname>forumhome_loggedinuser</hookname>
<phpcode><![CDATA[
if ($totalonline (<phrase 1="$numberregistered" 2="$numberguest">$vbphrase[x_members_and_y_guests]</phrase>))
{
Invisible: $numberinvisible;
}
]]>
</phpcode>
</plugin>
</plugins>
<phrases>
</phrases>
<options>
</options>
</product>


The if statement I'm guessing will look for that particular line in a template, and just stick my code after it.

* Guest210212002 scratches his head and continues to dig.

harmor19
07-05-2006, 01:17 PM
There is no need to create a plugin to show the number of invisible users online.

Edit the FORUMHOME template and add Invisible: $numberinvisible anywhere you like.

The only weird thing about this is that I made the main admin invisible but it stayed at zero. I logged in with my other username which is in the "Registered Users" group and set him to invisible and it worked.


Edit:


<phpcode><![CDATA[
if ($totalonline (<phrase 1="$numberregistered" 2="$numberguest">$vbphrase[x_members_and_y_guests]</phrase>))
{
Invisible: $numberinvisible;
}
]]>
</phpcode>
I don't know how your code will function but I can tell you that you need to put text that you want to output into a variable.
So change this Invisible: $numberinvisible; to $myvar = Invisible: . " $numberinvisible;
In the appropriate template just add the variable $myvar in it and it'll output the text assigned to it.

Guest210212002
07-05-2006, 01:31 PM
Thanks very much harmor. :) I realize that this is super basic and it'd be far quicker to just do the template edit - I'm just using this as a stepping stone to get a feel for the actual process. 99% of the "modding" that I do are template edits, and I'd love to be able to release some of them as products. I think if I can get this working and learn the basics, I can build off of that to make more complex/useful bits. :)

Where would I actually define that variable in the plugin?

Here's what I have right now, just adding in a phrase instead of the text. I'll start looking for the variable stuff from here.


<?xml version="1.0" encoding="ISO-8859-1"?>

<product productid="chris777_showinvisible" active="1">
<title>Show Invisible Users</title>
<description>Will add a count of invisible users in WGO.</description>
<version>1.0.0</version>
<codes>
</codes>
<templates>
</templates>
<plugins>
<plugin active="1">
<title>Show Invisible Users</title>
<hookname>forumhome_loggedinuser</hookname>
<phpcode><![CDATA[
if ($totalonline (<phrase 1="$numberregistered" 2="$numberguest">$vbphrase[x_members_and_y_guests]</phrase>))
{
$vbphrase[online_invisible] $numberinvisible;
}
]]>
</phpcode>
</plugin>
</plugins>
<phrases>
<phrasetype name="GLOBAL" fieldname="global">
<phrase name="online_invisible">
<![CDATA[ Invisible:
]]>
</phrase>
</phrasetype>

</phrases>
<options>
</options>
</product>


I think the most basic question I have then is, how do I go about adding what I'm looking to add directly after this text in the forumhome template?


if ($totalonline (<phrase 1="$numberregistered" 2="$numberguest">$vbphrase[x_members_and_y_guests]</phrase>))


Thanks again and I apologize for the super-basic-and-pretty-much-useless bit of code that I'm working on. I'm really looking forward to getting better at it and a couple of coders pointing me in the right direction will no doubt save me hours of API digging.

harmor19
07-05-2006, 01:49 PM
Well first let's start off with a simple plugin so you know the basics.
Let's create a plugin that'll display an easter egg if you type in "index.php?chris777"

<?xml version="1.0" encoding="ISO-8859-1"?>

<product productid="chris777_easteregg" active="1">
<title>Easter Egg</title>
<description>Will show an easter egg</description>
<version>1.0.0</version>
<codes>
</codes>
<templates>
</templates>
<plugins>
<plugin active="1">
<title>Easter Egg</title>
<hookname>forumhome_complete</hookname>
<phpcode><![CDATA[
if($_REQUEST['do'] == "chris777")
{
$easter_egg = "Easter Egg Here";
}
]]>
</phpcode>
</plugin>
</plugins>
<phrases>
</phrases>
<options>
</options>
</product>

Edit FORUMHOME
Above $header
Add $easter_egg<br /><br />

Let's take a closer look of why it works.
if($_REQUEST['do'] == "chris777")
{
$easter_egg = "Easter Egg Here";
}
When you visit "index.php?do=chris777" the variable is initiated (I guess that's the word) thus outputting the text at the top of the board.
The reason why you assign the text to a variable is so you can place it into a template, otherwise the text doesn't know where to go, I suppose.

I'm sorry but I'm not good at explaining how things work.

Guest210212002
07-05-2006, 10:07 PM
Thanks again, that definitely helps. I've been pining over the API all day, and either I'm senile, or can you not do direct template edits with plugins unless you're throwing a whole new section under the hook location?

For example, Paul M's Members Who Have Visited Today hack edits the forumhome template, and (albeit a LOT more complicated than what I'm trying to do) adds a section.

Is it not possible to have a plugin/product that directly edits templates in certain spots? I realize that what I'm doing is pretty pointless and is much easier to just edit in the template, but like I said I'm trying to use it as a stepping stone to bigger/more complex stuff. I've done a LOT of template work on my site, and I'd love to be able to share some of it as a simple product install. :)

Thanks very much once again, I really appreciate any advice/tips I can get.

* Guest210212002 cheers

Kirk Y
07-06-2006, 12:55 AM
I use this code in one of my hacks to add template code using a plugin:

$search_text = '$navbar';
$vbulletin->templatecache['FORUMHOME'] = str_replace($search_text,
$search_text.fetch_template('temp_with_code_you_wa nt_added'),$vbulletin->templatecache['FORUMHOME']);

I got it from one of Zacharia's posts somewhere on here... anyway, back to the point.

Basically, just replace the $navbar with a string from a template, in my case I'm using forumhome, if I'm understanding what you're trying to do, then I think you'd want to use the same. Try replacing $navbar with "$vbphrase[x_members_and_y_guests]</phrase>)".

Then create a template with whatever code you want and put the template name in the plugin.
<br />Invisible Users: $var

I've got the plugin running on forumhome_complete. Hope this is of some help to you.

Guest210212002
07-06-2006, 12:41 PM
That is incredibly helpful, thank you so much. :D

So something like this?


$search_text = '$vbphrase[x_members_and_y_guests]</phrase>)';
$vbulletin->templatecache['FORUMHOME'] = str_replace($search_text,
$search_text.fetch_template('silly_newbie_template '),$vbulletin->templatecache['FORUMHOME']);


Then make a template called silly_newbie_template, with:


$vbphrase[x_members_and_y_guests]</phrase>) Invisible: $numberinvisible


And that would technically replace [the default string] with [the default string + my snippet], correct?

* Guest210212002 thanks everyone for taking the time to help him out. :D

Edit:

I'm reading Kerry-Anne's post here on how to go about actually creating the template.

https://vborg.vbsupport.ru/showthread.php?p=1018718

So I know I have to include this somewhere:

eval('$mytemplate = "' . fetch_template('silly_newbie_template') . '";');

So here's what I've got now:


<?xml version="1.0" encoding="ISO-8859-1"?>

<product productid="chris777_showinvisible" active="1">
<title>Show Invisible Users Online</title>
<description>Will add a count of invisible users in WGO.</description>
<version>1.0.0</version>
<dependencies></dependencies>
<codes></codes>
<templates>
<template name="silly_newbie_template" templatetype="template" username="chris-777" version="1.0.0">
<![CDATA[
<!-- Newbie Template -->
$vbphrase[x_members_and_y_guests]</phrase>) Invisible: $numberinvisible
<!-- /Newbie -->
]]>
</template>
</templates>
<plugins>
<plugin active="1" executionorder="1">
<title>Show Invisible in WOL</title>
<hookname>forumhome_loggedinuser</hookname>
<phpcode><![CDATA[
$search_text = '$vbphrase[x_members_and_y_guests]</phrase>)';
$vbulletin->templatecache['FORUMHOME'] = str_replace($search_text,
$search_text.fetch_template('silly_newbie_template '),$vbulletin->templatecache['FORUMHOME']);]]>
</phpcode>
<phrases>
<phrasetype name="GLOBAL" fieldname="global">
<phrase name="online_invisible">
<![CDATA[ Invisible: ]]>
</phrase>
</phrasetype>
</phrases>
</product>



This (I think) should make the template:


<templates>
<template name="silly_newbie_template" templatetype="template" username="chris-777" version="1.0.0">
<![CDATA[
<!-- Newbie Template -->
$vbphrase[x_members_and_y_guests]</phrase>) Invisible: $numberinvisible
<!-- /Newbie -->
]]>
</template>
</templates>


And this should grab it and put it in place of the text I'm looking to replace:


<phpcode><![CDATA[
$search_text = '$vbphrase[x_members_and_y_guests]</phrase>)';
$vbulletin->templatecache['FORUMHOME'] = str_replace($search_text,
$search_text.fetch_template('silly_newbie_template '),$vbulletin->templatecache['FORUMHOME']);]]>
</phpcode>


Assuming I'm right, or close (heheh) so far, I've naturally got a few more questions.

* Guest210212002 grovels

- Since I'm search/replacing, do I need to use forumhome_loggedinuser for the hook? Or should I use cache_templates?
- Do I need to specify executionorder if there's only one plugin in the product?
- Am I at least getting close, or should I just give up now? :bunny:

Thanks very much again, I really do appreciate it. :)

Kirk Y
07-06-2006, 08:59 PM
Your 'newbie template' should just have whatever html you'd like to add. The string used in the plugin is a sort of locator, whatever you've got in the template is added beneath the string, it doesn't replace it -- so you can just put in the "Invisible Users: bla" stuff.

You don't need to declare your template in the plugin code, just put its name in the plugin used to find the string.

I'd just use forumhome_complete for the plugin, that's what works for me, but feel free to try different hooks. But since you've mentioned caching templates, I just remembered that you'll want to do just that to avoid additional queries. Try this code in a plugin using hook 'cache_templates':

if (THIS_SCRIPT == 'index'){
$globaltemplates = array_merge($globaltemplates, array('silly_newbie_template'));
}

To be honest, in all my hacks, I've never specified an executionorder for my plugins. I'm not entirely up to specs when it comes to plugin settings like that, but I've never seen any problems in relation to it.

I'd say you're getting close -- this is how we learn, heck this is how I learned, just posting a lot of threads in the Programming forum.

Code Monkey
07-07-2006, 02:08 AM
You can also just get the silly_newbie_template template from the cache provided you use a plugin to cache it, which you should. Then you won't need to run the fetch_template code.

$search_text = '$vbphrase[x_members_and_y_guests]</phrase>)';
$vbulletin->templatecache['FORUMHOME'] = str_replace($search_text,
$search_text.$vbulletin->templatecache['silly_newbie_template'],$vbulletin->templatecache['FORUMHOME']);

harmor19
07-07-2006, 02:34 AM
Why can't you use a simple variable instead of those functions?

$add_text = "Invisible: $numberinvisible";

$search_text = '$vbphrase[x_members_and_y_guests]</phrase>)';
$vbulletin->templatecache['FORUMHOME'] = str_replace($search_text,
$search_text.$add_text,$vbulletin->templatecache['FORUMHOME']);

Paul M
07-07-2006, 04:49 AM
Why can't you use a simple variable instead of those functionsI would guess because he wants to learn how to use templates.

Try this code in a plugin using hook 'cache_templates':


if (THIS_SCRIPT == 'index'){
$globaltemplates = array_merge($globaltemplates, array('silly_newbie_template'));
}


Array merge is overkill for this, just add to the array.

if (THIS_SCRIPT == 'index')
{
$globaltemplates[] = 'silly_newbie_template';
}
:)

Kirk Y
07-07-2006, 10:46 AM
Well, I learned something new too then, thanks Paul. When should array merge be used?

Guest210212002
07-08-2006, 12:41 PM
Once again thank you all very, very much for guiding me through this. :)

Here's what I changed:

- Dropped the executionorder per acidburn's advice
- Made the template phrased because I forgot to the first time :D
- Removed the search string from the template because I know how it works now (thank you again, acidburn)
- Added Paul's code snippet to add to the global template array
- Added JumpD's code to grab the template from cache
- Changed the hook to forumhome_complete

Things I'm not sure on:

- What/how the template actually gets added to the global templates, unless that's exactly what Paul's code does. I'm assuming that it's basically if you're on the index, then add s_n_t to the cache?
- If I took a step forward here. :D


<?xml version="1.0" encoding="ISO-8859-1"?>

<product productid="chris777_showinvisible" active="1">
<title>Show Invisible Users Online</title>
<description>Will add a count of invisible users in WGO.</description>
<version>1.0.0</version>
<dependencies></dependencies>
<codes></codes>
<templates>
<template name="silly_newbie_template" templatetype="template" username="chris-777" version="1.0.0">
<![CDATA[
<!-- Newbie Template -->
<phrase>$vbphrase[online_invisible]</phrase> $numberinvisible
<!-- /Newbie -->
]]>
</template>
</templates>
<plugins>
<plugin active="1">
<title>Show Invisible in WOL</title>
<hookname>forumhome_complete</hookname>
<phpcode><![CDATA[
if (THIS_SCRIPT == 'index')
{
$globaltemplates[] = 'silly_newbie_template';
}
$search_text = '$vbphrase[x_members_and_y_guests]</phrase>)';
$vbulletin->templatecache['FORUMHOME'] = str_replace($search_text, $search_text.$vbulletin->templatecache['silly_newbie_template'],$vbulletin->templatecache['FORUMHOME']); ]]>
</phpcode>
<phrases>
<phrasetype name="GLOBAL" fieldname="global">
<phrase name="online_invisible">
<![CDATA[ Invisible: ]]>
</phrase>
</phrasetype>
</phrases>
</product>


Again, very much appreciated. :) My weekend plan is to get this all sorted out. (Quite the party, I know!)

Kirk Y
07-08-2006, 03:00 PM
You don't need the <phrase> tags around $vbphrase[onlineinvisible]. You'll only need those if you're going to be using a variable inside of the phrase. For example: phrase1: "There have been {1} users online today, but there were {2} online yesterday." Then you'd use: <phrase 1="$userstoday" 2="$usersyesterday">$vbphrase[onlinetoday]</phrase>.

Paul's code caches the template so your board doesn't have to query for it every page load. The template is installed (if that's what you were trying to say) whenever the product is imported.

This code needs to be put in a plugin by itself using hook 'cache_templates'.
if (THIS_SCRIPT == 'index')
{
$globaltemplates[] = 'silly_newbie_template';
}

You'll want to take a look at this code again too, as it looks like you didn't copy the whole code that was posted. Take another look at JumpD's post.
$search_text = '$vbphrase[x_members_and_y_guests]</phrase>)';
$vbulletin->templatecache['FORUMHOME'] = str_replace($search_text,

- Removed the search string from the template because I know how it works now (thank you again, acidburn)
If you remove the search string from the template, the plugin won't know where to place the 's_n_t' code. As I said earlier, the search string is not replaced, instead whatever is in the 's_n_t' template is added beneath it.