Blog

Render arrays

Render arrays in Drupal 7 replace the template variables that were mostly globs of fully formatted HTML in prior versions. In Drupal 6 you'd see something like this to display content;

<?php print $content ?>

You often needed to break apart that variable then rebuild it in order to have full control over it's contents.

The new render function looks like this;

<?php print render($content); ?>

It has more granular control, you can look at the array contents like so (with devel module turned on);

<?php print dpm($content); ?>

The hashed values are render properties. There is a more detailed table at the bottom of this page on Drupal.org and here. Heres some common ones;

#themeThe theme hook, a function or a template which renders the element into html
#typeType of element to be rendered. A nice list of these in system element_info().
#theme_wrappersAn array with theme hooks that wrap children elements.
#weightNumber used to determine the order in which the field appears
#prefix/#suffixStuff appended or prepended
#sortedBoolean TRUE or FALSE. Used with #weight to sort blocks in a region.
#attachedSpecifies CSS or Javascript or libraries to load with the element.

You use alter hooks to generate and alter markup. Here is a hook that adds breadcrumbs to the footer through page_alter;

function mytheme_page_alter(&$page) {
  // dpm($page);
   $page['footer']['breadcrumbs'] = array(
      '#type' => 'container',
      '#attributes' => array('class' => array('wrap-breadcrumbs', 'clearfix')),
     );
   $page['footer']['breadcrumbs']['breadcrumb'] = array(
      '#theme' => 'breadcrumb',
      '#prefix' => '<h3> Breadcrumbs </h3>',
      '#breadcrumb' => drupal_get_breadcrumb(),
      );
}

The ['breadcrumbs'] are a new element that get tacked onto $page['footer'] and it uses the render properties to add markup and theme functions (breadcrumbs is a theme function in "include/theme.inc" in drupal core). You can get a feel for how the render properties are used in different blocks of content by looking at the dpm() (or kpr()) output of blocks / pages. This hook uses hook_html_head_alter() to change the meta content type in the doctype to match HTML5's shorter version.

function mytheme_html_head_alter(&$head_elements) {
   $head_elements['system_meta_content_type']['#attributes'] = array(
        'charset' => 'utf-8'
    );
}

There are quite a few alter hooks you can use to generate or alter content, many listed here in modules/system/system.api.php in Drupal core. Here's a list of some as they relate to themable templates.

 VariableTemplateAlter HookDescription
$pagepage.tpl.phphook_page_alter() Contains entire page, all fields.
$contentnode.tpl.php, comment.tpl.php, taxonomy-term.tpl.phphook_node_view_alter() , hook_comment_view_alter() , hook_taxonomy_term_view_alter() Contents of entities. Uses hook_entity_view_alter()
$tabspage.tpl.phphook_menu_local_tasks_alter() Primary and secondary tabs.
$action_linkspage.tpl.phphook_menu_local_tasks_alter() Action links.
$itemfield.tpl.phphook_field_display_alter() Display settings for fields.

I recommend this DrupalCon video by Franz Heinzmann for understanding the render api.

Preprocess functions

Preprocess functions let you make Drupal themes work the way you want them to. They go in the file 'template.php' that comes with all themes and they let you manipulate the variables and html that come out in the other templates.

Syntax

/**
 * Preprocessing--
 * Substitute THEMENAME for the name of your theme
 * Substitute THEMEFUNCTION for template you want to work with
 * i.e. node, page, breacrumbs, html, region, user_picture, search_results, views_VIEWNAME etc..
 */
function THEMENAME_preprocess_THEMEFUNCTION(&$variables) {
     // Do stuff
}

Code is gobbledegook unless you know what it's doing and why. Drupal uses mostly PHP arrays and objects to do things. There is a couple ways of looking inside an array so you can see what to do. My favorite in Drupal is the devel module. Once installed you can pass in an object to one of it's functions and get a detailed look into it's innards.

function mytheme_preprocess_node(&$variables) {
   dpm($variables);      // Tell me what's inside $variables
}

You get a nice list of the variables and arrays inside the object $variables which you can click to open and drill down further. In PHP syntax you can grab stuff in an array like this;

    $hidetitle = $variables['field_hide_title']['und']['0']['value'];

For this blog, I added a field of type 'boolean' called "Hide Title" (machine name: "field_hide_title") which I can check off if I want to hide the title - like Tumblr and stuff.

/**
 * See if hide_title is checked off in the node
 */
function mytheme_preprocess_node(&$variables) {
  if ( ($variables['type'] == 'blog') && ($variables['field_hide_title']['und']['0']['value'] == '1') ) {
        $variables['title'] = '';
     }
}

Pretty straightforward. If my "field_hide_title" is 1 for true, set the title to nothing. Not done yet though. There is a '$title' variable set in node.tpl.php for teasers and such but there is also one inside page.tpl.php for full page views. So need to write a preprocess function for page. Page.tpl.php has a whole different set of variables though. Which you can see here. The field_hide_title I added to blog entries is not one of them, so I need to pull in the node to check what's inside field_hide_title. Page uses menu_get_object() to grab the node. Menu_get_object() is a Drupal API function that grabs what's in the menu router, usually a node. In PHP syntax, you move into an object like so;

   $tree->apple
/**
 * See if hide_title is checked off in the node, within the page
 */
function mytheme_preprocess_page(&$variables) {
   // check if node is in menu_get_object()
   if ( $variables['node'] = menu_get_object() ) {
       // dpm($variables['node']   // Uncomment to look inside the node
       if ( ($variables['node']->type =='blog') && ($vars['node']->field_hide_title['und']['0']['value'] == '1') ) {
         $variables['title'] = '';
             }
         }
     }

Some more preprocess examples

/**
 * Add helpful body classes for CSS styling
 */
function mytheme_preprocess_html(&$variables) {
    // arg() grabs url segments, if page is at node/edit then add helpful 'edit-page' class to body "classes_array"
    if ( arg(0) == 'node' && arg(1) == 'edit' ) {
           $variables['classes_array'][] = 'edit-page';
     }
}
 
/**
 * Change the search form to use the HTML5 "search" input attribute 
 */
function mytheme_preprocess_search_block_form(&variables) {
   $variables['search_form'] = str_replace('type="text"', 'type="search"', $variables['search_form']);
}
 
/**
 * Include extra fields in search results
 */
function mytheme_preprocess_search_result(&$variables) {
   //node_load() returns a full node so we can grab the videoscreenshot field
   $fullnode = node_load($variables['result']['fields']['entity_id'], NULL, TRUE);
 
   // Check if the videoscreenshot field exists
   if ( isset($fullnode -> field_videoscreenshot['und']['0']) ) {
           // Create a new variable "videoscreenshot" for use in "search-results.tpl.php"
           // image_style_url() returns an image style with preset
          $variables['videoscreenshot'] = image_style_url("thumbnail", $fullnode->field_videoscreenshot['und']['0']['uri']);
          }
   }

PHP functions

Some common PHP functions used in Drupal;

  • isset()    //Check if a variable is or is not set and is not NULL, e.g. isset( $variables['body']['0']['value'] );
  • empty()     //Check if a variable is empty, e.g. empty( $variables['body']['0']['value'] );
  • unset()     //Destroy a variable, e.g. unset( $variables['title'] );
  • in_array()      //Check if something exists in an array, e.g. in_array( 'page-front', $variables['body_classes'] );
  • foreach()     //Iterate through arrays and objects, e.g;
   foreach ( $variables['classes_array'] as $key => $item ) {
          if ( $item == 'node-blog' ) {
                $variables['classes_array'][$key] = 'boing-boing';  //Change 'node-blog' in classes_array to 'boing-boing'
         }
    }

Drupal API functions

Drupal writes a lot of it's own functions to do "Drupally" type things. Their documented at api.drupal.org. Here's a few common ones.

  • arg()    //Return url segments
  • t()   //Proper method for printing text, handles language translation, e.g. t('Apples and oranges');
  • l()     //The proper method for writing links in PHP inside Drupal, handles aliased path's and add's "active" classes for themin e.g. l( t('Create a new blog entry'), 'node/add/blog') );
  • drupal_get_title()    //Returns the title of the current page
  • base_path()     //Returns the path of the Drupal install
  • path_to_theme()     //Return path to themed elements, goes nice with base_path() e.g. <?php print base_path() . path_to_theme() . '/' ?>images/my_image.jpg
  • node_load()      //Returns full node elements, requires the node id as a parameter, e.g. node_load( $variables['nid'] );

 

GeSHi filter

Geshi filter allows for adding code with syntax highlighting in blog posts. It's a bit of a pain to set up in Drupal 7 properly with WYSIWYG buttons so I'm documenting the process here.

How to install

Download and turn on these Drupal 7 modules;

Download 1.0.8x version of Geshi and put it in sites/all/libraries;

Setup the wysiwyg. Go to "configuration -> wysiwyg profiles" to set up text formats. You may need to install an editor. I am using the ckeditor for Drupal 7 that should be installed in sites/all/libraries. You would then select the editor you're using, edit each text format and check off the buttons you want.

Configure GeSHi

Configure GeSHi at admin/config/content/formats/geshifilter (you will get WSOD if you installed the libraries API module prior to the 7.x-2.x branch). Under "Generic syntax highlighting tags" add "pre" after blockcode. Select the languages tab and check off the code languages you want to include along with the tags (<jquery> etc..).

Go to "configuration -> text formats". Select "Add text format". Check off "GeSHi filter" and uncheck everything else -- or else be careful for conflicts and make sure GeSHi Filter is listed before other filters in the "filter processing order".

Go to "configuration -> wysiwyg profiles" and select an editor for GeSHi Filter. Edit the filter and under "buttons and plugins" check off the Geshi buttons you want to use (GeSHi: PHP, GeSHi: CSS etc..).

Include an image uploader

These two modules go great with wysiwyg for uploading images;

Setup the profiles #overlay=admin/config/media/imce and configure permissions. Turn on "image" and "IMCE" in the buttons section under configuration -> wysiwyg profiles -> edit a filter.

I format images under the advanced tab in the Image Properties box. Include some CSS classes in your theme.

img.left {
  margin: 20px 20px 12px -250px;
  float: left;
}
 
img.right {
  margin: 20px -250px 20px 20px;
  float: right;
}
 
img.center {
  margin: 20px 0 20px -3em;
}
 
img.border {
  border: 1px solid rgba(255,255,255,0.25);
}

An individual has not started living until he can rise above the narrow confines of his individualistic concerns to the broader concerns of all humanity.

New year, new site

It's a new year and I've got a new site. The design is simple like the last one. I just wanted something I would actually use, incorporated HTML5 and a responsive grid. I've also moved into a new studio in Healdsburg, just outside Santa Rosa.

I'm not usually that good with lists, but here's a few things I would like to accomplish this year:

  • Blog more on art, drupal development, design etc.
  • Sketch and draw more
  • My portfolio of projects is a bit old and stale, I'm working on some exciting new projects I hope to show off and I hope many more over the next year
  • I'd like to make some stellar, minimalist artist portfolio type themes for Drupal 7
  • Get better, that said here is a great list on .net