I have been trying to hack together conditional widgets that don't depend on the widgets themselves having code in them - so you can take a pre-canned widget and only have it appear on eg is_single() pages. I like the approach of having multiple sidebars defined, but it gets messy with lots of possible sidebars
Anyway, I have something sort of working. This 'proof of concept' has 2 disadvantages as it stands:
1) it is added to the widget control - so control-less widgets remain universal
2) to make it flexible in this first version it uses PHP eval() which can run arbitrary code, so there might be security concerns.
on the other hand it's a simple hack as it stands, being only a few isolated lines in 2 files:
wp-admin/widgets.php
Near the end of the file is a line <div id="controls"> followed by "foreach ($wp_registered_widget_controls...". Before the foreach insert:
if(!$wl_options = get_option('widget_logic')) $wl_options = array();
a few lines later find a line "call_user_func_array(...". Right after that insert:
if (isset($_POST[$widget['id'].'-widget_logic'])){
$wl_options[$widget['id']]=$_POST[$widget['id'].'-widget_logic'];
update_option('widget_logic', $wl_options);
}
echo '<p>Logic:<input type="text" name="'.$widget['id'].'-widget_logic" value="'.$wl_options[$widget['id']].'" /></p>';
wp-includes/widgets.php
search for the line containing "is_callable($callback)"
Change if ( is_callable($callback) ) { to if ($wl_value ) { and insert these line just before that:
$wl_options = get_option('widget_logic');
$wl_value=($wl_options[$id])?$wl_options[$id]:"return true;";
$wl_value=(stristr($wl_value, "return"))?$wl_value:"return ".$wl_value.";";
$wl_value=(eval($wl_value) && is_callable($callback));
what it does
It adds a "Logic" text field to the widget control in the admin interface. The text can be as simple as 'is_single()' or 'is_single() || is_category(5)' (I think that should work!). Basically the text is 'eval'd logically before the widget is output - it should either be a full line of PHP that returns a value like 'return true;' or if it doesn't contain the text 'return' then it adds 'return' on the front and a ';' on the end
Feedback on anyone trying this out most welcome!