If you're like me and you use Zen subthemes for every project you work on, you quickly find the process of creating subthemes according to good ol' README.txt to be a bit tedious. So I created a shell script that automates the process for me. Now a boring process that used to take a few minutes now takes about five seconds, including the time it takes to type in the command. (Granted, it took me a bit of time to make the shell script itself, but…)

To use this, you should already have the Zen theme directory in place, but it doesn't need to be activated yet. I have a Drupal directory which already has a couple essential modules and the Zen theme in place, and now this shell script is in that directory too; whenever I need to start a new project, I just duplicate that directory and work from that. This script will work well if you use a similar method. The script needs to be placed at the root level of the Drupal installation. Call it with syntax like;

zenify.sh foo "The Foo Template"

…then go into the theme list in Drupal and fire up your new subtheme as normal. Do

zenify.sh --help

(or just call it without any parameters) for help and more examples.

It should be noted that I'm pretty much a novice when it comes to shell scripting; this script probably isn't as cleanly written as it could be. But at the very least, it should work as advertised. It's been tested on Mac OS X, but I see no reason why it won't work on other *nix machines, so long as they have bash.

CommentFileSizeAuthor
zenify.sh_.gz0 bytesGarrett Albright
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Garrett Albright’s picture

Hmm, Drupal's attachment system didn't like that. Okay, I'll just C&P the code.

#!/bin/bash

function show_help() {
  echo "Zenify"
  echo "by Garrett Albright"
  echo "For quickly setting up subthemes of the Zen Drupal theme."
  echo "Place at the root level of your Drupal installation. After executing,"
  echo "DELETE THIS SCRIPT! (Or at least remove execute permissions.)"
  echo ""
  echo "Usage:"
  echo "  zenify.sh subtheme_name [human_name [layout_type [site_dir]]]"
  echo "Parameters:"
  echo "  subtheme_name: The machine name of your subtheme. Should consist of"
  echo "     lower-case letters or underscores only."
  echo "  human_name: The human-friendly name of your subtheme. If it contains"
  echo "     spaces, try enclosing the name in quotes, or weird stuff may happen."
  echo "  layout_type: The layout type: fixed or liquid. Defaults to 'fixed'."
  echo "  site_dir: The name of the directory inside Drupal's 'sites' directory"
  echo "    where your site files (including themes) will be stored. The Zen"
  echo "    base theme should already be in place at /sites/site_dir/themes/zen."
  echo "    Defaults to 'all'."
  echo ""
  echo "Examples:"
  echo "  Simplest usage:"
  echo "     zenify.sh foo"
  echo "  Giving your theme a human-friendly name:"
  echo "    zenify.sh foo \"The Foo Template\""
  echo "  A friendly name and a liquid layout:"
  echo "    zenify.sh foo \"The Foo Template\" liquid"
  echo "  A friendly name and a fixed layout, but only for example.com:"
  echo "    zenify.sh foo \"The Foo Template\" fixed example.com"
  exit
}

if [ -z "$1" ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]
then
  show_help
fi

if [ `echo "$1" | grep -c -e '[^[:lower:]_]'` -eq "1" ]
then
  echo "Invalid subtheme name. Subtheme names should consist only of lowercase"
  echo "letters and the underscore character."
  exit
fi

# Step 1: Create directory

dirname="`dirname $0`"

if [[ -z "$4" && -d "$dirname/sites/all/themes/zen/STARTERKIT" ]]
then
  subdir="$dirname/sites/all/themes"
else
  if [ -d "$dirname/sites/$4/themes/zen/STARTERKIT" ]
  then
    subdir="$dirname/sites/$4/themes"
  else 
    echo "Oh noes! STARTERKIT not found."
    exit
  fi
fi

cp -r "$subdir/zen/STARTERKIT" "$subdir/$1"

# Step 2: Rename and edit .info file


if [ -z "$2" ]
then
  human="$1"
else
  human="$2"
fi

sed -e "s/STARTERKIT/$1/g" -e "s/^name.*$/name        = $human/" -e "s/^description.*$/description = The $human theme \– created automatically by zenify.sh./" "$subdir/$1/STARTERKIT.info"> "$subdir/$1/$1.info"
rm "$subdir/$1/STARTERKIT.info"

# Step 3: Copy liquid or fixed stylesheet

if [ -z "$3" ]
then
  styletype="fixed"
else
  styletype="$3"
fi

cp "$subdir/zen/zen/layout-$styletype.css" "$subdir/$1/layout.css"

# Step 4: Copy print stylesheet

cp "$subdir/zen/zen/print.css" "$subdir/$1/print.css"

# Step 5: Copy Zen stylesheet. This step actually is wrong because the
# STARTERKIT directory already has a zen.css file in it. Let's rename it to the
# correct name, though.

mv "$subdir/$1/zen.css" "$subdir/$1/$1.css"

# Step 6: Change STARTERKIT in template.php and theme-settings.php.

sed -e "s/STARTERKIT/$1/g" -i ".backup" "$subdir/$1/template.php"
sed -e "s/STARTERKIT/$1/g" -i ".backup" "$subdir/$1/theme-settings.php"

rm "$subdir/$1/template.php.backup"
rm "$subdir/$1/theme-settings.php.backup"

echo "Done. PLEASE DELETE THIS SCRIPT NOW -- it's a security risk."
jjeff’s picture

Very cool!

I wonder if this could be turned in to a module...

Garrett Albright’s picture

When it first occurred to me to automate this process, my first thought was to build it as a module; however, it would be more work that way, since you'd have to go into the admin section and activate the module, then go to a page to enter in the details (template name, human-readable name, etc) and click a Submit button, then deactivate the module (unless I got crafty and had the module automatically deactivate itself after making a theme). Running a shell script is much faster.

On the other hand, if it were a module, it would be easier to use for people unfamiliar with the command line and/or unfortunate enough to be using Windows… So maybe there's a "market" for a module version too.

jjeff’s picture

Hmmm.... yes.... but!

If it were a module that output downloadable files (perhaps a .zip) we could set up a site (perhaps ZenTheme.com -- which I just registered) and *no one* has to install the module. We could just make this a hosted thing, where people come to a site, enter in their information and they get a customized download with the files that they need.

THAT would be cool! ;-)

Garrett Albright’s picture

Hmm. That's not a bad idea, but not a direction I personally would want to take the project. More power to you, though, if you want to do it.

jjeff’s picture

Don't get me wrong. I'm not talking about "privatizing" the process. I'm just thinking that if there was a module that did this, we could just install in somewhere on the 'net and everyone could use it there if they didn't want to go through the process of installing it themselves.

mikey_p’s picture

You're reading me mind...give me an hour or two....

mikey_p’s picture

So that took a little longer than expected due to some unexpected path issues on the server, but give it a try:

http://mikeyp.net/zen-creator

I hope to add the the ability to choose what *.tpl.php files you want included, and what css files as well, but that's for another day.

Garrett Albright’s picture

Title: Shell script for creating Zen subthemes » Zen subtheme creation automation

Nice. Good work, Mikey.

mikey_p’s picture

Garret, I need to put some credit on there for you for writing the original script.

Garrett Albright’s picture

Is your project using my shell script instead of doing the equivalent in PHP?

I'm assuming it's the latter, because your version does more than mine. But if it's the former, then… hopefully I'm stating the obvious, but… be careful when passing user-inputted values to the OS via exec() or something like that. I won't try it myself, but consider what might happen if someone tries to create a template with the name "foo; rm -rf ~" -- to use a more innocuous example.

mikey_p’s picture

Thanks for the concern. I had some careful regex in place already, but I've reviewed it and testing it again here on my local machine. Try putting some quotes or punctuation (other than . or , ) into any of the fields, and you should get a validation error showing you what characters are allowed.

jjeff’s picture

Wow! Very cool!

Garrett Albright’s picture

Mikey, if I may pick a nit…

Thanks for the credit on the site, but you misspelled my first name, omitting the second T. You're hardly the first to do so and I'll bet my life you won't be the last, but, well, it is my name, so I'm a bit picky about it. Thanks.

tcblack’s picture

W00t! Thanks Mikey and Garrett (note the two t's ) Since I had a bunch of these to make I'm quite happy about finding this.
The only thing that would make this better would be a "drag and drop" auto CSS creation interface. :-)

Yes It's asking for the moon, but if NASA can do it...

Garrett Albright’s picture

The only thing that would make this better would be a "drag and drop" auto CSS creation interface.

What do you mean by that? Like a layout tool like Dreamweaver, or something saner?

tcblack’s picture

The only thing that would make this better would be a "drag and drop" auto CSS creation interface.

What do you mean by that? Like a layout tool like Dreamweaver, or something saner?

Mostly it was a random comment without a lot of supporting thought. I do that from time to time. :-)

Still I meant something like color picker gone crazy - for every attribute. I don't see how it's doable outside of crafting or integrating a CSS design tool with a web interface. Like I said, random thought.

scottrigby’s picture

Hey Garrett & Mikey – nice work! :) Scott

Manuel Garcia’s picture

Oh my, this is the best idea !

What a great surprise, i couldn't help my self but test the converter on http://mikeyp.net/zen-creator

I've only encountered one strange behavior, only i have no idea if this is zen related at all, if i switch the default theme to the subtheme, and move blocks around, drupal thinks I'm working on garland. However, If I try the same, but previous to moving blocks, i clear the cache (using devel block), then drupal behaves normally. My guess this is because I'm working on drupal 6, I'm I correct?

Just thought I'd comment on it in case it isn't normal.

Last but not least, a ton of thanks for developing this, it's great!!

Garrett Albright’s picture

Version: 6.x-1.0-beta2 » 6.x-1.0-beta3

Here's an update to the shell script to work with Beta 3. Beta 3 has us "correctly" copying zen.css again, and apparently that's the file we're supposed to hack to customize the theme. As a personal preference, though, I don't like it because it's already too crowded and messy. So the script now creates a blank CSS file named "(themename)-fresh.css" that I prefer to start hacking with. Whether you want to do the same is up to you; if not, just comment out the lines it instructs you to below. Also, the script now attempts to delete itself when it's done.

#!/bin/bash

if [ -z "$1" ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]
then
  echo "Zenify"
  echo "by Garrett Albright"
  echo "For quickly setting up subthemes of the Zen Drupal theme."
  echo "Place at the root level of your Drupal installation. After executing,"
  echo "DELETE THIS SCRIPT if it did not delete itself! (Or at least remove"
  echo "execute permissions.)"
  echo ""
  echo "Usage:"
  echo "  zenify.sh subtheme_name [human_name [layout_type [site_dir]]]"
  echo "Parameters:"
  echo "  subtheme_name: The machine name of your subtheme. Should consist of"
  echo "     lower-case letters or underscores only."
  echo "  human_name: The human-friendly name of your subtheme. If it contains"
  echo "     spaces, try enclosing the name in quotes, or weird stuff may happen."
  echo "  layout_type: The layout type: fixed or liquid. Defaults to 'fixed'."
  echo "  site_dir: The name of the directory inside Drupal's 'sites' directory"
  echo "    where your site files (including themes) will be stored. The Zen"
  echo "    base theme should already be in place at /sites/site_dir/themes/zen."
  echo "    Defaults to 'all'."
  echo ""
  echo "Examples:"
  echo "  Simplest usage:"
  echo "     zenify.sh foo"
  echo "  Giving your theme a human-friendly name:"
  echo "    zenify.sh foo \"The Foo Template\""
  echo "  A friendly name and a liquid layout:"
  echo "    zenify.sh foo \"The Foo Template\" liquid"
  echo "  A friendly name and a fixed layout, but only for example.com:"
  echo "    zenify.sh foo \"The Foo Template\" fixed example.com"
  exit
fi

if [ `echo "$1" | grep -c -e '[^[:lower:]_]'` -eq "1" ]
then
  echo "Invalid subtheme name. Subtheme names should consist only of lowercase"
  echo "letters and the underscore character."
  exit
fi

# Step 1: Create directory.

dirname="`dirname $0`"

if [[ -z "$4" && -d "$dirname/sites/all/themes/zen/STARTERKIT" ]]
then
  subdir="$dirname/sites/all/themes"
else
  if [ -d "$dirname/sites/$4/themes/zen/STARTERKIT" ]
  then
    subdir="$dirname/sites/$4/themes"
  else 
    echo "Oh noes! STARTERKIT not found."
    exit
  fi
fi

cp -r "$subdir/zen/STARTERKIT" "$subdir/$1"

# Step 2: Rename and edit .info file.

if [ -z "$2" ]
then
  human="$1"
else
  human="$2"
fi

sed -e "s/STARTERKIT/$1/g" -e "s/^name.*$/name        = $human/" -e "s/^description.*$/description = The $human theme \– created automatically by zenify.sh./" "$subdir/$1/STARTERKIT.info"> "$subdir/$1/$1.info"
rm "$subdir/$1/STARTERKIT.info"

# Step 3: Copy liquid or fixed stylesheet.

if [ -z "$3" ]
then
  styletype="fixed"
else
  styletype="$3"
fi

cp "$subdir/zen/zen/layout-$styletype.css" "$subdir/$1/layout.css"

# Step 4: Copy print stylesheet.

cp "$subdir/zen/zen/print.css" "$subdir/$1/print.css"

# Step 5: Copy Zen stylesheet.

cp "$subdir/zen/zen/zen.css" "$subdir/$1/$1.css"

# This is a personal preference. Rather than hacking the ugly and crowded
# $1.css file, I prefer to start with a blank file. But it needs to be included
# by $1.css. If you don't go along with my preference, simply comment out the
# next three lines of code by prepending them with a hash mark, just as these
# lines are.

touch "$subdir/$1/$1-fresh.css"
echo "@import url(\"$1-fresh.css\");" | cat - $subdir/$1/$1.css > $subdir/$1/$1.css.temp
mv $subdir/$1/$1.css.temp $subdir/$1/$1.css

# Step 6: Change STARTERKIT in template.php and theme-settings.php.

sed -e "s/STARTERKIT/$1/g" -i ".backup" "$subdir/$1/template.php"
sed -e "s/STARTERKIT/$1/g" -i ".backup" "$subdir/$1/theme-settings.php"

rm "$subdir/$1/template.php.backup"
rm "$subdir/$1/theme-settings.php.backup"

echo "Done. The script will attempt to delete itself. Please check to make sure"
echo "that it succeeded, and if not, delete it manually. It may be a security"
echo "risk."
rm "$0"
SeanBannister’s picture

sub

SeanBannister’s picture

I'd really like to see the ability to modify the size of the left and right block regions, as thoes negative margins are confusing, there was talk at http://drupal.org/node/215229

SeanBannister’s picture

Hey mikey_p could we get the code for the Zen Sub-Theme Creator, it's be really cool to see this as a module of even as part of Zen, I think it would help a lot of people.

mikey_p’s picture

@ #23 - I've pulled the feature as I just migrated to a new server, and haven't set this up again, and I'm expecting to do some significant work to re-factor this soon. When I get around to it this will probably be a separate module hosted on d.o.

SeanBannister’s picture

I see this as a valuable addition to Zen, I would like to somehow see this become a part of Zen because the process of setting up a new Zen theme is currently a pain. I'd also like to see this module support multiple STARTERKITS.

Garrett Albright’s picture

I'd also like to see this module support multiple STARTERKITS.

What do you mean by this?

SeanBannister’s picture

Sorry I should make myself clear.

I've been thinking for a while that the mindset of just using "STARTERKIT" for new themes should be changed, for example I've created my own subtheme that I plan to release to the community called Zentastic. This is just a Zen subtheme with some enhanced CSS and HTML that works really well for starting my designs.

It'd be great if the Zen Sub-Theme Creator could take any Zen theme and make a subtheme of it. So down the track when there's more contrib subthemes users of Zen can choose which theme is a good starting point for their design and quickly role a subtheme.

GravitySpec’s picture

heh, figures my luck I would get to the generator page to see it is down until it can be brought back up. :P

This is definitely an interesting thing you guys have going here, please give us a heads up if a drupal module for this pops up. :D

Garrett Albright’s picture

Sean, giving some thought with what you said and thinking about my own (albeit limited) experiences with creating subthemes of subthemes with Zen, I don't think it's that frequent and/or difficult of a job to warrant tweaking my script to work with it. But if you disagree, feel free to alter my script yourself. Shell scripting is fairly simple if you already know your way around a Unix command line - the hardest part for me is just trying to remember all the bajillion things sed can do.

Anyway, here's a slightly updated version which adds the "fresh" CSS file by listing it in the .info file instead of importing it from another CSS file. This is more Drupalic, though the end user won't notice the difference.

#!/bin/bash

if [ -z "$1" ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]
then
  echo "Zenify"
  echo "by Garrett Albright"
  echo "For quickly setting up subthemes of the Zen Drupal theme."
  echo "Place at the root level of your Drupal installation. After executing,"
  echo "DELETE THIS SCRIPT if it did not delete itself! (Or at least remove"
  echo "execute permissions.)"
  echo ""
  echo "Usage:"
  echo "  zenify.sh subtheme_name [human_name [layout_type [site_dir]]]"
  echo "Parameters:"
  echo "  subtheme_name: The machine name of your subtheme. Should consist of"
  echo "     lower-case letters or underscores only."
  echo "  human_name: The human-friendly name of your subtheme. If it contains"
  echo "     spaces, try enclosing the name in quotes, or weird stuff may happen."
  echo "  layout_type: The layout type: fixed or liquid. Defaults to 'fixed'."
  echo "  site_dir: The name of the directory inside Drupal's 'sites' directory"
  echo "    where your site files (including themes) will be stored. The Zen"
  echo "    base theme should already be in place at /sites/site_dir/themes/zen."
  echo "    Defaults to 'all'."
  echo ""
  echo "Examples:"
  echo "  Simplest usage:"
  echo "     zenify.sh foo"
  echo "  Giving your theme a human-friendly name:"
  echo "    zenify.sh foo \"The Foo Theme\""
  echo "  A friendly name and a liquid layout:"
  echo "    zenify.sh foo \"The Foo Theme\" liquid"
  echo "  A friendly name and a fixed layout, but only for example.com:"
  echo "    zenify.sh foo \"The Foo Theme\" fixed example.com"
  exit
fi

if [ `echo "$1" | grep -c -e '[^[:lower:]_]'` -eq "1" ]
then
  echo "Invalid subtheme name. Subtheme names should consist only of lowercase"
  echo "letters and the underscore character."
  exit
fi

# Step 1: Create directory.

dirname="`dirname $0`"

if [[ -z "$4" && -d "$dirname/sites/all/themes/zen/STARTERKIT" ]]
then
  subdir="$dirname/sites/all/themes"
else
  if [ -d "$dirname/sites/$4/themes/zen/STARTERKIT" ]
  then
    subdir="$dirname/sites/$4/themes"
  else 
    echo "Oh noes! STARTERKIT not found."
    exit
  fi
fi

cp -r "$subdir/zen/STARTERKIT" "$subdir/$1"

# Step 2: Rename and edit .info file.

if [ -z "$2" ]
then
  human="$1"
else
  human="$2"
fi

sed -e "s/STARTERKIT/$1/g" -e "s/^name.*$/name        = $human/" -e "s/^description.*$/description = The $human theme \– created automatically by zenify.sh./" "$subdir/$1/STARTERKIT.info"> "$subdir/$1/$1.info"
rm "$subdir/$1/STARTERKIT.info"

# Step 3: Copy liquid or fixed stylesheet.

if [ -z "$3" ]
then
  styletype="fixed"
else
  styletype="$3"
fi

cp "$subdir/zen/zen/layout-$styletype.css" "$subdir/$1/layout.css"

# Step 4: Copy print stylesheet.

cp "$subdir/zen/zen/print.css" "$subdir/$1/print.css"

# Step 5: Copy Zen stylesheet.

cp "$subdir/zen/zen/zen.css" "$subdir/$1/$1.css"

# This is a personal preference. Rather than hacking the ugly and crowded
# $1.css file, I prefer to start with a blank file. If you don't go along with
# my preference, simply comment out the next four lines of code by prepending
# them with a hash mark, just as these lines are.

touch "$subdir/$1/$1-fresh.css"
sed -e "/stylesheets\[print\]\[\] = print.css/i\\
stylesheets[all][] = $1-fresh.css" -i ".backup" "$subdir/$1/$1.info"
rm "$subdir/$1/$1.info.backup"

# Step 6: Change STARTERKIT in template.php and theme-settings.php.

sed -e "s/STARTERKIT/$1/g" -i ".backup" "$subdir/$1/template.php"
sed -e "s/STARTERKIT/$1/g" -i ".backup" "$subdir/$1/theme-settings.php"

rm "$subdir/$1/template.php.backup"
rm "$subdir/$1/theme-settings.php.backup"

echo "Done. The script will attempt to delete itself. Please check to make sure"
echo "that it succeeded, and if not, delete it manually. It may be a security"
echo "risk."
rm "$0"
grendzy’s picture

subscribing

Garrett Albright’s picture

For those that might be interested, I've finally buckled and turned Zenify into a full-fledged module. Please give it a try if you can.

http://drupal.org/project/zenophile

q0rban’s picture

I'm surprised no one has mentioned creating drush commands for this instead of creating a whole module... Or, I suppose the zenophile module could house the drush commands... (heads over to the zenophile issue queue)

mikey_p’s picture

Component: Code » Miscellaneous

Garrett, would it be fair to close this issue, and send folks with this to the issue queue for Zenophile?

Garrett Albright’s picture

Status: Needs review » Closed (fixed)

Sure.

PeculiarJulia’s picture

I loved the Zenophile module so much, and it saved me so much time - i've blogged it - thanks all, i hope i've done you justice.

Garrett Albright’s picture

Thanks for the kind words, applegirl - I've quoted your review on the Zenophile project page.