Creating views programmatically

Last modified: October 4, 2007 - 22:07

Views doesn't have to be powered by hooks or by a GUI. It can be powered by the programmer in a "hard coded" fashion.

For example, say you wanted a site structure where you could have a content type followed by an arrangement of other arguements. This URL structure is too advanced for the GUI to handle so one could write this into a module.

Firstly, we'd need a menu structure to call up a function with arguments as required - for example:

<?php
function site_menu($may_cache) {
 
$items = array();
 
  if (!
$may_cache) {
   
//These are the types we need to generate menu's for + we can map the section type to a content type.
   
$types = array('forum' => 'forum', 'user' => 'user', 'encyc' => 'content_articles', 'blog' => 'blog', 'video' => 'content_video');
   
   
//Check if site section is in the types
   
if (isset($types[arg(0)])) {
     
     
//If user page...
     
if (substr(arg(1), 0, 5) == 'user-') {
       
$uname = substr(arg(1), 5);
       
$arg2 = arg(2);
       
       
//No arg 2
       
if (empty($arg2)) {
         
$items[] = array(
           
'path' => arg(0) . '/' . arg(1),
           
'type' => MENU_CALLBACK,
           
'callback' => 'site_generate_view',
           
'callback arguments' => array(array('type' => $types[arg(0)], 'username' => $uname)),
           
'access' => 1,
          );
        }
       
//arg 2 present, check for feed - if no feed, assume category
       
else {
         
//Feed
         
if ($arg2 == 'feed') {
           
$items[] = array(
             
'path' => arg(0) . '/' . arg(1) . '/feed',
             
'type' => MENU_CALLBACK,
             
'callback' => 'site_generate_view',
             
'callback arguments' => array(array('type' => $types[arg(0)], 'username' => $uname), TRUE),
             
'access' => 1,
            );
          }
         
//Category (NEED TO CHECK FOR CATEGORY FEED!
         
else {
           
$items[] = array(
             
'path' => arg(0) . '/' . arg(1) . '/' . arg(2),
             
'type' => MENU_CALLBACK,
             
'callback' => 'site_generate_view',
             
'callback arguments' => array(array('type' => $types[arg(0)], 'username' => $uname, 'category' => arg(2))),
             
'access' => 1,
            );
          }
        }
      }
     
     
//else Category Page
     
else {
       
$arg2 = arg(2);

       
//No arg 2
       
if (empty($arg2)) {
         
$items[] = array(
           
'path' => arg(0) . '/' . arg(1) ,
           
'type' => MENU_CALLBACK,
           
'callback' => 'site_generate_view',
           
'callback arguments' => array(array('type' => $types[arg(0)], 'category' => arg(1))),
           
'access' => 1,
          );
        }
       
//Arg 2 == feed
       
else if ($arg2 == 'feed') {
         
$items[] = array(
           
'path' => arg(0) . '/' . arg(1) . '/feed',
           
'type' => MENU_CALLBACK,
           
'callback' => 'site_generate_view',
           
'callback arguments' => array(array('type' => $types[arg(0)], 'category' => arg(1)), TRUE),
           
'access' => 1,
          );
        }
      }
    }
  }
 
  return
$items;
}
?>

That may look a little daunting but basically, it maps up some URL's in the following structure.

  • User

    • user/user-username
    • user/user-username/feed
  • Blog

    • blog/category_name
    • blog/category_name/feed
    • blog/user-username
    • blog/user-username/feed
    • blog/user-username/category_name
    • blog/user-username/category_name/feed
  • Forum

    • forum/category_name
    • forum/category_name/feed
    • forum/user-username
    • forum/user-username/feed
    • forum/user-username/category_name
    • forum/user-username/category_name/feed
  • Video

    • video/category_name
    • video/category_name/feed
    • video/user-username
    • video/user-username/feed
    • video/user-username/category_name
    • video/user-username/category_name/feed
  • Encyc

    • encyc/category_name
    • encyc/category_name/feed
    • encyc/user-username
    • encyc/user-username/feed
    • encyc/user-username/category_name
    • encyc/user-username/category_name/feed

These will all get passed into a function which will look something like this:

<?php
function site_generate_view($func_args = array(), $feed = FALSE) {
 
//Create a basic view object.
 
$view = views_create_view('site_structure', 'This is a test view');
 
 
//Now add a page "view" to the view (teasers, pager on and 5 nodes-a-page)
 
views_view_add_page($view, t('title'), NULL, 'teaser', true, 5, '', 1, false);
 
 
//Add a filter for the type we want (eg, blog)
 
views_view_add_filter($view, 'node', 'type',   '=', $func_args['type'], '');
 
 
//Add a filter so we only get the published status
 
views_view_add_filter($view, 'node', 'status', '=', 1, '');
 
 
//If username is an arg, then load the user and add that.
 
if (isset($func_args['username'])) {
   
$content_user = user_load(array('name' => $func_args['username']));
   
views_view_add_filter($view, 'users', 'uid', '=', $content_user->uid, '');
  }
 
 
//If category set, get all terms which go by that name and add them as an OR filter
 
if (isset($func_args['category'])) {
   
$terms = taxonomy_get_term_by_name($func_args['category']);
   
$t = array();
    while(
$term = array_shift($terms)) {
     
$t[] = $term->tid;
    }
   
   
views_view_add_filter($view, 'term_node', 'tid', 'OR', $t, '');
  }
 
 
//Set a default sorting order - in this case, created timestamp descending
 
views_view_add_sort($view, 'node', 'created', 'DESC', '');
 
 
//Invoke the cache (D5 only!)
 
views_load_cache();

 
//Santize it (eg, create field id's, etc)
 
views_sanitize_view($view);

 
//return the built view!
 
return views_build_view('embed', $view, array(), false);
}
?>

I say something like this because I haven't finished writing it myself yet - there is NO handling for the RSS feeds arguement.

Drupal 5 fix

dakku - May 1, 2007 - 10:02

you need to add this line:

// load this before Santize.
views_load_cache();

Add it just before:

//Santize it (eg, create field id's, etc)
views_sanitize_view($view);

EG:

// load this before Santize.
views_load_cache();

//Santize it (eg, create field id's, etc)
views_sanitize_view($view);

Overriding default views programmatically.

singularo - November 6, 2007 - 11:17

If you are using the views_union module, you may have noticed that it doesn't "export" the union when you export the view.

To work around this, you need to programmatically add the overridden views which you've put in with views_default_views, then manually insert the correct keys into the views_union table. Here's some sample code where clips is a view which is a union of the clips_shared and clips_mine views.

<?php
  views_load_cache
();

 
// Override the clips_mine view to get it in the db
 
$view = _views_get_default_view('clips_mine');
 
views_sanitize_view($view);
 
_views_save_view($view);

 
// Override the clips_shared view
 
$view = _views_get_default_view('clips_shared');
 
views_sanitize_view($view);
 
_views_save_view($view);

 
// Override the clips view
 
$view = _views_get_default_view('clips');
 
views_sanitize_view($view);
 
_views_save_view($view);


 
// Setup Views Union Module
 
$result = db_query("SELECT vid from {view_view} WHERE name = 'clips_mine'");
 
$clips_mine_vid = array_pop(db_fetch_array($result));

 
$result = db_query("SELECT vid from {view_view} WHERE name = 'clips_shared'");
 
$clips_shared_vid = array_pop(db_fetch_array($result));

 
$result = db_query("SELECT vid from {view_view} WHERE name = 'clips'");
 
$clips_vid = array_pop(db_fetch_array($result));

 
db_query("INSERT INTO views_union (id, parent, child) VALUES(NULL, %d, %d)", $clips_vid, $clips_mine_vid);
 
db_query("INSERT INTO views_union (id, parent, child) VALUES(NULL, %d, %d)", $clips_vid, $clips_shared_vid);
?>

Drupal 6

thaddeusmt - January 15, 2010 - 06:26

In Views 2 views_build_view() has gone away, so this will not work in Drupal 6. You can still programmatically create a View, however, but the code is a little different. I created a new tutorial page for Views 2 here:
http://drupal.org/node/685432

 
 

Drupal is a registered trademark of Dries Buytaert.