
This post is an entry in our 20 APIs in 20 Days series. Learn more about how best practices lead to sustainable development at www.trellon.com.
Views is the most widely used of all the contributed modules for Drupal. It offers the ability to easily create pages and blocks of dynamic content, which can be authored through a web based interface. It also allows site admins to attach filters to views, providing useful ways to drill down on data without too much effort.
The Views module also possesses a well defined API for working with views in code. Developers can call views within their modules, modify the way views are displayed, and even create new views programmatically. There is extensive documentation and community discussion about the different ways you can work with views in your code. This edition of the 20 APIs in 20 Days series seeks to provide an overview of some of the less well-known features of the API, that our team often finds useful when developing sites for clients.
For developers building custom modules, there are times you might want to have some views that already exist when your module is installed. You may also want to allow data generated by your module to display within Views created by users. The Views API provides data hooks to allow you to do this.
Data hooks are for developers looking to integrate their modules with the Views module. At a real basic level, data hooks allow developers to tell the Views module how to include data generated by the module into a view. They also give the Views module some information about that data, and how it relates to other content in your site. At a more advanced level, data hooks allow developers to control the way information will appear in Views, and how to handle more advanced operations like filtering and sorting. Overall, this set of hooks provides developers with a comprehensive way to tie the operations of their module into the Views module.
The data hooks available to developers in Views 6 are:
Together, these functions that compose the data hooks combine to create a powerful API for hooking into views. When exmployed, your custom module can provide data to views, control the way it will appear, and permit advanced filtering. Here is an example of data hooks in action, taken from the nodequeue module.
/**
* hook_views_api - registers the module with the Views API
* This specific example tells Drupal to use version 2 of the API
*/
function nodequeue_views_api() {
return array(
'api' => 2,
'path' => drupal_get_path('module', 'nodequeue') .'/includes/views',
);
}
/**
* Implementation of hook_views_data()
*
* hook_views_data tells the views module where to look for data. There is an entry
* for each field supported by the view. This example is truncated to save space.
*
*/
function nodequeue_views_data() {
$data = array();
// ----------------------------------------------------------------
// nodequeue_nodes table
$data['nodequeue_nodes']['table']['group'] = t('Nodequeue');
// this example shows how a field is connected to your views. A filter and sorting
// function is tied to the field, which enables views to carry out these functions without
// needing to write more code.
$data['nodequeue_nodes']['position'] = array(
'title' => t('Position'),
'help' => t('The position of the node within a queue.'),
'field' => array(
'handler' => 'views_handler_field_numeric',
'click sortable' => TRUE,
),
'sort' => array(
'handler' => 'views_handler_sort',
),
'filter' => array(
'handler' => 'views_handler_filter_numeric',
),
'argument' => array(
'handler' => 'views_handler_argument_numeric',
),
);
// notice how a different sorting handler and filter is applied to this field. Views
// has native tools for handling dates, numbers, text and other types of data.
$data['nodequeue_nodes']['timestamp'] = array(
'title' => t('Added date'),
'help' => t('The date the node was added to a queue.'),
'field' => array(
'handler' => 'views_handler_field_date',
'click sortable' => TRUE,
),
'sort' => array(
'handler' => 'views_handler_sort_date',
),
'filter' => array(
'handler' => 'views_handler_filter_date',
),
);
// there are a bunch of other fields contained in this function, but these two are good
// examples of how fields are tied into views.
...
return $data;
}
/**
* Implementation of hook_views_handlers()
*
* hook_views_handlers tells the views module how to present fields within the UI and also how to
* display fields within a view itself. You will find a file corresponding to each parent item
* in the module directory.
*
*/
function nodequeue_views_handlers() {
return array(
'info' => array(
'path' => drupal_get_path('module', 'nodequeue') .'/includes/views',
),
'handlers' => array(
'nodequeue_handler_argument_subqueue_qid' => array(
'parent' => 'views_handler_filter_numeric',
),
'nodequeue_handler_field_all_queues' => array(
'parent' => 'views_handler_field_prerender_list',
),
'nodequeue_handler_field_all_subqueues' => array(
'parent' => 'nodequeue_handler_field_all_queues',
),
'nodequeue_handler_field_links' => array(
'parent' => 'views_handler_field_node_link',
),
'nodequeue_handler_field_queue_tab' => array(
'parent' => 'views_handler_field_node_link',
),
'nodequeue_handler_filter_in_queue' => array(
'parent' => 'views_handler_filter_boolean_operator',
),
'nodequeue_handler_relationship_nodequeue' => array(
'parent' => 'views_handler_relationship',
),
),
);
}This is a fairly simple example of how to work with data hooks in custom modules to tie them into the Views API. By no means should this be considered exhaustive - there is detailed documentation available about the Views API at http://views.doc.logrus.com/.
Another group of Views APIs are alter hooks. Using these hooks you can change the view behavior in different phases of building a view. A change can be in any aspect of the view which can be changed in Views UI. Each view is a PHP Object, which consists of many different properties. Changing these properties can change the output of the view. Let's look at available hooks ordered by how they are called in code:
Alter hooks have a lot of applications in development, and they can make Views more usable and useful without having to write much code. This is an example of how to attach some text before a view. Using hook_views_pre_render allows us to keep PHP code out of the views header and control the display of certain views in a more permanent form:
/**
* Attach term description to view by argument
*/
function MYMODULE_views_pre_render(&$view) {
if ($view->name == 'view-i-want-to-change') {
// we can access view arguments
$term = taxonomy_get_term($view->arg[0]);
if ($term) {
$view->attachment_before = check_markup($term->description, FILTER_FORMAT_DEFAULT, FALSE);
}
}
}Beyond just controlling the display of views, filters and sorts can be modified as well. This example code demonstrates how to modify the order in which a view presents data.
function MYMODULE_views_pre_render(&$view) {
if ($view->name == 'view-i-want-to-change') {
// we defined 3 sort in Views UI for our view
$available_sorts = array('node_title' => t('Title'), 'node_created' => t('Post Date'), 'user_name' => t('Author'));
// determine which sort is available
$current_sort = isset($_GET['sort']) && isset($available_sorts[$_GET['sort']) ? $_GET['sort'] : 'node_title';
// now we will remove all sort definitions except one its used
$sort = $view->display_handler->get_option('sort');
foreach (array_keys($sort) as $sort_name) {
if ($sort_name != $current_sort) {
// here we are removing unused sorts
unset($sort[$sort_name]);
}
}
$view->display_handler->sort_option('sort', $sort);
// we build sort links
$links = array();
foreach ($available_sorts as $type => $title) {
$links[] = array(
'title' => $title,
'path' => $_GET['q'],
'query' => array('sort' => $type)
)
}
// we will attach links to view
$view->attachment_before = theme('links', $links);
}
}It should be noted that modifying the sort of a view can be a painful process and require a lot of troubleshooting to get right. Don't forget to use the Devel module when exploring view objects and it's nice dpm function, which can save you days of head scratching. Here is an example:
function MYMODULE_views_pre_render(&$view) {
dpm($view);
}A lot of hooks have been mentioned in this post, and it is generally unnecessary to store all of your views API code in a single file. In fact, it is usually a bad idea to keep everything all in one place - loading all of this code each time a view loads would lead to performance problems. With the Views API, code can be divided to many files without much effort, and only the necessary files will be loaded to get a view to run.
So which hook belongs where? Some thought has gone into common conventions for strucutring code within custom modules, to make them easier to understand and work with. The outline below is intended to demonstrate a typical implementation pattern for views code.
Finally, the Views API doesn't ends with hooks, but it provides also small functions that make the lives of developers easier. If you are planning on doing intensive Views hacking, it is worth your time to scour the documentation and get a better sense of all the Views module has to offer. Here are some of the more useful functions every developers should be aware of:
This overview only describes a few approaches to working with views, and these are just the ones we tend to use most often here at Trellon. There are some additional resources listed below for digging into the details of the Views API and coming up with your own solutions to common challenges. Be sure to catch all of Trellon’s API blog posts as we explore the fundamental tools for extending Drupal’s functionality.
3 Comments
One commonly used one that is
One commonly used one that is missed (possibly because it has YET to get patched into the documentation properly): hook_views_data_alter -- excellent for changing the default behavior on how Views handles already existing tables and fields.
ohh very nice
ohh very nice
goog job
goog job
Post new comment