<?php
/*
Plugin Name: Venus
Plugin URI: http://www.wasab.dk/morten/blog/archives/2006/10/22/wp-venus
Description: Planet Venus cache syndication - http://www.intertwingly.net/code/venus/
Author: Morten Frederiksen
Version: 0.6
Author URI: http://www.wasab.dk/morten/
*/

/*

=== Venus ===
Tags: links, subscriptions, planet, syndication
Requires: N/A

== What does this plugin do? ==

This plugin monitors a Planet Venus cache directory and syndicates new entries as posts.
It automagically creates users and categories as necessary.

== Installation and usage ==

1. Upload to your plugins folder, usually wp-content/plugins/
2. Activate the plugin on the plugin screen
3. Go to the Venus options screen and point it to your Planet Venus cache directory

== Changes ==

From 0.5 to 0.6:
----------------
* Added flag for optional checking of entry file size for detecting updates
* Added debug log
* Fixed GUID generation

From 0.4 to 0.5:
----------------
* On post delete now also removes cache file, if possible

From 0.3 to 0.4:
----------------
* To improve response time, a separate GET of the plugin is now needed
* Better category handling
* Improved user consolidation
* Permalinks also supported for guid
* Fixed bug regarding using atom:id as permalink

From 0.2 to 0.3:
----------------
* Added complete feed support
* Fixed invalid permalinks

From 0.1 to 0.2:
----------------
* Improved handling of missing categories and excerpts
* Better author identification and creation
* Fixed permalink generation
* Added user consolidation routine

== License ==

Copyright (c) 2006-2007 Morten Frederiksen <morten@wasab.dk>

Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

*/

function get_venus() {
  static
$venus;
  if (!isset(
$venus))
    
$venus = new Venus;
  return
$venus;
}

class
Venus {

  var
$debug;
  var
$do_update;
  var
$permalink;

  function
Venus() {
    
$this->debug=false;
    
$this->update=false;
    
$this->permalink=false;
  }

  function
action_admin_menu() {
    
add_submenu_page("options-general.php", $this->T('Venus'),
                     
$this->T('Venus'),
                     
8, basename(__FILE__), array(&$this, 'options_venus'));
  }

  function
action_delete_post($post_id) {
    
$options = get_settings('venus_options');
    list(
$filename) = get_post_custom_values('venus_cache_file');
    
$path = $options['cache_directory'] . DIRECTORY_SEPARATOR . $filename;
    @
unlink($path);
  }

  function
options_venus() {
    
$this->options_venus_checkaction();
    
$this->options_venus_display();
  }
  
  function
options_venus_checkaction() {
    global
$wpdb;
    switch (
$_REQUEST['action']) {
      case
'update_options':
        
/* update options */
        
$options = get_settings('venus_options');
        
$options['cache_directory']=$_REQUEST['cache_directory'];
        
$options['update_interval']=$_REQUEST['update_interval'];
        
$options['original_link']=@$_REQUEST['original_link']?1:0;
        
$options['check_entry_size']=@$_REQUEST['check_entry_size']?1:0;
        
$options['last_update']=0;
        
update_option('venus_options', $options);
        if (
$this->debug)
          
$this->log('updated options.');
        
$this->display_updated('Options updated.');
        break;
      case
'consolidate_users':
        
/* merge two users into one */
        
$user1=$_REQUEST['user1'];
        
$user2=$_REQUEST['user2'];
        if (!
$user1 || !$user2) {
          
$this->display_updated('Two users must be selected for consolidation.');
          break;
        }
        
# Move Venus ID(s) for user2 to user1.
        
$wpdb->query('UPDATE ' . $wpdb->usermeta . ' SET user_id="' . $wpdb->escape($user1) . '" WHERE meta_key="venus_id" AND user_id="' . $wpdb->escape($user2) . '"');
        
# Remove user2, moving posts to user1.
        
wp_delete_user($user2, $user1);
        
$this->display_updated('Users merged.');
        break;
    }
  }
  
  function
options_venus_display() {
    
/* Display options page */
    
global $wpdb;
    
$options = get_settings('venus_options');
    
?>
    <div class="wrap">
      <h2><?php $this->EHT('Venus Options') ?></h2>
      <form method="post">
        <input type="hidden" name="action" value="update_options" />
        <fieldset class="options">
        <legend><?php $this->EHT('General options') ?></legend>
        <table class="editform">
          <tr>
            <td><?php echo $this->EHT("Absolute path to Venus cache directory").": " ?></td>
            <td><input name="cache_directory" value="<?php echo $this->H($options['cache_directory']) ?>"
                       type="text" size="40" /></td>
          </tr><tr>
            <td><?php echo $this->EHT("Minimum update interval (minutes)").": " ?></td>
            <td><input name="update_interval" value="<?php echo $this->H($options['update_interval']) ?>"
                       title="<?php echo strftime('%a, %d %b %Y %H:%M:%S', $options['last_update']); ?>" type="text" size="5" /></td>
          </tr><tr>
            <td><?php echo $this->EHT("Check entry size?").": " ?></td>
            <td><input name="check_entry_size" value="1"
                       type="checkbox" <?php if (1==$options['check_entry_size']) echo 'checked="true" '; ?>/></td>
          </tr><tr>
            <td><?php echo $this->EHT("Use original link to post?").": " ?></td>
            <td><input name="original_link" value="1"
                       type="checkbox" <?php if (1==$options['original_link']) echo 'checked="true" '; ?>/></td>
          </tr>
        </table>
        <div class="submit"><input type="submit" value="<?php
                                   
echo $this->EHT('Update options') ?> &raquo;" /></div>
        </fieldset>
      </form>
      <?php
        $users
=$wpdb->get_results('SELECT u.ID, display_name, user_url, count(*) as post_count FROM '.$wpdb->users.' AS u LEFT JOIN '.$wpdb->posts.' AS p ON u.ID=p.post_author WHERE u.ID>1 GROUP BY u.ID ORDER BY display_name');
        if (
sizeof($users)) {
      
?>
      <form method="post">
        <input type="hidden" name="action" value="consolidate_users" />
        <fieldset class="options">
        <legend><?php $this->EHT('Consolidate users (merge User 2 into User 1)') ?></legend>
        <table class="editform">
          <tr>
            <th style="text-align: left"><?php echo $this->EHT("User 1").": " ?></th>
          </tr><tr>
            <td>
              <select name="user1">
                <option value="0"><?php echo $this->EHT("Select...") ?></option>
                <?php
                  
foreach ($users as $user)
                      print
'<option value="'.$user->ID.'">'.$this->H($user->display_name).' (ID: '.$this->H($user->ID).', posts: '.$this->H($user->post_count).', '.$this->H($user->user_url).')</option>';
                
?>

              </select>
            </td>
          </tr><tr>
            <th style="text-align: left"><?php echo $this->EHT("User 2").": " ?></th>
          </tr><tr>
            <td>
              <select name="user2">
                <option value="0"><?php echo $this->EHT("Select...") ?></option>
                <?php
                  
foreach ($users as $user)
                      print
'<option value="'.$user->ID.'">'.$this->H($user->display_name).' (ID: '.$this->H($user->ID).', posts: '.$this->H($user->post_count).', '.$this->H($user->user_url).')</option>';
                
?>

              </select>
            </td>
          </tr>
        </table>
        <div class="submit"><input type="submit" value="<?php
                                   
echo $this->EHT('Consolidate') ?> &raquo;" /></div>
        </fieldset>
      </form>
      <?php
        
}
      
?>
    </div>
    <?
  
}

  function
display_updated($text) {
    echo
'<div class="updated"><p>';
    
$this->EHT($text);
    echo
'</p></div>';
  }

  function
T($text) {
    return
__($text, 'venus');
  }

  function
H($text) {
    return
htmlspecialchars($text, ENT_QUOTES);
  }

  function
HT($text) {
    return
$this->H($this->T($text));
  }

  function
EHT($text) {
    echo
$this->HT($text);
  }

  function
update() {
    global
$wpdb;
    
    
$options = get_settings('venus_options');
    
# Not yet time to check for updates?
    
if (($options['last_update'] + $options['update_interval'] * 60) > mktime())
      return;

    
$options['last_update'] = mktime();
    
update_option('venus_options', $options);
    
# Loop through files in cache directory.
    
$handle = @opendir($options['cache_directory']);
    if (!
$handle)
      return;
    while ((
$filename = @readdir($handle)) !== false) {
      
$path = $options['cache_directory'] . DIRECTORY_SEPARATOR . $filename;
      
# Only handle real files.
      
if (@is_dir($path))
        continue;

      
# Check for existing entry/post.
      
$filemtime = @filemtime($path);
      
$filesize = @filesize($path);
      
$post = $wpdb->get_row('select ID, pm2.meta_value as mtime, pm3.meta_value as size from ' . $wpdb->posts .
                             
' join  ' . $wpdb->postmeta . ' as pm1 ' .
                             
' join  ' . $wpdb->postmeta . ' as pm2 ' .
                             
' join  ' . $wpdb->postmeta . ' as pm3 ' .
                             
' where ID = pm1.post_id and ID = pm2.post_id and ID = pm3.post_id ' .
                             
' and pm1.meta_key = "venus_cache_file" and pm1.meta_value = "' . $filename . '" ' .
                             
' and pm2.meta_key = "venus_cache_mtime"' .
                             
' and pm3.meta_key = "venus_cache_size" limit 1');
      
# Unchanged entry/post?
      
if ($post && $filemtime == $post->mtime && ($filesize == $post->size || !$options['check_entry_size']))
        continue;
      if (
$this->debug) {
          if (
$post)
          
$this->log('updated entry #'.$post->ID.' ('.$filemtime.'/'.$post->mtime.'/'.$filesize.'/'.$post->size.'): '.$filename);
        else
          
$this->log('new entry ('.$filemtime.'/'.$filesize.'): '.$filename);
      }

      
# Parse entry.
      
if (!function_exists('xml_parser_create')
          || !(
$parser = @xml_parser_create('UTF-8'))
          || !
is_resource($parser))
        
trigger_error('Unable to create XML/Atom parser');
      
xml_set_element_handler($parser,
                              array(&
$this, 'entry_start_element'),
                              array(&
$this, 'entry_end_element'));
      
xml_set_character_data_handler($parser, array(&$this, 'entry_cdata'));
      
$entry = file_get_contents($path);
      
$this->parse_tree = array();
      
$this->parse_level = 0;
      
$this->parse_inxhtml = false;
      if (
xml_parse($parser, $entry, $true) &&
              (
$errorcode = xml_get_error_code($parser)) != XML_ERROR_NONE)
        
trigger_error('Unable to parse Atom entry (' .
                      
sprintf(__('XML error: %1$s at line %2$s'),
                      
xml_error_string($errorcode),
                      
xml_get_current_line_number($parser)) . ')');
      
xml_parser_free($parser);
      if (
'FEED'==$this->parse_tree[0]['name'] && isset($this->parse_tree[0]['nodes']['entry'][0])) {
          foreach (
$this->parse_tree[0]['nodes']['entry'] as $entry) {
            if (!isset(
$entry['source'])) {
              
$entry['source'] = $this->parse_tree[0]['nodes'];
              unset(
$entry['source']['entry']);
            }
          
$this->insert_entry($post, $entry, $filename, $filemtime, $filesize);
          }
      } elseif (
'ENTRY'==$this->parse_tree[0]['name']) {
        
$entry = $this->parse_tree[0]['nodes'];
        
$this->insert_entry($post, $entry, $filename, $filemtime, $filesize);
      }
    }
  }

  function
insert_entry($post, $entry, $filename, $filemtime, $filesize) {
    global
$wpdb;

    if (!isset(
$entry['author']) && isset($entry['source']['author']))
      
$entry['author'] = &$entry['source']['author'];
    if (!isset(
$entry['category']) && isset($entry['source']['category']))
      
$entry['category'] = &$entry['source']['category'];
    if (!isset(
$entry['author']['uri']) && isset($entry['source']['id']))
      
$entry['author']['uri'] = &$entry['source']['id'];
    elseif (!isset(
$entry['author']['uri']) && isset($entry['source']['link_alternate']))
      
$entry['author']['uri'] = &$entry['source']['link_alternate'];
    elseif (!isset(
$entry['author']['uri']) && isset($entry['source']['link_self']))
      
$entry['author']['uri'] = &$entry['source']['link_self'];
    
$entry['summary']=preg_replace('|\[i\](.+?)\[/i\]|','<em>$1</em>',$entry['summary']);
    
$entry['summary']=preg_replace('|\[b\](.+?)\[/b\]|','<strong>$1</strong>',$entry['summary']);
    
$entry['summary']=preg_replace('|\s+---\s+|',' &mdash; ',$entry['summary']);
    if (!isset(
$entry['content']))
      
$entry['content'] = $entry['summary'];
    
$entry['summary']=strip_tags($entry['summary']);

    
# Find author.
    
$where = array();
    if (isset(
$entry['author']['uri']) && !empty($entry['author']['uri']))
      
$where[] = 'user_url = "' . $wpdb->escape($entry['author']['uri']) . '"';
    if (isset(
$entry['author']['email']) && !empty($entry['author']['email']))
      
$where[] = 'user_email = "' . $wpdb->escape($entry['author']['email']) . '"';
    if (isset(
$entry['author']['name']) && !empty($entry['author']['name']))
      
$where[] = 'display_name = "' . $wpdb->escape($entry['author']['name']) . '"';
    if (!
sizeof($where))
      
$post->post_author = 0;
    else {
      
$query = 'SELECT ID FROM ' . $wpdb->users . ' WHERE ' . join(' AND ', $where) . ' ORDER BY ID LIMIT 1';
      
$post->post_author = $wpdb->get_var($query);
      
$venus_id = $entry['author']['uri'].':'.$entry['author']['email'].':'.$entry['author']['name'];
      if (!
$post->post_author) {
        
$query = 'SELECT user_id FROM ' . $wpdb->usermeta . ' WHERE meta_key="venus_id" AND meta_value="' . $wpdb->escape($venus_id) . '" ORDER BY user_id LIMIT 1';
        
$post->post_author = $wpdb->get_var($query);
      }
      if (!
$post->post_author) {
        
# Create author.
        
include_once(ABSPATH . WPINC . '/registration-functions.php');
        
$author = array();
        if (isset(
$entry['author']['name']) && !empty($entry['author']['name']))
          
$author['user_login'] = $entry['author']['name'];
        elseif (isset(
$entry['author']['email']) && !empty($entry['author']['email']))
          
$author['user_login'] = preg_replace('|@.+$|','',$entry['author']['email']);
        elseif (isset(
$entry['author']['uri']) && !empty($entry['author']['uri']))
          
$author['user_login'] = 'u'.md5($entry['author']['uri']);
        if (isset(
$entry['author']['email']) && !empty($entry['author']['email']))
          
$author['user_email'] = $entry['author']['email'];
        if (isset(
$entry['author']['uri']) && !empty($entry['author']['uri']))
          
$author['user_url'] = $entry['author']['uri'];
        
$author['user_nicename'] = $author['user_login'];
        
$author['display_name'] = $author['user_login'];
        
$author['nickname'] = $author['user_login'];
        
$author['user_login'] = sanitize_title(sanitize_user($this->remove_accents($author['user_login']), true));
        
$author['user_nicename'] = $author['user_login'];
        
$author['user_pass'] = 'p'.md5(mktime());
        
$post->post_author = wp_insert_user($author);
        
update_usermeta($post->post_author, 'venus_id', $wpdb->escape($venus_id));
        if (
$this->debug)
          
$this->log('created author #'.$post->post_author.': '.$author['user_nicename']);
      }
    }

    
# Find categories.
    
$post->post_category = array();
    if (isset(
$entry['category']) && is_array($entry['category'])) {
      
$categories = array();
      foreach (
$entry['category'] as $c) {
        if (
is_array($c) && isset($c['term']))
          
$c = $c['term'];
        elseif (
is_array($c) && isset($c[0]) && isset($c[0]['term'])) {
          
$cc = array();
          foreach (
$c as $ct)
            
$cc[] = $ct['term'];
          
$c = join(',', $cc);
        }
        
$c = preg_split('/\s*,+\s*/', $c, -1, PREG_SPLIT_NO_EMPTY);
        
$categories = array_merge($categories, $c);
      }
      foreach (
$categories as $category) {
          if (
strlen($category)<2)
            continue;
        
$cat_nicename = sanitize_title($category);
        
$cat_nicename = apply_filters('pre_category_nicename', $cat_nicename);
        
$cat = $wpdb->get_var('SELECT cat_ID FROM ' . $wpdb->categories . ' WHERE category_nicename = "' . $wpdb->escape($cat_nicename) . '" OR cat_name = "' . $wpdb->escape($category) . ' "LIMIT 1');
        if (!
$cat) {
          
# Create category.
          
include_once(ABSPATH . 'wp-admin/admin-db.php');
          
$cat = wp_insert_category(array(
            
'cat_name' => $wpdb->escape($category),
            
'category_nicename' => $wpdb->escape($category)));
          if (
$this->debug)
            
$this->log('created category #'.$cat.': '.$category);
        }
        
$post->post_category[] = $cat;
      }
    }
     
    
# Create or update post
    
include_once(ABSPATH . WPINC . '/rss-functions.php');
    
$post->post_content = $wpdb->escape($entry['content']);
    
$post->post_excerpt = $wpdb->escape($entry['summary']);
    
$post->post_title = $wpdb->escape($entry['title']);
    
$post->post_status = 'publish';
    
$post->post_date = date('Y-m-d H:i:s',parse_w3cdtf($entry['updated']));
    
$post->comment_status = 'closed';
    
$post->ping_status = 'closed';      
    
$post->post_pingback = 0;
    if (!isset(
$entry['link_alternate']))
      
$this->permalink=$entry['id'];
    else
      
$this->permalink=$entry['link_alternate'];
    
define('WP_IMPORTING', 1);
    
$post_id = wp_insert_post($post);
    if (
$post_id && !$post->ID) {
      
add_post_meta($post_id, 'venus_cache_file', $filename);
      
add_post_meta($post_id, 'venus_cache_mtime', $filemtime);
      
add_post_meta($post_id, 'venus_cache_size', $filesize);
    } elseif (
$post_id) {
      
update_post_meta($post_id, 'venus_cache_mtime', $filemtime);
      
update_post_meta($post_id, 'venus_cache_size', $filesize);
    }
  }

  function
entry_start_element($parser, $elem, &$attrs) {
    
$attrs = array_change_key_case($attrs, CASE_LOWER);
    
$this->parse_level++;
    
$node = &$this->parse_tree;
    
$level = $this->parse_level - 1;
    while (
$level) {
      
$node = &$node[sizeof($node)-1]['nodes'];
      
$level--;
    }
    if (
$this->parse_inxhtml) {
      
$e = '<' . strtolower($elem);
      foreach (
$attrs as $a => $v)
        
$e .= ' ' . $a . '="' . htmlspecialchars($v) . '"';
      
$e .= '>';
      
$this->parse_xhtml .= $e;
    } elseif (isset(
$attrs['xmlns']) && $attrs['xmlns'] == 'http://www.w3.org/1999/xhtml') {
      
$this->parse_inxhtml = $this->parse_level-1;
      
$e = '<' . strtolower($elem);
      foreach (
$attrs as $a => $v)
        
$e .= ' ' . $a . '="' . htmlspecialchars($v) . '"';
      
$e .= '>';
      
$this->parse_xhtml = $e;
    }
    if (
'LINK'==$elem && isset($attrs['rel'])) {
      
$elem .= '_' . $attrs['rel'];
      
$node[] = array('name' => $elem, 'text' => $attrs['href']);
    } else
      
$node[] = array('name' => $elem, 'attrs' => $attrs);
  }
  
  function
entry_end_element($parser, $elem) {
    
$this->parse_level--;
    
$node = &$this->parse_tree;
    
$level = $this->parse_level;
    while (
$level) {
      
$node = &$node[sizeof($node)-1]['nodes'];
      
$level--;
    }
    if (
$this->parse_inxhtml) {
      
$this->parse_xhtml .= '</' . strtolower($elem) . '>';
      if (
$this->parse_inxhtml == $this->parse_level) {
        
$this->parse_inxhtml = false;
        
$node = $this->parse_xhtml;
      }
    }
    if (isset(
$node[sizeof($node)-1]['attrs']) && !sizeof($node[sizeof($node)-1]['attrs']))
      unset(
$node[sizeof($node)-1]['attrs']);
    if (isset(
$node[sizeof($node)-1]['nodes']) && !sizeof($node[sizeof($node)-1]['nodes']))
      
array_pop($node);
    elseif (isset(
$node[sizeof($node)-1]['nodes']) && is_array($node[sizeof($node)-1]['nodes'])) {
      
$nodes = array();
      foreach (
$node[sizeof($node)-1]['nodes'] as $n) {
        if (isset(
$n['nodes']))
          
$v = $n['nodes'];
        elseif (isset(
$n['text']))
          
$v = $n['text'];
        else
          
$v = $n['attrs'];
        if (isset(
$nodes[$n['name']])) {
          if (isset(
$nodes[$n['name']][0])) {
            if (
is_array($nodes[$n['name']][0]))
              
$nodes[$n['name']][] = $v;
            elseif (!
is_array($v))
              
$nodes[$n['name']] .= $v;
          } else
            
$nodes[$n['name']] = array($v);
        } else
          
$nodes[$n['name']] = $v;
      }
      if (
sizeof($nodes))
        
$node[sizeof($node)-1]['nodes'] = array_change_key_case($nodes, CASE_LOWER);
    }
  }

  function
entry_cdata($parser, $text) {
    
$node = &$this->parse_tree;
    
$level = $this->parse_level - 1;
    while (
$level) {
      
$node = &$node[sizeof($node)-1]['nodes'];
      
$level--;
    }
    if (
$this->parse_inxhtml)
      
$this->parse_xhtml .= $text;
    else
      
$node[sizeof($node)-1]['text'] .= $text;
  }
  
  function
remove_accents($s) {
      if (
seems_utf8($s)) {
          
$chars = array(
              
chr(195).chr(134) => 'AE',    # Aelig
              
chr(195).chr(166) => 'ae',    # aelig
              
chr(195).chr(184) => 'oe',    # oslash
              
chr(195).chr(152) => 'OE',    # Oslash
              
chr(195).chr(133) => 'AA',    # Aring
              
chr(195).chr(165) => 'aa'    # aring
          
);
          
$s = strtr($s, $chars);
      }
      return
remove_accents($s);    
  }

  function
action_publish_post($post_id) {
    
add_post_meta($post_id, 'venus_original_link', htmlspecialchars($this->permalink));
  }
  
  function
filter_post_link($permalink = '') {
    
$options = get_settings('venus_options');
    if (
$options['original_link']) {
      list(
$uri) = get_post_custom_values('venus_original_link');
      return ((
strlen($uri) > 0) ? $uri : $permalink);
    } else
      return
$permalink;
  }

  function
filter_get_the_guid($permalink = '') {
    return
$this->filter_post_link($permalink);
  }

  function
log($line) {
    
$fh = @fopen(ABSPATH . "wp-content/venus.log", "a");
    @
fwrite($fh, strftime("%D %T")."\t$line\n");
    @
fclose($fh);
  }

}

# Create global Venus object.
$venus = get_venus();

# Include configuration if called directly.
if (!function_exists('add_action')) {
  include_once(
'../../wp-config.php');
  
$venus->do_update=true;
}

load_plugin_textdomain('venus');
add_option('venus_options', array(
    
'last_update' => 0,
    
'original_link' => 0,
    
'check_entry_size' => 0,
    
'update_interval' => 60,
    
'cache_directory' => ''));

add_action('publish_post', array(&$venus, 'action_publish_post'), 1);

if (
$venus->do_update)
  
$venus->update();

add_action('admin_menu', array(&$venus, 'action_admin_menu'));
add_action('delete_post', array(&$venus, 'action_delete_post'));
add_filter('post_link', array(&$venus, 'filter_post_link'), 1);
add_filter('get_the_guid', array(&$venus, 'filter_get_the_guid'), 1);
#add_action('wp_head', array(&$venus, 'update'));

?>