Jul 25 2014
Jul 25

I needed to do some custom validation of fields on a form. So, I decided to use #element_validate. One of the fields I was validating appeared a bit strange to me, though. When I displayed its $form_state['values']['field_face_palm'] information I saw that it looked like:

$field_face_palm['und'] = 'you_knucklehead'

instead of like:

$field_face_palm['und'][0]['value'] = 'you_knucklehead'

Well, I figured that's just the way it was. I couldn't imagine why Drupal would be formatting the information differently, but I couldn't change it. So, I wrote and tested my code on my local development environment and pushed it up to the public test environment.

The validation did not work properly on the public test environment. To start debugging, I once again displayed the field information. This time it did correspond to the usual pattern.

I was completely stumped as to what was different between the two environments and figured that the error must be on my local environment. So, I was going to need to do more experimentation in my local environment.

In the process of testing different things, I used a $form['#validate'] and noticed that in that validation function the field was also formatted as I would have expected. So, the field was getting formatted properly at some point.

I guess I need to come clean at this point. Even though I was using element validation, I was comparing one element to others in some of the validation functions, as opposed to looking only at the element that was being validated. My issue was that the element in question had not yet been fully formatted when I was inside a different element validator function.

I still don't have an answer of why the element was fully formatted in the public test environment but not in my local development environment. I was using Features, which should guarantee that the content types were defined in exactly the same way. Nonetheless, it makes sense that one shouldn't make any assumptions about the state of any other fields when inside the validation function for a particular field. The proper approach for the situation in which one field needs to be compared to another is to use a form validation function.

May 30 2014
May 30

I was having trouble getting a feature to enable correctly. It wasn't creating all the fields for the content type it defined. It built some of the fields but not others. I was pretty certain that it was working fine on other sites. But, I couldn't imagine what was different about the environment in which I was having trouble. I finally found the culprit when I took a closer look at my directory structure.

Since I was grabbing code from a different environment that should have had a more recent version of the features I needed (and I didn't have version control in use in my test environment), I decided to rename the directory that held all my features before I pulled in the new version of the directory. For example, let's assume that I was working with code in sites/all/modules/custom/my_features_directory. Instead of doing a rm -r my_features_directory I did a mv my_features_directory my_features_directory_backup. Then I did a cp -r some/other/path/my_features_directory .. Can you see where my problem arose?

The issue is that even though I changed the name of the directory, all the modules (features) that were inside of the renamed directory still had the same name. I now had my_features_directory_backup/somesubmodule/somesubmodule.module as well as my_features_directory/somesubmodule/somesubmodule.module. So, when Drupal scanned for the modules (features) it found the older version(s) inside of the backup directory.

Remember: Drupal doesn't really care what you name your directories. It scans through them all looking for your .info and .module files. You aren't really "hiding" anything by renaming a directory. You aren't any safer if you move the directory somewhere else within the sites/all structure, either. Drupal follows this same directory scanning approach for a number of other things as well. So, the same lesson applies: You need to move things entirely out of your Drupal root structure.

As far as whether I should have been using version control, that's a topic for a different post.

May 01 2014
May 01

I was writing custom forms that needed a validate handler and a submit handler. So, I followed the standard approach of

  function my_module_menu(){
    $items = array();
    $items['my/module/custom-form'] = array(
      'title' => 'I am a doofus',
      'page callback' => 'drupal_get_form',
      'page arguments' => array('my_module_custom_form'),
      'access callback' => TRUE,
      'type' => MENU_CALLBACK,
    );
    return $items;
  }

Note: My access callback is just to simplify this example.

  function my_module_custom_form($form, &$form_state) {
    $form = array();
    $form['stuff'] = array(
      '#type' => 'item',
      '#markup' => t('I am a doofus'),
    );
    $form['actions'] = array(
      '#type' => 'actions',
    );
    $form['actions']['submit'] = array(
      '#type' => 'button',
      '#value' => t('Just shoot me!'),
    );
    return $form;
  }

Note: This is using Drupal 7 conventions, but the issue is the same in Drupal 6. I have written the code with the error in it. Can you see the error?

  function my_module_custom_form_validate($form, &$form_state) {
    // some validation here
    drupal_set_message(__FUNCTION__);
  }

Note: I had placed the drupal_set_message to help me figure out what was being called and what wasn't. The _validate function was being called.

  function my_module_custom_form_submit($form, &$form_state) {
    drupal_set_message(__FUNCTION__);
    drupal_goto();
  }

Note: I was not seeing the drupal_set_message for the _submit nor was the drupal_goto happening.

As noted above, I was seeing the drupal_set_message for the _validate function when I clicked the submit "button." So why wasn't my _submit handler being called? It's not like this is the first time I have ever used the FAPI. Nor is it the first time I had written _validate and _submit handlers.

Have you figured out what my mistake was, yet?

My problem was that I had used '#type' => 'button' instead of '#type' => 'submit' for my submit "button!"

Dec 23 2013
Dec 23

What's that feature: the #attributes key.

Perhaps you have written your own javascript code to determine that an empty textfield does not have focus, and in such a situation place some placeholder text in the field. If you are using the FAPI there is an easier way. You can do this:

$form['my_textfield'] = array(
  '#type' => 'textfield',
  '#attributes' => array(
    'placeholder' => t('My placeholder text'),
  ),
);

Take note that this is telling Drupal to use the placeholder="My placeholder text" attribute for the textfield. The placeholder attribute is an HTML5 attribute. Keep this in mind when considering what browsers will be accessing your site and whether it's important for all visitors to see the placeholder text.

You can tell Drupal to use any (valid) HTML attributes with this technique.

This really-easy-to-use feature was one that I had forgotten about. So, I figured others may have forgotten about it as well. I hope you enjoy it!

Nov 22 2013
Nov 22

What's that File (layout)?

There are many different ways to figure out what information the node table contains.

  1. You could use dsm($node); in an appropriate place in your code, assuming you have the Devel module installed.
  2. You could also use a poor man's version of dsm, a la drupal_set_message('
    ' . print_r($node, 1) . '
    ');
    .
  3. You might think to take a look at the Node template file.
  4. On the other hand, you might ssh into a server and do something like mysql -u someuser --database=somedatabase -p followed by DESC node. Some of you might even have done drush sqlc instead of entering the mysql sequence.

But, most of those options would require you to leave your browser. And maybe the node.tpl.php doesn't quite make things clear for you. How about looking at the code that defines the table?

Some of you may be saying, "But then I'd still have to go out to a terminal and do a drush dl drupal." Alas, there is another way to approach looking at code, that I use quite regularly. I'll walk you through the steps for this particular example.

  1. Navigate to the project page.
  2. Look in the right sidebar and click on the View commits link.
  3. Click on any of the commit ids
  4. Strip out part of the path to take you to the project git repo. Of course, if you remember the pattern [I never do], you can just go directly to the repo without all those extra clicks.
  5. Scroll down the page to the section that says "heads."
  6. Choose one of the heads and click on the tree link.
  7. Next click on the modules link.
  8. Select node.
  9. Open up node.install and look at function node_schema().

While this post focused strictly on finding out the schema for the node table, the technique could be used to find out anything about what a project is doing, without having to leave your browser. In addition, it makes mention of a lot of other handy tools.

You may be wondering:

  • "What is this devel module and what is dsm?"
  • "What is drupal_set_message and what if I can't interrupt the program flow to print a message to the screen at that time?"
  • "What is the Node template file and when would I use it?"
  • "What is this drush sqlc and drush dl?"

All of those questions make for more blog posts!

If you'd like to read a post on one of those topics, or on some other topic, register an account (sorry commenting is still disabled for anonymous visitors) and leave a comment or shoot me a message through my contact form.

Thanks to Chris Miller for suggesting that I write this post.

Nov 15 2013
Nov 15

What's that Feature?

When your code executes a variable_get what actually happens is that Drupal inspects the $conf global array variable to see if it contains an index with the variable name. It does NOT actually query the variable table.

The global variable is built from cached data. So, if you were having problems with $conf not containing the value that you verified was in the variable table, you could reasonably assume that you could fix the issue by making sure that you cleared caches to force it to be rebuilt. But, what if it STILL did not contain the value that's in the variable table?

Well, there is (at least) one other place where the $conf variable can be set: settings.php. Setting the variable in settings.php takes precedence over whatever is in the database.

So, the next time you can't seem to get the $conf variable to contain the value that you think it should contain, have a look through settings.php and see if it's being explicitly set there.

Thanks to Adrian Rollett for helping me out with this vexing problem when I simply could NOT figure out what was going on.

Edit: The Installation Guide contains a page that lists variables that can be set using the $conf array.

Apr 04 2013
Apr 04

I was writing an extremely simple custom module (for a D6 site) to make use of hook_block. Every time I enabled the module the blocks no longer displayed on the pages. Since it had been a long time since I had done any work in D6, I figured there must be something I was overlooking in how I wrote the function. If I disabled the module (or even just commented out the hook_block) function then the blocks reappeared. So, I spent a fair amount of time looking over how I had written the hook. But, I couldn't see anything wrong with it.

Next, I tried the usual fix-all of clearing cache. In fact, I cleared it two times in a row just to be sure. I also looked for any entries in error logs, including the watchdog file and the server error logs, and didn't find anything.

In the process of testing, I re-enabled the module and uncommented the function and things seemed to just start working again. I thought to myself, "Must be gremlins in the server." (Actually, I typed it out in the IRC channel.) But, the site was apparently working again, so I went on my way. Naturally, the problem cropped up again.

Since it seemed to be a sporadic error, I thought that it must be related to something with the server setup. So, I tested whether increasing the memory_limit or max_execution_time had any effect to no avail. Out of desperation I thought about just changing the name of the custom module, and a light finally went on! I realized that I had named the custom module the same thing as the custom theme. So, the situation was that I had /sites/mysite/themes/mycustomname/mycustomname.info as well as /sites/all/modules/custom/mycustomname/mycustomname.info and /sites/all/modules/custom/mycustomname/mycustomname.module. This lead to the function being named function mycustomname_block($op = 'list', $delta = 0, $edit = array()).

Once I renamed the module everything worked just as expected. I haven't investigated where in the process things broke between the module and the theme layer. The theme is a sub-theme of Omega and there is an empty preprocess-block.inc file in the /sites/all/themes/omega/preprocess directory. But, there is no implementation of hook_preprocess_block in the template.php for the custom theme or the base theme.

So, the moral of the story is: Whenever you are working on a site make sure that your theme names and your module names are distinct.

Mar 06 2013
Mar 06

There are some times in Drupal 6 where you push the limits of what the blocks interface can do. If you need to display the same block, multiple times on the same page, you will start to see these limitations. An example of where this is useful is a Newsletter signup form. Sometimes a client may want a newsletter signup form to be in the footer of every page, but also displayed more prominently on the contact form page.

You will also run into this issue if you want to output a block in one region on one page and another region on a separate page. An example of this would be to display the newsletter signup form in the header on the front page, but in the footer on every other page of the site.

Both of these examples can easily be achieved using something like Panels or Display Suite, but if you want to stick to the blocks interface, here is a simple way you can solve this by building a custom Drupal 6 module.

The first step is to create a simple Drupal 6 module. After you have the module created, we need to create our own Drupal 6 block. Drop the following code in your .module file. You will need to replace the module name with the name of your module. You will also need to look through the other code replacing text and descriptions as necessary. In my example I will be going through creating a second block for the Drupal 6 Constant Contact module.

/**
 * Implements hook_block().
 */
function MYMODULE_block($op = 'list', $delta = 0, $edit = array()) {
  if ($op == 'list') {
    $blocks[0] = array('info' => t('Constant Contact Block 2'));
 
    return $blocks;
  }
  else if ($op == 'view') {
    switch ($delta) {
      case 0:
        // Your module will need to define this function to render the block.
        $block = array(
          'subject' => t('Title of block #1'), 
          'content' => '',
        );
        break;
    }
    return $block;
  }
}

The next step is to identify the block you want to display. The best way to do this is to figure out which module you need to duplicate the block for. In my example this was the Constant Contact module. Open up the .module file for whichever module you want to duplicate the block for.

Once you have the module file opened, do a search for "_block" or "hook_block". This should get us to the function that has all the details you need to insert the line of code that will print this block. We need to get the module name and the delta value for our block. Here is an example from the constant_contact.module file's hook_block implementation.

/**
 * Enables us to place a signup form into a block
 */
function constant_contact_block($op = 'view', $delta = 0, $edit = array())
{
	switch($op) {
		case 'list':
			$blocks[0] = array(
				'info' => t('Constant Contact Signup Form'),
				'visibility'      => 0,
				'roles'      => array(1),
				'pages'      => 'user*',
			);
		return $blocks;
		case 'configure':
			$form = array();
		return;
		case 'save':
		return;
		case 'view':
			switch ($delta) {
				case 0:
					$block['subject'] = t('Signup');
					$block['content'] = drupal_get_form('constant_contact_signup_form');
				break;
			}
		return $block;
	}
}

I can pull out the module name from the function constant_contact_block and get that "constant_contact" is the module name. You can also take this from whatever is in front of the .module in the constant_contact.module file name.

The next step is to pull out the delta value for the block. This is displayed below the switch ($delta) { line of code. In this "case" we want the number "0". This is pulled from the case 0: line of code. Blocks may have multiple of these case statements, you will need to find the right delta value for the block you want to display. Many times in a Drupal 6 hook_block implementation this will simply be 0.

We now add the following line of code to our modules hook_block function.

$block = module_invoke('MYMODULE', 'block', 'view', [DELTA]);

We replace MyMODULE with the module name, in this case "constant_contact" and we replace [DELTA] with the delta value, in this case 0. Here is what the finished line of code looks like:

$block = module_invoke('constant_contact', 'block', 'view', 0);

You then need to replace this line of code with what would normally be your Drupal 6 block output code. The final version of your Drupal block code should look something like this:

/**
 * Implements hook_block().
 */
function MYMODULE_tweaks_block($op = 'list', $delta = 0, $edit = array()) {
  if ($op == 'list') {
    $blocks[0] = array('info' => t('Constant Contact Block 2'));
 
    return $blocks;
  }
  else if ($op == 'view') {
    switch ($delta) {
      case 0:
        $block = module_invoke('constant_contact', 'block', 'view', 0);
        break;
    }
    return $block;
  }
}

You can now add this block just like you would any other block. It should be an exact duplicate of the other Drupal block.

A couple notes: This approach still has it's limitations so a better solution is using something like Panels or Display Suite. However it works well for one off simple fixes on sites that are already making heavy use of blocks. Also note that if you are displaying the same block multiple times on the same page, everything should work fine, but your CSS may not validate if the block uses the same CSS ID since it will now be in multiple places inside the HTML.

Hope that helps and let me know if you have any questions.

Dec 12 2012
Dec 12

Have you ever ran into a problem where you needed to upload relatively large files and still want to be able to manage these from the Drupal 7 administrative interface? If so, you may run into a situation like the one below:

You will notice the 12 MB text stating that we can only upload files that are 12 MB and under. In this case I needed this number to be a little bigger.

In order to do this you will need to modify your PHP settings in your php.ini file.

Note: You should make sure you know what you are doing and understand the consequences of increasing this number. In my case this is on a site that only users that I trust will be uploading files. If you allow any user to upload files, increasing this number can add an increased load on the server and possible eat up your disk space pretty quickly.

Now that you have been warned, here is how I was able to do this. I first found the php.ini file on my system. I am on an Ubuntu server so I was able to get to edit mine using vim like so:


vim /etc/php5/apache2/php.ini

Change the upload_max_filesize setting

The first step was to find the upload_max_filesize setting from 12MB to 30MB.

Change:

To:

Change the post_max_size setting

You may also need to modify the post_max_size setting. I changed the post_max_size php.ini setting from 20MB to 30MB.

Change:

To:

Restart Apache

You will then need to restart or reload apache so the changes take effect. I simply restarted apache using the following command:


service apache2 restart

After that I simply refreshed the page on my Drupal 7 site to see:

Pretty simple! I hope it helps you if you need to increase the max file size of a Drupal 7 file upload field.

Dec 05 2012
Dec 05

The code is essentially the same, but requires just a minor change. If you want to hide the page title on only the front page of your Drupal 7 website, add the following code to your themes template.php file (replacing THEMENAME with the name of your theme):

function THEMENAME_preprocess_page(&$vars) {
  if ($vars['is_front']) {
    $vars['title'] = '';
  }
}

If you want to hide the page title for specific node types on your Drupal 7 website, add the following code to your template.php file (replacing THEMENAME with the name of your theme, and changing NODETYPE1 and NODETYPE2 to your node types):

function THEMENAME_preprocess_page(&$vars) {
  if (!empty($vars['node']) && in_array($vars['node']->type, array('NODETYPE1', 'NODETYPE2'))) {
    $vars['title'] = '';
  }
}

You can obviously combine the two of these to hide page titles on a specific node type and on the front page of a Drupal 7 website using this code:

function THEMENAME_preprocess_page(&$vars) {
  if ($vars['is_front']) {
    $vars['title'] = '';
  }
  elseif (!empty($vars['node']) && in_array($vars['node']->type, array('NODETYPE1', 'NODETYPE2'))) {
    $vars['title'] = '';
  }
}

Pretty simple, but will hopefully provide a good reference for those looking to hide the page title on a Drupal 7 site.

Oct 19 2012
Oct 19

Working with queries in an abstracted manner (like the new D7 database abstraction layer) can be tricky. Even working in D6 with functions like db_placeholders() or db_rewrite_sql() can start to make your head spin. For those of us who want to see the *actual* query sent to MySQL (or whichever database backend you're using), here is a handy snippet of code. When the Devel module is enabled, you can add the following lines to your settings.php file:

// Devel Configuration
$conf['dev_query'] = TRUE;

Note that this must be in the proper part of the file. The $conf array is used to override variables normally set via the UI, which are typically stored in the database in the "variable" table.

Now that Devel's query-logging feature is enabled, every database query -- the *actual* query itself, not the abstracted PDO syntax (Read more) -- is temporarily stored in a global variable $queries.

You can print out the latest query using the following snippet:

global $queries;
$query = array_pop($queries);
dd($query, 'descriptive text about the query being printed out -- this one is logged to /tmp/drupal_debug.txt');
dpm($query, 'descriptive text about the query being printed out -- this one is printed to the screen');

I've primarily used this in D6 development, although I'm fairly sure it works the same in D7. Insert this snippet immediately after the query you're wanting to see the raw version of.

You know the common Drupalism, "Don't hack core!" Well... during development it is *encouraged* to hack core, if it helps you debug a situation or understand better what's going on in a system. Just make sure to remove your hacks when you grok what's happening. With this technique you can get down to the most fundamental raw queries themselves... Hack away!

Oct 12 2012
Oct 12

Note: Turns out there is a much easier way to do this as there is an Ubercart function that does essentially the same thing (thanks to the comment below that pointed this out). Just use:

uc_product_is_product($node);

I left the original post below (although it is no longer really needed).

I have seemed to run into the issue of trying to determine if a specific Drupal 6 node is an Ubercart product content type a few too many times. There are many ways to verify this from checking the Drupal database in the uc_products table, to looking at the Drupal node object for a sell_price attribute (or other Ubercart attribute), etc. Here is the way that seems to work the best for me and that I will be using from here on out.

I have put this in a Drupal 6 hook_nodeapi implementation to try to demonstrate a practical Drupal example:

/**
 * Implements hook_nodeapi().
 */
function MYMODULE_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  //print('<pre>'.print_r($node,1).'</pre>');
  if ($op == 'view') {
    // Check if this is a product node.
    $node_types = uc_product_types();
    if (in_array($node->type, $node_types)) {
      // Do something with the product.
    }
  }
}

Overall it is pretty easy, but just wanted to get this put up somewhere to not only help others, but to also help myself the next time I run into this situation. Any questions or comments? If so, let me know if the comments below.

Sep 19 2012
Sep 19

While we were working on one of our upcoming projects, a new website for Stichting tegen Kanker, we had to integrate the Apache Solr module. We needed Solr for its faceted search capabilities. In combination with the FacetAPI module, which allows you to easily configure a block or a pane with facet links, we created a page displaying search results containing contact type content and a facets block on the left hand side to narrow down those results.

One of the struggles with FacetAPI are the URLs of the individual facets. While Drupal turns the ugly GET 'q' parameter into a clean URLs, FacetAPI just concatenates any extra query parameters which leads to Real Ugly Paths. The FacetAPI Pretty Paths module tries to change that by rewriting those into human friendly URLs.

Our challenge involved altering the paths generated by the facets, but with a slight twist.

Due to the projects architecture, we were forced to replace the full view mode of a node of the bundle type "contact" with a single search result based on the nid of the visited node. This was a cheap way to avoid duplicating functionality and wasting precious time. We used the CTools custom page manager to take over the node/% page and added a variant which is triggered by a selection rule based on the bundle type. The variant itself doesn't use the panels renderer but redirects the visitor to the Solr page passing the nid as an extra argument with the URL. This resulted in a path like this: /contacts?contact=1234.

With this snippet, the contact query parameter is passed to Solr which yields the exact result we need.

  1. /**
  2.  * Implements hook_apachesolr_query_alter().
  3.  */
  4. function myproject_apachesolr_query_alter($query) {
  5. if (!empty($_GET['contact'])) {
  6. $query->addFilter('entity_id', $_GET['contact']);
  7. }
  8. }

The result page with our single search result still contains facets in a sidebar. Moreover, the URLs of those facets looked like this: /contacts?contact=1234&f[0]=im_field_myfield..... Now we faced a new problem. The ?contact=1234 part was conflicting with the rest of the search query. This resulted in an empty result page, whenever our single search result, node 1234, didn't match with the rest of the search query! So, we had to alter the paths of the individual facets, to make them look like this: /contacts?f[0]=im_field_myfield.

This is how I approached the problem.

If you look carefully in the API documentation, you won't find any hooks that allow you to directly alter the URLs of the facets. Gutting the FacetAPI module is quite daunting. I started looking for undocumented hooks, but quickly abandoned that approach. Then, I realized that FacetAPI Pretty Paths actually does what we wanted: alter the paths of the facets to make them look, well, pretty! I just had to figure out how it worked and emulate its behaviour in our own module.

Turns out that most of the facet generating functionality is contained in a set of adaptable, loosely coupled, extensible classes registered as CTools plugin handlers. Great! This means that I just had to find the relevant class and override those methods with our custom logic while extending.

Facet URLs are generated by classes extending the abstract FacetapiUrlProcessor class. The FacetapiUrlProcessorStandard extends and implements the base class and already does all of the heavy lifting, so I decided to take it from there. I just had to create a new class, implement the right methods and register it as a plugin. In the folder of my custom module, I created a new folder plugins/facetapi containing a new file called url_processor_myproject.inc. This is my class:

  1. <?php
  2.  
  3. /**
  4.  * @file
  5.  * A custom URL processor for cancer.
  6.  */
  7.  
  8. /**
  9.  * Extension of FacetapiUrlProcessor.
  10.  */
  11. class FacetapiUrlProcessorMyProject extends FacetapiUrlProcessorStandard {
  12.  
  13. /**
  14.   * Overrides FacetapiUrlProcessorStandard::normalizeParams().
  15.   *
  16.   * Strips the "q" and "page" variables from the params array.
  17.   * Custom: Strips the 'contact' variable from the params array too
  18.   */
  19. public function normalizeParams(array $params, $filter_key = 'f') {
  20. return drupal_get_query_parameters($params, array('q', 'page', 'contact'));
  21. }
  22.  
  23. }

I registered my new URL Processor by implementing hook_facetapi_url_processors in the myproject.module file.

  1. /**
  2.  * Implements hook_facetapi_url_processors().
  3.  */
  4. function myproject_facetapi_url_processors() {
  5. return array(
  6. 'myproject' => array(
  7. 'handler' => array(
  8. 'label' => t('MyProject'),
  9. 'class' => 'FacetapiUrlProcessorMyProject',
  10. ),
  11. ),
  12. );
  13. }

I also included the .inc file in the myproject.info file:

  1. files[] = plugins/facetapi/url_processor_myproject.inc

Now I had a new registered URL Processor handler. But I still needed to hook it up with the correct Solr searcher on which the FacetAPI relies to generate facets. hook_facetapi_searcher_info_alter allows you to override the searcher definition and tell the searcher to use your new custom URL processor rather than the standard URL processor. This is the implementation in myproject.module:

  1. /**
  2.  * Implements hook_facetapi_search_info().
  3.  */
  4. function myproject_facetapi_searcher_info_alter(array &$searcher_info) {
  5. foreach ($searcher_info as &$info) {
  6. $info['url processor'] = 'myproject';
  7. }
  8. }

After clearing the cache, the correct path was generated per facet. Great! Of course, the paths still don't look pretty and contain those way too visible and way too ugly query parameters. We could enable the FacetAPI Pretty Path module, but by implementing our own URL processor, FacetAPI Pretty Paths will cause a conflict since the searcher uses either one or the other class. Not both. One way to solve this problem would be to extend the FacetapiUrlProcessorPrettyPaths class, since it is derived from the same FacetapiUrlProcessorStandard base class, and override its normalizeParams() method.

But that's another story.

Aug 17 2012
Aug 17

Everyone has their favorite text editors. For my first few years as a professional developer I used Textmate, not even realizing its more advanced features. When I started at OpenSourcery, peer pressure got me using Vim, which is actually great, since it's on 99% of the web servers I work with.

Just recently, however, I began using Sublime 2, which is actually more of an IDE, since it offers tons of advanced features and allows you to manage an entire project rather than managing just a single file at a time. This brings me to my first tip I use *all the time*:

command-p

(Linux users may need to use a different key like control.)
This brings up a list of files in the current project. Let's say you want to edit settings.php. Run this command then type "set" -- instantly, settings.php shows up at the top of the list. Hit enter and voila! You're editing settings.php.

command-shift-p

This brings up a list of available commands. Handy if you don't want to use the mouse, and it piggy-backs onto all the other add-ons you've installed, providing short-cuts to all sorts of commands.

Package Manager

This is my favorite part of Sublime, which is not actually part of the program out of the box. Like many Linux distributions out there have "package managers," Sublime has one too. Check it out!

command-k command-b

I think this is the first program I've seen that combines two keystrokes, but it's definitely useful. This will show or hide the sidebar that shows the project's file structure.

Vim Emulation

Sublime comes with a Vim emulation "vintage mode" out of the box. Just enable it! Here's some documentation. Mac users, pay attention to the "OS X Lion" section here. Key repeats are part of the "Vim experience," IMHO. Also, try out the VintageEx package.

Drupal auto-completion

Now that you have the package manager installed, type command-shift-p to bring up the list of commands, then type "pac" and the package manager commands will appear. Select "Package control: Install package". Let it work a bit, then start typing "Drupal" -- WOW! Sublime has a few packages just for Drupal development! Drupal Project Autocomplete is one.

Drupal code snippets

Like the previous tip, this is another package. Pretty great!

Goto Drupal API

Again, install this using the package manager. I don't use this command all that much, because of my Chrome search shortcuts, but it does work well and it's quick. Double-click a core function in any of your project files to select it, type shift-command-p to bring up the list of commands, then type "go" and hit enter. Your browser opens right to the documentation page at api.drupal.org! Awesome!

INI syntax highlighting

"INI" is yet another package useful to Drupal developers. Install it! Then, open any module's .info file. Next go to "View >> Syntax >> Open all with current extension as… >> INI"
This also works with .make files.

PO file syntax highlighting

command-d

This is one of the classics. I believe it's demonstrated on the Sublime 2 front page.

More…

Yes, there's much, much more. Some things I'm trying out, but haven't quite figured out include Ctags support, which provides the ability to click on a function and jump to where that function is defined. Also, an Xdebug interface is available, although I haven't quite gotten this configured yet. Next on the list is DrupalCS support, which should allow you to check the code in any given file against Drupal's coding standards.

If these short-cuts sound good to you, do yourself a favor and start out your free trial of Sublime 2, available for Mac, Linux and Windows! Test it out, and buy when you're ready!

Aug 03 2012
Aug 03

Git is great! Git is essential if you want to be a contributor to Drupal. Use it to work on a project, even without being connected to the internet. Make commits, merge branches, roll patches. Take the time to learn its very powerful features. Then use these tips to speed up your life! For example, why would you choose to type three characters when you can type one? Or, why type nine when you can type three?

Enter aliases…

Did you know about shell aliases? I have one in my ~/.profile (akin to a ~/.bashrc file for Linux users):

alias g='git '

This means I can type "g" and it really means "git".

Just like shell aliases, Git has its own form of aliases. There are commands you can type in the terminal to make configurations, but I find it easier to edit the ~/.gitconfig file directly. Begin the listing of aliases with [alias], then follow with a list of aliases, one per line. I use the following time-saving aliases in my .gitconfig file, picked up from various sources around the web:

[alias]
  s = status
  l = log --graph --pretty=format:'%C(yellow)%h%C(cyan)%d%Creset %s %C(white)- %an, %ar%Creset'
  ll = log --stat --abbrev-commit
  d = diff
  co = checkout
  a = add
  ap = add -p
  patch = format-patch --stdout HEAD~1
  rpatch = reset --hard HEAD~1

Interestingly enough, using the "g" bash alias in conjunction with an alias like "l" that might also have a bash alias defined results in a conflict. I don't know what to do about that. Oh, well. The "patch" and "rpatch" aliases are some of my favorite. Let's say I modified a contrib module and made a commit on it locally. (Just one commit.) I want to submit this commit as a patch to the module's issue queue. In the module's root directory, I type "g patch > /tmp/issue_description-1234567-4.patch". This takes the diff between the latest commit and the project before that, and formats a patch, which also includes authorship information! Next, I type "git rpatch". This removes all trace of the last commit (the one I made), so it now matches the way it still looks on drupal.org.

Git branch name in command prompt

See my post a few weeks ago about showing the Drush site alias in the command prompt. This also works with the current Git branch as well. I believe Adam's dotfiles repo has an implementation of this.

MOD stands for module

In the ~/.gitconfig file, add this:

[url "git+ssh://[email protected]/project/"]
  insteadOf = mod:

Now, when you type "git checkout mod:views" it clones views into your current directory, down from drupal.org. No need to visit the project page and hunt for the git cloning info. Make sure to replace the "jessehs" part with your drupal.org git username.
Jul 27 2012
Jul 27

For awhile now, Chrome has been my browser of choice for web development. It's fast, elegant and customizable. Over the years, there have been some great tricks and customizations that save time, make things easier, and even more pretty.

Chrome Custom Search

Chrome has the ability to set up a custom "search engine" so that by typing a few letters in the address bar, you can perform a search at the address that you configure. Set this up by clicking the wrench in the upper right, choosing "Settings" and then clicking the "manage search engines" button. I've got several of these set up:

  • "mod" (short for module) allows me to search through all modules on drupal.org. The actual configuration in Chrome is "http://drupal.org/project/%s", where %s stands for the module name.
  • "api" searches the drupal 7 api site: "http://api.drupal.org/api/search/7/%s"
  • "api6" searches the drupal 6 api: "http://api.drupal.org/api/search/6/%s"
  • "fapi6" Drupal 6 Form API reference. The %s part of this adds a link id to the end of the url: "http://api.drupal.org/api/drupal/developer!topics!forms_api_reference.ht..."
  • "apic" searches drupalcontrib.org for (D7) contrib modules' functions: "http://drupalcontrib.org/apis/%s"

    Chrome CSS customizations

    Call me shallow, but I like cool colors on my laptop. I use the Molokai color scheme in my vim editor. I just like the way it looks. And since I'm inspecting things all the time using Chrome's Element Inspector, might as well make that look cool, too, right? Check this out! Very chic.

    While we're at it, move those pesky checkboxes next to each css attribute/value pair over to the left, like Firebug does. Add this to Chrome's Custom.css file (I'm actually not sure whether this has been fixed in Chrome proper -- I added it over a year and a half ago):

    .styles-section .properties .enabled-button {
    position: absolute !important;
    left: 5px;
    margin: 2px 0 0 0 !important;
    }

    Lorem ipsum toolbar button

    Anonymous browsing

    Use the Browse anonymously window to test the site as an anonymous user. A lot of times, I use Firefox, Safari or Opera as well as Chrome to test out a site from multiple users' perspectives. Each browser stores its own cookies, so I can be logged in as 4 different users at the same time. This is handy when running through workflow processes that require multiple user roles, like moderation of comments or posts. But if you just want to check something out as an anonymous user really quick, it's as easy as Shift-Command-N to pop open an anonymous window. Or right-click a link and choose "Open link in incognito window". Bam! Anonymous!

    Dreditor

    This isn't exactly a "Chrome" thing, but all you Drupalistas and Drupaleros need to know about it! Check it out NOW!

    Thanks for reading. Next week I think I'll move on to Git.

  • Jul 20 2012
    Jul 20

    I've been a developer at OpenSourcery for over a year and a half now. Working with a team of developers in the office has definitely expanded my skills, and exposed me to tons of tips and shortcuts that I probably wouldn't have heard about otherwise. I wanted to compile these in a public way to get the word out! Pick out some useful ones and get it set up... a few minutes now will save you tons of time down the road, especially for those who spend hours at the command line every day. I've compiled these from many sources around the web. These are just the commands I find myself using a lot.

    The post here assumes you've at least heard of Drush. If not, read up.

    Drush

  • Site aliases - these are invaluable. When you set up a new project, add an alias that points to the drupal document root. These aliases live in your home directory in the .drush folder in a file called aliases.drushrc.php. Read up on it here.
  • Display the currently active site alias in the command prompt - This is very handy. I've pulled stuff from msonnabaum's and adamdicarlo's dotfiles to get some great status info in my command line prompt, including the currently active drush alias, as well as the currently active git branch. The sicle and hammer is pretty great in Mark's, too. I put a sun in mine (۞).
  • Drush conf - this is a great little utility, especially combined with the aforementioned Drush aliases. Let's say I want to bring up the settings.php file for any given site running on my laptop. I type "drush use @mysite" to set the drush alias. Then I type "drush conf" which prompts me to select from a list of configuration files for that site, including settings.php, .htaccess. It also can be used to edit your php.ini file or aliases.drushrc.php file.
  • One-time login links - use the command "drush uli [username]" to get a one-time login link for that user account. You can then paste it into your browser and surf the site as that user. This is great for Q/A, or reproducing an issue that's only reported by certain people, without having to reset their password.

    Well... I was going to cover a lot more here, but it's time to go home! I promise, I'll continue with some more blog posts in future weeks. Topics yet to cover: Git, Chrome, Terminal, Shell aliases, SSH aliases, DrupalCS, Vim and Sublime2

  • Jun 29 2012
    Jun 29

    I got annoyed by the mess on my laptop. Three years hence, its' hard disk has turned into an archive of stuff I've been working at some point or another. The vast majority ranges from fully fledged projects we maintain to half borked vanilla Drupal installations I once used to demo something to fully fledged. Over time, I changed employer a time or two and did some freelance stints. Each time, I had to adapt to new conventions, configurations, versioning tools and development setups.

    In the end, the thing I *didn't* do well was managing my own development environment. I'm not talking about the technology I'm using (as it happens: I'm on a OSX using MAMP) but the way, or lack of, I kept order in the data I manage. Inevitably, you're development environment gets cluttered over time. If you're not very careful, you'll end up with stale databases, different versions of files, directories and dumps with no specific purpose, cryptic leftover configuration files,... In short: chaos. Why? There's only so much time, and at the end of the day, it's very easy to just wing it rather then clean up abandoned local projects. That's what happened to me.

    So, I set forth to think how to improve this for myself. I've started using a set of common conventions each time I set up a new project. Most of them I picked up at Krimson. I decided to share them, here it goes:

    Filesystem

    • Create a Workspace folder i.e. /home/you/workspace. All PHP files, applications, DB dumps,... should be stored here.
    • Group each project in it's own folder. i.e. /home/you/workspace/myproject. Of course, you might work for different clients or employers. Just prefix your folders: i.e. colada_project and krimson_project.
    • Each project has four basic subfolders: www/ which contains your document root, db/ which contains database dumps, docs/ which contains your development information (notes,...) and patches/ with specific drupal patches you might need when setting up that project.

     

    Webserver

    • Use virtual hosts. No exceptions. Putting each project in a subfolder of the documentroot so you can surf to http://localhost/myproject is bad practice since such setups require extra configuration in .htaccess. When you go live, you might end up doing mucking in your .htaccess. Or worse, discovering you have to change hardcoded URL's in your code if you were really careless!
    • Use a comprehensive local domainname. You could go for "myproject.dev" or "myproject.lan". I use "netsensei.myproject" for extra clarity. The first part could also refer to the hostname of my machine.
    • Each vhosts comes with its' own vconf file. In my MAMP, I have a separate folder called sites/ which contains a vhost configuration per project.
    • Each configuration file is called netsensei.myproject.conf.
    • Use a working template file for your configuration. Just copy and paste and alter when need to do so (you shouldn't on your own machine unless really needed!) This way, you'll avoid having to debug your configuration for the gazillionth time i.e. because the path to your logfiles contains an error.
    • Same goes for your /etc/hosts file: keep it clean! I try to keep all the entries alphabetically ordered so I can easily find an entry in the list.

    Of course, you don't have to work with /etc/hosts and configuration files. You could also do a one time setup of a local BIND DNS server and let Apache do the heavy lifting for you. Check out this article on how to set up a smarter MAMP.

    Database

    As a Drupal dev, I'm 99.9% of the time working with a MySQL setup. But these should serve for any db system really...

    • Never, ever use the root user to connect to your database from your project. Not even on your development machine. Why? It's a bad habit and mistakes are easily made. Moreover, if something goes really wrong, you don't want other projects to get messed up too.
    • Use the same name for your database as for your user. Ie. DEV_MYPROJECT. Each user only has privileges granted to that database.
    • Be consistent in how you name your user and database: always go for uppercase or lowercase. But don't intermingle. Keep things clear and simple.
    • I use the DEV_ prefix on my local machine. Why? When my PHPMyAdmin tool is open, I want to be pretty sure that's not a production database I just dropped.

     

    Drush

    You didn't install Drush? Shame! You should! Drush Makes developer life a breeze!

    • Use Drush aliases for every project you start! An alias file allows you to load and bootstrap Drupal from the command line from every location.
    • Each file is called netsensei.myproject.alias.drushrc.php

    Those are a few conventions we try to live by. Of course, most of this is sheer repetition after a while. To avoid errors, we wanted to automate the process of setting up a project. A few years back, we worked with a set of shell scripts to get the job done. Over time, we converted our scripts to Drush commands. We couldn't share them because they were very Krimson specific, locked in our own workflow. A few months back, we started using Git. Integrating support in our tools turned out to be quite the hack. So I ventured out and created my own Drush toolset called Rum. It does two things:

    Setting up a new local project starting from a vanilla Drupal core setup or setting up an existing project from a remote repository (Git or Subversion) honoring the above conventions.

    Rum allows you to delete the entire project including the vhost configuration setup, database and reference in the host file.

    This is strictly a aid for use in a development environment. Of course, this is just one way of doing things. These might be the right tool when you're working on your own but turn out to be contraproductive on an enterprise level where individual developers many more variables to take into account. There are other ways of setting up development environments which allow you to easily and safely sync. I highly recommend looking at Vagrant which allows you to rapidly setup and tear down custom tailored virtualized development environments per project. I would also recommend taking a look into the realm of DevOps, which is a fairly young field aiming to tear down the wall between developers and system operators, lowering the bar for deployment, maintenance, security,... in terms of efficiency and flexibility.

    I presented Rum and my own setup as a BoF session at DrupalCampGent 2012 on May 26th. I've put my slides on Slideshare (Dutch)

    Apr 20 2012
    Apr 20

    In a previous article, we already gave you a sneak peek of the upcoming changes for Display Suite. More than two months later and a lot of coding, the new branch is ready to start testing. In this article we'll highlight the biggest changes.

    Menu structure and discoverability

    The main task of Display Suite is simple: configuring the display of your content. For new users, it took a while before they understood how they could get that 2 column layout on their basic page because of two major problems:

    • The main menu entry point at admin/structure/ds leads you to another overview screen with, depending on other settings and/or enabled modules, new options. The main task, namely configuring that layout, was not even the first one. And it was cryptically named as ‘layout’.
    • On the “Manage display” screen, the vertical tab on the default view mode, which usually is the first one you click on, underneath the table wasn’t visible enough to give users the hint that they should choose a layout before the magic starts.

    So we completely changed the menu structure for this. Clicking on Display Suite now leads directly to the overview of all available displays, with the most important one, namely, all content types available in your current Drupal website. Other functionality like fields and view modes have been converted to a menu tab.

    Besides that, the layout tab is now always the first with some new enhancements as well.

    Previews and default fields

    Nothing feels better to actually know how your template looks like. In the past, the only way to for site builders to get a bit of a hint, was reading the descriptions in the select box carefully. Or worse, switching over and over until they found the exact layout they want. From now on, selecting a layout will show you a preview image of how the structure looks like. Ajax, oh, we love you. Changing a layout will also show you the previous and next state, so you can’t miss anymore. And it gets better: from now on, when first selecting a layout, default fields will be inserted into the first known region. Imagine you have already configured formatter settings of an image and the body: you will not lose them anymore after selecting a layout.

    Configurable wrappers per layout

    In Display Suite 7.x.1.x layouts and regions were traditionally wrapped inside a div. It was possible to choose a different wrapper for regions and the layout inside a template. This has several drawbacks.

    • You have to create your own custom templates in code
    • Each sets of wrappers needs a custom template.

    To overcome this problem we decided to make the wrappers configurable in the user interface. This increases the flexibility of the layouts a lot. At this moment we support the following wrappers:

    • div
    • span
    • section
    • article
    • header
    • footer
    • aside

    Sometimes a group of fields listed in a region doesn't belong to the same wrapper. You can group a set of fields inside one region with fieldgroup. As of today there is an HTML5 formatter for fieldgroup that provides the same HTML5 wrappers we added to Display Suite.

    All these changes turn Display Suite into a flexible HTML5 layout builder. To make this possible we had to add more php code to the templates. But as a bonus, they now work on both display and form. If you want to create your own custom template it is advised to use the built in drush script.

    1. $ drush ds-build "Two regions" --regions="Region 1, Region 2"
    2. $ drush ds-build "Several regions and css" --css=1

    Hide empty regions

    We have removed the 'Hide empty region' checkbox. Instead, we ship with fluid and non fluid templates. The logic now happens inside the template to print or hide a region with or without content in it. This may seem dramatic, but it's actually a better way of working. Choose your layouts wisely now when configuring a display.

    Field template settings

    One of the hardest coding parts for this branch was moving the field template settings, an option in the Extras module, into the cogwheel on the right, instead of a link triggering a fake formatting screen. This benefits both frontend and backend performance, since we do not print all field template form elements for every field on the manage display screen. It’s now only loaded when configuring a single field. The 'expert' field template now has full control over the field template including (default) classes and attributes.

    There are still some tiny problems with this conversion, but the basic functionality is working fine.

    Alter before you print

    While the layouts in combination of fields gives you great flexibility to decide which content should be printed, there are still use cases where you do want to override a configured layout just before it's sent out to the template file. This was impossible in DS 1, but we now introduced hook_ds_pre_render_alter so you can make any changes you have to. Add new fields, switch them in regions, add new regions .. you name it, it's all possible now.

    Upgrade path

    With all the changes we listed so far, we have decided to not support an upgrade path between both branches. It’s not that we want too, it's simply because we know for sure sites will break, especially with the changes on template level. We don't want you to reconfigure your site together. Both branches are still supported, however, new features will only go into the second branch. So for existing sites, keep using the first branch. For every new site, you can start using the second one - or wait at least for an official release.

    Call for testers and coders

    We expect to roll out at least one release candidate at the beginning of june and a full release at the end of june, maybe somewhere just after the Drupal Dev Days in Barcelona. We will test this ourselves extensively the next coming weeks, but we invite you to test along with us and report any bugs you might find. Patches are always better of course. There are 2 critical issues remaining in the queue which need special attention from both site builders and theme developers.

    • http://drupal.org/node/1536066: due to the changes in the template system, we still need to decide how themes, like the Mothership, should provide layouts that can work for both versions of Display Suite.
    • http://drupal.org/node/1519916: the cogwheel needs some fixes to not print out summaries for fields that aren’t allowed to use the field templates, e.g. preprocess fields. Consequently, the field template options can not be available either, but for some the label should remain.

    Screencast

    We have plenty other subtle changes and a couple of new features. A full overview is available at http://drupal.org/node/1524800. However, a screencast is always better than words, so we recorded one for your viewing pleasure. Sit tight, grab some coffee and enjoy watching. The screencast is also embedded at the end of the post.

    Thanks to all who helped

    Usually, I don’t get so melodramatic, but sometimes thanking people can be fun, so here goes. I’d like to thank Bram "aspilicious" Goffings for accepting an internship at Krimson working almost full time during that period to get these changes rolling. He's also co-author of this post. Bojhan and Yoroy, our UX gatekeepers who assisted us in the issue queue with great screenshots, sketches and layouts. Pfrenssen, mrfelton and frega helping us out during the 3 days Easter Display Suite sprint. And last, but not least, Krimson for trusting me and jyve that this was worth doing. Maybe another last one: to all those 20K+ installations using our software. The steadily growth and feedback from everyone out there is what keeps me motivated to make this as good as possible!

    We’re excited, we hope you will be as well!

    Jun 29 2011
    Jun 29

    There are many times when you will be developing a module that you will need to confirm an action. An example might include before deleting a piece of content, or changing the status of something. Here is a very simple example of how to create a confirmation form in a Drupal 6 module.

    /**
     * Implements hook_menu().
     */
    function MYMODULE_menu() {
      $items = array();
      $items['MYMODULE/do-something'] = array(
        'type' => MENU_CALLBACK,
        'access arguments' => array('access content'),
        'page callback' => 'drupal_get_form',
        'page arguments' => array('MYMODULE_confirm_form'),
      );
     
      return $items;
    }
     
    /**
     * Confirm form example
     */
    function MYMODULE_confirm_form($form_state) {
     
      //you can pass variables here if need be
      $form['_my_var'] = array(
        '#type' => 'value',
        '#value' => 'MY Variable',
      );
     
      //you can set a redirect if needed
      $form['#redirect'] = 'user';
     
      return confirm_form($form,
        t('Are you sure you want to do something?'), //message title
        isset($_GET['destination']) ? $_GET['destination'] : 'user', //redirect if cancelled
        t('Only say yes if you are really sure.'), //message description
        t('Lets Do it!'), //confirm button text
        t('Cancel') //cancel button text
      );
    }
     
    /**
     * Submit handler for confirm form
     */
    function MYMODULE_confirm_form_submit($form, &$form_state) {
    	//verify that the form was confirmed
      if ($form_state['values']['confirm']) {
        //Do something here
     
        //set a message
        drupal_set_message('You did something!');
     
      }
    }

    You can do much more than this such as pass variables for user id's or node id's in the URL (through hook_menu). Hopefully this very simple example will get you started though. Its always good to make sure your users are confident in their actions before letting them do something dangerous.

    Cheers!

    Jun 27 2011
    Jun 27

    Here are two ways to get a list of users in Drupal 6. The first is to get a list of users in a specific role.

    $sql = "SELECT u.uid, u.name FROM {users} u
       INNER JOIN {users_roles} ur ON u.uid = ur.uid
       WHERE ur.rid = %d";
     
    //replace the 3 with whatever role id you are looking for
    $results = db_query($sql, 3);
     
    while ($result = db_fetch_object($results)) {
       //do whatever you need to with the results
     }

    However, it is often better to just create a new permission and give this permission to the correct roles. You can create a new permission in your module very easily (something like this):

    /**
      * Implements hook_perm().
      */
    function MYMODULE_perm() {
      //you can name this permission whatever you want and can create multiple permissions
      //by adding additional elements to the returned array
      return array(
        'MYMODULE permission',
      );
    }

    Now you can simply give this permission to the necessary role(s) and use this code to get a list of all the correct users:

    $sql = "SELECT u.uid, u.name FROM users u
      INNER JOIN users_roles ur ON u.uid = ur.uid
      INNER JOIN permission p ON ur.rid = p.rid
      WHERE p.perm like '%%%s%%'";
    $results = db_query($sql, 'MYMODULE permission');
     
    while ($result = db_fetch_object($results)) {
      //print('<pre>'.print_r($result,1).'</pre>');
      //do whatever you need to
    }

    Now lets do a quick summary of the two options. The first option is the slightly better performing of the two, however it is very inflexible. In order to change which users are selected by the query, the code would need to change. The second option performs slightly worse, but is much more flexible. The second option allows you to change which roles to select from the permissions page.

    I would say if you are building a very large site, you might want to stick with the first option as you will undoubtedly want as much of your configuration in code as possible. If you are building a small to medium sized site and plan to use the administration interface frequently, the second option may provide much needed flexibility.

    Jun 27 2011
    Jun 27

    Ran into a situation earlier today where I needed to validate a Drupal username and email address entered into a custom form that would create a Drupal 6 User account (see http://codekarate.com/content/create-user-account-drupal-6-programmatically for more information on the submit handler of the form). There are easy to use Drupal functions to validate the username and email addresses. See the examples below:

    //check if this is a valid Drupal username
    user_validate_name('USERNAME');
     
    //check if this is a valid email address
    user_validate_mail('[email protected]');

    These two functions helped a lot in my validation handler and hopefully they can help you.

    Jun 16 2011
    Jun 16

    Here is a quick issue I ran into earlier today that I wanted to share. This one will be short and sweet.

    Lets say you want to create a block in a module that will only ever be on a users profile page, or perhaps you have another situation where you are adding some code for display on a users profile page. If you are trying to get the user object of the currently viewed user, here is a quick way to do it.

    $user = menu_get_object('user_uid_optional');

    If you look on drupal.org it may lead you to believe that using "user" as the first parameter will work, however this is a bug. You can see more information at http://drupal.org/node/595818, but suffice it to say this is the easiest way that I have found to get the user object for the user that is being viewed (i.e. you are visiting another users profile). Thanks to heyrocker on drupal.org for pointing this out in the menu_get_object comments.

    Jan 25 2011
    tom
    Jan 25

    Here at krimson, we are working on our own super-duper start-theme. (Who's not, right?)
    In that quest for our holy grail, I did find some interesting tips and tricks I want to share.

    You've certainly heard about HTML5, and the new semantics this provides us.
    If you haven't, have a look at the magnificent keynote from Jeremy Keith at Drupalcon Copenhagen, called 'The design of HTML5'.

    At one brave day, I started to build a drupal theme, based on those new HTML5 elements.
    Very soon, a problem became clear: older browsers don't support those new semantic tags.

    The HTML5 boilerplate solves this by using modernizr, a javascript library to detect a browsers support for HTML elements.
    On top of that, it also provides a way to make older browsers use elements like header, section, etc.

    A quote from the modernizr website:

    "Modernizr also adds support for styling and printing HTML5 elements. This allows you to use more semantic, forward-looking elements such as section, header and dialog without having to worry about them not working in Internet Explorer."

    With the help of some clever javascript, modernizr creates those new elements in browsers that don't support them. Let's look at the technique used here:

    1. (function(){

    2. if (!/*@[email protected]*/0) return;

    3. var e = "abbr,article,aside,audio,bb,canvas,datagrid,datalist,details,dialog,eventsource,figure,footer,header,hgroup,mark,menu,meter,nav,output,progress,section,time,video".split(','),i=e.length;

    4. while (i--) {document.createElement(e[i])}})()

    So here all elements are created by javascript, and when you actually use them in your CSS selectors, everything will work .... Until you turn off javascript!
    This is where problems arise. Some statistics show that about 5% of all browsers don't have javascript capabilities or it is simple turned off.
    Do we (or our clients) need to decide if we simply ignore those users? Should we wait until everyone is migrated to more modern browsers?

    The million dollar question....
    I personally don't like that idea. I think we should work with the tools that are available on this actual moment.
    When this is just about HTML5 semantics like header, footer, nav, section, article, etc, we simply can use some simple tricks so we can still use them in our markup.
    But first of all, why do we want them in our markup?

    Does it give us any advantage at all? Why bother?

    Its all about adding some extra semantic richness to your document. This is good for the accessibility of your document.
    Screen readers know exactly what the navigation is, and what the main article is, so in theory this could replace the 'skip to content' anchors as an example.

    Another advantage of using HTML5 semantics is for search engines optimization, or SEO for friends.
    You can define more clearly which is which, and what is what in your documents, and this all tastes like sweet apple pie for search engines.

    Enough ranting, let's look at a small trick, so you can start using those semantics without letting down those older browsers without HTML5 support and javascript turned off.

    1. <header>

    2. <div class="header">

    3. <h1>Page Title</h1>

    4. <h2>Page Subtitle</h2>

    5. </div>

    6. </header>

    7. <article>

    8. <div class="article">

    9. <header>

    10. <h1>Article Title</h1>

    11. </header>

    12. <section class="main">

    13. <div class="main">

    14. Article goes here...

    15. </div>

    16. </section>

    17. </div>

    18. </article>

    And a CSS example:

    1. div.header {

    2. color: #000;

    3. }

    4. div.article h1 {

    5. color: #fff;

    6. }

    You see, the point is to create a child div for each HTML5 element, and we use those div's in our CSS selectors.
    Now if we create some CSS for our markup, we don't use any HTML5 element in our selectors, but we use the child divs.
    This way we can get the best of both worlds. We can start using those new semantics, and we have full browser compatibility.
    At least the new semantics won't be the show stopper.

    Any disadvantages?

    Nothing is without any cost. Disadvantage of working with child divs is that you create extra, unnecessary markup.
    But I think most drupal themers can cope with that. :)

    Other ideas

    If you know a better/other way to achieve the same, please shoot.

    Jan 01 2011
    tom
    Jan 01

    Are you already using Eclipse as your IDE for drupal module development?
    If so, meet the 'Eclipse Drupal hook templates'. A XML file to import in your editor, including all drupal hooks.

    Here's how Eclipse templates work:

    1. Type the name of the hook, here 'hook_perm'.

    2. Now press CTRL-space, the hook name will be replaced with the complete hook template.

    Interested? Download the Eclipse templates XML file at the Drupal project page.

    Using some other IDE or text editor?

    Eclipse is not the only IDE getting all this fun. Here are three other popular solutions having support for hook templates like Eclipse:

    Netbeans provides this feature using a plugin.
    Textmate provides support via the Drupal bundle.
    For Panic's Coda, you can get some snippets.

    Written byTom Behets

    Coming from the world of Sound, his interest for Drupal drove him to drop the 'engineering' for 'development' and he is now known as Tom, Drupal Developer next to being a fresh Linux fanatic. He can also always be found on IRC. In the most sinister days of his past he whored himself out to the dark side as a mercenary of spam... watch those inboxes! Plans on becoming an astronaut.

    About Drupal Sun

    Drupal Sun is an Evolving Web project. It allows you to:

    • Do full-text search on all the articles in Drupal Planet (thanks to Apache Solr)
    • Facet based on tags, author, or feed
    • Flip through articles quickly (with j/k or arrow keys) to find what you're interested in
    • View the entire article text inline, or in the context of the site where it was created

    See the blog post at Evolving Web

    Evolving Web