Custom UCM Development

Documentation > Custom Development

This page contains hints and tips for your own UCM custom development projects.

(expand all)

To enable debug mode open the includes/config.php file and change the DEBUG_MODE flag from false to true

Enabling debug mode will show a new drop-down at the top of every page. This drop down will show all the SQL queries run during page generation and other helpful information such as which module or page template is loaded.

Try this FAQ article:  Add custom link to menu or a new page

Or even better, try this sample code (it adds a new menu item to the left and a new settings page): https://github.com/dtbaker/ucm_plugin_whcms_login

When you open up a Customer record you will see a bunch of menu items along the top. These menu items are achieved  by populating the $links variable. Look at the example in includes/plugin_email/email.php:

public function pre_menu(){
   // the link within Admin > Settings > Emails.
        if($this->can_i('view','Email Settings','Config')){
            $this->links[] = array(
                "name"=>"Email",
                "p"=>"email_settings",
                "icon"=>"icon.png",
                "args"=>array('email_template_id'=>false),
                'holder_module' => 'config', // which parent module this link will sit under.
                'holder_module_page' => 'config_admin',  // which page this link will be automatically added to.
                'menu_include_parent' => 0,
            );
        }
        // only display if a customer has been created.
        if(isset($_REQUEST['customer_id']) && $_REQUEST['customer_id'] && $_REQUEST['customer_id']!='new'){
            $this->links[] = array(
                "name"=>'Emails',
                "p"=>"email_admin",
                'args'=>array('email_id'=>false),
                'holder_module' => 'customer', // which parent module this link will sit under.
                'holder_module_page' => 'customer_admin_open',  // which page this link will be automatically added to.
                'menu_include_parent' => 0,
            );
        }
}

So if you are making a new plugin that needs to nest under a Customer record then follow the above example and add code to the pre_menu() method of your new plugin.

If you have created your own plugin, here is some code you can add to the plugin to create dashboard alerts:

// create the 'handle_hook' method within your plugin (or add to existing handle_hook method)
public function handle_hook($hook,&$calling_module=false,$show_all=false){
	switch($hook){
                case "home_alerts":
                    $alerts = array();
                    $key = _l('Alert Group Title');
                    if(class_exists('module_dashboard',false)){
                        module_dashboard::register_group($key,array(
                            'columns'=>array(
                                'job'=>_l('Job Name'),
                                'customer'=>_l('Customer Name'),
                                'progress'=>_l('Task Progress'),
                                'task'=>_l('Task Description'),
                                'assigned_staff'=>_l('Staff'),
                                'date'=>_l('Due Date'),
                                'days'=>_l('Day Count'),
                            )
                        ));

                        // add an alert to the dashboard:
                        $alert_res = array();
                        $alert_res['warning'] = true; // if to highlight red or not
                        $alert_res['link'] = 'http://linkurl...';
                            $alert_res['name'] = false;
                            $alert_res['item'] = false;
                            $alert_res['group'] = $key;
                            // the data to show in each column from 'register_group' above:  
                            $alert_res['job'] = $this->link_open($todo_item['job_id'],true,$job_data);
                            $alert_res['customer'] = $job_data['customer_id'] ? module_customer::link_open($job_data['customer_id'],true) : _l('N/A');
                            $alert_res['assigned_staff'] = $todo_item['user_id'] ? module_user::link_open($todo_item['user_id'],true) : _l('N/A');
                            $alert_res['progress'] = ($percentage * 100).'%';
                            $alert_res['task'] = htmlspecialchars($todo_item['description']);
                            $alert_res['date'] = print_date($alert_res['date']);
                            $alert_res['days'] = ($alert_res['warning']) ? ''.print_date($alert_res['date']).'' : print_date($alert_res['date']);
                        $alerts[] = $alert_res;

                    }
                   return $alerts;
                 break;
         }
}

some of the UCM themes calls the "dashboard_widgets" hook for getting a list of widgets to display:

$home_widgets = handle_hook('dashboard_widgets',$calling_module);

to create your own new widget, put the following code in your plugin:

public function handle_hook($hook,$mod=false){
 switch($hook){
 case 'dashboard_widgets':
   $widgets = array();
   $widgets[] = array(
    'id'=>'your_widget_id',
    'title' => _l('Your Widget Title'),
    'icon' => 'piggy_bank',
    'content' => "your HTML content here",
   )
   return $widgets;
  }
}

A working example of a dashboard widget plugin is available here: https://gist.github.com/dtbaker/03695a18c601b94aae39

If you are making changes to the UCM core and you wish to track those changes in Subversion (or similar) here are some rough steps to get started:

  1. Install a local copy of ucm called "vendor" at a URL like this: http://localhost/ucm/vendor/ - this will be a factory default copy of UCM - no customisations will be made to this installation. Visit the http://localhost/ucm/vendor/ url in a browser and do a full installation, name this system CORE or change the theme background color in the settings so you can see which one it is quickly.
  2. Create a new empty Subversion repository called "ucm" - eg: http://example.com/svn/ucm/
  3. Import the factory default "vendor" code of UCM into Subversion under a "vendor" branch, something like this:
    svn import /local/path/to/ucm/vendor/ http://example.com/svn/ucm/vendor/current -m 'importing initial ucm code version 1.0'
  4. Tag this initial UCM core code as version 1.0 or something, like this:
    svn copy http://example.com/svn/ucm/vendor/current http://example.com/svn/ucm/vendor/1.0 -m 'tagging ucm 1.0'
  5. Copy this version 1.0 of UCM core code into a new branch called "trunk" - this will be where all our changes are made and tracked to the code in Subversion
    svn copy http://example.com/svn/ucm/vendor/1.0 http://example.com/svn/ucm/trunk -m 'bringing 1.0 into the main branch'
  6. We checkout this main branch into a new 'development' folder which is accessible via a url like http://localhost/ucm/development/
    svn checkout http://example.com/svn/ucm/trunk /local/path/to/ucm/development
  7. Remove the database details from /local/path/to/ucm/development/includes/config.php - then visit http://localhost/ucm/development/ in a browser and install a second copy of UCM in a fresh database with it's own settings - this will this will be your custom copy of UCM with all the core code changes in it - name this installation in settings to DEV or change the background color so you can tell you are on dev and not vendor.
  8. Make any changes to files in local/path/to/ucm/development as needed, and commit them back to SVN as normal.
  9. Time to update the UCM core vendor branch, and merge any changes into your local copy.
  10. Go to  http://localhost/ucm/vendor/ in a browser and update this vendor default copy of UCM through Settings > Update.  This will update files in the /local/path/to/ucm/vendor/ folder to the latest UCM copy.
  11. Commit these changes back into our SVN vendor branch, like so:
    cd /local/path/to/ucm/vendor
    do a svn status - svn add - svn delete etc.. to make sure the latest file changes and any new files are under version control.
    svn commit http://example.com/svn/ucm/vendor/current -m 'update ucm to version 1.1'
  12. Now we create a new vendor tag for version 1.1, like so:
    svn copy http://example.com/svn/ucm/vendor/current http://example.com/svn/ucm/vendor/1.1 -m 'tagging ucm 1.1'
  13. Now in SVN we have a copy of ucm at version 1.0 and ucm at version 1.1, along with a copy of our custom ucm changes.
  14. We tell SVN to merge the changes between the 1.0 and 1.1 into our development directory
    cd /local/path/to/ucm/
    svn merge http://example.com/svn/ucm/vendor/1.0 http://example.com/svn/ucm/vendor/1.1 development/
    resolve any conflicts here
    svn commit -m 'merging core ucm changes into development branch'
  15. Repeat the steps 9 to 14 each time you do a UCM update (eg: once a week).
  1. Create a new plugin called "custom_invoice" in the folder includes/plugin_custom_invoice/ (follow these instructions: https://dtbaker.net/admin/external/m.faq/h.public/i.15/hash.2411805ecf995376aeb2ba682625c3d4? )
  2. Create an external hook within this plugin called "generate_invoice" or something ( follow these instructions: https://dtbaker.net/admin/external/m.faq/h.public/i.24/hash.5da0c8f206550d1e110f536b7f639a34? - change all occurance of "job" to "custom_invoice" )
  3. Inside the case 'custom': block of code, add some code to generate an invoice and email it to the customer. Something like this:
  4. $_REQUEST['customer_id'] = $customer_id;
    $invoice_data = module_invoice::get_invoice('new',true);
    $invoice_data['customer_id'] = $customer_id;
    // set other invoice data here, like dates and stuff// add a line item to the invoice
    $invoice_data['invoice_invoice_item']=array(
    'new' => array(
    'description' => 'Invoice line item example',
    'hourly_rate' => $amount,
    'completed' => 1,
    'manual_task_type' => _TASK_TYPE_AMOUNT_ONLY,
    )
    );// email invoice to customer
    
    if(module_invoice::email_invoice_to_customer($invoice_id)){
    if($debug)echo "send successfully <br>\n";
    }else{
    echo " - failed to send invoice ".module_invoice::link_open($invoice_id,true)." to ".$member['owner_table']." <br>\n";
    }

    Then from your 3rd party application you can do a cURL request (or even iframe) to a url like:http://yoursite.com/ucm/external/m.custom_invoice/h.custom?customer_id=123 and it will generate and send an invoice to the UCM customer with ID number 123

<?php
chdir('/path/to/ucm/folder/on/webhost/');
include('init.php');

$invoice = module_invoice::get_invoice(false);
$invoice['date_create'] = date('Y-m-d');
$invoice['customer_id'] = 123;
$new_invoice_id = module_invoice::save_invoice('new',$invoice);
if($new_invoice_id){
// generating a new invoice was successful, now add a task to the invoice:
$task = array(
'invoice_id' => $new_invoice_id',
'description' => 'invoice item',
'amount' => 123.45,
);
update_insert('invoice_item_id','new','invoice_item',$task);
// send the invoice to the customer
module_invoice::email_invoice_to_customer($new_invoice_id);
}

 

<?php
chdir('/path/to/ucm/folder/on/webhost/');
include('init.php'); // the UCM init code.
$customer_data = array(
'customer_name' => 'Name Here',
// other customer database fields here.
);
$customer_id = $plugins['customer']->save_customer('new',$customer_data);
echo "Created customer with ID: $customer_id ";

Here is an example of creating some extra columns in the customer listing: http://ultimateclientmanager.com/2015/01/14/custom-hooks-for-table-data/

Create a new file called includes/plugin_customer_table/customer_table.php and inside that file put this code:

https://gist.github.com/dtbaker/ce8bf9006d56ae6eaac5