Tạo block lọc tội dung theo tháng với drupal 7

Creating a monthly archive block with Drupal 7 views

The level of experience that makes things easy in one version of Drupal can make tasks jarring in another. In Drupal 6, I have expertise with every level of views -- the normal stuff, like fields, filtering, and rewriting, plus more advanced features like arguments. With the Views Custom Field module, I can even use PHP to make views even more customizable. Getting that same level of familiarity with Drupal 7 views will be a challenge, but it's a fun challenge.

First views project in D7: Creating a monthly archive block for my right column. A pre-packaged version ships with the views module, but creating my own served as a crash course for Drupal 7 views. I started from the D6 tutorial at Chris Shattuck's blog, and referred to the pre-packaged version to fill in the gaps.

The goal of this tutorial is to create a block you can stick in a side column that displays linked months with a post count, and a page for each month so your visitors have somewhere to go when they click the linked months. Without further ado, here you go.

Step 1: Add a new view.

I named my view Posts by date. If you name yours Archived posts, you'll want to replace any references to that view name with yours. Set the view to show only blog post type content (or whatever type you want to collect).

When you add the view, create both a page and a block. The block is what will go in your right or left column, and the page is where users will go when they click the links in the block -- so http://www.webbykat.com/posts-by-date/201202 is the destination of the February 2012 link in my block.

Edit: As pointed out in the comments, your page's path should have a % in it to allow for the argument. If you want your page to display at posts-by-date/[date], make sure you set the path to posts-by-date/%. You'll set this on the next page, after Continue & edit.

For the block, you'll want a list of linked titles. For the page, decide whether you want a list of teasers or a list that shows the full node content. On my blog, I'm currently using a teaser list so visitors can browse what's available and then click through for what they really want to read, but I may eventually switch to full node content to decrease the required clicks to read something.

When you're happy with your settings, click Continue & edit. You can enlarge the screenshot below for comparison.


Step 2: Add a contextual filter.

If you're familiar with Drupal 6 views, just know that contextual filters are like arguments, and skip the next paragraph.

If you're not familiar with the concepts of arguments or contextual filters, they're features that get Drupal to serve up different lists of content based on a value you're providing, usually through the URL. For example, you could set up a news view at example.com/example_view with a contextual filter for years, and then any visits to example.com/example_view/2011 would show only news from 2011, while example.com/example_view/2012 would show only news from 2012. This is far more efficient than setting up a 2011 view and a 2012 view -- you do the work of one view, but get several different result pages out of it.

Back to the task at hand. Once your view has saved, click the Advanced tab in the right column to expand it. Click the add button next to contextual filters, and pick "Content: Created year + month" from the list. Apply it to all displays. This lets the view know that the information it should look for in the URL is a year and month.

Once you apply your filter, it'll take you to a screen where you can define what happens if the filter value (in this case, year and month) isn't in the URL, and what happens if it is.

Step 3: Define what happens if the value isn't in the URL.

Underneath "When the filter value is not in the URL," set it to display a summary. This will generate the "February 2012 (5)"-style links for your block.

It'll also create an index page that will come up if someone backspaces the value for your month and year and tries to get to the index. For example, on my site, http://www.webbykat.com/posts-by-date/201202 shows all the posts I made in February, and http://www.webbykat.com/posts-by-date shows every month I've made a post and how many posts I made. It's not pretty, but it helps ensure that some confused soul looking for the index won't end up at a 404 page.

Once you set it to display a summary, a new menu will appear beneath that. Give your summary a descending sort order so the later months display first, and keep it set to sort by date. Pick the list format if you want bullets/indentation and the unformatted one if you don't.

Set the base path to the path of your page. Usually this is the name of your view with hyphens instead of spaces, but you can confirm by checking the path under the page settings on the page display. In my case, this was posts-by-date.

Keep "Display record count with link" checked.


Step 4: Define what happens if the value is in the URL.

Underneath those settings, you'll see a few that get used if a year and month does show up in the URL. To get a title on your archive page, check the "Override title" box and set it to %1. That tells the view to use the first argument -- in this case, the only argument -- as the title of the page. Fortunately, it's smart enough to interpret the "201202" from your URL as "February 2012" and use the more presentable version as the page title. If you want to provide a custom breadcrumb, you can do that here as well.

When you're done, apply to all displays.

Step 5: Enable your block and set it to display in your side column.

Go to the Structure > Blocks menu and look for the new block. In my case, it's Views: Posts by date. Set it to show up in your side column region. Save.

Step 6: Test things out.

Pending any missteps in your settings, you're done. Give it a test run. If the links break, your culprit is most likely the base path setting under the contextual filters -- I originally had mine set to posts_by_date when my page path was posts-by-date. You can tweak your view settings again under Structure > Views if you need to.

Note: Someone recently asked me about an error with the out-of-the-box archive view, and pointed out that it also occurred in my recreated view. If you put a random, non-date value in your URL where the date would normally be, the page throws an error like "Warning: date_timezone_set() expects parameter 1 to be DateTime, boolean given in format_date()"; this is pretty logical since your contextual filter has told it to look for a date. To solve it:

  1. Open your contextual filter. Under "When the filter value is in the URL or a default is provided," check Specify validation criteria.
  2. On the validator dropdown that will appear, select Numeric.
  3. On the action to take dropdown, select Show "Page not found."

This should resolve the error, since it tells the view not to bother if the value it's looking for isn't a number. Instead, it will return a 404.