Back to vBulletin 4 Articles

[vB4] A Beginner's Guide To Creating vBulletin Products
by MarkFL 28 May 2015
Rating: (10 votes - 4.90 average)

Hello vBulletin Community,

This article is aimed at those of you who are making manual template edits and writing plugins to customize your site in an effort to help guide you into turning your customizations into distributable products so that you can share your work with others in a user-friendly and professional manner.

When I first decided to try to create vBulletin products about 2 months ago, I began looking at the XML files distributed by some of the generous folks here uploading their products for our use. I naively began creating my own XML files using theirs as a template. While this works, it can be quite tedious and I later found there is a much better way to go about this. vBulletin has all the tools we need to easily and successfully turn our coding into products we can share with other vBulletin owners. If we follow the right steps, vBulletin will generate the XML file for us.

While not absolutely necessary, I highly recommend creating a dev site where you can develop and debug your products without worrying about blowing anything up or otherwise causing any downtime for your users. I set up a local dev site on my hard drive for just such a purpose. You may also choose to set up a dev site on your server.

I recently developed a simple add-on for the site I help administrate for displaying DBTech's thanks statistic for our users in their postbits and on their profile pages. I will take you through the process of developing this product as a means of demonstrating many aspects of vBulletin product development.

Step 1: Put Your Dev Site Into Debug Mode

Putting your dev site into debug mode will activate many AdminCP features that you will need to develop your products. To do this, locate the file:

/includes/config.php

and at the top under the opening tag <?php enter the following line:

PHP Code:
$config['Misc']['debug'] = true
and save the file. That's all there is to it...but if you are using your live site for development you will want to set debug mode for admins only, please see this article:

3 methods for enabling debug mode for site admin ONLY

Okay, now that we are in debug mode, we are ready to begin product development.

2.) Adding The Product

We need to tell vBulletin that there is a new product with which to associate the templates and plugins we will be creating. So follow:

AdminCP ► Plugins & Products ► Manage Products

Scroll down to the bottom, click "[Add/Import Product]" and look for the block labeled "Add New Product." This is where we give vBulletin the details of our new product.

Product ID: We want to give our product an ID we know will be unique among all the other products that have ever been uploaded here at vBorg. I like to begin the ID with a descriptive string, and for this product I chose "displaythanksdata" and then to ensure uniqueness I append my username and the version of vB, so that my final Product ID is:

displaythanksdatamarkflvb4

You will likely develop your own naming conventions over time which is good; you just want to be sure your use a unique ID.

Title: Here you want to enter a descriptive title for your new product. This is what you will see when you manage your products and choose the product with which you wish to associate templates and plugins. I like to begin the title of each of my products with my username since vBulletin displays them alphabetically this will keep all of my own products together for ease of location. For this product, I chose the title:

MarkFL: Display DBTech Thanks Data

Version: Since this is a new product, I will use a version number of 1.0.

Description: You want to briefly describe what your product does. You know what it will do, but think of those who download your product and use it on their sites...they will appreciate seeing this description. For this product, I wrote:

Displays a user's thanks data in their postbits and/or profiles.

Product URL: If you will be uploading your product here for others to download and use, you will want them to easily be able to find your product thread so they can quickly go to that thread as a reference for installing, using, and see if perhaps an issue they may be having is answered there. The end of the URL contains the Product ID, and so the full Product URL for this product will be:

http://www.vbulletin.org/forum/misc.php?do=producthelp&pid=displaythanksdatamarkflvb4

Version Check URL: This will allow those who have installed your product to quickly ascertain if they are running the most current version of your product. Like the Product URL, the end of the string is the Product ID, and for this product, we have:

http://www.vbulletin.org/forum/misc.php?do=productcheck&pid=displaythanksdatamarkflvb4

Now, vBulletin has everything it needs to know about your new product, so click "Save."

3.) Add New Setting Group

We need to define the settings for our product, so that our users can configure the product to their liking. So follow:

AdminCP ► Settings ► Options

Because you are in debug mode, you will see a fieldset element on the left within the "vBulletin Options" block labeled "Developer Options." Click "Add New Setting Group."

Varname: We want to use a unique name here, and I like to begin with my username, then an underscore, and then an acronym for the product, and in this case I chose:

markfl_dtd

The "dtd" stands for "display thanks data." From here on out all variables associated with this product will begin with the string "markfl_dtd" for consistent naming convention.

Title: This is what the user will see when they choose from the options in the select element on the right of the "vBulletin Options" block. I like to use the title of the product here, and then append the version number, so I wrote:

MarkFL: Display DBTech Thanks Data v1.0

Product: From the drop-down menu choose the product you defined in step 2, in this case:

MarkFL: Display DBTech Thanks Data

Display Order: I have so far just used the default value of 65535.

vBulletin Default: I have so far left this set to the default value of "Yes."

Finally, click "Save" and you will be ready to add your product's settings. I always like to give the user the ability to disable products in the settings, so the first setting we will define will be to enable/disable the product. So, click "[Add Setting]" and now we can define this first setting.

Varname: This will be a variable we can use in our plugins to determine if actions should be taken or not depending on whether the product is enabled or not. I used:

markfl_dtd_enabled

and in our plugins, we can use $vbulletin->options['markfl_dtd_enabled'] to determine the value of this setting.

Setting Group and Product: From the dropdown menus, choose the options you previously defined.

Title: This should be a short descriptive name that will appear in bold above the elements that allow the user to configure this setting, such as radio buttons, checkboxes and textareas. Here, I used:

Product Enabled?

Description: This is used to explain to the user exactly what this setting does, and if needed how to use it. Since this is a simple Yes/No question we may simply use something like:

Choose "Yes" to enable this product.

Option Code: Here we may simply use:

yesno

This will instruct vBulletin to generate 2 radio buttons, one for Yes and one for No. The value of the associated setting variable will be 0 for No and 1 for Yes.

Default: I like to default my products to No which forces the user to visit the products options page and configure the product. So, we will use:

0

Data Validation Type: For this setting we want to choose:

Free

Validation PHP Code: Leave this blank as no validation is required.

Display Order: Use the default value of 10 presented there. You can edit this field later if you decide you want to change the order in which the settings appear on the page. vBulletin will use multiples of 10 to give you plenty of room to insert settings in between two previously defined settings if you realize you need to add one or more there.

Blacklist: I don't know what this does, but so far I have always left this at the default setting of "No."

vBulletin Default: "Yes"

Click "Save" and then we will be ready to add the next setting. I wanted to give users the ability to decide whether they want the thanks data displayed in user postbits or not. This will be another "Yes/No" setting defined in the same way as the first setting, with the differences being:

Varname: markfl_dtd_postbit

Title: Thanks Data In Postbits?

Description: Set whether thanks data is displayed in user postbits.

Display Order: 20

Click "Save." The next setting will allow the user to decide if they want the thanks data to be displayed on user profiles. This is another "Yes/No" setting, with the differences being:

Varname: markfl_dtd_profile

Title: Thanks Data In Profiles?

Description: Set whether thanks data is displayed in user profiles.

Display Order: 30

Click "Save." Now, the next 2 settings pertain to a value that is computed in the plugins, which is the ratio of thanks received to posts made. I help administrate a math help forum, and we decided our users might benefit by seeing this data for the users providing help to them. We didn't want to display this ratio if it is too low, nor for new users with a small number of posts. So, the next setting will allow the user to set the post threshold for display the thanks/post ratio.

Varname: markfl_dtd_tpp_postthreshold

Title: Thanks Per Post Post Threshold

Description: Set the minimum number of posts for a user before the thanks per post data is displayed.

Option Code: Leave Blank (this will instruct vBulletin to generate an input element of type "text.")

Default: 0

Data Validation Type: We want to make certain the user inputs a non-negative integer here, so choose:

Integer

Validation PHP Code: The Data Validation Type will ensure the input is an integer, but to make certain it is not negative, we can enter the following Validation PHP Code:

PHP Code:
if ($data 0)
{
    return 
false;
}
else
{
    return 
true;

An error message will display if a negative value is entered, and if the user ignores this warning, an alert will pop up letting them know the page has one or more errors if they try to save the settings. They can still save the settings, but they have been warned. We can take further measures to ensure valid data in our plugins if so desired.

Display Order: 40

The last setting will allow the user to set the minimum value for the thanks/post ratio before this datum will be displayed.

Varname: markfl_dtd_tpp_valuethreshold

Title: Thanks Per Post Value Threshold

Description: Set the minimum value of thanks per post for a user before the thanks per post data is displayed.

Default: 0

Data Validation Type: Numeric (We want to allow non-integral values here, but we don't want negative numbers, so use the same Validation PHP Code as the previous setting.)

We now have all the setting in place to allow the user to configure the product to their liking.

4.) Define The Custom Templates

This product uses 2 custom templates, one is rendered at a hook location within the "postbit_legacy" template, and the other will replace the "memberinfo_block_statistics" if the thanks data is to be displayed on user profiles. We will create the template for rendering the thanks data in user postbits first.

So, follow:

AdminCP ► Styles & Templates ► Style Manager

And for the "MASTER STYLE" select "Add New Template." Then on the generated form, select the product from the drop-down menu for which we wish to create the new template and the enter:

Title: markfl_thanks_postbit

Template:

HTML Code:
<dt>Thanks</dt> <dd>{vb:raw post.likes_given} time<vb:if condition="$post['likes_given'] != 1">s</vb:if></dd>
<dt>Thanked</dt><dd>{vb:raw post.likes_received} time<vb:if condition="$post['likes_received'] != 1">s</vb:if></dd>
<vb:if condition="$p >= $vbulletin->options['markfl_dtd_tpp_postthreshold'] AND $thanked_per_post >= $vbulletin->options['markfl_dtd_tpp_valuethreshold']">
	<dt name="TPP">Thank/Post</dt><dd>{vb:raw thanked_per_post}</dd>
</vb:if>
Click "Save." Next, we will create the replacement template for displaying thanks data on user profiles.

Title: markfl_thanks_memberinfo_block_statistics

Template:

HTML Code:
<!-- Statistics -->
<div class="blocksubhead subsectionhead userprof_headers userprof_headers_border" >
<h4 id="view-statistics" class="subsectionhead-understate"  style="width:100%">{vb:rawphrase statistics}</h4><br />
</div>
<div class="blockbody subsection userprof_content userprof_content_border">
	{vb:raw template_hook.profile_stats_first}
	<h5 class="subblocksubhead subsubsectionhead first">{vb:rawphrase total_posts}</h5>
	<dl class="blockrow stats">
		<dt>{vb:rawphrase total_posts}</dt>
		<dd> {vb:raw prepared.posts}</dd>
	</dl>
	<dl class="blockrow stats">
		<dt>{vb:rawphrase posts_per_day}</dt>
		<dd> {vb:raw prepared.postsperday}</dd>
	</dl>
	<vb:if condition="$prepared['lastposturl']">
	<dl class="blockrow stats">
		<dt>{vb:rawphrase last_post}</dt>
		<dd><a href="{vb:raw prepared.lastposturl}">{vb:raw prepared.lastposttitle}</a> {vb:raw prepared.lastpostdate}<vb:if condition="!$show['detailedtime']"> <span class="time">{vb:raw prepared.lastposttime}</span></vb:if></dd>
	</dl>
	</vb:if>
	<h5 class="subblocksubhead subsubsectionhead">Thanks Data</h5>
	<dl class="blockrow stats">
		<dt>Thanks Given</dt>
		<dd>{vb:raw markfl_thanks_given}</dd>
	</dl>
	<dl class="blockrow stats">
		<dt>Thanks Received</dt>
		<dd>{vb:raw markfl_thanks_received}</dd>
	</dl>
	<vb:if condition="$postcount >= $vbulletin->options['markfl_dtd_tpp_postthreshold'] AND $markfl_thanks_per_post >= $vbulletin->options['markfl_dtd_tpp_valuethreshold']">
		<dl class="blockrow stats">
			<dt>Thanks Received Per Post</dt>
			<dd>{vb:raw markfl_thanks_per_post}</dd>
		</dl>
	</vb:if>
	<vb:if condition="$show['album_block']">
	<h5 class="subblocksubhead subsubsectionhead">{vb:rawphrase albums}</h5>
	<dl class="blockrow stats">
		<dt>{vb:rawphrase total_albums}</dt>
		<dd> {vb:raw block_data.albumcount}</dd>
	</dl>
	<dl class="blockrow stats">
		<dt>{vb:rawphrase total_pictures}</dt>
		<dd> {vb:raw block_data.picturecount}</dd>
	</dl>
	<ul class="group">
		<li><a href="album.php?{vb:raw session.sessionurl}u={vb:raw prepared.userid}">{vb:rawphrase albums_created_by_x, {vb:raw prepared.username}}</a></li>
	</ul>
	</vb:if>
	<vb:if condition="$show['vm_block']">
	<h5 class="subblocksubhead subsubsectionhead">{vb:rawphrase visitor_messages}</h5>
	<dl class="blockrow stats">
		<dt>{vb:rawphrase total_messages}</dt>
		<dd> {vb:raw prepared.vm_total}</dd>
	</dl>
	<dl class="blockrow stats">
		<dt>{vb:rawphrase most_recent_message}</dt>
		<dd>{vb:raw prepared.lastvm_date}<vb:if condition="!$show['detailedtime']"> <span class="time">{vb:raw prepared.lastvm_time}</span></vb:if></dd>
	</dl>
	<ul class="group">
		<li><a href="javascript://" onclick="return tabViewPicker(document.getElementById('visitor_messaging-tab'));">{vb:rawphrase visitor_messages_for_x, {vb:raw prepared.username}}</a></li>
		<vb:if condition="$show['post_visitor_message']"><li><a href="javascript://" onclick="return goto_post_pm();">{vb:rawphrase post_a_visitor_message_for_x, {vb:raw prepared.username}}</a></li></vb:if>
	</ul>
	</vb:if>
	<vb:if condition="$show['usernote_block']">
	<h5 class="subblocksubhead subsubsectionhead">{vb:rawphrase user_notes}</h5>
	<vb:if condition="$show['usernote_data']">
	<dl class="blockrow stats">
		<dt>{vb:rawphrase total_user_notes}</dt>
		<dd> {vb:raw prepared.usernotecount}</dd>
	</dl>
	<dl class="blockrow stats">
		<dt>{vb:rawphrase most_recent_user_note}</dt>
		<dd> {vb:raw block_data.note_lastdate}<vb:if condition="!$show['detailedtime']"> <span class="time">{vb:raw block_data.note_lasttime}</span></vb:if></dd>
	</dl>
	</vb:if>
	<vb:if condition="$show['usernote_data'] OR $show['usernote_post']">
	<ul class="group">
		<vb:if condition="$show['usernote_data']">
		<li><a href="usernote.php?{vb:raw session.sessionurl}u={vb:raw userinfo.userid}">{vb:rawphrase user_notes_for_x, {vb:raw prepared.username}}</a></li>
		</vb:if>
		<vb:if condition="$show['usernote_post']">
		<li><a href="usernote.php?{vb:raw session.sessionurl}do=newnote&amp;u={vb:raw userinfo.userid}">{vb:rawphrase post_a_user_note}</a></li>
		</vb:if>
	</ul>
	</vb:if>
	</vb:if>
	{vb:raw template_hook.profile_stats_pregeneral}
	<h5 class="subblocksubhead subsubsectionhead">{vb:rawphrase general_information}</h5>
	<vb:if condition="$prepared['lastactivitydate']">
	<dl class="blockrow stats">
		<dt>{vb:rawphrase last_activity}</dt>
		<dd> {vb:raw prepared.lastactivitydate}<vb:if condition="!$show['detailedtime']"> <span class="time">{vb:raw prepared.lastactivitytime}</span></vb:if></dd>
	</dl>
	</vb:if>
	<vb:if condition="$prepared['action']">
	<dl class="blockrow stats">
		<dt>{vb:rawphrase current_activity}</dt>
		<dd> {vb:raw prepared.action} {vb:raw prepared.where}</dd>
	</dl>
	</vb:if>
	<dl class="blockrow stats">
		<dt>{vb:rawphrase join_date}</dt>
		<dd> {vb:raw prepared.joindate}</dd>
	</dl>
	<vb:if condition="$vboptions['usereferrer'] AND $userinfo['referrerid']">
	<dl class="blockrow stats">
		<dt>{vb:rawphrase referrer}</dt>
		<dd><a href="member.php?{vb:raw session.sessionurl}{vb:raw userinfo.referrerid}-{vb:raw userinfo.referrername}">{vb:raw userinfo.referrername}</a></dd>
	</dl>
	</vb:if>
	<vb:if condition="$vboptions['usereferrer'] AND $prepared['referrals']">
	<dl class="blockrow stats">
		<dt>{vb:rawphrase referrals}</dt>
		<dd> {vb:raw prepared.referrals}</dd>
	</dl>
	</vb:if>
	<vb:if condition="$prepared['homepage']">
	<dl class="blockrow stats">
		<dt>{vb:rawphrase home_page}</dt>
		<dd> <a href="{vb:raw prepared.homepage}" target="_blank">{vb:raw prepared.homepage}</a></dd>
	</dl>
	</vb:if>
	{vb:raw template_hook.profile_stats_last}
</div>
<!-- view-statistics -->
Now we have our templates defined, the next step is to write the plugins to make everything work.

vblts.ru supports vBulletin®, 2022-2024