Categories
PHP

Drupal: Invoke blocks and views from code

While Panels is great for controlling the layout of drupal pages, there are times when you can’t use the module to theme a page.  For uncached content, it does introduce some performance overhead into the drupal request change.  It can also be tedious to migrate changes from one environment to the other if you don’t export pages and variants to version control.

When you’re working in the stock theme layer, the following functions can come in handy.

Render a Block

/**
   * Convenience function to easily call a block from a module
   * @param string module name
   * @param string delta
   * @return array block
   */
  public function invoke_block($module, $delta) {
    if ('block' == $module) {
      global $theme_key;

      // the block_block view is pretty useless
      $block = db_fetch_object(db_query("SELECT b.*, bl.title, bl.*
                   FROM {boxes} b
                   INNER JOIN {blocks} bl ON (bl.module='block'
                       AND bl.delta=b.bid AND bl.theme='%s')
                   WHERE b.bid = %d", $theme_key, $delta));
     $data['subject'] = $block->title;
     $data['content'] = check_markup($block->body, $block->format, FALSE);

      if ('n/a' !== $data['content']) {
        return ($object) $data;
      }
    } else {
      if (module_exists($module)) {
        $block =  module_invoke($module, 'block', 'view', $delta);
        $block['delta'] = $delta;
        $block['module'] = $module;
        return (object) $block;
      }
      else {
        trigger_error("Module $module is not enabled.", E_USER_ERROR);
      }
    }
  }

To show block with delta 1 defined by module foo:

$block = invoke_block('foo', 1);
$output = theme('block', $block);

Render a View

/**
   * Convenience function to easily get the output of a view
   * A note about the display id, this is NOT the identifier
   * that you can set in the Views UI. To see the display id, look
   * at the theme information for the display.  For blocks it will
   * be something like block_1 or block_X where X is a number.
   * If the display_id doesn't match then Views automatically
   * uses the default display which can make themeing a pain.
   * modeled on view_embed_view().
   *
   * @param string view name
   * @param string display name (see theme info for the display name)
   * @param array additional options
   * @return string
   */
  static public function invoke_view($name, $display_id = 'default') {
    $args = func_get_args();
    array_shift($args); // remove $name

    if (count($args)) {
      array_shift($args); // remove $display_id
    }

    $view = views_get_view($name);
    if (!$view) {
      trigger_error('Unknown view invoked: ' . $name, E_USER_WARNING);
      return;
    }

    // validate the $display_id is valid
    // generate an error to prevent wasted time debugging.
    $defined = array_keys($view->display);

    if (!in_array($display_id, $defined)) {
      trigger_error('In view "' . $name . '" unknown display invoked "'
                  . $display_id . '"', E_USER_WARNING);

      // lets not render, chances are we don't want
      // the default display if we invoke a specific view
      return;
    }

    // if a view is empty, dont return anything
    $r = $view->preview($display_id, $args);
    if (false !== strpos($r, '
‘)) { return $r; } else { return null; } }

To render display page_1 from view foo. You can even pass arguments to the view.

$output = invoke_view('foo', 'display1');
$output2 = invoke_view('foo', 'display1', 2010, 111); // with args!