You are here

panels_views.module in Panels 5.2

Same filename and directory in other branches
  1. 6.2 panels_views/panels_views.module

panels_views.module

Provides views as panels content, configurable by the administrator. Each view provided as panel content must be configured in advance, but once configured, building panels with views is a little bit simpler.

File

panels_views/panels_views.module
View source
<?php

/**
 * @file panels_views.module
 *
 * Provides views as panels content, configurable by the administrator.
 * Each view provided as panel content must be configured in advance,
 * but once configured, building panels with views is a little bit simpler.
 */

/**
 * Implementation of hook_menu().
 */
function panels_views_menu($may_cache) {
  $items = array();
  if ($may_cache) {
    $access = user_access('administer panel views');
    $items[] = array(
      'path' => 'admin/panels/views',
      'title' => t('Views panes'),
      'access' => $access,
      'type' => MENU_NORMAL_ITEM,
      'callback' => 'panels_views_list_views',
      'description' => t('Configure Views to be used as panes within panel displays.'),
    );
    $items[] = array(
      'path' => 'admin/panels/views/list',
      'title' => t('List'),
      'access' => $access,
      'type' => MENU_DEFAULT_LOCAL_TASK,
      'callback' => 'panels_views_list_views',
      'weight' => -10,
    );
    $items[] = array(
      'path' => 'admin/panels/views/add',
      'title' => t('Add'),
      'access' => $access,
      'callback' => 'panels_views_add_view',
      'type' => MENU_CALLBACK,
    );
    $items[] = array(
      'path' => 'admin/panels/views/edit',
      'title' => t('Edit'),
      'access' => $access,
      'callback' => 'panels_views_edit_view',
      'type' => MENU_CALLBACK,
    );
    $items[] = array(
      'path' => 'admin/panels/views/delete',
      'title' => t('Delete'),
      'access' => $access,
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'panels_views_delete_confirm',
      ),
      'type' => MENU_CALLBACK,
    );
    $items[] = array(
      'path' => 'admin/panels/views/import',
      'title' => t('Import'),
      'access' => $access,
      'callback' => 'panels_views_import_view',
      'type' => MENU_LOCAL_TASK,
    );
    $items[] = array(
      'path' => 'admin/panels/views/export',
      'title' => t('Export'),
      'access' => $access,
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'panels_views_export_view',
      ),
      'type' => MENU_CALLBACK,
    );
    $items[] = array(
      'path' => 'admin/panels/views/disable',
      'access' => $access,
      'callback' => 'panels_views_disable_page',
      'weight' => -1,
      'type' => MENU_CALLBACK,
    );
    $items[] = array(
      'path' => 'admin/panels/views/enable',
      'access' => $access,
      'callback' => 'panels_views_enable_page',
      'weight' => -1,
      'type' => MENU_CALLBACK,
    );
  }
  return $items;
}

/**
 * Implementation of hook_perm().
 */
function panels_views_perm() {
  return array(
    'administer panel views',
  );
}

/**
 * Page callback to list view panes and the initial form to add new view panes.
 */
function panels_views_list_views() {

  // Run the form first as it may redirect; no point in doing the rest of
  // the work if it does.
  $form = drupal_get_form('panels_views_add_view_form');
  $items = array();
  $sorts = array();
  $header = array(
    array(
      'data' => t('Title'),
      'field' => 'title',
    ),
    array(
      'data' => t('Name'),
      'field' => 'name',
      'sort' => 'asc',
    ),
    array(
      'data' => t('Type'),
      'field' => 'type',
    ),
    array(
      'data' => t('View'),
      'field' => 'view',
    ),
    t('Operations'),
  );
  foreach (panels_views_load_all() as $panel_view) {
    $ops = array();
    if (empty($panel_view->disabled)) {
      $ops[] = l(t('Edit'), "admin/panels/views/edit/{$panel_view->name}");
      $ops[] = l(t('Export'), "admin/panels/views/export/{$panel_view->name}");
    }
    if ($panel_view->type != t('Default')) {
      $text = $panel_view->type == t('Overridden') ? t('Revert') : t('Delete');
      $ops[] = l($text, "admin/panels/views/delete/{$panel_view->name}");
    }
    else {
      if (empty($panel_view->disabled)) {
        $ops[] = l(t('Disable'), "admin/panels/views/disable/{$panel_view->name}", NULL, drupal_get_destination());
      }
      else {
        $ops[] = l(t('Enable'), "admin/panels/views/enable/{$panel_view->name}", NULL, drupal_get_destination());
      }
    }
    $item = array();
    $item[] = check_plain($panel_view->title);
    $item[] = check_plain($panel_view->name);

    // this is safe as it's always programmatic
    $item[] = $panel_view->type;
    $item[] = check_plain($panel_view->view);
    $item[] = implode(' | ', $ops);
    $items[] = $item;
    $ts = tablesort_init($header);
    switch ($ts['sql']) {
      case 'title':
        $sorts[] = $item[0];
        break;
      case 'name':
      default:
        $sorts[] = $item[1];
        break;
      case 'type':
        $sorts[] = $panel_view->type . $item[0];
        break;
      case 'view':
        $sorts[] = $item[2];
        break;
    }
  }
  if (drupal_strtolower($ts['sort']) == 'desc') {
    arsort($sorts);
  }
  else {
    asort($sorts);
  }
  $i = array();
  foreach ($sorts as $id => $title) {
    $i[] = $items[$id];
  }
  $output = theme('table', $header, $i);
  $output .= $form;
  return $output;
}

/**
 * Form to select a view for creating a new view pane.
 */
function panels_views_add_view_form() {
  $form['view'] = array(
    '#type' => 'select',
    '#options' => panels_views_get_all_views(),
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Create panel view'),
  );
  return $form;
}
function theme_panels_views_add_view_form($form) {
  $row = array(
    drupal_render($form['view']),
    drupal_render($form['submit']),
  );
  return theme('table', array(), array(
    $row,
  )) . drupal_render($form);
}
function panels_views_add_view_form_submit($form_id, $form_values) {
  return 'admin/panels/views/add/' . $form_values['view'];
}

/**
 * Page callback to add a new view pane from an existing view.
 */
function panels_views_add_view($view_name) {
  $view = views_get_view($view_name);
  if (empty($view)) {
    return drupal_not_found();
  }
  return drupal_get_form('panels_views_edit_view_form', $view, panels_views_default_view_pane($view));
}

/**
 * Page callback to edit a view pane.
 */
function panels_views_edit_view($view_name) {
  $pv = panels_views_load($view_name);
  if (empty($pv)) {
    return drupal_not_found();
  }
  $view = views_get_view($pv->view);
  drupal_set_title(t("Edit '@title'", array(
    '@title' => $pv->title,
  )));
  return drupal_get_form('panels_views_edit_view_form', $view, $pv);
}

/**
 * Form to add or edit add a view pane.
 */
function panels_views_edit_view_form($view, $panel_view) {
  panels_views_pane_arguments($view, $panel_view);
  $form['basic'] = array(
    '#type' => 'fieldset',
    '#title' => t('Basic information'),
  );
  if (!empty($panel_view->pvid) && is_numeric($panel_view->pvid)) {
    $form['pvid'] = array(
      '#type' => 'value',
      '#value' => $panel_view->pvid,
    );
  }
  $form['view'] = array(
    '#type' => 'value',
    '#value' => $panel_view->view,
  );
  $form['basic']['name'] = array(
    '#type' => 'textfield',
    '#title' => t('Panel view name'),
    '#description' => t('Enter a unique name for this view pane. It must contain only letters and numbers.'),
    '#default_value' => $panel_view->name,
  );
  $form['basic']['title'] = array(
    '#type' => 'textfield',
    '#title' => t('Panel view title'),
    '#description' => t('The title of the pane; this will appear in the add content dialog.'),
    '#default_value' => $panel_view->title,
  );
  $form['basic']['description'] = array(
    '#type' => 'textfield',
    '#title' => t('Description'),
    '#description' => t('This description will be shown to the user when as a hover tip when adding this pane.'),
    '#default_value' => $panel_view->description,
  );
  $form['basic']['category'] = array(
    '#type' => 'textfield',
    '#title' => t('Category'),
    '#category' => t('The category this view will appear in using the add content dialog.'),
    '#default_value' => $panel_view->category,
  );
  $form['basic']['category_weight'] = array(
    '#type' => 'select',
    '#default_value' => $panel_view->category_weight,
    '#title' => t('Category weight'),
    '#description' => t('The weight of the category; lower numbers will appear closer to the top of the dialog.'),
    '#options' => drupal_map_assoc(range(-10, 10)),
  );
  $form['basic']['view_type'] = array(
    '#type' => 'select',
    '#default_value' => $panel_view->view_type,
    '#title' => t('View type'),
    '#description' => t('Select which type of the view to display.'),
    '#options' => array(
      'page' => t('Page'),
      'block' => t('Block'),
      'embed' => t('Embedded'),
    ),
  );
  $form['contexts'] = array(
    '#tree' => TRUE,
  );
  views_load_cache();
  $arginfo = _views_get_arguments();
  panels_load_include('plugins');
  $contexts = panels_get_contexts();
  $context_options = array(
    'any' => t('Any context'),
  );
  foreach ($contexts as $name => $context) {
    $context_options[$name] = $context['title'];
  }
  asort($context_options);
  foreach ($panel_view->contexts as $id => $info) {
    $name = $arginfo[$view->argument[$id]['type']]['name'];
    $form['contexts'][$id] = array(
      '#type' => 'fieldset',
      '#title' => t('Argument: @arg', array(
        '@arg' => $name,
      )),
      '#tree' => TRUE,
    );
    $form['contexts'][$id]['type'] = array(
      '#type' => 'select',
      '#options' => array(
        'wildcard' => t('Argument wildcard'),
        'none' => t('No argument'),
        'context' => t('From context'),
        'panel' => t('From panel argument'),
        'fixed' => t('Fixed'),
        'user' => t('Input on pane config'),
      ),
      '#title' => t('Argument source'),
      '#default_value' => $panel_view->contexts[$id]['type'],
    );
    $form['contexts'][$id]['context'] = array(
      '#type' => 'select',
      '#title' => t('Required context'),
      '#description' => t('If "From context" is selected, which context to require.'),
      '#default_value' => $panel_view->contexts[$id]['context'],
      '#options' => $context_options,
    );
    $form['contexts'][$id]['panel'] = array(
      '#type' => 'select',
      '#title' => t('Panel argument'),
      '#description' => t('If "From panel argument" is selected, which panel argument to use.'),
      '#default_value' => $panel_view->contexts[$id]['panel'],
      '#options' => array(
        0 => t('First'),
        1 => t('Second'),
        2 => t('Third'),
        3 => t('Fourth'),
        4 => t('Fifth'),
        5 => t('Sixth'),
      ),
    );
    $form['contexts'][$id]['fixed'] = array(
      '#type' => 'textfield',
      '#title' => t('Fixed argument'),
      '#description' => t('If "Fixed" is selected, what to use as an argument.'),
      '#default_value' => $panel_view->contexts[$id]['fixed'],
    );
    $form['contexts'][$id]['label'] = array(
      '#type' => 'textfield',
      '#title' => t('Label'),
      '#description' => t('If this argument is presented to the panels user, what label to apply to it.'),
      '#default_value' => empty($panel_view->contexts[$id]['label']) ? $name : $panel_view->contexts[$id]['label'],
    );
  }
  $form['pager'] = array(
    '#type' => 'fieldset',
    '#title' => t('Paging information'),
  );
  $form['pager']['use_pager'] = array(
    '#type' => 'checkbox',
    '#title' => t('Use pager'),
    '#description' => t('Use a pager with this view'),
    '#default_value' => $panel_view->use_pager,
  );
  $form['pager']['pager_id'] = array(
    '#type' => 'textfield',
    '#title' => t('Pager ID'),
    '#description' => t('If using a pager, what pager ID to use; every pager on the page should be unique and you should always use the lowest pager ID available. Use 0 if at all possible.'),
    '#default_value' => $panel_view->pager_id,
  );
  $form['pager']['allow_use_pager'] = array(
    '#type' => 'checkbox',
    '#title' => t('Allow the pane configuration to modify the use pager setting.'),
    '#default_value' => $panel_view->allow_use_pager,
  );
  $form['pager']['nodes_per_page'] = array(
    '#type' => 'textfield',
    '#title' => t('Items to display'),
    '#description' => t('The maximum number of nodes to display.'),
    '#default_value' => $panel_view->nodes_per_page,
  );
  $form['pager']['allow_nodes_per_page'] = array(
    '#type' => 'checkbox',
    '#title' => t('Allow the pane configuration to modify the items to display setting'),
    '#default_value' => $panel_view->allow_nodes_per_page,
  );
  $form['pager']['offset'] = array(
    '#type' => 'textfield',
    '#title' => t('Offset'),
    '#description' => t('Enter the item number to start at; this option only works if "use pager" is not checked. Enter 0 to start at the first item, 1 to start at the second, etc.'),
    '#default_value' => $panel_view->offset,
  );
  $form['pager']['allow_offset'] = array(
    '#type' => 'checkbox',
    '#title' => t('Allow the pane configuration to modify the offset setting'),
    '#default_value' => $panel_view->allow_offset,
  );
  $form['deco'] = array(
    '#type' => 'fieldset',
    '#title' => t('Pane decorations'),
  );
  $form['deco']['link_to_view'] = array(
    '#type' => 'checkbox',
    '#title' => t('Link to view'),
    '#description' => t('If checked, link the title of the pane to the view.'),
    '#default_value' => $panel_view->link_to_view,
  );
  $form['deco']['allow_link_to_view'] = array(
    '#type' => 'checkbox',
    '#title' => t('Allow the pane configuration to modify the link to view setting.'),
    '#default_value' => $panel_view->allow_link_to_view,
  );
  $form['deco']['more_link'] = array(
    '#type' => 'checkbox',
    '#title' => t('More link'),
    '#description' => t('If checked, Panels will provide a "more" link that links to the view URL; this is different from the view\'s "more" link which will automatically be disabled.'),
    '#default_value' => $panel_view->more_link,
  );
  $form['deco']['allow_more_link'] = array(
    '#type' => 'checkbox',
    '#title' => t('Allow the pane configuration to modify the "more" link setting.'),
    '#default_value' => $panel_view->allow_more_link,
  );
  $form['deco']['more_text'] = array(
    '#type' => 'textfield',
    '#title' => t('More link text'),
    '#description' => t('If you checked the above box allowing Panels to provide its own "more" link, Panels will render that link using the text you enter here. If left blank, defaults to "more".'),
    '#default_value' => $panel_view->more_text,
  );
  $form['deco']['allow_more_text'] = array(
    '#type' => 'checkbox',
    '#title' => t('Allow the pane configuration to modify the "more" link text.'),
    '#default_value' => $panel_view->allow_more_text,
  );
  $form['deco']['feed_icons'] = array(
    '#type' => 'checkbox',
    '#title' => t('Show feed icons'),
    '#description' => t('If checked, any feed icons provided by the view will be visible in the pane.'),
    '#default_value' => $panel_view->feed_icons,
  );
  $form['deco']['allow_feed_icons'] = array(
    '#type' => 'checkbox',
    '#title' => t('Allow the pane configuration to modify the feed icon setting.'),
    '#default_value' => $panel_view->allow_feed_icons,
  );
  $form['deco']['url_override'] = array(
    '#type' => 'checkbox',
    '#title' => t('Override the panel URL with a manually set URL.'),
    '#default_value' => $panel_view->url_override,
  );
  $form['deco']['url'] = array(
    '#type' => 'textfield',
    '#title' => t('Override view URL'),
    '#description' => t('If override URL is set, the URL the view thinks it is using; all "more", "exposed filters", "summary" and "feed" type links will use this URL.') . ' ' . t('You may use $arg to pass panel arguments to the view.'),
    '#default_value' => $panel_view->url,
  );
  $form['deco']['allow_url_override'] = array(
    '#type' => 'checkbox',
    '#title' => t('Allow the pane configuration to modify the URL override setting.'),
    '#default_value' => $panel_view->allow_url_override,
  );
  $form['deco']['url_from_panel'] = array(
    '#type' => 'checkbox',
    '#title' => t('Set view URL to panel URL'),
    '#description' => t('If checked, the URL of the view will be changed to the URL of the panel; this setting is ignored if the "Override view URL" setting, above, is set or allowed.'),
    '#default_value' => $panel_view->url_from_panel,
  );
  $form['deco']['allow_url_from_panel'] = array(
    '#type' => 'checkbox',
    '#title' => t('Allow the pane configuration to modify the "set view URL to panel URL" setting.'),
    '#default_value' => $panel_view->allow_url_from_panel,
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save'),
  );
  return $form;
}

/**
 * Validate the edit form.
 */
function panels_views_edit_view_form_validate($form_id, $form_values, $form) {

  // Test uniqueness of name:
  if (!$form_values['name']) {
    form_error($form['basic']['name'], t('Panel view name is required.'));
  }
  else {
    if (preg_match("/[^A-Za-z0-9_]/", $form_values['name'])) {
      form_error($form['basic']['name'], t('Name must be alphanumeric or underscores only.'));
    }
    else {
      $query = "SELECT pvid FROM {panels_views} WHERE name = '%s'";
      if (!empty($form_values['pvid']) && is_numeric($form_values['pvid'])) {
        $query .= " AND pvid != {$form_values['pvid']}";
      }
      if (db_result(db_query($query, $form_values['name']))) {
        form_error($form['basic']['name'], t('Panel name must be unique.'));
      }
    }
  }
}

/**
 * Submit the edit form and save the values.
 */
function panels_views_edit_view_form_submit($form_id, $form_values) {
  $form_values['contexts'] = isset($form_values['contexts']) ? $form_values['contexts'] : array();
  $pv = new stdClass();
  foreach (array_keys(panels_views_pane_fields()) as $field) {
    $pv->{$field} = $form_values[$field];
  }
  panels_views_save($pv);
  drupal_set_message(t("The panel view has been saved."));
  return 'admin/panels/views';
}

/**
 * Provide a form to confirm deletion of a view pane.
 */
function panels_views_delete_confirm($panel_view) {
  if (!is_object($panel_view)) {
    $panel_view = panels_views_load($panel_view);
  }
  if (empty($panel_view) || empty($panel_view->pvid)) {
    return drupal_not_found();
  }
  $form['pvid'] = array(
    '#type' => 'value',
    '#value' => $panel_view->pvid,
  );
  return confirm_form($form, t('Are you sure you want to delete the panel view "@title"?', array(
    '@title' => $panel_view->title,
  )), $_GET['destination'] ? $_GET['destination'] : 'admin/panels/views', t('This action cannot be undone.'), t('Delete'), t('Cancel'));
}

/**
 * Handle the submit button to delete a view pane.
 */
function panels_views_delete_confirm_submit($form_id, $form) {
  if ($form['confirm']) {
    panels_views_delete((object) $form);
    return 'admin/panels/views';
  }
}

/**
 * Page callback to import a view pane.
 */
function panels_views_import_view() {
  if ($_POST['form_id'] == 'panels_views_edit_view_form') {
    $panel_view = $_SESSION['pv_import'];
    drupal_set_title(t('Import panel view "@s"', array(
      '@s' => $panel_view->title,
    )));
    $view = views_get_view($panel_view->view);
    return drupal_get_form('panels_views_edit_view_form', $view, $panel_view);
  }
  return drupal_get_form('panels_views_import_form');
}

/**
 * Form for the view pane import.
 */
function panels_views_import_form() {
  $form['panel_view'] = array(
    '#type' => 'textarea',
    '#title' => t('Panel view code'),
    '#cols' => 60,
    '#rows' => 15,
    '#description' => t('Cut and paste the results of an exported panel view here.'),
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Import'),
  );
  $form['#redirect'] = NULL;
  return $form;
}

/**
 * Handle the submit button on importing a view pane.
 */
function panels_views_import_form_submit($form_id, $form) {
  ob_start();
  eval($form['panel_view']);
  ob_end_clean();
  if (isset($panel_view)) {
    $view = views_get_view($panel_view->view);
    if (empty($view)) {
      drupal_set_message(t('Unable to load the view for that import. Be sure the view already exists in your system.'));
      return;
    }
    drupal_set_title(t('Import panel view "@s"', array(
      '@s' => $panel_view->title,
    )));
    $_SESSION['pv_import'] = $panel_view;
    $output = drupal_get_form('panels_views_edit_view_form', $view, $panel_view);
    print theme('page', $output);
    exit;
  }
  else {
    drupal_set_message(t('Unable to get a panel view out of that.'));
  }
}

/**
 * Page callback to export a view pane.
 */
function panels_views_export_view($pv, $prefix = '') {
  if (!is_object($pv)) {
    $pv = panels_views_load($pv);
  }
  if (empty($pv)) {
    return drupal_not_found();
  }
  drupal_set_title(check_plain($pv->title));
  $code = panels_views_export($pv);
  $lines = substr_count($code, "\n");
  $form['code'] = array(
    '#type' => 'textarea',
    '#title' => $pv->title,
    '#default_value' => $code,
    '#rows' => $lines,
  );
  return $form;
}

/**
 * Enable a default view pane.
 */
function panels_views_enable_page($name = NULL) {
  $defaults = panels_views_default_panels();
  if (isset($defaults[$name])) {
    $status = variable_get('panels_views_defaults', array());
    $status[$name] = FALSE;
    variable_set('panels_views_defaults', $status);
    drupal_set_message(t('Panel view enabled'));
  }
  drupal_goto();
}

/**
 * Disable a default view pane.
 */
function panels_views_disable_page($name = NULL) {
  $defaults = panels_views_default_panels();
  if (isset($defaults[$name])) {
    $status = variable_get('panels_views_defaults', array());
    $status[$name] = TRUE;
    variable_set('panels_views_defaults', $status);
    drupal_set_message(t('Panel view disabled'));
  }
  drupal_goto();
}

// -------------------------------------------------------------------------
// Content type routines.

/**
 * Implementation of hook_panels_content_types().
 */
function panels_views_panels_content_types() {
  $items['views2'] = array(
    'title' => t('View'),
    'content_types' => 'panels_views_content_types',
    'render callback' => 'panels_views_render',
    'add callback' => 'panels_views_edit',
    'edit callback' => 'panels_views_edit',
    'title callback' => 'panels_views_title',
    'add validate callback' => 'panels_views_edit_validate',
    'edit validate callback' => 'panels_views_edit_validate',
  );
  return $items;
}

/**
 * Return a list of each view type we support.
 */
function panels_views_content_types() {
  $panes = panels_views_load_all();
  $types = array();
  foreach ($panes as $name => $pv) {

    // Skip default but disabled panel views.
    if (!empty($pv->disabled)) {
      continue;
    }
    $contexts = array();
    if (!empty($pv->contexts)) {
      foreach ($pv->contexts as $context) {
        if ($context['type'] == 'context') {
          $contexts[] = new panels_required_context($context['label'], $context['context']);
        }
      }
    }
    $types[$name] = array(
      'title' => filter_xss_admin($pv->title),
      'icon' => $pv->view_type == 'block' ? 'icon_views_block.png' : 'icon_views_page.png',
      'description' => filter_xss_admin($pv->description),
      'path' => panels_get_path('content_types/views'),
      'required context' => $contexts,
      'category' => empty($pv->category) ? array(
        t('Views'),
        -1,
      ) : array(
        $pv->category,
        $pv->category_weight,
      ),
    );
  }
  return $types;
}

/**
 * Render a view as a pane.
 */
function panels_views_render($conf, $panel_args, &$contexts) {
  $pv = panels_views_load($conf['name']);
  if (empty($pv)) {
    return;
  }
  $v = views_get_view($pv->view);

  // no view, we go no further
  if (empty($v)) {
    return;
  }

  // Use clone to make sure this is fresh.
  $view = drupal_clone($v);

  // Check to make sure the user can view this view.
  if (function_exists('views_access') && !views_access($view)) {
    return;
  }
  $args = array();
  if (!empty($pv->contexts)) {
    foreach ($pv->contexts as $id => $data) {
      switch ($data['type']) {
        case 'context':
          $c = array_shift($contexts);
          $args[] = $c->argument;
          break;
        case 'fixed':
          $args[] = $data['fixed'];
          break;
        case 'panel':

          // Only fill $args if a panel arg was passed in that belongs there
          if (array_key_exists($data['panel'], $panel_args)) {
            $args[] = $panel_args[$data['panel']];
          }
          break;
        case 'user':
          $args[] = $conf['arguments'][$id];
          break;
        case 'wildcard':

          // Put in the wildcard.
          $args[] = $view->arguments[$id]['wildcard'] ? $view->arguments[$id]['wildcard'] : '*';
          break;
        case 'none':
        default:

          // Put in NULL.
          // views.module knows what to do with NULL (or missing) arguments
          $args[] = NULL;
          break;
      }
    }
  }
  if ($pv->allow_url_override && $conf['url']) {
    $view->url = $conf['url'];
  }
  else {
    if ($pv->url_override) {
      $view->url = $pv->url;
    }
  }
  $block = new stdClass();
  $block->module = 'views';
  $block->delta = $view->name;
  $view_type = $pv->view_type == 'embed' ? 'page' : $pv->view_type;
  $block->subject = views_get_title($view, $view_type, $args);

  // link to view
  if ($pv->allow_link_to_view && !empty($conf['link_to_view']) || !$pv->allow_link_to_view && $pv->link_to_view) {
    $block->title_link = views_get_url($view, $args);
  }

  // more link
  if ($pv->allow_more_link && !empty($conf['more_link']) || !$pv->allow_more_link && $pv->more_link) {
    $block->more = array(
      'href' => views_get_url($view, $args),
    );
    $view->block_more = FALSE;

    // Alternative "more" link text
    if ($pv->allow_more_text && $conf['more_text']) {
      $block->more['title'] = $conf['more_text'];
    }
    else {
      if ($pv->more_text) {
        $block->more['title'] = $pv->more_text;
      }
    }
  }

  // Turn on pager?
  if ($pv->allow_use_pager) {
    $pager_id = empty($conf['use_pager']) ? 0 : intval($conf['pager_id']) + 1;
  }
  else {
    $pager_id = empty($pv->use_pager) ? 0 : intval($pv->pager_id) + 1;
  }
  $nodes_per_page = $pv->allow_nodes_per_page ? $conf['nodes_per_page'] : $pv->nodes_per_page;
  $offset = $pv->allow_offset ? $conf['offset'] : $pv->offset;
  $stored_feeds = drupal_add_feed();

  // remove any trailing NULL arguments as these are non-args:
  while (count($args) && end($args) === NULL) {
    array_pop($args);
  }
  $block->content = views_build_view($pv->view_type, $view, $args, $pager_id, $nodes_per_page, 0, $offset);
  if ($view->num_rows < $nodes_per_page) {
    unset($block->more);
  }
  if ($pv->allow_feed_icons && !empty($conf['feed_icons']) || !$pv->allow_feed_icons && $pv->feed_icons) {
    $new_feeds = drupal_add_feed();
    if ($diff = array_diff(array_keys($new_feeds), array_keys($stored_feeds))) {
      foreach ($diff as $url) {
        $block->feeds[$url] = $new_feeds[$url];
      }
    }
  }

  // Provide administrative links
  if (user_access('administer views')) {
    $block->admin_links['update'] = array(
      'title' => t('Edit view'),
      'alt' => t("Edit this view"),
      'href' => $view->vid ? "admin/build/views/{$view->name}/edit" : "admin/build/views/add/{$view->name}",
      'query' => drupal_get_destination(),
    );
  }
  return $block;
}

/**
 * Provide the pane edit dialog.
 */
function panels_views_edit($id, $parents, $conf = array()) {
  $pv = panels_views_load($id);
  if (empty($pv)) {
    $form['markup'] = array(
      '#value' => t('The view for this pane is not valid or has been deleted from the system. This pane cannot render; you must either delete this pane or restore the panel view. If you save this pane and then restore the panel view, your settings may be lost.'),
    );
    return $form;
  }

  // Provide defaults for the items we let the user edit.
  if (empty($conf)) {
    if ($pv->allow_type) {
      $conf['view_type'] = $pv->view_type;
    }
    if ($pv->allow_link_to_view) {
      $conf['link_to_view'] = $pv->link_to_view;
    }
    if ($pv->allow_more_link) {
      $conf['more_link'] = $pv->more_link;
    }
    if ($pv->allow_more_text) {
      $conf['more_text'] = $pv->more_text;
    }
    if ($pv->allow_feed_icons) {
      $conf['feed_icons'] = $pv->feed_icons;
    }
    if ($pv->allow_use_pager) {
      $conf['use_pager'] = $pv->use_pager;
      $conf['pager_id'] = $pv->pager_id;
    }
    if ($pv->allow_nodes_per_page) {
      $conf['nodes_per_page'] = $pv->nodes_per_page;
    }
    if ($pv->allow_offset) {
      $conf['offset'] = $pv->offset;
    }
    if ($pv->allow_url_override) {
      $conf['url'] = $pv->url;
    }
    if ($pv->allow_url_from_panel) {
      $conf['url_from_panel'] = $pv->url_from_panel;
    }
  }
  $form['title'] = array(
    '#type' => 'hidden',
    '#value' => $pv->title,
  );
  $form['name'] = array(
    '#type' => 'hidden',
    '#value' => $id,
  );
  foreach ($pv->contexts as $id => $data) {
    if ($data['type'] == 'user') {
      $form['arguments'][$id] = array(
        '#type' => 'textfield',
        '#default_value' => $conf['arguments'][$id],
        '#title' => $data['label'],
      );
    }
  }

  // Provide form gadgets only on the things that th euser can change.
  if ($pv->allow_type) {
    $form['view_type'] = array(
      '#type' => 'select',
      '#default_value' => $conf['view_type'],
      '#title' => t('View type'),
      '#description' => t('Select which type of the view to display.'),
      '#options' => array(
        'page' => t('Page'),
        'block' => t('Block'),
        'embed' => t('Embedded'),
      ),
    );
  }
  if ($pv->allow_link_to_view) {
    $form['link_to_view'] = array(
      '#type' => 'checkbox',
      '#default_value' => $conf['link_to_view'],
      '#title' => t('Link title to view'),
      '#description' => t('If checked, the title will be a link to the view.'),
    );
  }
  if ($pv->allow_more_link) {
    $form['more_link'] = array(
      '#type' => 'checkbox',
      '#default_value' => $conf['more_link'],
      '#title' => t('Provide a "more" link that links to the view'),
      '#description' => t('This is independent of any more link that may be provided by the view itself; if you see two more links, turn this one off. Views will only provide a more link if using the "block" type, however, so if using embed, use this one.'),
    );
    if ($pv->allow_more_text) {
      $form['more_text'] = array(
        '#type' => 'textfield',
        '#default_value' => $conf['more_text'],
        '#title' => t('"More" link text'),
        '#description' => t('If you activated panels own "more" link above, this allows you to customize the text to display.'),
      );
    }
  }
  if ($pv->allow_feed_icons) {
    $form['feed_icons'] = array(
      '#type' => 'checkbox',
      '#default_value' => $conf['feed_icons'],
      '#title' => t('Display feed icons'),
      '#description' => t('If checked, any feed icons provided by this view will be displayed.'),
    );
  }
  if ($pv->allow_use_pager) {
    $form['pager_aligner_start'] = array(
      '#value' => '<div class="option-text-aligner">',
    );
    $form['use_pager'] = array(
      '#type' => 'checkbox',
      '#title' => t('Use pager'),
      '#default_value' => $conf['use_pager'],
      '#id' => 'use-pager-checkbox',
    );
    $form['pager_id'] = array(
      '#type' => 'textfield',
      '#default_value' => $conf['pager_id'],
      '#title' => t('Pager ID'),
      '#size' => 4,
      '#id' => 'use-pager-textfield',
    );
    $form['pager_aligner_stop'] = array(
      '#value' => '</div><div style="clear: both; padding: 0; margin: 0"></div>',
    );
  }
  if ($pv->allow_nodes_per_page) {
    $form['nodes_per_page'] = array(
      '#type' => 'textfield',
      '#default_value' => $conf['nodes_per_page'],
      '#title' => t('Num posts'),
      '#size' => 4,
      '#description' => t('Select the number of posts to display, or 0 to display all results.'),
    );
  }
  if ($pv->allow_offset) {
    $form['offset'] = array(
      '#type' => 'textfield',
      '#default_value' => $conf['offset'],
      '#title' => t('Offset'),
      '#size' => 4,
      '#description' => t('Enter the item number to start at; this option only works if "use pager" is not checked. Enter 0 to start at the first item, 1 to start at the second, etc.'),
    );
  }
  if ($pv->allow_url_override) {

    // TODO: Because javascript in the dialogs is kind of weird, dependent checkboxes
    // don't work right for external modules. This needs fixing in panels itself.
    $form['url'] = array(
      '#type' => 'textfield',
      '#default_value' => $conf['url'],
      '#title' => t('Override URL'),
      '#size' => 30,
      '#description' => t('If this is set, override the View URL; this can sometimes be useful to set to the panel URL.') . ' ' . t('You may use $arg to pass panel arguments to the view.'),
    );
  }
  if ($pv->allow_url_from_panel) {
    $form['url_from_panel'] = array(
      '#type' => 'checkbox',
      '#title' => t('Set view URL to panel URL'),
      '#default_value' => $conf['url_from_panel'],
    );
  }
  return $form;
}

/**
 * Returns the administrative title for a type.
 */
function panels_views_title($conf) {
  return $conf['title'];
}

// -------------------------------------------------------------------------
// Panels views helpers.

/**
 * Get a list of all views as an option array.
 *
 * This really should be included with views.
 */
function panels_views_get_all_views() {
  views_load_cache();
  $result = db_query("SELECT name, description FROM {view_view} ORDER BY name");
  $views = array();
  while ($view = db_fetch_object($result)) {
    $views[$view->name] = check_plain($view->name);
  }
  $default_views = _views_get_default_views();
  $views_status = variable_get('views_defaults', array());
  foreach ($default_views as $view) {
    if (!$views[$view->name] && ($views_status[$view->name] == 'enabled' || !$views_status[$view->name] && !$view->disabled)) {
      $views[$view->name] = check_plain($view->name);
    }
  }
  return $views;
}

// -------------------------------------------------------------------------
// Database routines

/**
 * Poor man's schema API.
 */
function panels_views_pane_fields() {

  // Schema version 0
  $names = array(
    'pvid' => array(
      'default' => 'NULL',
      'arg' => '%d',
      'definition' => 'integer NOT NULL PRIMARY KEY',
      'primary' => TRUE,
    ),
    'view' => array(
      'default' => '',
      'arg' => "'%s'",
      'definition' => 'varchar(255)',
    ),
    'name' => array(
      'default' => '',
      'arg' => "'%s'",
      'definition' => 'varchar(255) UNIQUE',
    ),
    'description' => array(
      'default' => '',
      'arg' => "'%s'",
      'definition' => 'varchar(255)',
    ),
    'title' => array(
      'default' => '',
      'arg' => "'%s'",
      'definition' => 'varchar(255)',
    ),
    'category' => array(
      'default' => 'Views',
      'arg' => "'%s'",
      'definition' => 'varchar(255)',
    ),
    'category_weight' => array(
      'default' => -1,
      'arg' => "%d",
      'definition' => 'integer',
    ),
    'view_type' => array(
      'default' => '',
      'arg' => "'%s'",
      'definition' => 'varchar(255)',
    ),
    'use_pager' => array(
      'default' => FALSE,
      'arg' => '%d',
      'definition' => 'integer',
    ),
    'pager_id' => array(
      'default' => 0,
      'arg' => '%d',
      'definition' => 'integer',
    ),
    'nodes_per_page' => array(
      'default' => 0,
      'arg' => '%d',
      'definition' => 'integer',
    ),
    'offset' => array(
      'default' => 0,
      'arg' => '%d',
      'definition' => 'integer',
    ),
    'link_to_view' => array(
      'default' => FALSE,
      'arg' => '%d',
      'definition' => 'integer',
    ),
    'more_link' => array(
      'default' => FALSE,
      'arg' => '%d',
      'definition' => 'integer',
    ),
    'more_text' => array(
      'default' => '',
      'arg' => "'%s'",
      'definition' => 'varchar(255)',
    ),
    'feed_icons' => array(
      'default' => FALSE,
      'arg' => '%d',
      'definition' => 'integer',
    ),
    'url_override' => array(
      'default' => FALSE,
      'arg' => '%d',
      'definition' => 'integer',
    ),
    'url' => array(
      'default' => '',
      'arg' => "'%s'",
      'definition' => 'varchar(255)',
    ),
    'url_from_panel' => array(
      'default' => FALSE,
      'arg' => '%d',
      'definition' => 'integer',
    ),
    'contexts' => array(
      'default' => array(),
      'arg' => "'%s'",
      'serialize' => TRUE,
      'definition' => 'text',
    ),
    // Whether or not array these things are allowed from the pane UI.
    'allow_type' => array(
      'default' => FALSE,
      'arg' => '%d',
      'definition' => 'integer',
    ),
    'allow_nodes_per_page' => array(
      'default' => FALSE,
      'arg' => '%d',
      'definition' => 'integer',
    ),
    'allow_offset' => array(
      'default' => FALSE,
      'arg' => '%d',
      'definition' => 'integer',
    ),
    'allow_use_pager' => array(
      'default' => FALSE,
      'arg' => '%d',
      'definition' => 'integer',
    ),
    'allow_link_to_view' => array(
      'default' => FALSE,
      'arg' => '%d',
      'definition' => 'integer',
    ),
    'allow_more_link' => array(
      'default' => FALSE,
      'arg' => '%d',
      'definition' => 'integer',
    ),
    'allow_more_text' => array(
      'default' => FALSE,
      'arg' => '%d',
      'definition' => 'integer',
    ),
    'allow_feed_icons' => array(
      'default' => FALSE,
      'arg' => '%d',
      'definition' => 'integer',
    ),
    'allow_url_override' => array(
      'default' => FALSE,
      'arg' => '%d',
      'definition' => 'integer',
    ),
    'allow_url_from_panel' => array(
      'default' => FALSE,
      'arg' => '%d',
      'definition' => 'integer',
    ),
  );
  return $names;
}

/**
 * Provide default settings for a new view pane.
 */
function panels_views_default_view_pane($view) {
  $names = panels_views_pane_fields();
  $panel_view = new stdClass();
  foreach ($names as $name => $info) {
    $panel_view->{$name} = $info['default'];
  }
  $panel_view->view = $panel_view->name = $view->name;
  $panel_view->description = $view->description;
  if ($view->page) {
    $panel_view->view_type = 'page';
    $panel_view->nodes_per_page = $view->nodes_per_page;
    $panel_view->title = $view->page_title;
  }
  else {
    $panel_view->view_type = 'block';
    $panel_view->nodes_per_page = $view->nodes_per_block;
    $panel_view->title = $view->block_title;
  }
  return $panel_view;
}

/**
 * Adjust a pane for a view's arguments, adding or subtracting as needed to
 * match the current view's argument configuration.
 */
function panels_views_pane_arguments($view, &$panel_view) {
  $contexts = array();
  foreach ($view->argument as $id => $arg) {
    if (empty($panel_view->contexts[$id])) {
      $contexts[$id] = array(
        'type' => 'context',
        'context' => 'any',
        'panel' => 0,
        'fixed' => '',
      );
    }
    else {
      $contexts[$id] = $panel_view->contexts[$id];
    }
  }

  // By copying this back, we automatically erase any arguments that may
  // no longer exist.
  $panel_view->contexts = $contexts;
}

/**
 * Write a view pane to the database.
 */
function panels_views_save($panel_view) {
  $fields = $types = $values = $pairs = array();

  // If pvid is empty, this is an insert, otherwise an update.
  $insert = empty($panel_view->pvid);

  // Build arrays of fields and types (resp. pairs of both) and of values.
  foreach (panels_views_pane_fields() as $field => $data) {
    $primary = !empty($data['primary']);

    // Skip primary key and empty values.
    if (!$primary && isset($panel_view->{$field})) {
      if ($insert) {
        $fields[] = $field;
        $types[] = $data['arg'];
      }
      else {
        $pairs[] = "{$field} = {$data['arg']}";
      }

      // Build the $values array, serializing some fields.
      $serialize = !empty($data['serialize']);
      $values[] = $serialize ? serialize($panel_view->{$field}) : $panel_view->{$field};
    }
  }
  if ($insert) {

    // Determine the new primary key.
    $panel_view->pvid = db_next_id('{panels_views}_pvid');

    // Build the query adding the new primary key.
    $sql = 'INSERT INTO {panels_views} (' . implode(', ', $fields) . ', pvid) VALUES (' . implode(', ', $types) . ', %d)';
  }
  else {

    // Build the query filtering by the primary key.
    $sql = 'UPDATE {panels_views} SET ' . implode(', ', $pairs) . ' WHERE pvid = %d';
  }
  $values[] = $panel_view->pvid;
  db_query($sql, $values);
}

/**
 * Load a view pane from the database.
 */
function panels_views_load($name) {
  static $panel_views = array();
  if (array_key_exists($name, $panel_views)) {
    return $panel_views[$name];
  }
  $pv = db_fetch_object(db_query("SELECT * FROM {panels_views} WHERE name = '%s'", $name));
  if (empty($pv)) {
    $defaults = panels_views_default_panels();
    if (isset($defaults[$name])) {
      $pv = $defaults[$name];
      $status = variable_get('panels_views_defaults', array());

      // Determine if default panel is enabled or disabled.
      if (isset($status[$pv->name])) {
        $pv->disabled = $status[$pv->name];
      }
      $panel_views[$name] = $pv;
      return $pv;
    }
    $panel_views[$name] = NULL;
    return;
  }
  $names = panels_views_pane_fields();
  foreach ($names as $key => $data) {
    if (!empty($data['serialize'])) {
      $pv->{$key} = unserialize($pv->{$key});
    }
  }
  $panel_views[$name] = $pv;
  return $panel_views[$name];
}

/**
 * Load all view panes.
 */
function panels_views_load_all() {
  static $panel_views = NULL;
  if (isset($panel_views)) {
    return $panel_views;
  }
  $panel_views = array();
  $names = panels_views_pane_fields();
  $result = db_query("SELECT * FROM {panels_views}");
  while ($pv = db_fetch_object($result)) {
    foreach ($names as $name => $data) {
      if (!empty($data['serialize'])) {
        $pv->{$name} = unserialize($pv->{$name});
      }
    }
    $pv->type = t('Local');
    $panel_views[$pv->name] = $pv;
  }

  // Now load all the in-code versions
  $status = variable_get('panels_views_defaults', array());
  foreach (panels_views_default_panels() as $pv) {

    // Determine if default panel is enabled or disabled.
    if (isset($status[$pv->name])) {
      $pv->disabled = $status[$pv->name];
    }
    if (!empty($panel_views[$pv->name])) {
      $panel_views[$pv->name]->type = t('Overridden');
    }
    else {
      $pv->type = t('Default');
      $panel_views[$pv->name] = $pv;
    }
  }
  return $panel_views;
}

/**
 * Get all 'default' view panes.
 *
 * @ingroup HookInvokers
 */
function panels_views_default_panels() {
  $panels = module_invoke_all('default_panel_views');
  if (!is_array($panels)) {
    $panels = array();
  }
  return $panels;
}

/**
 * Delete a view pane.
 */
function panels_views_delete($pv) {
  db_query("DELETE FROM {panels_views} WHERE pvid = %d", $pv->pvid);
  return TRUE;
}

/**
 * Export a view pane into PHP code.
 *
 * This code is suitable to run through eval()
 * and then be used in panels_views_save().
 */
function panels_views_export($pv, $prefix = '') {
  $output = '';
  $fields = panels_views_pane_fields();
  $output .= $prefix . '$panel_view = new stdClass()' . ";\n";
  foreach ($fields as $field => $data) {
    $value = empty($data['primary']) ? $pv->{$field} : 'new';
    $output .= $prefix . '  $panel_view->' . $field . ' = ' . panels_var_export($value, '  ') . ";\n";
  }
  return $output;
}

/**
 * Implementation of hook_panels_exportables().
 */
function panels_views_panels_exportables($op = 'list', $panels = NULL, $name = 'foo') {
  static $all_panels = NULL;
  if ($op == 'list') {
    if (empty($all_panels)) {
      $all_panels = panels_views_load_all();
    }
    foreach ($all_panels as $name => $panel) {
      $return[$name] = check_plain($name) . ' (' . check_plain($panel->title) . ')';
    }
    return $return;
  }
  if ($op == 'export') {
    $code = "/**\n";
    $code .= " * Implementation of hook_default_panel_views().\n";
    $code .= " */\n";
    $code .= "function " . $name . "_default_panel_views() {\n";
    foreach ($panels as $panel => $truth) {
      $code .= panels_views_export($all_panels[$panel], '  ');
      $code .= '  $panel_views[\'' . check_plain($panel) . '\'] = $panel_view;' . "\n\n\n";
    }
    $code .= "  return \$panel_views;\n";
    $code .= "}\n";
    return $code;
  }
}

/**
 * Implementation of hook_form_alter().
 *
 * Ugly, hacky fix to compensate for the fact that panels_views isn't aware when
 * views changes the system name of a view. With the system name wrong,
 * panels_views breaks.
 */
function panels_views_form_alter($form_id, &$form) {
  if ($form_id == 'views_edit_view' && !empty($form['basic-info']['name']['#default_value'])) {
    $pvids = array();
    $result = db_query("SELECT pvid FROM {panels_views} WHERE view = '%s'", $form['basic-info']['name']['#default_value']);
    while ($row = db_fetch_object($result)) {
      $pvids[] = $row->pvid;
    }
    if (!empty($pvids)) {
      $form['dependent_pvids'] = array(
        '#type' => 'value',
        '#value' => $pvids,
      );
      $form['#submit'] += array(
        'panels_views_update_pvids_submit' => array(),
      );
    }
  }
}

/**
 * If we've gotten this far, then we know we've got pvids that could need
 * updating. Don't bother with fancy footwork to see if the view name was
 * actually changed - just update em to be safe. Also no need to update
 * the whole view pane, so we just batch update using IN ().
 *
 */
function panels_views_update_pvids_submit($form_id, $form_values) {
  db_query("UPDATE {panels_views} SET view = '%s' WHERE pvid IN (" . implode(', ', $form_values['dependent_pvids']) . ")", $form_values['name']);
}

Functions

Namesort descending Description
panels_views_add_view Page callback to add a new view pane from an existing view.
panels_views_add_view_form Form to select a view for creating a new view pane.
panels_views_add_view_form_submit
panels_views_content_types Return a list of each view type we support.
panels_views_default_panels Get all 'default' view panes.
panels_views_default_view_pane Provide default settings for a new view pane.
panels_views_delete Delete a view pane.
panels_views_delete_confirm Provide a form to confirm deletion of a view pane.
panels_views_delete_confirm_submit Handle the submit button to delete a view pane.
panels_views_disable_page Disable a default view pane.
panels_views_edit Provide the pane edit dialog.
panels_views_edit_view Page callback to edit a view pane.
panels_views_edit_view_form Form to add or edit add a view pane.
panels_views_edit_view_form_submit Submit the edit form and save the values.
panels_views_edit_view_form_validate Validate the edit form.
panels_views_enable_page Enable a default view pane.
panels_views_export Export a view pane into PHP code.
panels_views_export_view Page callback to export a view pane.
panels_views_form_alter Implementation of hook_form_alter().
panels_views_get_all_views Get a list of all views as an option array.
panels_views_import_form Form for the view pane import.
panels_views_import_form_submit Handle the submit button on importing a view pane.
panels_views_import_view Page callback to import a view pane.
panels_views_list_views Page callback to list view panes and the initial form to add new view panes.
panels_views_load Load a view pane from the database.
panels_views_load_all Load all view panes.
panels_views_menu Implementation of hook_menu().
panels_views_panels_content_types Implementation of hook_panels_content_types().
panels_views_panels_exportables Implementation of hook_panels_exportables().
panels_views_pane_arguments Adjust a pane for a view's arguments, adding or subtracting as needed to match the current view's argument configuration.
panels_views_pane_fields Poor man's schema API.
panels_views_perm Implementation of hook_perm().
panels_views_render Render a view as a pane.
panels_views_save Write a view pane to the database.
panels_views_title Returns the administrative title for a type.
panels_views_update_pvids_submit If we've gotten this far, then we know we've got pvids that could need updating. Don't bother with fancy footwork to see if the view name was actually changed - just update em to be safe. Also no need to update the whole view pane, so…
theme_panels_views_add_view_form