diff --git a/ftplugin/drupal.vim b/ftplugin/drupal.vim
index 124a1bb..e0bbc1c 100644
--- a/ftplugin/drupal.vim
+++ b/ftplugin/drupal.vim
@@ -29,15 +29,40 @@ endif
 let s:options = {'root': 'Drupal', 'special': '<buffer>'}
 call drupal#CreateMaps('v', 'SVN blame', 'gl', ':<C-U>!svn blame <C-R>=expand("%:P") <CR> \| sed -n <C-R>=line("''<") <CR>,<C-R>=line("''>") <CR>p <CR>', s:options)
 
-" {{{ @var $DRUPAL_ROOT
-" plugin/drupal.vim defines several useful strings in b:Drupal_info.
-" There is no such thing as buffer-local environment variables, so call this
-" each time you enter a Drupal buffer.
 augroup Drupal
-  autocmd! BufEnter <buffer> if strlen(b:Drupal_info.DRUPAL_ROOT) |
-	\ let $DRUPAL_ROOT = b:Drupal_info.DRUPAL_ROOT | endif
+  autocmd! BufEnter <buffer> call s:BufEnter()
 augroup END
-" }}}
+
+" {{{ @function s:BufEnter()
+" There are some things that we *wish* were local to the buffer.  We stuff
+" them into this function and call them from the autocommand above.
+" - @var $DRUPAL_ROOT
+"   Set this environment variable from b:Drupal_info.DRUPAL_ROOT.
+" - SnipMate settings
+let s:snip_path = expand('<sfile>:p:h:h') . '/snipmate/drupal'
+function! s:BufEnter()
+  if strlen(b:Drupal_info.DRUPAL_ROOT)
+    let $DRUPAL_ROOT = b:Drupal_info.DRUPAL_ROOT
+  endif
+  if exists('*ExtractSnips')
+    call ResetSnippets('drupal')
+    " Load the version-independent snippets.
+    let snip_path = s:snip_path . '/'
+    for ft in split(&ft, '\.')
+      call ExtractSnips(snip_path . ft, 'drupal')
+      call ExtractSnipsFile(snip_path . ft . '.snippets', 'drupal')
+    endfor
+    " If we know the version of Drupal, add the coresponding snippets.
+    if strlen(b:Drupal_info.CORE)
+      let snip_path = s:snip_path . b:Drupal_info.CORE . '/'
+      for ft in split(&ft, '\.')
+	call ExtractSnips(snip_path . ft, 'drupal')
+	call ExtractSnipsFile(snip_path . ft . '.snippets', 'drupal')
+      endfor
+    endif " strlen(b:Drupal_info.CORE)
+  endif " exists('*ExtractSnips')
+endfun
+" }}} s:BufEnter()
 
 " The tags file can be used for PHP omnicompletion even if $DRUPAL_ROOT == ''.
 " If $DRUPAL_ROOT is set correctly, then the tags file can be used for tag
@@ -101,7 +126,7 @@ nnoremap <buffer> <LocalLeader>dv :execute "!drush vget ".shellescape(expand("<c
 	\ ':execute "!drush vget ".shellescape(expand("<cword>"), 1)<CR>',
 	\ s:options)
 
-" PHP specific settings.
+" {{{ PHP specific settings.
 " In ftdetect/drupal.vim we set ft=php.drupal.  This means that the settings
 " here will come after those set by the PHP ftplugins.  In particular, we can
 " override the 'comments' setting.
@@ -109,7 +134,8 @@ nnoremap <buffer> <LocalLeader>dv :execute "!drush vget ".shellescape(expand("<c
 if &ft =~ '\<php\>'
   setl ignorecase              "Ignore case in search
   setl smartcase               "Only ignore case when all letters are lowercase
-  setl comments=sr:/**,m:*\ ,ex:*/,://
   "  Format comment blocks.  Just type / on a new line to close.
   "  Recognize // (but not #) style comments.
+  setl comments=sr:/**,m:*\ ,ex:*/,://
 endif
+" }}} PHP specific settings.
diff --git a/snipmate/drupal/php.snippets b/snipmate/drupal/php.snippets
new file mode 100644
index 0000000..04fc048
--- /dev/null
+++ b/snipmate/drupal/php.snippets
@@ -0,0 +1,246 @@
+## Forms API
+
+snippet checkbox
+	$form['${1:/* form element */}'] = array(
+		'#type' => 'checkbox',
+		'#title' => t('${2:/* title */}'),
+		'#description' => t('${3:/* description */}'),
+	);
+
+snippet checkboxes
+	$form['${1:/* form element */}'] = array(
+		'#type' => 'checkboxes',
+		'#title' => t('${2:/* title */}'),
+		'#description' => t('${3:/* description */}'),
+		'#options' => array(
+			'${4:/* key */}' => t('${5:/* value */}'),
+		);
+	);
+
+snippet file
+	$form['${1:/* form element */}'] = array(
+		'#type' => 'file',
+		'#title' => t('${2:/* title */}'),
+		'#description' => t('${3:/* description */}'),
+	);
+
+snippet select
+	$form['${1:/* form element */}'] = array(
+		'#type' => 'select',
+		'#title' => t('${2:/* title */}'),
+		'#description' => t('${3:/* description */}'),
+		'#options' => array(
+			'${4:/* key */}' => t('${5:/* value */}'),
+		),
+	);
+
+snippet submit
+	$form['${1:/* form element */}'] = array(
+		'#type' => 'submit',
+		'#value' => t('${2:/* value */}'),
+	);
+
+snippet textarea
+	$form['${1:/* form element */}'] = array(
+		'#type' => 'textarea',
+		'#title' => t('${2:/* title */}'),
+		'#rows' => ${3:/* default:5 */},
+	);
+
+snippet textfield
+	$form['${1:/* form element */}'] = array(
+		'#type' => 'textfield',
+		'#title' => t('${2:/* title */}'),
+		'#size' => ${3:/* default:60 */},
+	);
+
+## drupal_ functions
+
+snippet drupal_get_form
+	drupal_get_form('${1:/* Form ID */}', $${2:argument});
+
+snippet drupal_get_path
+	drupal_get_path('${1:/* Type: module, theme or theme_engine */}', '${2:/* Name */}');
+
+snippet drupal_get_path_alias
+	drupal_get_path_alias('node/${1:nid}', ${2:language (optional)});
+
+# Shortcut for drupal_set_message
+snippet dsm
+	drupal_set_message('${1:message}.', '${2:status, warning, or error}', ${3:repeat (default:TRUE)});
+
+## Hooks
+
+snippet hook_cron
+	
+	/**
+	 * Implementation of hook_cron()
+	 */
+	function `Filename()`_cron() {
+		${1:// Your code here.}
+	}
+	
+
+snippet hook_form_alter
+	
+	/**
+	 * Implementation of hook_form_alter()
+	 */
+	function `Filename()`_form_alter(&$form, $form_state, $form_id) {
+		switch ($form_id) {
+			case '${1:/* your form */}':
+			  ${2:// your code.}
+		}
+	}
+	
+
+snippet hook_help
+	
+	/**
+	 * Implementation of hook_help
+	 */
+	function `Filename()`_help($path, $arg) {
+		switch ($path) {
+			case '${1:/* path */}':
+				// Enter your help text below
+				return t('${2:/* text */}');
+		}
+	}
+	
+
+snippet hook_init
+	/**
+	 * Implementation of hook_init().
+	 */
+	function `Filename()`_init() {
+		${1:/* your code here */}
+	}
+
+snippet hook_mail_alter
+	
+	/**
+	 * Implementation of hook_mail_alter()
+	 */
+	function `Filename()`_mail_alter(&$message) {
+		${1:// Your code here.}
+	}
+	
+
+snippet hook_menu
+	/**
+	 * Implementation of hook_menu()
+	 */
+	function `Filename()`_menu() {
+		$${1:items} = array();
+	
+		// Put your menu items here.
+		$$1['${2:path}'] = array(
+			'title' => '${3:title}',
+			'page callback' => '${4:page_callback}',
+			'access arguments' => array('${5:permission}'),
+			'type' => ${6:MENU_SUGGESTED_ITEM},
+		);
+	
+		return $$1;
+	}
+	
+
+snippet hook_menu_alter
+	
+	/**
+	 * Implementation of hook_menu_alter().
+	 */
+	function `Filename()`_menu_alter(&$${1:items}) {
+		$$1['${2:/* your code here */}']
+	}
+	
+
+snippet hook_node_info
+	
+	/**
+	 * Implementation of hook_node_info().
+	 */
+	function `Filename()`_node_info() {
+		return array(
+			'${1:/* machine-readable name */}' => array(
+				'name' => t('${2:/* human-readable name */}'),
+				'module' => '`Filename()`',
+				'description' => t('${3:/* description */}'),
+			),
+		);
+	}
+	
+
+snippet hook_node_operations
+	
+	/**
+	 * Implementation of hook_node_operations()
+	 */
+	function `Filename()`_node_operations() {
+		$operations = array(
+		  '${1:/* operation */}' => array(
+		    'label' => t('${2:/* label */}'),
+		    'callback' => '${3:/* callback */}',
+		  ),
+		);
+		return $operations;
+	}
+	
+	/**
+	 * Callback function
+	 */
+	function $3 {
+		${4:// Your code here.}
+	}
+	
+
+snippet hook_theme
+	
+	/**
+	 * Implementation of hook_theme()
+	 */
+	function `Filename()`_theme($existing, $type, $theme, $path) {
+		return array(
+			'${1:theme_function}' => array(
+				'arguments' => array(${2:/* Theme function arguments */}),
+				${3:/* See for options */}
+			),
+		);
+	}
+	
+
+snippet hook_user_operations
+	
+	/**
+	 * Implementation of hook_user_operations()
+	 */
+	
+	function `Filename()`_user_operations() {
+		$operations = array(
+			'${1:/* operation */}' => array(
+				'label' => t('${2:/* label */}'),
+				'callback' => '${3:/* callback */}',
+			),
+		);
+		return $operations;
+	}
+	
+	/**
+	 * Callback function
+	 */
+	function $3 {
+		${4:// Your code here.}
+	}
+	
+
+## Everything else
+
+snippet l
+	l(${1:/* text */}, ${2:/* link */})
+
+snippet url
+	url('${1:path}', array('query' => '${2:query}', 'absolute' => ${3:false}))
+
+snippet watchdog
+	watchdog('${1:/* type */}', '${2:/* message */}'${3});
+
diff --git a/snipmate/drupal6/php.snippets b/snipmate/drupal6/php.snippets
new file mode 100644
index 0000000..8dbca32
--- /dev/null
+++ b/snipmate/drupal6/php.snippets
@@ -0,0 +1,315 @@
+## Forms API
+
+snippet markup
+	$form['${1:/* form element */}'] = array(
+		'#value' => '<${2:div}>' . '${3:/* markup */}' . '</$2>',
+	);
+
+## Database functions
+
+snippet db_fetch_array
+	while ($${1:row} = db_fetch_array($result)) {
+		${2:// Your code here}
+	}
+
+snippet db_fetch_object
+	while ($${1:row} = db_fetch_object($result)) {
+		${2:// Your code here}
+	}
+
+snippet db_query
+	$result = db_query('${1:/* Query */}', ${2:/* Arguments */});
+
+snippet db_rewrite_sql
+	$result = db_query(db_rewrite_sql('${1:/* Query */}'), ${2:/* Arguments */});
+
+## drupal_ functions
+
+snippet drupal_add_css
+	drupal_add_css(${1:/* path */}, '${2:/* Type (optional) 'module' or 'theme' */}', '${3:/* Media (optional) e.g. 'all', 'print', or 'screen' */}', ${4:/* preprocess TRUE or FALSE */});
+
+snippet drupal_add_js
+	drupal_add_js(${1:/* Data */}, '${2:/* Type 'core', 'module', 'theme', 'inline' and 'setting' */}', '${3:/* Scope: header or footer */}', ${4:/* Defer TRUE or FALSE */}, ${5:/* Cache TRUE or FALSE*/}, ${6: /* Preprocess TRUE or FALSE */});
+
+snippet drupal_goto
+	drupal_goto('${1:path}', '${2:query}', '${3:anchor}', '${4:http_response_code}');
+
+## Everything else
+
+snippet t
+	t('${1:/* Your text */}', array(${2:/* arguments */}))
+
+## Hooks
+
+snippet hook_block
+	
+	/**
+	 * Implementation of hook_block()
+	 */
+	function `Filename()`_block($op = 'list', $delta = 0, $edit = array()) {
+		switch ($op) {
+			case 'list':
+				${1}
+				break;
+			case 'configure':
+				break;
+			case 'save':
+				break;
+			case 'view':
+				break;
+		}
+	}
+	
+
+snippet hook_comment
+	
+	/**
+	 * Implementation of hook_comment()
+	 */
+	function `Filename()`_comment(&$a1, $op) {
+		switch ($op) {
+			case "insert":
+				${1:// Your code here}
+				break;
+			case "update":
+				break;
+			case "view":
+				break;
+			case "validate":
+				break;
+			case "publish":
+				break;
+			case "unpublish":
+				break;
+			case "delete":
+				break;
+		}
+	}
+	
+
+snippet hook_node_type
+	
+	/**
+	 * Implementation of hook_node_type()
+	 */
+	function `Filename()`_node_type($op, $info) {
+		switch ($op) {
+			case 'delete':
+				${1:// Your code here.}
+				break;
+			case 'insert':
+				break;
+			case 'update':
+				break;
+		}
+	}
+	
+
+snippet hook_nodeapi
+	
+	/**
+	 * Implementation of hook_nodeapi()
+	 */
+	function `Filename()`_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
+		switch ($op) {
+			case 'alter':
+				${1:// Your code here.}
+				break;
+			case 'delete':
+				break;
+			case 'delete revision':
+				break;
+			case 'insert':
+				break;
+			case 'load':
+				break;
+			case 'prepare':
+				break;
+			case 'prepare translation':
+				break;
+			case 'print':
+				break;
+			case 'rss item':
+				break;
+			case 'search result':
+				break;
+			case 'presave':
+				break;
+			case 'update':
+				break;
+			case 'update index':
+				break;
+			case 'validate':
+				break;
+			case 'view':
+				break;
+		}
+	}
+	
+
+snippet hook_perm
+	
+	/**
+	 * Implementation of hook_perm()
+	 */
+	function `Filename()`_perm() {
+		return array('${1:/* permission */}');
+	}
+	
+
+snippet hook_requirements
+	/*
+	 * Implementation of hook_requirements()
+	 * @param string $phase
+	 *  The phase in which hook_requirements is run:
+	 *    'install': the module is being installed.
+	 *    'runtime': the runtime requirements are being checked and shown on the
+	 *      status report page.
+	 * @return
+	 *   A keyed array of requirements. Each requirement is itself an array with
+	 *     the following items:
+	 *       'title': the name of the requirement.
+	 *       'value': the current value (e.g. version, time, level, ...).
+	 *         During install phase, this should only be used for version
+	 *         numbers, do not set it if not applicable.
+	 *       'description': description of the requirement/status.
+	 *       'severity': the requirement's result/severity level, one of:
+	 *         REQUIREMENT_INFO: For info only.
+	 *         REQUIREMENT_OK: The requirement is satisfied.
+	 *         REQUIREMENT_WARNING: The requirement failed with a warning.
+	 *         REQUIREMENT_ERROR: The requirement failed with an error.
+	 *
+	 */
+	function `Filename()`_requirements($phase) {
+	  $requirements = array();
+	
+	  ${1:// Your code here.}
+	
+	  return $requirements;
+	}
+	
+
+snippet hook_schema
+	
+	/**
+	 * Implementation of hook_schema()
+	 */
+	function `Filename()`_schema() {
+		$schema['${1:table}'] = array(
+			'description' => '${2}',
+			'fields' => array(
+				'${3:column}' => array(
+					'description' => '${4}',
+					'type' => '${5}',
+					'unsigned' => ${6},
+					'not null' => ${7},
+				),
+			),
+			'indexes' => array(
+				${8}
+			),
+			'unique keys' => array(
+				${9}
+			),
+			'primary key' => array(${10}),
+		);
+		return $schema
+	}
+	
+
+snippet hook_taxonomy
+	
+	/**
+	 * Implementation of hook_taxonomy()
+	 */
+	function `Filename()`_taxonomy($op, $type, $array = NULL) {
+		switch ($op) {
+			case 'delete':
+				${1:// Your code here.}
+				break;
+			case 'insert':
+				break;
+			case 'update':
+				break;
+		}
+	}
+	
+
+snippet hook_update_N
+	/*
+	 * Implementation of hook_update_N().
+	 * @see http://api.drupal.org/api/drupal/developer--hooks--install.php/function/hook_update_N/6
+	 * @return array $ret
+	 *  An array with the results of the calls to update_sql().
+	 */
+	function `Filename()`_update_N(&$sandbox) {
+	  $ret = array();
+	
+	  ${1:// Your code here.}
+	
+	  return $ret;
+	}
+
+snippet hook_user
+	
+	/**
+	 * Implementation of hook_user()
+	 */
+	function `Filename()`_user($op, &$edit, &$account, $category = NULL) {
+		switch ($op) {
+			case 'after_update':
+				${1:// Your code here.}
+				break;
+			case 'categories':
+				break;
+			case 'delete':
+				break;
+			case 'form':
+				break;
+			case 'insert':
+				break;
+			case 'load':
+				break;
+			case 'login':
+				break;
+			case 'logout':
+				break;
+			case 'register':
+				break;
+			case 'submit':
+				break;
+			case 'update':
+				break;
+			case 'validate':
+				break;
+			case 'view':
+				break;
+		}
+	}
+	
+
+## Views hooks
+
+snippet hook_views_api
+	
+	/**
+	 * Implementation of hook_views_api()
+	 */
+	function `Filename()`_views_api() {
+		return array(
+			'api' => 2,
+			'path' => drupal_get_path('module', '`Filename()`') . '/views',
+		);
+	}
+	
+
+snippet hook_views_query_alter
+	
+	/**
+	 * Implementation of hook_views_query_alter()
+	 */
+	function `Filename()`_views_query_alter(&$view, &$query) {
+		${2:// Your code here.}
+	}
+	
+
diff --git a/snipmate/drupal7/php.snippets b/snipmate/drupal7/php.snippets
new file mode 100644
index 0000000..f10d173
--- /dev/null
+++ b/snipmate/drupal7/php.snippets
@@ -0,0 +1,225 @@
+## Forms API
+
+snippet markup
+	$form['${1:/* form element */}'] = array(
+		'#markup' => '<${2:div}>' . '${3:/* markup */}' . '</$2>',
+	);
+
+## Database functions
+
+snippet db_query
+	$result = db_query('${1:/* Query */}', ${2:/* Arguments */}, ${3:/* Options */});
+
+## drupal_ functions
+
+snippet drupal_add_css
+	drupal_add_css(${1:/* Data */}, '${2:/* Options */}');
+
+snippet drupal_add_js
+	drupal_add_js(${1:/* Data */}, '${2:/* Options */}');
+
+snippet drupal_goto
+	drupal_goto('${1:path}', '${2:options}', '${3:http_response_code}');
+
+## Hooks
+
+snippet hook_block
+	
+	/**
+	 * Implementation of hook_block_info()
+	 */
+	function `Filename()`_block_info() {
+	  ${1:// Your code here}
+	}
+	
+	/**
+	 * Implementation of hook_block_save()
+	 */
+	function `Filename()`_block_save() {
+	}
+	
+	/**
+	 * Implementation of hook_block_view()
+	 */
+	function `Filename()`_block_view() {
+	}
+	
+	/**
+	 * Implementation of hook_block_configure()
+	 */
+	function `Filename()`_block_configure() {
+	}
+	
+	/**
+	 * Implementation of hook_block_list_alter()
+	 */
+	function `Filename()`_block_list_alter() {
+	}
+	
+	/**
+	 * Implementation of hook_block_info_alter()
+	 */
+	function `Filename()`_block_info_alter() {
+	}
+	
+	/**
+	 * Implementation of hook_block_view_alter()
+	 */
+	function `Filename()`_block_view_alter() {
+	}
+	
+	/**
+	 * Implementation of hook_block_view_MODULE_DELTA_alter()
+	 */
+	function `Filename()`_block_view_MODULE_DELTA_alter() {
+	}
+	
+
+snippet hook_comment
+	
+	/**
+	 * Implementation of hook_comment_view()
+	 */
+	function `Filename()`_comment_view($comment, $view_mode, $langcode) {
+	  ${1:// Your code here}
+	}
+	
+	/**
+	 * Implementation of hook_comment_load()
+	 */
+	function `Filename()`_comment_load($comments) {
+	}
+	
+	/**
+	 * Implementation of hook_comment_update()
+	 */
+	function `Filename()`_comment_update($comment) {
+	}
+	
+	/**
+	 * Implementation of hook_comment_insert()
+	 */
+	function `Filename()`_comment_insert($comment) {
+	}
+	
+	/**
+	 * Implementation of hook_comment_delete()
+	 */
+	function `Filename()`_comment_delete($comment) {
+	}
+	
+	/**
+	 * Implementation of hook_comment_presave()
+	 */
+	function `Filename()`_comment_presave($comment) {
+	}
+	
+	/**
+	 * Implementation of hook_comment_publish()
+	 */
+	function `Filename()`_comment_publish($comment) {
+	}
+	
+	/**
+	 * Implementation of hook_comment_unpublish()
+	 */
+	function `Filename()`_comment_unpublish($comment) {
+	}
+	
+	/**
+	 * Implementation of hook_comment_view_alter()
+	 */
+	function `Filename()`_comment_view_alter(&$build) {
+	}
+	
+
+snippet hook_node_type
+	
+	/**
+	 * Implementation of hook_node_type_delete()
+	 */
+	function `Filename()`_node_type_delete($info) {
+	  ${1:// Your code here}
+	}
+	
+	/**
+	 * Implementation of hook_node_type_insert()
+	 */
+	function `Filename()`_node_type_insert($info) {
+	}
+	
+	/**
+	 * Implementation of hook_node_type_update()
+	 */
+	function `Filename()`_node_type_update($info) {
+	}
+	
+
+snippet hook_permission
+	
+	/**
+	 * Implementation of hook_permission()
+	 */
+	function `Filename()`_permission() {
+		return array('${1:/* permission */}' => array(
+	            'title' => t('${2}'),
+	            'description' => t('${3:/* optional */}'),
+	            'restrict access' => t('${4:/* optional */}'),
+	            'warning' => t('${5:/* optional */}'),
+	          ));
+	}
+	
+
+snippet hook_requirements
+	/*
+	 * Implementation of hook_requirements()
+	 * @param string $phase
+	 *  The phase in which hook_requirements is run:
+	 *    'install': the module is being installed.
+	 *    'update': the module is enabled and update.php is run.
+	 *    'runtime': the runtime requirements are being checked and shown on the
+	 *      status report page.
+	 * @return
+	 *   A keyed array of requirements. Each requirement is itself an array with
+	 *     the following items:
+	 *       'title': the name of the requirement.
+	 *       'value': the current value (e.g. version, time, level, ...).
+	 *         During install phase, this should only be used for version
+	 *         numbers, do not set it if not applicable.
+	 *       'description': description of the requirement/status.
+	 *       'severity': the requirement's result/severity level, one of:
+	 *         REQUIREMENT_INFO: For info only.
+	 *         REQUIREMENT_OK: The requirement is satisfied.
+	 *         REQUIREMENT_WARNING: The requirement failed with a warning.
+	 *         REQUIREMENT_ERROR: The requirement failed with an error.
+	 *
+	 */
+	function `Filename()`_requirements($phase) {
+	  $requirements = array();
+	
+	  ${1:// Your code here.}
+	
+	  return $requirements;
+	}
+	
+
+snippet hook_update_N
+	/*
+	 * Implementation of hook_update_N().
+	 * @see http://api.drupal.org/api/drupal/modules--system--system.api.php/function/hook_update_N/7
+	 * @return array $ret
+	 *  An array with the results of the calls to update_sql().
+	 */
+	function `Filename()`_update_N(&$sandbox) {
+	  $ret = array();
+	
+	  ${1:// Your code here.}
+	
+	  return $ret;
+	}
+
+## Everything else
+
+snippet t
+	t('${1:/* Your text */}', array(${1:/* arguments */}), array(${2:/* options */}))
+
