View source
<?php
function zenophile_menu() {
return array(
'admin/build/themes/zenophile' => array(
'title' => 'Create Zen subtheme',
'description' => 'Quickly create a Zen subtheme for theming.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'zenophile_create',
),
'access arguments' => array(
'create zen theme with zenophile',
),
'type' => MENU_LOCAL_TASK,
),
);
}
function zenophile_perm() {
return array(
'create zen theme with zenophile',
);
}
function zenophile_create() {
if (drupal_get_path('theme', 'STARTERKIT') === '') {
drupal_set_message(t('The STARTERKIT theme could not be found. Please check that the <a href="!zen">Zen theme</a> is properly installed.'), array(
'!zen' => 'http://drupal.org/project/zen',
), 'error');
}
else {
$zen_based = array();
foreach (list_themes(TRUE) as $theme) {
if (in_array('zen.css', array_keys($theme->info['stylesheets']['all']))) {
$zen_based[$theme->name] = t('@tname (@tsname)', array(
'@tname' => $theme->info['name'],
'@tsname' => $theme->name,
));
}
}
return array(
'parent' => array(
'#title' => t('Starter theme'),
'#type' => 'select',
'#options' => $zen_based,
'#default_value' => 'STARTERKIT',
'#required' => TRUE,
),
'sysname' => array(
'#title' => t('System name'),
'#description' => t('The machine-compatible name of your subtheme. This name should consist of only lowercase letters plus the underscore character.'),
'#type' => 'textfield',
'#required' => TRUE,
),
'friendly' => array(
'#title' => t('Human name'),
'#description' => t('A human-friendly name for your subtheme. This name may contain uppercase letters, spaces, punctuation, etc. If left blank, the system name will also be used here.'),
'#type' => 'textfield',
),
'description' => array(
'#title' => t('Description'),
'#description' => t('A short description of this theme.'),
'#type' => 'textfield',
'#required' => TRUE,
),
'layout' => array(
'#title' => t('Layout type'),
'#description' => t('A fixed layout will stay the same width, regardless of the user’s browser window width. Any space beyond the width of the layout will be filled with blank space on either side of the layout, so that the layout is always centered in the browser window. A liquid layout will adjust its width depending on the width of the user’s browser window width, so that the edges of the layout are always the same distance from the edges of the browser window (though this breaks when the browser window is made to be extremely narrow). If in doubt, you probably want to use a fixed layout.'),
'#type' => 'radios',
'#options' => array(
'fixed' => t('Fixed'),
'liquid' => t('Liquid'),
),
'#default_value' => 'fixed',
'#required' => TRUE,
),
'site' => array(
'#title' => t('Site directory'),
'#description' => t('Which site directory would you like your new subtheme to be placed in? If in doubt, select <em>all</em>.'),
'#type' => 'select',
'#options' => _zenophile_find_sites(),
'#default_value' => array(
'all',
),
'#required' => TRUE,
),
'fresh' => array(
'#title' => t('Create fresh CSS file'),
'#description' => t('If checked, Zenophile will create a new empty CSS file and add it to the theme via its .info file. Some themers may prefer to start with a fresh empty CSS file rather than adapting the pre-created CSS file which will be copied over from the STARTERKIT directory.'),
'#type' => 'checkbox',
'#default_value' => TRUE,
),
'submit' => array(
'#type' => 'submit',
'#value' => t('Submit'),
),
);
}
}
function zenophile_create_validate($form, &$form_state) {
if (preg_match('/[^a-z_]/', $form_state['values']['sysname'])) {
form_set_error('sysname', t('The <em>System name</em> may only consist of lowercase letters and the underscore character.'));
}
if (drupal_get_path('theme', $form_state['values']['sysname'])) {
form_set_error('sysname', t('A theme with this <em>System name</em> already exists. Cowardly refusing to create another one.'));
}
}
function zenophile_create_submit($form, &$form_state) {
$t_dir = "sites/{$form_state['values']['site']}/themes";
if (!file_exists($t_dir) && !mkdir($t_dir, 0755)) {
form_set_error(NULL, t('The <em>themes</em> directory for the %site site directory does not exist, and it could not be created automatically. Please create the directory %dir manually and try again.', array(
'%site' => $site,
'%dir' => $t_dir,
)), 'error');
}
else {
$dir = "{$t_dir}/{$form_state['values']['sysname']}";
if (file_exists($dir)) {
form_set_error(NULL, t('The subtheme directory %dir could not be created because a file or directory with that name already exists.', array(
'%dir' => $dir,
)));
}
else {
if (mkdir($dir)) {
$parent_dir = drupal_get_path('theme', $form_state['values']['parent']);
$zen_dir = drupal_get_path('theme', 'zen');
$h = opendir($parent_dir);
$parent_info = $form_state['values']['parent'] . '.info';
while (($file = readdir($h)) !== FALSE) {
$fpath = "{$parent_dir}/{$file}";
if (is_file($fpath) && $file[0] !== '.' && $file !== $parent_info && $file !== 'template.php' && $file !== 'theme-settings.php') {
copy($fpath, "{$dir}/{$file}");
}
}
$path_part = "{$dir}/{$form_state['values']['sysname']}";
$info = file_get_contents("{$parent_dir}/{$parent_info}");
$info = preg_replace('/^; \\$Id.*\\$$/m', '; $Id$', $info, 1);
$from = array(
"/{$form_state['values']['parent']}/",
'/^name\\s*=.*/m',
'/^description\\s*=.*/m',
);
$to = array(
$form_state['values']['sysname'],
'name = ' . ($form_state['values']['friendly'] === '' ? $form_state['values']['sysname'] : $form_state['values']['friendly']),
'description = ' . $form_state['values']['description'],
);
if ($form_state['values']['fresh']) {
$from[] = '/^stylesheets\\[all\\]\\[\\]\\s*=\\s*zen\\.css$/m';
$to[] = "stylesheets[all][] = zen.css\n\n ; Specifying a nice clean stylesheet\nstylesheets[all][] = {$form_state['values']['sysname']}-fresh.css";
touch($path_part . '-fresh.css');
}
$info = preg_replace($from, $to, $info);
file_put_contents($path_part . '.info', $info);
if ($form_state['values']['parent'] === 'STARTERKIT') {
copy("{$zen_dir}/layout-{$form_state['values']['layout']}.css", "{$dir}/layout.css");
copy($zen_dir . '/print.css', $dir . '/print.css');
$parent_css = "{$dir}/{$form_state['values']['parent']}.css";
if (file_exists($parent_css)) {
rename($parent_css, "{$dir}/{$form_state['values']['sysname']}.css");
}
else {
copy($zen_dir . '/zen.css', "{$dir}/{$form_state['values']['sysname']}.css");
}
}
$info = file_get_contents($parent_dir . '/template.php');
$info = str_replace($form_state['values']['parent'], $form_state['values']['sysname'], $info);
file_put_contents($dir . '/template.php', $info);
$info = file_get_contents($parent_dir . '/theme-settings.php');
$info = str_replace($form_state['values']['parent'], $form_state['values']['sysname'], $info);
file_put_contents($dir . '/theme-settings.php', $info);
drupal_set_message(t('A new subtheme was created in %dir.', array(
'%dir' => $dir,
)));
system_theme_data();
}
else {
drupal_set_message(t('An error occurred while trying to create the subtheme directory %dir.', array(
'%dir' => $dir,
)));
}
}
}
}
function _zenophile_find_sites() {
$sites = array();
if ($h = opendir('sites')) {
while (($site = readdir($h)) !== FALSE) {
if (is_dir('sites/' . $site) && !is_link('sites/' . $site) && $site[0] !== '.' && $site !== 'default') {
$sites[] = $site;
}
}
return drupal_map_assoc($sites);
}
else {
drupal_set_message(t('The <em>sites</em> directory could not be read.'), 'error');
return array();
}
}