I made a custom front page with panels showing two columns, each containing two views: 5 nodes with teaser and then 10 in a list showuing only title, date, and author. Each column refers to one content type. The idea is to have the 5 five newest nodes of each content type shown with teasers and then the 10 following ones in a list view.

Now I need to find a way to skip the first five entries/nodes in the list view since they're already shown in the teaser view. I couldn't find a way to do so. Any ideas?

Comments

luyendao’s picture

Thats a good question - that's a pretty common display use-case, and i've thought casually about how to do that myself. I'll mull this over, and ask our developer too - off the top of my head, i don't think views or panels for that matter can be extended to have that kind of logic, unless you can pass in via arguments a counter everytime a node is output in the views list.

yan’s picture

It's strange, I'm really overwhelmed sometimes by the things Drupal can do so easily. And then there are those things that seem to be so easy and just don't work...

No ideas? Anyone?

mooffie’s picture

If you're not using paging (the "1 2 3 4 5 Next >" thingy) for this view, then it's easy: open the "Arguments" box, then the "Argument Handling Code" box, and in it type the following PHP code: $offset = 5;.

But you probably do use paging for this view :-(

Some will suggest you theme your view to not show the first 5 nodes -- when the first page of the view is shown. But I just had a look at View's source code and I see that it's possible to plug some code, using hook_views_pre_view, that will get executed whenever a view is about to show itself. In this code you can eat up the first X nodes:

function YOUR-MODULE-NAME-HERE_views_pre_view($view, &$items) // note the '&' here!
{
  global $pager_page_array;

  // if this is our view...
  if ($views->name == "my-view-name" 
       // ..and we're on its first page...
       && $pager_page_array[0] == 0 ) {
    $items = array_splice($items, 0, 5); // ...then eat up the first 5 nodes
  }
}

I haven't actually tried this code. I may have typos here. Let me know if you need help.

that's a pretty common display use-case,

That's correct. Why don't you open an issue?

yan’s picture

If you're not using paging (the "1 2 3 4 5 Next >" thingy) for this view, then it's easy: open the "Arguments" box, then the "Argument Handling Code" box, and in it type the following PHP code: $offset = 5;.

That works, thanks a lot!

But you probably do use paging for this view :-(

I'm not =)

yan’s picture

That's correct. Why don't you open an issue?

I did now. Is this the way to write an issue? (Never done that before.)

syquest’s picture

I have a "Newer_Blogs" view that I would like to offset by one. The "Newest" blog is featured on the same page and would therfore be redundant in the "Newer_Blog" view. Your soultion looked so easy and simple until I tried it. Alas, it doesn't work for me.

I entered $offset = 1; in Argument Handling Code, but the 1st result always gets returned.

So I did some further reading here, and now I am confused. What isn't clear is whether of not an argument needs to be "added" in order for the Argument Handling Code to work. If so, then which one do I add for $offset = 1;

What am I missing here? Is this really that difficult?

mooffie’s picture

What isn't clear is whether of not an argument needs to be "added" in order for the Argument Handling Code to work.

You don't have to have arguments defined in order for the 'Argument Handling Code' to get executed.

Your soultion looked so easy and simple until I tried it. Alas, it doesn't work for me.

You probably use the pager in your view. Either clear the 'Use Pager' checkbox, or use the second method I provided.

Make your voice heard in the issue.

syquest’s picture

Thanks for responding. Yes, I had initially deselected the "Use Pager" check box as you suggested in your initial post. Still no success.

Unfortunately this is a deal breaker for my design. No offset equals no Previous Blogs block for my home page. Here is what I was hoping to achieve:

Block 1: Newest Blog = Blog 1
Block 2: Previous Blogs = Blog 2, Blog 3, Blog 4...

As you can see, the 2nd block requires an offset of 1.

mooffie’s picture

I had another look at Views.module. There's one case in which $offset is ignored (when not using a pager), and this is when you ask Views to show all the nodes --by setting "Nodes per Page" to "0". If you indeed have "0" there, you must change it --e.g., change it to some arbitrary huge number-- in order for $offset to have any effect.

I had initially deselected the "Use Pager" check box as you suggested in your initial post.

I didn't "suggest". If you use the first method I gave, then it's not merely a "suggestion" not to use the pager. It's a requirement.

Block 1: [...]
Block 2: [...]

BTW, If you're using blocks then there's another method for changing the offset: to use a custom block and in it to put PHP code that calls views_build_view() directly. But I won't go into the details now, I'm afraid it would confuse you further.

rootwork’s picture

@syquest: I was having the same problem as you describe -- creating a block, so obviously no pager, and putting $offset into argument handling code but having no result -- I always go the first result.

mooffie seems to think you won't be able to understand this, but since this is the only method by which I've managed to make this function, I think it's worth giving you the information.

Create a view with a block that contains the items you want to offset. Save that and note the name of the view. Then create a custom block and add the following (make sure input type is set to PHP):

<?php
    $view = views_get_view('VIEW');
    print views_build_view('TYPE', $view, array(), false, LIMIT, null, OFFSET);
?>

The caps items are what you'll want to replace.

VIEW: The name of your view. In my case it was blog_recent
TYPE: The type of view you want to render -- probably block, but could also be page or embed
LIMIT: The number of total items you want to display. In my case it was 5
OFFSET: The offset from the beginning; in my case (and I think in your case) it was 1

So my final code looked like this:

<?php
    $view = views_get_view('blog_recent');
    print views_build_view('block', $view, array(), false, 5, null, 1);
?>

Then you can set that block to appear wherever you like on your block admin page. Note that you could also choose to insert this code into a node template, a page template, a panel "custom content" area (that's what I did) or elsewhere that accepts PHP code.

Finally, this page might be of some help in exploring how this views_build_view works, though the definitions they give of each variable are not that great and there seem to be a lot of typos. But that's how I figured out, with some trial and error, how to do what I needed.

Hope that helps!

idflorin’s picture

I made a page with View Type: Listview; Fields : Image: Add your image here (it's a cck filed); Filters : Node: Published =yes; Node: Type = Story; Sort Criteria : Node: Created Time = descending

<?php
    $view = views_get_view('singlestorypage');
    if (arg(0) == 'node' && is_numeric(arg(1))) {
		$nid = arg(1); $OFFSET = $nid;
		};
    print views_build_view('embed', $view, array(), false, 5, null, $OFFSET);
?>

I tried OFFSET = 1 and works. It's skipping the latest post.
But I really nead something as above:
I know I'm wrong with $nid = arg(1) - because if my last node is 27 I don't want to skip the 27 stories.
In fact I want that if I'm on node/25 (for example) to print all the nodes published before node/25.

Actually I think I'll need the number of all stories published :(

jody lynn’s picture

This approach was useful for me. Thanks.

--Zivtech--

mooffie’s picture

if ($views->name == "my-view-name"

I have a typo here. It should be $view->name, not $views->name. I can confirm now that this function works. See here another use for this technique.