Including views in Drupal modules

Views are included in modules by implementing hook_views_api() and hook_views_default_views() and returning an array of view objects from the latter.

The easiest way to construct the view object is to create the desired view via the UI and then export it, saving each exported view into its own function in sites/all/modules/custom/modulename/modulename.views_default.inc and then returning them all in modulename_views_default_views() in the same file (named e.g. _modulename_views_view_name()). For example:

/**
 * Implements hook_views_default_views().
 */
function worksmanagement_views_default_views() {
  return array(
    'work_orders' => _worksmanagement_views_work_orders(),
    'job_reports' => _worksmanagement_views_job_reports(),
  );
}

All of which is good, and works well. (Why not use Features for this, which more or less does exactly the same thing? Not sure; probably stubbornness. That doesn’t matter for now though.) The confusion comes with updating the exported views.

When a view is created, its definition lives in the views_view and views_display database tables. Once the view has been exported and saved into the module, its definition is stored in two places! This can be seen in the Views admin screen, where (once the caches have been cleared) the view is shown as “Database overriding code” rather than “In database”. There will also no longer be an option of deleting it; rather, it can be reverted. Reverting a view will delete its metadata from the two DB tables, and it will be defined exclusively from the module’s code. This is good.

The next step is to edit the view, make some changes, and re-export it. Do not save it! There is no need to save the changes you make (as this would then stick it back into the database and you’d just have to revert it again), but rather just use the export function available from the view editing UI under the edit view name/description menu (see screenshot below). This will export the view as it stands (i.e. in its unsaved, editing state).

Screenshot of View export menu item

After exporting and overwriting the code in _modulename_views_view_name(), clearing the cache is all that’s required to make the view active and update to date with what’s in the module’s code.

Note that the view will be locked for editing; hit ‘cancel’ to unlock it, or break the lock when prompted when next editing the view.

(This is why I don’t want to use Features for this: it feels better to have everything living in the module, rather than having to copy (or ‘revert’ as Features calls it) view definitions from the module into the database.)

A bug in the Workflow module confuses me

I’m getting and annoying error when running reverting a Feature (drush fr featurename):

/var/www/stage.example.org$ drush fr featurename

Fatal error: __clone method called on non-object in /var/www/stage.example.org/sites/all/modules/workflow/workflow.features.inc on line 55
Drush command terminated abnormally due to an unrecoverable error.

Error: __clone method called on non-object in /var/www/stage.example.org/sites/all/modules/workflow/workflow.features.inc, line 55

It looks like this bug was fixed 2 September 2014 and is tagged as being fixed in 7.x-2.4 … but that version was released on 15 July.

[Update:] Ah. A coffee later, and I realise my stupidity this morning — the bug is tagged as being in 7.x-2.4, not fixed in that version. Gosh, one shouldn’t post before coffee!

I apply the patch manually.

Features (my cheatsheet)

The Features module is great. I think. Sometimes it seems too good to be true… usually it just is good though.

One can build a site in one’s local Drupal installation, and then piece by piece export its definition to a feature module that can be put under version control and deployed to other sites in one fell swoop. Start with:

drush fe --version-set=7.x-0.1 --destination=sites/all/modules/custom/featurename featurename components

where featurename is the new module’s name and components is the first thing to export (usually a content type). From then, the destination can be left out, and the components definition is also pretty flexible at making it quicker to select which components to export (naming contentions, such as common prefixes, help with this). So, as the site progresses, export new components to the feature:

drush fe --version-increment featurename components

If a component that’s already been exported needs to be changed, just change it and then update the feature with:

drush fu --version-increment featurename

That’s about all there is to the construction phase. Stick the sites/all/modules/custom/featurename directory into a VCS. Then it’s deployment time…


Check the featurename module out to the staging site (in the custom directory still, just for clarity’s sake) and enable the module:

drush en featurename

That only needs to be done the first time; subsequent updates are just cycles of updating the code and reverting the feature (a note on the slightly-confusing terminology of Features: one reverts (fr) the site, or updates (fu) the code).

$ git pull origin master
$ drush fr featurename