Optional context is always empty for content_type plugins.
It is caused by ctools_context_optional->add_empty() method during merge operation.
To solve it I propose simple patch:

ctools/includes/context.inc  
---
  
@@ -194,7 +194,8 @@ class ctools_context_optional extends ctools_context_required {
     $context = new ctools_context('any');
     $context->title      = t('No context');
     $context->identifier = t('No context');
-    $contexts = array_merge(array('empty' => $context), $contexts);
+    //$contexts = array_merge(array('empty' => $context), $contexts);
+    $contexts['empty'] = $context;
   }
 
   function filter($contexts) {

Comments

merlinofchaos’s picture

Status: Active » Needs work

This isn't right.

The reason we're using array_merge() there is so that empty always appears at the top of the list.

Other than that, this patch isn't changing anything, so I don't understand what it's trying to do. The bug report doesn't make any sense to me. There is not enough context.

brunodbo’s picture

I ran into the same problem. When you define an optional context in the $plugin array, the context isn't passed to the content type anymore (other content types in the same panel variant continue to work).

$plugin = array(
  ...
  'optional context' => new ctools_context_optional(t('Node'), 'node'),
  ...
);

I found #516504: Problem with multiple optional contexts - I'm only using one context though. Changing the code above to the code below, seems to fix the issue.

$plugin = array(
  ...
  'required context' => new ctools_context_optional(t('Node'), 'node'),
  ...
);
Anonymous’s picture

Version: 7.x-1.0-alpha2 » 7.x-1.x-dev

appending the 'empty' context instead of prepending it fixes this problem for me, as well

in ctools/includes/content.inc, line 763

          $filtered = ctools_context_filter($contexts, $required);
          if ($filtered) {
            $keys = array_keys($filtered);
            $conf['context'][$index] = array_shift($keys);
          }

when ctools_context_filter returns its filtered contexts, it returns an array with empty and the correctly matched context in that order. array_shift pulls the first element into the context, which is always 'empty' because add_empty forces it to the front

ianschweer’s picture

I am also experiencing this problem. I followed sidke advise on the subject and was able to take care of it. By appending the empty context to the array instead of prepending i was able to take care of it. However, i would think that adding restrictions on the ctools content type, then shouldn't the empty context be filtered out?

reevo’s picture

The fix in the OP works for me, too.

To summarise, $context->data is always NULL when using ctools_context_optional, even when context is present.

ctools_context::__set_state(array(
   'type' => 'any',
   'data' => NULL,
   'title' => 'No context',
   'page_title' => '',
   'identifier' => 'No context',
   'argument' => NULL,
   'keyword' => '',
   'original_argument' => NULL,
   'restrictions' => 
  array (
  ),
   'empty' => false,
))
karel010’s picture

Issue summary: View changes
Status: Needs work » Reviewed & tested by the community

Patch works as explained.

japerry’s picture

Status: Reviewed & tested by the community » Needs work

Marking needs work per #1, I'm not convinced either that this is needed or that it won't break something else.

sylus’s picture

I ran into this problem as well and patch resolved it for me.

papagrande’s picture

Status: Needs work » Needs review

This patch fixes content_type plugins that have optional contexts. Without it, an optional context will be an empty object even when there is valid data to create the object.

I've had this patch on a production site for almost a year with no apparent problems.

damienmckenna’s picture

The patch certainly could be cleaner, i.e. remove the commented-out line.

Does anyone have an example plugin that triggers the bug?

reevo’s picture

Status: Needs review » Needs work

I'm actually having trouble replicating the issue now, so will echo @DamienMcKenna's request: @sylus, @PapaGrande, can you provide an example plugin?

papagrande’s picture

@DamienMcKenna, @reevo Here's a simplified version of one of my plugins:

$plugin = array(
  'title' => t('My Plugin'),
  'single' => TRUE,
  'render callback' => 'my_module_plugin_render',
  'required context' => array(
    new ctools_context_optional(t('Context 1'), 'context_1'),
    new ctools_context_optional(t('Context 2'), 'context_2'),
  ),
);

function my_module_plugin_render($subtype, $conf, $panel_args, $context) {
  if (isset($context[0]->some_property)) {
    $entity_nid = $context[0]->nid;
  } elseif (isset($context[1]->some_property)) {
    $entity_nid = $context[1]->nid;
  } else {
    $entity_nid = '';
  }

  $markup =  array();
  $block = new stdClass();
  $block->title = t('My Block');
  $block->content = $markup;
  return $block;
}

I can clean up the patch if you agree that this is a good direction to go.

sylus’s picture

Attaching proper patch to move this issue along.

sylus’s picture

Status: Needs work » Needs review
mpotter’s picture

Status: Needs review » Reviewed & tested by the community

Wow, thanks for this patch. This was driving me crazy. We have a widget in Open Atrium with an optional node context and was having this exact problem (context was always null). The patch in #13 worked great! This really needs to get committed! Seems like there are numerous people reporting success with this patch here.

damienmckenna’s picture

+1.

mpotter’s picture

To add more info to this. #1 is correct in that the only difference with this is that the original code causes the 'empty' key to be at the beginning of the array. With the patch in #13, the array data is all the same except the "empty" key is at the end of the array.

In my case, here is what $contexts (var_dump) was set to using the patch:

array(5) {
  'panelizer' =>
  class ctools_context#894 (11) {
    ...
  }
  'relationship_entity_from_schema:uid-node-user_1' =>
  class ctools_context#1086 (11) {
    ...
  }
  'relationship_entity_from_field:og_group_ref-node-node_1' =>
  class ctools_context#1082 (11) {
    ...
  }
  'relationship_entity_from_field:oa_section_ref-node-node_1' =>
  class ctools_context#1083 (11) {
    ...
  }
  'empty' =>
  class ctools_context#1284 (10) {
    ...
  }
}

My guess is that the *real* cause of this bug is elsewhere in ctools where somehow the order of these keys actually matters. If it finds "empty" first, then it's returning a NULL node context. When "empty" is last it properly returns the node context from panelizer.

mortona2k’s picture

+1 for #13.

damienmckenna’s picture

japerry’s picture

Status: Reviewed & tested by the community » Fixed

Okay. looks good to me! Fixed.

  • japerry committed 4cc2c89 on 7.x-1.x authored by sylus
    Issue #1032218 by sylus, reevo: Optional context is always empty for...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.