Use your business data to your advantage with the help of Syncfusion’s new data science offerings. Discover how a custom big data solution can provide your company with valuable predictions about key market trends.

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.

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):

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.

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.)

Notes

The Ask-Seller link is an <a> tag with the href pointing to the Ask Seller page.

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.

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.

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.

<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.

Preparation

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.

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.

Notes

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.

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.

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.

Preparation

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.

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.

Notes

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.

Header templates

Page header is the next important element on the product list page. The page header varies with the type of product list page. So the category product listing, manufacturer product listing, and the keyword product listing have their respective header templates. There is an additional header template for the all product listing which lists out all the products in the VirtueMart shop. All these header templates are found within the browse/includes subdirectory of the VirtueMart templates directory. They are named as browse_header_category.tpl.php, browse_header_manufacturer.tpl.php, browse_header_keyword.tpl.php, and browse_header_all.tpl.php, respectively.

The browse_header_category template is used when the listing requested belongs to a certain category, identified by category_id in the URL request parameters. For the standard VirtueMart install, the category_id=1 corresponds to the Hand Tools category. The URL for this category is http://your_site_domain/index.php?option=com_virtuemart&page=shop.browse&category_id=1.

The category header template consists of four major subelements (in addition to the print, e-mail, and PDF buttons): the category name, the RSS feed button, the child category list, and the category description. The child category list may or may not exist. This is the list of child categories that belong to the category of the given category_id.

The browse_header_manufacturer template is used when there is a manufacturer_id specified in the URL. The template just contains two subelements: the manufacturer name and the manufacturer description.

The browse_header_keyword template is used for product searches. The template has just a single element: the search text.

The browse_header_all template is used just for the all product list. The link for the all product list is found in the mod_virtuemart module. You can also create your own all product list link by setting page=shop.browse in the URL. The full URL is http://your_site_domain/index.php?option=com_virtuemart&page=shop.browse.

The browse_header_all template consists of two sub elements: the browse page label and the RSS feed button.

Exercise 3.4: Adding a category banner

In this exercise, we are going to add a category banner to the category browse header. Here we will use a simple JPEG file. However, you can replace them with a flash slide or even an HTML page.

Preparation

Create category banners category_banner_1.jpg, category_banner_2.jpg, category_banner_3.jpg, and category_banner_4.jpg for the four categories with a standard VirtueMart install. You can use Photoshop or any other graphic editing program for this. The files should be placed under the subdirectory shop_image of the frontend VirtueMart directory.

Point your browser to the VirtueMart browse page for each of the categories. You should see a different category banner for each category.

Notes

In this exercise, we demonstrated one way to show a different image file for a different category.

The technique is not limited to JPG files. You can replace the img tag with an object tag to show a flash file. You just need to find some way to map the category to the file. In this example, we use $category_id. You can use $category_name or some other available fields.

Navigation templates

The navigation section is controlled by the template browse_orderbyform.tpl.php. There are two major elements in the navigation: the page navigation list and the sort order form, each of them has its own template. Both navigation templates are found in the includes subdirectory of the templates/browse directory.

The page navigation list is controlled by the template browse_pagenav.tpl.php. There are three subelements in the template: navigation links (including page number, previous, and next links), the limit drop-down box (to control the number of products per page), and the page counter (showing the current product numbers on the page). Actually, VirtueMart will pass a pageNavigation.class object to the template to show these three subelements.

The sort order form is controlled by the template browse_orderbyfields.tpl.php. This template will list out the order by selection with a drop-down box. The options available in the drop-down box are controlled by the VirtueMart configuration on the Site tab.

Exercise 3.5: Using a custom sort order form

In this exercise, we are going to replace the sort order form drop-down with a list of hyperlinks.

Point your browser to the VirtueMart browse page. You should see the sort by text link instead of the drop-down box.

Notes

There are different ways to present the sort order options to the shopper without changing anything in the server coding. This is the beauty of separating the presentation from the data and, for that matter, using the template.

The variable $VM_BROWSE_ORDERBY_FIELDS is an array containing the different options set in the VirtueMart configuration. An array is a PHP construct used to hold several values within one single variable. Each value or element will have an index which is either a number or a string. In the default VirtueMart configuration, the array $VM_BROWSE_ORDERBY_FIELDS contains three values:

The five possible options for sorting are product_list, product_name, product_sku, product_price, and product_cdate. They are pretty much self explanatory. The only two options that may need explanation are product_list and product_cdate. Sort by product_list means sorting in order of adding the product to the category. This doesn't seem to be controlled by any backend function and can probably only be changed at the database level. Sort by product_cdate means sorting by the creation date of the product.

In this exercise, we replace the drop-down with a list of links. Basically, we retain the original logic that the link will show as set by the $VM_BROWSE_ORDERBY_FIELDS.

Because we are using an <a> tag, we need to use JavaScript to control when to submit the form. The JavaScript function submit_orderby does exactly that. It first sets the orderby field of the form (named order) and submits the form.

We also added some basic CSS styles to format the links in a nicer way. You can change the styles without affecting the basic function.

Add-to-cart form template

Whether the add-to-cart button will show in the product list page or not will depend on the settings in the VirtueMart configuration and also on the product. If the product is a parent product and/or has advanced/custom attributes, the shopper will need to select additional options before the product can be added to the shop cart. In those cases, the add-to-cart form will not show in the product list. Instead, the shopper will need to go to the product detail page to order that product. (The add-to-cart will not show if VirtueMart is just used for a catalog or if there is no price set for the product as well.)

If the add-to-cart shows in the product list, its layout will be determined by the template addtocart_form.tpl.php. This is not a complicated template and there is not much to customize. But you can still change it if the need arises.

Exercise 3.6: Showing the add-to-cart button in all cases

As explained previously, there are situations where the add-to-cart button will not show. This is certainly appropriate if the site is used just as a catalog or when there is no price set. However, it may appear puzzling to the shopper if just a few products on the product list do not have the add-to-cart button. They may think that the products are not for sale.

However, you should bear in mind that when a product needs additional parameters before it can be placed in the shopcart, the only way to do that is on the product details page. (You may be tempted to show the attribute drop-down on the product list, but VirtueMart does not have a provision for that. Adding that feature will need substantial changes in several core VirtueMart files.)

Can we still show an add-to-cart button for those products that need additional selection? Maybe we could just redirect the shopper to the product details page to make the additional selection. This is exactly what this exercise tries to accomplish. However, we will need to modify the core browse template instead of the add-to-cart form template to make this work.

Preparation

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

Point your browser to the VirtueMart browse page. You should see the add-to-cart button showing for all products. (For example, the add-to-cart button will show up for Circular Saw as well.)

Notes

Since our goal is to change the add-to-cart button, it seems the work should be done on the addtocart_form template. But actually, customizing the addtocart_form template does not help. This is because the template will not be invoked at all when there are attributes that need to be selected.

In the original coding, the VirtueMart page file shop.browse.php will check whether the product should have an add-to-cart button. If yes, it will invoke the addtocart_form template and pass its value to the core browse template (in this case, browse_1.php) through the variable $form_addtocart. For those products that do not match the prescribed conditions, the addtocart_form will not be called at all. In those cases, shop.browse.php will simply pass an empty string to the core browse template.

We can certainly modify the shop.browse.php logic to enable the addtocart_form template to be parsed for all products. However, there are two problems with this approach:

shop.browse.php is a core file. Customization will be lost after upgrade.

We will need to modify two files instead of one.

In the preceding modifications, the magic is solely done in the core browse template. Instead of using echo $form_addtocart unconditionally, we replace it with an if condition. If $form_addtocart is not empty, the if condition will evaluate to true, the original add-to-cart button will still be sent as before.

If $form_addtocart is an empty string (meaning the VirtueMart prescribed conditions do not apply), we need to create the button ourselves. The coding is actually a clone from that in the addtocart_form template. We need to change the input type from submit to button to change the click behavior. We also added an onclick event handler to open the product flypage instead of adding the product to the shopcart.

Previously, we used add to cart as the button label. You can change the label to whatever text you deem appropriate (such as Select Additional Attributes). You don't need the function call $VM_LANG->_() unless multilanguage is needed. Simply replace the line with the following line of code:

$button_lbl = 'your text';

Otherwise, you will need to add another language element to the language file.

We also assumed that it is appropriate to show an add-to-cart button for all the products. Actually, this is not correct if the product does not have a price or the product is not in stock. To cater for these cases, additional checking will need to be added.

Summary

In this article, we have seen the structure of the product list page. We also looked through all the templates related to the product list and worked through several exercises to customize the browse templates. The technique we learnt here is not specific to the browse templates. You can apply them to other VirtueMart templates or even to Joomla! or non-Joomla! PHP code.

Alerts & Offers

Series & Level

We understand your time is important. Uniquely amongst the major publishers, we seek to develop and publish the broadest range of learning and information products on each technology. Every Packt product delivers a specific learning pathway, broadly defined by the Series type. This structured approach enables you to select the pathway which best suits your knowledge level, learning style and task objectives.

Learning

As a new user, these step-by-step tutorial guides will give you all the practical skills necessary to become competent and efficient.

Beginner's Guide

Friendly, informal tutorials that provide a practical introduction using examples, activities, and challenges.

Essentials

Fast paced, concentrated introductions showing the quickest way to put the tool to work in the real world.

Cookbook

A collection of practical self-contained recipes that all users of the technology will find useful for building more powerful and reliable systems.

Blueprints

Guides you through the most common types of project you'll encounter, giving you end-to-end guidance on how to build your specific solution quickly and reliably.

Mastering

Take your skills to the next level with advanced tutorials that will give you confidence to master the tool's most powerful features.

Starting

Accessible to readers adopting the topic, these titles get you into the tool or technology so that you can become an effective user.

Progressing

Building on core skills you already have, these titles share solutions and expertise so you become a highly productive power user.