Editing Client Area Menus

From WHMCS Documentation

WHMCS includes a programmatic way to interact with the client area navigation and sidebars through hooks and modules.

Menu structure

The client area's navigation and sidebars are defined in a tree structure of menu item objects. Each menu item has one parent item and can have many child items. The only menu item with no parent an invisible root item that is not displayed on the page.

Navigation bars

Navigation bars consist of the invisible menu root with children representing every item displayed in the navigation bar. Each of these items may have their own child items. These child items are rendered as that navigation bar item's dropdown menu.

  • Navigation bar root Item
    • navigation item
    • navigation item
      • dropdown item
    • navigation item
      • dropdown item
      • dropdown item
      • dropdown item
    • navigation item

Navigation bars are displayed on every page in the client area, but their contents may change if a client is logged in or not. For instance, the navigation bar may show login and password recovery links if a user isn't logged in.

Sidebars

Like the navigation bar, the sidebars in WHMCS begin with an invisible menu root, but each child represents an individual panel in the side bar. Each panel item is rendered as an item within the panel in the WHMCS client area.

  • Sidebar root Item
    • panel
      • panel item
      • panel item
      • panel item
    • panel
      • panel item
      • panel item
    • panel
      • panel item
      • panel item
      • panel item

Sidebars help provide context for the data displayed on the page. Different pages in the client area may have different sidebar items. For example, a page to view an account may contain sidebar links to view that client’s open tickets or unpaid invoices.

Menu layout

Desktop mode

The WHMCS 6.0 client area layout in desktop mode
There are two navigation bars in WHMCS’ client area. The primary navigation bar contains the bulk of the menu and floats to the left of the secondary navigation bar. The secondary navigation bar contains user-specific items and changes if a client is logged in to WHMCS. When a client is not logged in then the secondary navigation contains a login link, and when a client is logged in then the secondary menu contains links to the client’s account.

Likewise there are two sidebars on every client area page. The primary sidebar is displayed above the secondary side bar on the left side of the page. Sidebar content varies per page, though the primary sidebar typically displays information directly relevant to the page content while the secondary sidebar usually contains more general links.

Responsive mode

The WHMCS 6.0 client area layout in responsive mode
Responsive mode is activated when WHMCS’ client area is viewed on a smaller screen device such as a phone or tablet. WHMCS rearranges the page layout in responsive mode for best display on mobile devices.

In responsive mode the primary and secondary navigation bars are displayed above the primary sidebar, followed by the page’s content with the secondary sidebar displayed at the bottom of the page.

Menu items

Menu items are modeled in code by the \WHMCS\View\Menu\Item class. These objects contain all of the information needed to render that menu item within a template, including their parent and child menu item relationships. Menu items can have the following aspects:

  • A single parent item
  • Multiple optional child items
  • A name used to internally refer to the menu item
  • A label to display when the item is rendered to the page. If no label is defined, then WHMCS render's the menu item's name
  • A URI to link to when the user clicks or taps on a menu item
  • An optional icon displayed to the left of the label. WHMCS has access to both the Glyphicons and Font Awesome libraries.
  • An optional badge displayed to the right of the label, usually used for contextual information, such as the number of tickets in a status next to that statuses' name
  • The order that a menu item is displayed in its parent's list of children.

Menu item arrangement

Navigation bars

A client area navigation bar item represented as menu item properties.
This diagram represents an individual menu item in the navigation bars. All of the menu item’s children are rendered as dropdown menu items. All menu items are rendered with icons to the left of a link to the menu item’s URI followed by the menu item’s badge.

Sidebars

A client area sidebar panel represented as menu item properties.
This diagram represents an individual menu item in the sidebars. Unlike the navigation bars this menu item renders a panel in the side bar. Items in the panel rendered by the menu item’s children. Note how body and footer HTML content are also rendered around sidebar panel items. All menu items are rendered with icons to the left of a link to the menu item’s URI followed by the menu item’s badge.

Interacting with menus

Hooks

WHMCS 6.0 introduces a number of hooks to allow menu interaction before they’re sent to the template renderer. Use WHMCS’ add_hook() function to call custom code when WHMCS reaches these hook points during page generation.

  • ClientAreaPrimaryNavbar
    • Called prior to rendering navigation bars.
    • Passes the primary navigation bar object to the hook function.
  • ClientAreaSecondaryNavbar
    • Called prior to rendering navigation bars.
    • Passes the secondary navigation bar object to the hook function.
  • ClientAreaNavbars
    • Called prior to rendering navigation bars.
    • Passes no parameters to the hook function.
  • ClientAreaPrimarySidebar
    • Called prior to rendering sidebars.
    • Passes the primary side bar object to the hook function.
  • ClientAreaSecondarySidebar
    • Called prior to rendering sidebars.
    • Passes the secondary side bar object to the hook function.
  • ClientAreaSidebars
    • Called prior to rendering sidebars.
    • Passes no parameters to the hook function

Custom Actions
In WHMCS 8.5 and later, you can use the CustomActions server module function to add items to the server details sidebar menu. The item will perform a set function and then redirect the user to a specified URL. For more information, see Working With Client Area Home Page Panels and our Developer Documentation.

Direct Access

WHMCS allows direct manipulation of menu objects outside the hooks system for modules and other custom code that don’t use the hooks system. The built-in Menu class is an alias to an object repository that can retrieve all of WHMCS’ menu objects. Please note that if the menu isn’t generated by the page yet then an empty menu structure may exist that is overwritten by normal page generation. WHMCS recommends using the hooks system to interact with menus.

The Menu class has four static methods to retrieve menus:

  • Item Menu::primaryNavbar()
    • Retrieve the primary navigation bar.
  • Item Menu::secondaryNavbar()
    • Retrieve the secondary navigation bar.
  • Item Menu::primarySidebar()
    • Retrieve the primary sidebar.
  • Item Menu::secondarySidebar()
    • Retrieve the secondary sidebar.

WHMCS employs a number of pre-built sidebars in its built-in pages. These side bars are available to hook and module developers through the Menu::PrimarySidebar() and Menu::SecondarySidebar() methods. Call either of these methods with the name of the sidebar as the first parameter to retrieve the pre-built sidebar. WHMCS will build the side bar if it isn't already defined. See the table below for the currently defined pre-built sidebars and which pages they are used on.

Context

WHMCS’ menus, especially the sidebars, render information specific to the page in the client area that’s being accessed by the user. For instance, client information is passed to Account > My Account or, prior to WHMCS 8.0, My Account. Ticket information is passed to the “view ticket page”. This data is passed to menu item objects as context. Context can be any PHP object or data type. The Menu class has two static methods for setting and retrieving context items:

  • void Menu::addContext(string $key, mixed $value)
    • Add $value to the menu context at the key $key, overriding existing values.
  • mixed|null Menu::context(string $key)
    • Retrieve the menu context at $key or null if no context exists at the key.
Pre-set sidebars used per page
Sidebar name Pages used on Context
affiliateView
  • affiliates.php
  • \WHMCS\User\Client|null: client
    • The client currently logged in, or null if no client is logged in
announcementList
  • announcements.php
  • \WHMCS\User\Client|null: client
    • The client currently logged in, or null if no client is logged in
  • ''[[collection]] of [https://github.com/briannesbitt/Carbon \Carbon\Carbon]'': '''monthsWithAnnouncements'''
    • The past ten months in which announcements have been published.
clientAddFunds
  • clientarea.php?action=addfunds
  • \WHMCS\User\Client|null: client
    • The client currently logged in, or null if no client is logged in
clientRegistration register.php
  • \WHMCS\User\Client|null: client
    • The client currently logged in, or null if no client is logged in.
  • ''[[collection]] of [http://docs.whmcs.com/classes/7.1/WHMCS/User/Client/SecurityQuestion.html \WHMCS\User\Client\SecurityQuestion]'': '''securityQuestions'''
    • The configured system security questions.
clientQuoteList
  • clientarea.php?action=quotes
  • \WHMCS\User\Client|null: client
    • The client currently logged in, or null if no client is logged in.
clientView
  • clientarea.php
  • clientarea.php?action=addcontact
  • clientarea.php?action=changepw
  • clientarea.php?action=contacts
  • index.php?rp=/account/paymentmethods
  • clientarea.php?action=details
  • clientarea.php?action=emails
  • clientarea.php?action=security
  • \WHMCS\User\Client|null: client
    • The client currently logged in, or null if no client is logged in.
domainList
  • clientarea.php?action=domains
  • \WHMCS\User\Client|null: client
    • The client currently logged in, or null if no client is logged in
If the q request variable is defined, then the client's associated domain counts in the primary sidebar are filtered to those domains whose names contain q's value.
domainView
  • clientarea.php?action=domaincontacts
  • clientarea.php?action=domaindetails
  • clientarea.php?action=domaindns
  • clientarea.php?action=domainemailforwarding
  • clientarea.php?action=domaingetepp
  • clientarea.php?action=domainregisterns
downloadList
  • dl.php
  • downloads.php
  • \WHMCS\User\Client|null: client
    • The client currently logged in, or null if no client is logged in
  • ''[[collection]] of [http://docs.whmcs.com/classes/7.1/WHMCS/Download/Download.html \WHMCS\Download\Download]'': '''topFiveDownloads'''
    • The five most downloaded files that are not hidden or in a hidden download category, ordered by number of downloads in descending order.
  • \WHMCS\Download\Category: downloadCategory
    • The download category the user is currently viewing.
The topFiveDownloads and 'downloadCategory contexts are only passed to download.php.
invoiceList
  • clientarea.php?action=invoices
  • clientarea.php?action=masspay
  • \WHMCS\User\Client|null: client
    • The client currently logged in, or null if no client is logged in
networkIssueList serverstatus.php
  • \WHMCS\User\Client|null: client
    • The client currently logged in, or null if no client is logged in.
  • array: networkIssueStatusCounts
    • A key/value pair of network issue statuses and the number of network issues with each status.
orderFormView cart.php
  • \WHMCS\User\Client|null: client
    • The client currently logged in, or null if no client is logged in.
  • ''[[collection]] of [http://docs.whmcs.com/classes/7.1/WHMCS/Product/Group.html \WHMCS\Product\Group]'': '''productGroups'''
    • A WHMCS installation's configured product groups.
  • int: productGroupId
    • The current gid GET parameter value.
  • bool: domainRegistrationEnabled
    • Whether or not WHMCS is configured to register domains.
  • bool: domainTransferEnabled
    • Whether or not WHMCS is configured to transfer domains.
  • bool: domainRenewalEnabled
    • Whether or not WHMCS is configured to renew domains.
  • string: domain
    • When configuring domain options, the name of the domain in the shopping cart.
  • string: currency
    • The user's configured currency, or the system currency if no user is logged in. Eg: "USD", "GBP".
Only the secondary sidebar is supported on cart.php.
serviceList
  • clientarea.php?action=hosting
  • clientarea.php?action=products
  • clientarea.php?action=services
  • \WHMCS\User\Client|null: client
    • The client currently logged in, or null if no client is logged in.
If the q request variable is defined, then the client's associated service counts in the primary sidebar are filtered to those services whose domain names contain q's value.
serviceUpgrade
  • upgrade.php
serviceView
  • clientarea.php?action=cancel
  • clientarea.php?action=productdetails
sslCertificateOrderView
  • configuressl.php
  • \WHMCS\User\Client|null: client
    • The client currently logged in, or null if no client is logged in
  • \WHMCS\Service\Service|null: service
    • The service object representing the SSL certificate being ordered
  • string: orderStatus
    • The current status of the SSL certificate order
  • array: displayData
    • A key/value pair of additional SSL certificate data that is displayed on the page on step two of the order process
  • int: step
    • The current step of the order process
support various
  • \WHMCS\User\Client|null: client
    • The client currently logged in, or null if no client is logged in
The support secondary sidebar is displayed when a contact does not have permission to perform an action in the client area.
supportKnowledgeBase
  • knowledgebase.php
  • \WHMCS\User\Client|null: client
    • The client currently logged in, or null if no client is logged in
  • array: knowledgeBaseTags
    • An array of knowledge base tags and the number of articles with each tag.
ticketFeedback
  • viewticket.php
  • \WHMCS\User\Client|null: client
    • The client currently logged in, or null if no client is logged in.
Only used on viewticket.php when a user is entering feedback for a recently closed ticket.
ticketList
  • supporttickets.php
  • \WHMCS\User\Client|null: client
    • The client currently logged in, or null if no client is logged in.
  • array: ticketStatusCounts
    • A key/value pair of ticket statuses with the number of tickets in that status.
ticketSubmit
  • submitticket.php
  • \WHMCS\User\Client|null: client
    • The client currently logged in, or null if no client is logged in.
ticketView
  • viewticket.php
  • \WHMCS\User\Client|null: client
    • The client currently logged in, or null if no client is logged in.
  • int: ticketId
    • The id number of the ticket the user is viewing.
Profile
  • clientarea.php?action=changepw
  • clientarea.php
  • \WHMCS\User\Client|null: client
    • The currently-authenticated client or null if there is not an authenticated client.

Examples

Add a social media panel to the end of the sidebar

The Client Area supports a secondary sidebar with a custom social media panel highlighted.

You may want to better connect with your clients by using social media. The menu hooks in WHMCS 6.0 and later allow you to insert links to your company’s Facebook, Twitter, and other social media profiles directly into the interface. We recommend putting them at the end of the secondary sidebar so they’re rendered last and won’t interrupt your users’ experience.

This example uses the ClientAreaSecondarySidebar hook and the menu item’s addChild()and moveToBack() methods. To add panel with links to the sidebar you will need to create a panel at the end of the sidebar, retrieve the new panel, and add social media links to the panel. The Font Awesome library already has icons for all of these services.

To do this:

  1. Create the includes/hooks/socialMediaPanel.php file in your WHMCS installation.
  2. Enter the code below.
  3. Save the file.
  4. Reload your WHMCS installation’s Client Area.

WHMCS automatically loads all hooks the includes/hooks directory. The SecondarySidebar hook is registered with add_hook() and is consequently loaded every time WHMCS renders the secondary sidebar on page load.

<?php
 
use WHMCS\View\Menu\Item as MenuItem;
 
// Add social media links to the end of all secondary sidebars.
add_hook('ClientAreaSecondarySidebar', 1, function (MenuItem $secondarySidebar)
{
    // Add a panel to the end of the secondary sidebar for social media links.
    // Declare it with the name "social-media" so we can easily retrieve it
    // later.
    $secondarySidebar->addChild('social-media', array(
        'label' => 'Social Media',
        'uri' => '#',
        'icon' => 'fas fa-thumbs-up',
    ));
 
    // Retrieve the panel we just created.
    $socialMediaPanel = $secondarySidebar->getChild('social-media');
 
    // Move the panel to the end of the sorting order so it's always displayed
    // as the last panel in the sidebar.
    $socialMediaPanel->moveToBack();
 
    // Add a Facebook link to the panel.
    $socialMediaPanel->addChild('facebook-link', array(
        'uri' => 'https://facebook.com/our-great-company',
        'label' => 'Like us on Facebook!',
        'order' => 1,
        'icon' => 'fab fa-facebook-f fa-fw',
    ));
 
    // Add a Twitter link to the panel after the Facebook link.
    $socialMediaPanel->addChild('twitter-link', array(
        'uri' => 'https://twitter.com/ourgreatcompany',
        'label' => 'Follow us on Twitter!',
        'order' => 2,
        'icon' => 'fab fa-twitter fa-fw',
    ));
});

Add a special offer image and link to the top of the topmost sidebar

A Client Area panel displaying a custom special offer.
Your web host is doing amazing and to celebrate is offering a discount to all users. The marketing folks want a small image and message in the top of the first sidebar panel on every page that links to a page with the special offer.

This example uses the ClientAreaPrimarySidebar hook and the menu item’s getFirstChild() and setBodyHtml() methods. To add panel with links to the sidebar we must:

  1. Get the first panel from the primary sidebar.
  2. Set the panel’s body HTML.

Create the includes/hooks/specialOfferInSidebar.php file in your WHMCS installation and enter the code below. As with the previous example the new file and hook within the file is run on page load and adds the image and link to the topmost panel in the primary sidebar, no matter which page the client is accessing.

<?php
use WHMCS\View\Menu\Item as MenuItem;
 
add_hook('ClientAreaPrimarySidebar', 1, function (MenuItem $primarySidebar)
{
    // The HTML for the link to the the special offer.
    $specialOfferHtml = <<<EOT
<a href="//myawesomecompany.com/special-offer/">
   <img src="/assets/img/catdeals.png" alt="Click here for amazing deals!">
   Kitten says <strong><em>thanks</em></strong> for making us the best web host!
</a>
EOT;
 
    if($primarySidebar->count() > 0)
    {
 
         // Add a link to the special to the first panel's body HTML. It will render
        // above the panel's menu item list.
        $firstSidebar = $primarySidebar->getFirstChild();
  
    	$firstSidebar->setBodyHtml($specialOfferHtml);
 
    }
});

Move the “Contact Us” link to the secondary navigation bar and add more contact options

The WHMCS Six Theme Client Area navbars with the Contact Us link moved to the secondary navigation bar with a custom menu.
The graphic designer feels that our awesome hosting company’s WHMCS installation will more closely match the main site if the “Contact Us” link is moved to the right hand side of the installation’s navigation bars before the “Account” link. They also want a dropdown under the link with links specifically to email the sales team, call us, and provide a map to the company via Google Maps.

This example for the Six theme (but not Twenty-One) requires manipulating more than one menu bar. To do that we’ll use the ClientAreaNavbars hook and the Menu class to retrieve the primary and secondary navigation bars. We'll use the menu item's getChild(), removeChild(), addChild(), and moveToFront() methods and the static Menu::primaryNavbar() and Menu::secondaryNavbar() methods. Here’s what we’ll do:

  1. Save the “Contact Us” link from the primary navigation bar.
  2. Remove the “Contact Us” link from the primary navigation bar.
  3. Add an email link child to the “Contact Us” link.
  4. Add a phone link child to the “Contact Us” link.
  5. Add a map link child to the “Contact Us” link.
  6. Add the “Contact Us” link to the secondary navigation bar then move it to the beginning of the menu.

Create the includes/hooks/moveContactUsLink.php file in your WHMCS installation and enter the code below. As with the other examples this hook file is picked up on page load and rearranges the navigation bars with the appropriate dropdown items.

<?php
 
add_hook('ClientAreaNavbars', 1, function ()
{
    // Get the current navigation bars.
    $primaryNavbar = Menu::primaryNavbar();
    $secondaryNavbar = Menu::secondaryNavbar();

if (!is_null($primaryNavbar->getChild('Contact Us'))){
 
    // Save the "Contact Us" link and remove it from the primary navigation bar.
    $contactUsLink = $primaryNavbar->getChild('Contact Us');
    $primaryNavbar->removeChild('Contact Us');
 
    // Add the email sales link to the link's drop-down menu.
    $contactUsLink->addChild('email-sales', array(
        'label' => 'Email our sales team',
        'uri' => 'sales@my-awesome-company.com',
        'order' => 1,
        'icon' => 'far fa-gem',
    ));
 
    // Add the call us link to the link's drop-down menu.
    $contactUsLink->addChild('call-us', array(
        'label' => 'Call us',
        'uri' => 'tel:+18005551212',
        'order' => 2,
        'icon' => 'fas fa-mobile-alt',
    ));
 
    // Add the map to the company to the link's drop-down menu.
    $contactUsLink->addChild('map', array(
        'label' => '123 Main St. AnyTown, TX 11223, USA',
        'uri' => 'https:\/\/maps.google.com/maps/place/some-map-data',
        'order' => 3,
        'icon' => 'fas fa-map-marker-alt',
    ));
 
    // Add the link and its drop-down children to the secondary navigation bar.
    $secondaryNavbar->addChild($contactUsLink);
 
    // Make sure the contact us link appears as the first item in the
    // secondary navigation bar.
    $contactUsLink->moveToFront();
}});

Add support hours and a custom message to the sidebar on the submit ticket page

The WHMCS 6 submit ticket page in responsive mode with support hours and a custom message in the primary sidebar.
Your business has really taken off, and it's finally time to hire someone to help answer support tickets and sales inquiries. The new hire can't work 24 hours a day, 7 days a week, so it's time to implement official support hours. Your UX people feel that it's best to notify your users of these support hours on the submit ticket page, but only the submit ticket page. They'd like the hours at the top of the primary sidebar, so they're in plain view for the users. They'd also love it if we could notify the users that they can expect a reply from us soon or if they have to wait until the next business day.

Since the powers that be want this to appear at the top of the sidebars we'll manipulate the primary sidebar via the ClientAreaPrimarySidebar hook. We’ll use the menu item’s addChild(), moveToFront(), and setBodyHtml() methods to add the new panel. The special message to the user addresses the logged in user by first name. Every sidebar has a "client" context available which contains the record of the client that is logged in or null if no client is logged in. The Menu::context() method will retrieve the client record for us. If the client is logged in then we'll use the client object's firstName property to address the user by name. Version 6.0 uses the very helpful Carbon date library internally. Carbon is available to third party developers, so we'll use it to determine if support is currently open. Here’s what we’ll do:

  1. Determine if the user is visiting submitticket.php.
  2. Add a "Support Hours" panel to the primary sidebar and move it to the front so it displays at the top.
  3. Create child items in the support hours panel saying when support is open and closed.
  4. Determine if support is currently open.
  5. If there is a user logged in then determine their first name.
  6. Assign the support hours' panel body HTML to a special message depending on the logged in user's first name and whether support is currently open.

Create the includes/hooks/addSupportHours.php file in your WHMCS installation and enter the code below. As with the other examples this hook file is picked up on page load and adds the custom panel and message to the primary sidebar before the submit ticket page renders.

<?php

use Carbon\Carbon;
use WHMCS\View\Menu\Item as MenuItem;

// Add a helpful support hours notice to the top of the sidebar on the submit
// ticket page.
if (App::getCurrentFilename() == 'submitticket') {
    add_hook('ClientAreaPrimarySidebar', 1, function (MenuItem $primarySidebar) 
    {
        // Create the support hours panel and make sure it's the first one
        // displayed.
        /** @var MenuItem $supportHours */
        $supportHours = $primarySidebar->addChild('Support Hours');
        $supportHours->moveToFront();

        // Add hours to the panel.
        $supportHours->addChild(
            '<strong>Open</strong> 08:00-17:00 M-F',
            array(
                'icon'  => 'far fa-smile',
                'order' => 1,
            )
        );
        $supportHours->addChild(
            '<strong>Closed</strong> Weekends',
            array(
                'icon'  => 'far fa-frown',
                'order' => 2,
            )
        );

        // Add a custom notice to the support hours panel with the logged in
        // client's first name and a different message depending on whether
        // support is open.
        /** @var \WHMCS\User\Client $client */
        $client = Menu::context('client');
        $greeting = is_null($client)
            ? ''
            : ", <strong>{$client->firstName}</strong>";
    
        $now = Carbon::now();
        $supportIsOpen = $now->isWeekday()
            && $now->hour >= 8
            && $now->hour <= 17;

        $supportHours->setBodyHtml(
            $supportIsOpen
                ? "Hi{$greeting}! We're open and will respond to your ticket soon!"
                : "Don't worry{$greeting}! We will respond on the next business day. Sit tight!"
        );
    });
}