Bliki 1.0

From Organic Design wiki
Legacy.svg Legacy: This article describes a concept that has been superseded in the course of ongoing development on the Organic Design wiki. Please do not develop this any further or base work on this concept, this is only useful for a historic record of work done. You may find a link to the currently used concept or function in this article, if not you can contact the author to find out what has taken the place of this legacy item.

Please refer to [[Bliki 2.0 which allows tags, has a better post form and is based on Semantic MediaWiki instead of DynamicPageList.]] instead.


Bliki.jpg

I've needed to set up blog-like functionality on a few wikis now, so I want to get the common features into one place so it's easier to implement in future.

The basic features people need are a News page which shows the "blog roll" of items from a news category formatted in a blog-like with a commenting facility for each item that's more intuitive than the standard wiki talk-page paradigm. Users need to be able to subscribe to this stream of items, so it needs to be available as RSS and Atom feeds. Finally users need a simple way of creating news items without having to worry about categories or templates.

This article shows a number of simple modfications that can be made to a MediaWiki to get this basic blog functionality going and looks like the screenshot shown on the right when it's done.

The blog roll page

The "blog roll" is a page in the wiki such as News which displays a list of the items in Category:News in chronological order, newest first. The items are formatted in tables that can be styled with CSS and have the author name and creation date added. I've used a DPL query for this as follows:

<DPL>
  category             = News
  includepage          = *
  format               = ,¶{|class=news¶|-¶|¶== [[%PAGE%]] ==¶|-¶!Posted by [[User:%USER%|%USER%]] on %DATE%,¶|}¶¶,
  secseparators        = ¶|-¶|
  addfirstcategorydate = true
  addauthor            = true
  ordermethod          = categoryadd
  order                = descending
  userdateformat       = F d, Y
  count                = 10
</DPL>


Additionally, the news items are created with Template:News containing a Name and Content parameter. The template categorises the items into Category:News and appends a link for adding comments and embeds the talk page. I've also added a condition and query to the template so that if a user is reading the article directly (as opposed to reading it from the News page) then it includes a link back to the news page and includes the author and date posted. Here's an example of the template's content:

{{#ifeq:{{PAGENAME}}|News||
== This article is a [[News]] item ==
{{#dpl: title = {{PAGENAME}}
 | category             = News
 | format               = ,Posted by [[User:%USER%|%USER%]] on %DATE%,,
 | secseparators        =
 | addfirstcategorydate = true
 | addauthor            = true
 | userdateformat       = F d, Y
 | skipthispage         = false
}}

}}{{{Content}}}
<div class="news-addcomment plainlinks">[{{fullurl:Talk:{{{Name}}}|action=edit&section=new&returnto=News}} add a comment]</div>
{{#ifexist:Talk:{{{Name}}}|<div class="news-comments">
{{Talk:{{{Name}}}}}
</div>}}
<includeonly>[[Category:News]]</includeonly>

Making comments work more nicely

Adding this code to the ArticleSave hook makes sure that signatures are consistent and CSS addressable in any new sections that are added to talk pages. And also wraps the whole comment that was just added into a CSS addressable div element. This functionality only applies if the article being saved is a Talk page, and has been saved due to adding a section.

function onArticleSave( &$article, &$user, &$text, &$summary, $minor, $watch, $section, &$flags, &$status ) {
	$title = $article->getTitle();
	if( $title->isTalkPage() && array_key_exists( 'HTTP_REFERER', $_SERVER ) && strpos( $_SERVER['HTTP_REFERER'], 'section=new' ) > 0 ) {

		// Clean up signature
		$name = $user->getName();
		$date = date( "j F Y" );
		$text = trim( str_replace( '~~~~', '', $text ) );
		$text = "$text\n<div class=\"comment-sig\">Posted by [[$name]] on $date</div>";

		// Wrap the last post in a div for better CSS control
		$text = preg_replace( "|(.*^)(==[^=].+$.+)|sm", "$1<div class=\"news-comment\">\n$2</div>", $text );
	}
	return true;
}


Adding this code to the ArticleUpdateBeforeRedirect hook allows a returnto parameter to be added to the link for adding a comment (which is actually a new-section-edit link to a talk page) so that it returns back to the news page or the news item being commented on.

function onArticleUpdateBeforeRedirect( $article, &$sectionanchor, &$extraq ) {
	if( preg_match( "/returnto=(.+?)(&|$)/", $_SERVER['HTTP_REFERER'], $m ) ) $article->mTitle = Title::newFromText( $m[1] );
	return true;
}

Adding new items

It's a bit tedious for the user to have to type in template syntax with Name and Content parameters even if a preload is used to make it easier. A nicer solution is to use a form which can be done with the Semantic Forms extension, the RecordAdmin extension, or with some custom article-creation code in LocalSettings.php. I've uses RecordAdmin since the sites I'm using this functionality on already have it set up for managing tasks and activities with Wiki Organisation. Here's an image of the new blog form using RecordAdmin:

Bliki-new.jpg

Adding RSS and Atom feeds

There are many extensions for dealing with RSS in MediaWiki, but apart from the ones that handle embedding of external feeds, the ones handling RSS feeds out of the wiki are all overkill and not very stable either. The RSS feed system that comes with MediaWiki is very stable and the Recentchanges comes with a useful SpecialRecentChangesQuery hook allowing the query that selects the rows to be modified.

What I've done to create a news feed is to create a filter on the recent changes which applies if news=1 is supplied in the query-string. This parameter filters the recent-changes results to only show the creation of pages that are members of Category:News. Here's the code for the filter:

function onSpecialRecentChangesQuery( &$conds, &$tables, &$join_conds, $opts, &$query_options, &$select ) {
	if( array_key_exists( 'REQUEST_URI', $_SERVER ) && strpos( $_SERVER['REQUEST_URI'], 'news=1' ) ) {
		$tables[] = 'categorylinks';
		$conds[] = 'rc_new=1';
		$join_conds['categorylinks'] = array( 'RIGHT JOIN', 'cl_from=page_id AND cl_to=\'News\'' );
	}
	return true;
}


The feed links are added something like the following:

<html>
<a id="feed-atom" class="feedlink" title="Atom feed for this page" type="application/atom+xml" rel="alternate"
   href="/wiki/index.php?title=Special:RecentChanges&news=1&feed=atom">Atom</a>
</html>

Tidying it up with some CSS

To make it look like the screenshot shown at the beginning of the article, we'll need to add some CSS rules. The following rules placed into MediaWiki:Common.css make the news items look a lot nicer :-)

table.news {
    background-color: #f6f6f6;
    border: 1px solid #aaa;
    padding: 5px 30px 15px 30px;
    width: 700px;
    -moz-border-radius: 9px;
    -webkit-border-radius: 9px;
    -khtml-border-radius: 9px;
    border-radius: 9px;

}
table.news .editsection {
    display:none;
}
#bodyContent table.news h2 {
    margin-bottom: 0;
}
table.news th, #bodyContent .news-addcomment a.external {
    text-align: left;
    font-weight: normal;
    font-size: 75%;
    color: #666;
}
table.news th a {
    text-decoration: underline;
    color: #666;
}
.news-comment {
    margin-top: 5px;
    padding: 5px 10px;
    background: #d6d6d6;
    -moz-border-radius: 9px;
    -webkit-border-radius: 9px;
    -khtml-border-radius: 9px;
    border-radius: 9px;
}
.news-comment h2 {
    border: none;
    font-size: 125%;
    color: #666;
}
.comment-sig {
    font-size: 70%;
    color: #333;
}

See also