Drupal 7 Custom Module Development
Illustration by John Hersey

Creating a block


Drupal 7 Custom Module Development

with Jon Peck

Start your free trial now, and begin learning software, business and creative skills—anytime, anywhere—with video instruction from recognized industry experts.

Start Your Free Trial Now

Video: Creating a block

A Drupal block is an area which displays content whose position is controlled by the theme and administrative block settings. I'm going to programmatically create a block that shows a map of wind farms that are within 100 miles of the center specified. To help us some of the computation I'm going to leverage a library that is within the location module. There is no need to actually enable the location module to do this, but it does need to be there. Open windfarms.module and scroll to the end. Two functions are needed to generate a block and I will use a third to keep the code tidy.
please wait ...
Watch the Online Video Course Drupal 7 Custom Module Development
2h 57m Advanced Oct 16, 2012

Viewers: in countries Watching now:

Extend your Drupal 7 sites with custom modules, which allow you to create everything from admin interfaces to forms. Author Jon Peck describes how modules extend your base Drupal installation, then walks through how to write your own module with a practical example featuring geo-positioned alternative energy centers. The course also describes how to control access to site features, create new content types, build forms, understand data persistence, embrace coding standards, and much more.

Topics include:
  • Creating your first module
  • Interacting with hooks
  • Working with permissions and roles
  • Controlling access
  • Adding a menu item to an admin interface
  • Using the Form API (FAPI) to quickly create a form
  • Creating custom form validation
  • Manually creating a custom content type
  • Validating user input
  • Importing content using feeds
  • Creating a block
  • Understanding best practices and coding standards
Developer Web
Jon Peck

Creating a block

A Drupal block is an area which displays content whose position is controlled by the theme and administrative block settings. I'm going to programmatically create a block that shows a map of wind farms that are within 100 miles of the center specified. To help us some of the computation I'm going to leverage a library that is within the location module. There is no need to actually enable the location module to do this, but it does need to be there. Open windfarms.module and scroll to the end. Two functions are needed to generate a block and I will use a third to keep the code tidy.

The first function that's needed is an implementation of hook_block_info. By implementing this hook, I can declare to Drupal that a block with a particular machine name and human readable administrative name exists. Start with a docblock, Implements hook_block_info. Hook_block_info requires no parameters and returns a nested array, function windfarms_block_info, blocks = array.

Hook_block_info requires no parameters and returns a nested array. The array is keyed by the delta value of the block which is a fancy way of saying the machine name. Block names are unique to the module, so you don't have to worry about collisions. I'll create a block with the delta of gmap, blocks gmap is equal to an array. For each delta, define an array containing one key named info. This will contain a translated string of the administrative name for the block.

This is shown on the block admin interface and nowhere else. I'm setting the info to Wind Farm Map. Finally, return the blocks array. Next, I'm going to implement hook_block_view which returns the rendered contents of a block as an array with the two elements: the subject which is the localized title and the content. The content can either be a string or a renderable array which is similar to the farms, start with the docblock.

Implements hook_block_view, hook_block_view takes one parameter, function windfarms_block_view takes one parameter, the delta of the block in question defaulting to an empty string. As it returns an array, create a variable named block, initialized with an empty array and then switch on the delta, switch ($delta) and then a case for gmap.

The localized subject is displayed at the top of the block and can be overridden using the Drupal admin interface. If no title is needed, the subject is still required but it can be set to null. This case I'm going to set the $block 'subject' to the translated string Wind Farm Map. To keep things neat, I will generate the content of the block by calling a custom function that just returns renderable content and doesn't implement any hook, $block 'content' = windfarm_block_contents, and the ($delta).

After the end of the switch block return the block. The final function remains, windfarm_block_contents. I'll create the function first, function windfarm_block _contents, that takes one parameter the ($delta) and then I'll add the docblock, Wind Farm Block contents for the description, a parameter string the $delta, which is The block ID.

Then return a string containing the HTML output. Initialize the output, then switch on the ($delta) and add a case for gmap. As mentioned before, I will be using a library within the location module to handle some of the computations required. While I could theoretically copy and paste the functions, this causes several problems.

First, copying and pasting makes it look like I wrote the functions which I didn't. Second, the library can be updated and the enhancements would not be reflected in my code, and third, by mixing context the code structure can get concluded leading to what is referred to as Spaghetti code, where the logic is a big sloppy mess. I'm going to use module_load_include again, specifying include in the location module, in particular the earth file.

The function I'll be using operates in meters, so I'll convert the distance 100 miles into meters. 100 miles, $distance_meters = 100 * 1609.34. Next, I'll determine the range of the latitude and longitude from the default center. This is a simplified version of a proximity search which looks in a square, rather than a radius around a point. Why simplify? For two reasons, first it's fast and it has enough precision for an intention grabber.

And second, this course is about programming modules not geo-positioning calculations. Determine the range of lat and long from the default center. I'll use the default center latitude and longitude from the variables set from the admin interface, $lat = variable_get ( 'windfarms_default_center_lat'). I'll copy and paste and set that to long, and long.

Next I'll calculate the range using the Earth Library. So the $range_lat = earth_latitude_range, takes the long and lat and the distance will be actually distance_meters. I will do the same for the longitude with earth_longitude_range. Now that I know where I'll be looking it's time to build the query. While the last time I needed nodes I used DB query, but this time DB query isn't appropriate.

Drupal 7 introduced the EntityFieldQuery API which allows for queries of entities such as nodes to be built efficiently, avoiding the need to know the complete internals of every generated table and column. This API is used in an object oriented manner rather than procedural. To start, create a new entity field query object. Build_query then $query = new EntityFieldQuery.

Context is needed and to filter the query I will use what are known as conditions. In the end, these conditions will result in where statements with joints as necessary. The method entity condition adds a condition on entity generic metadata such as the entity type, bundle, revision ID or entity ID. Entity conditions take two required parameters, the name of what you want to filter and the value that you are filtering on. A third parameter, the operators such as equals, less than, and so forth, is optional and defaults to equals.

I want to only return nodes, which is in the entity type, so Only_show_nodes. So $query takes entityCondition, the name is entity_type and the value is node. Next, I will filter further and only show the bundle windfarm. Only_show_windfarms, $query-> entityCondition, the name is bundle, and the value is windfarm.

Now that I've filtered down to the node of content type windfarm, it's time to find only wind farms within the latitude and longitude range that I calculated earlier. To do so I will use the method fieldCondition. Similar to entityCondition, the first parameter is the name of what I want to filter on, which in this case is the field's windfarm latitude. The second parameter is the column that I want to filter on. Similar to when I was displaying the map the value of the latitude is stored in latitude.

Following the column is the value where the comparison will be made too. I will be checking to see if the latitude is within a range, so I will pass it the array containing that range. If I was filtering on a single value then I could just pass that value rather than putting it in array. Finally the optional operator, as I'm checking a range I will use the keyword between, Only show latitude between range, query fieldCondition, which takes the field windfarm latitude, then that value $range_lat and then the keyword between.

The longitude fieldCondition is constructed in a very similar manner, so I'll copy and paste, Only show longitude between the range and the windfarm_longitude, it will take the $range_long. Now that the query has been built, I can execute the query by calling the method execute. Execute query, so $result = $query->execute.

Following execution an array of associative arrays of stub entities will be returned, keyed by the entity type on the outside and relevant entity ID on the inside. Check to see if there are any nodes, if not, return an empty string. No results, if isset result keyed by the entity type, which in this case is node, then return the empty string. If there are nodes then load them all.

To do that, I will use node load multiple, which takes an array of node IDs and returns an array of node objects, $nodes = node_load_multiple. I'll use the array_keys of result node. Now that I have all the nodes for the windfarms that match, I can build the Google map using gmap 3D tools, same as the theme I will use module_ load_include to load the include file gmap3_tools.

Then create an empty array of markers, $markers = empty array, foreach nodes as node get the latitude and longitude, so the $lat = $node->windfarm_ latitude, LANGUAGE_NONE, 0 and then the key of 'value' and the long which is windfarm_longitude.

If either the latitude or longitude are missing, skip the entry. While it's highly unlikely, zero latitude and zero longitude is a legitimate coordinate. Cannot render map without both. If $lat == empty string or $long == empty string, continue.

If it passed validation get the facility name which is the node title $facility_name = check_plain($node_title). Then get the description, $description = check_plain($node-> body, LANGUAGE_NONE, index 0, and the 'value'. I'm going to add a link to the node. While it may be tempting to write a straight anchor tag in HTML, Drupal provides a clean mechanism for inserting links that integrates with a menu routing system.

The function is just L for link. This means that you can just pass a raw path for a node, and if you have an alias path defined for the node, the L function will convert it transparently. L takes three parameters, but only the first two are required. First, the text of the link for the anchor tag, then the internal path being linked to. Add a link to the node. $description concatenate equals a space followed by the L function, the first part is the label or info followed by the path node which is node/ and then the node ID.

Finally, create the marker and add it to the array. Add to markers, $markers, I'm going to append gmap3_tools_create_marker with a latitude, the longitude, the title is the $facility_ name and the description is the $description. When the markers are created, I will call gmap3_tools add map again, but this time the options will be a little different. Create map with all the markers, gmap3_tools_add_map with an array.

Instead of a dynamic mapID just specify gmap-canvas-block. The satellite view will be just fine for the map options, mapOptions set to an array and the mapTypeID set to GMAP3_ TOOLS_MAP_TYPE_ ID_SATELLITE. Instead of defining the marker in line, just pass the markers array.

So markers set to $markers. I will use a different option for the default markers position which will automatically zoom to encompass all the markers on the map. So gmap3ToolsOptions set to array, defaultMarkersPosition which is set to GMAP3_TOOLS_DEFAULT_MARKERS_POSITION_CENTER_ZOOM.

Finally, the only HTML that will actually be returned by the block function is the HTML container for the map. Set the ID to the same thing as the map ID above, so $output = 'div id="gmap-canvas-block". The style is the width 500 pixels and a height of 400, and close the div. Then end the switch statement, then at the end return the $output.

Save then return to the browser. Now that the block has been completely defined enable it in the admin interface. Go to Structure then Blocks. At the bottom, in disabled, Wind Farm Map is now shown. For the REGION set it to Content. Then arrange the content so Wind Farm Map is shown first, click Save blocks. The block will be shown on every page above the content which is a little disconcerting if you're looking at a wind farm or another node.

Therefore set it only show on the front page. Click configure, only on the listed pages and , click Save block, go to the homepage. The Wind Farm Map is now displayed on the front page using a block populated by the database using entity field query. In this chapter, I've created a feed importer that creates wind farms from a CSV, added a Google map by integrating with another module and theming, then created a block that contains a map filled with the results of the geographic search of the custom content.

At this point, the base functionality of the module is complete. The next question, where to go from here?

Find answers to the most frequently asked questions about Drupal 7 Custom Module Development .

Expand all | Collapse all
please wait ...
Q: gmap3_tools is not working the way I expected it to. What version of gmap3_tools should I be using?
A: Use the free exercise file containing the version of gmap3_tools used for recording; the published version of the module on drupal.org has changed since recording and is not backwards compatible.
Q: I attempted to run the Drupal site root from the project files, but the site isn't loading. Why not?
A: The Drupal configuration file in sites/default/settings.php contains database configuration specific to the environment used to record the movie. This may be different than your environment. Edit the file and search for "windfarms" - you may need to change the database host, username, password, db name and port to match your specific environment.
Share a link to this course

What are exercise files?

Exercise files are the same files the author uses in the course. Save time by downloading the author's files instead of setting up your own files, and learn by following along with the instructor.

Can I take this course without the exercise files?

Yes! If you decide you would like the exercise files later, you can upgrade to a premium account any time.

Become a member Download sample files See plans and pricing

Please wait... please wait ...
Upgrade to get access to exercise files.

Exercise files video

How to use exercise files.

Learn by watching, listening, and doing, Exercise files are the same files the author uses in the course, so you can download them and follow along Premium memberships include access to all exercise files in the library.

Exercise files

Exercise files video

How to use exercise files.

For additional information on downloading and using exercise files, watch our instructional video or read the instructions in the FAQ .

This course includes free exercise files, so you can practice while you watch the course. To access all the exercise files in our library, become a Premium Member.

* Estimated file size

Are you sure you want to mark all the videos in this course as unwatched?

This will not affect your course history, your reports, or your certificates of completion for this course.

Mark all as unwatched Cancel


You have completed Drupal 7 Custom Module Development.

Return to your organization's learning portal to continue training, or close this page.

Become a member to add this course to a playlist

Join today and get unlimited access to the entire library of video courses—and create as many playlists as you like.

Get started

Already a member ?

Exercise files

Learn by watching, listening, and doing! Exercise files are the same files the author uses in the course, so you can download them and follow along. Exercise files are available with all Premium memberships. Learn more

Get started

Already a Premium member?

Exercise files video

How to use exercise files.

Ask a question

Thanks for contacting us.
You’ll hear from our Customer Service team within 24 hours.

Please enter the text shown below:

The classic layout automatically defaults to the latest Flash Player.

To choose a different player, hold the cursor over your name at the top right of any lynda.com page and choose Site preferences from the dropdown menu.

Continue to classic layout Stay on new layout
Exercise files

Access exercise files from a button right under the course name.

Mark videos as unwatched

Remove icons showing you already watched videos if you want to start over.

Control your viewing experience

Make the video wide, narrow, full-screen, or pop the player out of the page into its own window.

Interactive transcripts

Click on text in the transcript to jump to that spot in the video. As the video plays, the relevant spot in the transcript will be highlighted.

Learn more, save more. Upgrade today!

Get our Annual Premium Membership at our best savings yet.

Upgrade to our Annual Premium Membership today and get even more value from your lynda.com subscription:

“In a way, I feel like you are rooting for me. Like you are really invested in my experience, and want me to get as much out of these courses as possible this is the best place to start on your journey to learning new material.”— Nadine H.

Thanks for signing up.

We’ll send you a confirmation email shortly.

Sign up and receive emails about lynda.com and our online training library:

Here’s our privacy policy with more details about how we handle your information.

Keep up with news, tips, and latest courses with emails from lynda.com.

Sign up and receive emails about lynda.com and our online training library:

Here’s our privacy policy with more details about how we handle your information.

submit Lightbox submit clicked
Terms and conditions of use

We've updated our terms and conditions (now called terms of service).Go
Review and accept our updated terms of service.