Joomla! VirtueMart: Product List Templates

22 min read

Joomla! VirtueMart 1.1 Theme and Template Design

Joomla! VirtueMart 1.1 Theme and Template Design

Give a unique look and feel to your VirtueMart e-Commerce store

        Read more about this book      

(For more resources on Joomla!, see here.)

The product list page

Product list page is the most important starting page for the shopping life cycle. While the landing page will give some general information regarding the shop, the list of items for sale in the shop is the major job of the product list page. Some shop owners even prefer to use product list page as their home page. Product list page is in singular, but actually the product list page is a series of pages. The total number of pages in the series varies from store-to-store and typically depends on the number of categories you have in the site. Each category will have its own page or even pages, if the category contains many products. Furthermore, the product list page is also used to list the products that relate to a particular manufacturer. It is also used for the keyword search and advanced search, if you enable the product search and advanced search Joomla! modules or the product search Joomla! plugin.

To simplify our discussion, we will first restrict ourselves to the study of category listing. The manufacturer listing and search listing are very similar. Let’s take a look at a typical category listing.

Joomla! VirtueMart 1.1 Theme and Template Design

From the preceding screenshot, we can identify a number of important elements on a product list page:

  • Page header: This includes the category name, category description, the PDF, and print icons. The layout of the page header will depend on the page header templates.
  • Navigation: This includes the order by form, the order by direction button (toggle between ascending and descending), number per page drop-down box, and the page navigation links. Note that the page navigation links can appear both at the top and the bottom. The navigation layout is controlled by the navigation templates.
  • Product listing: This is the major item of the page, where the products are listed in a way defined by the product listing style and the number of products per row settings. Each of the products displayed within the listing is controlled by the core browse template (the core browse template is explained in the section Core browse templates).
  • Addendum elements: This includes the recent products, latest products, featured products, and so on. Each of the addenda may have its own template.
  • Page footer: This is the element placed at the end of the listing. Right now, there is only one element within the page footer, the page navigation.

As we shall see, the layout of each of these elements is controlled by one or more templates. By customizing any one of these templates, we may be able to change the look of the page completely.

We need to distinguish the usage between the terms browse templates and core browse templates. For the purpose of making things clear, we retain the term “browse templates” to refer to all templates within the browse template group. Within this broad template group, there are two subgroups: those which control the layout detail of each individual product (each product in the product listing section) and those which control all the other elements. We refer to them as core and non-core templates, respectively. The core browse templates reside directly under the templates/browse subdirectory. All the non-core templates reside under the subdirectory templates/browse/includes. The difference between the core and non-core templates will become clear in the following explanation.


Looking at our first template

While VirtueMart templates are different from each other, they actually follow a definite pattern. To understand how the template is structured, probably the best way is to look at a sample.

Let’s take a look at the file browse_1.tpl.php as an example. This is one of the core browse templates. The full text of this file is as follows (with line numbers added):

1. <?php if( !defined( '_VALID_MOS' ) && !defined( '_JEXEC' ) )
die( 'Direct Access to '.basename(__FILE__).' is not allowed.' );
2. mm_showMyFileName(__FILE__);
3. ?>
4. <div class="browseProductContainer">
5. <h3 class="browseProductTitle"><a title="<?php echo
$product_name ?>" href="<?php echo $product_flypage ?>">
6. <?php echo $product_name ?></a>
7. </h3>
9. <div class="browsePriceContainer">
10. <?php echo $product_price ?>
11. </div>
13. <div class="browseProductImageContainer">
14. <script type="text/javascript">//<![CDATA[
15. document.write('<a href="javascript:void window.
open('<?php echo $product_full_image ?>', 'win2', 'status=no
dth=<?php echo $full_image_width ?>,height=<?php echo $full_image_
height ?>,directories=no,location=no');">');
16. document.write( '<?php echo ps_product::image_
tag( $product_thumb_image, 'class="browseProductImage" border="0"
title="'.$product_name.'" alt="'.$product_name .'"' ) ?></a>' );
17. //]]>
18. </script>
19. <noscript>
20. <a href="<?php echo $product_full_image ?>"
target="_blank" title="<?php echo $product_name ?>">
21. <?php echo ps_product::image_tag(
$product_thumb_image, 'class="browseProductImage" border="0"
title="'.$product_name.'" alt="'.$product_name .'"' ) ?>
22. </a>
23. </noscript>
24. </div>
26. <div class="browseRatingContainer">
27. <?php echo $product_rating ?>
28. </div>
29. <div class="browseProductDescription">
30. <?php echo $product_s_desc ?>&nbsp;
31. <a href="<?php echo $product_flypage ?>"
title="<?php echo $product_details ?>"><br />
32. <?php echo $product_details ?>...</a>
33. </div>
34. <br />
35. <span class="browseAddToCartContainer">
36. <?php echo $form_addtocart ?>
37. </span>
39. </div>

Downloading the example code You can download the example code files here

HTML fragments

The coding is pretty typical of a VirtueMart template file. You can see that the template is basically an HTML fragment embedded with PHP coding. All PHP code is enclosed within the tag <?php … ?>. In most cases, the PHP code uses the statement echo $field_name to add the field value to the HTML code. We will be looking at those PHP constructs in the next subsection. After parsing the template, the output should be a well-formed HTML code.

You should note that the template is just an HTML fragment, meaning no <html>, <head>, and <body> tags are needed. As you can recall, VirtueMart is just a Joomla! component that will handle the main content. So the HTML fragment produced by the template (together with other code, if any, built up by the page file) will be returned to the Joomla! engine for further processing. Typically, the Joomla! engine will pass this HTML fragment into the Joomla! template which, in turn, will insert the HTML into a location designated by the template. The final output of the Joomla! template will then be a valid HTML document. The <html>, <head>, and <body> tags will therefore be the responsibility of the Joomla! template.

Let’s look at the code to see how these 39 lines of code work. Remarks will only be needed for lines with the PHP tag. All the rest are HTML code that you should be familiar with.

  • Lines 1 to 3 are actually some housekeeping code following the Joomla!/VirtueMart pattern. They will restrict direct access to the code and print out the template filename when debugging.
  • Line 5 will output the product title with the product name embedded inside a hot link pointing to the product detail page.
  • Line 10 will output the product price.
  • Lines 14 to 23 contain a lengthy JavaScript code. The purpose is to output the image thumbnail embedded inside a hot link to open the full image. We need JavaScript here because we want to ensure the pop-up window size fits the full image size. (Otherwise, the pop-up window size will depend on the default size of the browser.) The window size cannot be controlled by HTML and so we need JavaScript help. If JavaScript is not enabled in a client browser, we will fall back to HTML code to handle the pop-up.
  • Line 27 outputs the product rating, as reviewed by the user.
  • Line 30 outputs the product’s short description.
  • Lines 31 to 33 outputs the text of product details within a hot link pointing to the product details page.
  • Line 36 outputs the add-to-cart form, which includes the add-to-cart button, the quantity box, and so on.

PHP crash course

While we are not going to present all the complex program structure of PHP, it will be useful if we have a basic understanding of some of its major constructs. You may not fully understand what exactly each line of code does at first, but stick with us for a little while. You will soon grasp the concept as the pattern appears repeatedly in the exercise we will work on. In the preceding sample template, the PHP coding is pretty simple. (The most complex structure is actually the JavaScript that tries to spit out some HTML on the client browser, not PHP!) We can identify a few basic PHP constructs among the sample code:

  • Variables: Just like any other programming language, a variable is a basic element in PHP. All PHP variables start with the dollar sign $. A variable name consists of alphanumeric characters and the underscore _ character. The first character must be either alphabetical or _, while numerals can also be used after the first character. It should be noted that the space character, together with most punctuation characters, are not allowed in a variable name. Alphabetic characters can be either uppercase or lowercase. Conventionally, VirtueMart will use only lowercase letters for variable names. While both uppercase and lowercase letters can be used without restrictions, variable names are case sensitive, meaning that $Product and $product will be treated as two different variables.
    The variable name chosen usually reflects the actual usage of the variable. In the sample template, $product_name and $product_flypage, for example, are typical variables and they will represent the value of a product name and product flypage, respectively. VirtueMart uses _ to separate words within a variable name to make the variable name more readable. Actually, many of the variables are passed into the template by the VirtueMart page file. These variables are called available fields. We will have more to say about that in the next subsection.
  • Constants: Variables are changing values. You can assign a new value to it at any time and it will take up the new value. There are times when you want to keep the value unchanged. You can use a constant for that purpose. A constant name is pretty much the same as a variable name, but you don’t need the $ character. In line 1 of the sample template, both _VALID_MOS and _JEXEC are constants. You probably recognize that they both use capital letters. This is conventional for Joomla! and VirtueMart so that constants stand out within the code.
    Constants are values that cannot be changed. If you try to give it another value, PHP will complain and fail.
  • Data type: Any variable will have a data type associated with it. Data type can be a number, a string (that is, a series of characters or text), or other possibilities. Since the major purpose of a VirtueMart template is to produce HTML code, we will find that most of the variables we deal with are strings.
    Often, we will need to write out a literal string in our coding. To distinguish our string from the rest of the coding, we need to enclose the literal string with quotes. We can use single or double quotes. Single and double quotes actually have subtle differences, but we won’t go into the detail for the time being. According to the VirtueMart program standard, a literal string should be enclosed in single quotes such as ‘product name‘. Note that ‘product name‘ is a literal string containing the text product name. It is different from $product_name, which is a variable and may contain characters like ‘circular saw‘ instead.
  • Operators: You learnt addition and subtraction at school. They are mathematical operations to combine numbers. In PHP, we also have other operations to combine two or more variables. The most important one in our exercises is probably string concatenation, symbolized by . (the dot character). String concatenation combines two or more strings together to form a single string. The operation ‘hello’.’world’ will give a new string ‘helloworld‘. Note that there is no space character between the words. To make sure the words are separated by a space, we will need to use two concatenations such as ‘hello’.’ ‘.’world’, which will give you the new string ‘hello world’.
  • Functions: Often, we will find that the same pattern of program code is used repeatedly to produce a given result. In PHP, we can group those code together to form a function. Each function will have a name and can be invoked using the following syntax:
    function_name (parameters)
    Here, parameters are values that will need to be passed into the function to evaluate the result. In PHP, we have lots of functions that deal with strings. The function strlen($product_name), for example, will return the number of characters in the string variable $product_name. If $product_name contains the string ‘circular saw‘, strlen($product_name) will return 12. (You probably recognize that strlen is just a short form for string length.) We will learn some more functions along the way.
  • echo statements: This is the most common statement in the template. echo is used to send the value of a string to the output buffer. So echo $product_name literally means “print out the value of the variable $product_name to the output buffer”.
    Sometimes, the echo statement is mistaken to be a function. So you may try to write something like echo($product_name), instead of echo $product_name. While this is acceptable in PHP most of the time, the braces are actually not needed. (You may be aware that sometimes the command print function is used to send data to the output buffer in the place of echo. While print and echo seem interchangeable, echo runs faster than print and so should be the preferred choice to output data.)
  • if statements: The if statement is a construct to test a condition before taking a certain action. The action will be taken only if the condition evaluates to true. The syntax of an if statement is as follows:
    if (condition) action
    where the condition is an expression for testing and action is a statement or a series of statements to be performed, if the expression evaluates to true. The expression can be a true-false type condition (such as $i>0), a mathematical expression (such as $i+$j), or some kind of complex operation involving functions. In any case, it will be considered as true, if it evaluates to a nonzero number or a non-empty string.
  • Statement separator: One important PHP construct we usually overlook is the statement separator ; (the semicolon). We need this to separate two or more statements, even if they are on new lines of their own. In the preceding sample code, we have a “;” at the end of line 1 and 2. This ; is very important. Without that, the PHP parser will be confused and will probably refuse to execute and will give you a fatal error.

These are just a few constructs in PHP for the time being. We will have more to say about PHP as we encounter more constructs along the way.

Available fields

Since many of the variables in our template code are passed down from the VirtueMart page file, one natural question to ask is “What variables can we use in our code?”. Variables that we can use in a template are known as available fields.

The available fields we have inside a template will vary with the template itself. A field which is available in the flypage template may not be available in a browse template. Even among the browse templates, there may be differences. To maximize our customization effort on a template, it is essential to be aware of the available fields in each template.

However, there are so many available fields in a template that it may not be wise to list them all here. For now, it will be useful to distinguish four different types of available fields:

  • Database fields: Most of the data we have comes from the database. Often, the VirtueMart page file just passes those fields directly to the template without changing anything. They are called database fields. The same data you put into the database from the backend will be at your fingertips. Examples are $product_id and $product_sku.
  • Formatted database fields: Sometimes the data you stored in the database is raw data. You will need a different format in the presentation. VirtueMart will do some formatting on the data before passing it to the template. An example is $product_available_date, which is stored in the database as an integer. However, you need to display it in a form that is appropriate to your culture such as yyyy-mm-dd, mm-dd-yyyy, and so on.
  • Processed data: Sometimes there may be complex logic before you can produce data that is useful in the template. A typical example is the $product_price. Do not expect this to be a simple number or a formatted number with the currency symbol added. Actually, the product price will depend on a number of factors such as whether the user has logged in, the shopper group, discount, tax, and so on. So the $product_price in the frontend may be different from the value you entered in the backend. Sometimes it is a formatted number and sometimes it is a message such as call for price. Another example is $product_thumb_image. You may expect this to be just the file location you see in the backend, but its value will depend on whether it is an out of site image, whether the image exists, and whether you want the image to be resized from the full image.
  • VirtueMart class object: In certain cases, VirtueMart developers may think there are too many possibilities for the use of a piece of data. So they decided to let the template designer control what to do with the data. In those cases, VirtueMart will simply pass a class object to the template. An example of this is $ps_product. There are lots of opportunities to make good use of these class objects. However, you will need to understand how this can be properly used and bear all the complexities to make it work.


Core browse templates

Product listing is unarguably the most important element on the product list page. There are two major factors that will affect the product listing: the product listing style, and the core browse template.

Core browse templates are used to define the layout and styles for each product in the product list. There are actually six different core browse templates in the default theme. We can define a default core browse template for general use and also a specific template for each of the product categories. If you take a closer look at the templates, you will find that they are pretty much the same, except the last one which is for creating a PDF file.

We already saw the detail coding in the browse_1.php. We don’t need to repeat it here again. So, let’s start on some exercises with the browse_1 template right away.

Exercise 3.1: Adding an Ask-Seller link to the browse page

We know that in the product detail page, there is an Ask-Seller link which will bring up a form so that a shopper can ask a question about the product. This link is not available on the product list page. In this exercise, we will add a similar link to the browse page. While we can use the exact same link here, we purposely use a simpler way to do it to make it easier to understand.


  1. Open your favorite text editor. Navigate to the VirtueMart frontend root.
  2. Open the file themes/default/templates/browse/browse_1.php.
  3. Insert the following line of code after line 5:
    <a href="index.php?option=com_virtuemart&page=shop.ask&
    product_id=<?php echo $product_id ?>">Ask a question about this
    product</a><br />
  4. Save the file and upload it to your server.
  5. Point your browser to any VirtueMart browse page that uses the browse_1.php template, you should see the Ask-Seller link added to every product. (This exercise is done on the browse_1 template only. If you browse to the product list of an individual category, the new styles will show only if the category is using the browse_1 template. The same applies to most of the following exercises.)

Joomla! VirtueMart 1.1 Theme and Template Design


  1. The Ask-Seller link is an <a> tag with the href pointing to the Ask Seller page.
  2. The href is built using three parameters:
    • option=com_virtuemart points to the VirtueMart component.
    • page=shop.ask points to the actual Ask Seller page. By changing the page parameter, we can point the shopper to any of the VirtueMart pages.
    • product_id=<? echo $product_id ?> provides the product ID to the Ask Seller page so that it knows which product the shopper has questions on. We need to use a variable because the product_id will vary from product to product.
  3. In the previous code, we purposely hardcoded the link as a relative URL to make the code simpler. This works unless SEF is enabled. To cater for SEF, a more generic way to create the link will be needed.
  4. The text Ask a question about this product is static text. Feel free to change it to anything you think appropriate. This will not affect the function of the link.
  5. <br /> is needed to insert a line break after the link.

Exercise 3.1 demonstrates the basic technique to modify a template. You can add static text to a template in whatever way you want. If you need variable data, simply insert the appropriate echo statement at the required place.


Exercise 3.2: Changing core browse template CSS

One major task of customizing a template is changing the style of HTML elements. In this exercise, we are going to add some CSS styles to the core browse template.


This exercise is built upon the browse_1.php file we modified in Exercise 3.1. If you start from the original template file, the exact line number may differ.


  1. Open your favorite text editor. Navigate to the VirtueMart frontend root.
  2. Open the file themes/default/templates/browse/browse_1.php.
  3. At line 4 (that is, the top of the file), insert the following lines of code:

    <?php if (!defined(VM_CUSTOM_CSS)) {
    define ('VM_CUSTOM_CSS',1);
    .browseProductContainer {border:1px solid #999;padding:5px;bac
    <?php } ?>

  4. Save the file and upload it to your server.
  5. Point your browser to any VirtueMart browse page that uses the browse_1.php template. You should see the product list now with the border, margin, and padding added.

Joomla! VirtueMart 1.1 Theme and Template Design


  1. We added a stylesheet for the class browseProductContainer in the template file. The stylesheet will be included as part of the HTML output to the browser.
  2. The core browse template will be applied for each product. So any coding added to it will be repeated for each product. To ensure that the stylesheet is included only once in the HTML, we define a constant named VM_CUSTOM_CSS the first time the stylesheet is included.
  3. The if condition at the start of the coding tests for the existence of the constant VM_CUSTOM_CSS. When the code is executed a second time, VM_CUSTOM_CSS is already defined and so the statements within the braces will be skipped.

Exercise 3.2 demonstrates another basic technique to modify a template. The technique applies not only to a CSS stylesheet, but to all coding in general. It can be used for JavaScript inclusion, and for other coding that you only need to appear once in the HTML.


Exercise 3.3: Moving and modifying data

In this exercise, we are going to experiment with moving data around and adding some new data fields that are available for the template.


This exercise is built upon the browse_1.php file we modified in Exercise 3.2. If you start from the original template file, the exact line numbers may differ.


  1. Open your favorite text editor. Navigate to the VirtueMart frontend root.
  2. Open the file themes/default/templates/browse/browse_1.php.
  3. At line 40, insert the following line of code:

    <br />Weight: <?php echo number_format($product_weight,1) .
    ' ' . $product_weight_uom ?><br />

  4. Move the Ask-Seller link from line 13 to line 47, that is, after the closing </span> tag for form_addtocart.
  5. Move the <br /> tag from the end of line 47 to the beginning of the line, that is, the line will become:
    <br /><a href="index.php?option=com_virtuemart&page=shop.ask&
    product_id=<?php echo $product_id ?>">Ask a question about this
  6. Save the file and upload it to your server.
  7. Point your browser to any VirtueMart browse page that uses the browse_1.php template and you should see that the Ask-Seller link has moved to the end of the display, and the product weight and unit has been added to every product.

Joomla! VirtueMart 1.1 Theme and Template Design


In this exercise, we have performed two modifications. We moved the Ask-Seller link to the bottom instead of the top and added the product_weight field to the browse template.

Actually, the order of appearance of the product fields can be changed at will. You can move it around to fit your requirement similar way.

To add new data to the display, you first need to determine what you want to show and whether the data is within the list of available fields. Since we know $product_weight and $product_weight_uom (uom stands for unit of measure) are available, we can simply use concatenation to build the final text for the output.

The weight is rounded off to 1 decimal place using the number_format() function to make it look nicer. You can change the number of decimal places by changing the second parameter to the number_format() function.



Please enter your comment!
Please enter your name here