b2evolution

Multilingual multiuser multiblog engine

b2evolution Technical Documentation (Version 2.4) [ class tree: evocore ] [ index: evocore ] [ all elements ]

Source for file _item.class.php

Documentation is available at _item.class.php

  1. <?php
  2. /**
  3.  * This file implements the Item class.
  4.  *
  5.  * This file is part of the evoCore framework - {@link http://evocore.net/}
  6.  * See also {@link http://sourceforge.net/projects/evocms/}.
  7.  *
  8.  * @copyright (c)2003-2008 by Francois PLANQUE - {@link http://fplanque.net/}
  9.  *  Parts of this file are copyright (c)2004-2006 by Daniel HAHLER - {@link http://thequod.de/contact}.
  10.  *
  11.  *  {@internal License choice
  12.  *  - If you have received this file as part of a package, please find the license.txt file in
  13.  *    the same folder or the closest folder above for complete license terms.
  14.  *  - If you have received this file individually (e-g: from http://evocms.cvs.sourceforge.net/)
  15.  *    then you must choose one of the following licenses before using the file:
  16.  *    - GNU General Public License 2 (GPL) - http://www.opensource.org/licenses/gpl-license.php
  17.  *    - Mozilla Public License 1.1 (MPL) - http://www.opensource.org/licenses/mozilla1.1.php
  18.  *  }}}
  19.  *
  20.  *  {@internal Open Source relicensing agreement:
  21.  *  Daniel HAHLER grants Francois PLANQUE the right to license
  22.  *  Daniel HAHLER's contributions to this file and the b2evolution project
  23.  *  under any OSI approved OSS license (http://www.opensource.org/licenses/).
  24.  *  }}}
  25.  *
  26.  * @package evocore
  27.  *
  28.  *  {@internal Below is a list of authors who have contributed to design/coding of this file: }}
  29.  * @author blueyed: Daniel HAHLER.
  30.  * @author fplanque: Francois PLANQUE.
  31.  * @author gorgeb: Bertrand GORGE / EPISTEMA
  32.  * @author mbruneau: Marc BRUNEAU / PROGIDISTRI
  33.  *
  34.  * @version $Id: _item.class.php,v 1.32.2.8 2009/06/13 18:50:47 tblue246 Exp $
  35.  */
  36. if!defined('EVO_MAIN_INIT') ) die'Please, do not access this page directly.' );
  37.  
  38. /**
  39.  * Includes:
  40.  */
  41. load_class('items/model/_itemlight.class.php');
  42. load_funcs('items/model/_item.funcs.php');
  43.  
  44.  
  45. /**
  46.  * Item Class
  47.  *
  48.  * @package evocore
  49.  */
  50. class Item extends ItemLight
  51. {
  52.     /**
  53.      * The User who has created the Item (lazy-filled).
  54.      * @see Item::get_creator_User()
  55.      * @see Item::set_creator_User()
  56.      * @var User 
  57.      * @access protected
  58.      */
  59.     var $creator_User;
  60.  
  61.  
  62.     /**
  63.      * @deprecated by {@link $creator_User}
  64.      * @var User 
  65.      */
  66.     var $Author;
  67.  
  68.  
  69.     /**
  70.      * ID of the user that created the item
  71.      * @var integer 
  72.      */
  73.     var $creator_user_ID;
  74.  
  75.  
  76.     /**
  77.      * The assigned User to the item.
  78.      * Can be NULL
  79.      * @see Item::get_assigned_User()
  80.      * @see Item::assign_to()
  81.      *
  82.      * @var User 
  83.      * @access protected
  84.      */
  85.     var $assigned_User;
  86.  
  87.     /**
  88.      * ID of the user that created the item
  89.      * Can be NULL
  90.      *
  91.      * @var integer 
  92.      */
  93.     var $assigned_user_ID;
  94.  
  95.     /**
  96.      * The visibility status of the item.
  97.      *
  98.      * 'published', 'deprecated', 'protected', 'private' or 'draft'
  99.      *
  100.      * @var string 
  101.      */
  102.     var $status;
  103.     /**
  104.      * Locale code for the Item content.
  105.      *
  106.      * Examples: en-US, zh-CN-utf-8
  107.      *
  108.      * @var string 
  109.      */
  110.     var $locale;
  111.  
  112.     var $content;
  113.  
  114.     /**
  115.      * Lazy filled, use split_page()
  116.      */
  117.     var $content_pages = NULL;
  118.  
  119.  
  120.     var $wordcount;
  121.     /**
  122.      * The list of renderers, imploded by '.'.
  123.      * @var string 
  124.      * @access protected
  125.      */
  126.     var $renderers;
  127.     /**
  128.      * Comments status
  129.      *
  130.      * "open", "disabled" or "closed
  131.      *
  132.      * @var string 
  133.      */
  134.     var $comment_status;
  135.  
  136.     var $pst_ID;
  137.     var $datedeadline = '';
  138.     var $priority;
  139.  
  140.     /**
  141.      * Have post processing notifications been handled?
  142.      * @var string 
  143.      */
  144.     var $notifications_status;
  145.     /**
  146.      * Which cron task is responsible for handling notifications?
  147.      * @var integer 
  148.      */
  149.  
  150.     /**
  151.      * array of IDs or NULL if we don't know...
  152.      *
  153.      * @var array 
  154.      */
  155.     var $extra_cat_IDs = NULL;
  156.  
  157.   /**
  158.      * Array of tags (strings)
  159.      *
  160.      * Lazy loaded.
  161.      *
  162.      * @var array 
  163.      */
  164.     var $tags = NULL;
  165.  
  166.     /**
  167.      * Array of Links attached to this item.
  168.      *
  169.      * NULL when not initialized.
  170.      *
  171.      * @var array 
  172.      * @access public
  173.      */
  174.     var $Links = NULL;
  175.  
  176.  
  177.     var $priorities;
  178.  
  179.     /**
  180.      * Pre-rendered content, cached by format/validated renderers.
  181.      *
  182.      * Can be NULL
  183.      *
  184.      * @see Item::get_prerendered_content()
  185.      * @access protected
  186.      * @var array 
  187.      */
  188.     var $content_prerendered;
  189.  
  190.  
  191.     /**
  192.      * Constructor
  193.      *
  194.      * @param object table Database row
  195.      * @param string 
  196.      * @param string 
  197.      * @param string 
  198.      * @param string for derived classes
  199.      * @param string datetime field name
  200.      * @param string datetime field name
  201.      * @param string User ID field name
  202.      * @param string User ID field name
  203.      */
  204.     function Item$db_row NULL$dbtable 'T_items__item'$dbprefix 'post_'$dbIDname 'post_ID'$objtype 'Item',
  205.                    $datecreated_field 'datecreated'$datemodified_field 'datemodified',
  206.                    $creator_field 'creator_user_ID'$lasteditor_field 'lastedit_user_ID' )
  207.     {
  208.         global $localtimenow$default_locale$current_User;
  209.  
  210.         $this->priorities = array(
  211.                 => /* TRANS: Priority name */ T_('1 - Highest'),
  212.                 => /* TRANS: Priority name */ T_('2 - High'),
  213.                 => /* TRANS: Priority name */ T_('3 - Medium'),
  214.                 => /* TRANS: Priority name */ T_('4 - Low'),
  215.                 => /* TRANS: Priority name */ T_('5 - Lowest'),
  216.             );
  217.  
  218.         // Call parent constructor:
  219.         parent::ItemLight$db_row$dbtable$dbprefix$dbIDname$objtype,
  220.                    $datecreated_field$datemodified_field,
  221.                    $creator_field$lasteditor_field );
  222.  
  223.         ifis_null($db_row) )
  224.         // New item:
  225.             ifisset($current_User) )
  226.             // use current user as default, if available (which won't be the case during install)
  227.                 $this->set_creator_User$current_User );
  228.             }
  229.             $this->set'notifications_status''noreq' );
  230.             // Set the renderer list to 'default' will trigger all 'opt-out' renderers:
  231.             $this->set'renderers'array('default') );
  232.             $this->set'status''published' );
  233.             $this->set'locale'$default_locale );
  234.             $this->set'priority');
  235.             $this->set'ptyp_ID'/* Post */ );
  236.         }
  237.         else
  238.         {
  239.             $this->datecreated $db_row->post_datecreated// Needed for history display
  240.             $this->creator_user_ID = $db_row->post_creator_user_ID// Needed for history display
  241.             $this->lastedit_user_ID $db_row->post_lastedit_user_ID// Needed for history display
  242.             $this->assigned_user_ID = $db_row->post_assigned_user_ID;
  243.             $this->status = $db_row->post_status;
  244.             $this->content = $db_row->post_content;
  245.             $this->pst_ID = $db_row->post_pst_ID;
  246.             $this->datedeadline = $db_row->post_datedeadline;
  247.             $this->priority = $db_row->post_priority;
  248.             $this->locale = $db_row->post_locale;
  249.             $this->wordcount = $db_row->post_wordcount;
  250.             $this->notifications_status = $db_row->post_notifications_status;
  251.             $this->notifications_ctsk_ID = $db_row->post_notifications_ctsk_ID;
  252.             $this->comment_status = $db_row->post_comment_status;            // Comments status
  253.  
  254.             // echo 'renderers=', $db_row->post_renderers;
  255.             $this->renderers = $db_row->post_renderers;
  256.  
  257.             $this->views $db_row->post_views;
  258.         }
  259.     }
  260.  
  261.  
  262.     /**
  263.      * @todo use extended dbchange instead of set_param...
  264.      * @todo Normalize to set_assigned_User!?
  265.      */
  266.     function assign_to$user_ID$dbupdate true /* BLOAT!? */ )
  267.     {
  268.         // echo 'assigning user #'.$user_ID;
  269.         ifempty($user_ID) )
  270.         {
  271.             if$dbupdate )
  272.             // Record ID for DB:
  273.                 $this->set_param'assigned_user_ID''number'$user_IDtrue );
  274.             }
  275.             else
  276.             {
  277.                 $this->assigned_user_ID = $user_ID;
  278.             }
  279.             $UserCache get_Cache'UserCache' );
  280.             $this->assigned_User = $UserCache->get_by_ID$user_ID );
  281.         }
  282.         else
  283.         {
  284.             // fp>> DO NOT set (to null) immediately OR it may KILL the current User object (big problem if it's the Current User)
  285.             unset$this->assigned_User );
  286.             if$dbupdate )
  287.             // Record ID for DB:
  288.                 $this->set_param'assigned_user_ID''number'NULLtrue );
  289.             }
  290.             else
  291.             {
  292.                 $this->assigned_User = NULL;
  293.             }
  294.             $this->assigned_user_ID = NULL;
  295.         }
  296.  
  297.     }
  298.  
  299.  
  300.     /**
  301.      * Template function: display author/creator of item
  302.      *
  303.      * @param string String to display before author name
  304.      * @param string String to display after author name
  305.      * @param string Output format, see {@link format_to_output()}
  306.      */
  307.     function author$params array() )
  308.     {
  309.         // Make sure we are not missing any param:
  310.         $params array_mergearray(
  311.                 'before'      => ' ',
  312.                 'after'       => ' ',
  313.                 'format'      => 'htmlbody',
  314.             )$params );
  315.  
  316.         // Load User
  317.         $this->get_creator_User();
  318.  
  319.         echo $params['before'];
  320.         echo $this->creator_User->preferred_name$params['format']false );
  321.         echo $params['after'];
  322.     }
  323.  
  324.  
  325.     /**
  326.      * Load data from Request form fields.
  327.      *
  328.      * This requires the blog (e.g. {@link $blog_ID} or {@link $main_cat_ID} to be set).
  329.      *
  330.      * @param boolean true to force edit date (as long as perms permit)
  331.      * @return boolean true if loaded data seems valid.
  332.      */
  333.     function load_from_Request$force_edit_date false )
  334.     {
  335.         global $default_locale$current_User;
  336.  
  337.         ifparam'post_locale''string'NULL !== NULL )
  338.         {
  339.             $this->set_from_Request'locale' );
  340.         }
  341.  
  342.         ifparam'item_typ_ID''integer'NULL !== NULL )
  343.         {
  344.             $this->set_from_Request'ptyp_ID''item_typ_ID' );
  345.         }
  346.  
  347.         ifparam'post_url''string'NULL !== NULL )
  348.         {
  349.             param_check_url'post_url''posting''' );
  350.             $this->set_from_Request'url' );
  351.         }
  352.         // Note: post_url is not part of the simple form, so this message can be a little bit awkward there
  353.         if$this->status == 'redirected' && empty($this->url) )
  354.         {
  355.             param_error'post_url'T_('If you want to redirect this post, you must specify an URL! (Expert mode)') );
  356.         }
  357.  
  358.         if( ( $force_edit_date || param'edit_date''integer') )
  359.                 && $current_User->check_perm'edit_timestamp' ) )
  360.         // We can use user date:
  361.             param_date'item_issue_date'T_('Please enter a valid issue date.')$force_edit_date /* required */ );
  362.             ifstrlen(get_param('item_issue_date')) )
  363.             // only set it, if a date was given:
  364.                 param_time'item_issue_time' );
  365.                 $this->set'issue_date'form_dateget_param'item_issue_date' )get_param'item_issue_time' ) ) )// TODO: cleanup...
  366.             }
  367.         }
  368.  
  369.         ifparam'post_excerpt''string'NULL !== NULL {
  370.             $this->set_from_Request'excerpt' );
  371.         }
  372.  
  373.         ifparam'post_urltitle''string'NULL !== NULL {
  374.             $this->set_from_Request'urltitle' );
  375.         }
  376.  
  377.         ifparam'item_tags''string'NULL !== NULL {
  378.             $this->set_tags_from_stringget_param('item_tags') );
  379.             // pre_dump( $this->tags );
  380.         }
  381.  
  382.         // Workflow stuff:
  383.         ifparam'item_st_ID''integer'NULL !== NULL {
  384.             $this->set_from_Request'pst_ID''item_st_ID' );
  385.         }
  386.  
  387.         ifparam'item_assigned_user_ID''integer'NULL !== NULL {
  388.             $this->assign_toget_param('item_assigned_user_ID') );
  389.         }
  390.  
  391.         ifparam'item_priority''integer'NULL !== NULL {
  392.             $this->set_from_Request'priority''item_priority'true );
  393.         }
  394.  
  395.         ifparam_date'item_deadline'T_('Please enter a valid deadline.')falseNULL !== NULL {
  396.             $this->set_from_Request'datedeadline''item_deadline'true );
  397.         }
  398.  
  399.         // Allow comments for this item (only if set to "post_by_post" for the Blog):
  400.         $this->load_Blog();
  401.         if$this->Blog->allowcomments == 'post_by_post' )
  402.         {
  403.             ifparam'post_comment_status''string''open' !== NULL )
  404.             // 'open' or 'closed' or ...
  405.                 $this->set_from_Request'comment_status' );
  406.             }
  407.         }
  408.  
  409.         ifparam'renderers_displayed''integer') )
  410.         // use "renderers" value only if it has been displayed (may be empty)
  411.             $Plugins_admin get_Cache('Plugins_admin');
  412.             $renderers $Plugins_admin->validate_renderer_listparam'renderers''array'array() ) );
  413.             $this->set'renderers'$renderers );
  414.         }
  415.         else
  416.         {
  417.             $renderers $this->get_renderers_validated();
  418.         }
  419.  
  420.         ifparam'content''html'NULL !== NULL )
  421.         {
  422.             param'post_title''html'NULL );
  423.  
  424.             // Do some optional filtering on the content
  425.             // Typically stuff that will help the content to validate
  426.             // Useful for code display.
  427.             // Will probably be used for validation also.
  428.             $Plugins_admin get_Cache('Plugins_admin');
  429.             $Plugins_admin->filter_contents$GLOBALS['post_title'/* by ref */$GLOBALS['content'/* by ref */$renderers );
  430.  
  431.             // Format raw HTML input to cleaned up and validated HTML:
  432.             param_check_html'post_title'T_('Invalid title.')'' );
  433.             $this->set'title'get_param'post_title' ) );
  434.  
  435.             param_check_html'content'T_('Invalid content.') );
  436.             $this->set'content'get_param'content' ) );
  437.         }
  438.  
  439.         return param_errors_detected();
  440.     }
  441.  
  442.  
  443.     /**
  444.      * Template function: display anchor for permalinks to refer to.
  445.      */
  446.     function anchor()
  447.     {
  448.         global $Settings;
  449.  
  450.         echo '<a id="'.$this->get_anchor_id().'"></a>';
  451.     }
  452.  
  453.  
  454.   /**
  455.      * @return string 
  456.      */
  457.     function get_anchor_id()
  458.     {
  459.         // In case you have old cafelog permalinks, uncomment the following line:
  460.         // return preg_replace( '/[^a-zA-Z0-9_\.-]/', '_', $this->title );
  461.  
  462.         return 'item_'.$this->ID;
  463.     }
  464.  
  465.  
  466.   /**
  467.      * Template tag
  468.      */
  469.     function anchor_id()
  470.     {
  471.         echo $this->get_anchor_id();
  472.     }
  473.  
  474.  
  475.     /**
  476.      * Template function: display assignee of item
  477.      *
  478.      * @param string 
  479.      * @param string 
  480.      * @param string Output format, see {@link format_to_output()}
  481.      */
  482.     function assigned_to$before ''$after ''$format 'htmlbody' )
  483.     {
  484.         if$this->get_assigned_User() )
  485.         {
  486.             echo $before;
  487.             $this->assigned_User->preferred_name$format );
  488.             echo $after;
  489.         }
  490.     }
  491.  
  492.  
  493.     /**
  494.      * Get list of assigned user options
  495.      *
  496.      * @uses UserCache::get_blog_member_option_list()
  497.      * @return string HTML select options list
  498.      */
  499.     function get_assigned_user_options()
  500.     {
  501.         $UserCache get_Cache'UserCache' );
  502.         return $UserCache->get_blog_member_option_list$this->blog_ID$this->assigned_user_ID,
  503.                             true,    ($this->ID != 0/* if this Item is already serialized we'll load the default anyway */ );
  504.     }
  505.  
  506.  
  507.     /**
  508.      * Check if user can see comments on this post, which he cannot if they
  509.      * are disabled for the Item or never allowed for the blog.
  510.      *
  511.      * @return boolean 
  512.      */
  513.     function can_see_comments()
  514.     {
  515.         if$this->comment_status == 'disabled'
  516.             || $this->get_Blog(&& $this->Blog->allowcomments == 'never' ) )
  517.         // Comments are disabled on this post
  518.             return false;
  519.         }
  520.  
  521.         return true// OK, user can see comments
  522.     }
  523.  
  524.  
  525.     /**
  526.      * Template function: Check if user can leave comment on this post or display error
  527.      *
  528.      * @param string|NULLstring to display before any error message; NULL to not display anything, but just return boolean
  529.      * @param string string to display after any error message
  530.      * @param string error message for non published posts, '#' for default
  531.      * @param string error message for closed comments posts, '#' for default
  532.      * @return boolean true if user can post, false if s/he cannot
  533.      */
  534.     function can_comment$before_error '<p><em>'$after_error '</em></p>'$non_published_msg '#'$closed_msg '#' )
  535.     {
  536.         global $Plugins;
  537.  
  538.         $display is_null($before_error) );
  539.  
  540.         // Ask Plugins (it can say NULL and would get skipped in Plugin::trigger_event_first_return()):
  541.         // Examples:
  542.         //  - A plugin might want to restrict comments on posts older than 20 days.
  543.         //  - A plugin might want to allow comments always for certain users (admin).
  544.         if$event_return $Plugins->trigger_event_first_return'ItemCanComment'array'Item' => $this ) ) )
  545.         {
  546.             $plugin_return_value $event_return['plugin_return'];
  547.             if$plugin_return_value === true )
  548.             {
  549.                 return true// OK, user can comment!
  550.             }
  551.  
  552.             if$display && is_string($plugin_return_value) )
  553.             {
  554.                 echo $before_error;
  555.                 echo $plugin_return_value;
  556.                 echo $after_error;
  557.             }
  558.  
  559.             return false;
  560.         }
  561.  
  562.         $this->get_Blog();
  563.  
  564.         if$this->Blog->allowcomments == 'never')
  565.         {
  566.             return false;
  567.         }
  568.  
  569.         if$this->Blog->allowcomments == 'always')
  570.         {
  571.             return true;
  572.         }
  573.  
  574.         if$this->comment_status == 'disabled'  )
  575.         // Comments are disabled on this post
  576.             return false;
  577.         }
  578.  
  579.         if$this->comment_status == 'closed'  )
  580.         // Comments are closed on this post
  581.  
  582.             if$display)
  583.             {
  584.                 if$closed_msg == '#' )
  585.                     $closed_msg T_'Comments are closed for this post.' );
  586.  
  587.                 echo $before_error;
  588.                 echo $closed_msg;
  589.                 echo $after_error;
  590.             }
  591.  
  592.             return false;
  593.         }
  594.  
  595.         if( ($this->status == 'draft'|| ($this->status == 'deprecated' || ($this->status == 'redirected' ) )
  596.         // Post is not published
  597.  
  598.             if$display )
  599.             {
  600.                 if$non_published_msg == '#' )
  601.                     $non_published_msg T_'This post is not published. You cannot leave comments.' );
  602.  
  603.                 echo $before_error;
  604.                 echo $non_published_msg;
  605.                 echo $after_error;
  606.             }
  607.  
  608.             return false;
  609.         }
  610.  
  611.         return true// OK, user can comment!
  612.     }
  613.  
  614.  
  615.   /**
  616.      * Template function: Check if user can can rate this post
  617.      *
  618.      * @return boolean true if user can post, false if s/he cannot
  619.      */
  620.     function can_rate()
  621.     {
  622.         $this->get_Blog();
  623.  
  624.         if$this->Blog->get_setting('allow_rating'== 'never' )
  625.         {
  626.             return false;
  627.         }
  628.  
  629.         return true// OK, user can rate!
  630.     }
  631.  
  632.  
  633.     /**
  634.      * Get the prerendered content. If it has not been generated yet, it will.
  635.      *
  636.      * @todo dh> Currently this makes up one query per displayed item. Probably the cache should get pre-fetched by ItemList2?
  637.      *  fp> DEFINITELY!!! Preloading all pre-rendered contents for the current Itemlistpage is paramount!
  638.      *
  639.      * @todo dh> In general, $content_prerendered gets only queried once per item, so it seems like a memory waste to cache the query result..!
  640.      *  fp> I don't know if this is supposed to be related but that doesn't change anything to the previous todo.
  641.      *
  642.      *  NOTE: This calls {@link Item::dbupdate()}, if renderers get changed (from Plugin hook).
  643.      *
  644.      * @param string Format, see {@link format_to_output()}.
  645.      *         Only "htmlbody", "entityencoded", "xml" and "text" get cached.
  646.      * @return string 
  647.      */
  648.     function get_prerendered_content$format )
  649.     {
  650.         global $Plugins;
  651.  
  652.         $post_renderers $this->get_renderers_validated();
  653.         $cache_key $format.'/'.implode('.'$post_renderers);
  654.  
  655.         ifisset$this->content_prerendered[$cache_key) )
  656.         {
  657.             $use_cache $this->ID && in_array$formatarray'htmlbody''entityencoded''xml''text' ) );
  658.  
  659.             // $use_cache = false;
  660.  
  661.             if$use_cache )
  662.             // the format/item can be cached:
  663.                 global $DB;
  664.  
  665.                 $cache $DB->get_var"
  666.                     SELECT itpr_content_prerendered
  667.                         FROM T_items__prerendering
  668.                      WHERE itpr_itm_ID = ".$this->ID."
  669.                          AND itpr_format = '".$format."'
  670.                        AND itpr_renderers = '".implode('.'$post_renderers)."'"00'Check prerendered item content' );
  671.  
  672.                 if$cache !== NULL // may be empty string
  673.                 // Retrieved from cache:
  674.                     // echo ' retrieved from prerendered cache';
  675.                     $this->content_prerendered[$cache_key$cache;
  676.                 }
  677.             }
  678.  
  679.             ifisset$this->content_prerendered[$cache_key) )
  680.             {    // Not cached yet:
  681.                 global $Debuglog;
  682.  
  683.                 if$this->update_renderers_from_Plugins() )
  684.                 {
  685.                     $post_renderers $this->get_renderers_validated()// might have changed from call above
  686.                     $cache_key $format.'/'.implode('.'$post_renderers);
  687.  
  688.                     // Save new renderers with item:
  689.                     $this->dbupdate();
  690.                 }
  691.  
  692.                 // Call RENDERER plugins:
  693.                 // pre_dump( $this->content );
  694.                 $this->content_prerendered[$cache_key$this->content;
  695.                 $Plugins->render$this->content_prerendered[$cache_key/* by ref */$post_renderers$formatarray'Item' => $this )'Render' );
  696.                 // pre_dump( $this->content_prerendered[$cache_key] );
  697.  
  698.                 $Debuglog->add'Generated pre-rendered content ['.$cache_key.'] for item #'.$this->ID'items' );
  699.  
  700.                 if$use_cache )
  701.                 // save into DB (using REPLACE INTO because it may have been pre-rendered by another thread since the SELECT above)
  702.                     $DB->query"
  703.                         REPLACE INTO T_items__prerendering (itpr_itm_ID, itpr_format, itpr_renderers, itpr_content_prerendered)
  704.                          VALUES ( ".$this->ID.", '".$format."', ".$DB->quote(implode('.'$post_renderers)).', '.$DB->quote($this->content_prerendered[$cache_key]).' )''Cache prerendered item content' );
  705.                 }
  706.             }
  707.         }
  708.         else
  709.         {
  710.             $Debuglog->add'Fetched pre-rendered content ['.$cache_key.'] for item #'.$this->ID'items' );
  711.         }
  712.  
  713.         return $this->content_prerendered[$cache_key];
  714.     }
  715.  
  716.  
  717.     /**
  718.      * Set the pre-rendered content.
  719.      *
  720.      * This is meant to get called by ItemList2, which would do a single query for all
  721.      * items.
  722.      *
  723.      * @param string Pre-rendered content
  724.      * @param string Cache-Key ($format.'/'.$renderers). See {@link Item::get_prerendered_content()} for the appropriate query skeleton.
  725.      */
  726.     function set_prerendered_content$content$cache_key )
  727.     {
  728.         $this->content_prerendered[$cache_key$content;
  729.     }
  730.  
  731.  
  732.     /**
  733.      * Trigger {@link Plugin::ItemApplyAsRenderer()} event and adjust renderers according
  734.      * to return value.
  735.      * @return boolean True if renderers got changed.
  736.      */
  737.     function update_renderers_from_Plugins()
  738.     {
  739.         global $Plugins;
  740.  
  741.         $r false;
  742.  
  743.         foreach$Plugins->get_list_by_event('ItemApplyAsRenderer'as $Plugin )
  744.         {
  745.             ifempty($Plugin->code) )
  746.                 continue;
  747.  
  748.             $plugin_r $Plugin->ItemApplyAsRenderer$tmp_params array('Item' => $this) );
  749.  
  750.             ifis_bool($plugin_r) )
  751.             {
  752.                 if$plugin_r )
  753.                 {
  754.                     $r $this->add_renderer$Plugin->code || $r;
  755.                 }
  756.                 else
  757.                 {
  758.                     $r $this->remove_renderer$Plugin->code || $r;
  759.                 }
  760.             }
  761.         }
  762.  
  763.         return $r;
  764.     }
  765.  
  766.  
  767.     /**
  768.      * Make sure, the pages have been obtained (and split up_ from prerendered cache.
  769.      *
  770.      * @param string Format, used to retrieve the matching cache; see {@link format_to_output()}
  771.      */
  772.     function split_pages$format 'htmlbody' )
  773.     {
  774.         ifisset$this->content_pages[$format) )
  775.         {
  776.             // SPLIT PAGES:
  777.             $this->content_pages[$formatexplode'<!--nextpage-->'$this->get_prerendered_content($format) );
  778.  
  779.             $this->pages count$this->content_pages[$format);
  780.             // echo ' Pages:'.$this->pages;
  781.         }
  782.     }
  783.  
  784.  
  785.     /**
  786.      * Get a specific page to display (from the prerendered cache)
  787.      *
  788.      * @param integer Page number
  789.      * @param string Format, used to retrieve the matching cache; see {@link format_to_output()}
  790.      */
  791.     function get_content_page$page$format 'htmlbody' )
  792.     {
  793.         // Make sure, the pages are split up:
  794.         $this->split_pages$format );
  795.  
  796.         if$page )
  797.         {
  798.             $page 1;
  799.         }
  800.  
  801.         if$page $this->pages )
  802.         {
  803.             $page $this->pages;
  804.         }
  805.  
  806.         return $this->content_pages[$format][$page-1];
  807.     }
  808.  
  809.  
  810.   /**
  811.      * This is like a teaser with no HTML and a cropping.
  812.      *
  813.      * @todo fp> allow use to submit his own excerpt in expert editing mode
  814.      */
  815.     function get_content_excerpt$crop_at 200 )
  816.     {
  817.         // Get teaser for page 1:
  818.         // fp> Note: I'm not sure about using 'text' here, but there should definitely be no rendering here.
  819.         $output $this->get_content_teaser1false'text' );
  820.  
  821.         // Get rid of all HTML:
  822.         $output strip_tags$output );
  823.  
  824.         // Ger rid of all new lines:
  825.         $output trimstr_replacearray"\r""\n""\t" )array' '' '' ' )$output ) );
  826.  
  827.         ifstrlen$output $crop_at )
  828.         {
  829.             $output substr$output0$crop_at ).'...';
  830.         }
  831.  
  832.         return $output;
  833.     }
  834.  
  835.  
  836.     /**
  837.      * Display content teaser of item (will stop at "<!-- more -->"
  838.      */
  839.     function content_teaser$params )
  840.     {
  841.         // Make sure we are not missing any param:
  842.         $params array_mergearray(
  843.                 'before'      => '',
  844.                 'after'       => '',
  845.                 'disppage'    => '#',
  846.                 'stripteaser' => '#',
  847.                 'format'      => 'htmlbody',
  848.             )$params );
  849.  
  850.         $r $this->get_content_teaser$params['disppage']$params['stripteaser']$params['format');
  851.  
  852.         if!empty($r) )
  853.         {
  854.             echo $params['before'];
  855.             echo $r;
  856.             echo $params['after'];
  857.         }
  858.     }
  859.  
  860.     /**
  861.      * Template function: get content teaser of item (will stop at "<!-- more -->"
  862.      *
  863.      * @param mixed page number to display specific page, # for url parameter
  864.      * @param boolean # if you don't want to repeat teaser after more link was pressed and <-- noteaser --> has been found
  865.      * @param string filename to use to display more
  866.      * @return string 
  867.      */
  868.     function get_content_teaser$disppage '#'$stripteaser '#'$format 'htmlbody' )
  869.     {
  870.         global $Plugins$preview$Debuglog;
  871.         global $more;
  872.  
  873.         // Get requested content page:
  874.         if$disppage === '#' )
  875.         // We want to display the page requested by the user:
  876.             global $page;
  877.             $disppage $page;
  878.         }
  879.  
  880.         $content_page $this->get_content_page$disppage$format )// cannot include format_to_output() because of the magic below.. eg '<!--more-->' will get stripped in "xml"
  881.         // pre_dump($content_page);
  882.  
  883.         $content_parts explode'<!--more-->'$content_page );
  884.         // echo ' Parts:'.count($content_parts);
  885.  
  886.         ifcount($content_parts)
  887.         // This is an extended post (has a more section):
  888.             if$stripteaser === '#' )
  889.             {
  890.                 // If we're in "more" mode and we want to strip the teaser, we'll strip:
  891.                 $stripteaser $more && preg_match('/<!--noteaser-->/'$content_page ) );
  892.             }
  893.  
  894.             if$stripteaser )
  895.             {
  896.                 return NULL;
  897.             }
  898.         }
  899.  
  900.         $output $content_parts[0];
  901.  
  902.         // Trigger Display plugins FOR THE STUFF THAT WOULD NOT BE PRERENDERED:
  903.         $output $Plugins->render$output$this->get_renderers_validated()$formatarray(
  904.                 'Item' => $this,
  905.                 'preview' => $preview,
  906.                 'dispmore' => ($more != 0),
  907.             )'Display' );
  908.  
  909.         // Character conversions
  910.         $output format_to_output$output$format );
  911.  
  912.         return $output;
  913.     }
  914.  
  915.  
  916.     /**
  917.      * DEPRECATED
  918.      */
  919.     function content()
  920.     {
  921.         // ---------------------- POST CONTENT INCLUDED HERE ----------------------
  922.         skin_include'_item_content.inc.php'array(
  923.                 'image_size'    =>    'fit-400x320',
  924.             ) );
  925.         // Note: You can customize the default item feedback by copying the generic
  926.         // /skins/_item_feedback.inc.php file into the current skin folder.
  927.         // -------------------------- END OF POST CONTENT -------------------------
  928.     }
  929.  
  930.  
  931.     /**
  932.      * Display content teaser of item (will stop at "<!-- more -->"
  933.      */
  934.     function content_extension$params )
  935.     {
  936.         // Make sure we are not missing any param:
  937.         $params array_mergearray(
  938.                 'before'      => '',
  939.                 'after'       => '',
  940.                 'disppage'    => '#',
  941.                 'format'      => 'htmlbody',
  942.                 'force_more'  => false,
  943.             )$params );
  944.  
  945.         $r $this->get_content_extension$params['disppage']$params['force_more']$params['format');
  946.  
  947.         if!empty($r) )
  948.         {
  949.             echo $params['before'];
  950.             echo $r;
  951.             echo $params['after'];
  952.         }
  953.     }
  954.  
  955.  
  956.     /**
  957.      * Template function: get content extension of item (part after "<!-- more -->")
  958.      *
  959.      * @param mixed page number to display specific page, # for url parameter
  960.      * @param boolean 
  961.      * @param string filename to use to display more
  962.      * @return string 
  963.      */
  964.     function get_content_extension$disppage '#'$force_more false$format 'htmlbody' )
  965.     {
  966.         global $Plugins$more$preview;
  967.  
  968.         if$more && $force_more )
  969.         {    // NOT in more mode:
  970.             return NULL;
  971.         }
  972.  
  973.         // Get requested content page:
  974.         if$disppage === '#' )
  975.         // We want to display the page requested by the user:
  976.             global $page;
  977.             $disppage $page;
  978.         }
  979.  
  980.         $content_page $this->get_content_page$disppage$format )// cannot include format_to_output() because of the magic below.. eg '<!--more-->' will get stripped in "xml"
  981.         // pre_dump($content_page);
  982.  
  983.         $content_parts explode'<!--more-->'$content_page );
  984.         // echo ' Parts:'.count($content_parts);
  985.  
  986.         ifcount($content_parts)
  987.         // This is NOT an extended post
  988.             return NULL;
  989.         }
  990.  
  991.         // Output everything after <!-- more -->
  992.         array_shift($content_parts);
  993.         $output implode(''$content_parts);
  994.  
  995.         // Trigger Display plugins FOR THE STUFF THAT WOULD NOT BE PRERENDERED:
  996.         $output $Plugins->render$output$this->get_renderers_validated()$formatarray(
  997.                 'Item' => $this,
  998.                 'preview' => $preview,
  999.                 'dispmore' => true,
  1000.             )'Display' );
  1001.  
  1002.         // Character conversions
  1003.         $output format_to_output$output$format );
  1004.  
  1005.         return $output;
  1006.     }
  1007.  
  1008.  
  1009.   /**
  1010.      * Increase view counter
  1011.      *
  1012.      * @todo merge with inc_viewcount
  1013.      */
  1014.     function count_view$params array() )
  1015.     {
  1016.         // Make sure we are not missing any param:
  1017.         $params array_mergearray(
  1018.                 'allow_multiple_counts_per_page' => false,
  1019.             )$params );
  1020.  
  1021.  
  1022.         global $Hit$preview$Debuglog;
  1023.  
  1024.         if$preview )
  1025.         {
  1026.             // echo 'PREVIEW';
  1027.             return false;
  1028.         }
  1029.  
  1030.         /*
  1031.          * Check if we want to increment view count, see {@link Hit::is_new_view()}
  1032.          */
  1033.         if$Hit->is_new_view() )
  1034.         {    // This is a reload
  1035.             // echo 'RELOAD';
  1036.             return false;
  1037.         }
  1038.  
  1039.         if$params['allow_multiple_counts_per_page')
  1040.         {    // Check that we don't increase multiple viewcounts on the same page
  1041.             // This make the assumption that the first post in a list is "viewed" and the other are not (necesarily)
  1042.             global $view_counts_on_this_page;
  1043.             if$view_counts_on_this_page >= )
  1044.             {    // we already had a count on this page
  1045.                 // echo 'ALREADY HAD A COUNT';
  1046.                 return false;
  1047.             }
  1048.             $view_counts_on_this_page++;
  1049.         }
  1050.  
  1051.         //echo 'COUNTING VIEW';
  1052.  
  1053.     // Increment view counter (only if current User is not the item's author)
  1054.         return $this->inc_viewcount()// won't increment if current_User == Author
  1055.  
  1056.     }
  1057.  
  1058.  
  1059.     /**
  1060.      * Template tag
  1061.      */
  1062.     function more_link$params array() )
  1063.     {
  1064.         echo $this->get_more_link$params );
  1065.     }
  1066.  
  1067.  
  1068.   /**
  1069.      * Display more link
  1070.      */
  1071.     function get_more_link$params array() )
  1072.     {
  1073.         // Make sure we are not missing any param:
  1074.         $params array_mergearray(
  1075.                 'before'      => '<p class="bMore">',
  1076.                 'after'       => '</p>',
  1077.                 'link_text'   => '#',        // text to display as the more link
  1078.                 'anchor_text' => '#',        // text to display as the more anchor (once the more link has been clicked)
  1079.                 'disppage'    => '#',        // page number to display specific page, # for url parameter
  1080.                 'format'      => 'htmlbody',
  1081.             )$params );
  1082.  
  1083.         global $more;
  1084.  
  1085.         // Get requested content page:
  1086.         if$params['disppage'=== '#' )
  1087.         // We want to display the page requested by the user:
  1088.             global $page;
  1089.             $params['disppage'$page;
  1090.         }
  1091.  
  1092.         $content_page $this->get_content_page$params['disppage']$params['format')// cannot include format_to_output() because of the magic below.. eg '<!--more-->' will get stripped in "xml"
  1093.         // pre_dump($content_page);
  1094.  
  1095.         $content_parts explode'<!--more-->'$content_page );
  1096.         // echo ' Parts:'.count($content_parts);
  1097.  
  1098.         ifcount($content_parts)
  1099.         // This is NOT an extended post:
  1100.             return '';
  1101.         }
  1102.  
  1103.         if$more )
  1104.         {    // We're NOT in "more" mode:
  1105.             if$params['link_text'== '#' )
  1106.             // TRANS: this is the default text for the extended post "more" link
  1107.                 $params['link_text'T_('Read more').' &raquo;';
  1108.             }
  1109.  
  1110.             return format_to_output$params['before']
  1111.                         .'<a href="'.$this->get_permanent_url().'#more'.$this->ID.'">'
  1112.                         .$params['link_text'].'</a>'
  1113.                         .$params['after']$params['format');
  1114.         }
  1115.         elseifpreg_match('/<!--noteaser-->/'$content_page ) )
  1116.         {    // We are in mode mode and we're not hiding the teaser:
  1117.             // (if we're higin the teaser we display this as a normal page ie: no anchor)
  1118.             if$params['anchor_text'== '#' )
  1119.             // TRANS: this is the default text displayed once the more link has been activated
  1120.                 $params['anchor_text''<p class="bMore">'.T_('Follow up:').'</p>';
  1121.             }
  1122.  
  1123.             return format_to_output'<a id="more'.$this->ID.'" name="more'.$this->ID.'"></a>'
  1124.                             .$params['anchor_text']$params['format');
  1125.         }
  1126.     }
  1127.  
  1128.  
  1129.     /**
  1130.      * Template function: display deadline date (datetime) of Item
  1131.      *
  1132.      * @param string date/time format: leave empty to use locale default date format
  1133.      * @param boolean true if you want GMT
  1134.      */
  1135.     function deadline_date$format ''$useGM false )
  1136.     {
  1137.         ifempty($format) )
  1138.             echo mysql2datelocale_datefmt()$this->datedeadline$useGM);
  1139.         else
  1140.             echo mysql2date$format$this->datedeadline$useGM);
  1141.     }
  1142.  
  1143.  
  1144.     /**
  1145.      * Template function: display deadline time (datetime) of Item
  1146.      *
  1147.      * @param string date/time format: leave empty to use locale default time format
  1148.      * @param boolean true if you want GMT
  1149.      */
  1150.     function deadline_time$format ''$useGM false )
  1151.     {
  1152.         ifempty($format) )
  1153.             echo mysql2datelocale_timefmt()$this->datedeadline$useGM );
  1154.         else
  1155.             echo mysql2date$format$this->datedeadline$useGM );
  1156.     }
  1157.  
  1158.  
  1159.     /**
  1160.      * Get reference to array of Links
  1161.      */
  1162.     function get_Links()
  1163.     {
  1164.         // Make sure links are loaded:
  1165.         $this->load_links();
  1166.  
  1167.         return $this->Links;
  1168.     }
  1169.  
  1170.  
  1171.     /**
  1172.      * Template function: display number of links attached to this Item
  1173.      */
  1174.     function linkcount()
  1175.     {
  1176.         // Make sure links are loaded:
  1177.         $this->load_links();
  1178.  
  1179.         echo count($this->Links);
  1180.     }
  1181.  
  1182.  
  1183.     /**
  1184.      * Load links if they were not loaded yet.
  1185.      */
  1186.     function load_links()
  1187.     {
  1188.         ifis_null$this->Links ) )
  1189.         // Links have not been loaded yet:
  1190.             $LinkCache get_Cache'LinkCache' );
  1191.             $this->Links = $LinkCache->get_by_item_ID$this->ID );
  1192.         }
  1193.     }
  1194.  
  1195.  
  1196.   /**
  1197.      * Get array of tags
  1198.      *
  1199.      * Load from DB if necessary
  1200.      *
  1201.      * @return array 
  1202.      */
  1203.     function get_tags()
  1204.     {
  1205.         global $DB;
  1206.  
  1207.         if!isset$this->tags ) )
  1208.         {
  1209.             $this->tags = $DB->get_col(
  1210.                                             'SELECT tag_name
  1211.                                                   FROM T_items__itemtag INNER JOIN T_items__tag ON itag_tag_ID = tag_ID
  1212.                                                  WHERE itag_itm_ID = '.$this->ID.'
  1213.                                                  ORDER BY tag_name'0'Get tags for Item' );
  1214.         }
  1215.  
  1216.         // pre_dump( $this->tags );
  1217.         return $this->tags;
  1218.     }
  1219.  
  1220.  
  1221.     /**
  1222.      * Split tags by comma or semicolon
  1223.      *
  1224.      * @param string The tags, separated by comma or semicolon
  1225.      */
  1226.     function set_tags_from_string$tags )
  1227.     {
  1228.         if$tags === '' )
  1229.         {
  1230.             $this->tags = array();
  1231.             return;
  1232.         }
  1233.         $this->tags = preg_split'/\s*[;,]+\s*/'$tags-1PREG_SPLIT_NO_EMPTY );
  1234.  
  1235.         iffunction_exists'mb_strtolower' && function_exists'mb_detect_encoding' ) )
  1236.         {    // fp> TODO: instead of those "when used" ifs, it would make more sense to redefine mb_strtolower beforehand if it doesn"t exist (it would then just be a fallback to the strtolower + a Debuglog->add() )
  1237.             array_walk$this->tagscreate_function'& $tag''$tag = mb_strtolower( $tag, mb_detect_encoding( $tag.\'a\', \'UTF-8, ISO-8859-1, ISO-8859-15\', true ) );' ) );
  1238.         }
  1239.         else
  1240.         {    // Tblue> Note: This doesn't work with ISO-8859-1 umlauts like 'Ä' and won't work with UTF-8 either.
  1241.             array_walk$this->tagscreate_function'& $tag''$tag = strtolower( $tag );' ) );
  1242.         }
  1243.         $this->tags = array_unique$this->tags );
  1244.         // pre_dump( $this->tags );
  1245.     }
  1246.  
  1247.  
  1248.     /**
  1249.      * Template function: Provide link to message form for this Item's author.
  1250.      *
  1251.      * @param string url of the message form
  1252.      * @param string to display before link
  1253.      * @param string to display after link
  1254.      * @param string link text
  1255.      * @param string link title
  1256.      * @param string class name
  1257.      * @return boolean true, if a link was displayed; false if there's no email address for the Item's author.
  1258.      */
  1259.     function msgform_link$params array() )
  1260.     {
  1261.         // Make sure we are not missing any param:
  1262.         $params array_mergearray(
  1263.                 'before'      => ' ',
  1264.                 'after'       => ' ',
  1265.                 'text'        => '#',
  1266.                 'title'       => '#',
  1267.                 'class'       => '',
  1268.                 'format'      => 'htmlbody',
  1269.                 'form_url'    => '#current_blog#',
  1270.             )$params );
  1271.  
  1272.         $this->get_creator_User();
  1273.  
  1274.         ifempty($this->creator_User->email) )
  1275.         // We have no email for this Author :(
  1276.             return false;
  1277.         }
  1278.         ifempty($this->creator_User->allow_msgform) )
  1279.         {
  1280.             return false;
  1281.         }
  1282.  
  1283.         if$params['form_url'== '#current_blog#' )
  1284.         {    // Get
  1285.             global $Blog;
  1286.             $params['form_url'$Blog->get('msgformurl');
  1287.         }
  1288.  
  1289.         $params['form_url'url_add_param$params['form_url']'recipient_id='.$this->creator_User->ID.'&amp;post_id='.$this->ID
  1290.             .'&amp;redirect_to='.rawurlencode(url_rel_to_same_host(regenerate_url('','','','&')$params['form_url'])) );
  1291.  
  1292.         if$params['title'== '#' $params['title'T_('Send email to post author');
  1293.         if$params['text'== '#' $params['text'get_icon'email''imgtag'array'class' => 'middle''title' => $params['title') );
  1294.  
  1295.         echo $params['before'];
  1296.         echo '<a href="'.$params['form_url'].'" title="'.$params['title'].'"';
  1297.         if!empty$params['class') ) echo ' class="'.$params['class'].'"';
  1298.         echo ' rel="nofollow">'.$params['text'].'</a>';
  1299.         echo $params['after'];
  1300.  
  1301.         return true;
  1302.     }
  1303.  
  1304.  
  1305.     /**
  1306.      * Template function: Provide link to message form for this Item's assigned User.
  1307.      *
  1308.      * @param string url of the message form
  1309.      * @param string to display before link
  1310.      * @param string to display after link
  1311.      * @param string link text
  1312.      * @param string link title
  1313.      * @param string class name
  1314.      * @return boolean true, if a link was displayed; false if there's no email address for the assigned User.
  1315.      */
  1316.     function msgform_link_assigned$form_url$before ' '$after ' '$text '#'$title '#'$class '' )
  1317.     {
  1318.         if$this->get_assigned_User(|| empty($this->assigned_User->email) )
  1319.         // We have no email for this Author :(
  1320.             return false;
  1321.         }
  1322.  
  1323.         $form_url url_add_param$form_url'recipient_id='.$this->assigned_User->ID );
  1324.         $form_url url_add_param$form_url'post_id='.$this->ID );
  1325.  
  1326.         if$title == '#' $title T_('Send email to assigned user');
  1327.         if$text == '#' $text get_icon'email''imgtag'array'class' => 'middle''title' => $title ) );
  1328.  
  1329.         echo $before;
  1330.         echo '<a href="'.$form_url.'" title="'.$title.'"';
  1331.         if!empty$class ) ) echo ' class="'.$class.'"';
  1332.         echo ' rel="nofollow">'.$text.'</a>';
  1333.         echo $after;
  1334.  
  1335.         return true;
  1336.     }
  1337.  
  1338.  
  1339.     /**
  1340.      *
  1341.      */
  1342.     function page_links$before '#'$after '#'$separator ' '$single ''$current_page '#'$pagelink '%d'$url '' )
  1343.     {
  1344.  
  1345.         // Make sure, the pages are split up:
  1346.         $this->split_pages();
  1347.  
  1348.         if$this->pages <= )
  1349.         {    // Single page:
  1350.             echo $single;
  1351.             return;
  1352.         }
  1353.  
  1354.         if$before == '#' $before '<p>'.T_('Pages:').' ';
  1355.         if$after == '#' $after '</p>';
  1356.  
  1357.         if$current_page == '#' )
  1358.         {
  1359.             global $page;
  1360.             $current_page $page;
  1361.         }
  1362.  
  1363.         ifempty($url) )
  1364.         {
  1365.             $url $this->get_permanent_url'''''&amp;' );
  1366.         }
  1367.  
  1368.         $page_links array();
  1369.  
  1370.         for$i 1$i <= $this->pages$i++ )
  1371.         {
  1372.             $text str_replace('%d'$i$pagelink);
  1373.  
  1374.             if$i != $current_page )
  1375.             {
  1376.                 if$i == )
  1377.                 {    // First page special:
  1378.                     $page_links['<a href="'.$url.'">'.$text.'</a>';
  1379.                 }
  1380.                 else
  1381.                 {
  1382.                     $page_links['<a href="'.url_add_param$url'page='.$i ).'">'.$text.'</a>';
  1383.                 }
  1384.             }
  1385.             else
  1386.             {
  1387.                 $page_links[$text;
  1388.             }
  1389.         }
  1390.  
  1391.         echo $before;
  1392.         echo implode$separator$page_links );
  1393.         echo $after;
  1394.     }
  1395.  
  1396.  
  1397.     /**
  1398.      * Display the images linked to the current Item
  1399.      *
  1400.      * @param array of params
  1401.      * @param string Output format, see {@link format_to_output()}
  1402.      */
  1403.     function images$params array()$format 'htmlbody' )
  1404.     {
  1405.         echo $this->get_images$params$format );
  1406.     }
  1407.  
  1408.  
  1409.     /**
  1410.      * Get block of images linked to the current Item
  1411.      *
  1412.      * @param array of params
  1413.      * @param string Output format, see {@link format_to_output()}
  1414.      */
  1415.     function get_images$params array()$format 'htmlbody' )
  1416.     {
  1417.         $params array_mergearray(
  1418.                 'before' =>              '<div>',
  1419.                 'before_image' =>        '<div class="image_block">',
  1420.                 'before_image_legend' => '<div class="image_legend">',
  1421.                 'after_image_legend' =>  '</div>',
  1422.                 'after_image' =>         '</div>',
  1423.                 'after' =>               '</div>',
  1424.                 'image_size' =>          'fit-720x500'
  1425.             )$params );
  1426.  
  1427.         $FileCache get_Cache'FileCache' );
  1428.  
  1429.         $FileList new DataObjectList2$FileCache );
  1430.  
  1431.  
  1432.         $SQL new SQL();
  1433.         $SQL->SELECT'file_ID, file_title, file_root_type, file_root_ID, file_path, file_alt, file_desc' );
  1434.         $SQL->FROM'T_links INNER JOIN T_files ON link_file_ID = file_ID' );
  1435.         $SQL->WHERE'link_itm_ID = '.$this->ID );
  1436.         $SQL->ORDER_BY'link_ID' );
  1437.  
  1438.         $FileList->sql $SQL->get();
  1439.  
  1440.         $FileList->queryfalsefalsefalse );
  1441.  
  1442.         $r '';
  1443.     /**
  1444.          * @var File
  1445.          */
  1446.         $File NULL;
  1447.         while$File $FileList->get_next() )
  1448.         {
  1449.             if$File->is_image() )
  1450.             {    // Skip anything that is not an image
  1451.                 // fp> TODO: maybe this property should be stored in link_ltype_ID
  1452.                 continue;
  1453.             }
  1454.             // Generate the IMG tag with all the alt, title and desc if available
  1455.             $r .= $File->get_tag$params['before_image']$params['before_image_legend']$params['after_image_legend']$params['after_image']$params['image_size');
  1456.         }
  1457.  
  1458.         if!empty($r) )
  1459.         {
  1460.             $r $params['before'].$r.$params['after'];
  1461.  
  1462.             // Character conversions
  1463.             $r format_to_output$r$format );
  1464.         }
  1465.  
  1466.         return $r;
  1467.     }
  1468.  
  1469.  
  1470.     /**
  1471.      * Template function: Displays link to the feed for comments on this item
  1472.      *
  1473.      * @param string Type of feedback to link to (rss2/atom)
  1474.      * @param string String to display before the link (if comments are to be displayed)
  1475.      * @param string String to display after the link (if comments are to be displayed)
  1476.      * @param string Link title
  1477.      */
  1478.     function feedback_feed_link$skin '_rss2'$before ''$after ''$title='#' )
  1479.     {
  1480.         if$this->can_see_comments() )
  1481.         {    // Comments disabled
  1482.             return;
  1483.         }
  1484.  
  1485.         if$title == '#' )
  1486.         {
  1487.             $title get_icon'feed' ).' '.T_('Comment feed for this post');
  1488.         }
  1489.  
  1490.         $url $this->get_feedback_feed_url($skin);
  1491.  
  1492.         echo $before;
  1493.         echo '<a href="'.$url.'">'.format_to_output($title).'</a>';
  1494.         echo $after;
  1495.     }
  1496.  
  1497.  
  1498.     /**
  1499.      * Get URL to display the post comments in an XML feed.
  1500.      *
  1501.      * @param string 
  1502.      */
  1503.     function get_feedback_feed_url$skin_folder_name )
  1504.     {
  1505.         $this->load_Blog();
  1506.  
  1507.         return url_add_param$this->Blog->get_tempskin_url$skin_folder_name )'disp=comments&amp;p='.$this->ID);
  1508.     }
  1509.  
  1510.  
  1511.     /**
  1512.      * Template function: Displays link to feedback page (under some conditions)
  1513.      *
  1514.      * @param array 
  1515.      */
  1516.     function feedback_link$params )
  1517.     {
  1518.         if$this->can_see_comments() )
  1519.         {    // Comments disabled
  1520.             return;
  1521.         }
  1522.  
  1523.         $params array_mergearray(
  1524.                                     'type' => 'feedbacks',
  1525.                                     'status' => 'published',
  1526.                                     'link_before' => '',
  1527.                                     'link_after' => '',
  1528.                                     'link_text_zero' => '#',
  1529.                                     'link_text_one' => '#',
  1530.                                     'link_text_more' => '#',
  1531.                                     'link_title' => '#',
  1532.                                     'use_popup' => false,
  1533.                                     'url' => '#',
  1534.                                 )$params );
  1535.  
  1536.  
  1537.         // dh> TODO:    Add plugin hook, where a Pingback plugin could hook and provide "pingbacks"
  1538.         switch$params['type')
  1539.         {
  1540.             case 'feedbacks':
  1541.                 if$params['link_title'== '#' $params['link_title'T_('Display feedback / Leave a comment');
  1542.                 if$params['link_text_zero'== '#' $params['link_text_zero'T_('Send feedback').' &raquo;';
  1543.                 if$params['link_text_one'== '#' $params['link_text_one'T_('1 feedback').' &raquo;';
  1544.                 if$params['link_text_more'== '#' $params['link_text_more'T_('%d feedbacks').' &raquo;';
  1545.                 break;
  1546.  
  1547.             case 'comments':
  1548.                 if$params['link_title'== '#' $params['link_title'T_('Display comments / Leave a comment');
  1549.                 if$params['link_text_zero'== '#' )
  1550.                 {
  1551.                     if$this->can_commentNULL ) ) // NULL, because we do not want to display errors here!
  1552.                     {
  1553.                         $params['link_text_zero'T_('Leave a comment').' &raquo;';
  1554.                     }
  1555.                     else
  1556.                     {
  1557.                         $params['link_text_zero''';
  1558.                     }
  1559.                 }
  1560.                 if$params['link_text_one'== '#' $params['link_text_one'T_('1 comment').' &raquo;';
  1561.                 if$params['link_text_more'== '#' $params['link_text_more'T_('%d comments').' &raquo;';
  1562.                 break;
  1563.  
  1564.             case 'trackbacks':
  1565.                 $this->get_Blog();
  1566.                 if$this->Blog->get'allowtrackbacks' ) )
  1567.                 // Trackbacks not allowed on this blog:
  1568.                     return;
  1569.                 }
  1570.                 if$params['link_title'== '#' $params['link_title'T_('Display trackbacks / Get trackback address for this post');
  1571.                 if$params['link_text_zero'== '#' $params['link_text_zero'T_('Send a trackback').' &raquo;';
  1572.                 if$params['link_text_one'== '#' $params['link_text_one'T_('1 trackback').' &raquo;';
  1573.                 if$params['link_text_more'== '#' $params['link_text_more'T_('%d trackbacks').' &raquo;';
  1574.                 break;
  1575.  
  1576.             case 'pingbacks':
  1577.                 // Obsolete, but left for skin compatibility
  1578.                 $this->get_Blog();
  1579.                 if$this->Blog->get'allowtrackbacks' ) )
  1580.                 // Trackbacks not allowed on this blog:
  1581.                     // We'll consider pingbacks to follow the same restriction
  1582.                     return;
  1583.                 }
  1584.                 if$params['link_title'== '#' $params['link_title'T_('Display pingbacks');
  1585.                 if$params['link_text_zero'== '#' $params['link_text_zero'T_('No pingback yet').' &raquo;';
  1586.                 if$params['link_text_one'== '#' $params['link_text_one'T_('1 pingback').' &raquo;';
  1587.                 if$params['link_text_more'== '#' $params['link_text_more'T_('%d pingbacks').' &raquo;';
  1588.                 break;
  1589.  
  1590.             default:
  1591.                 debug_die"Unknown feedback type [{$params['type']}]);
  1592.         }
  1593.  
  1594.         $link_text $this->get_feedback_title$params['type']$params['link_text_zero']$params['link_text_one']$params['link_text_more']$params['status');
  1595.  
  1596.         ifempty($link_text) )
  1597.         {    // No link, no display...
  1598.             return false;
  1599.         }
  1600.  
  1601.         if$params['url'== '#' )
  1602.         // We want a link to single post:
  1603.             $params['url'$this->get_single_url'auto' );
  1604.         }
  1605.  
  1606.  
  1607.         echo $params['link_before'];
  1608.  
  1609.         if!empty$params['url') )
  1610.         {
  1611.             echo '<a href="'.$params['url'];
  1612.             echo '#'.$params['type'].'" ';    // Position on feedback
  1613.             echo 'title="'.$params['link_title'].'"';
  1614.             if$params['use_popup')
  1615.             {    // Special URL if we can open a popup (i-e if JS is enabled):
  1616.                 $popup_url url_add_param$params['url']'disp=feedback-popup' );
  1617.                 echo ' onclick="return pop_up_window( \''.$popup_url.'\', \'evo_comments\' )"';
  1618.             }
  1619.             echo '>';
  1620.             echo $link_text;
  1621.             echo '</a>';
  1622.         }
  1623.         else
  1624.         {
  1625.             echo $link_text;
  1626.         }
  1627.  
  1628.         echo $params['link_after'];
  1629.     }
  1630.  
  1631.  
  1632.     /**
  1633.      * Get text depending on number of comments
  1634.      *
  1635.      * @param string Type of feedback to link to (feedbacks (all)/comments/trackbacks/pingbacks)
  1636.      * @param string Link text to display when there are 0 comments
  1637.      * @param string Link text to display when there is 1 comment
  1638.      * @param string Link text to display when there are >1 comments (include %d for # of comments)
  1639.      * @param string Status of feedbacks to count
  1640.      */
  1641.     function get_feedback_title$type 'feedbacks',    $zero '#'$one '#'$more '#'$status 'published' )
  1642.     {
  1643.         if$this->can_see_comments() )
  1644.         {    // Comments disabled
  1645.             return NULL;
  1646.         }
  1647.  
  1648.         // dh> TODO:    Add plugin hook, where a Pingback plugin could hook and provide "pingbacks"
  1649.         switch$type )
  1650.         {
  1651.             case 'feedbacks':
  1652.                 if$zero == '#' $zero '';
  1653.                 if$one == '#' $one T_('1 feedback');
  1654.                 if$more == '#' $more T_('%d feedbacks');
  1655.                 break;
  1656.  
  1657.             case 'comments':
  1658.                 if$zero == '#' $zero '';
  1659.                 if$one == '#' $one T_('1 comment');
  1660.                 if$more == '#' $more T_('%d comments');
  1661.                 break;
  1662.  
  1663.             case 'trackbacks':
  1664.                 if$zero == '#' $zero '';
  1665.                 if$one == '#' $one T_('1 trackback');
  1666.                 if$more == '#' $more T_('%d trackbacks');
  1667.                 break;
  1668.  
  1669.             case 'pingbacks':
  1670.                 // Obsolete, but left for skin compatibility
  1671.                 if$zero == '#' $zero '';
  1672.                 if$one == '#' $one T_('1 pingback');
  1673.                 if$more == '#' $more T_('%d pingbacks');
  1674.                 break;
  1675.  
  1676.             default:
  1677.                 debug_die"Unknown feedback type [$type]);
  1678.         }
  1679.  
  1680.         $number generic_ctp_number$this->ID$type$status );
  1681.  
  1682.         if$number == )
  1683.             return $zero;
  1684.         elseif$number == )
  1685.             return $one;
  1686.         elseif$number )
  1687.             return str_replace'%d'$number$more );
  1688.     }
  1689.  
  1690.  
  1691.     /**
  1692.      * Template function: Displays feeback moderation info
  1693.      *
  1694.      * @param string Type of feedback to link to (feedbacks (all)/comments/trackbacks/pingbacks)
  1695.      * @param string String to display before the link (if comments are to be displayed)
  1696.      * @param string String to display after the link (if comments are to be displayed)
  1697.      * @param string Link text to display when there are 0 comments
  1698.      * @param string Link text to display when there is 1 comment
  1699.      * @param string Link text to display when there are >1 comments (include %d for # of comments)
  1700.      * @param string Link
  1701.      * @param boolean true to hide if no feedback
  1702.      */
  1703.     function feedback_moderation$type 'feedbacks'$before ''$after '',
  1704.                                                     $zero ''$one '#'$more '#'$edit_comments_link '#'$params array() )
  1705.     {
  1706.         /**
  1707.          * @var User
  1708.          */
  1709.         global $current_User;
  1710.  
  1711.     $params array_mergearray(
  1712.                                     'type' => 'feedbacks',
  1713.                                     'block_before' => '',
  1714.                                     'blo_after' => '',
  1715.                                     'link_text_zero' => '#',
  1716.                                     'link_text_one' => '#',
  1717.                                     'link_text_more' => '#',
  1718.                                     'link_title' => '#',
  1719.                                     'use_popup' => false,
  1720.                                     'url' => '#',
  1721.                                 'type' => 'feedbacks',
  1722.                                     '' => '',
  1723.                                 )$params );
  1724.  
  1725.         ifisset($current_User&& $current_User->check_perm'blog_comments''any'false,    $this->blog_ID ) )
  1726.         {    // We jave permission to edit comments:
  1727.             if$edit_comments_link == '#' )
  1728.             {    // Use default link:
  1729.                 global $admin_url;
  1730.                 $edit_comments_link '<a href="'.$admin_url.'?ctrl=items&amp;blog='.$this->blog_ID.'&amp;p='.$this->ID.'#comments" title="'.T_('Moderate these feedbacks').'">'.get_icon'edit' ).' '.T_('Moderate...').'</a>';
  1731.             }
  1732.         }
  1733.         else
  1734.         // User has no right to edit comments:
  1735.             $edit_comments_link '';
  1736.         }
  1737.  
  1738.         // Inject Edit/moderate link as relevant:
  1739.         $zero str_replace'%s'$edit_comments_link$zero );
  1740.         $one str_replace'%s'$edit_comments_link$one );
  1741.         $more str_replace'%s'$edit_comments_link$more );
  1742.  
  1743.         $r $this->get_feedback_title$type$zero$one$more'draft' );
  1744.  
  1745.         if!empty$r ) )
  1746.         {
  1747.             echo $before.$r.$after;
  1748.         }
  1749.  
  1750.     }
  1751.  
  1752.  
  1753.  
  1754.     /**
  1755.      * Template tag: display footer for the current Item.
  1756.      *
  1757.      * @param array 
  1758.      * @return boolean true if something has been displayed
  1759.      */
  1760.     function footer$params )
  1761.     {
  1762.         // Make sure we are not missing any param:
  1763.         $params array_mergearray(
  1764.                 'mode'        => '#',                // Will detect 'single' from $disp automatically
  1765.                 'block_start' => '<div class="item_footer">',
  1766.                 'block_end'   => '</div>',
  1767.                 'format'      => 'htmlbody',
  1768.             )$params );
  1769.  
  1770.         if$params['mode'== '#' )
  1771.         {
  1772.             global $disp;
  1773.             $params['mode'$disp;
  1774.         }
  1775.  
  1776.         // pre_dump( $params['mode'] );
  1777.  
  1778.         $this->get_Blog();
  1779.         switch$params['mode')
  1780.         {
  1781.             case 'xml':
  1782.                 $text $this->Blog->get_setting'xml_item_footer_text' );
  1783.                 break;
  1784.  
  1785.             case 'single':
  1786.                 $text $this->Blog->get_setting'single_item_footer_text' );
  1787.                 break;
  1788.  
  1789.             default:
  1790.                 // Do NOT display!
  1791.                 $text '';
  1792.         }
  1793.  
  1794.         $text preg_replace_callback'¤\$([a-z_]+)\$¤'array$this'replace_callback' )$text );
  1795.  
  1796.         ifempty($text) )
  1797.         {
  1798.             return false;
  1799.         }
  1800.  
  1801.         echo format_to_output$params['block_start'].$text.$params['block_end']$params['format');
  1802.  
  1803.         return true;
  1804.     }
  1805.  
  1806.  
  1807.  
  1808.     /**
  1809.      * Gets button for deleting the Item if user has proper rights
  1810.      *
  1811.      * @param string to display before link
  1812.      * @param string to display after link
  1813.      * @param string link text
  1814.      * @param string link title
  1815.      * @param string class name
  1816.      * @param boolean true to make this a button instead of a link
  1817.      * @param string page url for the delete action
  1818.      */
  1819.     function get_delete_link$before ' '$after ' '$text '#'$title '#'$class ''$button false$actionurl '#' )
  1820.     {
  1821.         global $current_User$admin_url;
  1822.  
  1823.         ifis_logged_in() ) return false;
  1824.  
  1825.         if$current_User->check_perm'blog_del_post''any'false$this->blog_ID ) )
  1826.         // User has right to delete this post
  1827.             return false;
  1828.         }
  1829.  
  1830.         if$text == '#' )
  1831.         {
  1832.             if$button )
  1833.             {
  1834.                 $text get_icon'delete''imgtag' ).' '.T_('Delete!');
  1835.             }
  1836.             else
  1837.             {
  1838.                 $text T_('Delete!');
  1839.             }
  1840.         }
  1841.  
  1842.         if$title == '#' $title T_('Delete this post');
  1843.  
  1844.         if$actionurl == '#' )
  1845.         {
  1846.             $actionurl $admin_url.'?ctrl=items&amp;action=delete&amp;post_ID=';
  1847.         }
  1848.         $url $actionurl.$this->ID;
  1849.  
  1850.         $r $before;
  1851.         if$button )
  1852.         // Display as button
  1853.             $r .= '<input type="button"';
  1854.             $r .= ' value="'.$text.'" title="'.$title.'" onclick="if ( confirm(\'';
  1855.             $r .= TS_('You are about to delete this post!\\nThis cannot be undone!');
  1856.             $r .= '\') ) { document.location.href=\''.$url.'\' }"';
  1857.             if!empty$class ) ) $r .= ' class="'.$class.'"';
  1858.             $r .= '/>';
  1859.         }
  1860.         else
  1861.         // Display as link
  1862.             $r .= '<a href="'.$url.'" title="'.$title.'" onclick="return confirm(\'';
  1863.             $r .= TS_('You are about to delete this post!\\nThis cannot be undone!');
  1864.             $r .= '\')"';
  1865.             if!empty$class ) ) $r .= ' class="'.$class.'"';
  1866.             $r .= '>'.$text.'</a>';
  1867.         }
  1868.         $r .= $after;
  1869.  
  1870.         return $r;
  1871.     }
  1872.  
  1873.  
  1874.     /**
  1875.      * Displays button for deleting the Item if user has proper rights
  1876.      *
  1877.      * @param string to display before link
  1878.      * @param string to display after link
  1879.      * @param string link text
  1880.      * @param string link title
  1881.      * @param string class name
  1882.      * @param boolean true to make this a button instead of a link
  1883.      * @param string page url for the delete action
  1884.      */
  1885.     function delete_link$before ' '$after ' '$text '#'$title '#'$class ''$button false$actionurl '#' )
  1886.     {
  1887.         echo $this->get_delete_link$before$after$text$title$class$button$actionurl );
  1888.     }
  1889.  
  1890.  
  1891.     /**
  1892.      * Provide link to edit a post if user has edit rights
  1893.      *
  1894.      * @param array Params:
  1895.      *   - 'before': to display before link
  1896.      *   - 'after':    to display after link
  1897.      *   - 'text': link text
  1898.      *   - 'title': link title
  1899.      *   - 'class': CSS class name
  1900.      *   - 'save_context': redirect to current URL?
  1901.      */
  1902.     function get_edit_link$params array() )
  1903.     {
  1904.         global $current_User$admin_url;
  1905.  
  1906.         ifis_logged_in() ) return false;
  1907.  
  1908.         if$this->ID )
  1909.         // preview..
  1910.             return false;
  1911.         }
  1912.  
  1913.         if$current_User->check_perm'item_post!'.$this->status'edit'false$this ) )
  1914.         // User has no right to edit this post
  1915.             return false;
  1916.         }
  1917.  
  1918.         // Make sure we are not missing any param:
  1919.         $params array_mergearray(
  1920.                 'before'       => ' ',
  1921.                 'after'        => ' ',
  1922.                 'text'         => '#',
  1923.                 'title'        => '#',
  1924.                 'class'        => '',
  1925.                 'save_context' => true,
  1926.             )$params );
  1927.  
  1928.  
  1929.         if$params['text'== '#' $params['text'get_icon'edit' ).' '.T_('Edit...');
  1930.  
  1931.         if$params['title'== '#' $params['title'T_('Edit this post...');
  1932.  
  1933.         $actionurl $admin_url.'?ctrl=items&amp;action=edit&amp;p='.$this->ID;
  1934.        if$params['save_context')
  1935.         {
  1936.             $actionurl .= '&amp;redirect_to='.rawurlencoderegenerate_url'''''''&' ) );
  1937.         }
  1938.  
  1939.  
  1940.         $r $params['before'];
  1941.         $r .= '<a href="'.$actionurl;
  1942.         $r .= '" title="'.$params['title'].'"';
  1943.         if!empty$params['class') ) $r .= ' class="'.$params['class'].'"';
  1944.         $r .=  '>'.$params['text'].'</a>';
  1945.         $r .= $params['after'];
  1946.  
  1947.         return $r;
  1948.     }
  1949.  
  1950.  
  1951.     /**
  1952.      * Template tag
  1953.      * @see Item::get_edit_link()
  1954.      */
  1955.     function edit_link$params array() )
  1956.     {
  1957.         echo $this->get_edit_link$params );
  1958.     }
  1959.  
  1960.  
  1961.     /**
  1962.      * Provide link to publish a post if user has edit rights
  1963.      *
  1964.      * Note: publishing date will be updated
  1965.      *
  1966.      * @param string to display before link
  1967.      * @param string to display after link
  1968.      * @param string link text
  1969.      * @param string link title
  1970.      * @param string class name
  1971.      * @param string glue between url params
  1972.      */
  1973.     function get_publish_link$before ' '$after ' '$text '#'$title '#'$class ''$glue '&amp;'$save_context true )
  1974.     {
  1975.         global $current_User$admin_url;
  1976.  
  1977.         ifis_logged_in() ) return false;
  1978.  
  1979.         if( ($this->status == 'published'// Already published!
  1980.             || ($current_User->check_perm'item_post!published''edit'false$this ))
  1981.             || ($current_User->check_perm'edit_timestamp' ) ) )
  1982.         // User has no right to publish this post now:
  1983.             return false;
  1984.         }
  1985.  
  1986.         if$text == '#' $text get_icon'publish''imgtag' ).' '.T_('Publish NOW!');
  1987.         if$title == '#' $title T_('Publish now using current date and time.');
  1988.  
  1989.         $r $before;
  1990.         $r .= '<a href="'.$admin_url.'?ctrl=items'.$glue.'action=publish'.$glue.'post_ID='.$this->ID;
  1991.        if$save_context )
  1992.         {
  1993.             $r .= $glue.'redirect_to='.rawurlencoderegenerate_url'''''''&' ) );
  1994.         }
  1995.         $r .= '" title="'.$title.'"';
  1996.         if!empty$class ) ) $r .= ' class="'.$class.'"';
  1997.         $r .= '>'.$text.'</a>';
  1998.         $r .= $after;
  1999.  
  2000.         return $r;
  2001.     }
  2002.  
  2003.  
  2004.     function publish_link$before ' '$after ' '$text '#'$title '#'$class ''$glue '&amp;'$save_context true )
  2005.     {
  2006.         echo $this->get_publish_link$before$after$text$title$class$glue$save_context );
  2007.     }
  2008.  
  2009.  
  2010.     /**
  2011.      * Provide link to deprecate a post if user has edit rights
  2012.      *
  2013.      * @param string to display before link
  2014.      * @param string to display after link
  2015.      * @param string link text
  2016.      * @param string link title
  2017.      * @param string class name
  2018.      * @param string glue between url params
  2019.      */
  2020.     function get_deprecate_link$before ' '$after ' '$text '#'$title '#'$class ''$glue '&amp;' )
  2021.     {
  2022.         global $current_User$admin_url;
  2023.  
  2024.         ifis_logged_in() ) return false;
  2025.  
  2026.         if( ($this->status == 'deprecated'// Already deprecateded!
  2027.             || ($current_User->check_perm'item_post!deprecated''edit'false$this )) )
  2028.         // User has no right to deprecated this post:
  2029.             return false;
  2030.         }
  2031.  
  2032.         if$text == '#' $text get_icon'deprecate''imgtag' ).' '.T_('Deprecate!');
  2033.         if$title == '#' $title T_('Deprecate this post!');
  2034.  
  2035.         $r $before;
  2036.         $r .= '<a href="'.$admin_url.'?ctrl=items'.$glue.'action=deprecate'.$glue.'post_ID='.$this->ID;
  2037.         $r .= '" title="'.$title.'"';
  2038.         if!empty$class ) ) $r .= ' class="'.$class.'"';
  2039.         $r .= '>'.$text.'</a>';
  2040.         $r .= $after;
  2041.  
  2042.         return $r;
  2043.     }
  2044.  
  2045.  
  2046.     /**
  2047.      * Display link to deprecate a post if user has edit rights
  2048.      *
  2049.      * @param string to display before link
  2050.      * @param string to display after link
  2051.      * @param string link text
  2052.      * @param string link title
  2053.      * @param string class name
  2054.      * @param string glue between url params
  2055.      */
  2056.     function deprecate_link$before ' '$after ' '$text '#'$title '#'$class ''$glue '&amp;' )
  2057.     {
  2058.         echo $this->get_deprecate_link$before$after$text$title$class$glue );
  2059.     }
  2060.  
  2061.  
  2062.     /**
  2063.      * Template function: display priority of item
  2064.      *
  2065.      * @param string 
  2066.      * @param string 
  2067.      */
  2068.     function priority$before ''$after '' )
  2069.     {
  2070.         ifisset($this->priority) )
  2071.         {
  2072.             echo $before;
  2073.             echo $this->priority;
  2074.             echo $after;
  2075.         }
  2076.     }
  2077.  
  2078.  
  2079.     /**
  2080.      * Template function: display list of priority options
  2081.      */
  2082.     function priority_options$field_value$allow_none )
  2083.     {
  2084.         $priority = isset($field_value$field_value $this->priority;
  2085.  
  2086.         $r '';
  2087.         if$allow_none )
  2088.         {
  2089.             $r '<option value="">'./* TRANS: "None" select option */T_('No priority').'</option>';
  2090.         }
  2091.  
  2092.         foreach$this->priorities as $i => $name )
  2093.         {
  2094.             $r .= '<option value="'.$i.'"';
  2095.             if$priority == $i )
  2096.             {
  2097.                 $r .= ' selected="selected"';
  2098.             }
  2099.             $r .= '>'.$name.'</option>';
  2100.         }
  2101.  
  2102.         return $r;
  2103.     }
  2104.  
  2105.  
  2106.     /**
  2107.      * Template function: display checkable list of renderers
  2108.      *
  2109.      * @param array|NULLIf given, assume these renderers to be checked.
  2110.      */
  2111.     function renderer_checkboxes$item_renderers NULL )
  2112.     {
  2113.         global $Plugins$inc_path$admin_url;
  2114.  
  2115.         load_funcs('plugins/_plugin.funcs.php');
  2116.  
  2117.         $Plugins->restart()// make sure iterator is at start position
  2118.  
  2119.         $atLeastOneRenderer false;
  2120.  
  2121.         ifis_null($item_renderers) )
  2122.         {
  2123.             $item_renderers $this->get_renderers();
  2124.         }
  2125.         // pre_dump( $item_renderers );
  2126.  
  2127.         echo '<input type="hidden" name="renderers_displayed" value="1" />';
  2128.  
  2129.         foreach$Plugins->get_list_by_eventsarray('RenderItemAsHtml''RenderItemAsXml''RenderItemAsText') ) as $loop_RendererPlugin )
  2130.         // Go through whole list of renders
  2131.             // echo ' ',$loop_RendererPlugin->code;
  2132.             ifempty($loop_RendererPlugin->code) )
  2133.             // No unique code!
  2134.                 continue;
  2135.             }
  2136.             if$loop_RendererPlugin->apply_rendering == 'stealth'
  2137.                 || $loop_RendererPlugin->apply_rendering == 'never' )
  2138.             // This is not an option.
  2139.                 continue;
  2140.             }
  2141.             $atLeastOneRenderer true;
  2142.  
  2143.             echo '<div>';
  2144.  
  2145.             // echo $loop_RendererPlugin->apply_rendering;
  2146.  
  2147.             echo '<input type="checkbox" class="checkbox" name="renderers[]" value="';
  2148.             echo $loop_RendererPlugin->code;
  2149.             echo '" id="renderer_';
  2150.             echo $loop_RendererPlugin->code;
  2151.             echo '"';
  2152.  
  2153.             switch$loop_RendererPlugin->apply_rendering )
  2154.             {
  2155.                 case 'always':
  2156.                     echo ' checked="checked"';
  2157.                     echo ' disabled="disabled"';
  2158.                     break;
  2159.  
  2160.                 case 'opt-out':
  2161.                     ifin_array$loop_RendererPlugin->code$item_renderers // Option is activated
  2162.                         || in_array'default'$item_renderers ) ) // OR we're asking for default renderer set
  2163.                     {
  2164.                         echo ' checked="checked"';
  2165.                     }
  2166.                     break;
  2167.  
  2168.                 case 'opt-in':
  2169.                     ifin_array$loop_RendererPlugin->code$item_renderers ) ) // Option is activated
  2170.                     {
  2171.                         echo ' checked="checked"';
  2172.                     }
  2173.                     break;
  2174.  
  2175.                 case 'lazy':
  2176.                     ifin_array$loop_RendererPlugin->code$item_renderers ) ) // Option is activated
  2177.                     {
  2178.                         echo ' checked="checked"';
  2179.                     }
  2180.                     echo ' disabled="disabled"';
  2181.                     break;
  2182.             }
  2183.  
  2184.             echo ' title="';
  2185.             echo format_to_output($loop_RendererPlugin->short_desc'formvalue');
  2186.             echo '" />'
  2187.             .' <label for="renderer_';
  2188.             echo $loop_RendererPlugin->code;
  2189.             echo '" title="';
  2190.             echo format_to_output($loop_RendererPlugin->short_desc'formvalue');
  2191.             echo '">';
  2192.             echo format_to_output($loop_RendererPlugin->name);
  2193.             echo '</label>';
  2194.  
  2195.             // fp> TODO: the first thing we want here is a TINY javascript popup with the LONG desc. The links to readme and external help should be inside of the tiny popup.
  2196.             // fp> a javascript DHTML onhover help would be evenb better than the JS popup
  2197.  
  2198.             // internal README.html link:
  2199.             echo ' '.$loop_RendererPlugin->get_help_link('$readme');
  2200.             // external help link:
  2201.             echo ' '.$loop_RendererPlugin->get_help_link('$help_url');
  2202.  
  2203.             echo "</div>\n";
  2204.         }
  2205.  
  2206.         if!$atLeastOneRenderer )
  2207.         {
  2208.             global $admin_url$mode;
  2209.             echo '<a title="'.T_('Configure plugins').'" href="'.$admin_url.'?ctrl=plugins"'.'>'.T_('No renderer plugins are installed.').'</a>';
  2210.         }
  2211.     }
  2212.  
  2213.  
  2214.     /**
  2215.      * Template function: display status of item
  2216.      *
  2217.      * Statuses:
  2218.      * - published
  2219.      * - deprecated
  2220.      * - protected
  2221.      * - private
  2222.      * - draft
  2223.      *
  2224.      * @param string Output format, see {@link format_to_output()}
  2225.      */
  2226.     function status$params array() )
  2227.     {
  2228.         global $post_statuses;
  2229.  
  2230.         // Make sure we are not missing any param:
  2231.         $params array_mergearray(
  2232.                 'before'      => '',
  2233.                 'after'       => '',
  2234.                 'format'      => 'htmlbody',
  2235.             )$params );
  2236.  
  2237.         echo $params['before'];
  2238.  
  2239.         if$params['format'== 'raw' )
  2240.         {
  2241.             status_raw();
  2242.         }
  2243.         else
  2244.         {
  2245.             echo format_to_output$this->get('t_status')$params['format');
  2246.         }
  2247.  
  2248.         echo $params['after'];
  2249.     }
  2250.  
  2251.  
  2252.     function status_raw()
  2253.     {
  2254.         echo $this->status;
  2255.     }
  2256.  
  2257.  
  2258.     /**
  2259.      * Template function: display extra status of item
  2260.      *
  2261.      * @param string 
  2262.      * @param string 
  2263.      * @param string Output format, see {@link format_to_output()}
  2264.      */
  2265.     function extra_status$before ''$after ''$format 'htmlbody' )
  2266.     {
  2267.         if$format == 'raw' )
  2268.         {
  2269.             $this->disp$this->get('t_extra_status')'raw' );
  2270.         }
  2271.         elseif$extra_status $this->get('t_extra_status') )
  2272.         {
  2273.             echo $before.format_to_output$extra_status$format ).$after;
  2274.         }
  2275.     }
  2276.  
  2277.  
  2278.  
  2279.      /**
  2280.      * Display tags for Item
  2281.      *
  2282.      * @param array of params
  2283.      * @param string Output format, see {@link format_to_output()}
  2284.      */
  2285.     function tags$params array() )
  2286.     {
  2287.         $params array_mergearray(
  2288.                 'before' =>           '<div>'.T_('Tags').': ',
  2289.                 'after' =>            '</div>',
  2290.                 'separator' =>        ', ',
  2291.                 'links' =>            true,
  2292.             )$params );
  2293.  
  2294.         $tags $this->get_tags();
  2295.  
  2296.         if!empty$tags ) )
  2297.         {
  2298.             echo $params['before'];
  2299.  
  2300.             if$links $params['links')
  2301.             {
  2302.                 $this->get_Blog();
  2303.             }
  2304.  
  2305.             $i 0;
  2306.             foreach$tags as $tag )
  2307.             {
  2308.                 if$i++ > )
  2309.                 {
  2310.                     echo $params['separator'];
  2311.                 }
  2312.                 if$links )
  2313.                 {    // We want links
  2314.                     echo '<a href="'.$this->Blog->gen_tag_url$tag ).'">';
  2315.                 }
  2316.                 echo htmlspecialchars$tag );
  2317.                 if$links )
  2318.                 {
  2319.                     echo '</a>';
  2320.                 }
  2321.             }
  2322.  
  2323.             echo $params['after'];
  2324.         }
  2325.     }
  2326.  
  2327.  
  2328.     /**
  2329.      * Template function: Displays trackback autodiscovery information
  2330.      *
  2331.      * TODO: build into headers
  2332.      */
  2333.     function trackback_rdf()
  2334.     {
  2335.         $this->get_Blog();
  2336.         if$this->Blog->get'allowtrackbacks' ) )
  2337.         // Trackbacks not allowed on this blog:
  2338.             return;
  2339.         }
  2340.  
  2341.         echo '<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" '."\n";
  2342.         echo '  xmlns:dc="http://purl.org/dc/elements/1.1/"'."\n";
  2343.         echo '  xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">'."\n";
  2344.         echo '<rdf:Description'."\n";
  2345.         echo '  rdf:about="';
  2346.         $this->permanent_url'single' );
  2347.         echo '"'."\n";
  2348.         echo '  dc:identifier="';
  2349.         $this->permanent_url'single' );
  2350.         echo '"'."\n";
  2351.         $this->titlearray(
  2352.             'before'    => ' dc:title="',
  2353.             'after'     => '"'."\n",
  2354.             'link_type' => 'none',
  2355.             'format'    => 'xmlattr',
  2356.             ) );
  2357.         echo '  trackback:ping="';
  2358.         $this->trackback_url();
  2359.         echo '" />'."\n";
  2360.         echo '</rdf:RDF>';
  2361.     }
  2362.  
  2363.  
  2364.     /**
  2365.      * Template function: displays url to use to trackback this item
  2366.      */
  2367.     function trackback_url()
  2368.     {
  2369.         echo $this->get_trackback_url();
  2370.     }
  2371.  
  2372.  
  2373.     /**
  2374.      * Template function: get url to use to trackback this item
  2375.      * @return string 
  2376.      */
  2377.     function get_trackback_url()
  2378.     {
  2379.         global $htsrv_url$Settings;
  2380.  
  2381.         // fp> TODO: get a clean (per blog) setting for this
  2382.         //    return $htsrv_url.'trackback.php/'.$this->ID;
  2383.  
  2384.         return $htsrv_url.'trackback.php?tb_id='.$this->ID;
  2385.     }
  2386.  
  2387.  
  2388.     /**
  2389.      * Template function: Display link to item related url.
  2390.      *
  2391.      * By default the link is displayed as a link.
  2392.      * Optionally some smart stuff may happen.
  2393.      */
  2394.     function url_link$params array() )
  2395.     {
  2396.         global $rsc_url;
  2397.  
  2398.         ifempty$this->url ) )
  2399.         {
  2400.             return;
  2401.         }
  2402.  
  2403.         // Make sure we are not missing any param:
  2404.         $params array_mergearray(
  2405.                 'before'        => ' ',
  2406.                 'after'         => ' ',
  2407.                 'text_template' => '$url$',        // If evaluates to empty, nothing will be displayed (except player if podcast)
  2408.                 'url_template'  => '$url$',
  2409.                 'target'        => '',
  2410.                 'format'        => 'htmlbody',
  2411.                 'podcast'       => '#',                        // handle as podcast. # means depending on post type
  2412.                 'before_podplayer' => '<div class="podplayer">',
  2413.                 'after_podplayer'  => '</div>',
  2414.             )$params );
  2415.  
  2416.         if$params['podcast'== '#' )
  2417.         {    // Check if this post is a podcast
  2418.             $params['podcast'$this->ptyp_ID == 2000 );
  2419.         }
  2420.  
  2421.         if$params['podcast'&& $params['format'== 'htmlbody' )
  2422.         {    // We want podcast display:
  2423.  
  2424.             echo $params['before_podplayer'];
  2425.  
  2426.             echo '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,0,0" width="200" height="20" id="dewplayer" align="middle"><param name="wmode" value="transparent"><param name="allowScriptAccess" value="sameDomain" /><param name="movie" value="'.$rsc_url.'swf/dewplayer.swf?mp3='.$this->url.'&amp;showtime=1" /><param name="quality" value="high" /><param name="bgcolor" value="" /><embed src="'.$rsc_url.'swf/dewplayer.swf?mp3='.$this->url.'&amp;showtime=1" quality="high" bgcolor="" width="200" height="20" name="dewplayer" wmode="transparent" align="middle" allowScriptAccess="sameDomain" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer"></embed></object>';
  2427.  
  2428.             echo $params['after_podplayer'];
  2429.  
  2430.         }
  2431.         else
  2432.         // Not displaying podcast player:
  2433.  
  2434.             $text str_replace'$url$'$this->url$params['text_template');
  2435.             ifempty($text) )
  2436.             {    // Nothing to display
  2437.                 return;
  2438.             }
  2439.  
  2440.             $r $params['before'];
  2441.  
  2442.             $r .= '<a href="'.str_replace'$url$'$this->url$params['url_template').'"';
  2443.  
  2444.             if!empty$params['target') )
  2445.             {
  2446.                 $r .= ' target="'.$params['target'].'"';
  2447.             }
  2448.  
  2449.             $r .= '>'.$text.'</a>';
  2450.  
  2451.             $r .= $params['after'];
  2452.  
  2453.             echo format_to_output$r$params['format');
  2454.         }
  2455.     }
  2456.  
  2457.  
  2458.     /**
  2459.      * Template function: Display the number of words in the post
  2460.      */
  2461.     function wordcount()
  2462.     {
  2463.         echo (int)$this->wordcount// may have been saved as NULL until 1.9
  2464.     }
  2465.  
  2466.  
  2467.     /**
  2468.      * Template function: Display the number of times the Item has been viewed
  2469.      *
  2470.      * Note: viewcount is incremented whenever the Item's content is displayed with "MORE"
  2471.      * (i-e full content), see {@link Item::content()}.
  2472.      *
  2473.      * Viewcount is NOT incremented on page reloads and other special cases, see {@link Hit::is_new_view()}
  2474.      *
  2475.      * %d gets replaced in all params by the number of views.
  2476.      *
  2477.      * @param string Link text to display when there are 0 views
  2478.      * @param string Link text to display when there is 1 views
  2479.      * @param string Link text to display when there are >1 views
  2480.      * @return string The phrase about the number of views.
  2481.      */
  2482.     function get_views$zero '#'$one '#'$more '#' )
  2483.     {
  2484.         if!$this->views )
  2485.         {
  2486.             $r $zero == '#' T_'No views' $zero );
  2487.         }
  2488.         elseif$this->views == )
  2489.         {
  2490.             $r $one == '#' T_'1 view' $one );
  2491.         }
  2492.         else
  2493.         {
  2494.             $r $more == '#' T_'%d views' $more );
  2495.         }
  2496.  
  2497.         return str_replace'%d'$this->views$r );
  2498.     }
  2499.  
  2500.  
  2501.     /**
  2502.      * Template function: Display a phrase about the number of Item views.
  2503.      *
  2504.      * @param string Link text to display when there are 0 views
  2505.      * @param string Link text to display when there is 1 views
  2506.      * @param string Link text to display when there are >1 views (include %d for # of views)
  2507.      * @return integer Number of views.
  2508.      */
  2509.     function views$zero '#'$one '#'$more '#' )
  2510.     {
  2511.         echo $this->get_views$zero$one$more );
  2512.  
  2513.         return $this->views;
  2514.     }
  2515.  
  2516.  
  2517.     /**
  2518.      * Set param value
  2519.      *
  2520.      * By default, all values will be considered strings
  2521.      *
  2522.      * @todo extra_cat_IDs recording
  2523.      *
  2524.      * @param string parameter name
  2525.      * @param mixed parameter value
  2526.      * @param boolean true to set to NULL if empty value
  2527.      * @return boolean true, if a value has been set; false if it has not changed
  2528.      */
  2529.     function set$parname$parvalue$make_null false )
  2530.     {
  2531.         switch$parname )
  2532.         {
  2533.             case 'pst_ID':
  2534.                 return $this->set_param$parname'number'$parvaluetrue );
  2535.  
  2536.             case 'content':
  2537.                 $r1 $this->set_param'content''string'$parvalue$make_null );
  2538.                 // Update wordcount as well:
  2539.                 $r2 $this->set_param'wordcount''number'bpost_count_words($this->content)false );
  2540.                 return $r1 || $r2 )// return true if one changed
  2541.  
  2542.             case 'wordcount':
  2543.                 return $this->set_param'wordcount''number'$parvaluefalse );
  2544.  
  2545.             case 'datedeadline':
  2546.                 return $this->set_param'datedeadline''date'$parvaluetrue );
  2547.  
  2548.             case 'renderers'// deprecated
  2549.                 return $this->set_renderers$parvalue );
  2550.  
  2551.             default:
  2552.                 return parent::set$parname$parvalue$make_null );
  2553.         }
  2554.     }
  2555.  
  2556.  
  2557.     /**
  2558.      * Set the renderers of the Item.
  2559.      *
  2560.      * @param array List of renderer codes.
  2561.      * @return boolean true, if it has been set; false if it has not changed
  2562.      */
  2563.     function set_renderers$renderers )
  2564.     {
  2565.         return $this->set_param'renderers''string'implode'.'$renderers ) );
  2566.     }
  2567.  
  2568.  
  2569.     /**
  2570.      * Set the Author of the Item.
  2571.      *
  2572.      * @param User (Do NOT set to NULL or you may kill the current_User)
  2573.      * @return boolean true, if it has been set; false if it has not changed
  2574.      */
  2575.     function set_creator_User$creator_User )
  2576.     {
  2577.         $this->creator_User = $creator_User;
  2578.         $this->Author = $this->creator_User// deprecated  fp> TODO: Test and see if this line can be put once and for all in the constructor
  2579.         return $this->set$this->creator_field$creator_User->ID );
  2580.     }
  2581.  
  2582.  
  2583.     /**
  2584.      * Create a new Item/Post and insert it into the DB
  2585.      *
  2586.      * This function has to handle all needed DB dependencies!
  2587.      *
  2588.      * @deprecated since EVO_NEXT_VERSION. Use set() + dbinsert() instead
  2589.      */
  2590.     function insert(
  2591.         $author_user_ID,              // Author
  2592.         $post_title,
  2593.         $post_content,
  2594.         $post_timestamp,              // 'Y-m-d H:i:s'
  2595.         $main_cat_ID 1,             // Main cat ID
  2596.         $extra_cat_IDs array(),     // Table of extra cats
  2597.         $post_status 'published',
  2598.         $post_locale '#',
  2599.         $post_urltitle '',
  2600.         $post_url '',
  2601.         $post_comment_status 'open',
  2602.         $post_renderers array('default'),
  2603.         $item_typ_ID 1,
  2604.         $item_st_ID NULL )
  2605.     {
  2606.         global $DB$query$UserCache;
  2607.         global $localtimenow$default_locale;
  2608.  
  2609.         if$post_locale == '#' $post_locale $default_locale;
  2610.  
  2611.         // echo 'INSERTING NEW POST ';
  2612.  
  2613.         ifisset$UserCache ) )    // DIRTY HACK
  2614.         // If not in install procedure...
  2615.             $this->set_creator_User$UserCache->get_by_ID$author_user_ID ) );
  2616.         }
  2617.         else
  2618.         {
  2619.             $this->set$this->creator_field$author_user_ID );
  2620.         }
  2621.         $this->set$this->lasteditor_field$this->{$this->creator_field);
  2622.         $this->set'title'$post_title );
  2623.         $this->set'urltitle'$post_urltitle );
  2624.         $this->set'content'$post_content );
  2625.         $this->set'datestart'$post_timestamp );
  2626.  
  2627.         // TODO: dh> $localtimenow is not defined during install! - all sample posts get a last-modified date of 1970-01-01
  2628.         $this->set'datemodified'date('Y-m-d H:i:s',$localtimenow) );
  2629.  
  2630.         $this->set'main_cat_ID'$main_cat_ID );
  2631.         $this->set'extra_cat_IDs'$extra_cat_IDs );
  2632.         $this->set'status'$post_status );
  2633.         $this->set'locale'$post_locale );
  2634.         $this->set'url'$post_url );
  2635.         $this->set'comment_status'$post_comment_status );
  2636.         $this->set_renderers$post_renderers );
  2637.         $this->set'ptyp_ID'$item_typ_ID );
  2638.         $this->set'pst_ID'$item_st_ID );
  2639.  
  2640.         // INSERT INTO DB:
  2641.         $this->dbinsert();
  2642.  
  2643.         return $this->ID;
  2644.     }
  2645.  
  2646.  
  2647.     /**
  2648.      * Insert object into DB based on previously recorded changes
  2649.      *
  2650.      * @return boolean true on success
  2651.      */
  2652.     function dbinsert()
  2653.     {
  2654.         global $DB$current_User$Plugins;
  2655.  
  2656.         $DB->begin();
  2657.  
  2658.         ifempty($this->creator_user_ID) )
  2659.         // No creator assigned yet, use current user:
  2660.             $this->set_creator_User$current_User );
  2661.         }
  2662.  
  2663.         // validate url title
  2664.         $this->set'urltitle'urltitle_validate$this->urltitle$this->title0false$this->dbprefix$this->dbIDname$this->dbtablename) );
  2665.  
  2666.         $this->update_renderers_from_Plugins();
  2667.  
  2668.         // TODO: allow a plugin to cancel update here (by returning false)?
  2669.         $Plugins->trigger_event'PrependItemInsertTransact'$params array'Item' => $this ) );
  2670.  
  2671.         $dbchanges $this->dbchanges// we'll save this for passing it to the plugin hook
  2672.  
  2673.         if$result parent::dbinsert() )
  2674.         // We could insert the item object..
  2675.  
  2676.             // Let's handle the extracats:
  2677.             $this->insert_update_extracats'insert' );
  2678.  
  2679.             // Let's handle the tags:
  2680.             $this->insert_update_tags'insert' );
  2681.  
  2682.             $DB->commit();
  2683.  
  2684.             $Plugins->trigger_event'AfterItemInsert'$params array'Item' => $this'dbchanges' => $dbchanges ) );
  2685.         }
  2686.         else
  2687.         {
  2688.             $DB->rollback();
  2689.         }
  2690.  
  2691.         return $result;
  2692.     }
  2693.  
  2694.  
  2695.  
  2696.  
  2697.     /**
  2698.      * Update the DB based on previously recorded changes
  2699.      *
  2700.      * @return boolean true on success
  2701.      */
  2702.     function dbupdate()
  2703.     {
  2704.         global $DB$Plugins;
  2705.  
  2706.         $DB->begin();
  2707.  
  2708.         // validate url title
  2709.         ifempty($this->urltitle|| isset($this->dbchanges['post_urltitle']) )
  2710.         // Url title has changed or is empty
  2711.             // echo 'updating url title';
  2712.             $this->set'urltitle'urltitle_validate$this->urltitle$this->title$this->ID,
  2713.                                                                 false$this->dbprefix$this->dbIDname$this->dbtablename ) );
  2714.         }
  2715.  
  2716.         $this->update_renderers_from_Plugins();
  2717.  
  2718.         // TODO: dh> allow a plugin to cancel update here (by returning false)?
  2719.         $Plugins->trigger_event'PrependItemUpdateTransact'$params array'Item' => $this ) );
  2720.  
  2721.         $dbchanges $this->dbchanges// we'll save this for passing it to the plugin hook
  2722.  
  2723.         if$result parent::dbupdate() )
  2724.         // We could update the item object..
  2725.  
  2726.             // Let's handle the extracats:
  2727.             $this->insert_update_extracats'update' );
  2728.  
  2729.             // Let's handle the extracats:
  2730.             $this->insert_update_tags'update' );
  2731.  
  2732.             // Empty pre-rendered content cache - any item property may have influence on it:
  2733.             $DB->query'DELETE FROM T_items__prerendering WHERE itpr_itm_ID = '.$this->ID );
  2734.             $this->content_prerendered = NULL;
  2735.  
  2736.             $DB->commit();
  2737.  
  2738.             $Plugins->trigger_event'AfterItemUpdate'$params array'Item' => $this'dbchanges' => $dbchanges ) );
  2739.         }
  2740.         else
  2741.         {
  2742.             $DB->commit();
  2743.         }
  2744.  
  2745.         return $result;
  2746.     }
  2747.  
  2748.  
  2749.     /**
  2750.      * Trigger event AfterItemDelete after calling parent method.
  2751.      *
  2752.      * @todo fp> delete related stuff: comments, cats, file links...
  2753.      *
  2754.      * @return boolean true on success
  2755.      */
  2756.     function dbdelete()
  2757.     {
  2758.         global $DB$Plugins;
  2759.  
  2760.         // remember ID, because parent method resets it to 0
  2761.         $old_ID $this->ID;
  2762.  
  2763.         $DB->begin();
  2764.  
  2765.         if$r parent::dbdelete() )
  2766.         {
  2767.             // Empty pre-rendered content cache:
  2768.             $DB->query'DELETE FROM T_items__prerendering
  2769.                                WHERE itpr_itm_ID = '.$this->ID );
  2770.             $this->content_prerendered = NULL;
  2771.  
  2772.             $DB->commit();
  2773.  
  2774.             // re-set the ID for the Plugin event
  2775.             $this->ID = $old_ID;
  2776.  
  2777.             $Plugins->trigger_event'AfterItemDelete'$params array'Item' => $this ) );
  2778.  
  2779.             $this->ID = 0;
  2780.         }
  2781.         else
  2782.         {
  2783.             $DB->rollback();
  2784.         }
  2785.  
  2786.         return $r;
  2787.     }
  2788.  
  2789.  
  2790.     /**
  2791.      * @param string 'insert' | 'update'
  2792.      */
  2793.     function insert_update_extracats$mode )
  2794.     {
  2795.         global $DB;
  2796.  
  2797.         $DB->begin();
  2798.  
  2799.         ifis_null$this->extra_cat_IDs ) )
  2800.         // Okay the extra cats are defined:
  2801.  
  2802.             if$mode == 'update' )
  2803.             {
  2804.                 // delete previous extracats:
  2805.                 $DB->query'DELETE FROM T_postcats WHERE postcat_post_ID = '.$this->ID'delete previous extracats' );
  2806.             }
  2807.  
  2808.             // insert new extracats:
  2809.             $query "INSERT INTO T_postcats( postcat_post_ID, postcat_cat_ID ) VALUES ";
  2810.             foreach$this->extra_cat_IDs as $extra_cat_ID )
  2811.             {
  2812.                 //echo "extracat: $extracat_ID <br />";
  2813.                 $query .= "$this->ID$extra_cat_ID ),";
  2814.             }
  2815.             $query substr$query0strlen$query );
  2816.             $DB->query$query'insert new extracats' );
  2817.         }
  2818.  
  2819.         $DB->commit();
  2820.     }
  2821.  
  2822.  
  2823.     /**
  2824.      * Save tags to DB
  2825.      *
  2826.      * @param string 'insert' | 'update'
  2827.      */
  2828.     function insert_update_tags$mode )
  2829.     {
  2830.         global $DB;
  2831.  
  2832.         ifisset$this->tags ) )
  2833.         // Okay the tags are defined:
  2834.  
  2835.             $DB->begin();
  2836.  
  2837.             if$mode == 'update' )
  2838.             {    // delete previous tag associations:
  2839.                 // Note: actual tags never get deleted
  2840.                 $DB->query'DELETE FROM T_items__itemtag
  2841.                                             WHERE itag_itm_ID = '.$this->ID'delete previous tags' );
  2842.             }
  2843.  
  2844.             if!empty($this->tags) )
  2845.             {
  2846.                 // Find the tags that are already in the DB
  2847.                 $query 'SELECT LOWER( tag_name )
  2848.                                         FROM T_items__tag
  2849.                                      WHERE tag_name IN ('.$DB->quote($this->tags).')';
  2850.                 $existing_tags $DB->get_col$query0'Find existing tags' );
  2851.  
  2852.                 $new_tags array_diff$this->tags$existing_tags );
  2853.                 //pre_dump($new_tags);
  2854.  
  2855.                 if!empty$new_tags ) )
  2856.                 {    // insert new tags:
  2857.                     $query "INSERT INTO T_items__tag( tag_name ) VALUES ";
  2858.                     foreach$new_tags as $tag )
  2859.                     {
  2860.                         $query .= '( '.$DB->quote($tag).' ),';
  2861.                     }
  2862.                     $query substr$query0strlen$query );
  2863.                     $DB->query$query'insert new tags' );
  2864.                 }
  2865.  
  2866.                 // ASSOC:
  2867.                 $query 'INSERT INTO T_items__itemtag( itag_itm_ID, itag_tag_ID )
  2868.                                   SELECT '.$this->ID.', tag_ID
  2869.                                       FROM T_items__tag
  2870.                                      WHERE tag_name IN ('.$DB->quote($this->tags).')';
  2871.                 $DB->query$query'Make tag associations!' );
  2872.             }
  2873.  
  2874.             $DB->commit();
  2875.         }
  2876.     }
  2877.  
  2878.  
  2879.     /**
  2880.      * Increment the view count of the item directly in DB (if the item's Author is not $current_User).
  2881.      *
  2882.      * This method serves TWO purposes (that would break if we used dbupdate() ) :
  2883.      *  - Increment the viewcount WITHOUT affecting the lastmodified date and user.
  2884.      *  - Increment the viewcount in an ATOMIC manner (even if several hits on the same Item occur simultaneously).
  2885.      *
  2886.      * This also triggers the plugin event 'ItemViewsIncreased' if the view count has been increased.
  2887.      *
  2888.      * @return boolean Did we increase view count?
  2889.      */
  2890.     function inc_viewcount()
  2891.     {
  2892.         global $Plugins$DB$current_User$Debuglog;
  2893.  
  2894.         ifisset$current_User && $current_User->ID == $this->creator_user_ID ) )
  2895.         {
  2896.             $Debuglog->add'Not incrementing view count, because viewing user is creator of the item.''items' );
  2897.  
  2898.             return false;
  2899.         }
  2900.  
  2901.         $DB->query'UPDATE T_items__item
  2902.                         SET post_views = post_views + 1
  2903.                       WHERE '.$this->dbIDname.' = '.$this->ID );
  2904.  
  2905.         // Trigger event that the item's view has been increased
  2906.         $Plugins->trigger_event'ItemViewsIncreased'array'Item' => $this ) );
  2907.  
  2908.         return true;
  2909.     }
  2910.  
  2911.  
  2912.     /**
  2913.      * Get the User who is assigned to the Item.
  2914.      *
  2915.      * @return User|NULLNULL if no user is assigned.
  2916.      */
  2917.     function get_assigned_User()
  2918.     {
  2919.         ifisset($this->assigned_User&& isset($this->assigned_user_ID) )
  2920.         {
  2921.             $UserCache get_Cache'UserCache' );
  2922.             $this->assigned_User = $UserCache->get_by_ID$this->assigned_user_ID );
  2923.         }
  2924.  
  2925.         return $this->assigned_User;
  2926.     }
  2927.  
  2928.  
  2929.     /**
  2930.      * Get the User who created the Item.
  2931.      *
  2932.      * @return User 
  2933.      */
  2934.     function get_creator_User()
  2935.     {
  2936.         ifis_null($this->creator_User) )
  2937.         {
  2938.             $UserCache get_Cache'UserCache' );
  2939.             $this->creator_User = $UserCache->get_by_ID$this->creator_user_ID );
  2940.             $this->Author = $this->creator_User;  // deprecated
  2941.         }
  2942.  
  2943.         return $this->creator_User;
  2944.     }
  2945.  
  2946.  
  2947.     /**
  2948.      * Get the Blog object for the Item.
  2949.      *
  2950.      * @return Blog 
  2951.      */
  2952.     function get_Blog()
  2953.     {
  2954.         ifis_null($this->Blog) )
  2955.         {
  2956.             $this->load_Blog();
  2957.         }
  2958.  
  2959.         return $this->Blog;
  2960.     }
  2961.  
  2962.  
  2963.     /**
  2964.      * Load the Blog object for the Item, without returning it.
  2965.      *
  2966.      * This is needed for {@link Results} object callbacks.
  2967.      */
  2968.     function load_Blog()
  2969.     {
  2970.         ifis_null($this->Blog) )
  2971.         {
  2972.             $BlogCache get_Cache'BlogCache' );
  2973.             $this->Blog = $BlogCache->get_by_ID$this->blog_ID );
  2974.         }
  2975.     }
  2976.  
  2977.  
  2978.     /**
  2979.      * Execute or schedule post(=after) processing tasks
  2980.      *
  2981.      * Includes notifications & pings
  2982.      */
  2983.     function handle_post_processing()
  2984.     {
  2985.         global $Settings$Messages;
  2986.  
  2987.         $notifications_mode $Settings->get('outbound_notifications_mode');
  2988.  
  2989.         if$notifications_mode == 'off' )
  2990.         {    // Exit silently
  2991.             return false;
  2992.         }
  2993.  
  2994.         if$this->notifications_status == 'finished' )
  2995.         // pings have been done before
  2996.             $Messages->addT_('Post had already pinged: skipping notifications...')'note' );
  2997.             return false;
  2998.         }
  2999.  
  3000.         if$this->notifications_status != 'noreq' )
  3001.         // pings have been done before
  3002.  
  3003.             // TODO: Check if issue_date has changed and reschedule
  3004.  
  3005.             $Messages->addT_('Post processing already pending...')'note' );
  3006.             return false;
  3007.         }
  3008.  
  3009.         if$this->status != 'published' )
  3010.         {
  3011.  
  3012.             // TODO: discard any notification that may be pending!
  3013.  
  3014.             $Messages->addT_('Post not publicly published: skipping notifications...')'note' );
  3015.             return false;
  3016.         }
  3017.  
  3018.         if$notifications_mode == 'immediate' )
  3019.         {    // We want to do the post processing immediately:
  3020.             // send outbound pings:
  3021.             $this->send_outbound_pings();
  3022.  
  3023.             // Send email notifications now!
  3024.             $this->send_email_notificationsfalse );
  3025.  
  3026.             // Record that processing has been done:
  3027.             $this->set'notifications_status''finished' );
  3028.         }
  3029.         else
  3030.         {    // We want asynchronous post processing:
  3031.             $Messages->addT_('Scheduling asynchronous notifications...')'note' );
  3032.  
  3033.             // CREATE OBJECT:
  3034.             load_class'/cron/model/_cronjob.class.php' );
  3035.             $edited_Cronjob new Cronjob();
  3036.  
  3037.             // start datetime. We do not want to ping before the post is effectively published:
  3038.             $edited_Cronjob->set'start_datetime'$this->issue_date );
  3039.  
  3040.             // no repeat.
  3041.  
  3042.             // name:
  3043.             $edited_Cronjob->set'name'sprintfT_('Send notifications for &laquo;%s&raquo;')strip_tags($this->title) ) );
  3044.  
  3045.             // controller:
  3046.             $edited_Cronjob->set'controller''cron/jobs/_post_notifications.job.php' );
  3047.  
  3048.             // params: specify which post this job is supposed to send notifications for:
  3049.             $edited_Cronjob->set'params'array'item_ID' => $this->ID ) );
  3050.  
  3051.             // Save cronjob to DB:
  3052.             $edited_Cronjob->dbinsert();
  3053.  
  3054.             // Memorize the cron job ID which is going to handle this post:
  3055.             $this->set'notifications_ctsk_ID'$edited_Cronjob->ID );
  3056.  
  3057.             // Record that processing has been scheduled:
  3058.             $this->set'notifications_status''todo' );
  3059.         }
  3060.  
  3061.         // Save the new processing status to DB
  3062.         $this->dbupdate();
  3063.  
  3064.         return true;
  3065.     }
  3066.  
  3067.  
  3068.     /**
  3069.      * Send email notifications to subscribed users
  3070.      *
  3071.      * @todo fp>> shall we notify suscribers of blog were this is in extra-cat? blueyed>> IMHO yes.
  3072.      */
  3073.     function send_email_notifications$display true )
  3074.     {
  3075.         global $DB$admin_url$debug$Debuglog;
  3076.  
  3077.          $edited_Blog $this->get_Blog();
  3078.  
  3079.         if$edited_Blog->get_setting'allow_subscriptions' ) )
  3080.         {    // Subscriptions not enabled!
  3081.             return;
  3082.         }
  3083.  
  3084.         if$display )
  3085.         {
  3086.             echo "<div class=\"panelinfo\">\n";
  3087.             echo '<h3>'T_('Notifying subscribed users...')"</h3>\n";
  3088.         }
  3089.  
  3090.         // Get list of users who want to be notfied:
  3091.         // TODO: also use extra cats/blogs??
  3092.         $sql 'SELECT DISTINCT user_email, user_locale
  3093.                             FROM T_subscriptions INNER JOIN T_users ON sub_user_ID = user_ID
  3094.                         WHERE sub_coll_ID = '.$this->blog_ID.'
  3095.                             AND sub_items <> 0
  3096.                             AND LENGTH(TRIM(user_email)) > 0';
  3097.         $notify_list $DB->get_results$sql );
  3098.  
  3099.         // Preprocess list: (this comes form Comment::send_email_notifications() )
  3100.         $notify_array array();
  3101.         foreach$notify_list as $notification )
  3102.         {
  3103.             $notify_array[$notification->user_email$notification->user_locale;
  3104.         }
  3105.  
  3106.         ifempty($notify_array) )
  3107.         // No-one to notify:
  3108.             if$display )
  3109.             {
  3110.                 echo '<p>'T_('No-one to notify.')"</p>\n</div>\n";
  3111.             }
  3112.             return false;
  3113.         }
  3114.  
  3115.         /*
  3116.          * We have a list of email addresses to notify:
  3117.          */
  3118.         $this->get_creator_User();
  3119.         $mail_from '"'.$this->creator_User->get('preferredname').'" <'.$this->creator_User->get('email').'>';
  3120.  
  3121.         // Send emails:
  3122.         $cache_by_locale array();
  3123.         foreach$notify_array as $notify_email => $notify_locale )
  3124.         {
  3125.             ifisset($cache_by_locale[$notify_locale]) )
  3126.             // No message for this locale generated yet:
  3127.                 locale_temp_switch($notify_locale);
  3128.  
  3129.                 // Calculate length for str_pad to align labels:
  3130.                 $pad_len maxstrlen(T_('Blog'))strlen(T_('Author'))strlen(T_('Title'))strlen(T_('Url'))strlen(T_('Content')) );
  3131.  
  3132.                 $cache_by_locale[$notify_locale]['subject'sprintfT_('[%s] New post: "%s"')$edited_Blog->get('shortname')$this->get('title') );
  3133.  
  3134.                 $cache_by_locale[$notify_locale]['message'=
  3135.                     str_padT_('Blog')$pad_len ).': '.$edited_Blog->get('shortname')
  3136.                     .' ( '.str_replace('&amp;''&'$edited_Blog->gen_blogurl())." )\n"
  3137.  
  3138.                     .str_padT_('Author')$pad_len ).': '.$this->creator_User->get('preferredname').' ('.$this->creator_User->get('login').")\n"
  3139.  
  3140.                     .str_padT_('Title')$pad_len ).': '.$this->get('title')."\n"
  3141.  
  3142.                     // linked URL or "-" if empty:
  3143.                     .str_padT_('Url')$pad_len ).': '.empty$this->url '-' str_replace('&amp;''&'$this->get('url')) )."\n"
  3144.  
  3145.                     .str_padT_('Content')$pad_len ).': '
  3146.                         // TODO: We MAY want to force a short URL and avoid it to wrap on a new line in the mail which may prevent people from clicking
  3147.                         // TODO: might get moved onto a single line, at the end of the content..
  3148.                         .str_replace('&amp;''&'$this->get_permanent_url())."\n\n"
  3149.  
  3150.                     .$this->get('content')."\n"
  3151.  
  3152.                     // Footer:
  3153.                     ."\n-- \n"
  3154.                     .T_('Edit/Delete').': '.$admin_url.'?ctrl=items&blog='.$this->blog_ID.'&p='.$this->ID."\n\n"
  3155.  
  3156.                     .T_('Edit your subscriptions/notifications').': '.str_replace('&amp;''&'url_add_param$edited_Blog->gen_blogurl()'disp=subs' ) )."\n";
  3157.  
  3158.                 locale_restore_previous();
  3159.             }
  3160.  
  3161.             if$display echo T_('Notifying:').$notify_email."<br />\n";
  3162.             if$debug >= )
  3163.             {
  3164.                 echo "<p>Sending notification to $notify_email:<pre>$cache_by_locale[$notify_locale]['message']</pre>";
  3165.             }
  3166.  
  3167.             send_mail$notify_email$cache_by_locale[$notify_locale]['subject']$cache_by_locale[$notify_locale]['message']$mail_from );
  3168.         }
  3169.  
  3170.         if$display echo '<p>'T_('Done.')"</p>\n</div>\n";
  3171.     }
  3172.  
  3173.  
  3174.   /**
  3175.      * Send outbound pings for a post
  3176.      */
  3177.     function send_outbound_pings()
  3178.     {
  3179.         global $Plugins$baseurl$Messages;
  3180.  
  3181.         load_funcs('xmlrpc/model/_xmlrpc.funcs.php');
  3182.  
  3183.         $this->load_Blog();
  3184.         $ping_plugins array_unique(explode(','$this->Blog->get_setting('ping_plugins')));
  3185.  
  3186.         ifpreg_match'#^http://localhost[/:]#'$baseurl)
  3187.             || preg_match'~^\w+://[^/]+\.local/~'$baseurl /* domain ending in ".local" */  )
  3188.         {
  3189.             $Messages->addT_('Skipping pings (Running on localhost).')'note' );
  3190.         }
  3191.         else foreach$ping_plugins as $plugin_code )
  3192.         {
  3193.             $Plugin $Plugins->get_by_code($plugin_code);
  3194.  
  3195.             if$Plugin )
  3196.             {
  3197.                 $Messages->addsprintf(T_('Pinging %s...')$Plugin->ping_service_name)'note' );
  3198.                 $params array'Item' => $this'xmlrpcresp' => NULL'display' => false );
  3199.  
  3200.                 $r $Plugin->ItemSendPing$params );
  3201.  
  3202.                 ifisset($params['xmlrpcresp']&& is_a($params['xmlrpcresp']'xmlrpcresp') )
  3203.                 {
  3204.                     // dh> TODO: let xmlrpc_displayresult() handle $Messages (e.g. "error", but should be connected/after the "Pinging %s..." from above)
  3205.                     ob_start();
  3206.                     xmlrpc_displayresult$params['xmlrpcresp']true );
  3207.                     $Messages->addob_get_contents()'note' );
  3208.                     ob_end_clean();
  3209.                 }
  3210.             }
  3211.         }
  3212.     }
  3213.  
  3214.  
  3215.   /**
  3216.      * Callback user for footer()
  3217.      */
  3218.     function replace_callback$matches )
  3219.     {
  3220.         switch$matches[1)
  3221.         {
  3222.             case 'item_perm_url':
  3223.                 return $this->get_permanent_url();
  3224.  
  3225.             case 'item_title':
  3226.                 return $this->title;
  3227.  
  3228.             default:
  3229.                 return $matches[1];
  3230.         }
  3231.     }
  3232.  
  3233.     /**
  3234.      * Get a member param by its name
  3235.      *
  3236.      * @param mixed Name of parameter
  3237.      * @return mixed Value of parameter
  3238.      */
  3239.     function get$parname )
  3240.     {
  3241.         global $post_statuses;
  3242.  
  3243.         switch$parname )
  3244.         {
  3245.             case 't_author':
  3246.                 // Text: author
  3247.                 $this->get_creator_User();
  3248.                 return $this->creator_User->get'preferredname' );
  3249.  
  3250.             case 't_assigned_to':
  3251.                 // Text: assignee
  3252.                 if$this->get_assigned_User() )
  3253.                 {
  3254.                     return '';
  3255.                 }
  3256.                 return $this->assigned_User->get'preferredname' );
  3257.  
  3258.             case 't_status':
  3259.                 // Text status:
  3260.                 return T_$post_statuses[$this->status);
  3261.  
  3262.             case 't_extra_status':
  3263.                 $ItemStatusCache get_Cache'ItemStatusCache' );
  3264.                 if($Element $ItemStatusCache->get_by_ID$this->pst_IDtruefalse ) ) )
  3265.                 // No status:
  3266.                     return '';
  3267.                 }
  3268.                 return $Element->get_name();
  3269.  
  3270.             case 't_type':
  3271.                 // Item type (name):
  3272.                 ifempty($this->ptyp_ID) )
  3273.                 {
  3274.                     return '';
  3275.                 }
  3276.  
  3277.                 $ItemTypeCache get_Cache'ItemTypeCache' );
  3278.                 $type_Element $ItemTypeCache->get_by_ID$this->ptyp_ID );
  3279.                 return $type_Element->get_name();
  3280.  
  3281.             case 't_priority':
  3282.                 return $this->priorities$this->priority ];
  3283.  
  3284.             case 'pingsdone':
  3285.                 // Deprecated by fp 2006-08-21
  3286.                 return ($this->post_notifications_status == 'finished');
  3287.         }
  3288.  
  3289.         return parent::get$parname );
  3290.     }
  3291.  
  3292.  
  3293.     /**
  3294.      * Assign the item to the first category we find in the requested collection
  3295.      *
  3296.      * @param integer $collection_ID 
  3297.      */
  3298.     function assign_to_first_cat_for_collection$collection_ID )
  3299.     {
  3300.         global $DB;
  3301.  
  3302.         // Get the first category ID for the collection ID param
  3303.         $cat_ID $DB->get_var'
  3304.                 SELECT cat_ID
  3305.                     FROM T_categories
  3306.                  WHERE cat_blog_ID = '.$collection_ID.'
  3307.                  ORDER BY cat_ID ASC
  3308.                  LIMIT 1' );
  3309.  
  3310.         // Set to the item the first category we got
  3311.         $this->set'main_cat_ID'$cat_ID );
  3312.     }
  3313.  
  3314.  
  3315.     /**
  3316.      * Get the list of renderers for this Item.
  3317.      * @return array 
  3318.      */
  3319.     function get_renderers()
  3320.     {
  3321.         return explode'.'$this->renderers );
  3322.     }
  3323.  
  3324.  
  3325.     /**
  3326.      * Get the list of validated renderers for this Item. This includes stealth plugins etc.
  3327.      * @return array List of validated renderer codes
  3328.      */
  3329.     function get_renderers_validated()
  3330.     {
  3331.         ifisset($this->renderers_validated) )
  3332.         {
  3333.             $Plugins_admin get_Cache('Plugins_admin');
  3334.             $this->renderers_validated $Plugins_admin->validate_renderer_list$this->get_renderers() );
  3335.         }
  3336.         return $this->renderers_validated;
  3337.     }
  3338.  
  3339.  
  3340.     /**
  3341.      * Add a renderer (by code) to the Item.
  3342.      * @param string Renderer code to add for this item
  3343.      * @return boolean True if renderers have changed
  3344.      */
  3345.     function add_renderer$renderer_code )
  3346.     {
  3347.         $renderers $this->get_renderers();
  3348.         ifin_array$renderer_code$renderers ) )
  3349.         {
  3350.             return false;
  3351.         }
  3352.  
  3353.         $renderers[$renderer_code;
  3354.         $this->set_renderers$renderers );
  3355.  
  3356.         $this->renderers_validated NULL;
  3357.         //echo 'Added renderer '.$renderer_code;
  3358.     }
  3359.  
  3360.  
  3361.     /**
  3362.      * Remove a renderer (by code) from the Item.
  3363.      * @param string Renderer code to remove for this item
  3364.      * @return boolean True if renderers have changed
  3365.      */
  3366.     function remove_renderer$renderer_code )
  3367.     {
  3368.         $r false;
  3369.         $renderers $this->get_renderers();
  3370.         while( ( $key array_search$renderer_code$renderers ) ) !== false )
  3371.         {
  3372.             $r true;
  3373.             unset($renderers[$key]);
  3374.         }
  3375.  
  3376.         if$r )
  3377.         {
  3378.             $this->set_renderers$renderers );
  3379.             $this->renderers_validated NULL;
  3380.             //echo 'Removed renderer '.$renderer_code;
  3381.         }
  3382.         return $r;
  3383.     }
  3384. }
  3385.  
  3386.  
  3387. /*
  3388.  * $Log: _item.class.php,v $
  3389.  * Revision 1.32.2.8  2009/06/13 18:50:47  tblue246
  3390.  * [MFH] Item::set_tags_from_string(): Fixed SQL error in combination with umlauts (same umlaut, different case)
  3391.  *
  3392.  * Revision 1.32.2.7  2009/01/29 15:54:51  tblue246
  3393.  * Use 1 as the default post type ID when creating a new Item object. Fixes http://forums.b2evolution.net/viewtopic.php?t=17780 .
  3394.  *
  3395.  * Revision 1.32.2.6  2008/12/22 01:19:53  fplanque
  3396.  * minor
  3397.  *
  3398.  * Revision 1.32.2.5  2008/12/06 14:07:00  tblue246
  3399.  * RDF trackback autodiscovery: Display post title properly (reported by Austriaco, see http://forums.b2evolution.net/viewtopic.php?t=16205 ).
  3400.  *
  3401.  * Revision 1.32.2.4  2008/09/15 10:44:45  fplanque
  3402.  * MFH: skin cleanup
  3403.  *
  3404.  * Revision 1.32.2.3  2008/04/26 22:28:53  fplanque
  3405.  * MFH
  3406.  *
  3407.  * Revision 1.32.2.2  2008/04/12 19:34:03  fplanque
  3408.  * bugfix
  3409.  *
  3410.  * Revision 1.32.2.1  2008/02/18 20:23:20  fplanque
  3411.  * no message
  3412.  *
  3413.  * Revision 1.32  2008/01/23 12:51:20  fplanque
  3414.  * posts now have divs with IDs
  3415.  *
  3416.  * Revision 1.31  2008/01/21 09:35:31  fplanque
  3417.  * (c) 2008
  3418.  *
  3419.  * Revision 1.30  2008/01/20 18:20:26  fplanque
  3420.  * Antispam per group setting
  3421.  *
  3422.  * Revision 1.29  2008/01/19 15:45:28  fplanque
  3423.  * refactoring
  3424.  *
  3425.  * Revision 1.28  2008/01/18 15:53:42  fplanque
  3426.  * Ninja refactoring
  3427.  *
  3428.  * Revision 1.27  2008/01/17 14:38:30  fplanque
  3429.  * Item Footer template tag
  3430.  *
  3431.  * Revision 1.26  2008/01/14 07:22:07  fplanque
  3432.  * Refactoring
  3433.  *
  3434.  * Revision 1.25  2008/01/08 03:31:51  fplanque
  3435.  * podcast support
  3436.  *
  3437.  * Revision 1.24  2008/01/07 02:53:27  fplanque
  3438.  * cleaner tag urls
  3439.  *
  3440.  * Revision 1.23  2007/12/08 14:43:36  yabs
  3441.  * bugfix ( http://forums.b2evolution.net/viewtopic.php?t=13482 )
  3442.  *
  3443.  * Revision 1.22  2007/11/30 21:37:29  fplanque
  3444.  * removed empty tags
  3445.  *
  3446.  * Revision 1.21  2007/11/29 22:47:12  fplanque
  3447.  * tags everywhere + debug
  3448.  *
  3449.  * Revision 1.20  2007/11/29 20:53:45  fplanque
  3450.  * Fixed missing url link in basically all skins ...
  3451.  *
  3452.  * Revision 1.19  2007/11/25 14:28:17  fplanque
  3453.  * additional SEO settings
  3454.  *
  3455.  * Revision 1.18  2007/11/24 21:24:14  fplanque
  3456.  * display tags in backoffice
  3457.  *
  3458.  * Revision 1.17  2007/11/22 17:53:39  fplanque
  3459.  * filemanager display cleanup, especially in IE (not perfect)
  3460.  *
  3461.  * Revision 1.16  2007/11/15 23:45:41  blueyed
  3462.  * (Re-)Added phpdoc for get_edit_link
  3463.  *
  3464.  * Revision 1.15  2007/11/04 01:10:57  fplanque
  3465.  * skin cleanup continued
  3466.  *
  3467.  * Revision 1.14  2007/11/03 23:54:38  fplanque
  3468.  * skin cleanup continued
  3469.  *
  3470.  * Revision 1.13  2007/11/03 21:04:26  fplanque
  3471.  * skin cleanup
  3472.  *
  3473.  * Revision 1.12  2007/11/02 01:54:46  fplanque
  3474.  * comment ratings
  3475.  *
  3476.  * Revision 1.11  2007/09/13 19:16:14  fplanque
  3477.  * feedback_link() cleanup
  3478.  *
  3479.  * Revision 1.10  2007/09/13 02:37:22  fplanque
  3480.  * special cases
  3481.  *
  3482.  * Revision 1.9  2007/09/11 23:10:39  fplanque
  3483.  * translation updates
  3484.  *
  3485.  * Revision 1.8  2007/09/10 14:53:04  fplanque
  3486.  * cron fix
  3487.  *
  3488.  * Revision 1.7  2007/09/09 12:51:58  fplanque
  3489.  * cleanup
  3490.  *
  3491.  * Revision 1.6  2007/09/09 09:15:59  yabs
  3492.  * validation
  3493.  *
  3494.  * Revision 1.5  2007/09/08 19:31:28  fplanque
  3495.  * cleanup of XML feeds for comments on individual posts.
  3496.  *
  3497.  * Revision 1.4  2007/09/04 22:16:33  fplanque
  3498.  * in context editing of posts
  3499.  *
  3500.  * Revision 1.3  2007/08/28 02:43:40  waltercruz
  3501.  * Template function to get the rss link to the feeds of the comments on each post
  3502.  *
  3503.  * Revision 1.2  2007/07/03 23:21:32  blueyed
  3504.  * Fixed includes/requires in/for tests
  3505.  *
  3506.  * Revision 1.1  2007/06/25 11:00:24  fplanque
  3507.  * MODULES (refactored MVC)
  3508.  *
  3509.  * Revision 1.184  2007/06/24 22:26:34  fplanque
  3510.  * improved feedback template
  3511.  *
  3512.  * Revision 1.183  2007/06/21 00:44:37  fplanque
  3513.  * linkblog now a widget
  3514.  *
  3515.  * Revision 1.182  2007/06/20 21:42:13  fplanque
  3516.  * implemented working widget/plugin params
  3517.  *
  3518.  * Revision 1.180  2007/06/18 20:59:55  fplanque
  3519.  * do not display link to comments if comments are disabled
  3520.  *
  3521.  * Revision 1.179  2007/06/13 23:29:02  fplanque
  3522.  * minor
  3523.  *
  3524.  * Revision 1.178  2007/06/11 01:55:57  fplanque
  3525.  * level based user permissions
  3526.  *
  3527.  * Revision 1.177  2007/05/28 15:18:30  fplanque
  3528.  * cleanup
  3529.  *
  3530.  * Revision 1.176  2007/05/28 01:33:22  fplanque
  3531.  * permissions/fixes
  3532.  *
  3533.  * Revision 1.175  2007/05/27 00:35:26  fplanque
  3534.  * tag display + tag filtering
  3535.  *
  3536.  * Revision 1.174  2007/05/20 01:01:35  fplanque
  3537.  * make trackback silent when it should be
  3538.  *
  3539.  * Revision 1.173  2007/05/14 02:47:23  fplanque
  3540.  * (not so) basic Tags framework
  3541.  *
  3542.  * Revision 1.172  2007/05/13 22:02:07  fplanque
  3543.  * removed bloated $object_def
  3544.  *
  3545.  * Revision 1.171  2007/04/26 00:11:11  fplanque
  3546.  * (c) 2007
  3547.  *
  3548.  * Revision 1.170  2007/04/15 13:34:36  blueyed
  3549.  * Fixed default $url generation in page_links()
  3550.  *
  3551.  * Revision 1.169  2007/04/05 22:57:33  fplanque
  3552.  * Added hook: UnfilterItemContents
  3553.  *
  3554.  * Revision 1.168  2007/03/31 22:46:46  fplanque
  3555.  * FilterItemContent event
  3556.  *
  3557.  * Revision 1.167  2007/03/26 12:59:18  fplanque
  3558.  * basic pages support
  3559.  *
  3560.  * Revision 1.166  2007/03/25 10:19:30  fplanque
  3561.  * cleanup
  3562.  *
  3563.  * Revision 1.165  2007/03/24 20:41:16  fplanque
  3564.  * Refactored a lot of the link junk.
  3565.  * Made options blog specific.
  3566.  * Some junk still needs to be cleaned out. Will do asap.
  3567.  *
  3568.  * Revision 1.164  2007/03/19 23:59:32  fplanque
  3569.  * minor
  3570.  *
  3571.  * Revision 1.163  2007/03/18 03:43:19  fplanque
  3572.  * EXPERIMENTAL
  3573.  * Splitting Item/ItemLight and ItemList/ItemListLight
  3574.  * Goal: Handle Items with less footprint than with their full content
  3575.  * (will be even worse with multiple languages/revisions per Item)
  3576.  *
  3577.  * Revision 1.162  2007/03/11 23:57:07  fplanque
  3578.  * item editing: allow setting to 'redirected' status
  3579.  *
  3580.  * Revision 1.161  2007/03/06 12:18:08  fplanque
  3581.  * got rid of dirty Item::content()
  3582.  * Advantage: the more link is now independant. it can be put werever people want it
  3583.  *
  3584.  * Revision 1.160  2007/03/05 04:52:42  fplanque
  3585.  * better precision for viewcounts
  3586.  *
  3587.  * Revision 1.159  2007/03/05 04:49:17  fplanque
  3588.  * better precision for viewcounts
  3589.  *
  3590.  * Revision 1.158  2007/03/05 02:13:26  fplanque
  3591.  * improved dashboard
  3592.  *
  3593.  * Revision 1.157  2007/03/05 01:47:50  fplanque
  3594.  * splitting up Item::content() - proof of concept.
  3595.  * needs to be optimized.
  3596.  *
  3597.  * Revision 1.156  2007/03/03 01:14:11  fplanque
  3598.  * new methods for navigating through posts in single item display mode
  3599.  *
  3600.  * Revision 1.155  2007/03/02 04:40:38  fplanque
  3601.  * fixed/commented a lot of stuff with the feeds
  3602.  *
  3603.  * Revision 1.154  2007/03/02 03:09:12  fplanque
  3604.  * rss length doesn't make sense since it doesn't apply to html format anyway.
  3605.  * clean solutionwould be to handle an "excerpt" field separately
  3606.  *
  3607.  * Revision 1.153  2007/02/23 19:16:07  blueyed
  3608.  * MFB: Fixed handling of Item::content for pre-rendering (it gets passed by reference!)
  3609.  *
  3610.  * Revision 1.152  2007/02/18 22:51:26  waltercruz
  3611.  * Fixing a little confusion with quotes and string concatenation
  3612.  *
  3613.  * Revision 1.151  2007/02/08 03:45:40  waltercruz
  3614.  * Changing double quotes to single quotes
  3615.  *
  3616.  * Revision 1.150  2007/02/05 13:32:49  waltercruz
  3617.  * Changing double quotes to single quotes
  3618.  *
  3619.  * Revision 1.149  2007/01/26 04:52:53  fplanque
  3620.  * clean comment popups (skins 2.0)
  3621.  *
  3622.  * Revision 1.148  2007/01/26 02:12:06  fplanque
  3623.  * cleaner popup windows
  3624.  *
  3625.  * Revision 1.147  2007/01/23 03:46:24  fplanque
  3626.  * cleaned up presentation
  3627.  *
  3628.  * Revision 1.146  2007/01/19 10:45:42  fplanque
  3629.  * images everywhere :D
  3630.  * At this point the photoblogging code can be considered operational.
  3631.  *
  3632.  * Revision 1.145  2007/01/11 19:29:50  blueyed
  3633.  * Fixed E_NOTICE when using the "excerpt" feature
  3634.  *
  3635.  * Revision 1.144  2006/12/26 00:08:29  fplanque
  3636.  * wording
  3637.  *
  3638.  * Revision 1.143  2006/12/21 22:35:28  fplanque
  3639.  * No regression. But a change in usage. The more link must be configured in the skin.
  3640.  * Renderers cannot side-effect on the more tag any more and that actually makes the whole thing safer.
  3641.  *
  3642.  * Revision 1.142  2006/12/20 13:57:34  blueyed
  3643.  * TODO about regression because of pre-rendering and the <!--more--> tag
  3644.  *
  3645.  * Revision 1.141  2006/12/18 13:31:12  fplanque
  3646.  * fixed broken more tag
  3647.  *
  3648.  * Revision 1.140  2006/12/16 01:30:46  fplanque
  3649.  * Setting to allow/disable email subscriptions on a per blog basis
  3650.  *
  3651.  * Revision 1.139  2006/12/15 22:59:05  fplanque
  3652.  * doc
  3653.  *
  3654.  * Revision 1.138  2006/12/14 22:26:31  blueyed
  3655.  * Fixed E_NOTICE and displaying of pings into $Messages (though "hackish")
  3656.  *
  3657.  * Revision 1.137  2006/12/12 02:53:56  fplanque
  3658.  * Activated new item/comments controllers + new editing navigation
  3659.  * Some things are unfinished yet. Other things may need more testing.
  3660.  *
  3661.  * Revision 1.136  2006/12/07 23:13:11  fplanque
  3662.  * @var needs to have only one argument: the variable type
  3663.  * Otherwise, I can't code!
  3664.  *
  3665.  * Revision 1.135  2006/12/06 23:55:53  fplanque
  3666.  * hidden the dead body of the sidebar plugin + doc
  3667.  *
  3668.  * Revision 1.134  2006/12/05 14:28:29  blueyed
  3669.  * Fixed wordcount==0 handling; has been saved as NULL
  3670.  *
  3671.  * Revision 1.133  2006/12/05 06:38:40  blueyed
  3672.  * doc
  3673.  *
  3674.  * Revision 1.132  2006/12/05 00:39:56  fplanque
  3675.  * fixed some more permalinks/archive links
  3676.  *
  3677.  * Revision 1.131  2006/12/05 00:34:39  blueyed
  3678.  * Implemented custom "None" option text in DataObjectCache; Added for $ItemStatusCache, $GroupCache, UserCache and BlogCache; Added custom text for Item::priority_options()
  3679.  *
  3680.  * Revision 1.130  2006/12/04 20:52:40  blueyed
  3681.  * typo
  3682.  *
  3683.  * Revision 1.129  2006/12/04 19:57:58  fplanque
  3684.  * How often must I fix the weekly archives until they stop bugging me?
  3685.  *
  3686.  * Revision 1.128  2006/12/04 19:41:11  fplanque
  3687.  * Each blog can now have its own "archive mode" settings
  3688.  *
  3689.  * Revision 1.127  2006/12/03 18:15:32  fplanque
  3690.  * doc
  3691.  *
  3692.  * Revision 1.126  2006/12/01 20:04:31  blueyed
  3693.  * Renamed Plugins_admin::validate_list() to validate_renderer_list()
  3694.  *
  3695.  * Revision 1.125  2006/12/01 19:46:42  blueyed
  3696.  * Moved Plugins::validate_list() to Plugins_admin class; added stub in Plugins, because at least the starrating_plugin uses it
  3697.  *
  3698.  * Revision 1.124  2006/11/28 20:04:11  blueyed
  3699.  * No edit link, if ID==0 to avoid confusion in preview, see http://forums.b2evolution.net/viewtopic.php?p=47422#47422
  3700.  *
  3701.  * Revision 1.123  2006/11/24 18:27:24  blueyed
  3702.  * Fixed link to b2evo CVS browsing interface in file docblocks
  3703.  *
  3704.  * Revision 1.122  2006/11/22 20:48:58  blueyed
  3705.  * Added Item::get_Chapters() and Item::get_main_Chapter(); refactorized
  3706.  *
  3707.  * Revision 1.121  2006/11/22 20:12:18  blueyed
  3708.  * Use $format param in Item::categories()
  3709.  *
  3710.  * Revision 1.120  2006/11/19 22:17:42  fplanque
  3711.  * minor / doc
  3712.  *
  3713.  * Revision 1.119  2006/11/19 16:07:31  blueyed
  3714.  * Fixed saving empty renderers list. This should also fix the saving of "default" instead of the explicit renderer list
  3715.  *
  3716.  * Revision 1.118  2006/11/17 18:36:23  blueyed
  3717.  * dbchanges param for AfterItemUpdate, AfterItemInsert, AfterCommentUpdate and AfterCommentInsert
  3718.  *
  3719.  * Revision 1.117  2006/11/13 20:49:52  fplanque
  3720.  * doc/cleanup :/
  3721.  *
  3722.  * Revision 1.116  2006/11/10 20:14:11  blueyed
  3723.  * doc, fix
  3724.  *
  3725.  * Revision 1.115  2006/11/02 16:12:49  blueyed
  3726.  * MFB
  3727.  *
  3728.  * Revision 1.114  2006/11/02 16:01:00  blueyed
  3729.  * doc
  3730.  *
  3731.  * Revision 1.113  2006/10/29 18:33:23  blueyed
  3732.  * doc fix
  3733.  *
  3734.  * Revision 1.112  2006/10/23 22:19:02  blueyed
  3735.  * Fixed/unified encoding of redirect_to param. Use just rawurlencode() and no funky &amp; replacements
  3736.  *
  3737.  * Revision 1.111  2006/10/18 00:03:51  blueyed
  3738.  * Some forgotten url_rel_to_same_host() additions
  3739.  */
  3740. ?>

Documentation generated on Sat, 06 Mar 2010 03:35:27 +0100 by phpDocumentor 1.4.2. This site is hosted and maintained by Daniel HAHLER (Contact).