Community Documentation

Automated ways to build a sub-theme (6.x)

Last updated April 2, 2012. Created by ScottKeller on November 19, 2008.
Edited by Christopher Jam..., KrisBulman, xjm, roderik. Log in to edit this page.

Zenophile Module

Zenophile is a tiny module which allows themers to very easily create Zen subthemes without all the tedious file copying and find-and-replacing required when creating subthemes by hand. With this module, subthemes can be created in a fraction of the time just by entering information into a single-page form and clicking “Submit.”

Drush

zen.drush.inc for zen-6.x-2.x

With Drush 7.x-4.4 this script needs named as zen.drush.inc to be placed in your ~/.drush/ folder.

Run the command from the themes folder that zen resides in, example:
/sites/all/themes/

It supports the following commands:

drush zen "My theme name" my_theme

zen.drush.inc

<?php
/**
* @file
* Contains functions only needed for drush integration.
*/

/**
* Implementation of hook_drush_command().
*/
function zen_drush_command() {
  $items = array();

  $items['zen'] = array(
    'description' => 'Create a theme using zen.',
    'arguments' => array(
      'name'         => 'A name for your theme.',
      'machine_name' => '[optional] A machine-readable name for your theme.',
      'description'  => 'A description of your theme.',
    ),
    'options' => array(
      'name'         => 'A name for your theme.',
      'machine-name' => '[a-z, 0-9] A machine-readable name for your theme.',
      'description'  => 'A description of your theme.',
      'without-rtl'  => 'Remove all RTL stylesheets.',
      // @TODO: Add these options:
      // 'layout'       => '[fixed,fluid,960gs] Choose the page layout method.',
    ),
    'examples' => array(
      'drush zen "My theme name"' => 'Create a sub-theme, using the default options.',
      'drush zen "My theme name" my_theme' => 'Create a sub-theme with a specific machine name.',
    ),
  );

  return $items;
}

/**
* Create a zen sub-theme using the starter kit.
*/
function drush_zen($name = NULL, $machine_name = NULL) {
  // Determine the theme name.
  if (!isset($name)) {
    $name = drush_get_option('name');
  }

  // Determine the machine name.
  if (!isset($machine_name)) {
    $machine_name = drush_get_option('machine-name');
  }
  if (!$machine_name) {
    $machine_name = $name;
  }
  $machine_name = str_replace(' ', '_', strtolower($machine_name));
  $search = array(
    '/[^a-z0-9_]/', // Remove characters not valid in function names.
    '/^[^a-z]+/',   // Functions must begin with an alpha character.
  );
  $machine_name = preg_replace($search, '', $machine_name);

  // Determine the path to the new subtheme by finding the path to zen.
  $zen_path = drush_locate_root() . '/' . drupal_get_path('theme', 'zen');
  $subtheme_path = explode('/', $zen_path);
  array_pop($subtheme_path);
  $subtheme_path = implode('/', $subtheme_path) . '/' . str_replace('_', '-', $machine_name);

  // Make a fresh copy of the original starter kit.
  drush_op('zen_copy', $zen_path . '/STARTERKIT', $subtheme_path);

  // Replace all occurrences of 'STARTERKIT' with the machine name of our sub theme.
  drush_op('zen_file_str_replace', $subtheme_path . '/STARTERKIT.info.txt', 'STARTERKIT', $machine_name);

  // Rename the .info file.
  $subtheme_info_file = $subtheme_path . '/' . $machine_name . '.info';
  drush_op('rename', $subtheme_path . '/STARTERKIT.info.txt', $subtheme_info_file);

  // Alter the contents of the .info file based on the command options.
  $alterations = array(
    '= Zen Sub-theme Starter Kit' => '= ' . $name,
  );
  if ($description = drush_get_option('description')) {
    $alterations['Read the <a href="http://drupal.org/node/629510">online docs</a> or the included README.txt on how to create a Zen sub-theme.'] = $description;
  }
  drush_op('zen_file_str_replace', $subtheme_info_file, array_keys($alterations), $alterations);

  // Replace all occurrences of 'STARTERKIT' with the machine name of our sub theme.
  drush_op('zen_file_str_replace', $subtheme_path . '/theme-settings.php', 'STARTERKIT', $machine_name);
  drush_op('zen_file_str_replace', $subtheme_path . '/template.php', 'STARTERKIT', $machine_name);

  // Remove all RTL stylesheets.
  if ($without_rtl = drush_get_option('without-rtl')) {
    foreach (array('forms', 'html-reset', 'layout-fixed', 'layout-liquid', 'navigation', 'pages', 'tabs') as $file) {
      // Remove the RTL stylesheet.
      drush_op('unlink', $subtheme_path . '/css/' . $file . '-rtl.css');
      drush_op('zen_file_str_replace', $subtheme_path . '/css/' . $file . '.css', ' /* LTR */', '');
      // Remove the RTL sass file.
      drush_op('unlink', $subtheme_path . '/sass/' . $file . '-rtl.scss');
      drush_op('zen_file_str_replace', $subtheme_path . '/sass/' . $file . '.scss', ' // LTR', '');
    }
  }

  // Notify user of the newly created theme.
  drush_print(dt('Starter kit for "!name" created in: !path', array(
    '!name' => $name,
    '!path' => $subtheme_path,
  )));
}

/**
* Copy a directory recursively.
*/
function zen_copy($source_dir, $target_dir, $ignore = '/^(\.(\.)?|CVS|\.svn|\.git|\.DS_Store)$/') {
  if (!is_dir($source_dir)) {
    drush_die(dt('The directory "!directory" was not found.', array('!directory' => $source_dir)));
  }
  $dir = opendir($source_dir);
  @mkdir($target_dir);
  while($file = readdir($dir)) {
    if (!preg_match($ignore, $file)) {
      if (is_dir($source_dir . '/' . $file)) {
        zen_copy($source_dir . '/' . $file, $target_dir . '/' . $file, $ignore);
      }
      else {
        copy($source_dir . '/' . $file, $target_dir . '/' . $file);
      }
    }
  }
  closedir($dir);
}

/**
* Replace strings in a file.
*/
function zen_file_str_replace($file_path, $find, $replace) {
  $file_contents = file_get_contents($file_path);
  $file_contents = str_replace($find, $replace, $file_contents);
  file_put_contents($file_path, $file_contents);
}

UNIX Shell script

This script prompts for a human-readable name for a new subtheme name. The human readable name is placed in the theme's .info file. A machine-readable name is created by converting the human-readable name to all lowercase letters (dashes and spaces become underscores); for example, Joe Cool's "Better" Theme becomes joe_cools_better_theme. The script then copies the STARTERKIT to the new subtheme directory and renames internal references as necessary.

Script for zen-6.x-1.x

#!/bin/bash
# This script creates a new subtheme for zen following the instructions on drupal.org/node/226507
# Place this file in your themes directory, alongside the zen folder, as a file named "subtheme"
# Usage: open a shell, navigate to the themes directory and run ./subtheme
# (Run chmod 700 on this file to make it executable)
# Based on script submitted here: drupal.org/node/276120

echo "Enter a human-readable subtheme name:"
read -e INPUTNAME

NAME=`echo $INPUTNAME | tr '[:upper:]' '[:lower:]' | sed -e 's/[ -]/_/g' -e 's/[^a-z0-9_]//g'`
SEDNAME=`echo $INPUTNAME | sed -e 's/"/\\"/g'`

echo -n "Choose a page layout type [f]ixed or [l]iquid for subtheme $NAME: "
read -e LAYOUT

if [ $LAYOUT = "f" ]; then
  CSS="layout-fixed.css"
elif [ $LAYOUT = "l" ]; then
  CSS="layout-liquid.css"
else
  echo Invalid layout type.
  exit
fi

cp -r zen/STARTERKIT $NAME

#
# Change the theme name (the line 'name = ...') to the new subtheme name
#
sed 's/STARTERKIT/'$NAME'/g' $NAME/STARTERKIT.info.txt | sed 's/^\(name *= *\).*/\1'"$SEDNAME"'/g' > $NAME/$NAME.info
  rm $NAME/STARTERKIT.info.txt

cp zen/zen/$CSS $NAME/layout.css
cp zen/zen/print.css $NAME/print.css
cp zen/zen/html-elements.css $NAME/html-elements.css
cp zen/zen/zen.css $NAME/$NAME.css
sed 's/STARTERKIT/'$NAME'/g' zen/STARTERKIT/template.php > $NAME/template.php
sed 's/STARTERKIT/'$NAME'/g' zen/STARTERKIT/theme-settings.php > $NAME/theme-settings.php

exit 0

Script for zen-6.x-2.x

#!/bin/bash
# This script creates a new subtheme for zen-6.x-2.x-dev
# Place this file in your theme directory, alongside the zen folder, as a file name "subtheme-creator"
# Usage: open a shell, navigate to the zen directory and run ./subtheme-creator
# (Run chmod 700 on this file to make it executable)
# Based on script submitted here: drupal.org/node/276120

#~ Chain of events:
#~ * copy STARTERKIT/ from zen/ and rename to NEWNAME (lowercase/underscores)
#~ * rename STARTERKIT.info.txt to NEWNAME.info
#~ * edit NEWNAME.info name and description field
#~ * remove unneeded layout-{!chosen layout}.css file and reference in NEWNAME.info
#~ * replace all occurances of STARTERKIT in template.php & theme-settings.php with NEWNAME


echo -n "Enter a name for your theme: "
read -e NAME

HUMAN=`echo $NAME | sed -e 's/[^a-zA-Z0-9\ ]//g'`
NAME=`echo $NAME | tr [:upper:] [:lower:] | sed -e 's/[\-\ ]/_/g' -e 's/[^a-z0-9_]//g'`

if [ -d $NAME ]; then
    echo "Theme folder already exists with that name."
    echo "Do you want to remove the existing theme?"
    select OVERWRITE in Yes No
    do
        if [ $OVERWRITE = "Yes" ]; then
            rm -r $NAME /tmp/$NAME;
            break
        else
            echo "Exiting..."
            exit
        fi
    done
fi

echo "Choose a page layout"
select LAYOUT in Fixed Liquid
do
    if [ $LAYOUT = "Liquid" ]; then
        DELCSS="layout-fixed"
        CSS="layout-liquid"
        break
    else
        DELCSS="layout-liquid"
        CSS="layout-fixed"
        break
    fi
done

# Copy the STARTERKIT folder
cp -r zen/STARTERKIT $NAME

# Create .info file
sed -e 's/STARTERKIT/'$NAME'/g' -e 's/Zen Sub-theme Starter Kit/'"$HUMAN"'/g' -e 's/^\(description = \).*$/\1A Zen sub-theme/g' $NAME/STARTERKIT.info.txt > $NAME/$NAME.info
rm $NAME/STARTERKIT.info*

# Remove layout css file and references not required
rm $NAME/css/$DELCSS*
sed -e 's/'$DELCSS'/'$CSS'/g' $NAME/$NAME.info > /tmp/zen.info
mv /tmp/zen.info $NAME/$NAME.info

# Replace all occurances of STARTERKIT with theme name in template and theme-settings files
sed 's/STARTERKIT/'$NAME'/g' $NAME/template.php > /tmp/zen-template.php
mv /tmp/zen-template.php $NAME/template.php
sed 's/STARTERKIT/'$NAME'/g' $NAME/theme-settings.php > /tmp/zen-theme-settings.php
mv /tmp/zen-theme-settings.php $NAME/theme-settings.php

echo New theme folder $NAME created in `pwd`

exit 0

Comments

Handle SVN

I added this to handle an svn committed STARTERKIT dir.

# Handle svn - export if .svn dir exists.
DIRECTORY="zen/STARTERKIT"
if [ -d "$DIRECTORY""/.svn" ]; then
  svn export $DIRECTORY $NAME
else
  cp -r $DIRECTORY $NAME
fi

the 6.2 versions workd for 7.3

the 6.2 versions work for 7.3 as well.
thank you.

Page status

No known problems

Log in to edit this page

About this page

Drupal version
Drupal 6.x
Drupal’s online documentation is © 2000-2013 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. Comments on documentation pages are used to improve content and then deleted.