Page 1 of 4

[SOLVED] News Archives by Year/Month

Posted: Mon Jul 21, 2008 2:59 pm
by sam_butler
This is a question/cry for help regarding the bundled News module.

My client wants to provide users with a list of links to news items by year; like a blog archive. So let's say there were 15 articles posted in 2004, 17 in 2005, etc. In 2008, I want to show the full (paginated) list, plus a simple list under my navigation menu which has something like "News Archives: 2008, 2007, 2006, 2005, 2004," and so on.

I'm sure I could delve into the News module, find all the variables, create a custom script or UDT, etc., but I'd rather not reinvent the wheel or spend extra time if someone has already done it or knows a quick way of doing it. What I thought is perhaps it could be done with a custom summary template.

So here's what I reckon I'll need:
1) Output an array of years (or months & years if possible) during which articles are in the db, with URLs for...
2) ...a page for each year that displays *only* the articles posted during that year (I would then style the summaries and they would link to each article).

I'm going to keep on trucking with everything else, but this is my first CMSMS project and I'm liking it. Hope someone can point me in the right direction! Cheers.

Re: News Archives by Year/Month

Posted: Tue Jul 22, 2008 12:39 pm
by stopsatgreen
Here's how I did it recently; I set it to capture by month, but you could easily set it up by year instead:

1. Add a new line to your template to capture a date value you're going to supply:

Code: Select all

{content block='Date' oneline='true' assign='item_date'}
2. Create a new page for each year of the archive, and fill in the 'Date' block with the year you want it to cover.

3. Create a UDT called 'newsletter_date' to get the value of that field and pass it to the News summary template:

Code: Select all

global $gCms;
$myVar = $smarty->get_template_vars('item_date');
echo date('d F Y',strtotime($myVar));
4. Capture that value in the News summary template and filter the results based on that:

Code: Select all

{capture assign='thedate'}{newsletter_date}{/capture}
<ul>
{foreach from=$items item=entry}
{if $entry->postdate|date_format:'%m' == $thedate|date_format:'%m'}
<li>{$entry->titlelink}</li>
{/if}
{/foreach}
</ul>
This is probably a convoluted way of getting it working, so I'd love it if someone else could show a better way.

Re: News Archives by Year/Month

Posted: Wed Jul 23, 2008 2:08 am
by NaN
I've created a module called NewsMenu. (see attachement)
It is not documented and therefore it is not in the forge yet.
Additionally i did some modifications to the News module so i don't know if it will work as a general tool.

It just prints out a kind of menu wich filters news articles by years/months.

If you want to test it just download, install it and insert {cms_modue module="NewsMenu"} where you want a menu with years and months for the news.
Maybe that is what you're looking for.

Please report if there are errors or someone has some suggestions.

(rename .txt in .zip first)

Re: News Archives by Year/Month

Posted: Wed Jul 23, 2008 2:53 am
by NaN
I tried it myself and also get an error : unexpected end of archive.
I guess something went wrong when uploading it.
Just try again.

Re: News Archives by Year/Month

Posted: Wed Jul 23, 2008 2:58 am
by NaN
I tryed it several times but always the same. Before uploading it it works fine. after upload and download it file is broken ???

Re: News Archives by Year/Month

Posted: Wed Jul 23, 2008 5:41 pm
by sam_butler
Hm, interesting stopsatgreen, I will try it out and get back to you. NaN I'll send you a private message so you can email me your mod, and I'll give it a try.

Thanks a lot for your help, I didn't notice you'd posted because email notifications didn't come through for some reason ???

The site is looking nice but I can't show you yet  ;) - I'll let you know when it's done.

Re: News Archives by Year/Month

Posted: Wed Jul 23, 2008 7:29 pm
by NaN
This time it might work... (see post above for download)

Re: News Archives by Year/Month

Posted: Wed Jul 23, 2008 8:20 pm
by sam_butler
Ok NaN, tried your mod. What changes did you make to the News mod? Because for me, while it outputs the list, it's not giving me any news items in the content block. Perhaps your News mod changes facilitated this?

Also, amusingly, in the module info you made a typo: {cms_modue...} instead of module. Lazy me copied and pasted and met a Smarty error!

Stopsatgreen, I tried your method and of course it works, but I will need to create archive pages for each year. Not impossible, but I'd need to include in the documentation for my client how to do it each year, assuming the site will continue to exist in a year! Good thing about CMSMS of course, is that the site can be changed while the content remains intact. So I want to plan for this.

Also with that method, I need to manually create the list that NaN's mod outputs, and have my client add to it when adding a news archive page. It increases their maintenance overhead but it does work, so thank you.

Keep those cogs whirring and let me know if you have any other bright ideas! I'll keep going with the rest of the project...

Re: News Archives by Year/Month

Posted: Wed Jul 23, 2008 8:57 pm
by NaN
I'll have to take a look into my modified News Module. Maybe there is just a kind of params of the NewsMenu that the NewModule natively does not know.
These modifications were quite easy, I remember.
I'll post it here.

Re: News Archives by Year/Month

Posted: Wed Jul 23, 2008 9:04 pm
by sam_butler
Cheers. Don't know where you are in the world but it's late here, so if I don't get a chance to try it tonight, I'll be on it first thing tomorrow.

Re: News Archives by Year/Month

Posted: Thu Jul 24, 2008 12:28 am
by NaN
It's late here, too, but i'm a fulltime workaholic...  8)

So here we go:

Line numbers in files depends on the modules version. So you will sometimes get better results when searching for the sample code.
The following modifications has been tested with NewsModule 2.6.1 and 2.8. Line numbers refers to the 2.8 version.

1st of all we need to add some params to the Newsmodule.
This is done in a kind of initial module file. In CMSms it is usually the [Name_of_the_module].module.php.
So open the file modules/News/News.module.php.
Look for a function called SetParameters() (near line 54).
Within that function there is an if-loop:

Sample:

Code: Select all


...

global $CMS_VERSION;
$res = version_compare( $CMS_VERSION, '1.1' );
if( $res >= 0 )
{
	#
	# For 1.1's enhanced security checking, each
	# parameter that is passed in a frontend url or
	# frontend form needs to be typed here.
	#

	...

Within that if-loop you just need to insert the following lines to set some additional params to the Newsmodule for the frontend:

Code: Select all


### Added by NaN for NewsMenu: ###
    $this->SetParameterType('newsmenu',CLEAN_STRING); // should be int, or boolean
    $this->SetParameterType('parent_item',CLEAN_INT); // should be int, or boolean
    $this->SetParameterType('active_item',CLEAN_INT); // should be int, or boolean
###

The comments "Added By NaN" are not for ads here but just to mark what code is no default code of the Newsmodule.
Since you need to modify your NewsModule every time you updated it, it could be useful to mark where you made what changes.

Save the file.

Next step is to tell the Newsmodule to show only articles where the newsdate is within the selected year/month.
The modules output is processed either in a function called DoAction() within the initial module file or in a separat default file that will be executed when the module is just called with the {cms_module module="Module_Name"} syntax.
The default file is always called action.default.php. The NewsModule uses the default file method.
So open modules/News/action.default.php.
Look for the following code (near line 112):

Sample:

Code: Select all


...

$query1 .= "(".$db->IfNull('start_time',$db->DBTimeStamp(1))." < ".$db->DBTimeStamp(time()).") ";
$query2 .= "(".$db->IfNull('start_time',$db->DBTimeStamp(1))." < ".$db->DBTimeStamp(time()).") ";
if (isset($params['showarchive']) && $params['showarchive'] == true) {
  $query1 .= " AND (end_time < ".$db->DBTimeStamp(time()).") ";
  $query2 .= " AND (end_time < ".$db->DBTimeStamp(time()).") ";
 }

...

Put the queries 1 and 2 of the first two lines into an if-loop:

Code: Select all


if($newsmenu == false) # <- if-loop added by NaN for NewsMenu; queries are original code
{
	$query1 .= "(".$db->IfNull('start_time',$db->DBTimeStamp(1))." < ".$db->DBTimeStamp(time()).") ";
	$query2 .= "(".$db->IfNull('start_time',$db->DBTimeStamp(1))." < ".$db->DBTimeStamp(time()).") ";
}

if (isset($params['showarchive']) && $params['showarchive'] == true) {
  $query1 .= " AND (end_time < ".$db->DBTimeStamp(time()).") ";
  $query2 .= " AND (end_time < ".$db->DBTimeStamp(time()).") ";
 }

Before that code (near line 112) just insert the following one:

Code: Select all


### added by NaN for NewsMenu: ###
$newsmenu = false;
if(isset($params['newsmenu']) && (strtolower($params['newsmenu'])=='true' || $params['newsmenu']==true))
{
	$news =& $this->GetModuleInstance('NewsMenu');
	if( !$news )
	{
		return;
	}

	$parent_item = '';
	if(isset($params['parent_item']))
		$parent_item = $params['parent_item'];
	else if(isset($news->smarty->params[$news->smarty->id.'parent_item']))
	{
		$parent_item = $params['parent_item'] = $news->smarty->params[$news->smarty->id.'parent_item'];
	}
	else
	{
		foreach($_GET as $key=>$val)
		{
			if(endswith($key,'parent_item'))
			{
				$parent_item = $params['parent_item'] = $val;
			}
		}
	}
	
	$active_item = '';
	if(isset($params['active_item']))
		$active_item = $params['active_item'];
	else if(isset($news->smarty->params[$news->smarty->id.'active_item']))
	{
		$active_item = $params['active_item'] = $news->smarty->params[$news->smarty->id.'active_item'];
	}
	else
	{
		foreach($_GET as $key=>$val)
		{
			if(endswith($key,'active_item'))
			{
				$active_item = $params['active_item'] = $val;
			}
		}
	}
	
	if($parent_item != '')
	{
		if($parent_item == $active_item)
		{
			$news_date_min = mktime(0, 0, 0, 1, 1, $parent_item);
			$news_date_max = mktime(0, 0, 0, 1, 1, $parent_item+1);
		}
		else
		{
			$news_date_min = mktime(0, 0, 0, $active_item, 1, $parent_item);
			$news_date_max = mktime(0, 0, 0, $active_item+1, 1, $parent_item);
		}
		$query1 .= "(".$db->IfNull('start_time',$db->DBTimeStamp(1))." > ".$db->DBTimeStamp($news_date_min)." AND ";
		$query1 .= $db->IfNull('start_time',$db->DBTimeStamp(1))." < ".$db->DBTimeStamp($news_date_max).") ";
		$query2 .= "(".$db->IfNull('start_time',$db->DBTimeStamp(1))." > ".$db->DBTimeStamp($news_date_min)." AND ";
		$query2 .= $db->IfNull('start_time',$db->DBTimeStamp(1))." < ".$db->DBTimeStamp($news_date_max).") ";
		$newsmenu=true;
	}
}
###

After that we just need to add some params to the details links.
Look for the following uncommented code (near line 350 before and near line 430 after modification):

Sample:

Code: Select all


...

#CreateLink($id, $action, $returnid='', $contents='', $params=array(), $warn_message='', $onlyhref=false, $inline=false, $addttext='', $targetcontentonly=false, $prettyurl='')
...

Before that code insert the following one:

Code: Select all


### Added by NaN for NewsMenu: ###
      if (isset($params['parent_item']))
      {
	$sendtodetail['parent_item'] = $parent_item;
      }
      if (isset($params['active_item']))
      {
	$sendtodetail['active_item'] = $active_item;
      }
###


The last thing is to call the NewsMenu with the new param we defined in the News.module.php:

Code: Select all


{news newsmenu=true}

I hope that's all.

PS: this only works if NewsMenu and NewsModule are called together.
E.g. call the News within your content and the NewsMenu within your menu area.

I think it would be a better idea to create a plugin or userdefined tag of the NewsMenu instead of a module since it doesn't need any tables etc. But i dunno how to create a plugin with that code since it's indeed late for today.

Greetings from Germany,
NaN.

Re: News Archives by Year/Month

Posted: Thu Jul 24, 2008 7:15 am
by sam_butler
Cheers NaN. I'll give these changes a whirl, hopefully today. Looks like I have to put together a submission for the client this morning. Lots of jpegs to add... I'll get back to you when I've created the beast with your code  ;D

Re: News Archives by Year/Month

Posted: Thu Jul 24, 2008 8:42 am
by stopsatgreen
I will need to create archive pages for each year. Not impossible, but I'd need to include in the documentation for my client how to do it each year,
All they should have to do is add a new page, and in the 'Date' block enter the year of the archive. My method is a little convoluted, but it has the advantage of not breaking if the News module is upgraded, which happens with NaN's version.

Of course, it would be better if the developers could be persuaded to add parameters to filter by date:

http://dev.cmsmadesimple.org/tracker/index.php?func=detail&aid=1550&group_id=8&atid=112

Re: News Archives by Year/Month

Posted: Thu Jul 24, 2008 9:03 am
by sam_butler
Agreed, it should be native to the module. Some people use it as a blog, which reminds me of WordPress' archive which appears in the sidebar. I think it was something like this that my client was looking for. I got your solution to work by the way, and I just set up a 2007 archive. There's news from 2003 to 2008 so I will have to create a page for each and what I meant was that in future, the client or his whoever is administering the site will need to add another page each year. It's hardly the most difficult thing, which is why I said I would just have to include it in my documentation. I think we could be on to a winner. I'm still exploring NaN's idea though.

Cheers mate!

Re: News Archives by Year/Month

Posted: Thu Jul 24, 2008 10:18 am
by blast2007
sam_butler wrote: Agreed, it should be native to the module. Some people use it as a blog, which reminds me of WordPress' archive which appears in the sidebar. I think it was something like this that my client was looking for. I got your solution to work by the way, and I just set up a 2007 archive. There's news from 2003 to 2008 so I will have to create a page for each and what I meant was that in future, the client or his whoever is administering the site will need to add another page each year. It's hardly the most difficult thing, which is why I said I would just have to include it in my documentation. I think we could be on to a winner. I'm still exploring NaN's idea though.

Cheers mate!
Hi all
you can use thisworking patch to achieve what you needs. Parameters are startperiod and endperiod.

Calguy told me that we have to wait until 1.4 is out before these kind of patches will be integrated in the official module. We hope.

Regards
blast