Jump to content

Recommended Posts

Following a question from @Mauwiks...


how do we link an available add-on product to any of our customers?

natively in WHMCS, there is no way to do this - but with the help of the attached hook, it is possible - just upload the hook to /includes/hooks

the hook currently includes EIGHT different parameter options - I can think of at least 4 more options that I could add, and may do so at a later date, but I think 8 is plenty to be going on with. ūüôā


note: the addon's ID value can be found when in the URL when you edit that product addon in the admin area - configaddons.php?action=manage&id=1

  • Linking to one specific product addon


  • Linking to Market Connect product addons by brand


these addons are found by the hook searching whether specific terms are found at the START of the product addon descriptions, e.g Codeguard etc

  • Linking to multiple product addons


  • Linking to a predefined group of product addons

$group1 is a predefined array of product addon IDs that you can edit in the hook..

$group1 = array(12,28,20);


you could, in theory, have multiple groups (arrays of addon IDs) predefined in the hook, but it's currently only coded for 1 group - but it would be simple enough to change.

  • if you pass a numeric addon ID value that doesn't exist for the particular client, then you'll get the no addons available error message...


... I did toy with the idea of showing all addons under those circumstances, but I decided against it for now - not least because it keeps the coding simplified! ūüėČ

  • if you pass an undefined non-numeric id, e.g cart.php?gid=addons&id=brian, then there is nothing for the hook to remove and it will show all addons as per normal.
  • you can only use one parameter option in a URL - e.g., you can't use cart.php?gid=addons&id=43&multi[]=32


Edited by brian!

Share this post

Link to post
Share on other sites

This is very much awesome @brian!

And I can't thank you enough for the effort of doing this. Thank you, thank you and more thanks. More power and everthing else. You're the best. I hope I can offer something as a token of appreciation. I will take note of this at the time being and will surely give back one day

Share this post

Link to post
Share on other sites

This was a very good idea, but does it work on version 7.10.x?

Have tried, but all addons are displayed anyway.

Share this post

Link to post
Share on other sites
12 hours ago, web2008 said:

This was a very good idea

it still is! ‚ėļÔłŹ

12 hours ago, web2008 said:

but does it work on version 7.10.x?

yes. ūüėé

newer MarketConnect brands might need to be added to the hook code at some point, but it definitely still works in v.7.10.1


13 hours ago, web2008 said:

Have tried, but all addons are displayed anyway.

as you're using a custom orderform, is there an addons.tpl template in the v1 folder ?

if all addons are showing, i'm wondering if the if statement that checks the template name isn't being triggered for some reason - difficult for me to know as these are effectively client only pages, so I can't directly access them to test.

almost certainly, this solution should work with any template as it's basically only manipulating the $addons array.

btw - I still can't reproduce the network issues hook issue locally. headshake.gif

Share this post

Link to post
Share on other sites


How to replace Addons & Extras Purchase & Activate by Upgrade/Downgrade Options?


Thank you

Share this post

Link to post
Share on other sites
21 hours ago, Kelby said:

How to replace Addons & Extras Purchase & Activate by Upgrade/Downgrade Options?

with difficulty.... I assume this is related to this thread ?

Share this post

Link to post
Share on other sites
Posted (edited)

Hi Brian, thank you.

Uploaded your php to includes/hooks

thank you.

Did try various approaches .. couldn't get working :)


my main category is: cart.php?gid=1

product shopping cart link: cart.php?a=add&pid=1

what would be the exact url to display only product id=1 on the page?



and what would be the exact url to show items of 2 categories on one page?

cat 1: cart.php?gid=3

cat 2: cart.php?gid=5

Huge thank you,


Edited by HostMaria

Share this post

Link to post
Share on other sites
On 19/06/2020 at 14:06, HostMaria said:

Uploaded your php to includes/hooks

for anyone else, this is in relation to the thread below...

and i'll answer the question in the above thread as it's not really relevant to the purpose of the hook in this thread.

Share this post

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Similar Content

    • By stevelack
      I am trying to remove the sidebar menu "Actions" from the My Products and Services page.  I have created the following hook:
      use WHMCS\View\Menu\Item as MenuItem;
      add_hook('ClientAreaPrimarySidebar', 1, function(MenuItem $primarySidebar)
         if (!is_null($primarySidebar->getChild('My Services Actions'))) {
                  $primarySidebar->removeChild('My Services Actions');
      But it is not removing the sidebar from the page /clientarea.php?action=services
      What am I doing wrong?
    • By Remitur
      Starting from the code provided by @brian! in this post: 
      I realized a pop-up system which shows every time user log-in, but once a day (that's to say: if the user login 5 or more times in a day, the pop-up shows just one time, in order not to annoy him)
      The pop-up shows to the user his previous log-in time, and one "trick of the day" (randomly chosen one) 
      (IMHO, "trick of the day" is a great way to spread knowledge and marketing news without annoying the user)
      The code, in form of a hook (note: line #35 is for testing purposes only: remove or comment it):
      <?php //Show modal popup to clients, with a welcome message and a random trick of the day //original code by brian! , modified by Remitur function client_custom_headoutput_hook($vars) { $head_return = ''; $head_return = '<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script> <script> $(document).ready(function() { $(\'#myModal\').appendTo("body"); function show_modal(){ $(\'#myModal\').modal(); } window.setTimeout(show_modal, 100); $(".dismiss").click(function() {}); }); </script>'; return $head_return; } add_hook("ClientAreaHeadOutput",1,"client_custom_headoutput_hook"); use Carbon\Carbon; function client_custom_headeroutput_hook($vars) { $client = Menu::context('client'); $lastlogin = Carbon::parse($client->lastLoginDate); $enddate = Carbon::parse($client->lastLoginDate)->addDays(1); // next line is just for testing purposes: remove it! $enddate = Carbon::today(); $today = Carbon::today(); $templatefile = $vars['templatefile']; if (empty($client->id)) { return; } if ($today >= $enddate and $templatefile == "clientareahome") { $header_return = ''; $header_return = '<div class="container"> <div class="modal fade" id="myModal" role="dialog"> <div class="modal-dialog modal-md"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal">√ó</button> <h4 class="modal-title"><i class="fa fa-thumbs-up fa-lg"></i> '.Lang::trans('hello').', '.$client->firstname.'</h4> <p>Your last login has been '.$lastlogin.'</p> </div> <div class="modal-body"> <p>Trick of the day:</p> <p>'.Lang::trans ('tricks.'.rand(1,13)).'</p> </div> <div class="modal-footer"> <button type="button" class="btn btn-primary dismiss" data-dismiss="modal">'.Lang::trans('orderForm.close').'</button> </div> </div> </div> </div> </div>'; return $header_return; } } add_hook("ClientAreaHeaderOutput",1,"client_custom_headeroutput_hook"); The tricks are provided as an array of language variables; here there're 13, I guess that 30 is the minimum reasonable number; more is better.
      In the tricks you can provide also  internal and external links (just one here for example):
      #====================== tricks for popup ============================================ $_LANG['tricks']['1'] = "On DomainRegister you can register your own .com.br domain even if you have not a headquarter in Brazil"; $_LANG['tricks']['2'] = "Interface on DomainRegister is available in three different languages (English, Italian and Slovenian): select your preferred one using the flags in the upper right corner "; $_LANG['tricks']['3'] = "On DomainRegister you can renew any domain up to 10 years in advance (even those for which a multi-year renewal is not envisaged)"; $_LANG['tricks']['4'] = "If you manage a large number of domains, on DomainRegister you can create one or more DNS templates, to quickly implement complex DNS configurations for each single domain "; $_LANG['tricks']['5'] = "Using wildcard SSL certificates, with a single SSL certificate you can secure both your main domain and an unlimited number of subdomains on any number of different servers"; $_LANG['tricks']['6'] = "<a href=\"https://domainregister.international/dns-service.php\" target=\"_blank\">DomainRegister's DNS service</a> (which is free for any domain registered through us) got 100% uptime... since 2011!"; $_LANG['tricks']['7'] = "If you change the data of the registrant of a .com domain, you cannot transfer the domain for 60 days (sixty days lock)"; $_LANG['tricks']['8'] = "With DomainRegister's Linux Pro hosting plan, you get your own, dedicate european IP for your site"; $_LANG['tricks']['9'] = "DomainRegister's StarterMail starts with 5 email addresses and 5 GB archive space, and may be expanded up to 25 email addresses and 25 GB archive space; larger solutions are available upon request"; $_LANG['tricks']['10'] = "Keep your domains and services safe by protecting them with 2FA authentication: on DomainRegister it's free!"; $_LANG['tricks']['11'] = "trick 11"; $_LANG['tricks']['12'] = "trick 12"; $_LANG['tricks']['13'] = "trick 13";  
      Any idea to improve this hook is welcome!

    • By MaikelVE
      Does anybody know how I can change this: 
      To this:
      Either via a hook or in what template do I need to look for this? (I'm also using the Lagom theme)
    • By mfoland
      So I'm working with the licensing addon, and attempting to figure out the hook part..
      add_hook('LicensingAddonVerify', 1, function($vars) { return [ 'Hash' => 'Hash Here', ]; } ); The hash actually shows in the license how it should, but I'm trying to do it since I make several softwares, and not only one, so what I'm trying to do is something like
      if ($productid == "prodID number") { add_hook('LicensingAddonVerify', 1, function($vars) { return [ 'Hash' => 'Hash Here', ]; } ); } else -- run get different product It doesn't retrieve the product id at all.. What am I missing here? The hash is basically there to tell the system if a new version has been released. 
    • By WHMCS Josh
      In the latest release, you may have noticed that the Request Cancellation link in the left sidebar has been removed for free and one time products and services.
      This change was made in response to a bug report relating to one time products not being automatically cancelled. There was some concern that allowing cancellation requests for free and one time items, which have no next due date, and therefore terminate immediately on the following cron run could lead to irrevocable data loss.
      It is important to note that this is only a visual change that removes the link to submit a cancellation request. Submitting a cancellation request for a free service is still possible. If you wish to restore the option to cancel free products, you can do so using a hook.
      I've prepared some sample code that uses the ClientAreaPrimarySidebar hook point to achieve this.
      Here is the code below:
      <?php /** * This hook restores the Request Cancellation sidebar option on free services * * @author WHMCS Josh * @see https://developers.whmcs.com/hooks-reference/client-area-interface/#clientareaprimarysidebar * @see https://developers.whmcs.com/advanced/db-interaction/ */ use WHMCS\Database\Capsule; use WHMCS\View\Menu\Item; add_hook('ClientAreaPrimarySidebar', 1, function($primarySidebar) { // Get the handle for the Service Details Overview sidebar $serviceDetailsOverview = $primarySidebar->getChild('Service Details Overview'); // Make sure the handle is not null if (!is_null($serviceDetailsOverview)) { // Make sure the ID is available if (!empty($_REQUEST['id'])) { $serviceId = (int) $_REQUEST['id']; // Check if this is a free service $billingCycle = Capsule::table('tblhosting') ->where('id', $serviceId) ->value('billingcycle'); if ($billingCycle === 'Free Account') { // Add the cancellation request menu item for the service to the sidebar $serviceDetailsOverview->addChild( 'freeServiceCancellationRequest', [ 'name' => 'CancellationRequest', 'label' => 'Request Cancellation', 'uri' => '/clientarea.php?action=cancel&id=' . $serviceId, 'order' => 90, ] ); } } } }); To install this, you can simply add the code to a file in your /includes/hooks directory such as /includes/hooks/free_product_cancellation_request.php.
      For convenience, I've attached the completed hook file to this post here: free_product_cancellation_requests.php
      Below is also a screenshot of how this looked on my test installation of WHMCS 7.7.0.

      Please note that this is being provided only as an example and is not guaranteed to work with future versions of WHMCS.
      Feel free to modify it to suit your needs and I hope it helps!
  • Recently Browsing   0 members

    No registered users viewing this page.

  • Create New...

Important Information

By using this site, you agree to our Terms of Use & Guidelines and understand your posts will initially be pre-moderated