Jump to content


Popular Content

Showing content with the highest reputation since 05/18/2019 in all areas

  1. 2 points
    Hi everyone, It's been quite some time since we added a new member to our Gearhead Program, A GearHead is a member of the community who is a champion of the WHMCS software. A GearHead is hand-picked by the WHMCS.Community Staff. We look for individuals who are long-standing activists in the community, courteous to other members, always providing technical insight and advice, and generally helping to make our forums a better place to learn, troubleshoot, and advance. With that in mind we're pleased to add @Kian to the GearHead ranks! A active community member for a number of years Kian provides a range of helpful responses to members right across the WHMCS.Community Platform. We look forward to seeing @Kian's future contributions to the platform alongside our current Gearheads.
  2. 2 points
    Exactly. @Remitur The problem is that WHMCS language is based on sessions so it doesn't matter what's the URL. The article will always use the default language which in your case is English. This hook should work. I tested on my dev system lazily. I'm gonna update if it doesn't work. It's commented. More information are provided below. <?php use WHMCS\Database\Capsule; use WHMCS\Config\Setting; add_hook('ClientAreaPageKnowledgebase', 1, function($vars) { /** * The way I'm getting $ArticleLanguage looks complicated but is necessary to match "Hello hello-hello" title with the rewritten URLs "Hello-hello-hello" * In fact there's no way to distinguish real dashes "-" from fake ones added by Friendly URLs of WHMCS * Keep in mind that I'm forced to use "raw" static method since WHERE statement doesn't support complex functions like REPLACE */ // Getting title from querty string $PageName = pathinfo($_GET['rp'])['filename']; // Retreiving the language of the currently displayed article by ID and title $ArticleLanguage = Capsule::select(Capsule::raw('SELECT language FROM tblknowledgebase WHERE parentid = "' . $vars['kbarticle']['id'] . '" AND REPLACE(title, "-", " ") = "' . str_replace('-', ' ', $PageName) . '" LIMIT 1'))[0]->language; // Retreiving the default language of WHMCS from tblconfiguration $DefaultLanguage = Setting::getValue('Language'); /** * This section is optional but needed if you want to protect yourself against blackhat SEO techniques (read post for more info) */ // Retreiving default language title $LegitURL = Capsule::select(Capsule::raw('SELECT REPLACE(title, " ", "-") AS title FROM tblknowledgebase WHERE id = "' . $vars['kbarticle']['id'] . '" LIMIT 1'))[0]->title; // If the URL currently in use is not 100% legit I force a redirect to the article in default langiage if ($LegitURL !== $PageName AND !$ArticleLanguage) { header('Location: index.php?rp=/knowledgebase/' . $vars['kbarticle']['id'] . '/' . $LegitURL . '.html'); die(); } /** * Here we set the right language depending on the URL */ // I check if the $ArticleLanguage is different from the language currently in use. I also make sure that $ArticleLanguage is different from $_SESSION['Language'] to avoid infinite loops if ($ArticleLanguage != $DefaultLanguage AND $ArticleLanguage != $_SESSION['Language']) { // Set language $_SESSION['Language'] = $ArticleLanguage; // Redirect visitor to current page to re-load the correct language header('Location: index.php?rp=' . $_GET['rp']); die(); } }); add_hook('ClientAreaHeadOutput', 1, function($vars) { /** * This guy adds canonical URL inside <head></head> tag so that Google doesn't penalize you (read post for more info) */ if ($vars['templatefile'] == 'knowledgebasearticle') { $PageName = pathinfo($_GET['rp'])['filename']; $CanonicalURL = Capsule::select(Capsule::raw('SELECT REPLACE(title, " ", "-") AS title FROM tblknowledgebase WHERE (parentid = "' . $vars['kbarticle']['id'] . '" OR id = "' . $vars['kbarticle']['id'] . '") AND REPLACE(title, "-", " ") = "' . str_replace('-', ' ', $PageName) . '" LIMIT 1'))[0]->title; return '<link rel="canonical" href="index.php?rp=/knowledgebase/' . $vars['kbarticle']['id'] . '/' . $CanonicalURL . '.html"/>'; } }); Even though we're now showing the right language to visitors, Google and all other Search Engines still hate us because we're providing duplicate contents. Their hate is so strong that they penalize us on SERP. Here is why: whmcs.com/index.php?rp=/knowledgebase/55/How-to-boil-water.html whmcs.com/index.php?rp=/knowledgebase/55/How-to-boil-vodka.html whmcs.com/index.php?rp=/knowledgebase/55/How-to-boil-rum.html whmcs.com/index.php?rp=/knowledgebase/55/How-to-boil-wine.html 4 URLs, same page and (duplicate) content. The only way to avoid penalties is that we let them know what's the unique URL by using rel="canonical" tag. The above hook adds it automatically where it is supposed to be (<head>here</head>). And if you are questioning why someone should use fake links, take a look at blackhat SEO techniques. One of your malicious competitor could publish some of those fake-links so that weeks later Google & co. penalize you for duplicate content. The above hook protects you from this technique forcing a redirect to the default article in case the URL in use is not the legit one.
  3. 2 points
    Yo! Congratulations @Kian 👏 @brian!, please don't leave us 🙏, I thought that you were (only) the One.
  4. 2 points
    The quick and dirty way: a simple query in phpmyadmin ...
  5. 2 points
    I was going to say that it would be easy to convert it to PDO prepared statements but the Capsule is great too. 🙂 should be easy to use those examples to convert it to the capsule. Hi brian! good to hear from you as well, good to see your still at it. I did alittle bit of coding after WHMCS but finally decided that even as a hobby i needed to call it quits for health reasons so i have not coded anything for pay in almost a year now. Part of me still misses it and sometimes ill whip up something just to learn how to do something new but thats about it. I moved to East Texas and i am loving it so much, its pretty and green and the lake it close enough to toss a rock and hit a fish lol.... But unlike NM, Texas has so many lakes its hard to chose just one, its alot like Texas girls, they are all beautiful its hard to choose just one. lol This is a very quiet rural community where the police chief dresses like a old west cowboy in the old days 🙂, its a very very small town and thats what i love about it. I bought some land here, first time land owner 🙂 and its keeping me busy, building a fence and so forth. I know im retired now but the plan is when i get to actual retirement age all i have for bills is utilities and a small HOA fee every month and the rest is for play time including fishing. So thats the plan.... so they say.. Sorry to be so long winded off topic... hope everyone is doing well and brian! take it easy man and do that voodoo that you do so well 🙂
  6. 1 point
    Welcome to WHMCS.Community Believe_! We're glad you're here please take some time to familiarise yourself with the Community Rules & Guidelines and take a moment to introduce yourself to other WHMCS.Community members in the Introduce Yourself Board.
  7. 1 point
    Feeling Dev-y today. Let's make WHMCS EVEN BETTER!
  8. 1 point
    that's from the checkout.tpl template - so in standard_cart, it's using... {if $servedOverSsl} <div class="alert alert-warning checkout-security-msg"> <i class="fa fa-lock"></i> {$LANG.ordersecure} (<strong>{$ipaddress}</strong>) {$LANG.ordersecure2} </div> {/if} on your equivalent orderform template, it would be... {if $servedOverSsl} <div class="section"> <div class="alert alert-warning checkout-security-msg"> <div class="alert-body"> <i class="ls ls-lock"></i> {$LANG.ordersecure} (<strong>{$ipaddress}</strong>) {$LANG.ordersecure2} </div> </div> </div> {/if} i'm not sure if it's the correct solution though as your text is in Dutch (and my Dutch knowledge is limited), but that's the only template that uses checkout-security-msg... so if it's not that, WHMCS is adding it in the background.
  9. 1 point
    I suppose you could get the title of the article, query the tblkb table and see if there's a language assigned to the article and redirect to the correct language with a hook.... though whether that's worth doing, I don't know.
  10. 1 point
    Congrats @Kian. Glad to have you as a Gearhead!
  11. 1 point
    Best congratulations to @Kian!!!!! Disappointment about the @brian! leaving...
  12. 1 point
    I don't think there would be a direct relationship. I think the important database columns for you to check are 'type' and 'relid' in tblinvoiceitems... because the value 'relid' relates to the 'id' of other database tables, depending upon the value to the 'type' field... so for example, the first 'relid' of 41 relates to the id column #41 in tbldomains; the second 'relid' of 29 relates to 'id' column # 29 in tblhosting and so on. so if the invoice line refers to a service/product, that relid value will relate to tblhosting... then within tblhosting, you can get the 'packageid' (Product ID) value which relates to the id field within tblproducts... with regards to promotion discount, that should be a line item in tblinvoiceitems... if you had wanted the name of the promo code (and not value), then you could have got the orderid value from tblhosting and that relates to the id value in tblorders... which contains a column called 'promocode' which stores the name of the code used in the order.... you could then used that value in tblpromotions if you needed details of the promocode requirements.conditions etc - but you don't want that, just the value - so you can just pull the value from tblinvoiceitems as above.
  13. 1 point
    Thanks brian it's work with data feeds
  14. 1 point
    that output is from the Additional Domain Fields settings for .fr domains... https://docs.whmcs.com/Additional_Domain_Fields the docs page should walk you through the whole process - but just remember that it's better to create a custom file, additionalfields.php in the resources/domains folder, as specified above and then modifying your fields, rather than modifying the existing dist.additionalfields.php - which would work fine, but you'd lose all your modifications after updating WHMCS (which shouldn't occur if you use the method specified in the docs). <?php // .FR $additionaldomainfields[".fr"][] = array("Name" => "Legal Type", "LangVar" => "fr_legaltype", "Type" => "dropdown", "Options" => "Individual,Company", "Default" => "Individual",); $additionaldomainfields[".fr"][] = array("Name" => "Info", "LangVar" => "fr_info", "Type" => "display", "Default" => "{$_LANG['enomfrregistration']['Heading']} <ul> <li><strong>{$_LANG['enomfrregistration']['French Individuals']['Name']}</strong>: {$_LANG['enomfrregistration']['French Individuals']['Requirements']}</li> <li><strong>{$_LANG['enomfrregistration']['EU Non-French Individuals']['Name']}</strong>: {$_LANG['enomfrregistration']['EU Non-French Individuals']['Requirements']}</li> <li><strong>{$_LANG['enomfrregistration']['French Companies']['Name']}</strong>: {$_LANG['enomfrregistration']['French Companies']['Requirements']}</li> <li><strong>{$_LANG['enomfrregistration']['EU Non-French Companies']['Name']}</strong>: {$_LANG['enomfrregistration']['EU Non-French Companies']['Requirements']}</li> </ul> <em>{$_LANG['enomfrregistration']['Non-EU Warning']}</em>",); $additionaldomainfields[".fr"][] = array("Name" => "Birthdate", 'LangVar' => 'fr_indbirthdate', "Type" => "text","Size" => "16","Default" => "1900-01-01","Required" => false); $additionaldomainfields[".fr"][] = array("Name" => "Birthplace City", 'LangVar' => 'fr_indbirthcity', "Type" => "text","Size" => "25","Default" => "","Required" => false); $additionaldomainfields[".fr"][] = array("Name" => "Birthplace Country", 'LangVar' => 'fr_indbirthcountry', "Type" => "text", "Size" => "2", "Default" => "", "Required" => false, "Description" => "Please enter your country code (eg. FR, IT, etc...)"); $additionaldomainfields[".fr"][] = array("Name" => "Birthplace Postcode", 'LangVar' => 'fr_indbirthpostcode', "Type" => "text","Size" => "6","Default" => "","Required" => false); $additionaldomainfields[".fr"][] = array("Name" => "SIRET Number", 'LangVar' => 'fr_cosiret', "Type" => "text","Size" => "50","Default" => "","Required" => false); $additionaldomainfields[".fr"][] = array("Name" => "DUNS Number", 'LangVar' => 'fr_coduns', "Type" => "text","Size" => "50","Default" => "","Required" => false); $additionaldomainfields[".fr"][] = array("Name" => "VAT Number", 'LangVar' => 'fr_vat', "Type" => "text","Size" => "50","Default" => "","Required" => false); $additionaldomainfields[".fr"][] = array("Name" => "Trademark Number", 'LangVar' => 'fr_trademarknumber', "Type" => "text","Size" => "50","Default" => "","Required" => false); $additionaldomainfields[".re"] = $additionaldomainfields[".fr"]; $additionaldomainfields[".pm"] = $additionaldomainfields[".fr"]; $additionaldomainfields[".tf"] = $additionaldomainfields[".fr"]; $additionaldomainfields[".wf"] = $additionaldomainfields[".fr"]; $additionaldomainfields[".yt"] = $additionaldomainfields[".fr"]; and then just change Birthdate, Birthplace City etc to French and save.
  15. 1 point
    another option would be to auto-close the ticket after a period of inactivity... https://docs.whmcs.com/Support_Tickets#Auto_Closing if the ticket is auto-closed before the issue is fixed, they can always reopen it.
  16. 1 point
    During the last few years I started to think that writing KB articles an more in general any content is worthless. It feels like we write to satisfy SERP instead of actual people. The new trend I'm seeing is that people are becoming more and more lazy. They turn on/off checkboxes without even reading 25 chars long descriptions. Few minutes later they blame about something that is not working as expected. Guess what? It was due to that checkbox. It seems hilarious but it's not 😟
  17. 1 point
  18. 1 point
    It depends on how many users you have. Personally I'd start with the cheapest one. 2 vCores and 2 GB of RAM are perfectly fine for a small WHMCS. When you start seeing your Load Averages consistently going over 1.50 then it's time to upgrade. Nowadays you should be able to increase vCores and RAM on demand in few clicks in case your Provider supports it. Anyway since we are talking about very small prices probably it would be preferable to start with the biggest.
  19. 1 point
    On AffiliateActivation create the coupon code... INSERT INTO tblpromotions (code, [...etc...]) VALUES ({$COUPON}, [...etc...]) {$COUPON} should contain the ID of the affiliate in some ways (eg. Affiliate ID is 24 - Coupon code is 24AAABBB). This way you can determine the what is the right coupon to use for each affiliate by simply looking at digits. Alternatively if you don't want to store the ID in the code you'll need to create a separate table that stores the connection between 24 and AAABBB.
  20. 1 point
    Hi guys, I'd like to apply discount for some invoice items and found that PreInvoicingGenerateInvoiceItems hook may help. Is there any possibility to identify which services will be used for invoice generation or maybe I can get user id? It's a pity that PreInvoicingGenerateInvoiceItems hook doesn't have any input parameters :(
  21. 1 point
    Many TLDs require "local presence", which is usually billed by Registrar (i.e.: .de , .br ... but also .fr, .eu and .it, if registrant is out of UE) It would be nice WHMCS providing a way to mage this billing (as for redirect, DNS etc.), someone is asking for it, but it's not so, and so we need to find another way... But what? How do you manage it? a - rising the price for that TLD for all, as if everyone would need the local presence b - create a full independent service £local presence" for each domain (this can be right for renewals, but in setu it's a mess c - ????
  22. 1 point
    Using this example, I can access the customfield 'website' field value code: <?php if (!defined("WHMCS")) die("This file cannot be accessed directly"); use WHMCS\Database\Capsule; add_hook('ClientEdit', 1, function($vars) { //die(json_encode($vars)); $userid = $vars['userid']; foreach (Capsule::table('tblcustomfieldsvalues')->where('fieldid','1')->where('relid', $userid)->get() as $client) { //Do stuffs } }); So, my question still remains.... Do I need to use the Capsule API to access the customfields value from the clientEdit hook? Or am I overlooking something?
  23. 1 point
    I dug a little further and figured out how to access the customFields via $vars['customfields']['1']; , but it seems that I cannot access the customeFields inside of the clientEdit hook. I placed a die(json_encode($vars)); at the top in the clientEdit hook to output the array in JSON format so its easily readable. I then noticed the customfield could be accessible from within "olddata", but that defeats the purpose of getting the 'updated' field value. Will I need to use the Capsule API access the value via mysql?
  24. 1 point
    В этом случае счет не оплатится автоматически. Клиенту нужно зайти в неоплаченный счет и применить средства с кредитного баланса.
  25. 1 point
    Couldn't agree more. I'm stunned that the current state-of-affairs has survived for so long.

Important Information

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