This might not really be Quicktabs's fault, but it fails to pass on context when loading a View that gets a default value from the page context in a Panel. The first tab loaded works fine; the rest do not. They all work if ajax is turned off. Has anybody else run into this?

Note: it works fine if I specify %1 as the argument. The problem is that I'd like to load up these views in mini panels, and have the argument provided by the page context - not specifically have to be passed as an argument.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Renee S’s picture

Issue summary: View changes

clarification

Renee S’s picture

So, I can accomplish what I want to do with panel arguments, and forcing the View context to use them instead of falling back on the default page context. This probably is a pretty esoteric use-case anyway, but might leave it open until somebody weighs in and says it's totally not worth bothering with looking into further. ;)

Renee S’s picture

Priority: Normal » Minor
Renee S’s picture

Issue summary: View changes

edit

Renee S’s picture

So, this problem exists in other tabbing modules, along with a hint at a solution that should work for Quicktabs also: #1944510: Views not receiving arguments from ajax tab

Renee S’s picture

Title: Quicktabs with ajax load don't pass on context to Views » Quicktabs with ajax load don't pass on context to blocks (eg: mini panels)
Issue summary: View changes

Making title clearer.

Renee S’s picture

Title: Quicktabs with ajax load don't pass on context to blocks (eg: mini panels) » Quicktabs with ajax load don't pass on context (eg: views, mini panels)

eta

suhel.rangnekar’s picture

Assigned: Unassigned » suhel.rangnekar
joelpittet’s picture

Assigned: suhel.rangnekar » Unassigned
Priority: Minor » Normal
joelpittet’s picture

Status: Active » Needs review

I ended up making a mini panels QuickContent

It seems all the ajax stuff is passed through as get arguments, so I stole the page_manager's context bits that I needed and serialized them across. (only the plugin and argument are needed to rebuild them on the other side)

  public function __construct($item) {
    parent::__construct($item);
    $this->settings['page_path'] = rawurlencode($_GET['q']);
    $contexts = array();
    if (module_exists('page_manager') && $current_page = page_manager_get_current_page()) {
      if (!empty($current_page['contexts'])) {
        foreach ($current_page['contexts'] as $context) {
          $contexts[] = array($context->plugin, $context->argument);
        }
      }
    }
    $this->settings['contexts'] = rawurlencode(serialize($contexts));
  }

then in the render() function


  public function render($hide_empty = FALSE, $args = array()) {
    // Non-ajax rendering of a mini panel.
    if ($this->rendered_content) {
      return $this->rendered_content;
    }
    $item = $this->settings;
    if (!empty($args)) {
      // The args have been passed in from an ajax request.
      // The first element of the args array is the qt_name, which we don't need
      // for this content type.
      array_shift($args);
      list($item['name'], $item['page_path'], $item['contexts']) = $args;
      if (!empty($item['page_path'])) {
        $item['page_path'] = rawurldecode($item['page_path']);
      }
      if (!empty($item['contexts'])) {
        $item['contexts'] = unserialize(rawurldecode($item['contexts']));
      }
    }

    $output = array();
    if (isset($item['name'])) {
      if (module_exists('panels_mini')) {
        if ($panel_mini = panels_mini_load($item['name'])) {
          // Add contexts to the mini panel.
          ctools_include('context');

          $contexts = array();
          if (module_exists('page_manager') && $current_page = page_manager_get_current_page()) {
            if (!empty($current_page['contexts'])) {
              $contexts = ctools_context_match_required_contexts($panel_mini->requiredcontexts, $current_page['contexts']);
            }
          }
          elseif (!empty($item['contexts'])) {
            $ajax_contexts = array();
            foreach ($item['contexts'] as $context) {
              list($plugin, $arg) = $context;
              $ajax_contexts[] = ctools_context_create($plugin, $arg);
            }
            $contexts = ctools_context_match_required_contexts($panel_mini->requiredcontexts, $ajax_contexts);
          }

          // Load up any contexts we might be using.
          $panel_mini->context = $panel_mini->display->context = ctools_context_load_contexts($panel_mini, FALSE, $contexts);
          $panel_mini->display->css_id = panels_mini_get_id($panel_mini->name);
          $panel_mini->display->owner = $panel_mini;
          // unique ID of this mini.
          $panel_mini->display->owner->id = $panel_mini->name;
          $content = panels_render_display($panel_mini->display);

          if (!empty($content)) {
            $output['#markup'] = $content;
          }
        }
      }
      elseif (!$hide_empty) {
        $output['#markup'] = t('Mini Panels module is not enabled, cannot display content.');
      }
    }
    $this->rendered_content = $output;
    return $output;
  }

Not totally sure if that is the right way to go about fixing this problem of passing context around but it does work.

Here is the full plugin.

// In file: MODULE.module
/**
 * Implements hook_quicktabs_contents().
 */
function MODULE_quicktabs_contents() {
  $path = drupal_get_path('module', 'MODULE') . '/plugins';
  $info['panels_mini'] = array(
    'path' => $path,
    'handler' => array(
      'file' => 'QuickMiniPanelsContent.inc',
      'class' => 'QuickMiniPanelsContent',
    ),
    'dependencies' => array('panels_mini'),
  );

  return $info;
}

// In file: plugins/QuickMiniPanelsContent.inc
/**
 * Class for tab content of type "panels_mini" - this is for rendering a mini
 * panel as tab content.
 */
class QuickMiniPanelsContent extends QuickContent {

  public static function getType() {
    return 'panels_mini';
  }

  public function optionsForm($delta, $qt) {
    $tab = $this->settings;
    $form = array();

    $mini_panels = array();
    foreach (panels_mini_load_all() as $mini) {
      $mini_panels[$mini->name] = $mini->admin_title;
    }
    $keys = array_keys($mini_panels);

    $selected_mini_panel = (isset($tab['name']) ? $tab['name'] : (isset($keys[0]) ? $keys[0] : ''));
    $form['panels_mini']['name'] = array(
      '#type' => 'select',
      '#options' => $mini_panels,
      '#default_value' => $selected_mini_panel,
      '#title' => t('Select a mini panel'),
    );

    return $form;
  }

  public function __construct($item) {
    parent::__construct($item);
    $this->settings['page_path'] = rawurlencode($_GET['q']);
    $contexts = array();
    if (module_exists('page_manager') && $current_page = page_manager_get_current_page()) {
      if (!empty($current_page['contexts'])) {
        foreach ($current_page['contexts'] as $context) {
          $contexts[] = array($context->plugin, $context->argument);
        }
      }
    }
    $this->settings['contexts'] = rawurlencode(serialize($contexts));
  }

  public function render($hide_empty = FALSE, $args = array()) {
    // Non-ajax rendering of a mini panel.
    if ($this->rendered_content) {
      return $this->rendered_content;
    }
    $item = $this->settings;
    if (!empty($args)) {
      // The args have been passed in from an ajax request.
      // The first element of the args array is the qt_name, which we don't need
      // for this content type.
      array_shift($args);
      list($item['name'], $item['page_path'], $item['contexts']) = $args;
      if (!empty($item['page_path'])) {
        $item['page_path'] = rawurldecode($item['page_path']);
      }
      if (!empty($item['contexts'])) {
        $item['contexts'] = unserialize(rawurldecode($item['contexts']));
      }
    }

    $output = array();
    if (isset($item['name'])) {
      if (module_exists('panels_mini')) {
        if ($panel_mini = panels_mini_load($item['name'])) {
          // Add contexts to the mini panel.
          ctools_include('context');

          $contexts = array();
          if (module_exists('page_manager') && $current_page = page_manager_get_current_page()) {
            if (!empty($current_page['contexts'])) {
              $contexts = ctools_context_match_required_contexts($panel_mini->requiredcontexts, $current_page['contexts']);
            }
          }
          elseif (!empty($item['contexts'])) {
            $ajax_contexts = array();
            foreach ($item['contexts'] as $context) {
              list($plugin, $arg) = $context;
              $ajax_contexts[] = ctools_context_create($plugin, $arg);
            }
            $contexts = ctools_context_match_required_contexts($panel_mini->requiredcontexts, $ajax_contexts);
          }

          // Load up any contexts we might be using.
          $panel_mini->context = $panel_mini->display->context = ctools_context_load_contexts($panel_mini, FALSE, $contexts);
          $panel_mini->display->css_id = panels_mini_get_id($panel_mini->name);
          $panel_mini->display->owner = $panel_mini;
          // unique ID of this mini.
          $panel_mini->display->owner->id = $panel_mini->name;
          $content = panels_render_display($panel_mini->display);

          if (!empty($content)) {
            $output['#markup'] = $content;
          }
        }
      }
      elseif (!$hide_empty) {
        $output['#markup'] = t('Mini Panels module is not enabled, cannot display content.');
      }
    }
    $this->rendered_content = $output;
    return $output;
  }

  public function getAjaxKeys() {
    return array('name', 'page_path', 'contexts');
  }

  public function getUniqueKeys() {
    return array('name');
  }
}
joelpittet’s picture

Status: Needs review » Active

No patch, still active.

SocialNicheGuru’s picture

the code almost works. but I have optional contexts for my mini-panels which means that this code throws WSOD

SocialNicheGuru’s picture

Status: Active » Needs review
FileSize
496 bytes

Uploading a patch with #8
made changes to include optional required contexts for mini-panels
can't set the contexts from the ui

SocialNicheGuru’s picture

I used git diff but it did not pick up the added file.

I added the file, QuickMiniPanelsContent.inc.txt. Change to QuickMiniPanelsContent.inc and place in sites/all/quicktabs/plugins.

if you can share how to do a recursive git diff to pick up an added file I would appreciate it.

bfuzze9898’s picture

I'm experiencing similar issue, but the above patch seems very specific to panels, whereas the issue is in general context id is not reconciled. To be clear, I have a view-block with a context filter set to get context id from url. By itself, the block renders on a node view page ok. Inside quicktabs with ajax loading enabled ti does not render. I have played around with removing various block dynamics (pager, filters, php, sorts, etc.), but it seems ajax-loading is the issue.

D 7.41 (!yikes)

jasonaaronwood’s picture

I also need this to work beyond just a Panels fix.

I'm using it in a block that appears on a node's main content region.

Each Quicktab instance shows a Views Block containing a different list of node titles with Flag links (via the Flag module). One of those blocks is set to ONLY show flagged content. But it only appears after refreshing the page, which defeats the point of Ajax. I need the items to appear via Ajax in the flagged-only block when they're flagged in the other referenced blocks in the other Quicktabs.