One of Drupal's primary powers is the seperation of the data processig from the presentation. Lasqueti.ca takes full advantage of these abilities by defining a custom theme. The "lasqueti theme" is documented here, along with some sub-pages that describe some of the custom theme programming.
The Lasqueti theme is a "hard-coded" version of the Denver theme. Denver is a very flexible theme and specifies vitually everything with configurable parameters. That is great for proto-typing, but slow for the production site.
The Denver theme was set-up to look "correct", and them copied to the Lasqueti theme. The Lasqueti theme was then editted to "hard code" the various parmater values set in Denver.
Several additional changes were made to Lasqueti theme, for example:
All of this is documented in the sites/all/themes/lasqueti readme.
The Lasqueti theme could have a set of sub-themes, which simply change the banner for special parts of the site (e.g., like the marketplace) or provide style to hide images or other bandwidth intensive content (a low-bandwidth style).
Important - from the Denver Theme readme file:
"to prevent rendering errors in IE you must enable the CSS Aggregator in admin/settings/performance... Enable "aggregate and compress CSS files" to make your production drupal site run faster, and to prevent IE rendering errors."
The following functions were added to PHPtemplate in the lasqueti theme to obtain the required functionality. Some of these should probably be made into a custom module.
see: HowTo: Replace node title with a related image | drupal.org
<code>
// This function is used to substitue the node title with an image of the same name.
// Really good candidate to turn into a small module.
function _phptemplate_variables($hook, $vars = array()) {
switch ($hook) {
case 'page':
// substitute node title with an image, if a suitable replacement can be found.
// save original title text for use in head and breadcrumb.
$vars['breadcrumb_title'] = $vars['title'];
$vars['head_title'] = $vars['title'];
// Substitute title only for nodes...
if (arg(0) == 'node' && is_numeric(arg(1))) {
$node = node_load(arg(1)); // (expensive, unless arg(1) is already loaded, which is should be at this point.)
// ... of one of the listed types - add node types to process to the array.
if (in_array($node->type, array('page', 'page_layout_b'))) {
// convert title to suitable filename and derive both file system path and URL.
$titleFile = clean_title($vars['title']) . '.gif';
$titleImage = base_path() . "files/images/titles/" . $titleFile;
$titleURL = "http://" . $_SERVER['SERVER_NAME'] . $titleImage;
$titlePath = $_SERVER['DOCUMENT_ROOT'] . $titleImage;
// $vars['title'] = $titleURL; // DEBUG - see what's being produced
// Determine if a suitable replacement image for title can be found, and make substitution.
if ( file_exists($titlePath) ) {
$newTitle = '<img alt=\'' . $vars['title'] .'\' src=\'' . $titleURL .'\' />';
$vars['title'] = $newTitle;
}
}
}
break;
}
return $vars;
}
// Prepare some general title text for use as a file name.
// Remove special HTML characters, trim whitespace, convert to lower-case
// repace spaces with underscores.
function clean_title($string)
{
$cleanString = htmlspecialchars_decode( strtolower(trim($string)), ENT_QUOTES );
$cleanString = str_replace(array("& ", "'"), '', $cleanString);
// $string = strtolower(preg_replace("/[^a-zA-Z0-9 ]/", "", $string)); // slower, but more general purpose.
return str_replace(' ', '_', $cleanString );;
}
</code>
<code>
// Create a mock-menu from a view's summary (usually for a block view)
// See Example: How to Display a Summary View as a Mock Menu http://drupal.org/node/42605
function _summary_menu($view, $level, $nodes) {
foreach ($nodes as $node) {
$list .= '<li class="leaf">' . views_get_summary_link($view->argument[$level]['type'], $node, $view->real_url) . "</li>\n";
}
if ($list) {
return "<div class='menu'><ul>$list</ul></div>";
}
}
// Photo albums are per-user, so agrument is user ID UID
function phptemplate_views_summary_photo_albums($view, $type, $level, $nodes, $args) {
if ($type == 'block') {
return _summary_menu($view, $level, $nodes);
}
else {
drupal_add_css(drupal_get_path('theme', 'lasqueti') .'/css/image_gallery.css', 'theme');
// Need generic way to get image file info? - must use name of CCK field.
// Replace this with the name of your image field.
// Uncomment the print_r below to figure out what it is.
$cck_fid_field = 'node_data_field_image_field_image_fid';
$content .= '<ul class="galleries">';
$title = "'s Personal Photo Album";
$baseUrl = $view->url;
// Build a small, single node teaser for each query in the summary and
// use it as a link to the actual view page with that argument.
foreach ($nodes as $query) {
// Get the argument for this view from the query.
$uid = $query->uid; // argument is user id;
$user = $query->name; // query also has user's name.
// Build a 1 item query to grab the first node in this view
$result = views_build_view('items', $view, array($uid), false, 1);
// Grab the image from that node to display in our summary.
// The file id comes from the node info. we got back from views.
// print_r($result['items'][0]);
$fid = $result['items'][0]->$cck_fid_field;
$modDate = $result['items'][0]->node_changed;
// Query the database to get the file object
$file = _imagefield_file_load($fid);
$imgTag = theme('imagecache', 'Thumbnail', $file['filepath'], 'Latest image from gallery', $user . $title);
$url= $baseUrl .'/'. $uid;
$linkText = $imgTag .' '. $user . $title;
$content .= _theme_gallery_summary($imgTag, $url, $user.$title, $query->num_nodes, $modDate, NULL);
}
$content .= "</ul>\n";
return $content;
}
}
// Produce the themed output for the image gallery summary.
// This code was ripped from the image gallery module.
function _theme_gallery_summary($imgTag, $url, $title, $count, $modDate, $description=NULL)
{
$content = "";
$content .= '<li class="clear-block">';
if ($count>0) {
$content .= l($imgTag, $url, array(), NULL, NULL, FALSE, TRUE);
}
$content .= "<h3>". l($title, $url) ."</h3>\n";
if ($description) {
$content .= '<div class="description">'. check_markup($description) ."</div>\n";
}
$content .= '<p class="count">'. format_plural($count, 'There is 1 photo in this gallery', 'There are @count photos in this gallery') ."</p>\n";
if ($modDate) {
$content .= '<p class="last">'. t('Last updated: %date', array('%date' => format_date($modDate))) ."</p>\n";
}
$content .= "</li>\n";
return $content;
}
// Photo galleries are per-term, so argument is taxonomy term.
function phptemplate_views_summary_photo_gallery($view, $type, $level, $nodes, $args) {
if ($type == 'block') {
return _summary_menu($view, $level, $nodes);
}
else {
drupal_add_css(drupal_get_path('theme', 'lasqueti') .'/css/image_gallery.css', 'theme');
// Need generic way to get image file info? - must use name of CCK field.
// Replace this with the name of your image field.
// Uncomment the print_r below to figure out what it is.
$cck_fid_field = 'node_data_field_image_field_image_fid';
$content .= '<ul class="galleries">';
$title = " Photo Gallery";
$baseUrl = $view->url;
// Build a small, single node teaser for each query in the summary and
// use it as a link to the actual view page with that argument.
foreach ($nodes as $query) {
// Get the gallery description from the term's vocab.
$term = $query->letter; // argument for taxonomy terms;
$tid = $query->tid; // term IS the argument!
$termObj = taxonomy_get_term($tid);
$description = $termObj->description;
// Build a 1 item query to grab the first node in this view
$result = views_build_view('items', $view, array($term), false, 1);
// Grab the image from that node to display in our summary.
// The file id comes from the node info. we got back from views.
// print_r($result['items'][0]);
$fid = $result['items'][0]->$cck_fid_field;
$modDate = $result['items'][0]->node_changed;
$file = _imagefield_file_load($fid);
$imgTag = theme('imagecache', 'Thumbnail', $file['filepath'], 'Latest image from gallery', $term . $title);
$url= $baseUrl .'/'. $term;
$linkText = $imgTag .' '. $term . $title;
$content .= _theme_gallery_summary($imgTag, $url, $term.$title, $query->num_nodes, $modDate, $description);
}
$content .= "</ul>\n";
return $content;
}
}
This simply addes a collapsible fieldset for the CCK fields in the "Market Page" type, and hides the Categories fieldset from non-admins, to try to improve useability. See http://drupal.org/node/101092#comment-748013 for details.
function phptemplate_page_layout_b_node_form($form) {
// Collapse the taxonomoy fieldset by default (as this rarely changes).
$form['taxonomy']['#collapsed'] = true;
// enforce crude access rights on the taxonomy terms.
global $user;
if (!($user->uid==1 || in_array('contributor',$user->roles)) ) {
unset($form['taxonomy']);
}
// These are the fields that should be in the fieldset
$fields = array('field_teaser_image', 'field_bio_image', 'field_bio');
// Add fieldsets to the page_layout_b input form & render it.
_add_fieldset($form, 'Images', $fields);
return drupal_render($form);
}
/**
* Add the given fields to a new fieldset on the form.
* @form - the form to add the fieldset to
* @name - a string name of the fieldset
* @fieldsInSet - field ids (names) for the fields in
* the form that should go into the fieldset.
*/
function _add_fieldset(&$form, $name, $fieldsInSet) {
// Add a fieldset to the form to hold related fields.
$form[$name] = array (
'#type' => 'fieldset',
'#title' => $name,
'#collapsible' => 1,
'#collapsed' => 0,
'#weight' => -2,
'#tree' => 1,
);
// Move all the related fields into the new fieldset.
foreach ($fieldsInSet as $field) {
if ($form[$field]) {
$form[$name][$field] = $form[$field];
$form[$name][$field]['#parents'] = array ($name, $field);
unset($form[$field]);
}
}
}
When a node's page is viewed in a tab, we don't want to show any book navigation.
function phptemplate_book_navigation($node) {
if ($node->inTab)
return NULL;
else
return theme_book_navigation($node);
}
Exposed filters allow the user to have control over what nodes are viewed by selecting from a widget. The default layout is to have the widget displayed above the view, in the page - yuck - very ugly and poor usability. This "snippet" hides the default exposed filter for a view with the name "test" - it can be copied for any View where you want to do this. Then a custom block is created to display the exposed filter widget off to the side, or "rolled-up"! Much nicer.
See http://www.angrydonuts.com/displaying_views_exposed_filters
function phptemplate_views_display_filters_test() {
// Do absolutely nothing.
}
Anywhere the user can enter data is a form.
Mostly, these forms are generated by Drupal and the sequence the fields are presented is controlled using the field weights (manage fields under Content Types). However, there were a few cases where input forms were customised to improve their usability (mostly to make them less daunting to the community).
Any page, node, or block can have a custom template that defines its look. This is a very easy way to subtly alter the look of different parts of the site, or to customize the display of different types of data.
Heavily modified the Denver Theme version to remove almost all conditional theming and unused divs. Made a few other customizations to:
Basically, this is straight from the Denver theme, but with:
Defines the footer portion of the page that includes the "Our Community" and "MarketPlace" random image blocks.
Defines a custom layout for the "Market Page". Basically, this just adds the code to pull in the "mini-gallery" at the bottom of the page.
Added this to customize the look and feel of comments.
See Theming Drupal Comments, Exemplifying with Garland | All Drupal Themes
Some things just can't be developed as a full-fledged module...
Sometimes a hard-coded argument is required (e.g., specify vocabulary for a view), sometimes the code just needs further development to create a nice, general-purpose module. In any case, these small "modulettes" are less than a full-fledged module, but more than simply a snippet. They all perform some custom theming, often for a summary view of some sort.
This module creates a view of nodes by-category, to form a simple, 2-column directory.
Requires:
Options:
All code snippets, modules, and modulettes on this site are covered by GPL - see license.txt
The source code is attached below...
Full instructions for installing and using this module are included as comments in the source file.
Attachment | Size |
---|---|
directory_view.zip | 15.28 KB |
This module themes a views summary for a set of image galleries. The image galleries are defined with a view using an argument (usually Term or User). The summary view shows a thumbnail of the latest image from each gallery, the page title, last modified date, and number of images in the gallery. This is nearly identical to the gallery summary provided by the Image module's Image Gallery contrib module. This can be used to theme per-user gallery summaries or per-term gallery summaries. I can't think of (and haven't tested) other possibilities, but it should work with any argument type and any node type that defines at least one image where you want a nice looking summary.
Requires:
Options:
All code snippets, modules, and modulettes on this site are covered by GPL - see license.txt
The source code is attached below...
Full instructions for installing and using this module are included as comments in the source file.
Attachment | Size |
---|---|
summary_view_image_gallery.zip | 15.01 KB |
This module "automatically" replaces text titles with an "associated:" image, if a suitable replacement can be found. It simply converts the title into a filename and looks for that file - if it finds it, it formats the image tag to replace the title.
Requires:
All code snippets, modules, and modulettes on this site are covered by GPL - see license.txt
The source code is attached below...
Full instructions for installing and using this module are included as comments in the source file.
Attachment | Size |
---|---|
replace_title.zip | 13.35 KB |
This very tiny module creates a "mock menu" from a views summary - a menu item is created for each query, or potential argument value, in the views summary. This is handy for providing a menu that links to the various pages provided when a view has an argument.
All code snippets, modules, and modulettes on this site are covered by GPL - see license.txt
The source code is attached below...
Full instructions for installing and using this module are included as comments in the source file.
Attachment | Size |
---|---|
summary_view_mock_menu.zip | 13.03 KB |
This module creates a "mock menu" from a vocabulary, with links to the terms at a given base-path. This is very handy for providing a menu that links to a view with a Taxonomy:Term ID argument.
Requires:
Options:
All code snippets, modules, and modulettes on this site are covered by GPL - see license.txt
The source code is attached below...
Full instructions for installing and using this module are included as comments in the source file.
Attachment | Size |
---|---|
category_mock_menu.zip | 13.95 KB |