In this Lullabot Module Monday lesson we walk through the useful Menu Position module. It's a word that can strike fear into the heart of the bravest site builder: Breadcrumbs. Manage them well, and you'll give visitors a helpful visual indicator of where they're at in your site. Miss a detail, and the weird inconsistencies will be more confusing than no breadcrumbs at all. The challenges stem from Drupal's "flat hierarchy" -- by default, almost all pages (including every node you create) live just beneath the home page itself in an undifferentiated pool of content. All of the visual cues it sends to visitors (breadcrumb trails, highlighted parent items in the navigation menus, and so on) start with that assumption until you override them. That's where the Menu Position module helps out. It lets you set up simple rules that tell Drupal where each node type should go in the site's hierarchy, then handles all of the frustrating details automatically.
Additional resources
In this Lullabot Module Monday article, we learn about the Mass Password Reset module. It's a question we all ask ourselves: What would I do if my site or server was compromised? Security professionals have loads of checklists to follow, and experienced server administrators drill for those moments. As we saw when Twitter.com was compromised by hackers, "Reset everyone's passwords, right away!" is almost always one of the important steps. If you run a Drupal site, that particular step can be frustrating. Resetting user passwords one by one is incredibly time consuming, and there's no way to do it for everyone in one fell swoop. At least, there wasn't until the release of the Mass Password Reset module.
Additional resources
In this Lullabot Module Monday lesson, we take a look at the Style Guide module. Comparing Drupal themes is tough: the screenshots they provide are often based on heavily tweaked sites with plenty of slider blocks, tweaked media attachments, and other just-so content. Figuring out the "basics" — how a given theme styles core HTML elements and recurring Drupal interface patterns — can be tough! Fortunately, the Style Guide module can help.
Additional resources
In this Lullabot Module Monday lesson we are introduced to the Publish Button module. It's a simple problem, but a serious one. You've put your content editors in front of Drupal for the first time, and they can understand the node form without any problems. They understand taxonomy terms, grok menus and node references… but they get nervous when it's time to save their work. "Will... will this be published as soon as I click 'save?'" Normally, there's no good way to make the distinction between saving and publishing a piece of content explicit. Site builders can set a content type to be unpublished by default, then give editors the broad "administer nodes" permission, but that's clumsy solution that forces editors to dig for what should be a simple action: publishing or unpublishing a post. That's where the Publish Button module comes in.
Additional resources
There's a reason views is the most popular module on drupal.org and it's pointy-clickly user interface is only a part of that. In this series we cover the ins and outs of writing modules that implement the Views API. Once you’ve realized the power of creating complex lists of nodes, users and other content via the views UI the next logical desire is to allow people to do that with the content provided by your custom module as well. This series will take an in-depth look at exposing your own database tables to the Views module so that users can use them as a place to pull content from including the fields themselves and meta-data about how they can be used to create relationships to other content on your site.
After getting the basics out of the way we’ll also take a look at writing our own custom field handlers to expose our module’s data to views so that it can be sorted, filtered, and queried in new ways. We’ll also look at implementing views plugins to do things like add custom access control options to views and to add new output styles.
Once you understand a bit more about how views works under the hood and how easy it is to tie in to that system you’ll be reimaging your solutions for all sorts of different problems.
In this video Joe describes the process of adding the rest of the fields from the databasics module to our implementation of hook_views_data() including how to differentiate between different data types like strings of text and numeric values and how this changes the views module's behavior. Then Joe talks about how to tell views about various tables that can be used in relationship to the databasics table via foreign keys like the node ID.
Additional resources
Modules Needed
In this chapter Karen Stevenson explains all the pieces that make up an Organic Group content type. Show explains how organic groups adds the necessary fields to make this happen while demonstrating the necessary settings when building your content types. She also covers the content type used for group content as it is different than the group itself. To start the video off she goes over install the necessary modules for the first part of this series.
Note: There have been significant changes to Organic Groups since this lesson was made. Though we would like to revisit this series to update it, we have no current schedule to complete that. The best place to figure out what has changed and why, would be the Organic Groups issue queue on Drupal.org (http://drupal.org/project/issues/search/og).
Additional resources
In this lesson Joe will explain what an entity is and provide a little bit of history about how they came into being. We’ll also learn about some of the differences between custom entities and nodes (which happen to be a type of entity) and when, and why you might want to choose to write your own custom entities instead of using the node system or a more traditional datastore.
Entities were introduced in Drupal 7 as a way of taking the things that people loved about nodes + CCK in Drupal 6 and applying them to other types of data like users, comments, and taxonomy terms. The Entity API in Drupal 7 provides a set of common functions and classes to make it easier for developers to create their own custom entity types or to work with existing ones in a generic way. The API in Drupal core however is still missing some really useful tools and is supplemented by the Entity module in Drupal contributed which we'll make heavy use of throughout the series.
In this series we'll learn about the interplay between Entities, Entity Types, Bundles, and Fields and how to write custom code to deal with each of these things. The Entity API demo site files that we use in this series are all located in the Lullabot GitHub, as well as in zip files attached to the respective video pages, under the Downloads tab.
This series covers:
- What entities are and how they fit into the Drupal ecosphere
- EntityFieldQuery
- Entity classes, what they do and how to override them
- Providing an admin UI for adding/editing and deleting entities from Drupal
- Making entities fieldable
- View modes
- Creating custom UI's for dealing with entities
- Describing entity properties to Drupal
- Views integration for entities
- Entity Metadata wrappers
- Making entities revisionable
And much much more. This series assumes that you're already familiar with the basic tenets of writing modules for Drupal and makes use of things like hook_menu() without spending time explaining them. If you're not familiar with Drupal module development, you might want to brush up by watching our Module Development for Drupal 7 first.
Additional resources
Entity API Demo site files on GitHub
Entity module at Drupal.org
This lesson will explore the use of EntityFieldQuery to retrieve lists of entities from Drupal without directly querying the database which can be problematic in a system where the underlying schema can change depending on configuration settings in the user interface. Again focusing on writing code that will work with any entity in Drupal and isn't hard coded to your particular setup.
Additional resources
In the next set of lessons we're going to be writing to the code to create our own custom entity type. The goal is to create a video entity that stores embed codes for YouTube videos and allows us to display the videos on our site. In this scenario we don't want all the overhead that comes with using the node system, like comments for example, so instead we're going to write our own custom entity for storing the data. We're going to take a look at the completed entity type that we're attempting to build and just walk through all the various components. We'll take a look at creating/updating, and deleting a video via the UI, and also the views integration and fieldability of our custom video entities.
This lesson introduces students to Entity classes and illustrates what each of the main Entity classes does, followed by a more in depth look at the CRUD operations provided by the base entity class, and finally demonstrates overriding the default Entity class with our own custom Entity object to define a defaultUrl() for our entities and a new implementation of hook_menu where we can view an entity.
Note: At the end of the this video code is added to hook_entity_info() that references a VideoEntityUIController
class, however, the definition of that class is in our sample code, but was not shown being added here. And it is necessary to follow along with the videos. If you're following along you'll want to add the following code to the bottom of your videoasset.module file. If you're curious about what it does it's explained in the last part of this video.
/**
* Our custom controller for the admin ui.
*/
class VideoEntityUIController extends EntityDefaultUIController {}
Additional resources
Update your hook_entity_info implementation to take advantage of the Admin UI provided by the Entity API and quickly provide users of your site access to all the Entity CRUD operations via the UI. The API gives us a really good head start but we still need to write some code in order to provide a useable form for administrators. The API doesn’t make any assumptions about things like validating input so we also need to take care of that ourselves.
This video adds a new permission that allows privileged users administer our new videoasset entities. If you're following along as a user other than user 1 you'll need to make sure you give yourself the proper permissions. In the video, I'm logged in as the user with the ID of 1 so I'm just granted the permissions automatically.
Note: If you're following along with the videos in sequence there's an error that needs correcting. At the end of the previous video code was added to videoentity_entity_info()
that references a VideoEntityUIController
class, however, the definition of that class was not added. Which, will cause a PHP error because the class is missing.
In order to correct this error, you'll want to add the following code to the bottom of your videoentity.module file. This just ensures that the class is defined so that there are no errors. If you're curious about what it does it's explained in the last part of the previous video.
/**
* Our custom controller for the admin ui.
*/
class VideoEntityUIController extends EntityDefaultUIController {}
In a later tutorial in this series, we'll customize the form for our video entity by adding more code to this class.
Note: At 14:10 on line 36 this line is added:
'#value' => isset($VideoAsset->id) ? t('Update video asset') : t('Save video
asset'),
It should be:
'#value' => isset($video->id) ? t('Update video asset') : t('Save video
asset'),
So far we’ve seen that you can use entity_load and entity_view to display your entity. But what if you want more control over how your content gets rendered? In this lesson we’ll take a look at overriding the buildContent() method of our entity controller to spruce up the output a bit. We'll also overrid the save() method of the controller in order to populate the created_at and updated_at fields automatically when saving a video entity.
Note: In order to improve upon the security of the code in this lesson you'll want to make sure you're escaping all user input properly. The following code:
$build['embedcode'] = array(
'#type' => 'markup',
'#markup' => '<iframe width="560" height="315" src="http://www.youtube.com/embed/'. $entity->embedcode . '" frameborder="0" allowfullscreen></iframe>',
);
Should be updated to use the check_url() function when outputting $entity->embedcode
to ensure that user entered content is safe for use in the context of a URL.
$build['embedcode'] = array(
'#type' => 'markup',
'#markup' => '<iframe width="560" height="315" src="http://www.youtube.com/embed/'. check_url($entity->embedcode) . '" frameborder="0" allowfullscreen></iframe>',
);
Bundles are an implementation of an entity type to which fields can be attached. In this lesson we’ll take a look at configuring a single bundle type for our entities in order to allow us to make them fieldable by hardcoding the bundle information into hook_entity_info(). This is the most basic implementation of bundles. Then we’ll look at adding the ability to attach fields to our newly created bundle.
Because Omega doesn't make assumptions about your layout, it comes with lots of options and plenty of regions to work with. This is great but also has some down falls espcially if you are converting an exisiting theme that just doesn't need as many regions and zones. Along with removing regions you may need to add some as well. In this lesson we will demonstrate:
- Adding a region
- Removing regions
- Placing content into these regions
- Cleaning up the .info file
Once this is complete, we now have our converted theme setup just as it was before when it comes to the grid system and some blocks in place to make sure the layout is looking good.
NOTE: Kyle initially sets a position, but not the weight, of the footer_bottom region in this video, and then you'll see that he catches the mistake, and fixes it to have a weight of 3.
This chapter walks through the process of adding links to the contextual drop-down widgets new in Drupal 7. It also shows how using menu autoloaders can help simplify the code that you write in your page callback function since you won't have to do extra checking on the data.
As a note, if you are wondering why we started our function with an underscore (_), naming functions with an underscore in front of the name is a common convention in Drupal that sort of implies that "this function is for internal use by this module only" and shouldn't be called by itself. It's also a nice way to ensure that your internal functions are not colliding with the namespace of a hook or another module. Here's a good blog post about naming things.
Features is a module which generates modules for us. You can then extend that module just as you would any other Drupal module. In this video we'll add some additional code to our feature to make it more complete for our needs, outside of the realm of what Features itself can provide.
The features module (and the drush command) are pretty smart about not overwriting custom changes, and your chances of overwriting your custom code are pretty slim. When features exports a module it creates a .module file with only one line of code in it. Which is an include for another file: mymodule.features.inc. Features then puts all of the automatically generated code into this included file. When you regenerate or update a feature it just uses the existing mymodule.module file which maintains any code that you wrote, and then regenerates the mymodule.features.inc and associated files.
Additional resources
Features project (Drupal.org)
Introduction to Drush Series (Drupalize.Me)
https://github.com/DrupalizeMe/drupalize-lullablog (GitHub.com)
Login Redirects
FreeThis screencast shows how to set up Rules to mimick parts of the Login Destination module. It covers:
- How to redirect administrators to the content admin page on login
- How to redirect non-adminsitrators to the front page on login
- That you need the “force redirect” option when redirecting on login (yes, really!)
- Some words about utilizing user permissions instead of user roles for conditions
Additional resources
Rules guide (Drupal.org)
Components
FreeWhy creating Rules components? Here is why!
- You can reuse and simplify configuration
- You can export each component individually
- You can use rules components to perform conditions from within actions
- You can execute components manually for easier debugging (or just for the sake of executing their actions)
An important aspect of components is that they have variables – parameters that must be sent to the component when executing it.
Additional resources
Rules guide (Drupal.org)