Creating Custom Page Meta Tag Attributes in CP3

Page meta tag attributes are a Customer Portal feature that allow a developer to establish page behaviors in a declarative fashion. A meta tag is placed at the top of every page (/views/pages) and behavior is defined through the addition of attributes and attribute values. Except for very rare cases, each page has a page meta tag.

A typical meta tag looks something like this:

<rn:meta title="#rn:msg:_MY_PAGE_LABEL_#" 
  login_required="true" 
  template="standard.php" 
  answer_details="true" 
  clickstream="answer_view"/>

The core product has many of these attributes available natively, the most common being:

  • title: Defines the HTML title that appears at the top of the browser window
  • template: Determines which /views/template file is used for rendering the page content.
  • login_required: Forces user authentication before the page is displayed.
  • answer_details: Tells the framework that the current page is an Answer type page and that SLA's and access checks should be performed.
  • force_https: >Forces page access over HTTPS. If the page is accessed over simple HTTP, the framework will automatically redirect the user to the HTTPS version of the page. Appropriate for password type pages or other pages that submit/receive sensitive information.
  • More: for a full list of out-of-the-box page meta tag attributes, visit your site's admin panel @ https://mysite.custhelp.com/ci/admin/docs/framework/pageMeta

With the CP3 framework, you can easily define your own custom page meta tag attributes. This tutorial will shows how to implement a custom attribute that ensure that a logged in contact has a certain value selected for a Yes/No type Contact Custom Attribute.

Database set-up

To complete this tutorial, we need to add a new Custom Attribute of field type Yes/No that represents a boolean permission on the Contact record. We will name this field 'IsAdministrator' which represents that the user has access to administration-type pages that a typical user should not be accessing.

I will add my 'IsAdministrator' field to a packaged called 'Auth' and I will not index the field since I don't plan to search on it. I will set the default value of the field to 'No' as I anticipate that most users will not have this permission enabled. Once the field is defined, I will 'Deploy' the object model changes.

Custom Attribute set-up for IsAdministrator

Creating a Pre Page Render hook handler

This solutions works by creating a hook handler that fires on the 'Pre Page Render' system event. This hook will have access to the page meta tag and allows us to define custom logic that is executed before the page (and any encapsulated widgets) are evaluated.

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_page_render.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_render and a method named checkMetaTag. Leave this method empty for now. Later we will add logic to this method to check the custom page meta tags that we define.

<?php namespace Custom\Models\hooks; /** * Pre Page Render Handler */ class pre_page_render extends \RightNow\Models\Base { /** * Logic to handle custom page metadata attributes * @return void * @throws \Exception */ public function checkMetaTag() { //Implementation will go here } }

Register the Hook Handler

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

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

Add the Custom Meta Tag Attribute to the home.php page

For this hypothetical use case only users who are considered 'Administrators' should have access the Customer Portal home page. A user is an 'Administrator' if the Contact.Auth.IsAdministrator field on the contact record is set to 'YES'. I will declare this access restriction through adding a custom page meta tag to the home.php file located in 'views/pages'. The meta tag attribute can be named anything as long as it is a valid HTML attribute name and clearly describes the behavior of the tag (for future supportability reasons, not for technical reasons). For this tutorial the attribute will be named cxdev_admin_required.

Note: I have chosen to prefix or namespace my attribute with cxdev_ to ensure that the attribute will be unique and won't conflict with any new tags introduced by a CP framework upgrade.

Open the home.php file and add the following to the page's metatag.

<rn:meta title="#rn:msg:SHP_TITLE_HDG#" 
  template="standard.php" 
  clickstream="home" 
  cxdev_admin_required="true" />
<div id="rn_PageTitle" class="rn_Home">
...
</div>

Process the Custom Meta Tag Attribute

Open the models/custom/hooks/pre_page_render.php file. Add the following code to the checkMetaTag method:

public function checkMetaTag() { //Get a pointer to the Code Igniter singleton. $CI =& get_instance(); //Use the framework method '_getMetaInformation' to retrieve an array of //attributes and values for the current page. The framework parses and retrieves //this information automatically $meta = $CI->_getMetaInformation(); //Iterate through the attributes. foreach($meta as $attribute => $value) { //Explicitly define the attributes the custom code will handle through a switch condition. switch($attribute) { //Handle the custom attribute defined in this tutorial case 'cxdev_admin_required': //Only validate if the attribute value is 'true' (Note: string comparison) //and the user is logged into Customer Portal if($value === "true" && Framework::isLoggedIn()) { //Retrieve the currently logged in contact $contact = $CI->model('Contact')->get($CI->session->getProfileData('contactID'))->result; //Check to make sure the 'IsAdministrator' Custom Attribute is set to Yes if($contact->CustomFields->Auth->IsAdministrator == true) { //The user has permission. Continue to the next attribute in the foreach loop continue; } } //Else condition. Redirect to the Customer Portal Access Denied page header("Location: /app/error/error_id/4"); break; //An example of a second hypothetical custom attribute case 'cxdev_other_attribute': //Do something here break; //An example of a third hypothetical custom attribute case 'cxdev_another_attribute': //Do something here break; } } }

Once the modified pre_page_render.php is uploaded, the solution is complete. I can now only view the 'Home' page if I'm authenticated and my 'IsAdministrator' Contact Custom Attribute is set to 'Yes'. If not, I am redirected to the CP Access Denied error page. I could apply this same behavior to other Customer Portal pages by adding the 'cxdev_admin_required' attribute to their page meta tags.

For an explanation of what is happening inside of the method, review the inline code comments. As demonstrated in the example above, the hook handler can process multiple custom attributes in a single method. The switch conditional statement offers a good structure for looping over all of the attributes and defining custom logic when appropriate. My demo shows how two additional attributes named 'cxdev_other_attribute' and 'cxdev_another_attribute' could be processed by the handler.

Most of the time a custom attribute results in a user redirect (upon failure), but any valid custom PHP code can be executed inside of the handler. The use case for this demo results in a redirect to the Customer Portal Error Page upon failure. The action you decide to take will depend on your use case. For example, you could decide to change the selected Customer Portal theme on a per page basis through a custom attribute.

Using the Attribute Value

You can utilize the attribute value inside of your handler through the $value variable (based on my code set-up). This demo simply checked to see if the $value was set to true, but instead we could have defined a redirect location through the $value.

Example Alternative

<rn:meta title="#rn:msg:SHP_TITLE_HDG#" 
  template="standard.php" 
  clickstream="home" 
  cxdev_admin_required="/app/error/error_id/4" />
<div id="rn_PageTitle" class="rn_Home">
...
</div>
public function checkMetaTag() { //Get a pointer to the Code Igniter singleton. $CI =& get_instance(); //Use the framework method '_getMetaInformation' to retrieve an array of //attributes and values for the current page. The framework parses and retrieves //this information automatically $meta = $CI->_getMetaInformation(); //Iterate through the attributes. foreach($meta as $attribute => $value) { //Explicitly define the attributes the custom code will handle through a switch condition. switch($attribute) { //Handle the custom attribute defined in this tutorial case 'cxdev_admin_required': //Only validate if the attribute value is set //and the user is logged into Customer Portal if($value && Framework::isLoggedIn()) { //Retrieve the currently logged in contact $contact = $CI->model('Contact')->get($CI->session->getProfileData('contactID'))->result; //Check to make sure the 'IsAdministrator' Custom Attribute is set to Yes if($contact->CustomFields->Auth->IsAdministrator == true) { //The user has permission. Continue to the next attribute in the foreach loop continue; } } //Else condition. Redirect to page defined in the attribute header("Location: $value"); break; } } }

Next Steps

Using Custom Meta Tag Attributes a developer can define custom behaviors and apply them in a declarative fashion on a per-page basis. This tutorial shows the basic pattern and give some ideas on how it can be used. The pattern is very flexible and can be used for many other use cases beyond additional access control. Please share your ideas and experiences implementing other types of custom meta tag attributes in the comments section of this article.

Categories : 

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