Altering Drupal Views Embed Programmatically
Published:
Heads up! This content is more than six months old. Take some time to verify everything still works as expected.
Views have a tendency to get a bit... complex. Reusing existing portions of a view makes perfect sense, and the built in tools do a pretty bang up job of letting you create slightly adjusted displays that inherit the pieces you need for the most part. But, somethings crafting more and more displays, just to tweak one setting or another is just beyond frustrating due to pure volume. So instead, I submit the following idea. Start simple, and evolve as needed.
A habit I've recently developed is to build the most basic possible view possible, as the default (drupal 6), or master (drupal 7). From there, I don't create pages, or blocks, or even attachments. I grab the wonderful base tool, and tweak on the fly as I embed it on pages. This might be easier to explain using a simple concrete example.
Let's imagine you have two content types: Event Type
and Event
Event
contains a reference to an Event Type
.
The editor needs to be able to go in and edit the Event Type
to
add text, etc. And on the view side, below her content, we need to
display a view of events, matching the type being viewed. This could
be done by installing a views field module, and setting up an extra
argument on the view to take in the event type's nid. But who needs
the extra module? And what if one argument doesn't satisfy all our
needs? So, instead, we use hook_node_view to embed a view to the
bottom of the event type problematically. We'll set the filter on
that view on the fly.
Your events
view would have a very simple base, with filters only
for published of true and node type of event type. Then the
following code comes into play:
function _custom_node_event_type_view($node, $view_mode, $langcode){ // Only affect full displays, it wouldn't make much sense on a preview if( in_array($view_mode, array('default', 'full') ) ){ // Add a view of events of this type $view_display = 'default'; // You could actually use any display $view = views_get_view('events'); $view->set_display($view_display); // Options to set the number of items per page, add pager. $pager = $view->display_handler->get_option('pager'); $pager['type'] = 'full'; // Options are none, some, mini, full $pager['options']['items_per_page'] = 5; // Options are none, some, mini, full $view->display_handler->set_option('pager', $pager); // Filter events by reference $node->nid $filters = $view->display_handler->get_option( 'filters' ); $filters['field_event_type_target_id'] = array( 'id' => 'field_event_type_target_id', 'table' => 'field_data_field_event_type', 'field' => 'field_event_type_target_id', 'operator' => '=', 'value' => array( 'value' => $node->nid ) ); $view->display_handler->set_option( 'filters', $filters ); // Option to add a field on the fly // Add missing body view. $fields = $view->display_handler->get_option( 'fields' ); $fields['body'] = array( 'id' => 'body', 'table' => 'field_data_body', 'field' => 'body', 'label' => '', 'type' => 'text_default' ); $view->display_handler->set_option( 'fields', $fields ); // The output is not always a string, depending on the view display you choose // Make sure to observe what it gives back. Blocks have to be thrown though render() for instance $view_output = $view->execute_display( $view_display, '' ); // Add this view to the node $node->content[ 'upcoming_events' ] = array( '#weight' => 99, '#markup' => $view_output ); } }
Note that this code is for Drupal 7, but is very similar in Drupal 6.
This should let you add filters, fields, and even control paging on the fly.
Update 4/27/2012 9:05:
I forgot to mention one important part. "Where did you get the arrays for the filters and fields to add?!" Seems important, sorry for the oversight. It's actually very simple, a step I forget when I'm thinking about the harder parts.
Go to the view you want to manipulate. Add the filter or field to the
view directly through the views admin ui, and save it. Now, in the
above code, simple drupal_set_message( var_export($filters, TRUE) )
,
or krumo($filters)
. The keys and values for the arrays you need to
add will be listed. Make copy magic. After that, go back to the
views admin ui, and remove the field, then save and you're all done.
Eventually, you'll have done this enough to start to understand the arrays to add, without the guide. It's always handy for new field types.
Credits:
Thanks to Beshoy Girgis for updating my pseudo-code and explanation into working code for a project we were working on.