Situation
-- I have no blocks that are site-wide.
-- I have two contexts "sectionA" and "sectionB".

So in situations where "sectionA" and "sectionB" are not set, I want to apply a "default" context.

If I create a new context called "default", with a site-wide context condition, it comes up everywhere - which I don't want. I just want it to apply if no other contexts apply.

So can someone prescribe a way to achieve this? Either with code or UI?

CommentFileSizeAuthor
#16 813954_context_condition.patch7.2 KByhahn
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

sime’s picture

I've looked at context_layouts, and I see how to achieve the outcome by modifying the theme layouts.

Hopefully there is a solution that doesn't lock me into the theme.

sime’s picture

The cleanest workaround I've found is:

1. In admin/build/context, set up the contexts for specific situations. Don't set up a universal site-wide default context.
2. In admin/build/block set up your default blocks.
3. For each block that you want to suppress if any context i active, add this code to the block visibility settings:

  <?php
  // Suppress this block if any contexts are active. 
  return (count(context_get()) < 1);
sime’s picture

Obviously, that can be simplified, but a little more obscure.
<?php return !count(context_get());

sime’s picture

Status: Active » Needs review

If #794634: Path conditions don't override sitewide conditions is fixed then I think this issue will be made redundant. Need confirmation of that.

Steven Jones’s picture

That linked issue is for context 2.x, this is for 3.x. What version are you running?

sime’s picture

Hi

No, the linked issue was updated to version 3 at comment #3

I'm running version 3.

Steven Jones’s picture

Nuts, I can't read.

Steven Jones’s picture

Nuts, I can't read.

dropcube’s picture

The problem with the workaround proposed at#2 is that is it uses core blocks (can't be included in features).

I just solved the same situation implementing a new condition plugin. This new condition plugin sets a context active if no other context is active when the condition runs.

class context_condition_no_other_active_context extends context_condition {
  function condition_values() {
    return array(1 => t('Active'));
  }

  /**
   * Execute.
   */
  function execute() {
    $active_contexts = context_get('context');
    if (empty($active_contexts)) {
      parent::execute(1);
    }
  }

}

The condition is triggered from an implementation of hook_context_page_condition():

/**
 * Implementation of hook_context_page_condition().
 */
function nr_context_page_condition() {
  if ($plugin = context_get_plugin('condition', 'no_other_contexts')) {
    $plugin->execute();
  }
}

Then create a 'default' context with this condition, and configure the layout or any other reaction you need in the default context, the context that get activated when No other context is set.

sirkitree’s picture

Component: Documentation » Code
Status: Needs review » Needs work

I've given this a try but it's not working for me. Maybe you can help point out my mistakes @dropcube.

I've created the plugin:
1. Implemented hook_context_plugins and hook_context_registry

<?php
/**
 * Implementation of hook_context_plugins().
 *
 * This is a ctools plugins hook.
 */
function g365_site_context_plugins() {
 
module_load_include('inc', 'g365_site', 'g365_site.plugins');
  return
_g365_site_context_plugins();
}
/**
 * Implementation of hook_context_registry().
 */
function g365_site_context_registry() {
 
$registry = array();
 
$registry['conditions']['no_other_active_context'] = array(
   
'title' => t('No other active context'),
   
'description' => t('Set this context when no other context is active.'),
   
'plugin' => 'g365_site_context_condition_no_other_active_context',
  );
  return
$registry;
}
?>

2. Created a plugins file referenced in the above hook_context_plugins.

<?php
/**
 * Context plugins.
 */
function _g365_site_context_plugins() {
 
$plugins = array();
 
/**
   * Conditions.
   */
 
$plugins['g365_site_context_condition_no_other_active_context'] = array(
   
'handler' => array(
     
'path' => drupal_get_path('module', 'g365_site') .'/plugins',
     
'file' => 'g365_site_context_condition_no_other_active_context.inc',
     
'class' => 'g365_site_context_condition_no_other_active_context',
     
'parent' => 'context_condition',
    ),
  );
  return
$plugins;
}
?>

3. Created a plugins directory with an .inc file with the code you gave above, only changing my module name.

<?php
class g365_site_context_condition_no_other_active_context extends context_condition {
  function
condition_values() {
    return array(
1 => t('Active'));
  }
 
/**
   * Execute.
   */
 
function execute() {
   
$active_contexts = context_get('context');
    if (empty(
$active_contexts)) {
     
parent::execute(1);
    }
  }
}
?>

This had the intended result of making a new context condition available within context ui which I can choose and set active.
Editing context auth_default | GRAMMY 365 Public

I've also set a block reaction, but after going to a page that has no other active contexts, my block doesn't show up.

I then implemented the hook you have above:

<?php
/**
 * Implementation of hook_context_page_condition().
 */
function g365_site_context_page_condition() {
  if (
$plugin = context_get_plugin('condition', 'no_other_active_contexts')) {
   
$plugin->execute();
  }
}
?>

Still notta. This really is what I need, but I can't get it to work. Ideally, this is how sitewide context condition should work, I think. But if this can be implemented as a 'default' context condition, such as 2.x has, then that would probably be a good thing to have in the core context module.

sirkitree’s picture

Status: Needs work » Needs review

Just found it - that last hook had the incorrect name... 'no_other_active_contexts' should have been 'no_other_active_context' - without the 's' - sheesh - now it's working.

So the next question is, should this be in the core context module? If so should we call it 'Default'? And if not, is there a way to make the 'sitewide' context condition work this way?

Also, if separate, it should probably have special consideration for the 'sitewide' context condition, otherwise any 'sitewide' would always blanket this making it pretty much useless.


class g365_site_context_condition_no_other_active_context extends context_condition {
  function condition_values() {
    return array(1 => t('Active'));
  }

  /**
   * Execute.
   */
  function execute() {
    $active_contexts = context_get('context');
    // Special consideration for when there is only one other context and it 
    // is using the 'sitewide' condition.
    if (count($active_contexts) == 1) {
      foreach ($active_contexts as $context) {
        if (!empty($context->conditions['sitewide'])) {
          parent::execute(1);
        }
      }
    }
    if (empty($active_contexts)) {
      parent::execute(1);
    }
  }

}
tim.plunkett’s picture

Tried #10 and it worked, I will test #11 later.

q0rban’s picture

I think it'd be nice to also be able to select the contexts that override the default context.

jrabeemer’s picture

+1
The questions raised in #11 need serious consideration

yhahn’s picture

Version: 6.x-3.0-beta5 » 6.x-3.x-dev
Priority: Normal » Critical
Status: Needs review » Active
yhahn’s picture

Category: support » feature
Status: Active » Needs review
FileSize
7.2 KB

Ok, here is a patch that attempts to address this (and many related issues) in a holistic manner.

  1. Adds path exclusion to the path condition. You can now add a path condition like this:

    node/add/*
    ~node/add/blog
    

    And it will be true for all node/add paths except for node/add/blog.

  2. Adds a Context condition plugin. You can now have one context "dependent" upon another context being active. For example, you can create a blog_page context that is made active when the blog context is active.

  3. The Context condition plugin uses the same matching syntax as the path plugin, meaning you can do something like this:

    blog*
    ~blog_post
    

    To set your context whenever another context whose name starts with blog is active, except if that context is the blog_post context. You can also do this:

    ~*
    

    To make your context only be active if no other context is active (aka, the "default" or "fallback" context).

Would love people's feedback!

yhahn’s picture

Title: default context that gets overridden » Path exclusion and active context condition
mikemccaffrey’s picture

Title: Path exclusion and active context condition » default context that gets overridden

1) The path exclusion seems like a huge and obvious help.

2) The Context condition initially seemed repetitive, but I am starting to think of cases where it may be of use.

3) Using text matching syntax on names for the context condition actually seems like a bad idea. As new features define additional contexts, there seems to be a huge chance of unintended interaction between contexts in different features from accidental pattern matches.

Thanks for all your work improving the modules!

mikemccaffrey’s picture

Title: default context that gets overridden » Path exclusion and active context condition
indytechcook’s picture

1. Awesome.
2 & 3. I like this ideas. Especially the default ability. I don't share mike's concern with the name conflicts. Using proper naming conventions (not sure if that's in kit) solves that problem. Te same argument could have been made with module namespaces and functions but naming conventions were acceptable there. The simple use case of one context being active when one other context is active (like statement 2 form comment 16) isn't practically. This field is useful for more complicated use cases. This would make future project easier (as I have already written the plugins for my current proejct to do soemthing similar.)

Cheers,
Neil

irakli’s picture

@yhahn,

All of these are FANTASTIC! And I've had to write custom conditions before to achieve these for specific cases.

Very nice. Can't wait to use 'em.

Thanks

tim.plunkett’s picture

The context exclusion works great, but the path exclusion fails on urls generated by pathauto.
Using pathauto-6.x-1.3 and globalredirect-6.x-1.x-dev.

My guess is that pathauto plays nice with drupal_match_path(), but not the custom regex.

yhahn’s picture

Would you mind posting the particular path alias and condition settings you used? It will help debug.

tim.plunkett’s picture

Pathauto setting: [type]/[title-raw] (one of the content types is festival)
Condition: ~festival and ~festival/*

A view with the path festival/schedule is recognized, but a node with the path festival/tickets is not.

brad.bulger’s picture

the Context condition is great. it also seems to me to be a straightforward way of addressing the role visibility issue for blocks #550934: Block visibility by role is not respected.

sime’s picture

Took me a while to work out how this related to the OP, but I see now.

I think you'll get less support requests if you replace "~*" with a checkbox that says "Apply this context if no others are active."

yhahn’s picture

Status: Needs review » Fixed

@tim.plunkett: Thanks for the info, it helped me debug the problem.

Committed: http://drupal.org/cvs?commit=400452

Status: Fixed » Closed (fixed)

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

dbu’s picture

sime: you are so right. took me a while until i got to the idea of putting "~*" for a no-specific-context context. just adding the tip to the help text below the field for contexts would be a big help. that would not even require any coding on the module...

ShaunDychko’s picture

There seems to be a problem with excluding contexts in a chain. If Context B is activated when Context A doesn't exist, then trying to activate Context C when Context B doesn't exist, doesn't work. Please forgive all the negatives...

Context A: shows a block at node/[nid] on one specific page
Context B: shows a block in a part of the menu tree if Context A isn't triggered (uses ~name_of_context_a, and a top level menu item)
Context C: the "if all else fails, show this" block, which is supposed to trigger when Context B isn't showing (using ~name_of_context_b) doesn't work. Context C ALWAYS displays.

I tried starting the name of context C with an 'a', a 'z', putting it in it's own group...
The fix is this little module: http://drupal.org/node/730812#comment-3622364