Supplying Contextual Report Filters to CBO Reports in Customer Portal

In Customer Portal you may notice that much of the content is supplied by Analytic Reports that are filtered by the ID of the logged in Contact. An example of this is the list of submitted Incident's found on the Account Overview page (/app/account/overview).

The framework automatically adds a Contact ID filter for Incident type reports as well as Answer type reports. Unfortunately this contextual filter is not automatically added for any other object types.

With the addition of CBO's, it has become a common occurrence to create objects that are owned by a Contact and it is natural to want to display these in Customer Portal using the built in Grid widgets. If you try this, you will find that all results from the CBO table are returned and displayed in the grid. If you want to filter this list by the logged in Contact you have to add a bit of custom code in the form of a pre_report_get hook handler.

Note: the following code is for CP3. CP2 behaves in a similar fashion, but the code is slightly different.

Create a Pre Report Get hook handler

What is a hook?
Hooks are system events defined in the Customer Portal framework that custom code can subscribe to through a 'hook handler'. Hook handlers execute custom logic whenever the subscribed event occurs.

Create the following file in the models/custom folder.

  • models/custom/hooks/pre_report_get.php

Note: I like to define hook handlers in a file that represents the system event's name (in this case pre_page_render.php) and inside of a folder named 'hooks'. With this convention I can easily find the custom logic that is executing for any given event. This pattern doesn't fit every use case, but it is helpful most of the time.

Inside the file define a class named pre_page_get and a method named addFilters with the following implementation:

<?php namespace Custom\Models\hooks; use RightNow\Utils\Framework; /** * Pre Report Get hook hanlders */ class pre_report_get extends \RightNow\Models\Report { /** * Include Contact ID and Org ID filters in report requests * @param array $data */ public function addFilters(&$data) { $contact = self::GetContact(); $report_id = $data['data']['reportId']; if((int) $report_id > 100000 && $contact) //Custom Reports only { $filters = $this->getRuntimeFilters($report_id)->result; foreach($filters as $filter){ $name = $filter['name']; switch($name) { case "Contact ID": case "c_id": case "Contact.ID": $value = $contact->ID; break; case "Organization.ID": case "Org ID": case "Organization ID": case "org_id": $value = ($contact->Organization->ID)?:-1; //Note: passing 0 is equivelent to *. Pass -1 to return nothing break; default: continue(2); break; } $data['data']['filters'][$name] = $this->createSearchFilter($report_id, $name, $filter['fltr_id'], $value, $filter['expression1'], $filter['oper_id'])->result; } } } /** * Get the Current Contact, or Contact by ID * @param integer $contactID * @return \RightNow\Connect\v1_2\Contact */ public static function GetContact($contactID = null) { $CI =& get_instance(); if (!$contactID && Framework::isLoggedIn()) { $contactID = $CI->session->getProfileData('contactID'); } if ($contactID) { return $CI->model('Contact')->get($contactID)->result; } } }

Register the Hook Handler

To register the hook handler with the 'Pre Report Get' event open the config/hooks.php file and adding the following entry near the bottom of the file.

$rnHooks['pre_report_get'][] = array( 'class' => 'pre_report_get', 'function' => 'addFilters', 'filepath' => 'hooks' );

Naming Your Report Filters

This solution relies on the naming of your runtime report filters. The filter's name must be one of the following values:

  • Contact ID
  • c_id
  • Contact.ID

You can specify the filter name in the Report Editor when you are creating a runtime filter. In the screenshot below I've set mine to "Contact ID"

Filter Configuration

This solution will work for ANY custom report regardless of object type. Once this is in place it is global to the solution. The only two requirements are that the report be a custom report (i.e., ID > 100000) and that a filter with a matching name exists on the report.

I can use this same hook handler and pattern to add more dynamic filters as necessary. Another common filter I add is Organization ID. This pattern is very flexible and can be modified to meet your exact needs.


this solution worked like a charm,

5 stars from me -

thank you!

does this solution useful for passing parameters in report url on customer portal

Hi... Conversely, is it possible to remove the c_id filter that's imposed on Incident reports? It seems that even if I base a report on another table and then join this table to the incidents table then the c_id filter on the logged-in user gets applied, and I'd like this removed.. thanks.

Thank you so much for taking the time to write these step by step tutorials for noobs to RightNow. You are saving my life! I was able to tweek this to filter a custom object report by Org ID on the portal. Much appreciated!! :)

Please can you tell me what are the tweeks you did so I can do the same to get data using Org ID. Thank you.

All you need to do is add more case conditions that look for your Org filter's name. When these "hit" you can then supply the Org ID of the contact to the filter. I've updated my example code in this article to show how this is done.

I was adding the Organisation case directly in the Contact case part and changing the Value to Contacts->org_id. Thank you very much

is it possible to remove the c_id filter that's imposed on Incident reports? How do I remove this contact ID filter from Incident reports?

Try seeing what the pre_report_get_data hook give you for data. You should be able to unset any filters applied by the framework at this stage in the execution.

Zircon - This is a contributing Drupal Theme
Design by WeebPal.