You are here

panels_mini.module in Panels 5.2

panels_mini.module

This module provides mini panels which are basically panels that can be used within blocks or other panels.

File

panels_mini/panels_mini.module
View source
<?php

/**
 * @file panels_mini.module
 *
 * This module provides mini panels which are basically panels that can be
 * used within blocks or other panels.
 */

/**
 * Implementation of hook_help().
 */
function panels_mini_help($section = '') {
  switch ($section) {
    case 'admin/panels/panel-mini':
    case 'admin/panels/panel-mini/list':
      $output = '<p>';
      $output .= t('You can edit existing mini panels, or click add to create a new one.');
      $output .= '</p>';
      break;
    case 'admin/panels/panel-mini/add':
      $output = '<p>';
      $output .= t('Mini panels are the small variants of panel pages. Instead of pages, they define blocks.');
      $output .= '</p>';
      break;
  }
  return $output;
}

/**
 * Implementation of hook_perm().
 */
function panels_mini_perm() {
  return array(
    'create mini panels',
    'administer mini panels',
  );
}

/**
 * Implementation of hook_menu().
 */
function panels_mini_menu($may_cache) {
  if ($may_cache) {
    $access = user_access('create mini panels');
    $items[] = array(
      'path' => 'admin/panels/panel-mini',
      'title' => t('Mini panels'),
      'access' => $access,
      'callback' => 'panels_mini_list_page',
      'description' => t('Create and administer mini panels (panels exposed as blocks).'),
    );
    $items[] = array(
      'path' => 'admin/panels/panel-mini/list',
      'title' => t('List'),
      'access' => $access,
      'callback' => 'panels_mini_list_page',
      'weight' => -10,
      'type' => MENU_DEFAULT_LOCAL_TASK,
    );
    $items[] = array(
      'path' => 'admin/panels/panel-mini/add',
      'title' => t('Add'),
      'access' => $access,
      'callback' => 'panels_mini_add_page',
      'type' => MENU_LOCAL_TASK,
    );
    $items[] = array(
      'path' => 'admin/panels/panel-mini/import',
      'title' => t('Import'),
      'access' => $access,
      'callback' => 'panels_mini_import_mini',
      'type' => MENU_LOCAL_TASK,
    );
    $items[] = array(
      'path' => 'admin/panels/panel-mini/settings',
      'title' => t('Settings'),
      'access' => $access,
      'callback' => 'panels_mini_settings',
      'type' => MENU_LOCAL_TASK,
    );
    $items[] = array(
      'path' => 'admin/panels/panel-mini/disable',
      'access' => $access,
      'callback' => 'panels_mini_disable_page',
      'weight' => -1,
      'type' => MENU_CALLBACK,
    );
    $items[] = array(
      'path' => 'admin/panels/panel-mini/enable',
      'access' => $access,
      'callback' => 'panels_mini_enable_page',
      'weight' => -1,
      'type' => MENU_CALLBACK,
    );
  }
  else {
    if (arg(0) == 'admin' && arg(1) == 'panels' && arg(2) == 'panel-mini') {
      $mini = panels_mini_load(arg(3));
      if ($mini && empty($mini->disabled)) {
        $items = array();
        panels_mini_menu_items($items, "admin/panels/panel-mini/{$mini->name}", $mini);
      }
    }
  }
  return $items;
}
function panels_mini_menu_items(&$items, $base, $panel_mini) {
  $access = user_access('administer mini panels');
  if ($access) {
    $items[] = array(
      'path' => $base,
      'title' => t('Preview'),
      'access' => $access,
      'callback' => 'panels_mini_preview_panel',
      'callback arguments' => array(
        $panel_mini,
      ),
      'weight' => -10,
      'type' => MENU_CALLBACK,
    );
    $items[] = array(
      'path' => $base . '/preview',
      'title' => t('Preview'),
      'access' => $access,
      'callback' => 'panels_mini_preview_panel',
      'callback arguments' => array(
        $panel_mini,
      ),
      'weight' => -10,
      'type' => MENU_DEFAULT_LOCAL_TASK,
    );
    $items[] = array(
      'path' => $base . '/edit/layout',
      'title' => t('Layout'),
      'access' => $access,
      'callback' => 'panels_mini_edit_layout',
      'callback arguments' => array(
        $panel_mini,
      ),
      'weight' => -9,
      'type' => MENU_LOCAL_TASK,
    );
    $items[] = array(
      'path' => $base . '/edit/general',
      'title' => t('Settings'),
      'access' => $access,
      'callback' => 'panels_mini_edit',
      'callback arguments' => array(
        $panel_mini,
      ),
      'weight' => -5,
      'type' => MENU_LOCAL_TASK,
    );
    $items[] = array(
      'path' => $base . '/edit/settings',
      'title' => t('Layout settings'),
      'access' => $access,
      'callback' => 'panels_mini_edit_layout_settings',
      'callback arguments' => array(
        $panel_mini,
      ),
      'weight' => -3,
      'type' => MENU_LOCAL_TASK,
    );
    $items[] = array(
      'path' => $base . '/edit/context',
      'title' => t('Context'),
      'access' => $access,
      'callback' => 'panels_mini_edit_context',
      'callback arguments' => array(
        $panel_mini,
      ),
      'weight' => -2,
      'type' => MENU_LOCAL_TASK,
    );
    $items[] = array(
      'path' => $base . '/edit/content',
      'title' => t('Content'),
      'access' => $access,
      'callback' => 'panels_mini_edit_content',
      'callback arguments' => array(
        $panel_mini,
      ),
      'weight' => -1,
      'type' => MENU_LOCAL_TASK,
    );
    $items[] = array(
      'path' => $base . '/export',
      'title' => t('Export'),
      'access' => $access,
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'panels_mini_edit_export',
        $panel_mini,
      ),
      'weight' => 0,
      'type' => MENU_LOCAL_TASK,
    );
    $items[] = array(
      'path' => $base . '/delete',
      'title' => t('Delete mini panel'),
      'access' => user_access('create mini panels'),
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'panels_mini_delete_confirm',
        $panel_mini,
      ),
      'type' => MENU_CALLBACK,
    );
  }
}

// ---------------------------------------------------------------------------
// Mini panel administrative pages.

/**
 * Settings for mini panels.
 */
function panels_mini_settings() {
  panels_load_include('common');
  return drupal_get_form('panels_common_settings', 'panels_mini');
}

/**
 * Provide a list of mini panels, with links to edit or delete them.
 */
function panels_mini_list_page() {
  panels_load_include('plugins');
  $layouts = panels_get_layouts();
  $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',
    ),
    t('Layout'),
    t('Operations'),
  );

  // Load all mini panels and their displays.
  $panel_minis = panels_mini_load_all();
  $dids = array();
  foreach ($panel_minis as $panel_mini) {
    if (empty($panel_mini->display)) {
      $dids[] = $panel_mini->did;
    }
  }
  $displays = panels_load_displays($dids);
  foreach ($panel_minis as $panel_mini) {
    $ops = array();
    if (empty($panel_mini->disabled)) {
      $ops[] = l(t('Edit'), "admin/panels/panel-mini/{$panel_mini->name}/edit/general");
      $ops[] = l(t('Export'), "admin/panels/panel-mini/{$panel_mini->name}/export");
    }
    if ($panel_mini->type != t('Default')) {
      $text = $panel_mini->type == t('Overridden') ? t('Revert') : t('Delete');
      $ops[] = l($text, "admin/panels/panel-mini/{$panel_mini->name}/delete");
    }
    else {
      if (empty($panel_mini->disabled)) {
        $ops[] = l(t('Disable'), "admin/panels/panel-mini/disable/{$panel_mini->name}", NULL, drupal_get_destination());
      }
      else {
        $ops[] = l(t('Enable'), "admin/panels/panel-mini/enable/{$panel_mini->name}", NULL, drupal_get_destination());
      }
    }
    $item = array();
    $item[] = check_plain($panel_mini->title);
    $item[] = check_plain($panel_mini->name);

    // this is safe as it's always programmatic
    $item[] = $panel_mini->type;
    if (empty($panel_mini->display)) {
      $panel_mini->display = $displays[$panel_mini->did];
    }
    $item[] = check_plain($layouts[$panel_mini->display->layout]['title']);
    $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_mini->type . $item[0];
        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);
  return $output;
}

/**
 * Provide a form to confirm deletion of a mini panel.
 */
function panels_mini_delete_confirm($panel_mini) {
  if (!is_object($panel_mini)) {
    $panel_mini = panels_mini_load($panel_mini);
  }
  $form['pid'] = array(
    '#type' => 'value',
    '#value' => $panel_mini->pid,
  );
  $form['did'] = array(
    '#type' => 'value',
    '#value' => $panel_mini->did,
  );
  return confirm_form($form, t('Are you sure you want to delete the mini panel "@title"?', array(
    '@title' => $panel_mini->title,
  )), $_GET['destination'] ? $_GET['destination'] : 'admin/panels/panel-mini', t('This action cannot be undone.'), t('Delete'), t('Cancel'));
}

/**
 * Handle the submit button to delete a mini panel.
 */
function panels_mini_delete_confirm_submit($form_id, $form) {
  if ($form['confirm']) {
    panels_mini_delete((object) $form);
    return 'admin/panels/panel-mini';
  }
}

/**
 * Provide an administrative preview of a mini panel.
 */
function panels_mini_preview_panel($mini) {
  $mini->display->args = array();
  $mini->display->css_id = panels_mini_get_id($mini->name);
  panels_load_include('plugins');
  $mini->context = $mini->display->context = panels_context_load_contexts($mini);
  drupal_set_title(filter_xss_admin($mini->title));
  return panels_render_display($mini->display);
}

/**
 * Page callback to export a mini panel to PHP code.
 */
function panels_mini_edit_export($panel_mini) {
  if (!is_object($panel_mini)) {
    $panel_mini = panels_mini_load($panel_mini);
  }
  drupal_set_title(check_plain($panel_mini->title));
  $code = panels_mini_export($panel_mini);
  $lines = substr_count($code, "\n");
  $form['code'] = array(
    '#type' => 'textarea',
    '#title' => $panel_mini->title,
    '#default_value' => $code,
    '#rows' => $lines,
  );
  return $form;
}

/**
 * Page callback to import a mini panel from PHP code.
 */
function panels_mini_import_mini() {
  if ($_POST['form_id'] == 'panels_mini_edit_form') {
    $panel_mini = unserialize($_SESSION['pm_import']);
    drupal_set_title(t('Import panel mini "@s"', array(
      '@s' => $panel_mini->title,
    )));
    return drupal_get_form('panels_mini_edit_form', $panel_mini);
  }
  return drupal_get_form('panels_mini_import_form');
}

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

/**
 * Handle the submit button on importing a mini panel.
 */
function panels_mini_import_form_submit($form_id, $form) {
  ob_start();
  eval($form['panel_mini']);
  ob_end_clean();
  if (isset($mini)) {
    drupal_set_title(t('Import mini panel "@s"', array(
      '@s' => $mini->title,
    )));

    // As $mini contains non-stdClass objects,
    // it needs to be serialized before being stored in the session variable.
    $_SESSION['pm_import'] = serialize($mini);
    $output = drupal_get_form('panels_mini_edit_form', $mini);
    print theme('page', $output);
    exit;
  }
  else {
    drupal_set_message(t('Unable to get a mini panel out of that.'));
  }
}

/**
 * Handle the add mini panel page.
 */
function panels_mini_add_page($layout = NULL) {
  panels_load_include('plugins');
  $layouts = panels_get_layouts();
  if ($layout === NULL) {
    foreach ($layouts as $id => $layout) {
      $output .= panels_print_layout_link($id, $layout, $_GET['q'] . '/' . $id);
    }
    return $output;
  }
  if (!$layouts[$layout]) {
    return drupal_not_found();
  }
  $panel_mini = new stdClass();
  $panel_mini->display = panels_new_display();
  $panel_mini->display->layout = $layout;
  $panel_mini->pid = 'new';
  $panel_mini->did = 'new';
  return panels_mini_edit($panel_mini);
}

/**
 * Edit a mini panel.
 *
 * Called from both the add and edit points to provide for common flow.
 */
function panels_mini_edit($panel_mini) {
  if (!is_object($panel_mini)) {
    $panel_mini = panels_mini_load($panel_mini);
  }
  drupal_set_title(check_plain($panel_mini->title));
  return drupal_get_form('panels_mini_edit_form', $panel_mini);
}

/**
 * Form to edit the settings of a mini panel.
 */
function panels_mini_edit_form($panel_mini) {
  panels_load_include('common');
  drupal_add_css(panels_get_path('css/panels_admin.css'));
  $form['pid'] = array(
    '#type' => 'value',
    '#value' => $panel_mini->pid,
  );
  $form['panel_mini'] = array(
    '#type' => 'value',
    '#value' => $panel_mini,
  );
  $form['right'] = array(
    '#prefix' => '<div class="layout-container">',
    '#suffix' => '</div>',
  );
  $form['left'] = array(
    '#prefix' => '<div class="info-container">',
    '#suffix' => '</div>',
  );
  $form['left']['settings'] = array(
    '#type' => 'fieldset',
    '#title' => t('Settings'),
  );
  $form['left']['settings']['title'] = array(
    '#type' => 'textfield',
    '#size' => 24,
    '#default_value' => $panel_mini->title,
    '#title' => t('Mini panel title'),
    '#description' => t('The title for this mini panel. It can be overridden in the block configuration.'),
  );
  $form['left']['settings']['name'] = array(
    '#type' => 'textfield',
    '#size' => 24,
    '#default_value' => $panel_mini->name,
    '#title' => t('Mini panel name'),
    '#description' => t('A unique name used to identify this panel page internally. It must be only be alpha characters and underscores. No spaces, numbers or uppercase characters.'),
  );
  $form['left']['settings']['category'] = array(
    '#type' => 'textfield',
    '#size' => 24,
    '#default_value' => $panel_mini->category,
    '#title' => t('Mini panel category'),
    '#description' => t("The category that this mini-panel will be grouped into on the Add Content form. Only upper and lower-case alphanumeric characters are allowed. If left blank, defaults to 'Mini panels'."),
  );
  panels_load_include('plugins');
  $panel_mini->context = $panel_mini->display->context = panels_context_load_contexts($panel_mini);
  $form['right']['layout'] = array(
    '#type' => 'fieldset',
    '#title' => t('Layout'),
  );
  $layout = panels_get_layout($panel_mini->display->layout);
  $form['right']['layout']['layout-icon'] = array(
    '#value' => panels_print_layout_icon($panel_mini->display->layout, $layout),
  );
  $form['right']['layout']['layout-display'] = array(
    '#value' => check_plain($layout['title']),
  );
  $form['right']['layout']['layout-content'] = array(
    '#value' => theme('panels_common_content_list', $panel_mini->display),
  );
  $contexts = theme('panels_common_context_list', $panel_mini);
  if ($contexts) {
    $form['right']['context'] = array(
      '#type' => 'fieldset',
      '#title' => t('Contexts'),
    );
    $form['right']['context']['context'] = array(
      '#value' => $contexts,
    );
  }
  $label = $panel_mini->pid == 'new' ? t('Save and proceed') : t('Save');
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => $label,
  );
  return $form;
}

/**
 * Validate submission of the mini panel edit form.
 */
function panels_mini_edit_form_validate($form_id, $form_values, $form) {

  // Test uniqueness of name:
  if (!$form_values['name']) {
    form_error($form['left']['settings']['name'], t('Panel mini name is required.'));
  }
  else {
    if (preg_match("/[^A-Za-z0-9_]/", $form_values['name'])) {
      form_error($form['left']['settings']['name'], t('Name must be alphanumeric or underscores only.'));
    }
    else {
      if (preg_match("/[^A-Za-z0-9 ]/", $form_values['category'])) {
        form_error($form['left']['settings']['category'], t('Categories may contain only alphanumerics or spaces.'));
      }
      else {
        $query = "SELECT pid FROM {panels_mini} WHERE name = '%s'";
        if (!empty($form_values['pid']) && is_numeric($form_values['pid'])) {
          $query .= " AND pid != {$form_values['pid']}";
        }
        if (db_result(db_query($query, $form_values['name']))) {
          form_error($form['left']['settings']['name'], t('Panel name must be unique.'));
        }
      }
    }
  }
}

/**
 * Process submission of the mini panel edit form.
 */
function panels_mini_edit_form_submit($form_id, $form_values) {
  $panel_mini = $form_values['panel_mini'];
  if ($panel_mini->pid != 'new' && $panel_mini->name != $form_values['name']) {

    // update all existing mini panels to point to this one appropriately.
    db_query("UPDATE {blocks} b SET delta = '%s' WHERE b.module = 'panels_mini' AND b.delta = '%s'", $form_values['name'], $panel_mini->name);

    // Above was blocks; these are actual panel panes.
    $result = db_query("SELECT * FROM {panels_pane} WHERE type = 'panels_mini' and subtype = '%s'", $panel_mini->name);
    while ($pane = db_fetch_object($result)) {
      $conf = unserialize($pane->configuration);
      $conf['name'] = $form_values['name'];
      db_query("UPDATE {panels_pane} SET configuration = '%s', subtype = '%s' WHERE pid = %d", serialize($conf), $conf['name'], $pane->pid);
    }
  }
  $panel_mini->title = $form_values['title'];
  $panel_mini->name = $form_values['name'];
  $panel_mini->category = empty($form_values['category']) ? '' : $form_values['category'];
  if ($panel_mini->pid == 'new') {
    unset($_SESSION['pm_import']);
    drupal_set_message(t('Your new mini panel %title has been saved.', array(
      '%title' => $panel_mini->title,
    )));
    panels_mini_save($panel_mini);
    $GLOBALS['form_values']['pid'] = $panel_mini->pid;
    $layout = panels_get_layout($panel_mini->display->layout);
    if ($layout['settings form']) {
      return "admin/panels/panel-mini/{$panel_mini->name}/edit/settings/next";
    }
    return "admin/panels/panel-mini/{$panel_mini->name}/edit/context/next";
  }
  else {
    drupal_set_message(t('Your changes have been saved.'));
    panels_mini_save($panel_mini);
  }
}

/**
 * Form to edit context features of a mini panel.
 */
function panels_mini_edit_context($panel_mini, $next = NULL) {
  if (!empty($_POST)) {
    $panel_mini = panels_common_cache_get('panel_object:panel_mini', $panel_mini->name);
  }
  else {
    panels_common_cache_set('panel_object:panel_mini', $panel_mini->name, $panel_mini);
  }
  drupal_set_title(check_plain($panel_mini->title));
  return drupal_get_form('panels_mini_context_form', $panel_mini, $next);
}

/**
 * Form to edit the context settings of a mini panel.
 */
function panels_mini_context_form($panel_mini, $next = NULL) {
  drupal_add_css(panels_get_path('css/panels_admin.css'));
  panels_load_include('plugins');
  $layout = panels_get_layout($panel_mini->display->layout);
  $form['pid'] = array(
    '#type' => 'value',
    '#value' => $panel_mini->pid,
  );
  $form['panel_mini'] = array(
    '#type' => 'value',
    '#value' => $panel_mini,
  );
  $form['right'] = array(
    '#prefix' => '<div class="right-container">',
    '#suffix' => '</div>',
  );
  $form['left'] = array(
    '#prefix' => '<div class="left-container">',
    '#suffix' => '</div>',
  );
  panels_load_include('common');
  $settings = panels_common_add_context_form('panel_mini', $form, $form['right']['contexts_table'], $panel_mini);
  $settings += panels_common_add_required_context_form('panel_mini', $form, $form['left']['required_contexts_table'], $panel_mini);
  $settings += panels_common_add_relationship_form('panel_mini', $form, $form['right']['relationships_table'], $panel_mini);
  panels_common_add_context_js($settings);
  $label = $next ? t('Save and proceed') : t('Save');
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => $label,
  );
  return $form;
}

/**
 * Process submission of the mini panel edit form.
 */
function panels_mini_context_form_submit($form_id, $form_values) {
  $panel_mini = $form_values['panel_mini'];

  // Organize these from the common form.
  panels_common_save_context('context', $panel_mini->contexts, $form_values);
  panels_common_save_context('requiredcontext', $panel_mini->requiredcontexts, $form_values);
  panels_common_save_context('relationship', $panel_mini->relationships, $form_values);
  drupal_set_message(t('Your changes have been saved.'));
  panels_mini_save($panel_mini);
  panels_common_cache_clear('panel_object:panel_mini', $panel_mini->name);
  if ($form_values['submit'] == t('Save and proceed')) {
    return "admin/panels/panel-mini/{$panel_mini->name}/edit/content";
  }
}

/**
 * Enable a default mini panel.
 */
function panels_mini_enable_page($name = NULL) {
  $defaults = panels_mini_default_panels();
  if (isset($defaults[$name])) {
    $status = variable_get('panel_mini_defaults', array());
    $status[$name] = FALSE;
    variable_set('panel_mini_defaults', $status);
    drupal_set_message(t('Panel mini enabled'));
  }
  drupal_goto();
}

/**
 * Disable a default mini panel.
 */
function panels_mini_disable_page($name = NULL) {
  $defaults = panels_mini_default_panels();
  if (isset($defaults[$name])) {
    $status = variable_get('panel_mini_defaults', array());
    $status[$name] = TRUE;
    variable_set('panel_mini_defaults', $status);
    drupal_set_message(t('Panel mini disabled'));
  }
  drupal_goto();
}

/**
 * Pass through to the panels content editor.
 */
function panels_mini_edit_content($panel_mini) {
  if (!is_object($panel_mini)) {
    $panel_mini = panels_mini_load($panel_mini);
  }
  panels_load_include('plugins');

  // Collect a list of contexts required by the arguments on this page.
  $panel_mini->display->context = $contexts = panels_context_load_contexts($panel_mini);
  panels_load_include('common');
  $content_types = panels_common_get_allowed_types('panels_mini', $contexts);
  $output = panels_edit($panel_mini->display, NULL, $content_types);
  if (is_object($output)) {
    $panel_mini->display = $output;
    $panel_mini->did = $output->did;
    panels_mini_save($panel_mini);
    drupal_goto("admin/panels/panel-mini/{$panel_mini->name}/edit/content");
  }

  // Print this with theme('page') so that blocks are disabled while editing a display.
  // This is important because negative margins in common block layouts (i.e, Garland)
  // messes up the drag & drop.
  drupal_set_title(check_plain($panel_mini->title));
  print theme('page', $output, FALSE);
}

/**
 * Pass through to the panels layout editor.
 */
function panels_mini_edit_layout($panel_mini) {
  if (!is_object($panel_mini)) {
    $panel_mini = panels_mini_load($panel_mini);
  }
  $output = panels_edit_layout($panel_mini->display, t('Save'));
  if (is_object($output)) {
    $panel_mini->display = $output;
    $panel_mini->did = $output->did;
    panels_mini_save($panel_mini);
    drupal_goto("admin/panels/panel-mini/{$panel_mini->name}/edit/layout");
  }
  drupal_set_title(check_plain($panel_mini->title));
  return $output;
}

/**
 * Pass through to the panels layout settings editor.
 */
function panels_mini_edit_layout_settings($panel_mini, $next = NULL) {
  if (!is_object($panel_mini)) {
    $panel_mini = panels_mini_load($panel_mini);
  }
  if (empty($next)) {
    $button = t('Save');
    $dest = "admin/panels/panel-mini/{$panel_mini->name}/edit/settings";
  }
  else {
    $button = t('Save and proceed');
    $dest = "admin/panels/panel-mini/{$panel_mini->name}/edit/context/next";
  }
  $output = panels_edit_layout_settings($panel_mini->display, $button, NULL, $panel_mini->title);
  if (is_object($output)) {
    $panel_mini->display = $output;
    $panel_mini->did = $output->did;
    panels_mini_save($panel_mini);
    drupal_goto($dest);
  }
  drupal_set_title(check_plain($panel_mini->title));
  return $output;
}

// ---------------------------------------------------------------------------
// Allow the rest of the system access to mini panels

/**
 * Implementation of hook_block().
 *
 * Expose qualifying mini panels to Drupal's block system.
 */
function panels_mini_block($op = 'list', $delta = 0, $edit = array()) {
  if ($op == 'list') {
    $blocks = array();
    $minis = panels_mini_load_all();
    foreach ($minis as $panel_mini) {
      if (empty($panel_mini->disabled) && empty($panel_mini->requiredcontext)) {
        $title = $panel_mini->hide_title ? t('Mini panel: %title (Title will be hidden)', array(
          '%title' => $panel_mini->title,
        )) : t('Mini panel: %title', array(
          '%title' => $panel_mini->title,
        ));
        $blocks[$panel_mini->pid] = array(
          'info' => $title,
        );
      }
    }
    return $blocks;
  }
  elseif ($op == 'view') {
    $panel_mini = panels_mini_load($delta);
    panels_load_include('plugins');
    $panel_mini->context = $panel_mini->display->context = panels_context_load_contexts($panel_mini);
    $panel_mini->display->css_id = panels_mini_get_id($panel_mini->name);
    $block = array(
      'subject' => $panel_mini->hide_title ? '' : check_plain($panel_mini->title),
      'content' => panels_render_display($panel_mini->display),
    );
    return $block;
  }
}

/**
 * Expose all mini panels to our own system.
 */
function panels_mini_panels_content_types() {
  $items['panels_mini'] = array(
    'title' => t('Mini panels'),
    'content_types' => 'panels_mini_content_types',
    'render callback' => 'panels_mini_content',
    'add callback' => 'panels_mini_add_mini_panel',
    'edit callback' => 'panels_mini_edit_mini_panel',
    'title callback' => 'panels_mini_title_mini_panel',
  );
  return $items;
}

/**
 * Return each available mini panel available as a subtype.
 */
function panels_mini_content_types() {
  $types = array();
  foreach (panels_mini_load_all() as $mini) {
    if (!empty($mini->disabled)) {
      continue;
    }
    $types[$mini->name] = array(
      'title' => filter_xss_admin($mini->title),
      // For now mini panels will just use the contrib block icon.
      'icon' => 'icon_contrib_block.png',
      'path' => panels_get_path("content_types/block"),
      'description' => filter_xss_admin($mini->title),
      'category' => array(
        !empty($mini->category) ? filter_xss_admin($mini->category) : t('Mini panel'),
        -8,
      ),
    );
    if (!empty($mini->requiredcontexts)) {
      $types[$mini->name]['required context'] = array();
      foreach ($mini->requiredcontexts as $context) {
        $info = panels_get_context($context['name']);

        // TODO: allow an optional setting
        $types[$mini->name]['required context'][] = new panels_required_context($context['identifier'], $info['context name']);
      }
    }
  }
  return $types;
}

/**
 * Statically store all used IDs to ensure all mini panels get a unique id.
 */
function panels_mini_get_id($name) {
  static $id_cache = array();
  $id = 'mini-panel-' . $name;
  if (!empty($id_cache[$name])) {
    $id .= "-" . $id_cache[$name]++;
  }
  else {
    $id_cache[$name] = 1;
  }
  return $id;
}

/**
 * Render a mini panel called from a panels display.
 */
function panels_mini_content($conf, $panel_args, &$contexts) {
  $mini = panels_mini_load($conf['name']);
  if (!$mini) {
    return FALSE;
  }
  panels_load_include('plugins');

  // Load up any contexts we might be using.
  $context = panels_context_match_required_contexts($mini->requiredcontexts, $contexts);
  $mini->context = $mini->display->context = panels_context_load_contexts($mini, FALSE, $context);
  if (empty($mini) || !empty($mini->disabled)) {
    return;
  }
  $mini->display->args = $panel_args;
  $mini->display->css_id = panels_mini_get_id($conf['name']);
  $mini->display->owner = $mini;

  // unique ID of this mini.
  $mini->display->owner->id = $mini->name;
  $block = new stdClass();
  $block->module = 'panels_mini';
  $block->delta = $conf['name'];
  $block->content = panels_render_display($mini->display);
  if (!$mini->hide_title) {
    $block->subject = filter_xss_admin($mini->title);
  }
  return $block;
}

/**
 * Form to add a mini panel to a panel.
 */
function panels_mini_add_mini_panel($id, $parents, $conf = array()) {
  $conf['name'] = $id;
  return panels_mini_edit_mini_panel($id, $parents, $conf);
}

/**
 * Returns an edit form for the mini panel.
 *
 * There isn't much here as most of this is set up at mini panel creation time.
 */
function panels_mini_edit_mini_panel($id, $parents, $conf) {
  $form['name'] = array(
    '#type' => 'value',
    '#value' => $conf['name'],
  );
  return $form;
}
function panels_mini_title_mini_panel($conf) {
  $mini = panels_mini_load($conf['name']);
  if (!$mini) {
    return t('Deleted/missing mini panel @name', array(
      '@name' => $conf['name'],
    ));
  }
  $title = filter_xss_admin($mini->title);
  if (empty($title)) {
    $title = t('Untitled mini panel');
  }
  return $title;
}

// ---------------------------------------------------------------------------
// Database functions.

/**
 * A list of the fields used in the panel_mini table.
 */
function panels_mini_fields() {
  return array(
    'name' => "'%s'",
    'category' => "'%s'",
    'title' => "'%s'",
    'contexts' => "'%s'",
    'requiredcontexts' => "'%s'",
    'relationships' => "'%s'",
  );
}

/**
 * Sanitize a mini panel, to guarantee certain data is as we believe it will be.
 */
function panels_mini_sanitize($panel_mini) {
  foreach (array(
    'contexts',
    'relationships',
    'requiredcontexts',
  ) as $id) {
    if (!is_array($panel_mini->{$id})) {
      $panel_mini->{$id} = array();
    }
  }
  return $panel_mini;
}

/**
 * Fetch all mini panels in the system.
 *
 * This function does not cache.
 */
function panels_mini_load_all($page_size = 0) {
  static $results = array();
  if (array_key_exists($page_size, $results)) {
    return $results[$page_size];
  }
  $panels = $dids = array();
  $query = "SELECT * FROM {panels_mini}";
  if ($page_size) {
    $result = pager_query($query, $page_size);
  }
  else {
    $result = db_query($query);
  }
  while ($panel_mini = db_fetch_object($result)) {
    $panel_mini->contexts = !empty($panel_mini->contexts) ? unserialize($panel_mini->contexts) : array();
    $panel_mini->requiredcontexts = !empty($panel_mini->requiredcontexts) ? unserialize($panel_mini->requiredcontexts) : array();
    $panel_mini->relationships = !empty($panel_mini->relationships) ? unserialize($panel_mini->relationships) : array();
    $panel_mini->category = !empty($panel_mini->category) ? $panel_mini->category : 'Mini panels';
    $panel_mini->hide_title = (bool) db_result(db_query('SELECT hide_title FROM {panels_display} WHERE did = %d', $panel_mini->did));
    $panel_mini->type = t('Local');
    $panels[$panel_mini->name] = panels_mini_sanitize($panel_mini);
  }
  $status = variable_get('panel_mini_defaults', array());
  foreach (panels_mini_default_panels() as $panel_mini) {

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

/**
 * Load a mini panel.
 */
function panels_mini_load($pid) {
  static $cache = array();
  if (array_key_exists($pid, $cache)) {
    return $cache[$pid];
  }
  if (!is_numeric($pid)) {
    $where = "name = '%s'";
  }
  else {
    $where = 'pid = %d';
  }
  $panel_mini = db_fetch_object(db_query("SELECT m.*, d.hide_title FROM {panels_mini} AS m INNER JOIN {panels_display} AS d ON m.did = d.did WHERE {$where}", $pid));
  if (!$panel_mini) {
    $defaults = panels_mini_default_panels();
    if (isset($defaults[$pid])) {
      $panel_mini = $defaults[$pid];
      $status = variable_get('panel_mini_defaults', array());

      // Determine if default panel is enabled or disabled.
      if (isset($status[$panel_mini->name])) {
        $panel_mini->disabled = $status[$panel_mini->name];
      }
      $cache[$pid] = $panel_mini;
      return $panel_mini;
    }
    return;
  }
  $panel_mini->contexts = !empty($panel_mini->contexts) ? unserialize($panel_mini->contexts) : array();
  $panel_mini->requiredcontexts = !empty($panel_mini->requiredcontexts) ? unserialize($panel_mini->requiredcontexts) : array();
  $panel_mini->relationships = !empty($panel_mini->relationships) ? unserialize($panel_mini->relationships) : array();

  // $panel_mini->hide_title = ((bool) db_result(db_query('SELECT hide_title FROM {panels_display} WHERE did = %d', $panel_mini->did)));
  $cache[$pid] = panels_mini_sanitize($panel_mini);
  $cache[$pid]->display = panels_load_display($cache[$pid]->did);
  return $cache[$pid];
}

/**
 * Save a mini panel.
 */
function panels_mini_save(&$panel_mini) {
  $fields = $types = $values = $pairs = array();

  // Save the display if one was given to us.
  if (!empty($panel_mini->display)) {
    $display = panels_save_display($panel_mini->display);
  }

  // Ensure empty values get translated correctly.
  // Also make sure we don't mess up the original.
  $mini_clone = drupal_clone(panels_mini_sanitize($panel_mini));

  // If pid is set to our "magic value", this is an insert, otherwise an update.
  $insert = $mini_clone->pid && $mini_clone->pid == 'new';

  // Build arrays of fields and types (resp. pairs of both) and of values.
  foreach (panels_mini_fields() as $field => $type) {

    // Skip empty values.
    if (isset($mini_clone->{$field})) {
      if ($insert) {
        $fields[] = $field;
        $types[] = $type;
      }
      else {
        $pairs[] = "{$field} = {$type}";
      }

      // Build the $values array, serializing some fields.
      $serialize = in_array($field, array(
        'contexts',
        'requiredcontexts',
        'relationships',
      ));
      $values[] = $serialize ? serialize($mini_clone->{$field}) : $mini_clone->{$field};
    }
  }
  if ($insert) {

    // Determine the new primary key.
    $mini_clone->pid = db_next_id('{panels_mini}_pid');

    // Build the query adding the new primary key and the did.
    $sql = 'INSERT INTO {panels_mini} (' . implode(', ', $fields) . ', did, pid) VALUES (' . implode(', ', $types) . ', %d, %d)';
    $values[] = $display->did;
  }
  else {

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

/**
 * Delete a mini panel.
 */
function panels_mini_delete($panel_mini) {
  db_query("DELETE FROM {panels_mini} WHERE pid = %d", $panel_mini->pid);
  db_query("DELETE FROM {blocks} WHERE module = 'panels_mini' AND delta = %d", $panel_mini->pid);
  return panels_delete_display($panel_mini->did);
}

/**
 * Export a mini panel into PHP code for use in import.
 *
 * The code returned from can be used directly in panels_mini_save().
 */
function panels_mini_export($panel_mini, $prefix = '') {
  $output = '';
  $fields = panels_mini_fields();
  $output .= $prefix . '$mini = new stdClass()' . ";\n";
  $output .= $prefix . '$mini->pid = \'new\'' . ";\n";
  foreach ($fields as $field => $sub) {
    $output .= $prefix . '  $mini->' . $field . ' = ' . panels_var_export($panel_mini->{$field}, '  ') . ";\n";
  }

  // Export the primary display
  $display = !empty($panel_mini->display) ? $panel_mini->display : panels_load_display($panel_mini->did);
  $output .= panels_export_display($display, $prefix);
  $output .= $prefix . '$mini->display = $display' . ";\n";
  return $output;
}

/**
 * Get all 'default' mini panels.
 *
 * @ingroup HookInvokers
 */
function panels_mini_default_panels() {
  $panels = module_invoke_all('default_panel_minis');
  if (!is_array($panels)) {
    $panels = array();
  }
  return $panels;
}

/**
 * Remove the block version of mini panels from being available content types.
 */
function panels_mini_panels_block_info($module, $delta, &$info) {
  $info = NULL;
}

/**
 * Implementation of hook_panels_exportables().
 */
function panels_mini_panels_exportables($op = 'list', $panels = NULL, $name = 'foo') {
  static $all_panels = NULL;
  if ($op == 'list') {
    if (empty($all_panels)) {
      $all_panels = panels_mini_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_minis()\n";
    $code .= " */\n";
    $code .= "function " . $name . "_default_panel_minis() {\n";
    foreach ($panels as $panel => $truth) {
      $code .= panels_mini_export($all_panels[$panel], '  ');
      $code .= '  $minis[\'' . check_plain($panel) . '\'] = $mini;' . "\n\n\n";
    }
    $code .= "  return \$minis;\n";
    $code .= "}\n";
    return $code;
  }
}

Functions

Namesort descending Description
panels_mini_add_mini_panel Form to add a mini panel to a panel.
panels_mini_add_page Handle the add mini panel page.
panels_mini_block Implementation of hook_block().
panels_mini_content Render a mini panel called from a panels display.
panels_mini_content_types Return each available mini panel available as a subtype.
panels_mini_context_form Form to edit the context settings of a mini panel.
panels_mini_context_form_submit Process submission of the mini panel edit form.
panels_mini_default_panels Get all 'default' mini panels.
panels_mini_delete Delete a mini panel.
panels_mini_delete_confirm Provide a form to confirm deletion of a mini panel.
panels_mini_delete_confirm_submit Handle the submit button to delete a mini panel.
panels_mini_disable_page Disable a default mini panel.
panels_mini_edit Edit a mini panel.
panels_mini_edit_content Pass through to the panels content editor.
panels_mini_edit_context Form to edit context features of a mini panel.
panels_mini_edit_export Page callback to export a mini panel to PHP code.
panels_mini_edit_form Form to edit the settings of a mini panel.
panels_mini_edit_form_submit Process submission of the mini panel edit form.
panels_mini_edit_form_validate Validate submission of the mini panel edit form.
panels_mini_edit_layout Pass through to the panels layout editor.
panels_mini_edit_layout_settings Pass through to the panels layout settings editor.
panels_mini_edit_mini_panel Returns an edit form for the mini panel.
panels_mini_enable_page Enable a default mini panel.
panels_mini_export Export a mini panel into PHP code for use in import.
panels_mini_fields A list of the fields used in the panel_mini table.
panels_mini_get_id Statically store all used IDs to ensure all mini panels get a unique id.
panels_mini_help Implementation of hook_help().
panels_mini_import_form Form for the mini panel import.
panels_mini_import_form_submit Handle the submit button on importing a mini panel.
panels_mini_import_mini Page callback to import a mini panel from PHP code.
panels_mini_list_page Provide a list of mini panels, with links to edit or delete them.
panels_mini_load Load a mini panel.
panels_mini_load_all Fetch all mini panels in the system.
panels_mini_menu Implementation of hook_menu().
panels_mini_menu_items
panels_mini_panels_block_info Remove the block version of mini panels from being available content types.
panels_mini_panels_content_types Expose all mini panels to our own system.
panels_mini_panels_exportables Implementation of hook_panels_exportables().
panels_mini_perm Implementation of hook_perm().
panels_mini_preview_panel Provide an administrative preview of a mini panel.
panels_mini_sanitize Sanitize a mini panel, to guarantee certain data is as we believe it will be.
panels_mini_save Save a mini panel.
panels_mini_settings Settings for mini panels.
panels_mini_title_mini_panel