Recent Changes - Search:

Cookbook

PmWiki

pmwiki.org

BlogWithPageList

Summary: How to build a blog system with pagelists
Version: 26 October 2005
Prerequisites: Requires at least PmWiki version: 2.1.beta; last tested on PmWiki version: 2.0.3
Status:
Maintainer: MarcioRPS
Categories: Blog

Question

Can I make a blog just using the PageList Directive?

Answer

Well, of course.

The pagelist directive is very flexible (and getting better every day!). Therefore, there are many different ways to use it to achieve what would stand for a blog. A general idea will be described first, and below many other ideas about how to deviate from this strategy. HansB has joined those ideas in an experimental blog bundle.

The idea is that entries in the log are different wiki pages. We use the pagelist directive to make beautifull presentations of it, from a blog page containing the full text of the last entries to a sidebar containing just the entries. The blog entries all belong to a group called BlogGroup.

This invocation:

(:PageList group=BlogGroup fmt=#include list=normal count=10 order=-ctime :)

will be replaced by PmWiki with the complete text of the last 10 entries created (not only modified) in the BlogGroup group. For this to work you need to add the following custom fmt=#include to Site.PageListTemplates:

fmt=#include

This format includes whole pages, with titles as links to the pages, separated by a horizontal rule underneath each page's content. An edit link appears if authorised as editor.

[[#include]]
(:if auth edit:)
%rfloat%[[{=$FullName}?action=edit|[-edit-]]](:if:)
!!![[{=$FullName}|[+{=$Title}+]]]
(:include {=$FullName}:)
----
(:if equal {>$Group}:)
(:title {$Title}:)(:if:)
[[#includeend]]

Note: {$Title} is added to the end to preserve the page title, so it will not be replaced by any title given with the included pages. PmWiki may change this in future to preserve titles automatically. So this is a bit of a hack here to overcome a present limitation in PmWiki.

fmt=#blogtitles

Pagelist of spaced blog titles with date stripped for sidebar.

[[#blogtitles]](:if equal {<$Group}:)
>>blogtitles<<(:if:)
* [[{=$Namespaced}]]
(:if equal {>$Group}:)
>><<(:if:)
[[#blogtitlesend]]

You can alter this to fit many purposes. For example, change count=10 in the pagelist to the amount of entries you want listed (and remember count can have negative values). You can find more info on how to tweak those values in Cookbook.PagelistExplained and Site.PageListTemplates .

And that is the format for a list of only the entries' names, best suited for a SideBar or listing page:

(:PageList group=BlogGroup fmt=#blogtitles list=normal count=10 order=-ctime :)

The format below includes just the first paragraph of each page in a pagelist. Just start each blog entry with a introduction/teaser.

fmt=#headerinclude

[[#headerinclude]]
(:include {=$FullName} para=1:)
!!!!Full article [[{=$FullName}|[+{=$Title}+]]]
----
(:if equal {>$Group}:)
(:title {$Title}:)(:if:)
[[#headerincludeend]]

(:pagelist group=BlogEntries order=-time fmt=#headerinclude count=5:)

Naming and placing of blog entries

If you do as explained above, all your entry-pages will be separated from everything else in their particular group. This way, their names are easy to read and understand.

You can add the blog group in the search exclude patterns so that your blog entries won't mess the rest of your wiki. If you have many blogs you can specify a prefix for the blog groups and add the prefix to the search patterns.

Another option is making all your blog entries have a name that start with a date. For example: 2006-02-03-todayIEditedTheCookbook. This have many advantages:

  • it is much faster for the sorting (order=ctime forces pmwiki to open all the files)
  • allows you to create pages not refering to the moment you are creating them
  • it might make for better understandability
  • it might allow you to avoid having a blog group, instead leaving the blog entries in a personal group and sorting them through a list= argument to the pagelist.

Then each new blog entry must be named beginning with the date, always in the same format, and with the year first, then month, then day, etc, as specifically as one wants. For example, 2005-10-25-ThisIsMyFirstEntry, or 197910 or something of the like. Remember to stick to a same format. This is very important so that the ordering of the pages will be correct.

At first, you will have to write those names in the address bar of your browser, and they will NOT appear as WikiWords. This can be changed (see below).

If the blog entries all start with the date, you can create a search pattern that only show blog entries. Then when you use list=dates inside your pagelist directive you exclude other pages. To to this, use the following code:

$SearchPatterns['dates'][] = '/\.[0-9]{4}/';

Making all entries alike

If you feel that your blog entries need to share a common style, you can set an Edit Template for the group to try and make all entries follow a common format.

Utilities for a better blog experience

Add the following code to config.php, or install blogdate.phpΔ by copying the script to the cookbook directory and adding to config.php include_once("$FarmD/cookbook/blogdate.php");

 /* page variables defined in blogdate.php */ 
# add page variable {$Today}, formats today's date as yyyy-mm-dd
$FmtPV['$Today'] = 'strftime("%Y-%m-%d", time() )';

# add page variable {$BlogDate}, displays as page creation date
$FmtPV['$BlogDate'] = 'strftime("%Y-%m-%d", $page["ctime"])';

# add page variable {$BlogTitle}, displays as spaced name with date stripped off
$FmtPV['$BlogTitle'] = 'StripDate($pagename)';
function StripDate($pagename) {
    $sd = preg_replace("/[^.]*\.([\d\-]*)(.*)/e","'$2'==''?'$1':'$2'",$pagename); 
    $BlogTitle = AsSpaced($sd);
    return $BlogTitle;
}

This adds several tools:

  • a {$Today} page variable which displays as today's date in the format yyyy-mm-dd
  • a fmt=#blogtitles format option for pagelist, which strips away the date part of the page names, to give nice lists of names only. The pagelist template is described below.
  • a {$BlogTitle} page variable which displays the pagename without the date part (if there is more than just the date in the page name) and spaces the words.
  • a {$BlogDate} page variable which displays the page creation date in the format yyyy-mm-dd.

You can use (:title {$BlogTitle}:) in the page. Best include this in an Edit Template to be used for all blog pages. {$BlogTitle} is defined as a custom page variable in blogdate.phpΔ. It strips the date part from the name and spaces the name. The blog pages will appear in pagelists also with this stripped title. If there is no name part then the date part will remain as the page name.

The NewPageBoxPlus recipe allows you to creates a newpagebox which has today's date already in it as an initial value, and you just need to add the blog title. It creates new blog pages in group "Blog". Add the following markup somewhere to create a simple form for creating new blog pages:

(:newpagebox button=right label="New Blog Entry" size=40 base=Blog.HomePage value="{$Today}-":)

Warning

If you make a pagelist with the include format and it includes itself it might generate problems, akin to what happens when you put a mirror in front of another. (Maybe Pm stopped it from happening with the new pagelist, I'm not sure, but it used to give big problems...)

Notes

Releases

Well, I am not really counting this, but after the adoption of PagelistTemplates it should be at least 0.4

Comments

(Moved from its own page)

If you use the blog with page list recipe you might want to use the following to easily create new blog entries. It will add the directive (:newdateform:) that will be replaced by a form with year, month and day select box. This is a Ugly Hack, I think.


Markup('newdateform', '>links',
  '/\\(:newdateform:\\)/e',
  "NewDateForm()");
##NewDateForm() returns a form to creating a new date
function NewDateForm() {
$formOut = '<form action="" method="post" name="Data" id="Data">
<p><input type="text" name="iTitulo" id="iTitulo" size="40" maxlength="60" /></p>
  <p>
    <select name="iDia" id="iDia">
      <option value="01" selected>01</option>
      <option value="02">02</option>
      <option value="03">03</option>
      <option value="04">04</option>
      <option value="05">05</option>
      <option value="06">06</option>
      <option value="07">07</option>
      <option value="08">08</option>
      <option value="09">09</option>
      <option value="10">10</option>
      <option value="11">11</option>
      <option value="12">12</option>
      <option value="13">13</option>
      <option value="14">14</option>
      <option value="15">15</option>
      <option value="16">16</option>
      <option value="17">17</option>
      <option value="18">18</option>
      <option value="19">19</option>
      <option value="20">20</option>
      <option value="21">21</option>
      <option value="22">22</option>
      <option value="23">23</option>
      <option value="24">24</option>
      <option value="25">25</option>
      <option value="26">26</option>
      <option value="27">27</option>
      <option value="28">28</option>
      <option value="29">29</option>
      <option value="30">30</option>
      <option value="31">31</option>
    </select>
    <select name="iMes" id="iMes">
      <option value="01" selected>Janeiro</option>
      <option value="02">Fevereiro</option>
      <option value="03">Mar&ccedil;o</option>
      <option value="04">Abril</option>
      <option value="05">Maio</option>
      <option value="06">Junho</option>
      <option value="07">Julho</option>
      <option value="08">Agosto</option>
      <option value="09">Setembro</option>
      <option value="10">Outubro</option>
      <option value="11">Novembro</option>
      <option value="12">Dezembro</option>
    </select>
    <input name="iAno" type="text" id="iAno" value="2005" size="6"> 
    at 
    <input name="iHora" type="text" id="iHora" value="12" size="4"> : 
<input name="iMin" type="text" id="iMin" value="00" size="4"></p>
<p>
	<input name="vai" type="button" id="vai" value="Vai!"
	onclick="mF = document.getElementById( \'Data\' );
	mString = document.location.href.replace(/[^.\/]+$/,
	(mF.iAno.value+mF.iMes.value+mF.iDia.value+mF.iHora.value+
	mF.iMin.value+mF.iTitulo.value+\'?action=edit\'));
	document.location.href = mString;" >
</p>
</form>';
return Keep($formOut);
}


It works fine for me too. It would be fine to have just a few lines of each page in the blog and a link to the page after these lines noe November 15, 2005, at 03:09

You could use PagelistTemplateSamples#teaser or make a modified fmt=#include by adding lines=5 to (:include {=$FullName} lines=5:) in the #include template section. - HansB January 03, 2006, at 04:25 PM

Using any other order-parameter to the pagelist than "name" or "-name" forces the pagelist algorithm to load each file. This might get a performance bottleneck if you are having a lot of blog entries. (I thought about using "order=-ctime" instead of having the date in the filename). - Balu


I've been thinking about how this setup could work with RSS to create a blog-like RSS feed. The closest thing to that available on your site, from what I can tell, would be /BlogPages/RecentChanges?action=rss. Obviously what's missing there is , usually the full text of the most recent 10 pages are included in blog rss feeds, and then of course you have enclosures and the like associated with podcasts. Cookbook:RSSImproved is a beginning of this sort of thing, but sadly it hasn't been ported for 2.1.betawhatever yet--with feeds.php instead of rss.php. What seems to not be working, to me, is RSS feeds of category pages, archive pages, or indeed the main page Blog/Blog. It appears that included pages don't show up in RSS feeds. It seems like feeds.php is still in development so maybe it will all become clear in the future...? - JonHaupt

RSS feeds can be set up including pagelist parameters now. So you can use

     ...?action=rss&group=BlogPages&list=blog&order=-ctime&count=50

to get a feed of the last 50 pages from group BlogPages in order of creation time.

you can also add feed links to all blog pages, so visitors with browsers like Firefox can click the rss feed symbol and add the blog pages to their bookmarks easily.

Add to config.php:

## add blog feed links to header
$group = FmtPageName('$Group', $pagename);
if ($group=='Blog' || $group=='BlogPages' || $group=='BlogComments') {
  $HTMLHeaderFmt['blogrsslink'] =
    "\n <link rel='alternate' title='\$WikiTitle Blog RSS Feed'
      href='\$ScriptUrl?action=rss&group=BlogPages&list=blog&order=-ctime&count=50'
      type='application/rss+xml' />\n  ";
  $HTMLHeaderFmt['blogatomlink'] =
    "<link rel='alternate' title='\$WikiTitle Blog Atom Feed'
      href='\$ScriptUrl?action=atom&group=BlogPages&list=blog&order=-ctime&count=50'
      type='application/atom+xml' />\n  ";
}

Of course to have rss output it would also need to have pmwiki's rss feed enabled with:

# add rss feed supply capability
if ($action == 'rss' || $action == 'atom') {
     @include_once("$FarmD/scripts/feeds.php"); }

~HansB


Following HansB's idea of the page variable, I did come up with this:

 
function ReadDateFromName ( $dc ) {
	global $TimeFmt;
	$dc = preg_replace("/(^|\.)([-\\d]*)/", '$2', $dc);
	$dc = preg_replace("/-/", '', $dc);
	$dc = $dc . substr("20051002093000", strlen($dc));
	return '(' . strftime($TimeFmt,
		mktime(substr($dc, 8, 2),
		substr($dc, 10, 2),
		substr($dc, 12, 2),
		substr($dc, 4, 2),
		substr($dc, 6, 2),
		substr($dc, 0, 4))) . ') ';
}
# add page variable {$DateOnName}, using global date fmt
$FmtPV['$DateOnName'] = 'ReadDateFromName ( $pagename )';

What this does is: it makes a pagevariable {$DateOnName} which is replaced by the date referenced in the name of the page, but formated following the sitewide $TimeFmt formating of dates (that is, the same that goes on RecentChanges pages and stuff...) MarcioRPS

See Also

Contributors

Edit - History - Print - Recent Changes - Search
Page last modified on April 25, 2007, at 01:43 PM