Community Documentation

Theming forms: system_themes

Last updated February 19, 2008. Created by webchick on November 3, 2005.
Edited by ax. Log in to edit this page.

This function demonstrates how to make use of multiple checkboxes, theming of form elements in a table, and a seperate theming function which allows for rendering of the table and inline HTML elements.

Before

<?php
function system_themes() {
 
system_listing_save();
 
$form = system_theme_listing();
 
$form .= form_submit(t('Save configuration'));
  print
theme('page', form($form));
}

function
system_theme_listing() {
 
$themes = system_theme_data();
 
ksort($themes);

  foreach (
$themes as $info) {
   
$info->screenshot = dirname($info->filename) . '/screenshot.png';
   
$row = array();

   
// Screenshot column.
   
$row[] = file_exists($info->screenshot) ? theme('image', $info->screenshot, t('Screenshot for %theme theme', array('%theme' => $info->name)), '', 'class="screenshot"', false) : t('no screenshot');

   
// Information field.
   
$row[] = "<strong>$info->name</strong><br /><em>" . dirname($info->filename) . '</em>';

   
// enabled, default, and operations columns
   
$row[] = array('data' => form_checkbox('', 'status]['. $info->name, 1, $info->status), 'align' => 'center');
   
$row[] = array('data' => form_radio('', 'theme_default', $info->name, (variable_get('theme_default', 'bluemarine') == $info->name) ? 1 : 0), 'align' => 'center');
    if (
function_exists($info->prefix . '_settings') || function_exists($info->prefix . '_features')) {
     
$row[] = array('data' => l(t('configure'), 'admin/themes/settings/' . $info->name), 'align' => 'center');
    }
    else {
     
$row[] = '';
    }
   
$rows[] = $row;
  }

 
$header = array(t('Screenshot'), t('Name'), t('Enabled'), t('Default'), t('Operations'));
 
$output = form_hidden('type', 'theme');
 
$output .= theme('table', $header, $rows);
  return
$output;
}
?>

After

<?php
function system_themes() {
 
$themes = system_theme_data();
 
ksort($themes);

  foreach (
$themes as $info) {
   
$info->screenshot = dirname($info->filename) . '/screenshot.png';
   
$screenshot = file_exists($info->screenshot) ? theme('image', $info->screenshot, t('Screenshot for %theme theme', array('%theme' => $info->name)), '', array('class' => 'screenshot'), false) : t('no screenshot');

   
### Note both the use of '#markup' to drop the screenshot info into the form, and
    ### the grouping of the screenshot/description under the theme name in the form array
   
$form[$info->name]['screenshot'] = array('#type' => 'markup', '#value' => $screenshot);

   
### Use of a form item.  Notice how '#value' is used, because the value is not editable
    ### by a user
   
$form[$info->name]['description'] = array(
     
'#type' => 'item',
     
'#title' => $info->name,
     
'#value' => dirname($info->filename),
    );

   
### Here the options array for all checkboxes is built.  Notice that the theme name is used
    ### for the key--this will be important later when the form is themed
   
$options[$info->name] = '';

   
### Here the status array is built conditionally--only checkboxes that are checked are
    ### added to this array.  Notice in this array the theme name is put in the element's value,
    ### unlike the $options array
   
if ($info->status) {
     
$status[] = $info->name;
    }
    if (
$info->status && (function_exists($info->prefix . '_settings') || function_exists($info->prefix . '_features'))) {

     
### Note that links can also be included in a markup element.  Markup can hold any
      ### kind of markup that needs to get into the form
     
$form[$info->name]['operations'] = array(
       
'#type' => 'markup',
       
'#value' => l(t('configure'),
       
'admin/themes/settings/' . $info->name),
      );
    }
    else {
     
// Dummy element for form_render. Cleaner than adding a check in the theme function.
     
$form[$info->name]['operations'] = array();
    }
  }

 
### Now that all checkbox options have been built, and all checked boxes are know, the
  ### checkboxes element can be declared.  Notice that the $status array is dropped directly
  ### into '#default_value'
 
$form['status'] = array(
   
'#type' => 'checkboxes',
   
'#options' => $options,
   
'#default_value' => $status,
  );

 
### Radio button groups are built the same basic way, using the same $options array in
  ### this case
 
$form['theme_default'] = array(
   
'#type' => 'radios',
   
'#options' => $options,
   
'#default_value' => variable_get('theme_default', 'bluemarine')
  );

 
### Notice that the two submit buttons are grouped under a 'buttons' group in the form array
  ### This will be important when we examine the execute function
 
$form['buttons']['submit'] = array('#type' => 'submit', '#value' => t('Save configuration') );
 
$form['buttons']['reset'] = array('#type' => 'submit', '#value' => t('Reset to defaults') );

 
### Drop the form array into the master form function
 
return drupal_get_form('system_themes', $form);
}
?>

In this case, the theming of the form is fairly complex, so a custom theming function is used. Custom theme functions are declared by prepending theme_ to the form_id of the form you wish to theme. The single arg is the constructed form array.

<?php
function theme_system_themes($form) {

 
### The constructed form array has a number of internal record-keeping elements, so directly
  ### looping through the array would result in errors.  The element_children function
  ### extracts only those form elements that have a value.
 
foreach (element_children($form) as $key) {

   
### Here the table rows are constructed using the previous convention of a rows array.
    ### Notice that there is a check to make sure that the particular form array element
    ### is has valid theme info in it, otherwise an empty row is added
   
$row = array();
    if (
is_array($form[$key]['description'])) {

     
### In order to manually render a portion of the form, form_render is called.  It's
      ### single argument is the section of the form array that is to be rendered.  Note
      ### that form_render is recursive--it will render all form array elements in the portion
      ### of the array that you declare.
     
$row[] = form_render($form[$key]['screenshot']);
     
$row[] = form_render($form[$key]['description']);

     
### $form['status'] is the checkboxes element.  Notice that by using $form['status'][$key],
      ### only the checkbox for the current theme $key gets rendered.  If the rendered checkbox
      ### has a matching value in the above created $status array (which was passed to the
      ### checkboxes element), then it will be rendered as a checked box
     
$row[] = array('data' => form_render($form['status'][$key]), 'align' => 'center');
      if (
$form['theme_default']) {

       
### The radio buttons are rendered using the same logic as the checkboxes
       
$row[] = array('data' => form_render($form['theme_default'][$key]), 'align' => 'center');
       
$row[] = array('data' => form_render($form[$key]['operations']), 'align' => 'center');
      }
    }
   
$rows[] = $row;
  }

 
### Now the table is created using the usual theme_table approach
 
$header = array(t('Screenshot'), t('Name'), t('Enabled'), t('Default'), t('Operations'));
 
$output = theme('table', $header, $rows);

 
### The rendering code remembers which form elements have already been rendered--therefore,
  ### to render any remaining elements (in this case the submit buttons), simply call form_render
  ### using the entire form array, and only unrendered elements will be rendered.  It's good
  ### practice to always end with this, in case other modules may have used form_alter to
  ### include additional form elements
 
$output .= form_render($form);

 
### Finally, the constructed output is returned in the standard fashion.
 
return $output;
}
?>

A custom submit function also exists for this form. Note that the form is executed before it is themed/displayed.

<?php
function system_themes_submit($form_id, $values) {

 
db_query("UPDATE {system} SET status = 0 WHERE type = 'theme'");

 
### $_POST['op'] can be examined just as before to determine which button was pressed
 
if ($_POST['op'] == t('Save configuration')) {
    if (
is_array($values['status'])) {

     
### Only those checkboxes that were checked are returned in the processed form array
     
foreach ($values['status'] as $key => $choice) {
        if (
$choice) {
         
// If theme status is being set to 1 from 0, initialize block data for this theme if necessary.
         
if (db_num_rows(db_query("SELECT status FROM {system} WHERE type = 'theme' AND name = '%s' AND status = 0", $key))) {
           
system_initialize_theme_blocks($key);
          }
         
db_query("UPDATE {system} SET status = 1 WHERE type = 'theme' and name = '%s'", $key);
        }
      }
    }

   
### Likewise, only the selected radio button's value is available in the processed form,
    ### so it can be used to set the default
   
variable_set('theme_default', $values['theme_default']);
  }
  else {
   
variable_del('theme_default');
  }

 
drupal_set_message(t('The configuration options have been saved.'));

 
### Redirecting back to the page, which will reload the form with the updated data
 
drupal_goto('admin/themes');
}
?>

Archive

Drupal’s online documentation is © 2000-2012 by the individual contributors and can be used in accordance with the Creative Commons License, Attribution-ShareAlike 2.0. PHP code is distributed under the GNU General Public License.
nobody click here