Conditional content

We encourage users to post events happening in the community to the community events group on https://www.drupal.org.
darksnow's picture

A little puzzle for us.

I need to be able to display a sort of landing page for an unfiltered view.

I'm filtering a collection of views based on a global filter. This is a postcode search and is working fine. What I need is another node to appear if there is NO value set in the global filter at all.

So, when you enter a postcode you get a table of results. When there's no filter set I don't want the full table to show, but another node explaining how to use search. The other node is actually a views generated page showing national regions on a map, allowing the user to narrow the search with a quick click.

I should also note that this is distinct from no results. If we have a filter which returns no results I'm expecting the no results behaviour from the view that generated the table of results.

So to reiterate, if there are NO global filters set, display another view altogether, otherwise, let the main view do it's thing unhindered.

Any ideas? Even if it requires custom code. I'm stumped and just need a nudge in the right direction. Perhaps it's a hook where I can manually check the global filters and render the appropriate view? Who knows?

Cheers.

Comments

This seems fairly

Made in Orkney's picture

This seems fairly straightforward which probably means that I am completely missing the point. Do this before any output is generated. PHP would look something like this

$res = $db->query( "select ..." );
if( $res->num_rows == 0 ){
header( "Location: /node/12345" ); // explain search system
exit();
}

// else proceed to show results

That is not the "Drupal Way",

intrafusion's picture

That is not the "Drupal Way", you should use drupal_add_http_header [1] in D7 and drupal_set_header [2] in D6. Using exit isn't ideal either.

[1] https://api.drupal.org/api/drupal/includes%21bootstrap.inc/function/drup...
[2] https://api.drupal.org/api/drupal/includes%21common.inc/function/drupal_...

I would imagine you need to

intrafusion's picture

I would imagine you need to use hook_views_pre_view [1] as this allows altering a view at the very beginning of views processing, before anything is done. I would imagine that the filters should be available by then, if not take a look at Views Hooks [2]

[1] https://api.drupal.org/api/views/views.api.php/function/hook_views_pre_v...
[2] https://api.drupal.org/api/views/views.api.php/group/views_hooks/7

Everything what intrafusion

Stefan Lehmann's picture

Everything what intrafusion said. Although drupal_goto() might be a better solution for the use case of a site internal redirect, which - by the way - is as far as I understand it not what the thread starter wants to do. He rather wants to output a custom views filter. It can either be achieved by doing it how intrafusion explains in his last post. Another easy option, if you don't want or can't write the necessary implementation of this views hook, would be to write a bit of static HTML and some Javascript. The HTML contains the map with filter links to your view. A bit of added Javascript / CSS will show / hide the view if the page was loaded with an added parameter. All of this can go into the header of the view and needs no custom PHP code.

PS: I just see, that the custom filter is also a view .. You could just use the attachment display to attach 1 view to the other.

Thanks for the quick

darksnow's picture

Thanks for the quick responses from everyone.

To clarify, it's an internal redirect I want I suppose. If you go to the URL for my view, I want a small piece of code that checks if ANY filters are set on the view, and if not, display something else.

Looks like hook_views_pre_view might be the answer. I'll let everyone know the solution once I work it out.

Cheers all.

Martin...

I don't think you really want

Stefan Lehmann's picture

I don't think you really want to redirect users. You rather want to display other additional content under certain conditions on the current view page.

If you go down the path with a redirect you'll have 2 pages with different URLs / menu items, which will make it rather difficult / error prone to implement imho.

That's what I meant

darksnow's picture

That's what I meant by an "internal" redirect, quoting you.

I want the URL of the original view to show something else if the global filters are not set. So exactly as you say.

So, I won't use the header method mentioned above, but just get the view page to render something else internally.

Cheers.

Nearly there

darksnow's picture

Nearly there I think.

I've created the hook_views_pre_view and I can tell if the appropriate filters are set, so I know when I need to render a different view.

Since the views are not related I can't add a new display to the same view and just switch them, which would be ideal.

I can't use drupal_goto or any HTTP redirect because I don't want the URL to change. The user should not be aware that anything happened.

I can get the node I need and render it, but then I get that odd node within a node things, where one gets rendered but the main one still carries on until it gets rendered.

So, the question now becomes, is there an alternative to drupal_goto? Can I cancel the render of the current node in some way? That way I can render the one I need then just stop, getting the result I need.

So close :)

Not quite sure, why you have

Stefan Lehmann's picture

Not quite sure, why you have to render a node, if you just want to display another view. There are functions to load and render views manually in code.

See here and the example at the bottom: https://api.drupal.org/api/views/views.module/function/views_get_view/7

Perhaps this will make it clearer

darksnow's picture

From the very generous help in this thread, this is what I have so far:

function hook_views_pre_view(&$view, &$display_id, &$args) {
if ($view->name == 'places' && $view->current_display == 'page_place_search') {
      $d = global_filter_get_session_value('distance');
        $r = global_filter_get_session_value('field_region');
        if (empty($r) && (empty($d) || is_array($d))) {
            dpm('Bump!');
            $display_id = 'page_region_map';
         $view = views_get_view('regions');
           $view->set_display($display_id);
        }
  }
}

Turns out setting the $view in this function doesn't do anything. I guess it's too late in the render process, I thought I'd give it a shot since there's a little & before the view and display_id.

If I do $view->render() then I get the view rendered, as expected, but at the top of the page, it obviously doesn't replace the page that's being called.

I hope this clarifies my requirements some. Perhaps I'm using the wrong hook to do this but it feels like I'm pretty close to a solution here.

Cheers for all the help so far.

Martin...

Yeah I think, that's not the

Stefan Lehmann's picture

Yeah I think, that's not the place to hide a view. Although there might be a parameter which prevents the view from rendering. Dunno.

A possible solution which should work, could be:
- implement the basic template file for the view which you want to hide. Should be something like views-view--machine_name_of_your_view.tpl.php
- set a custom attribute to the $view object in hook_views_pre_view() (PS: I hope you didn't edit the function directly btw.)
- check this custom attribute in the template file and show / hide everything depending on it

GOT IT!

darksnow's picture

It's a bit out of the box this one, but here's my solution.

You can't change the view that is being rendered, but you can change the display within that view.

You can also assign any other view as the no results behaviour of a display.

So. I created a new dummy display in my main view, set the filters to published == true AND published == false

Then set my secondary view as the no results display. Since this view never returns any results, it will ALWAYS show the no results behviour, neatly linking a completely unrelated view to a display inside the view I want to handle.

Now, the original code above just needs modified to remove the views_get_view() call and instead simply replace the current display with my new dummy one if no global filter is set.

And it works.

Thanks for all the help, with it I wouldn't have found the pre_view hook, you guys really pointed me in the right direction.

Martin...

P.S. Stefan, I implemented the hook in a custom module, the example code up there had the function name changed to keep the project name private, NDA and all that, but thanks for pointing it out, it's good to remind people not to ever edit core.

I think you'd be better off

joachim's picture

I think you'd be better off thinking about this the other way round.

Instead of hacking the view to show something else, get the view's filters and show them on what you want.

You can get the view to expose its filters as a block. Place that above a node using context.

Thanks

darksnow's picture

That doesn't really address what I needed though.

I had the filters working fine, in this case global filters, but contextual filters as far as Views was concerned. They are working and the no-results behaviour is fine, so the view in itself works exactly as required.

My requirement was to show an entirely different page when no filters were set. Distinct from no results. The closest thing I could do was change Views display so had to working within that restriction.

Cheers for the reply though.

Drupal Scotland

Group organizers

Group categories

Regions

Group notifications

This group offers an RSS feed. Or subscribe to these personalized, sitewide feeds: