So, who am I ? Posted March 7, 2017 Share Posted March 7, 2017 Hello, I need to edit invoice email template. I made idn domain registration, and when user registers idn domain invoice is sent to him as an email, but domain is written in punycode encoded version and I don't want my user to see encoded domain, I want it to be readable for user. So I need to edit {$invoice_html_contents} in email template. I tried these hooks: PreInvoicingGenerateInvoiceItems, InvoiceCreationPreEmail but when I print $vars array, it's all empty, how am I supposed to edit it ? Also, one more thing, these hooks work when user registers domain himself, but I also need to find a hook that's run when I manually click 'Send Email' button in my admin area and send user a new invoice mail. Can anyone help ? 0 Quote Link to comment Share on other sites More sharing options...
brian! Posted March 7, 2017 Share Posted March 7, 2017 the quick way, to avoid the need for using a hook, would be to just edit the invoice email template and modify {$invoice_html_contents} by using Smarty Replace to change specific substrings... {$invoice_html_contents|replace:'.xn--node':'.გე'} if you are selling multiple different IDN's, then you can use multiple replaces in the template... {$invoice_html_contents|replace:'.xn--node':'.გე'|replace:'.xn--80adxhks':'.москва'} this will work whether you create the order, or the client does... 0 Quote Link to comment Share on other sites More sharing options...
So, who am I ? Posted March 7, 2017 Author Share Posted March 7, 2017 oh that's helpful, but I need to include punycode class to decode sld for example: 'ჰელო.გე' is 'xn--podmj7e.xn--node' I need punycode class to decode 'xn--podmj7e' to 'ჰელო'. I couldn't include php file in smarty template that's why I decided to use hooks. 0 Quote Link to comment Share on other sites More sharing options...
brian! Posted March 8, 2017 Share Posted March 8, 2017 remember when I said that IDN domains in WHMC were more hassle than their worth.... anyway, the PHP class below should work for your conversion... https://github.com/mk-j/PHP_IDN_Punycode 0 Quote Link to comment Share on other sites More sharing options...
So, who am I ? Posted March 8, 2017 Author Share Posted March 8, 2017 yeah, I know. building it into whmcs is so messy I have a punycode class file that decodes and even ecnodes, but I can't include it to email template. I've searched for hooks before but couldn't solve it and then thought I could decode it straight in the email template but what I tried didn't work so I asked staff members via ticket and they told me to use hooks, I gave it another try but none of the hooks gave me access to {$invoice_html_contents}, some of them printed empty arrays and some of them just printed invoice id and stuff. {$invoice_html_contents} is this in the email that's sent to user after registering domain: Domain Registration - xn--1odaaa.xn--node - 1 Year/s (07/03/2017 - 06/03/2018) I guess I can work around with invoice id in hook, like get invoice items form database using invoice id and then check if it includes '.xn--node' and if it does, I'd decode the whole domain then. But thought maybe there's anotehr way around, like simplier way without getting info from database and doing all the check and all. 0 Quote Link to comment Share on other sites More sharing options...
brian! Posted March 8, 2017 Share Posted March 8, 2017 if you want my advice, forget about $invoice_html_contents - all that is is a pretty version of the $invoice_items array for the template... even if you could modify it, where does it get you? it would just fix the output in the email template - not the pdf invoice; not the html invoice, not how it's shown in the client area etc. if you can get your hook to modify the invoice item description(s) in the database, they it will be used throughout the site - including inside $invoice_html_contents - therefore, I would have thought PreInvoicingGenerateInvoiceItems would be the one to use. plus, there's still the option of doing it completely in the email template, using Smarty, if you wish.... https://forum.whmcs.com/showthread.php?126354-PHP-code-inside-the-EMAIL-template-how-do-I-accomplish-that-Unicode-domain-to-IDN-ASCII&p=506174#post506174 0 Quote Link to comment Share on other sites More sharing options...
So, who am I ? Posted March 9, 2017 Author Share Posted March 9, 2017 I've just tried to do it as you suggested, but since {$invoice_html_contents} is this string: Domain Registration - xn--1odaaa.xn--node - 1 Year/s (07/03/2017 - 06/03/2017 ) I have to split it and it says "modifier 'explode' not allowed by security setting". I also tried to use $Invoice_items but first I need to see what's in the array, so I tried to print it with print_r and it said "modifier 'print_r' not allowed by security setting". I edited $smarty_security_policy array: 'mail' => array( 'php_functions' => array( 'explode', 'print_r' ), also tried including file with $trusted_dir but it said file isn't readable, I modified $smarty_security_policy for $trusted_dir but still have that error 0 Quote Link to comment Share on other sites More sharing options...
So, who am I ? Posted March 9, 2017 Author Share Posted March 9, 2017 Just came up with the idea to change punycode domains in database. like get invoice description, that is {$invoice_html_contents} in email template, with EmailPreSend hook and check if it includes punycode domain and if it does, I'd decode it and write decoded version into database. I guess it won't mess anything up with the system. 0 Quote Link to comment Share on other sites More sharing options...
brian! Posted March 9, 2017 Share Posted March 9, 2017 I've just tried to do it as you suggested, but since {$invoice_html_contents} is this string: bear in mind that if the client has registered multiple domains, or multiple products with domains, in the order then the string will be more than one line! I have to split it and it says "modifier 'explode' not allowed by security setting".I also tried to use $Invoice_items but first I need to see what's in the array, so I tried to print it with print_r and it said "modifier 'print_r' not allowed by security setting". I edited $smarty_security_policy array: also tried including file with $trusted_dir but it said file isn't readable, I modified $smarty_security_policy for $trusted_dir but still have that error i'd have just used foreach loops to see the output - though there are many subarrays in there, so you'd need to nest them.... or just added {debug} and examined the array in the popup. Just came up with the idea to change punycode domains in database. like get invoice description, that is {$invoice_html_contents} in email template, with EmailPreSend hook and check if it includes punycode domain and if it does, I'd decode it and write decoded version into database. I guess it won't mess anything up with the system. isn't that what I said above? with regards to converting without a class, the following would work to convert the first occurrence of an IDN domain... $invoiceitems = 'Domain Registration - xn--1odaaa.xn--node - 2 Year/s (07/03/2017 - 06/03/2019)'; $step1 = strstr($invoiceitems, 'xn--'); $step2 = strstr($step1, ' ', true); $idn = idn_to_utf8($step2); $replacement = str_replace($step2, $idn, $invoiceitems); echo '<br> original = '.$invoiceitems; // original invoice item echo '<br> step 1 = '.$step1; // remove everything before domain echo '<br> step 2 = '.$step2; // remove everything after domain echo '<br> idn = '.$idn; // convert domain echo '<br> replacement = '.$replacement; // replacement string original = Domain Registration - xn--1odaaa.xn--node - 2 Year/s (07/03/2017 - 06/03/2019) step 1 = xn--1odaaa.xn--node - 2 Year/s (07/03/2017 - 06/03/2019) step 2 = xn--1odaaa.xn--node idn = რრრრ.გე replacement = Domain Registration - რრრრ.გე - 2 Year/s (07/03/2017 - 06/03/2019) which you could trim down further... $invoiceitems = 'Domain Registration - xn--1odaaa.xn--node - 2 Year/s (07/03/2017 - 06/03/2019)'; $domain = strstr(strstr($invoiceitems, 'xn--'), ' ', true); $replacement = str_replace($domain, idn_to_utf8($domain), $invoiceitems); ... or ultimately to just one line... $replacement = str_replace(strstr(strstr($invoiceitems, 'xn--'), ' ', true), idn_to_utf8(strstr(strstr($invoiceitems, 'xn--'), ' ', true)), $invoiceitems); the above is written in PHP, but you could convert it to Smarty if you wanted to use it in a template - web or email (as long as you made the appropriate changes to the security policy). 0 Quote Link to comment Share on other sites More sharing options...
So, who am I ? Posted March 10, 2017 Author Share Posted March 10, 2017 Modifying Smarty is a mess cuz no matter I modify security policy or not, there's still an error. so I made it with EmailPreSend hook and then used GetInvoice API inside hook that I passed invoice_id caught by EmailPreSend hook, so I got the $description and modified it and printed into email template, but now I have to edit 'Order Confirmation' email template and I guess I have to do it like that I just need a correct API for it. 0 Quote Link to comment Share on other sites More sharing options...
So, who am I ? Posted March 14, 2017 Author Share Posted March 14, 2017 Any ideas how to add my variable to 'Order Confirmation' email template ? I used $merge fields array: $merge_fields['idn_domain'] = $idn; then printed {$idn_domain} in my 'Order Confirmation' email template and it printed nothing. I did the same for 'Customer Invoice' email template and it worked fine. 0 Quote Link to comment Share on other sites More sharing options...
brian! Posted March 14, 2017 Share Posted March 14, 2017 if it's an EmailPreSend hook, then the variable should be available in all client (not admin) email templates, e.g if I use the following hook, the variables are available in the Order Confirmation template... <?php function hook_emailvars($vars) { $merge_fields = []; $merge_fields['my_custom_var'] = "My Custom Var"; $merge_fields['my_custom_var2'] = "My Custom Var2"; return $merge_fields; } add_hook("EmailPreSend",1,"hook_emailvars"); add_hook("EmailTplMergeFields",1,"hook_emailvars"); ?> i'll likely need to see your code to spot if there are any obvious errors in there, but i'd be worried what the variable value would be if there were two (or more) IDN domains in the order? 0 Quote Link to comment Share on other sites More sharing options...
So, who am I ? Posted March 15, 2017 Author Share Posted March 15, 2017 This is the hook, I used for 'Customer Invoice' email template: add_hook('EmailPreSend', 1, function($vars) { $command = 'GetInvoice'; $postData = array( 'invoiceid' => $vars['relid'], ); $adminUsername = 'Voland'; $results = localAPI($command, $postData, $adminUsername); $original_description = $results['items']['item'][0]['description']; $description = strstr($original_description, 'xn--'); $domain = strstr($description, ' ', true); if (strpos($domain, '.xn--node')) { include("itdcapi.php"); $idn = $Punycode->decode($domain); $description = str_replace($domain, $idn, $original_description); $merge_fields = array(); $merge_fields['description'] = $description; $merge_fields['idn_domain'] = $idn; return $merge_fields; } }); $merge_fields['idn_domain'] = $idn; << I used this line to assign decoded domain name to array's 'idn_domain' variable and printed $idn_domain in 'Order Confirmation' email but it doesn't work. I tried like you told me too: function hook_emailvars($vars) { $command = 'GetInvoice'; $postData = array( 'invoiceid' => $vars['relid'], ); $adminUsername = 'Username'; $results = localAPI($command, $postData, $adminUsername); $original_description = $results['items']['item'][0]['description']; $description = strstr($original_description, 'xn--'); domain = strstr($description, ' ', true); if (strpos($domain, '.xn--node')) { include("itdcapi.php"); $idn = $Punycode->decode($domain); $description = str_replace($domain, $idn, $original_description); $merge_fields = array(); $merge_fields['description'] = $description; $merge_fields['idn_domain'] = $idn; return $merge_fields; } } add_hook("EmailPreSend",1,"hook_emailvars"); add_hook("EmailTplMergeFields",1,"hook_emailvars"); still it doesn't work. 0 Quote Link to comment Share on other sites More sharing options...
brian! Posted March 15, 2017 Share Posted March 15, 2017 I tried like you told me too hey don't bring me into it, I never suggested using the API - that was your idea. have you tried outputting each of the variables as mergefields - at least then you should be able to tell where it's failing... perhaps relid is the issue. 0 Quote Link to comment Share on other sites More sharing options...
So, who am I ? Posted March 15, 2017 Author Share Posted March 15, 2017 yeah API was my idea, I just did what you suggested about 'EmailTplMergeFields' hook have you tried outputting each of the variables as mergefields - at least then you should be able to tell where it's failing... perhaps relid is the issue. when I var_dump mergefields array it shows that there's 'description' and 'idn_domain' elements in it but 'idn_domain' doesn't print in 'Order Confirmation' email template. 0 Quote Link to comment Share on other sites More sharing options...
brian! Posted March 15, 2017 Share Posted March 15, 2017 yeah API was my idea, I just did what you suggested about 'EmailTplMergeFields' hook well that just adds it to the Merge Fields table at the bottom - so doesn't interfere with the functionality of the hook in any way. when I var_dump mergefields array it shows that there's 'description' and 'idn_domain' elements in it but 'idn_domain' doesn't print in 'Order Confirmation' email template. ok, so if I hard-code the variables in the hook, I can pass them to the order confirmation template without issue... <?php # Add Merge Fields To Email Templates # Written by brian! function hook_emailvars($vars) { $domain = "xn--1odaaa.xn--node"; $idn = idn_to_utf8($domain); $merge_fields = []; $merge_fields['original_domain'] = $domain; $merge_fields['idn_domain'] = $idn; return $merge_fields; } add_hook("EmailPreSend",1,"hook_emailvars"); add_hook("EmailTplMergeFields",1,"hook_emailvars"); ?> if I then add the following to the order confirmation email... domain = {$original_domain} idn = {$idn_domain} it will output the values correctly... so passing the merge fields isn't the issue, it must be the source of the data and/or any manipulation done to it. whilst it makes sense to use getinvoice for an invoice template, invoiceid might not exist in a general template (nor do I even think the template uses the invoice item description anyway), so you might be better off using another API, e.g getorders and working through its output... it might end up being easier as you should be able to get the domain by itself, so you won't need to do any manipulation just to isolate it from the description. 0 Quote Link to comment Share on other sites More sharing options...
So, who am I ? Posted March 16, 2017 Author Share Posted March 16, 2017 'GetOrders' API requires order_id and with this hook I only have invoice_id, 'GetOrders' returns this with invoice_id Array( [result] => success [totalresults] => 0 [startnumber] => 0 [numreturned] => 0 ) 0 Quote Link to comment Share on other sites More sharing options...
brian! Posted March 16, 2017 Share Posted March 16, 2017 'GetOrders' API requires order_id and with this hook I only have invoice_id, 'GetOrders' returns this with invoice_id you have the order_id (or at least can get it from the template)... with that, you should be good to go. 0 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.