twitter plugin

Compatible with DokuWiki

No compatibility info given!

plugin Will show Tweets from Twitter

Last updated on
2009-06-30
Provides
Syntax

Tagged with embed, listing, search, social, users

Purpose

IF you want to show some tweets from twitter on a DokuWiki page, use this Plugin. The syntax is easy:

[TWITTER:TYPE:USERNAME/SEARCHWORD:COUNT]

Replace the following:

  • TYPE: Valid options are USER and SEARCH: USER will show a timeline of a user and SEARCH will search for a given word on twitter.
  • USERNAME/SEARCHWORD: The name of the user (in USER mode) or word (in search mode).
  • COUNT: The number of tweets to show, when in user mode.

And here comes some valid examples:

//The 5 latest tweets from user schwarzenegger.
[TWITTER:USER:schwarzenegger:5]
//All tweets from user BritneySpears
[TWITTER:USER:BritneySpears]
//Search for the word mj
[TWITTER:SEARCH:mj]
//Search for the word dokuwiki
[TWITTER:SEARCH:dokuwiki]

(Not that I would insert them in my DokuWiki ;-) )

Maybe you can use it, to show some tweets related to your company, or insert the Tweets from your employees.

Information

I created that plugin in around 30 minutes, so it's only a first demo and I personally don't like the look. But at least it's working. I will do some improvements, when I have more free time.

Installation

Save the following code into syntax.php and copy it into folder: /lib/plugins/twitter/conf

default.php
<?php
/**
 * Options for the Twitter plugin
 */
$conf['timeout']          = 60;        // timeout for twitter news cache

Save the following code into syntax.php and copy it into folder: /lib/plugins/twitter/

action.php
<?php
/**
 * Twitter Plugin
 *
 * Action plugin component, for cache validity determination; based on the Source Plugin/Action scripts
 *
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
 * @author     Christopher Smith <chris@jalakai.co.uk> ; rewritten for twitter plugin: Björn Kalkbrenner <terminar@cyberphoria.org>
 */
if(!defined('DOKU_INC')) die();  // no Dokuwiki, no go
 
if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
require_once(DOKU_PLUGIN.'action.php');
 
/**
 * All DokuWiki plugins to extend the parser/rendering mechanism
 * need to inherit from this class
 */
class action_plugin_twitter extends DokuWiki_Action_Plugin {
 
    /**
     * return some info
     */
    function getInfo(){
      return array(
        'author' => 'Christopher Smith',
        'email'  => 'chris@jalakai.co.uk',
        'date'   => '2006-12-22',
        'name'   => 'Source Plugin',
        'desc'   => 'Twitter plugin cache',
        'url'    => 'http://wiki.splitbrain.org/plugin:twitter',
      );
    }
 
    /**
     * plugin should use this method to register its handlers with the dokuwiki's event controller
     */
    function register(&$controller) {
      $controller->register_hook('PARSER_CACHE_USE','BEFORE', $this, '_cache_prepare');
    }
 
    /**
     * prepare the cache object for default _useCache action
     */
    function _cache_prepare(&$event, $param) {
      $cache =& $event->data;
 
      // we're only interested in wiki pages and supported render modes
      if (!isset($cache->page)) return;
      if (!isset($cache->mode) || !in_array($cache->mode,array('i','metadata'))) return;
 
      $max_age = $this->_cache_maxage($cache->page);
 
      if (is_null($max_age)) return;
 
      if ($max_age <= 0) {
        // expire the cache
        //no cache for twitter!
        $event->preventDefault();
        $event->stopPropagation();
        $event->result = false;
        return;
      }
 
      $cache->depends['age'] = !empty($cache->depends['age']) ?  min($cache->depends['age'],$max_age): $max_age;
 
    }
 
    /**
     * determine the max allowable age of the cache
     *
     * @param   string    $id         wiki page name
     *
     * @return  int                   max allowable age of the cache
     *                                null means not applicable
     */
    function _cache_maxage($id) {
 
      $hasPart = p_get_metadata($id, 'relation haspart');
 
      if (empty($hasPart) || !is_array($hasPart)) return null;
 
      $age = 0;
      foreach ($hasPart as $file => $data) {
        if ($file == "_plugin_twitter")
        {
            //this is us, outdate the cache if older than the configured seconds
            return $this->getConf('timeout');
        }
      }
 
      return $age ? time()-$age : null;
    }
 
}
syntax.php
<?php
/**
 * Twitter Plugin
 *
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
 * @author     Christoph Lang <calbity@gmx.de>
 */
 
// based on http://wiki.splitbrain.org/plugin:tutorial
 
// must be run within DokuWiki
if (!defined('DOKU_INC')) die();
 
if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN', DOKU_INC . 'lib/plugins/');
require_once(DOKU_PLUGIN . 'syntax.php');
 
/**
 * All DokuWiki plugins to extend the parser/rendering mechanism
 * need to inherit from this class
 */
class syntax_plugin_twitter extends DokuWiki_Syntax_Plugin {
    function getInfo() {
        return array(
        'author'  => 'Christoph Lang',
        'email'   => 'calbity@gmx.de',
        'date'    => '2008-07-05',
        'name'    => 'Twitter Plugin',
        'desc'    => 'Show Tweets from Twitter',
        'url'     => 'http://www.google.de'
        );
    }
 
    private function replace($data) {
 
 
    		$sResponse = "<h1>".$data[1]."</h1>";
    		$data = $data[0];
 
    		if(!isset($data)){
    			return $sResponse."<h4>Twitter is down....</h4>";
    		}
    		$sResponse .= '<table class="twitterentries" style="width:100%;">';
 
 
    		foreach($data as $entry){
 
    			$text=$entry->text." ";
    			$image=$entry->user->profile_image_url;
    			$time=$entry->created_at;    			
    			$time = strtotime($time);
    			//$time = date("Y-m-d H:i:s",$time);
    			$time = $this->Timesince($time);
    			$from=$entry->from_user;
    			$name = "";
    			if(!empty($entry->user->name))
	    			$name = " (".$entry->user->name.")";
 
    			if(empty($from))
    				$from=$entry->user->screen_name;
 
    			if(isset($entry->profile_image_url))
    			{
    			 $image=$entry->profile_image_url;
    			}
 
    			// get links
          $search = array(
            '`((?:https?|ftp)://\S+[[:alnum:]]/?)`si',
            '`((?<!//)(www\.\S+[[:alnum:]]/?))`si'
          );
          $replace = array(
            '<a href="$1"  target="_blank">$1</a> ',
            '<a href="http://$1" target="_blank">$1</a>'
          );
          $text = preg_replace($search, $replace, $text);
 
    			// get hashtags
    			if (preg_match_all('/#(.*?)\s/', $text, $arMatches))
    			{
    				for($i=0; $i < count($arMatches[0]); $i++)
    			   		$text = str_replace($arMatches[0][$i], '<a target="_blank" href="http://search.twitter.com/search?q=' . $arMatches[1][$i] . '">' . $arMatches[0][$i] . "</a>", $text);
          }
 
    			// get twitterer
    			if (preg_match_all('/@(.*?)\s/', $text, $arMatches))
    			{
    				for($i=0; $i < count($arMatches[0]); $i++){
    			   $strTwitterer = preg_replace('/\W/', '', $arMatches[0][$i]);
    			   $text = str_replace($strTwitterer, '<a target="_blank" href="http://twitter.com/' . $strTwitterer . '">' . $strTwitterer . "</a>", $text);
    			  }
          }
 
    			$sResponse .= '<tr onmouseover="this.style.backgroundColor=\'#cccccc\';" onmouseout="this.style.backgroundColor=\'\';" style="width:100%;"><td style="width:48px;"><img width="48" src="'.$image.'" alt="'.$from.'"/></td><td>'.$text.'<br/>About '.$time.' ago from <a target="_blank" href="http://twitter.com/'.$from.'">'.$from. $name.'</a></td></tr>';
    		}
    		$sResponse .= "</table>";
 
 
        return $sResponse;
    }
    /* Works out the time since the entry post, takes a an argument in unix time (seconds)  
		*/  
		public function Timesince($original) {   
		    // array of time period chunks   
		    $chunks = array(   
		    array(60 * 60 * 24 * 365 , 'year'),   
		    array(60 * 60 * 24 * 30 , 'month'),   
		    array(60 * 60 * 24 * 7, 'week'),   
		    array(60 * 60 * 24 , 'day'),   
		    array(60 * 60 , 'hour'),   
		    array(60 , 'min'),   
		    array(1 , 'sec'),   
		    );   
 
		    $today = time(); /* Current unix time  */  
		    $since = $today - $original;   
 
		    // $j saves performing the count function each time around the loop   
		    for ($i = 0, $j = count($chunks); $i < $j; $i++) {   
 
		    $seconds = $chunks[$i][0];   
		    $name = $chunks[$i][1];   
 
		    // finding the biggest chunk (if the chunk fits, break)   
		    if (($count = floor($since / $seconds)) != 0) {   
		        break;   
		    }   
		    }   
 
		    $print = ($count == 1) ? '1 '.$name : "$count {$name}s";   
 
		    if ($i + 1 < $j) {   
		    // now getting the second item   
		    $seconds2 = $chunks[$i + 1][0];   
		    $name2 = $chunks[$i + 1][1];   
 
		    // add second item if its greater than 0   
		    if (($count2 = floor(($since - ($seconds * $count)) / $seconds2)) != 0) {   
		        $print .= ($count2 == 1) ? ', 1 '.$name2 : ", $count2 {$name2}s";   
		    }   
		    }   
		    return $print;   
		}  
 
 
    function connectTo($mode) {	
				$this->Lexer->addSpecialPattern('\[TWITTER\:USER\:.*?\]', $mode, 'plugin_twitter');
				$this->Lexer->addSpecialPattern('\[TWITTER\:SEARCH\:.*?\]', $mode, 'plugin_twitter');
 
				$this->Lexer->addSpecialPattern('{{twitter>user\:.*?}}', $mode, 'plugin_twitter');
				$this->Lexer->addSpecialPattern('{{twitter>search\:.*?}}', $mode, 'plugin_twitter');
 
    }
 
    function getType() { return 'substition'; }
 
    function getSort() { return 314; }
 
    function handle($match, $state, $pos, &$handler) {
 
    		$match = str_replace(array(">","{{","}}"),array(":","[","]"),$match);
 
    		$match = substr($match,1,-1);
    		$data = explode(":",$match);    	
 
    		$number ="";    		
 
 				$data[2] = str_replace(" ","%20",$data[2]);
    		if(strtoupper($data[1]) == "SEARCH"){
 
    			@$json = file_get_contents("http://search.twitter.com/search.json?q=".$data[2].$number);
    		}else{
 
    			if(isset($data[3]))
    				$number = "?count=".$data[3];
 
    			@$json = file_get_contents("http://twitter.com/statuses/user_timeline/".$data[2].".json".$number);		
 
				}
 
				$decode = json_decode ( $json );
 
				if(isset($decode->results))
				{
				  return array($decode->results,"Results for search: ".str_replace("%20"," and ",$data[2]));
				}
 
        return array($decode,"Timeline from ".$data[2]);
    }
 
    function render($mode, &$renderer, $data) {
 
        if ($mode == 'xhtml') {
            // prevent caching to ensure content is always fresh
            $renderer->info['cache'] = false;
 
            $renderer->doc .= $this->replace($data);
            return true;
        } elseif ($mode == 'metadata'){
            // for metadata renderer
            $renderer->meta['relation']['haspart']['_plugin_twitter'] = true;
            return true;
        }
 
        return false;
    }
}

Discussion

I would like to send dokuwiki changes (the changelog) to twitter automatically. How can I do that? citizenkeys 2010/04/17 19:29

That is not possible with this plugin. You would need another plugin to do automatic tweeting of the changelog. The plugin needs to be a action plugin and not a syntax plugin. Currently i'm not havin any plans to realize that, althought it would be really easy because Twitter has a really good API. Christoph Lang
As they say 'better late than never'. I created a new plugin called autotweet that automatically posts Tweets with page changes of specific pages to Twitter using the oAuth authentication protocoll. You can specify the look and feel of the Tweet to suit your needs and also specify which pages should be regarded. I hope this is what you had in mind, maybe it's still usefull to somebody. jdt 2011/10/06 11:10

Can you (or anybody!) please write a plugin to send dokuwiki updates to twitter? Right now, my site has a plugin to automatically send sitemap updates to Google. We would like to send page updates automatically to twitter. citizenkeys 2010/04/17 19:29

I wouldn't even know what to tweet on a page update, because 140 chars not much. Personally i think a rss feed is the much better choice here. But maybe someone will do your plugin Christoph Lang

Nice plugin! But is it possible to make the syntax more *DokuWiki-like*? Such as using reder? — Reder 2009/07/04 08:30

Ok, just updated the code. Now you can also use:
//Timeline of user
{{twitter>user:reder}}
//Search for Keyword 'PHP'
{{twitter>search:PHP}}

Hope that helps.


I build some regex into the Plugin to make links, twitterer and hashtags clickable. rifter 2009/07/08 17:56

Thank you, seems to work very fine!

Christoph Lang 2009/07/08 23:46

Updated the code a little bit, mainly the time of the tweet is now displayed Twitter-like, e.g. 5 minutes ago, or About 1 week ago. Also there was a problem with the regex (only first hastag was clickable). Now all hastags are clickable. Christoph Lang 2009/07/09 23:01

Getting a “Twitter is down” error when it isn't. — Grimp
“Twitter is down” means either Twitter is down, or the response from Twitter is invalid. Maybe you used a wrong syntax?
Give me a sample of your syntax, and I will look. Maybe it's a Bug. — C.Lang
I have the same problem “Twitter is down” … example on http://pichat-wiki.de/links#twitter — Mark Wolfgruber
In you PHP.ini the option allow_url_fopen is Off. You have to turn it On, so that the Plugin can fetch the data from Twitter.
If Option is Off file_get_contents can only open local files, and not files on another server. — C.Lang
I can't change the parameter for allow_url_fopen to On
but now it is working with the following additional function code
to install put the private function file_get_contents e.g. top of the function handle
replace in the function handles: file_get_contents with $this→file_get_contents
Mark Wolfgruber 2009/11/23 02:42

I updated the mod, now you can use allow_url_fopen with ON or OFF (I need for local Installation ON and for the Server OFF) — Mark Wolfgruber 2010/04/23 00:16

    private function file_get_contents($url) {
    /** 
     *  Mod from Mark Wolfgruber (http://www.600infos.de) for http://www.pichat-wiki.de  
     *             
     *  this function is needed if you have in the PHP Core allow_url_fopen Off 
     *  replace in the function handle: file_get_contents with $this->file_get_contents
     *  
     * thx to Christoph Lang and http://www.php.net/manual/en/function.curl-exec.php
     **/
     @$json=file_get_contents($url);
      // handle error if fopen is Off
      if (is_bool($json) && $json == false)
      {
        $curl = @curl_init($url);
        @curl_setopt($curl, CURLOPT_HEADER, FALSE);
        @curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
        @$json = curl_exec($curl);
        curl_close($curl);
      } 
       return $json;
     }

Fantastic plugin, thanks - is there a way to do negative keywords on the search? (UPDATE 7/22 - WORKED! THANKS CHRISTOPH!) — Tyler (mail at tribalcore dot com)

Just updated the plugin. Now you can combine searchwords, e.g:
//Search for PHP but NOT Zend
{{twitter>search:php -zend}}
//Search for PHP AND Zend
{{twitter>search:php zend}}

In theory other search parameters from the Twitter-Api should also work, but I didn't test it.

This requires PHP 5.2 or later, or alternatively you'll have to add a json_decode function, e.g. from http://au.php.net/manual/en/function.json-decode.php#91216 — Robert

Your plugin does not work on my server. It shows only: About 40 years, 1 month ago from. (www.pyload.org/beta)
Johann Bauer

It seems your server is returning the wrong time to the plugin. 01.01.1970 is the start of the UNIX time, and that is what your server is returning (40years and 1 month ago).
Maybe you have to set the correct time on your server first. — C.Lang

No, the server's time (So 7. Feb 17:49:24 CET 2010) is right (for Germany) and there aren't tweets and pictures, so that I think it's another problem

Just checked your site pyload and saw that it wasn't working. Seems your having another problem. Do you have at least PHP 5.2?
Maybe you can provide me with more detailed information, because I can't think of any reason for your problem.
You can also contact me via Email, my mail address is on top of the page (I'm German, too).
Updated the plugin with cache “management” (from source plugin).

Björn Kalkbrenner 2010/06/18 20:15

Andreas — Just receiving the message: Timeline from experimenteandi Twitter is down….

What's wrong ?

This was already discussed a few lines above. Check your PHP Inifile for allow_url_fopen. Christoph Lang
plugin/twitter.txt · Last modified: 2011/10/06 11:12 by jdt
 
Except where otherwise noted, content on this wiki is licensed under the following license: CC Attribution-Share Alike 3.0 Unported
Imprint Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki
WikiForumIRCBugsGitXRefTranslate