DokuWiki

It's better when it's simple

User Tools

Site Tools


tips:newssystem

This is an old revision of the document!


Recipe to include a news system in DokuWiki

This is a recipe to include a news system in DokuWiki. You'll get a form to write news articles. You'll get one summary page, where the headlines and the first few lines of text will show up. You'll get one complete page, where all news articles are listed. Articles are tagged and displayed with a publishing date, and may have a perishing date. That means, while writing an article, you could say that the article should disappear in, oh, let's say two weeks.

You may want to take a look at this stuff at work.

And, oh, you can tinker around with that stuff, it all boils down to using the template plugin and a bit of PHP code in your site template.

Requirements

  • DokuWiki (tested with version 2006-03-09b, 2006-11-06 and 2007-06-26b)
  • Command plugin for DokuWiki
  • Template extension for the command plugin

Enhance your site template

You've got an “active template directory” in your dokuwiki installation. In my installation, it's in /var/www/dokuwiki/lib/tpl/mytemplate/. Go there.

Download and unpack one of the following archives there (or copy&paste them from far below on this page):

user@server:/var/www/dokuwiki/lib/tpl/mytemplate$ wget http://fsinfo.cs.uni-dortmund.de/~dave/newssystem-0.1.tar.bz2
user@server:/var/www/dokuwiki/lib/tpl/mytemplate$ tar xvjf newssystem-0.1.tar.bz2

Edit your style.ini. This here is just an excerpt, you'll have to add the line with news.css in the section [stylesheets]:

[stylesheets]
layout.css     = screen
design.css     = screen
style.css      = screen
news.css       = screen

After everything works, you'll just have to edit news.css to get some sensible design matching your template. Maybe you'll want to edit the .php files too to get button text and error messages in your language.

How to use

First: Set the format of the input form

You'll have to create a page with the following content. Let's assume you saved it as newstemplate.

  * targetpage: newsdata
  * head: 40| |Headline
  * start: 10|date(now)|Publishing date (first appearance of the article in the list)
  * stop: 10|date(2 weeks)|Perishing date (on this day the article will disappear)
  * text: 50*5| |Your article
----

This form definition will be interpreted by datainput.php, which outputs an HTML input form following this definition and saves the submitted form data in a data page. To invoke datainput.php, see step two.

Excourse on what datainput.php does

This section may be skipped. It just contains some useful background information.

You'll see the syntax of one line of the “template” right away:

  * fieldname: fieldvalue

The fieldname is an arbitrary word at this point. It is used by datainput.php to name the form fields in HTML. After submitting the form, datainput.php saves the input on the wikipage denoted by the special field targetpage, using the fieldnames “invented” here. Another PHP script has to be written to actually interpret the dataset. E.g., the submission of the form generated by the definition above will result in the following dataset on the page newsdata:

  * head: Article Headline
  * start: 2007-12-12
  * stop: 2007-12-24
  * text: Sim salabim bam basela dusela dim.
----

Each form submission will be put on top of the existing datasets (that means: even if you make a typo in the targetpage field, the operation is non-destructive – it just adds some data, never deletes any). The only way to edit or delete datasets is to manually edit the wikipage.

The field's value (i.e. the size/type definiton of the form fields) could be divided into:

  Size | Default | Headline

… and 'Size' may be a lone integer (for one-lined text input) or something like X*Y (columns times rows of a multi-line input field). It may also be hidden (you'll need this in the case where multiple forms write to one datapage, but you want to distinct in the handling code between these forms … simply create multiple form templates, all with the same targetpage, but with different values in a hidden field).

The 'Default' part is an arbitrary text, but may include the date() function, which really just calls the PHP date() function and uses its output as default. In this example, the news articles will disappear 2 weeks after they were written, if the article author does not input another date.

'Headline' is the text which describes the input field. It will be displayed next to the corresponding input field on the page.

Therefore, datainput.php gives you a generic, configurable input form generator for your wiki. It outputs data pages in the syntax required by the template extension to the command plugin. You could create input forms for arbitrary data sets – the only thing missing is the PHP code to actually display the data in your wiki. See the template extension for hints on how to do that – for this recipe, newslist.php and newsdata.php contain the “display code”, i.e. each one implements a different view on the saved datasets. See below on how to use these.

Second: Generate input form

This command just takes the above created data page, interprets it and generates a form out of it:

#template(datainput.php|newstemplate)#

It is good practice to write step four below that on the same wiki page, so after submitting you'll see the reassuring effects of the form.

Complete suggestion for the news article input page (page writenews):

====== Write new news ======
**[ [[news|all news]] | [[writenews|write news]] | [[newsdata|edit news]] ]**
 
#template(datainput.php|newstemplate)#
 
#template(newsitems.php|newsdata)#

Third: Show article preview

Put this stuff somewhere into the start page of your wiki or whereever you like. I'd suggest putting a box around it ;-)

%template?previewlength=120&indexpage=news:news(newslist.php|newsdata)%
**[ [[news:news|all news]] | [[news:writenews|write news]] | [[data:newsdata|edit news]] ]**

Shows a preview of news in a data page (in this case from the page newsdata with a preview text length of 120 chars). The second line is just for convenience (access all news-related pages from there).

Fourth: Show complete news articles

This is the wiki page news:news:

====== News ======
**[ [[news:news|all news]] | [[news:writenews|write news]] | [[data:newsdata|edit news]] ]**
 
#template(newsitems.php|newsdata)#

The first two lines are there for convenience, the actual stuff is done in the last line.

Fifth: Edit news articles

You'll have to do that by hand. Don't worry, just open your data page and edit it. The format of the data page should explain itself. Mostly you will just correct some minor details, I expect, so I did not write a script to edit the stuff.

Bugs

  • You can't use bullet lists in news articles. The template plugin seems to disallow that.
  • You'll need to use ~~NOCACHE~~ on some pages.

Stuff to remember when tinkering around with this stuff

There are some reserved words among the field names, but not all of them are reserved by the same .php file.

datainput.php

You may use datainput.php to generate arbitrary data input forms. Just remember that the field name targetpage is reserved. All other field names will be used when writing to the target page – therefore, you may invent some, and they will be used.

The special default value date(something) will resolve the date represetation of the string 'something' on generation of the form.

newslist.php/newsitems.php

Here the field names start, stop, head and text are reserved. Any other field in the data page will be ignored.

Author

The author is Dave Kliczbor maligree [at] gmx [dot] de. Feel free to tinker around with this stuff and completely rewrite this wiki page (if you must).

Files

datainput.php

<?
/**
 * DataInput template extension
 *
 * Gives you a data input form based on a "data page".
 * You could define simple text input forms and an output data page.
 * 
 * You'll need another template extension to display the data!
 *
 * @link   http://www.dokuwiki.org/tips:newssystem
 * @author Dave Kliczbor <maligree@gmx.de>
 */
 
$params = $TEMPLATECOMMAND_SOURCE->getParamHash();
$prefix = "plugin_datainput_";
 
//now, go through all data sets
foreach( $TEMPLATECOMMAND_SOURCE->getHtmlRecords() as $rec_num => $record ) {
 
  //ok, display only if showonly is not set or showonly matches the record number
  if( (!isset($params['showonly'])) || ($params['showonly'] == "$rec_num") ) {
    //data record is only valid if "target" is set
    if( isset($record['targetpage']) ) {
 
      $targetpage = htmlspecialchars(trim($record['targetpage']));
      //security check ... evaluate form only when template data set is unchanged 
      //  (i.e. committed hidden field is still in the same template data record number)
      //and check anyway if the user is allowed to edit teh targetpage
      if( ($_POST["X-".$prefix.$targetpage] == "$rec_num") && (auth_quickaclcheck($targetpage) >= AUTH_EDIT) ) {
        $newrecord = '';
        foreach( $_POST as $postkey => $postvalue ) {
          // we only need $_POST fields that start with $prefix
          if( strpos($postkey, $prefix) === 0 ) {
            $key = substr($postkey, strlen($prefix));
            //DEBUG-Code
            //echo '<p>' . $key . '</p><p>' . $postvalue . '</p><p>';
 
            if( strpos(trim($postvalue), "\n") !== false ) {
              // this is a multilined value, so we need to prepend a linebreak
              // to achieve a multilined value for the template plugin
              $postvalue = "\n" . $postvalue;
            }
            $newrecord .= "  * " . $key . ": " . $postvalue . "\n";
          }
        }
        $newrecord .= "\n----\n\n";
        $oldrecord = rawwiki($targetpage);
 
        saveWikiText($targetpage, $newrecord.$oldrecord, "New news article");
 
        msg('Your news article has been saved successfully.');
      } else if( isset($_POST["X-".$prefix.$targetpage]) ){
        msg('Your news article could not be saved. Try to log in to gain permission to write news articles or politely ask your admin to give you permission.');
      }
 
      echo '<form id="'.$prefix.$targetpage.'" method="POST" action="'.$_SERVER['REQUEST_URI'].'">';
      echo '<input type="hidden" name="X-'.$prefix.$targetpage.'" value="'.$rec_num.'">';
      //walk through all fields in one data set
      foreach( $record as $fieldname => $fieldvalue ) {
        $fieldname = htmlspecialchars(trim($fieldname));
        //...but not through certain fields
        if( $fieldname != 'targetpage' ) {
 
          //explode field value by '|'
          $matches = explode('|', $fieldvalue);
          //$matches[0] == field type; $matches[1] = default value; $matches[2] == friendly field title; 
          $fieldtype = htmlspecialchars(trim($matches[0]));
          $fieldtitle = htmlspecialchars($matches[2]);
 
          // parse default values
          if( isset($params['default_'.$fieldname]) ) {
 
            $default_value = strtr($params['default_'.$fieldname], "_", " ");
 
          } else {  
 
            $default_value = htmlspecialchars(trim($matches[1]));
 
            if( preg_match('/^date\((.*)\)/', trim($matches[1]), $dateparam) !== 0 ) {
              $default_value = date("Y-m-d", strtotime($dateparam[1]));
            }
 
          }
 
          // output fields
          if( fieldtype == 'hidden' ) {
            echo '<input type="hidden" name="'.$prefix.$fieldname.'" value="'.fieldtitle.'">'."\n";
          } else if( preg_match('/^(\d+)\*(\d+)$/', $fieldtype, $dimensions) > 0 ) {
            echo '<p>' . $fieldtitle . '</p>' . '<p><textarea name="'.$prefix.$fieldname.'" cols="'.$dimensions[1].'" rows="'.$dimensions[2].'">'.$default_value.'</textarea></p>'."\n";
          } else if( preg_match('/^\d+$/', $fieldtype) == 1 ) {
            echo '<p>' . $fieldtitle . '</p>' . '<p><input type="text" name="'.$prefix.$fieldname.'" size="'.$fieldtype.'" value="'.$default_value.'" /></p>'."\n";
          } else {
            //DEBUG-Code
            //echo '|' . $fieldtype . "|-|" . $fieldtitle . '|';
          }
 
        }
      }
      echo '<input type="submit" value="Submit!">';
      echo '</form>';
 
    }
  }
 
}
 
?>

newsitems.php

<?
/**
 * NewsItems template extension
 *
 * Displays the complete list of news articles from a data page,
 * taking care of start and stop dates.
 *
 * @link   http://www.dokuwiki.org/tips:newssystem
 * @author Dave Kliczbor <maligree@gmx.de>
 */
 
foreach( $TEMPLATECOMMAND_SOURCE->getTextRecords() as $rec_num => $record ) {
 
  if( (!isset($record['start']) || strtotime($record['start']) < time())
   && (!isset($record['stop'])  || strtotime($record['stop'])  > time()) ) {
 
    //format start timestamp
    if( !isset($record['start']) ) {
      $date = '';
    } else {
      $date = date('l, d.m.Y ', strtotime($record['start']));
    }
 
    echo "\n\n=== " . $record['head'] . " ===\n//<sub>" . $date .  "</sub>//\n\n";
    echo $record['text'] . "\n\n----\n";
 
  } 
 
}
 
?>

newslist.php

<?
/**
 * NewsList template extension
 *
 * Displays a preview of news articles.
 *
 * @link   http://www.dokuwiki.org/tips:newssystem
 * @author Dave Kliczbor <maligree@gmx.de>
 */
 
require_once(DOKU_INC.'inc/parser/xhtml.php');
 
$xhtml_renderer = new Doku_Renderer_xhtml();
 
echo '</p><ul class="newslist">';
 
foreach( $TEMPLATECOMMAND_SOURCE->getHtmlRecords() as $rec_num => $record ) {
 
  if( (!isset($record['start']) || strtotime($record['start']) < time())
   && (!isset($record['stop'])  || strtotime($record['stop'])  > time()) ) {
 
    //format start timestamp
    if( !isset($record['start']) ) {
      $date = '';
    } else {
      $date = "Submitted on " . date('d.m.', strtotime($record['start'])) . " ... ";
    }
    $params = $TEMPLATECOMMAND_SOURCE->getParamHash();
    $page = wl( (isset($params['indexpage']) ? $params['indexpage'] : 'news:news') );
    $link = $page.'#'.$xhtml_renderer->_headerToLink($record['head']);
    echo '<li class="newslist"><b><a class="wikilink1" href="' . $link . '">' . $record['head'] . '</a></b>'."\n";
 
    $preview_length = ( isset($params['previewlength']) ? $params['previewlength'] : 200 );
    $preview_string = substr( trim( preg_replace ('/\<.*?\>/', ' ', $record['text'] ) ), 0, $preview_length );
    echo '<div class="news_preview">' . $preview_string . ' ... <br /> (<span class="newsdate">' . $date . '</span> <a class="wikilink1" href="' . $link . '">to full article</a>)</div>';
 
    echo "</li>\n";
#    echo '  * [["'.$link.'#'.$record['head'].'|' . $record['head'] . ']] ' . $date . "\n";
    
  } 
 
}
echo "</ul><p>";
 
?>

news.css

li.newslist {
  padding-bottom:1ex;
}
 
.news_preview {
  font-size:90%;
  line-height:115%;
  color:__darker__;
  margin:0;
  padding:0;
}
 
.newsdate {
  font-size:90%;
  color:__darkgray__;
}
 
div.listabocheck {
#  display:inline;
  border:1px dotted __dark__;
  background-color:__light__;
  margin-bottom:1em;
}

I like the word “stuff”, or didn't you notice? ;-)

I notice that.
Thank you very much for your recipe.
No problem ;-)
tips/newssystem.1359886791.txt.gz · Last modified: 2013-02-03 11:19 by Aleksandr

Except where otherwise noted, content on this wiki is licensed under the following license: CC Attribution-Share Alike 4.0 International
CC Attribution-Share Alike 4.0 International Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki