theme | Eric's Drupal Blog

Content tagged with: theme

Eric's picture

How to conditionally show regions based on client browser using jQuery

I recently signed up for Google AdSense and I thought it would be fun to show ads for Internet Explorer users. Of course, you could use this tutorial for more productive purposes. Here is how I integrated this functionality into my theme.

I added 2 regions to THEME.info file:

regions[ad_left] = Ad Left
regions[ad_right] = Ad Right

I then included the regions in my theme by adding some code to my theme's page.tpl.php file:

<?php if ($ad_left): ?>
  <div id='ad_left' class='google_ads'>
    <?php print $ad_left; ?>
  </div>
<?php endif; ?>

<?php if ($ad_right): ?>
  <div id='ad_right' class='google_ads'>
    <?php print $ad_right; ?>
  </div>
<?php endif; ?>

Next, I added some CSS in my style.css theme file to absolutely position the regions in a fixed position:

.google_ads {
  position: absolute;
  bottom: 10px;
  width: 120px;
  height: 600px;
  display: none;
}

.google_ads .block {
  padding: 0;
  margin: 0;
}

body > .google_ads {
  position: fixed;
}

#ad_left {
  left: 10px; 
}

#ad_right {
  right: 10px;
}

Now that my regions were setup, I added 2 blocks containing the Google AdSense code and assigned the blocks to my new regions. You'll need to make sure the input filter you choose allows for javascript to be included.

At this point, the ads are included for every browser, but they will not be shown due to the "display: none" property I added to the "google_ads" CSS class. I added a few lines of jQuery in my theme's script.js file to show the regions for IE users:

$(document).ready(function(){
  // per IE ads
  if ($.browser.msie) {
    $('.google_ads').show();  
  }
});

If you view this page in IE, you'll see my code in action ^_^

My additional thoughts... this code executes the Google AdSense javascript regardless of your browser, but it is only shown to IE users. A more efficient method would be to use AJAX to include the javascript ONLY if the browser is IE, or of course, by implementing a server side browser detection library.

gradient spacer
Eric's picture

Adding functionality to allow users to select different profile themes

In this blog entry, I'll show you how you can add some module code to allow users to select different themes for their profile page. I decided to use the standard user-profile.tpl.php as the base template. I copied this file into my theme folder and replicated it a few times. I named the files:

user-profile-version-1.tpl.php
user-profile-version-2.tpl.php

For my example, I simply added the text "Version 1" and "Version 2" to the top of these files to show it's working, but you could revise the layout, add CSS, etc.

Next, I created a module to contain all the following code. I defined a hook_perm() and hook_menu() function to add a menu local task (tab) to the user page.

<?php
function MYMODULE_perm() {
  return array(
   
'choose profile theme'
 
);
}

function
MYMODULE_menu() {
 
 
$items = array();
 
 
$items['user/%user/choose-profile-them'] = array(
   
'title' => 'Choose Profile Theme',
   
'page callback' => '_MYMODULE_callback_choose_profile_theme',
   
'page arguments' => array(1),
   
'access callback' => 'user_access',
   
'access arguments' => array('choose profile theme'),
   
'type' => MENU_LOCAL_TASK,
  );
 
  return
$items;
 
}
?>

user profile tab

Next, I defined the page callback to create a list of available templates for the user to choose from.

<?php
function _MYMODULE_callback_choose_profile_theme($user) {

 
// create an empty strong variable for page html
 
$html = "";

 
// define a list of available profile templates
 
$profileTemplates = array(
   
'user-profile-version-1' => 'Version 1',
   
'user-profile-version-2' => 'Version 2'
 
);
 
 
// loop through templates and ensure they exist
 
foreach ($profileTemplates as $template => $name) {
    if (!
file_exists(path_to_theme() . '/' . $template . '.tpl.php')) {
      unset(
$profileTemplates[$name]); 
    }
  }
 
  if (
count($profileTemplates)) {
   
$html .= drupal_get_form('_MYMODULE_callback_choose_profile_theme_form', $user, $profileTemplates);
  } else {
   
$html .= "No profile themes currently exist.";
  }
 
  return
$html;
 
}
?>

The following functions define the form array, and validation and submit handlers. When the form is submitted, the template option is saved to the user account variables using the user_save() function.

<?php
function _MYMODULE_callback_choose_profile_theme_form($form_state, $user, $profileTemplates) {

 
$form = array();
 
 
// add a select input element
 
$form['profileTemplate'] = array(
   
'#type' => 'select',
   
'#title' => t('Profile Template'),
   
'#options' => $profileTemplates,
   
'#default_value' => $GLOBALS['user']->profileTemplate
 
);
 
 
// add a submit button
 
$form['submit'] = array(
   
'#type' => 'submit',
   
'#value' => t('Submit')
  );
 
 
// add hidden element for userID
 
$form['userID'] = array(
   
'#type' => 'hidden',
   
'#value' => $user->uid
 
);
 
  return
$form;
}

function
_MYMODULE_callback_choose_profile_theme_form_validate($form, &$form_state) {
 
// TODO: add your additional form validation here
 
  // ensure userID submitted matches current user
 
if ($form_state['values']['userID']!=$GLOBALS['user']->uid) {
   
form_set_error('', t('Error processing form.')); 
  }
 
}

function
_MYMODULE_callback_choose_profile_theme_form_submit($form, &$form_state) {

 
// load user object
 
$user = user_load($form_state['values']['userID']);
 
 
// save profile template to user variables
 
user_save($user, array('profileTemplate' => $form_state['values']['profileTemplate']));
 
 
// set a message
 
drupal_set_message('Your profile template has been set.');
 
}
?>

user profile form

Last, I defined the preprocess function to see if a template has been set in the user variables, and add the templates suggestion to change the user profile template.

<?php
function MYMODULE_preprocess_user_profile(&$variables) {

 
// ensure the template file exists, and is set in the user object
 
if (file_exists(path_to_theme() . '/' . $variables['user']->profileTemplate . '.tpl.php') && $variables['user']->profileTemplate) {

   
// set a templates suggestion
   
$variables['template_files'][] = $variables['user']->profileTemplate;
  }
 
}
?>

As you can see below, when I choose the "Version 2" template option, the file "user-profile-version-2.tpl.php" is being loaded, and the text "Version 2" is displayed at the top of the page.

user profile selected

gradient spacer
Eric's picture

Displaying the total number of results on the search page and how many are being shown on the current page

Back in March I wrote this article: Displaying the total number of results in a view and how many are being shown on the current page. This code snippet will show you how you can add the same functionality on the search results page and improve usability by showing the following text:

Displaying ### - ### of ### results

First I added a preprocess_search_results function in my theme's template.php file to generate the html to show on the search results page:

<?php
function MYTHEME_preprocess_search_results(&$variables) {

 
// define the number of results being shown on a page
 
$itemsPerPage = 10;

 
// get the current page
 
$currentPage = $_REQUEST['page']+1;

 
// get the total number of results from the $GLOBALS
 
$total = $GLOBALS['pager_total_items'][0];
   
 
// perform calculation
 
$start = 10*$currentPage-9;
 
$end = $itemsPerPage * $currentPage;
  if (
$end>$total) $end = $total;
   
 
// set this html to the $variables
 
$variables['MYTHEME_search_totals'] = "Displaying $start - $end of $total results";

}
?>

Now, you can show this variable on the search results page by copying the search results template file (modules/search/search-results.tpl.php) into your theme folder and editing it.

Here is the new contents of my modified file (minus the comments at the top):

<!-- NEW SEARCH RESULTS TOTALS: -->
<?php print $MYTHEME_search_totals; ?>

<!-- ORIG CONTENTS: -->
<dl class="search-results <?php print $type; ?>-results">
  <?php print $search_results; ?>
</dl>
<?php print $pager; ?>

gradient spacer
Eric's picture

Integrating Open Flash Charts into a Drupal View

In this tutorial I'll show how I integrated Open Flash Charts into a Drupal view to create a fancy flash based chart from CCK node data.

Let's start by creating a new CCK node type to contain the data. I called mine "graph_data".

I added an integer field called "field_data".

I created a bunch of nodes, populating them with a random integer from 0 to 100.

I added a view called "Graph" to show all of my data. I filtered by node type and published, added sort criteria, chose "Unformatted" for Style, chose how many items to show (100), and added a page view.

At this point, you'll need to download and incorporate the Open Flash Charts library. You can download the library here or by visiting their website and clicking on Downloads in the top right. Uncompress the download and copy the entire directory (version-2-ichor) into your theme directory.

Sample directory structure:

/sites/all/themes/YOURTHEME/version-2-ichor

I created a new file in my theme directory called "views-view-unformatted--Graph.tpl.php" (see: Theme Information section on the View edit page) to override it's output. I put the guts of my code in this file:

<?php
// loop through the view results and populate a numeric array
$values = array();
foreach (
$view->result as $k => $v) {
 
$values[] = intval($v->node_data_field_data_field_data_value);
}

// include OFC PHP library
require_once(path_to_theme() . '/version-2-ichor/php-ofc-library/open-flash-chart.php');

// create a new line object
$line = new line();

// set the view values to the line object
$line->set_values( $values );

// create a new flash object
$chart = new open_flash_chart();

// add the line object to the chart object
$chart->add_element( $line );

// create a new x_axis object
$x = new x_axis();

// set the number of steps
$x->set_steps(10);

// add the x_axis object to the chart
$chart->set_x_axis($x);

// create a new y_axis object
$y = new y_axis();

// set the range of the y axis, based on the min/max view values
$y->set_range(min($values),max($values));

// set the number of steps
$y->set_steps(10);

// add the y_axis object to the chart
$chart->set_y_axis($y);
?>


<!-- Include Javascript libraries -->
<script type="text/javascript" src="<?php print base_path() . path_to_theme(); ?>/version-2-ichor/js/json/json2.js"></script>
<script type="text/javascript" src="<?php print base_path() . path_to_theme(); ?>/version-2-ichor/js/swfobject.js"></script>
<script type="text/javascript">
swfobject.embedSWF("<?php print base_path() . path_to_theme(); ?>/version-2-ichor/open-flash-chart.swf", "my_chart", "350", "200", "9.0.0");
</script>

<!-- Add Javascript to initialize the chart and load its data -->
<script type='text/javascript'>

function open_flash_chart_data() {
  return JSON.stringify(data);
}

function findSWF(movieName) {
  if (navigator.appName.indexOf("Microsoft")!= -1) {
    return window[movieName];
  } else {
    return document[movieName];
  }
}

// output the graph data into a javascript variable
var data = <?php echo $chart->toPrettyString(); ?>;
</script>

<!-- Output a container div for the chart -->
<div id="my_chart"></div>

Here's a screenshot of my new flash integrated view

gradient spacer
Eric's picture

Creating your own template files for your theme

In order to promote readable and scalable themes (and modules), it's important to plan the organization of your template files and preprocess functions. If you find yourself putting too much PHP code in a template file, you might need to move that code into a preprocess function. On the other hand, if you find yourself putting too much HTML in a function, you might need to create your own template file.

In this code snippet, I'll show you how you can create and define your own template files to be used in your Drupal site. The first thing to do is find a section of your code that has a significant amount of HTML scattered throughout.

Let's take this sample piece of code for example:

<?php
$html
= "";
$myVar = "HTML";
$html .= "<div>HERE IS A LARGE AMOUNT OF <b>"
 
. $myVar . "</b> BEING CREATED.</div>";
return
$html;
?>

For this example, I'm going to convert the statement that creates the HTML into its own template file. I'll start by creating a new file in my template directory called "example.tpl.php". I'll then copy the following into my new file:

<div>
  HERE IS A LARGE AMOUNT OF <b><?php print $myVar; ?></b> BEING CREATED.
</div>

Notice that I had to enclose my variable in PHP tags with a print statement. This is because the template file will be treated as HTML, just like node.tpl.php or block.tpl.php.

Now, we have to let our theme know that we created a template file by defining a hook_theme(). The hook_theme() function resides in the template.php file of your theme, please read more about it here. In your hook_theme() function, you return an associative array of theme implementations along with their arguments and template names.

<?php
function MYTHEME_theme() {
  return array(
   
'MYTHEME_example' => array(
     
'template' => 'example',
     
'arguments' => array('myVar' => null),
    )
  );
}
?>

At this point, you'll have to flush your theme registry before hook_theme() is processes and your new template file is available. Once that's done, you can use the theme() function to call your theme implementation. Let's replace the original example with a theme() function call:

<?php
$html
= "";
$myVar = "HTML";

/*
$html .= "<div>HERE IS A LARGE AMOUNT OF <b>"
  . $myVar . "</b> BEING CREATED.</div>";
*/
$html .= theme('MYTHEME_example', $myVar);

return
$html;
?>

In the above snippet, I used the theme() function to call my template implementation called "MYTHEME_example" and passed it one argument "myVar". As long as you defined arguments in hook_theme(), they will be passed into your template scope. The following will be contents of the $html variable:

<div>
  HERE IS A LARGE AMOUNT OF <b>HTML</b> BEING CREATED.
</div>

gradient spacer Syndicate content