Drupal is set up to maintain community-based sites out of the box, with comments, blogs, forums, and multiple users and roles integrated as part of core.
However it's also a very strong platform for centralized, traditional Content Management and a full web development platform, from a brochureware 'about us' site presence to full ecommerce site or knowlegebase.
This handbook focuses directly on the latter cases, with lessons learned from private, corporate and government sites.
These types of site differ from default Drupal sites in the following ways:
Large projects often come with, or evolve, a large number of feature requests. What starts with "Content editors shall be able to easily edit any content they are authorized to have access to", soon becomes:
Now all this is well and good, and each of these requests, as well as many more can be handled within Drupal. Using a combination of Drupal contrib modules and user permissions, all these features can be added.
A responsive web developer will go through the list of features and turn each of these things on.
Once we have a number of individual features in action, the Drupal node edit screen starts getting bigger and bigger. It gets filled with a number of optional extras, that may or may not be used or required for various contexts. Drupal role permissions - although they are already quite granular, are often a bit global in some respects.
A rule like "Content editor can place 'book pages' in a menu but not assign a menu item to 'press release'" is not handled in core. Enabling the "Administer menus" permission to a content editor means that all nodes they can edit get that feature.
The ability to change the date on an item comes with the 'Administer nodes' role, and as well as adding that right globally (not per page type or per section) it adds yet another edit widget to the page, A widget that is only used rarely, if ever.
Some contrib module exist that can further break down the permissions system to deal with each of these cases (Menu Permissions, Menu Subtree Permissions, Menu Admin per menu, ... ) And those fixes may work, but start to branch away from the core business requirements, and can add complexity to testing.
And then there is the documentation. All the features are there, and most of them are straightforward to use in themselves, but when there are 20 features and form fields in an edit page, finding the right one, learning the terminology, and ignoring the irrelevancies makes training difficult and intimidating.
Client: The edit interface is "Too complex". It should be "simpler" and "more intuitive". Editors don't know what to do
OK, so which of the required features do you want to remove? Everything on that page is there because you asked for it specifically!
... I think this could probably be addressed with a little training and familiarity (Client: "No training, it should "just work") :-/
Yeah. So most form elements can have more descriptive text added, to really explain the bits that are currently "confusing". This can be done by either
Client: The form is now 7 screens long, all that text makes it hard to find the part I need, and editing is slow with all the scrolling
Damn right it's now harder to use. How about we minimize the help text, tuck it into a hover text or something so it only shows up when needed?
(Help Toggle, BeautyTips)
.. And we are back where we started. That didn't work.
Adding text to explain your UI means your usability has failed. Lets fix the problem instead of making excuses for it and propping it up with documentation.
The default Drupal 6 UI will 'collapse' unused fieldsets, but they still sorta take up space and require scrolling past. And apparently some users still don't understand that they can click to open them. (Fix? Put a css expandy icon next to the collapsed items?)
Best suggestion: Enable "Vertical Tabs". This massively tames the Drupal edit form, and means much less scrolling. It's core in Drupal 7.
Client: I don't know which parts to edit, what if I miss something? I still have to click through everything to make sure it's right.
Um, you're just being difficult now, aren't you?.
These extra features (eg embargo) are only used very occasionally, maybe if we remove them from the UI altogether unless you ask for it? They will be available, but not in-your-face most of the time.
So here's my fix.
Advanced Form will take the form fields, and hide them on the client side until they are needed.
There have been other modules that do this, like Formfilter - which removes unwanted fields for some roles, but can't be toggled. I want to minimize some form elements, but keep them available on demand.
With Advanced Form, we can specify which fields show up where, depending on node type, state, or user role. It will hide many unused fields, but allow them to be available if wanted. This is not a security layer, it is a UI-simplification tool.
Enable Advanced Form, and a small toggle widget will be placed on the page. Toggle this and the unused fields will be revealed.
When setting up from a brand new install, a few basic steps are:
Drupal supports the concept of 'profiles' which, when used properly, can be created to do all this for you automatically.
However, you are going to have to review all these settings at some stage anyway.
| Attachment | Size |
|---|---|
| corporate.profile | 5.44 KB |
It's easy to forget, but does several housekeeping tasks (like log-rolling) you may not be aware of.
On a dev site, I set the cron job to run under the www-data username
#> sudo su www-data
$> crontab -eFor a site that you are building to hand over to a client, set up an 'editor' role early on, create an editor user, and log in as that often during development. See what the end-user content-manager will see. Become familiar with the access rights that each module provides.
Avoid using just 'Authenticated user' unless you have planned the future registration strategy. During development, all 'authenticated users' should be either developers or editors, so put them in those groups. Otherwise you may find yourself granting permissions to a role that will cause security problems later.
Most modules do not provide access to their functions unless you have granted that permission Even rights like 'View Search Results' have to be turned on by hand. It's common that installing a module will have no visible effect, or that its menu items will be hidden until you also enable access to the functionality.
Admin user #1 automatically has all rights, so you may not see the gaps unless you try as a content editor role. Note that even if you make an 'Administrator' role, that is still not as powerful as user #1 and still has to have new rights assigned to it when new rights (from modules) become available. A handy work-around is to allow the 'Administrator' role to 'administer access control' - which means they have the ability to give themselves access to anything they want. It's a possible security hole, but it's useful enough as to be 'by design'.
Figure out a backup (and restore) strategy ASAP. If nothing else, It's handy to have a 'snapshot' function you can use before testing out potentially misbehaving modules or actions.
File backups are intuitive, but Database backups are even more important when most of the configurations are actually stored in the DB.
For local development, I use MySQL Administrator to do manual 'backups' and rollbacks several times in the course of development. PHPAdmin etc can also do this, or Drupal modules exist to help also. Backup Migrate is the standard for that, and includes a scheduler, which is a breeze to set up.
Nowadays I've taken to using drush - Drupal shell along with some modified sitesynch scripts for drush to really make this easy.
Even if you are not planning to use a distribution as a multisite, it helps a lot to start thinking that way.
/sites/sitename, and all else is core.This makes it trivial to automate a backup, zip an archive, and even painlessly run an entire alternate version of the site alongside another, with minimal duplication.
Never place anything in any of the distributed directories except under /sites. This includes '/modules', '/themes' and even '/files'. Do not even create and start putting things in a root directory called /images like normal without considering the options.
The options are : that theme-specific images go into the theme dir, and page-specific images go into the files dir. What else is there?
sitename here can and probably should be default for stand-alone sites, but you still end up with three potential places for modules to be
/modules - Don't touch/sites/all/modules - Clean distributions only/sites/default/modules - Custom and hacked modules - the bits that are unique to this version of this siteUse /sites/all/modules for installing clean, untouched distributions downloaded from drupal.org.
The minute you start hacking or patching modules from there, move that module from /sites/all/modules into /sites/default/module - to indicate that the files are now all your own, and no longer pristine.
When beginning to tweak, it would be good at this stage to actually CVS checkout the module from cvs.drupal.org - to ensure you have the latest, and so that your changes can easily be turned into a patch - even if just for your own reference.
When moving a module, you may have to visit the modules page and save once more. This should just reset the filepath for the module to the correct place.
For a multisite or development site, change the file system path from 'files' to 'sites/default/files' as soon as it's installed. This may create awkwardly long URLs, so it's probably not neccessary for a one-off site.
It's common to start mocking up a theme with direct references to source images in an absolute directory. As development progresses, many of these image references are moved into CSS. This is good, but it's not the end of the story.
As well as being the Right Way To Do It, this has the advantage of seamless theme upgrades into the future, where you will be able to plug a whole new theme in alongside an existing working site without worrying about image conflicts with 'logo.jpg' etc.
For this reason, it makes sense to 'version' themes when naming them. OTOH, you should NOT version your custom modules. As above, your custom theme should go into /sites/default/themes not /themes
+---sites/
| +---default/
| | +---themes/
| | | +---theme_2007/
| | | | +---<b>style.css</b>
| | | | +---<b>page.tpl.php</b>
| | | | +---images/
| | | | | +---bg-header.gifThe way to do this is twofold:
#header { url('images/bg-header.gif') center no-repeat; }As URLs found in CSS are taken to be relative to the location of the css itself.
page.tpl.php and others<img src="/themes/theme_2007/images/footer-logo.gif" />use PHP to construct the URL
<img src="<?php print(url($directory)); ?>/images/footer-logo.gif" />... where $directory is the current path_to_theme() provided by phptemplate for this purpose.
This approach should also be used if manually adding CSS or JS, although there are also more Drupally ways of doing this also.
<link rel="stylesheet" type="text/css" media="print" href="<?php print url($directory.'/print.css'); ?>" />This approach should probably be tried any time there is a raw href in the template. Even links are probably better converting from the hard-coded:
<a href="/home">Home</a>... to the more portable (it can even work in subsites)
<a href="<?php print url('home') ; ?>">Home</a>... or even the true Drupal (it can be enhanced on-the-fly)
<?php print l('Home', 'home') ; ?>It's the CMS job to look after dirty details like that, so removing hard-code from the template and giving it to Drupal is a good thing. Just pasting in raw HTML does work and is a good start, but you want to migrate everything into managed menus and blocks eventually.
At some stage, your site is going to have need of some code that existing modules cannot fulfill.
However, do search the repository and ask on the forums if it's been done before. Often the modules are named in ways that are non-obvious to what you want them to do.
Next, scan the PHP snippets (both page and block) to see if there are any ideas there. But be aware that most 'snippet' code is of 'proof of concept' quality only and is often inefficient or deficient in several ways.
Most importantly, using inline PHP code in a block or node body is a painful way to program and test. The sooner you bite the bullet and start your own custom tweaks module, the better.
Your own module can implement as many or as few of the available hooks as you like. Start small.
A big advantage of putting your code in a module is that it's easier to version, diff, backup and deploy to other sites, eg staging to live. This is much trickier when you've created a PHP node or block, and you then have to copy & paste the code from one place to anther using the Drupal UI. Add to this the risk that a mistake in a PHP block can crash the entire site.
Moving the code into a module - even if it's only a single-use thing - starts you thinking about configurations and re-use. Hard-coding a taxonomy ID for example looks obvious on a PHP page, (see the snippets) but IDs may be different between different sites (dev|staging|live) and writing the same hard-coded number into a .module file would be a mistake.
As there are core theme functions, such as l(), theme_item_list(), and even theme_table() to use.
The exception is actual theme_functions defined by the module itself, which are designed to be over-ridden.This is a general guideline for module development. Write-once custom code can take a few short-cuts
Sometimes it's hard to distinguish between what is a theme task and what is a functional task. Neither a PHP nor HTML make that decision easy, as they've always traditionally mixed them up also.
There are several gems hidden in the handbook but they are easy to miss if you didn't even know the question to ask.
Every fragment of a Drupal page (apart from your own page.tpl.php) has been output by a theme_*() function somewhere. If you can find the name of that function, you can bend it to your will. The hardest part is finding the right one!.
Read more about over-riding theme_*() functions. non-exhaustive list of available theme_*() functions (each contrib module adds a few more possibilities).
To find the function I often have to to a find-in-files over my drupal distribution, or inspect the likely modules directly, looking for function names.
I use The Eclipse IDE so it's usually only a cople of clicks to find the keyword I need.
Common theming targets include
Note that if there are tasks that seem too hard to do in a theme override function, you probably have to go up a level to find its caller, or maybe get happy with hook_form_alter() for serious re-renderings.
Get familiar with the built-in power of the phptemplate theme engine, and how it can automagically select unique templates based simply on the ID of the calling object.
Try to break your theme CSS up into functional bits, eg search form styling, to keep it manageable. Drupal (with CSS caching) will fix thing so that this approach does not least to lots of file requests, so go granular!
I try to refactor my themes into something like:
layout.css
typography.css
admin.css
color.css... as appropriate. Then sometimes lay on function or feature-specific tweaks such as
menu.css
ecommerce.cssif needed. This is not always needed, but if I'm doing some highly special thing to the menu navigation, maybe it is best done stand-alone.
Following the example of the page selection pattern, we can do the same with blocks, AND package a block-specific bit of CSS along with it.
Investigating phptemplate_block() we see that, for example, the user login block will be looked for in any available file called:
block-user-1.tpl.php
block-user.tpl.php
block-left.tpl.php
block.tpl.phpSo, we can create a custom block template, called block-user-1.tpl.php and call our own css to be included only on pages where that block shows up.
block-user-1.tpl.php
<?php
// Add a block-specific css, if it exists
if(file_exists( $css = path_to_theme() .'/block-'. $block->module .'.css')){
drupal_add_css($css);
}
// This block includes a couple of placeholders used for styling graphic corners,
// and a title placeholder for semantic image-replacement.
?>
<div id="block-<?php print $block->module; ?>-<?php print $block->delta; ?>" class="block<?php print " block-$block->module"; ?>">
<div class="top placeholder"></div>
<?php if ($block->subject): ?>
<h3 class="title"><span class="title-text"><?php print $block->subject; ?></span></h3>
<?php endif; ?>
<div class="content"><?php print $block->content; ?></div>
<div class="bottom placeholder"></div>
</div>This will end up including the themes block-user.css
Due to the order the page gets built, the use of drupal_add_css() means that the css declaration will find its way into the head in time, and NOT get included if this particular block is not being shown.
You can see the possibilities for modular code here! This is quite handy if you have a small team working on the same design at the same time.
No more big interwoven CSS files.
Yeah, on the other hand this can get harder to manage in your head at one time - but with an IDE and the DOM inspector, it's not that hard at all.
Note that you cannot disable or backup a module reliably by renaming its directory. Due to the way Drupal module management scans for available modules, creating a local backup called, eg like
sites/default/modules/image/
sites/default/modules/image.backup.2007-07/... as a precaution before messing around with image/image.module will cause madness as you cannot be sure which actual code Drupal will choose to use!
When backing up or duplicating modules, you must either zip-up or move the entire directory outside of the active 'modules' directory or it may be found and used.
Similarly, the same applies to module files. If you get into the situation of:
modules/image/image.module
modules/image/Copy of image.moduleYou may engender conflicts. Change the suffix to avoid this.
modules/image/image.module.originalSee the administration modules available. Utils like devel.module, backup or sitesynch all have their own merit.
It's pretty rare I'd build a site without using image.module and upload.module
I still don't know which to choose between tinyMCE and fckEditor.
Differences include - Image embedding, UI button configuration, Available plugins, Configuration of where the WYSIWYG is used.
contact.module is not as versatile as webform.module