Last updated September 9, 2014. Created on January 4, 2011.
Edited by nedjo, jhodgdon, jwilson3, DamienMcKenna. Log in to edit this page.

One of Views' most useful features is being able to export a view into code. This has a few benefits:

  • A view in code can be managed with revision control systems (git, svn, etc).
  • A view in code can be included in a module as a "default" view; for example, the Views module includes a replacement for the standard taxonomy term page structure.

Once a view is put into code, you can override it in the Views user interface (add extra fields, add displays, add arguments, etc.). Rather than leaving the modified view stored in the database, and having it be listed on the Views main administration page as "Overridden", it is considered a good practice to save the modified view back into code, rather than leaving the changes in the database only. There are two ways to do that.

Method #1 - Easy

The easy method involves completely replacing the existing view with your modified view. This method has the disadvantage that if the default view from the original module is updated, you wouldn't get the updates. (Of course, that might not be a disadvantage to you).

To do this, first export your modified view into a text buffer. Then, in your own module, add an implementation of hook_views_default_views_alter() that looks like this:

<?php
/**
 * Implementation of hook_views_default_views_alter().
 */
function mymodule_views_default_views_alter(&$views) {
 
// Alter only the 'view_name_of_interest' view.
 
if (array_key_exists('view_name_of_interest', $views)) {
   
$view = new view;
   
$view->name = 'view_name_of_interest';
   
// The rest of the definition from the exported view goes here.
    // ...

    // Override the existing view with this new definition.
   
$views['view_name_of_interest'] = $view;
  }
}
?>

After that's all done, enable your module and clear your site caches to make Views recognize your changes. Then go to the Views administration page, and revert your changes to the view. It should now be your changed version.

Method #2 - Hard

The alternative method involves less code, but a greater awareness of how Views works: rather than replacing the entire view definition, the idea is to specify the few parts of the view that are to be changed. This will mean that if the underlying view from the other module changes, you will get the changes. Achieving this is a several-step process:

  1. As before, create a hook_views_default_views_alter() in your module.
  2. For the first version of the hook, use the dpm() function from the Devel module (or you could use print_r()) to output the existing view from the other module:
    <?php
    /**
     * Implementation of hook_views_default_views_alter().
     */
    function mymodule_views_default_views_alter(&$views) {
     
    // Alter only the 'view_name_of_interest' view.
     
    if (array_key_exists('view_name_of_interest', $views)) {
       
    dpm($views['view_name_of_interest']);
      }
    }
    ?>
  3. Export the overridden view, and compare this to the dpm() output, to figure out what has changed.
  4. Put the changes into your hook_views_default_views_alter() function. For example:
    <?php
    /**
     * Implementation of hook_views_default_views_alter().
     */
    function mymodule_views_default_views_alter(&$views) {
     
    // Alter only the 'view_name_of_interest' view.
     
    if (array_key_exists('view_name_of_interest', $views)) {
       
    // Change the path of the first page display.
       
    $views['view_name_of_interest']->display['page']->display_options['path'] = 'new_page_path';

      }
    }
    ?>

Workaround: cloning a default view

An alternative approach that's feasible in some cases is to substitute the default view with a version you've cloned and modified.

Note however that this approach depends on where and how the default view you're replacing is referenced elsewhere on the site. If it's a view that provides a single page display, replacing it with a clone should work fine, since the page will continue to work at the same path. However, if your view provides for example a block display, cloning the view would require edits to any code or configuration referencing that block.

To replace a view with a cloned version:

  1. Clone the view of interest, giving it a new name and making any changes you wish to make. If you have already overridden the view, you can clone your overridden version then revert the original view.
  2. Export your cloned view to code. You can do so manually or by using the Features module.
  3. Disable the original view. You can do so through the Views UI or in code. To do so in code, use hook_views_default_views_alter() to change the 'enabled' property of the exported view. Or see #1961734-6: Add support for exporting admin views in Features for an alternate approach.

Looking for support? Visit the Drupal.org forums, or join #drupal-support in IRC.

Comments

cbandes’s picture

Can this method be used in themes, or only in modules? (Specifically I want a view to work one way in theme A and a different way in theme B - would the method above help in that scenario?)

--
Senior Web Developer/Project Lead
Harvard University Division of Continuing Education

pounard’s picture

The drupal_alter() method for calling hooks also calls them on themes: if the Views module uses drupal_alter() properly, then themes are able to implement this as well.

I'm not sure Views is using this function properly, but since it's a well used module that exists since a long time, I guess it does.

stickywes’s picture

If you are just planning to add an additional display to a default view definition that has been defined by another module, you can rely on the Easy step, as well. Assuming you've created that additional display and just want to get it into code, go into export and find the comment that addresses your display directly.

/* Display: Page */
$handler = $view->new_display('page', 'Page', 'page_1');
$handler->display->display_options['defaults']['arguments'] = FALSE;
$handler->display->display_options['path'] = 'path';
....

Then you follow the Easy step mostly the same, making sure you set $view to the correct existing view.

<?php
function mymodule_views_default_views_alter(&$views) {
 
// Alter only the 'view_name_of_interest' view.
 
if (array_key_exists('view_name_of_interest', $views)) {
   
$view = $views['view_name_of_interest'];
   
$handler = $view->new_display('page', 'Page', 'page_1');
   
$handler->display->display_options['defaults']['arguments'] = FALSE;
   
$handler->display->display_options['path'] = 'path';
   
// The rest of the definition from the exported view display goes here.
    // ...
 
}
}
?>
njogz’s picture

I have two fairly obvious questions but just learning drupal so bear with me. Can Method #1 be used to override a view by using an if statement depending on the logged in user's id? Does 'view_name_of_interest' refer to the view being overridden or is it the new name of the custom view?

jmev’s picture

I have been researching this some myself recently, and I'm sure the answer is yes on both of your questions. On the first, you may actually be able to pass variables to a view's definition, and just modify the variable value based on the user (uid). You can use user_load() to load a specific user (https://api.drupal.org/api/drupal/modules!user!user.module/function/user...), or you can get the current user id like this:
$uid = $GLOBALS['user']->uid

Then, you can control individual variables, or use a completely different view definition, directly entering it, or by doing a selective include of an external file that will hold the view definition (better, in my opinion).

HTH!

Very teachable jack-of-all-trades. Working with Drupal since 2010 and diving more and more into the mysterious details daily — and having fun at it!!!

asparaguscat’s picture

Is there a way to programmatically set which region the block belonging to the view will be in?

I've tried using the machine name I set for the block in the Views UI, but it's not the name that the block uses to identify itself. The block is identified by a long alphanumeric string that is different depending on whether existing blocks have been created in a view, meaning I can't reliably select it to set the region in a module install file.

Am I doing something wrong to cause it not to take the name I assign to it?