izghitu Posted September 13, 2018 Share Posted September 13, 2018 Hi, I have a product that has some custom fields for the customer to enter after the purchase. Is there any way to make the product name append one of the custom fields as its name at the time when I view the product list for either the client or for all clients? For example the product name is: Server monitoring. One the custom fields the client uses is IP: 1.2.3.4. After the custom field is entered by the client the product name should show: Server monitoring(1.2.3.4) or whatever text/format I need on the page where I view the product list or in the drop down menu where I select the product to view for the particular client. Please let me know Thanks in advance. 0 Quote Link to comment Share on other sites More sharing options...
izghitu Posted September 18, 2018 Author Share Posted September 18, 2018 Just an update. I was able to implement this for the client area only like this: includes/hooks/service_customfields.php <?php use WHMCS\Database\Capsule as DB; if (!defined("WHMCS")) { die("This file cannot be accessed directly"); } add_hook('ClientAreaPageProductsServices', 1, function($vars) { $fieldId = 1; //Custom field id if (isset($vars['services'])) { $csVals = []; foreach ($vars['services'] as $service) { $fieldVal = ''; $data = DB::table('tblcustomfieldsvalues AS t1') ->leftJoin('tblcustomfields AS t2', 't1.fieldid', '=', 't2.id') ->select('t1.value') ->where('t2.id', $fieldId)->where('t2.type', 'product')->where('t1.relid', $service['id']) ->first(); if (!is_null($data)) { $fieldVal = $data->value; } $csVals[$service['id']] = $fieldVal; } return ['customFields' => $csVals]; } }); templates/six/clientareaproducts.tpl - I have added "- {$customFields[$service.id]}" right after {$service.product} ... <td><strong>{$service.product} - {$customFields[$service.id]}</strong>{if $service.domain}<br /><a href="http://{$service.domain}" target="_blank">{$service.domain}</a>{/if}</td> ... But I am still unable to apply the same logic to the admin area interface where I list the products. I even searched for the "service.product" string in all whmcs files and did not find any except those in the client area that I already applied this to. Does anyone know how do I apply the same to the admin interface? Please help. Thanks! 1 Quote Link to comment Share on other sites More sharing options...
brian! Posted September 18, 2018 Share Posted September 18, 2018 47 minutes ago, izghitu said: Just an update. I was able to implement this for the client area only firstly, well done for posting your code - it's sad how many users don't share their own solutions. 47 minutes ago, izghitu said: But I am still unable to apply the same logic to the admin area interface where I list the products. I even searched for the "service.product" string in all whmcs files and did not find any except those in the client area that I already applied this to. are you thinking specifically of the encrypted clientservices.php page? might be awkward to do that... unless you wrote a hook to change the actual names of the services in the database and then you wouldn't have to worry about tweaking the output in the client/admin areas. the other way in might be the clientsummary.tpl template... which on the frontpage shows the products for an individual client... that at least gives you an identifiable array that you can manipulate with a hook to tweak the product name. 1 Quote Link to comment Share on other sites More sharing options...
izghitu Posted September 20, 2018 Author Share Posted September 20, 2018 The WHMCS support guys just told me there's no way to do this for the admin interface and encouraged me to write a Feature request which I will do. Thanks for your suggestions though. 0 Quote Link to comment Share on other sites More sharing options...
brian! Posted September 20, 2018 Share Posted September 20, 2018 5 minutes ago, izghitu said: The WHMCS support guys just told me there's no way to do this for the admin interface and encouraged me to write a Feature request which I will do. three points with this... just because Support say 'there's no way to do this', never assume that they're correct - often it's true, but not always... and I speak from personal experience as many years ago, after being told by Support that something couldn't be done, I solved it myself in about 30 minutes... to be fair, depending upon what exactly you asked them, i'd be inclined to think that modifying the services page (as you envisage) using a hook wouldn't be possible.... though i'd stand by that either modifying the client summary tables would be possible, as would updating the database directly to change the product name. be aware that feature requests, however trivial you may think them to be, will take years before being completed by WHMCS - that's just a fact. if you submit a feature request, it might be useful to add a link to the request in this thread in case anyone reads this thread in the future... otherwise, it might not be easy to find! 0 Quote Link to comment Share on other sites More sharing options...
izghitu Posted September 22, 2018 Author Share Posted September 22, 2018 On 9/20/2018 at 7:35 PM, brian! said: three points with this... just because Support say 'there's no way to do this', never assume that they're correct - often it's true, but not always... and I speak from personal experience as many years ago, after being told by Support that something couldn't be done, I solved it myself in about 30 minutes... to be fair, depending upon what exactly you asked them, i'd be inclined to think that modifying the services page (as you envisage) using a hook wouldn't be possible.... though i'd stand by that either modifying the client summary tables would be possible, as would updating the database directly to change the product name. be aware that feature requests, however trivial you may think them to be, will take years before being completed by WHMCS - that's just a fact. if you submit a feature request, it might be useful to add a link to the request in this thread in case anyone reads this thread in the future... otherwise, it might not be easy to find! So I chose the hooks way to get the same implemented into the admin interface. Below is the hook to be used to make it display the required custom field's value along with the product name: <?php if ( !defined('WHMCS')) { header("Location: ../../index.php"); } use WHMCS\Database\Capsule; // Please set custom field id here. $customfieldId = 1; if($_REQUEST['getAll'] == '1') { if($_REQUEST['userid'] != '') { $all = Capsule::table('tblcustomfieldsvalues') ->join('tblhosting', 'tblcustomfieldsvalues.relid', '=', 'tblhosting.id') ->where('fieldid', $customfieldId ) ->where('userid', $_REQUEST['userid'] ) ->get(); }else { $all = Capsule::table('tblcustomfieldsvalues')->where('fieldid', $customfieldId)->get(); } $all = json_decode( json_encode( $all ) , true ); $newAll = []; foreach($all as $a) { $newAll[$a['relid']] = $a['value']; } ob_clean(); echo json_encode(array( "all" => $newAll )); die; } add_hook('AdminAreaPage', 1, function($vars) { if( $vars['filename'] == 'clientsservices' ) { echo '<script> document.addEventListener("DOMContentLoaded", function(){ $.post(window.location, { getAll: 1 }, function(data, status){ var data = JSON.parse(data); var first = []; setInterval(function() { var x = document.querySelectorAll("[data-value]"); for (var i = 1; i < x.length ; i++) { if(typeof first[x[i].dataset.value] === "undefined") { first[x[i].dataset.value] = x[i].innerText; } if(typeof data.all[x[i].dataset.value] !== "undefined" && data.all[x[i].dataset.value] != "") { x[i].innerText = first[x[i].dataset.value] + " - " + data.all[x[i].dataset.value]; } } }, 100); }); }); </script>'; } if( $vars['filename'] == 'clientshostinglist') { echo '<script> document.addEventListener("DOMContentLoaded", function(){ $.post(window.location, { getAll: 1 }, function(data, status){ var data = JSON.parse(data); var table = document.getElementById("sortabletbl1"); var rows = table.rows; for (var i = 1; i < rows.length ; i++) { if(data.all[rows[i].cells[1].innerText] != null && data.all[rows[i].cells[1].innerText] != "") { rows[i].cells[2].innerHTML = rows[i].cells[2].innerHTML+ " - " + data.all[rows[i].cells[1].innerText]; } } }); }); </script>'; } }); The only thing that needs to be setup is the $customfieldId inside the hook. Hope this is useful to someone. Thanks! 1 Quote Link to comment Share on other sites More sharing options...
ewsoares Posted December 11, 2018 Share Posted December 11, 2018 I wanted to give back for this brilliant piece of code IZGHITU provided that helped me tremendously. The problem I faced is that I needed this coded to work for multiple products utilizing the same custom field name and his code snippet was hard coded for one product. I am not that great but a couple hours later it is dynamic for multiple products. Just change the 'fieldname' in the first query to match your needs. You can also change 'fieldtype' and 'type' to further suit your needs. If anyone can provide constructive criticism I'd appreciate it but for now this works for me and for many products instead of just one even if you delete a product and add it again since it will find the id for us now. For me I wanted to see the Location Name in the admin area. if($_REQUEST['getAll'] == '1') { $newAll = []; $gotCustomFieldID = []; // Get fieldid for 'Location Name' for every product // Change 'Location Name' to suit your custom field needed $getCustomFieldID = Capsule::table('tblcustomfields') ->select('id') ->where('tblcustomfields.type','product') ->where('tblcustomfields.fieldname','Location Name') ->where('tblcustomfields.fieldtype','text') ->get(); foreach ($getCustomFieldID as $data) { $gotCustomFieldID[] = $data->id; } foreach ($gotCustomFieldID as $customFieldID) { $all = Capsule::table('tblcustomfieldsvalues') ->join('tblhosting', 'tblcustomfieldsvalues.relid', '=', 'tblhosting.id') ->where('fieldid', $customFieldID ) ->where('userid', $_REQUEST['userid'] ) ->get(); $all = json_decode( json_encode( $all ) , true ); foreach($all as $a) { $newAll[$a['relid']] = $a['value']; } } ob_clean(); echo json_encode(array( "all" => $newAll )); die; } 0 Quote Link to comment Share on other sites More sharing options...
izghitu Posted December 13, 2018 Author Share Posted December 13, 2018 Thanks, I am glad I was able to help. I also faced the need to display this for multiple products and found the same solution as you but never had time to post it. 0 Quote Link to comment Share on other sites More sharing options...
AmitTQ Posted February 2, 2019 Share Posted February 2, 2019 On 12/11/2018 at 1:26 PM, ewsoares said: I wanted to give back for this brilliant piece of code IZGHITU provided that helped me tremendously. The problem I faced is that I needed this coded to work for multiple products utilizing the same custom field name and his code snippet was hard coded for one product. I am not that great but a couple hours later it is dynamic for multiple products. Just change the 'fieldname' in the first query to match your needs. You can also change 'fieldtype' and 'type' to further suit your needs. If anyone can provide constructive criticism I'd appreciate it but for now this works for me and for many products instead of just one even if you delete a product and add it again since it will find the id for us now. For me I wanted to see the Location Name in the admin area. if($_REQUEST['getAll'] == '1') { $newAll = []; $gotCustomFieldID = []; // Get fieldid for 'Location Name' for every product // Change 'Location Name' to suit your custom field needed $getCustomFieldID = Capsule::table('tblcustomfields') ->select('id') ->where('tblcustomfields.type','product') ->where('tblcustomfields.fieldname','Location Name') ->where('tblcustomfields.fieldtype','text') ->get(); foreach ($getCustomFieldID as $data) { $gotCustomFieldID[] = $data->id; } foreach ($gotCustomFieldID as $customFieldID) { $all = Capsule::table('tblcustomfieldsvalues') ->join('tblhosting', 'tblcustomfieldsvalues.relid', '=', 'tblhosting.id') ->where('fieldid', $customFieldID ) ->where('userid', $_REQUEST['userid'] ) ->get(); $all = json_decode( json_encode( $all ) , true ); foreach($all as $a) { $newAll[$a['relid']] = $a['value']; } } ob_clean(); echo json_encode(array( "all" => $newAll )); die; } I was able to use the initial code shared by "izghitu" but new code shared by "ewsoares" did not work to me. I used same way to use the quoted code like the initial code. It will be very great if someone advise me to use it in right way. 0 Quote Link to comment Share on other sites More sharing options...
ewsoares Posted February 3, 2019 Share Posted February 3, 2019 Off the top of my head I think you may not have created your custom fields or added the custom field name into the code. See below and let us know if this was it to help someone else who stumbles upon this thread please. ->where('tblcustomfields.type','product') ->where('tblcustomfields.fieldname','Location Name') <--- The name you named your custom field that you added to a PRODUCT. See line above as it is PRODUCT type as opposed to I think CUSTOMER custom fields. ->where('tblcustomfields.fieldtype','text') <--- The type of custom field you added, currently set to text field, can use drop down, etc. Check DataBase to be sure what these field types are called. 0 Quote Link to comment Share on other sites More sharing options...
ewsoares Posted February 3, 2019 Share Posted February 3, 2019 And remember my posted code only replaces the following portion of what IZGHITU posted. You still need the whole code he posted replacing only below with what I posted if($_REQUEST['getAll'] == '1') { if($_REQUEST['userid'] != '') { $all = Capsule::table('tblcustomfieldsvalues') ->join('tblhosting', 'tblcustomfieldsvalues.relid', '=', 'tblhosting.id') ->where('fieldid', $customfieldId ) ->where('userid', $_REQUEST['userid'] ) ->get(); }else { $all = Capsule::table('tblcustomfieldsvalues')->where('fieldid', $customfieldId)->get(); } $all = json_decode( json_encode( $all ) , true ); $newAll = []; foreach($all as $a) { $newAll[$a['relid']] = $a['value']; } ob_clean(); echo json_encode(array( "all" => $newAll )); die; } 0 Quote Link to comment Share on other sites More sharing options...
AmitTQ Posted February 16, 2019 Share Posted February 16, 2019 On 2/3/2019 at 12:53 PM, ewsoares said: And remember my posted code only replaces the following portion of what IZGHITU posted. You still need the whole code he posted replacing only below with what I posted if($_REQUEST['getAll'] == '1') { if($_REQUEST['userid'] != '') { $all = Capsule::table('tblcustomfieldsvalues') ->join('tblhosting', 'tblcustomfieldsvalues.relid', '=', 'tblhosting.id') ->where('fieldid', $customfieldId ) ->where('userid', $_REQUEST['userid'] ) ->get(); }else { $all = Capsule::table('tblcustomfieldsvalues')->where('fieldid', $customfieldId)->get(); } $all = json_decode( json_encode( $all ) , true ); $newAll = []; foreach($all as $a) { $newAll[$a['relid']] = $a['value']; } ob_clean(); echo json_encode(array( "all" => $newAll )); die; } Actually, the original Hook and .tpl edit is fine in mechanism, what I need is to use field name instead of field ID so I can use a general field name for all products (like product serial number) and have it in all customer products not just for a specific filed of specific product. Thank for the reply! 0 Quote Link to comment Share on other sites More sharing options...
AmitTQ Posted February 16, 2019 Share Posted February 16, 2019 I finally found the way!! The original code is doing below query: SELECT * FROM tblcustomfieldsvalues AS t1 LEFT JOIN tblcustomfields AS t2 ON t1.fieldid = t2.id WHERE t2.id = 2 #Field id AND t2.type = 'product' AND t1.relid = 9 #service id So on the query part we dont need to do anything but in retrieving part, we can have a change I have changed: ->where('t2.id', $fieldId)->where('t2.type', 'product')->where('t1.relid', $service['id']) to: ->where('t2.fieldname', $fieldId)->where('t2.type', 'product')->where('t1.relid', $service['id']) and from: $fieldId = 4; //Custom field id to: $fieldId = 'Field Name'; //Custom field name Now, in the product list of clientarea, we have the custom field value on all products, no matter of field ID, we only need to have a custom field with same name on all products. so the new code for hook file will be: <?php use WHMCS\Database\Capsule as DB; if (!defined("WHMCS")) { die("This file cannot be accessed directly"); } add_hook('ClientAreaPageProductsServices', 1, function($vars) { $fieldId = 'Field Name'; //Custom field name if (isset($vars['services'])) { $csVals = []; foreach ($vars['services'] as $service) { $fieldVal = ''; $data = DB::table('tblcustomfieldsvalues AS t1') ->leftJoin('tblcustomfields AS t2', 't1.fieldid', '=', 't2.id') ->select('t1.value') ->where('t2.fieldname', $fieldId)->where('t2.type', 'product')->where('t1.relid', $service['id']) ->first(); if (!is_null($data)) { $fieldVal = $data->value; } $csVals[$service['id']] = $fieldVal; } return ['customFields' => $csVals]; } }); the rest is same as "izghitu" initial codes: On 9/18/2018 at 9:34 PM, izghitu said: Just an update. I was able to implement this for the client area only like this: includes/hooks/service_customfields.php <?php use WHMCS\Database\Capsule as DB; if (!defined("WHMCS")) { die("This file cannot be accessed directly"); } add_hook('ClientAreaPageProductsServices', 1, function($vars) { $fieldId = 1; //Custom field id if (isset($vars['services'])) { $csVals = []; foreach ($vars['services'] as $service) { $fieldVal = ''; $data = DB::table('tblcustomfieldsvalues AS t1') ->leftJoin('tblcustomfields AS t2', 't1.fieldid', '=', 't2.id') ->select('t1.value') ->where('t2.id', $fieldId)->where('t2.type', 'product')->where('t1.relid', $service['id']) ->first(); if (!is_null($data)) { $fieldVal = $data->value; } $csVals[$service['id']] = $fieldVal; } return ['customFields' => $csVals]; } }); templates/six/clientareaproducts.tpl - I have added "- {$customFields[$service.id]}" right after {$service.product} ... <td><strong>{$service.product} - {$customFields[$service.id]}</strong>{if $service.domain}<br /><a href="http://{$service.domain}" target="_blank">{$service.domain}</a>{/if}</td> ... But I am still unable to apply the same logic to the admin area interface where I list the products. I even searched for the "service.product" string in all whmcs files and did not find any except those in the client area that I already applied this to. Does anyone know how do I apply the same to the admin interface? Please help. Thanks! 0 Quote Link to comment Share on other sites More sharing options...
shadvalentine Posted November 9, 2019 Share Posted November 9, 2019 I tried this with my WHMCS install, without success. I need to add the service ID and/or the Dedicated IP/Port to the drop down list in the admin area for the clients products. I am wondering if this is not compatible with the newer versions of WHMCS, I am currently running 7.8 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.