Looks like the Search API function setComment() is not required after all (cf. bug #0000902)
3 /* Reminder: always indent with 4 spaces (no tabs). */
4 // +---------------------------------------------------------------------------+
6 // +---------------------------------------------------------------------------+
9 // | This file implements plugin support in Geeklog. |
10 // +---------------------------------------------------------------------------+
11 // | Copyright (C) 2000-2009 by the following authors: |
13 // | Authors: Tony Bibbs - tony AT tonybibbs DOT com |
14 // | Blaine Lang - blaine AT portalparts DOT com |
15 // | Dirk Haun - dirk AT haun-online DOT de |
16 // +---------------------------------------------------------------------------+
18 // | This program is free software; you can redistribute it and/or |
19 // | modify it under the terms of the GNU General Public License |
20 // | as published by the Free Software Foundation; either version 2 |
21 // | of the License, or (at your option) any later version. |
23 // | This program is distributed in the hope that it will be useful, |
24 // | but WITHOUT ANY WARRANTY; without even the implied warranty of |
25 // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
26 // | GNU General Public License for more details. |
28 // | You should have received a copy of the GNU General Public License |
29 // | along with this program; if not, write to the Free Software Foundation, |
30 // | Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
32 // +---------------------------------------------------------------------------+
35 * This is the plugin library for Geeklog. This is the API that plugins can
36 * implement to get tight integration with Geeklog.
37 * See each function for more details.
38 * @link http://wiki.geeklog.net/index.php/Plugin_API
42 if (strpos(strtolower($_SERVER['PHP_SELF']), 'lib-plugins.php') !== false) {
43 die('This file can not be used on its own!');
47 * Include plugin class
49 require_once $_CONF['path_system'] . 'classes/plugin.class.php';
52 * Response codes for the service invocation PLG_invokeService(). Note that
53 * these are intentionally vague so as not to give away too much information.
55 define('PLG_RET_OK', 0); // success
56 define('PLG_RET_ERROR', -1); // generic error
57 define('PLG_RET_PERMISSION_DENIED', -2); // access to item or object denied
58 define('PLG_RET_AUTH_FAILED', -3); // authentication failed
59 define('PLG_RET_PRECONDITION_FAILED', -4); // a precondition was not met
61 // buffer for function names for the center block API
62 $PLG_bufferCenterAPI = array();
63 $PLG_buffered = false;
65 // buffer enabled plugins
66 $result = DB_query("SELECT pi_name FROM {$_TABLES['plugins']} WHERE pi_enabled = 1");
68 * @global array List of all active plugins
71 while ($A = DB_fetchArray($result)) {
72 $_PLUGINS[] = $A['pi_name'];
76 * Calls a function for all enabled plugins
78 * @param string $function_name holds name of function to call
81 * @internal not to be used by plugins
82 * @todo only supports functions without any parameters
85 function PLG_callFunctionForAllPlugins($function_name)
89 foreach ($_PLUGINS as $pi_name) {
90 $function = 'plugin_' . $function_name . '_' . $pi_name;
91 if (function_exists($function)) {
95 $function = 'CUSTOM_' . $function_name;
96 if (function_exists($function)) {
102 * Calls a function for a single plugin
104 * This is a generic function used by some of the other API functions to
105 * call a function for a specific plugin and, optionally pass parameters.
106 * This function can handle up to 5 arguments and if more exist it will
107 * try to pass the entire args array to the function.
109 * @param string $function holds name of function to call
110 * @param array $args arguments to send to function
111 * @return mixed returns result of function call, otherwise false
113 * @internal not to be used by plugins
116 function PLG_callFunctionForOnePlugin($function, $args='')
118 if (function_exists($function)) {
123 // great, function exists, run it
124 switch (count($args)) {
129 return $function($args[1]);
132 return $function($args[1], $args[2]);
135 return $function($args[1], $args[2], $args[3]);
138 return $function($args[1], $args[2], $args[3], $args[4]);
141 return $function($args[1], $args[2], $args[3], $args[4], $args[5]);
144 return $function($args[1], $args[2], $args[3], $args[4], $args[5], $args[6]);
147 return $function($args[1], $args[2], $args[3], $args[4], $args[5], $args[6], $args[7]);
150 return $function($args);
159 * Tells a plugin to install itself. NOTE: not currently used any more
161 * @param string $type Plugin name
162 * @return boolean Returns true on success otherwise false
163 * @deprecated deprecated since Geeklog 1.6.0
164 * @link http://wiki.geeklog.net/index.php/Plugin_Autoinstall
167 function PLG_install($type)
169 return PLG_callFunctionForOnePlugin('plugin_install_' . $type);
173 * Upgrades a plugin. Tells a plugin to upgrade itself.
175 * @param string $type Plugin name
176 * @return mixed true on success, false or error number on failure
179 function PLG_upgrade($type)
181 return PLG_callFunctionForOnePlugin('plugin_upgrade_' . $type);
185 * Called during site migration - let plugin handle changed URLs or paths
187 * @param string $type Plugin name
188 * @param array $old_conf contents of $_CONF before the migration
189 * @return boolean true on success, otherwise false
190 * @link http://wiki.geeklog.net/index.php/PLG_migrate
191 * @since Geeklog 1.6.0
194 function PLG_migrate($type, $old_conf)
196 if (! function_exists('plugin_migrate_' . $type)) {
197 // since PLG_callFunctionForOnePlugin would return false ...
201 $args[1] = $old_conf;
203 return PLG_callFunctionForOnePlugin('plugin_migrate_' . $type, $args);
207 * Calls the plugin function to return the current version of code.
208 * Used to indicate to admin if an update or upgrade is required.
210 * @param string $type Plugin name
211 * @return boolean Returns true on success otherwise false
214 function PLG_chkVersion($type)
216 return PLG_callFunctionForOnePlugin('plugin_chkVersion_' . $type);
220 * Tells a plugin to uninstall itself.
222 * @param string $type Plugin to uninstall
223 * @return boolean Returns true on success otherwise false
224 * @link http://wiki.geeklog.net/index.php/Plugin_Auto-Uninstall
227 function PLG_uninstall($type)
229 global $_PLUGINS, $_TABLES;
235 if (function_exists('plugin_autouninstall_' . $type)) {
236 COM_errorLog ("Auto-uninstalling plugin $type:", 1);
237 $function = 'plugin_autouninstall_' . $type;
238 $remvars = $function();
240 if (empty($remvars) || $remvars == false) {
245 $num_tables = count($remvars['tables']);
246 for ($i = 0; $i < $num_tables; $i++) {
247 if (isset($_TABLES[$remvars['tables'][$i]])) {
248 COM_errorLog("Dropping table {$_TABLES[$remvars['tables'][$i]]}", 1);
249 DB_query("DROP TABLE {$_TABLES[$remvars['tables'][$i]]}", 1);
250 COM_errorLog('...success', 1);
254 // removing variables
255 $num_vars = count($remvars['vars']);
256 for ($i = 0; $i < $num_vars; $i++) {
257 COM_errorLog ("Removing variable {$remvars['vars'][$i]}", 1);
258 DB_delete($_TABLES['vars'], 'name', $remvars['vars'][$i]);
259 COM_errorLog ('...success', 1);
263 $num_groups = count($remvars['groups']);
264 for ($i = 0; $i < $num_groups; $i++) {
265 $grp_id = DB_getItem ($_TABLES['groups'], 'grp_id',
266 "grp_name = '{$remvars['groups'][$i]}'");
267 if (!empty($grp_id)) {
268 COM_errorLog ("Attempting to remove the {$remvars['groups'][$i]} group", 1);
269 DB_delete($_TABLES['groups'], 'grp_id', $grp_id);
270 COM_errorLog ('...success', 1);
271 COM_errorLog ("Attempting to remove the {$remvars['groups'][$i]} group from all groups.", 1);
272 DB_delete($_TABLES['group_assignments'], 'ug_main_grp_id', $grp_id);
273 COM_errorLog ('...success', 1);
278 $num_features = count($remvars['features']);
279 for ($i = 0; $i < $num_features; $i++) {
280 SEC_removeFeatureFromDB($remvars['features'][$i]);
284 $sql = "SELECT filename FROM {$_TABLES['syndication']} WHERE type = '$type';";
285 $result = DB_query( $sql );
286 $nrows = DB_numRows( $result );
288 COM_errorLog ('removing feed files', 1);
289 COM_errorLog ($nrows. ' files stored in table.', 1);
290 for ( $i = 0; $i < $nrows; $i++ ) {
292 $A = DB_fetchArray( $result );
293 $fullpath = SYND_getFeedPath( $A[0] );
294 if ( file_exists( $fullpath ) ) {
296 COM_errorLog ("removed file $fcount of $nrows: $fullpath", 1);
298 COM_errorLog ("cannot remove file $fcount of $nrows, it does not exist! ($fullpath)", 1);
301 COM_errorLog ('...success', 1);
302 // Remove Links Feeds from syndiaction table
303 COM_errorLog ('removing links feeds from table', 1);
304 DB_delete($_TABLES['syndication'], 'type', $type);
305 COM_errorLog ('...success', 1);
308 // remove comments for this plugin
309 COM_errorLog ("Attempting to remove comments for $type", 1);
310 DB_delete($_TABLES['comments'], 'type', $type);
311 COM_errorLog ('...success', 1);
313 // uninstall php-blocks
314 $num_blocks = count($remvars['php_blocks']);
315 for ($i = 0; $i < $num_blocks; $i++) {
316 DB_delete($_TABLES['blocks'], array('type', 'phpblockfn'),
317 array('phpblock', $remvars['php_blocks'][$i]));
320 // remove config table data for this plugin
321 COM_errorLog ("Attempting to remove config table records for group_name: $type", 1);
322 DB_delete($_TABLES['conf_values'], 'group_name', $type);
323 COM_errorLog ('...success', 1);
325 // uninstall the plugin
326 COM_errorLog ("Attempting to unregister the $type plugin from Geeklog", 1);
327 DB_delete($_TABLES['plugins'], 'pi_name', $type);
328 COM_errorLog ('...success',1);
330 COM_errorLog ("Finished uninstalling the $type plugin.", 1);
335 $retval = PLG_callFunctionForOnePlugin ('plugin_uninstall_' . $type);
337 if ($retval === true) {
338 $plg = array_search ($type, $_PLUGINS);
339 if ($plg !== false) {
340 unset ($_PLUGINS[$plg]);
352 * Inform plugin that it is either being enabled or disabled.
354 * @param string $type Plugin name
355 * @param boolean $enable true if enabling, false if disabling
356 * @return boolean Returns true on success otherwise false
357 * @see PLG_pluginStateChange
360 function PLG_enableStateChange($type, $enable)
362 global $_CONF, $_TABLES, $_DB_table_prefix;
366 // IF we are enabling the plugin
367 // THEN we must include its functions.inc so we have access to the function
369 require_once ($_CONF['path'] . 'plugins/' . $type . '/functions.inc');
372 return PLG_callFunctionForOnePlugin ('plugin_enablestatechange_' . $type,
377 * Checks to see if user is a plugin moderator
379 * Geeklog is asking if the user is a moderator for any installed plugins.
381 * @return boolean True if current user is moderator of plugin otherwise false
384 function PLG_isModerator()
386 return PLG_callFunctionForAllPlugins('ismoderator');
390 * Gives plugins a chance to print their menu items in header
392 * Note that this is fairly unflexible. This simply loops through the plugins
393 * in the database in the order they were installed and get their menu items.
394 * If you want more flexibility in your menu then you should hard code the menu
395 * items in header.thtml for the theme(s) you are using.
397 * @return array Returns menu options for plugin
400 function PLG_getMenuItems()
405 foreach ($_PLUGINS as $pi_name) {
406 $function = 'plugin_getmenuitems_' . $pi_name;
407 if (function_exists($function)) {
408 $menuitems = $function();
409 if (is_array($menuitems)) {
410 $menu = array_merge ($menu, $menuitems);
419 * Get view URL and name of unique identifier
421 * @author Vincent Furia, vinny01 AT users DOT sourceforge DOT net
422 * @param string $type Plugin to delete comment
423 * @return array string of URL of view page, name of unique identifier
425 function PLG_getCommentUrlId($type)
429 $ret = PLG_callFunctionForOnePlugin('plugin_getcommenturlid_' . $type);
430 if (empty($ret[0])) {
431 $ret[0] = $_CONF['site_url'] . "/$type/index.php";
433 if (empty($ret[1])) {
441 * Plugin should delete a comment
443 * @author Vincent Furia, vinny01 AT users DOT sourceforge DOT net
444 * @param string $type Plugin to delete comment
445 * @param int $cid Comment to be deleted
446 * @param string $id Item id to which $cid belongs
447 * @return mixed false for failure, HTML string (redirect?) for success
449 function PLG_commentDelete($type, $cid, $id)
454 return PLG_callFunctionForOnePlugin('plugin_deletecomment_' . $type, $args);
458 * Plugin should save a comment
460 * @author Vincent Furia, vinny01 AT users DOT sourceforge DOT net
461 * @param string $type Plugin to delete comment
462 * @param string $title comment title
463 * @param string $comment comment text
464 * @param string $id Item id to which $cid belongs
465 * @param int $pid comment parent
466 * @param string $postmode 'html' or 'text'
467 * @return mixed false for failure, HTML string (redirect?) for success
469 function PLG_commentSave($type, $title, $comment, $id, $pid, $postmode)
475 $args[5] = $postmode;
477 return PLG_callFunctionForOnePlugin('plugin_savecomment_' . $type, $args);
481 * Plugin should display [a] comment[s]
483 * @author Vincent Furia, vinny01 AT users DOT sourceforge DOT net
484 * @param string $type Plugin to display comment
485 * @param string $id Unique idenifier for item comment belongs to
486 * @param int $cid Comment id to display (possibly including sub-comments)
487 * @param string $title Page/comment title
488 * @param string $order 'ASC' or 'DSC' or blank
489 * @param string $format 'threaded', 'nested', or 'flat'
490 * @param int $page Page number of comments to display
491 * @param boolean $view True to view comment (by cid), false to display (by $pid)
492 * @return mixed results of calling the plugin_displaycomment_ function
494 function PLG_displayComment($type, $id, $cid, $title, $order, $format, $page, $view)
504 return PLG_callFunctionForOnePlugin('plugin_displaycomment_' . $type, $args);
508 * Allows plugins a chance to handle a comment before Geeklog does.
510 * This is a first-come-first-serve affair so if a plugin returns an error, other
511 * plugins wishing to handle comment preprocessing won't get called
513 * @author Tony Bibbs, tony AT tonybibbs DOT com
515 * @param int $uid User ID
516 * @param string &$title Comment title
517 * @param string &$comment Comment text
518 * @param string $sid Story ID (not always a story, remember!)
519 * @param int $pid Parent comment ID
520 * @param string $type Type of comment
521 * @param string &$postmode HTML or text
522 * @return mixed an error otherwise false if no errors were encountered
523 * @see PLG_itemPreSave
526 function PLG_commentPreSave($uid, &$title, &$comment, $sid, $pid, $type, &$postmode)
530 foreach ($_PLUGINS as $pi_name) {
531 $function = 'plugin_commentPreSave_' . $pi_name;
532 if (function_exists($function)) {
533 $someError = $function($uid, $title, $comment, $sid, $pid, $type, $postmode);
535 // Plugin doesn't want to save the comment
541 $function = 'CUSTOM_commentPreSave';
542 if (function_exists($function)) {
543 $someError = $function($uid, $title, $comment, $sid, $pid, $type, $postmode);
545 // Custom function refused save:
554 * Allows plugins a chance to handle an item before Geeklog does. Modeled
555 * after the PLG_commentPreSave() function.
557 * This is a first-come-first-serve affair so if a plugin returns an error, other
558 * plugins wishing to handle comment preprocessing won't get called
560 * @author Mark Evans, mevans AT ecsnet DOT com
562 * @param string $type Type of item, i.e.; registration, contact ...
563 * @param string $content item specific content
564 * @return string empty is no error, error message if error was encountered
565 * @see PLG_commentPreSave
568 function PLG_itemPreSave($type, $content)
572 foreach ($_PLUGINS as $pi_name) {
573 $function = 'plugin_itemPreSave_' . $pi_name;
574 if (function_exists ($function)) {
575 $msgError = $function ($type, $content);
576 if (!empty($msgError)) {
577 // Plugin doesn't want to save the item
583 $function = 'CUSTOM_itemPreSave';
584 if (function_exists ($function)) {
585 $msgError = $function ($type, $content);
586 if (!empty($msgError)) {
587 // Custom doesn't want to save the item
596 * The way this function works is very specific to how Geeklog shows its
597 * statistics. On stats.php, there is the top box which gives overall
598 * statistics for Geeklog and then there are blocks below it that give
599 * more specific statistics for various components of Geeklog.
601 * This plugin API function suffers from a variety of bugs and bad design
602 * decisions for which we have to provide backward compatibility, so please
605 * The only parameter to this function, $showsitestats, was documented as being
606 * being 1 for the site stats and 0 for the plugin-specific stats. However, the
607 * latter was always called with a value of 2, so plugins only did a check for 1
608 * and "else", which makes extensions somewhat tricky.
609 * Furthermore, due to the original templates for the site stats, it has
610 * become standard practice to hard-code a <table> in the plugins as the return
611 * value for $showsitestats == 1. This table, however, didn't align properly
612 * with the built-in site stats entries.
614 * Because of all this, the new mode, 3, works differently:
615 * - for $showsitestats == 3, we call a new plugin API function,
616 * plugin_statssummary_<plugin-name>, which is supposed to return the plugin's
617 * entry for the site stats in an array which stats.php will then properly
618 * format, alongside the entries for the built-in items.
619 * - for $showsitestats == 1, we only call those plugins that do NOT have a
620 * plugin_statssummary_<plugin-name> function, thus providing backward
622 * - for $showsitestats == 2, nothing has changed
624 * @param int $showsitestats value indicating type of stats to return
625 * @return mixed array (for mode 3) or string
628 function PLG_getPluginStats($showsitestats)
632 if ($showsitestats == 3) {
638 foreach ($_PLUGINS as $pi_name) {
639 if ($showsitestats == 3) {
640 $function = 'plugin_statssummary_' . $pi_name;
641 if (function_exists ($function)) {
642 $summary = $function ();
643 if (is_array($summary)) {
644 $retval[$pi_name] = $summary;
647 } elseif ($showsitestats == 1) {
648 $function1 = 'plugin_showstats_' . $pi_name;
649 $function2 = 'plugin_statssummary_' . $pi_name;
650 if (!function_exists ($function2)) {
651 if (function_exists ($function1)) {
652 $retval .= $function1 ($showsitestats);
655 } elseif ($showsitestats == 2) {
656 $function = 'plugin_showstats_' . $pi_name;
657 if (function_exists ($function)) {
658 $retval .= $function ($showsitestats);
663 if ($showsitestats == 3) {
664 $function = 'CUSTOM_statssummary';
665 if (function_exists ($function)) {
666 $summary = $function ();
667 if (is_array($summary)) {
668 $retval['Custom'] = $summary;
671 } elseif ($showsitestats == 1) {
672 $function1 = 'CUSTOM_showstats';
673 $function2 = 'CUSTOM_statssummary';
674 if (!function_exists ($function2)) {
675 if (function_exists ($function1)) {
676 $retval .= $function1 ($showsitestats);
679 } elseif ($showsitestats == 2) {
680 $function = 'CUSTOM_showstats';
681 if (function_exists ($function)) {
682 $retval .= $function ($showsitestats);
690 * This function gives each plugin the opportunity to put a value(s) in
691 * the 'Type' drop down box on the search.php page so that their plugin
692 * can be incorporated into searches.
694 * @return array String array of search types for plugin(s)
697 function PLG_getSearchTypes()
702 $cur_types = array();
704 foreach ($_PLUGINS as $pi_name) {
705 $function = 'plugin_searchtypes_' . $pi_name;
706 if (function_exists ($function)) {
707 $cur_types = $function ();
708 if (is_array($cur_types) && (count($cur_types) > 0)) {
709 $types = array_merge ($types, $cur_types);
711 } // no else because this is not a required API function
714 $function = 'CUSTOM_searchtypes';
715 if (function_exists ($function)) {
716 $cur_types = $function ();
717 if (is_array($cur_types) && (count($cur_types) > 0)) {
718 $types = array_merge ($types, $cur_types);
727 * Determines if a specific plugin supports Geeklog's
728 * expanded search results feature
730 * NOTE: This function is not currently used
732 * @author Tony Bibbs, tony AT tonybibbs DOT com
734 * @param string $type Plugin name
735 * @return boolean True if it is supported, otherwise false
736 * @deprecated no longer used
739 function PLG_supportsExpandedSearch($type)
742 $function = 'plugin_supportsexpandedsearch_' . $type;
743 if (function_exists($function)) {
744 $retval = $function();
746 if (empty($retval) OR !is_bool($retval)) {
754 * This function gives each plugin the opportunity to do their search
755 * and return their results. Results come back in an array of HTML
756 * formatted table rows that can be quickly printed by search.php
758 * @param string $query What the user searched for
759 * @param date $datestart beginning of date range to search for
760 * @param date $dateend ending date range to search for
761 * @param string $topic the topic the user searched within
762 * @param string $type Type of items they are searching, or 'all'
763 * @param int $author UID...only return results for this person
764 * @param string $keyType search key type: 'all', 'phrase', 'any'
765 * @param int $page page number of current search (deprecated)
766 * @param int $perpage number of results per page (deprecated)
767 * @return array Returns search results
770 function PLG_doSearch($query, $datestart, $dateend, $topic, $type, $author, $keyType = 'all', $page = 1, $perpage = 10)
775 * The API, as of 1.6.0, does not use $page, $perpage
776 * $type is now only used in the core and should not be passed to the plugin
779 $search_results = array();
781 foreach ($_PLUGINS as $pi_name) {
782 $function = 'plugin_dopluginsearch_' . $pi_name;
783 if (function_exists($function)) {
784 $result = $function($query, $datestart, $dateend, $topic, $type, $author, $keyType, $page, $perpage);
785 if (is_array($result)) {
786 $search_results = array_merge($search_results, $result);
788 $search_results[] = $result;
791 // no else because implementation of this API function not required
794 $function = 'CUSTOM_dopluginsearch';
795 if (function_exists($function)) {
796 $search_results[] = $function($query, $datestart, $dateend, $topic, $type, $author, $keyType, $page, $perpage);
799 return $search_results;
803 * Asks each plugin to report any submissions they may have in their
806 * @return int Number of submissions in queue for plugins
809 function PLG_getSubmissionCount()
814 foreach ($_PLUGINS as $pi_name) {
815 $function = 'plugin_submissioncount_' . $pi_name;
816 if (function_exists($function)) {
817 $num = $num + $function();
825 * This function will get & check user or admin options from plugins and check
826 * required ones for availability. This function is called by several other
827 * functions and is not to be called from the plugin directly. The function which
828 * call this here follow below.
830 * NOTE for plugin developers:
831 * The plugin is responsible for its own security.
832 * This supports a plugin having either a single menuitem or multiple menuitems.
833 * The plugin has to provide an array for the menuitem of the format:
835 * array(menuitem_title, item_url, submission_count)
837 * or an array of arrays in case there are several entries:
840 * array(menuitem1_title, item1_url, submission1_count),
841 * array(menuitem2_title, item2_url, submission2_count),
842 * array(menuitem3_title, item3_url, submission3_count))
844 * Plugin function can return a single record array or multiple records
847 * @param array $var_names An array of the variables that are retrieved.
848 * This has to match the named array that is used
849 * in the function returning the values
850 * @param array $required_names An array of true/false-values, describing
851 * which of the above listed values is required
852 * to give a valid set of data.
853 * @param string $function_name A string that gives the name of the function
854 * at the plugin that will return the values.
855 * @return array Returns options to add to the given menu that is calling this
857 * @internal not to be used by plugins
860 function PLGINT_getOptionsforMenus($var_names, $required_names, $function_name)
864 $plgresults = array();
866 $num_var_names = count($var_names);
867 foreach ($_PLUGINS as $pi_name) {
868 $function = $function_name . $pi_name;
869 if (function_exists($function)) {
870 $plg_array = $function();
871 if (($plg_array !== false) && (count($plg_array) > 0)) {
872 // Check if plugin is returning a single record array or multiple records
873 $sets_array = array();
874 $entries = count($plg_array[0]);
876 // Single record - so we need to prepare the sets_array;
877 $sets_array[0] = $plg_array;
879 // Multiple menuitem records - in required format
880 $sets_array = $plg_array;
882 foreach ($sets_array as $val) {
883 $plugin = new Plugin();
885 for ($n = 0; $n < $num_var_names; $n++) {
886 if (isset($val[$n])) {
887 $plugin->$var_names[$n] = $val[$n];
889 $plugin->$var_names[$n] = '';
891 if (empty($plugin->$var_names[$n]) && $required_names[$n]) {
897 $plgresults[] = $plugin;
908 * This function shows the option for all plugins at the top of the
909 * command and control center.
911 * This supports that a plugin can have several lines in the CC menu.
912 * The plugin has to provide simply a set arrays with 3 variables in order to
913 * get n lines in the menu such as
916 * array("first line", "url1", "1"),
917 * array("second line", "url2", "44"),
920 * If there is only one item, a single array is enough:
922 * array("first line", "url1", "1")
925 * @return array Returns Command and Control options for moderation.php
928 function PLG_getCCOptions()
930 $var_names = array('adminlabel', 'adminurl', 'plugin_image');
931 $required_names = array(true, true, true);
932 $function_name = 'plugin_cclabel_';
933 $plgresults = PLGINT_getOptionsforMenus($var_names, $required_names, $function_name);
939 * This function will show any plugin adminstrative options in the
940 * admin functions block on every page (assuming the user is an admin
943 * NOTE: the plugin is responsible for its own security.
944 * This supports that a plugin can have several lines in the Admin menu.
945 * The plugin has to provide simply a set arrays with 3 variables in order to
946 * get n lines in the menu such as
949 * array("first line", "url1", "1"),
950 * array("second line", "url2", "44"),,
953 * If there is only one item, a single array is enough:
955 * array("first line", "url1", "1")
958 * @return array Returns options to put in admin menu
961 function PLG_getAdminOptions()
963 $var_names = array('adminlabel', 'adminurl', 'numsubmissions');
964 $required_names = array(true, true, false);
965 $function_name = 'plugin_getadminoption_';
966 $plgresults = PLGINT_getOptionsforMenus($var_names, $required_names, $function_name);
972 * This function will show any plugin user options in the
973 * user block on every page
975 * This supports that a plugin can have several lines in the User menu.
976 * The plugin has to provide simply a set of arrays with 3 variables in order to
977 * get n lines in the menu such as
980 * array("first line", "url1", "1"),
981 * array("second line", "url2", "44"),
984 * If there is only one item, a single array is enough:
986 * array("first line", "url1", "1")
989 * NOTE: the plugin is responsible for its own security.
991 * @return array Returns options to add to user menu
994 function PLG_getUserOptions()
996 // I know this uses the adminlabel, adminurl but who cares?
997 $var_names = array('adminlabel', 'adminurl', 'numsubmissions');
998 $required_names = array(true, true, false);
999 $function_name = 'plugin_getuseroption_';
1000 $plgresults = PLGINT_getOptionsforMenus($var_names, $required_names, $function_name);
1006 * This function is responsible for calling
1007 * plugin_moderationapproves_<pluginname> which approves an item from the
1008 * submission queue for a plugin.
1010 * @param string $type Plugin name to do submission approval for
1011 * @param string $id used to identify the record to approve
1012 * @return boolean Returns true on success otherwise false
1015 function PLG_approveSubmission($type, $id)
1019 return PLG_callFunctionForOnePlugin('plugin_moderationapprove_' . $type, $args);
1023 * This function is responsible for calling
1024 * plugin_moderationdelete_<pluginname> which deletes an item from the
1025 * submission queue for a plugin.
1027 * @param string $type Plugin to do submission deletion for
1028 * @param string $id used to identify the record for which to delete
1029 * @return boolean Returns true on success otherwise false
1032 function PLG_deleteSubmission($type, $id)
1036 return PLG_callFunctionForOnePlugin('plugin_moderationdelete_' . $type, $args);
1040 * This function calls the plugin_savesubmission_<pluginname> to save
1043 * @param string $type Plugin to save submission for
1044 * @param array $A holds plugin specific data to save
1045 * @return boolean Returns true on success otherwise false
1048 function PLG_saveSubmission($type, $A)
1052 return PLG_callFunctionForOnePlugin('plugin_savesubmission_' . $type, $args);
1056 * This function starts the chain of calls needed to show any submissions
1057 * needing moderation for the plugins.
1059 * @param string $token security token
1060 * @return string returns list of items needing moderation for plugins
1063 function PLG_showModerationList($token)
1069 foreach ($_PLUGINS as $pi_name) {
1070 $retval .= itemlist($pi_name, $token);
1077 * This function is responsible for setting the plugin-specific values
1078 * needed by moderation.php to approve stuff.
1080 * @param string $type Plugin to call function for
1084 function PLG_getModerationValues($type)
1086 return PLG_callFunctionForOnePlugin('plugin_moderationvalues_' . $type);
1090 * This function is resonsible for calling plugin_submit_<pluginname> so
1091 * that the submission form for the plugin is displayed.
1093 * @param string $type Plugin to show submission form for
1094 * @return string HTML for submit form for plugin
1097 function PLG_showSubmitForm($type)
1099 return PLG_callFunctionForOnePlugin('plugin_submit_' . $type);
1103 * This function will show the centerblock for any plugin.
1105 * Plugin can display some of their own content in a block on the index or any
1106 * topic index page. The block can be at the top or bottom of the page, after
1107 * the featured story or the plugin can take over the entire page.
1108 * The plugin is responsible to format the output correctly.
1110 * @param int $where where 1 = top, 2 = after feat. story, 3 = bottom of page, 0 = entire page
1111 * @param int $page page number (1, ...)
1112 * @param string $topic topic ID or empty string == front page
1113 * @return string Formatted center block content
1114 * @since Geeklog 1.3.8
1117 function PLG_showCenterblock($where = 1, $page = 1, $topic = '')
1119 global $PLG_bufferCenterAPI, $PLG_buffered, $_PLUGINS;
1123 // buffer function names since we're coming back for them two more times
1124 if (!$PLG_buffered) {
1125 $PLG_bufferCenterAPI = array();
1126 foreach ($_PLUGINS as $pi_name) {
1127 $function = 'plugin_centerblock_' . $pi_name;
1128 if (function_exists($function)) {
1129 $PLG_bufferCenterAPI[$pi_name] = $function;
1132 $PLG_buffered = true;
1135 foreach ($PLG_bufferCenterAPI as $function) {
1136 $retval .= $function($where, $page, $topic);
1138 if (($where == 0) && !empty($retval)) {
1142 $function = 'CUSTOM_centerblock';
1143 if (function_exists($function)) {
1144 $retval .= $function($where, $page, $topic);
1151 * This function will inform all plugins when a new user account is created.
1153 * @param int $uid user id of the new user account
1157 function PLG_createUser($uid)
1161 foreach ($_PLUGINS as $pi_name) {
1162 $function = 'plugin_user_create_' . $pi_name;
1163 if (function_exists($function)) {
1168 $function = 'CUSTOM_user_create';
1169 if (function_exists($function)) {
1175 * This function will inform all plugins when a user account is deleted.
1177 * @param int $uid user id of the deleted user account
1181 function PLG_deleteUser($uid)
1185 foreach ($_PLUGINS as $pi_name) {
1186 $function = 'plugin_user_delete_' . $pi_name;
1187 if (function_exists ($function)) {
1192 $function = 'CUSTOM_user_delete';
1193 if (function_exists($function)) {
1199 * This function will inform all plugins when a user logs in
1201 * Note: This function is NOT called when users are re-authenticated by their
1202 * long-term cookie. The global variable $_USER['auto_login'] will be set to
1203 * 'true' in that case, however.
1205 * @param int $uid user id
1209 function PLG_loginUser($uid)
1213 foreach ($_PLUGINS as $pi_name) {
1214 $function = 'plugin_user_login_' . $pi_name;
1215 if (function_exists($function)) {
1220 $function = 'CUSTOM_user_login';
1221 if (function_exists($function)) {
1227 * This function will inform all plugins when a user logs out.
1228 * Plugins should not rely on this ever being called, as the user may simply
1229 * close the browser instead of logging out.
1231 * @param int $uid user id
1235 function PLG_logoutUser($uid)
1239 foreach ($_PLUGINS as $pi_name) {
1240 $function = 'plugin_user_logout_' . $pi_name;
1241 if (function_exists($function)) {
1246 $function = 'CUSTOM_user_logout';
1247 if (function_exists($function)) {
1253 * This function is called to inform plugins when a user's information
1254 * (profile or preferences) has changed.
1256 * @param int $uid user id
1260 function PLG_userInfoChanged($uid)
1264 foreach ($_PLUGINS as $pi_name) {
1265 $function = 'plugin_user_changed_' . $pi_name;
1266 if (function_exists($function)) {
1271 $function = 'CUSTOM_user_changed';
1272 if (function_exists($function)) {
1278 * This function is called to inform plugins when a group's information has
1279 * changed or a new group has been created.
1281 * @param int $grp_id Group ID
1282 * @param string $mode type of change: 'new', 'edit', or 'delete'
1286 function PLG_groupChanged($grp_id, $mode)
1290 foreach ($_PLUGINS as $pi_name) {
1291 $function = 'plugin_group_changed_' . $pi_name;
1292 if (function_exists($function)) {
1293 $function($grp_id, $mode);
1297 $function = 'CUSTOM_group_changed';
1298 if (function_exists($function)) {
1304 * Geeklog is about to display the edit form for the user's profile. Plugins
1305 * now get a chance to add their own variables and input fields to the form.
1307 * @param int $uid user id of the user profile to be edited
1308 * @param ref &$template reference of the Template for the profile edit form
1312 function PLG_profileVariablesEdit($uid, &$template)
1316 foreach ($_PLUGINS as $pi_name) {
1317 $function = 'plugin_profilevariablesedit_' . $pi_name;
1318 if (function_exists($function)) {
1319 $function ($uid, $template);
1323 $function = 'CUSTOM_profilevariablesedit';
1324 if (function_exists($function)) {
1325 $function($uid, $template);
1330 * Geeklog is about to display the edit form for the user's profile. Plugins
1331 * now get a chance to add their own blocks below the standard form.
1333 * @param int $uid user id of the user profile to be edited
1334 * @return string HTML for additional block(s)
1337 function PLG_profileBlocksEdit($uid)
1343 foreach ($_PLUGINS as $pi_name) {
1344 $function = 'plugin_profileblocksedit_' . $pi_name;
1345 if (function_exists($function)) {
1346 $retval .= $function ($uid);
1350 $function = 'CUSTOM_profileblocksedit';
1351 if (function_exists($function)) {
1352 $retval .= $function($uid);
1359 * Geeklog is about to display the user's profile. Plugins now get a chance to
1360 * add their own variables to the profile.
1362 * @param int $uid user id of the user profile to be edited
1363 * @param ref &$template reference of the Template for the profile edit form
1367 function PLG_profileVariablesDisplay($uid, &$template)
1371 foreach ($_PLUGINS as $pi_name) {
1372 $function = 'plugin_profilevariablesdisplay_' . $pi_name;
1373 if (function_exists($function)) {
1374 $function ($uid, $template);
1378 $function = 'CUSTOM_profilevariablesdisplay';
1379 if (function_exists($function)) {
1380 $function($uid, $template);
1385 * Geeklog is about to display the user's profile. Plugins now get a chance to
1386 * add their own blocks below the standard profile form.
1388 * @param int $uid user id of the user profile to be edited
1389 * @return string HTML for additional block(s)
1392 function PLG_profileBlocksDisplay($uid)
1398 foreach ($_PLUGINS as $pi_name) {
1399 $function = 'plugin_profileblocksdisplay_' . $pi_name;
1400 if (function_exists($function)) {
1401 $retval .= $function ($uid);
1405 $function = 'CUSTOM_profileblocksdisplay';
1406 if (function_exists($function)) {
1407 $retval .= $function($uid);
1414 * The user wants to save changes to his/her profile. Any plugin that added its
1415 * own variables or blocks to the profile input form will now have to extract
1416 * its data and save it.
1417 * Plugins will have to refer to the global $_POST array to get the
1420 * @param string $plugin name of a specific plugin or empty(all plugins)
1424 function PLG_profileExtrasSave($plugin = '')
1426 if (empty($plugin)) {
1427 PLG_callFunctionForAllPlugins ('profileextrassave');
1429 PLG_callFunctionForOnePlugin ('plugin_profileextrassave_' . $plugin);
1434 * This function can be called to check if an plugin wants to set a template
1437 * Example in COM_siteHeader, the API call is now added
1438 * A plugin can check for $templatename == 'header' and then set additional
1439 * template variables
1441 * @param string $templatename Name of calling template
1442 * @param ref &$template reference for the Template
1444 * @see CUSTOM_templateSetVars
1447 function PLG_templateSetVars($templatename, &$template)
1451 foreach ($_PLUGINS as $pi_name) {
1452 $function = 'plugin_templatesetvars_' . $pi_name;
1453 if (function_exists($function)) {
1454 $function ($templatename, $template);
1458 if (function_exists('CUSTOM_templateSetVars')) {
1459 CUSTOM_templatesetvars($templatename, $template);
1464 * This function is called from COM_siteHeader and will return additional header
1465 * information. This can be used for JavaScript functions required for the plugin
1468 * @return string returns a concatenated string of all plugins extra header code
1469 * @since Geeklog 1.3.8
1472 function PLG_getHeaderCode()
1478 foreach ($_PLUGINS as $pi_name) {
1479 $function = 'plugin_getheadercode_' . $pi_name;
1480 if (function_exists($function)) {
1481 $headercode .= $function();
1485 $function = 'CUSTOM_getheadercode';
1486 if (function_exists($function)) {
1487 $headercode .= $function();
1494 * Get a list of all currently supported autolink tags.
1496 * Returns an associative array where $A['tag-name'] = 'plugin-name'
1498 * @return array All currently supported autolink tags
1500 * @internal not to be used by plugins
1503 function PLG_collectTags()
1505 global $_CONF, $_PLUGINS;
1507 if (isset($_CONF['disable_autolinks']) && ($_CONF['disable_autolinks'] == 1)) {
1508 // autolinks are disabled - return an empty array
1512 // Determine which Core Modules and Plugins support AutoLinks
1513 // 'tag' => 'module'
1514 $autolinkModules = array('story' => 'geeklog');
1516 foreach ($_PLUGINS as $pi_name) {
1517 $function = 'plugin_autotags_' . $pi_name;
1518 if (function_exists($function)) {
1519 $autotag = $function ('tagname');
1520 if (is_array($autotag)) {
1521 foreach ($autotag as $tag) {
1522 $autolinkModules[$tag] = $pi_name;
1525 $autolinkModules[$autotag] = $pi_name;
1530 return $autolinkModules;
1534 * This function will allow plugins to support the use of custom autolinks
1535 * in other site content. Plugins can now use this API when saving content
1536 * and have the content checked for any autolinks before saving.
1537 * The autolink would be like: [story:20040101093000103 here]
1539 * @param string $content Content that should be parsed for autolinks
1540 * @param string $plugin Optional if you only want to parse using a specific plugin
1543 function PLG_replaceTags($content, $plugin = '')
1545 global $_CONF, $_TABLES, $LANG32;
1547 if (isset($_CONF['disable_autolinks']) && ($_CONF['disable_autolinks'] == 1)) {
1548 // autolinks are disabled - return $content unchanged
1552 $autolinkModules = PLG_collectTags();
1554 // For each supported module, scan the content looking for any AutoLink tags
1556 $contentlen = MBYTE_strlen($content);
1557 $content_lower = MBYTE_strtolower($content);
1558 foreach ($autolinkModules as $moduletag => $module) {
1559 $autotag_prefix = '['. $moduletag . ':';
1562 while ($offset < $contentlen) {
1563 $start_pos = MBYTE_strpos($content_lower, $autotag_prefix,
1565 if ($start_pos === false) {
1568 $end_pos = MBYTE_strpos($content_lower, ']', $start_pos);
1569 $next_tag = MBYTE_strpos($content_lower, '[', $start_pos + 1);
1570 if (($end_pos > $start_pos) AND
1571 (($next_tag === false) OR ($end_pos < $next_tag))) {
1572 $taglength = $end_pos - $start_pos + 1;
1573 $tag = MBYTE_substr($content, $start_pos, $taglength);
1574 $parms = explode(' ', $tag);
1576 // Extra test to see if autotag was entered with a space
1577 // after the module name
1578 if (MBYTE_substr($parms[0], -1) == ':') {
1579 $startpos = MBYTE_strlen($parms[0]) + MBYTE_strlen($parms[1]) + 2;
1580 $label = str_replace(']', '', MBYTE_substr($tag, $startpos));
1583 $label = str_replace(']', '', MBYTE_substr($tag,
1584 MBYTE_strlen($parms[0]) + 1));
1585 $parms = explode(':', $parms[0]);
1586 if (count($parms) > 2) {
1587 // whoops, there was a ':' in the tag id ...
1588 array_shift($parms);
1589 $tagid = implode(':', $parms);
1596 'module' => $module,
1597 'tag' => $moduletag,
1599 'startpos' => $start_pos,
1600 'length' => $taglength,
1601 'parm1' => str_replace(']', '', $tagid),
1606 // Error: tags do not match - return with no changes
1607 return $content . $LANG32[32];
1609 $prev_offset = $offset;
1615 // If we have found 1 or more AutoLink tag
1616 if (count($tags) > 0) { // Found the [tag] - Now process them all
1617 foreach ($tags as $autotag) {
1618 $function = 'plugin_autotags_' . $autotag['module'];
1619 if (($autotag['module'] == 'geeklog') AND
1620 (empty($plugin) OR ($plugin == 'geeklog'))) {
1622 $linktext = $autotag['parm2'];
1623 if ($autotag['tag'] == 'story') {
1624 $autotag['parm1'] = COM_applyFilter($autotag['parm1']);
1625 if (! empty($autotag['parm1'])) {
1626 $url = COM_buildUrl($_CONF['site_url']
1627 . '/article.php?story=' . $autotag['parm1']);
1628 if (empty($linktext)) {
1629 $linktext = stripslashes(DB_getItem($_TABLES['stories'], 'title', "sid = '{$autotag['parm1']}'"));
1635 $filelink = COM_createLink($linktext, $url);
1636 $content = str_replace($autotag['tagstr'], $filelink,
1639 } elseif (function_exists($function) AND
1640 (empty($plugin) OR ($plugin == $autotag['module']))) {
1641 $content = $function('parse', $content, $autotag);
1651 * Prepare a list of all plugins that support feeds. To do this, we re-use
1652 * plugin_getfeednames_<plugin name> and only keep the names of those plugins
1653 * which support that function
1655 * @return array array of plugin names (can be empty)
1658 function PLG_supportingFeeds()
1664 foreach ($_PLUGINS as $pi_name) {
1665 $function = 'plugin_getfeednames_' . $pi_name;
1666 if (function_exists($function)) {
1667 $feeds = $function();
1668 if (is_array($feeds) && (count($feeds) > 0)) {
1669 $plugins[] = $pi_name;
1674 $function = 'CUSTOM_getfeednames';
1675 if (function_exists($function)) {
1676 $feeds = $function();
1677 if (is_array($feeds) && (count($feeds) > 0)) {
1678 $plugins[] = 'custom';
1686 * Ask the plugin for a list of feeds it supports. The plugin is expected to
1687 * return an array of id/name pairs where 'id' is the plugin's internal id
1688 * for the feed and 'name' is what will be presented to the user.
1690 * @param string $plugin plugin name
1691 * @return array array of id/name pairs
1694 function PLG_getFeedNames($plugin)
1700 if ($plugin == 'custom')
1702 $function = 'CUSTOM_getfeednames';
1703 if (function_exists($function)) {
1704 $feeds = $function();
1707 if (in_array($plugin, $_PLUGINS)) {
1708 $function = 'plugin_getfeednames_' . $plugin;
1709 if (function_exists($function)) {
1710 $feeds = $function();
1721 * Get the content of a feed from the plugin.
1723 * The plugin is expected to return an array holding the content of the feed
1724 * and to fill in 'link' (some link that represents the same content on the
1725 * site as that in the feed) and 'update_data' (to be stored for later up-to-date
1728 * @param string $plugin plugin name
1729 * @param int $feed feed id
1730 * @param string &$link link to content on the site
1731 * @param string &$update_data information for later up-to-date checks
1732 * @param string $feedType The type of feed (RSS/Atom etc)
1733 * @param string $feedVersion The version info of the feed.
1734 * @return array content of feed
1737 function PLG_getFeedContent($plugin, $feed, &$link, &$update_data, $feedType, $feedVersion)
1743 if ($plugin == 'custom') {
1744 $function = 'CUSTOM_getfeedcontent';
1745 if (function_exists($function)) {
1746 $content = $function($feed, $link, $update_data, $feedType, $feedVersion);
1749 if (in_array($plugin, $_PLUGINS)) {
1750 $function = 'plugin_getfeedcontent_' . $plugin;
1751 if (function_exists ($function)) {
1752 $content = $function ($feed, $link, $update_data, $feedType, $feedVersion);
1761 * Get extension tags for a feed. For example, some plugins may extened the
1762 * available elements for an RSS 2.0 feed for articles. For some reason. This
1763 * function allows that.
1765 * @param string $contentType Type of feed content, article or a plugin specific type
1766 * @param string $contentID Unique identifier of content item to extend
1767 * @param string $feedType Type of feed format (RSS/Atom/etc)
1768 * @param string $feedVersion Type of feed version (RSS 1.0 etc)
1769 * @param string $topic The topic for the feed.
1770 * @param string $fid The ID of the feed being fetched.
1771 * @return array list of extension tags
1774 function PLG_getFeedElementExtensions($contentType, $contentID, $feedType, $feedVersion, $topic, $fid)
1778 $extensions = array();
1779 foreach( $_PLUGINS as $plugin )
1781 $function = 'plugin_feedElementExtensions_'.$plugin;
1782 if (function_exists($function))
1784 $extensions = array_merge($extensions, $function($contentType, $contentID, $feedType, $feedVersion, $topic, $fid));
1788 $function = 'CUSTOM_feedElementExtensions';
1789 if (function_exists($function))
1791 $extensions = array_merge($extensions, $function($contentType, $contentID, $feedType, $feedVersion, $topic, $fid));
1798 * Get namespaces extensions for a feed. If a plugin has added extended tags
1799 * to a feed, then it may also need to insert some extensions to the name
1802 * @param string $contentType Type of feed content, article or a plugin specific type
1803 * @param string $feedType Type of feed format (RSS/Atom/etc)
1804 * @param string $feedVersion Type of feed version (RSS 1.0 etc)
1805 * @param string $topic The topic for the feed.
1806 * @param string $fid The ID of the feed being fetched.
1807 * @return array list of extension namespaces
1810 function PLG_getFeedNSExtensions($contentType, $feedType, $feedVersion, $topic, $fid)
1814 $namespaces = array();
1815 foreach( $_PLUGINS as $plugin )
1817 $function = 'plugin_feedNSExtensions_'.$plugin;
1818 if (function_exists($function))
1820 $namespaces = array_merge($namespaces, $function($contentType, $feedType, $feedVersion, $topic, $fid));
1824 $function = 'CUSTOM_feedNSExtensions';
1825 if (function_exists($function))
1827 $namespaces = array_merge($namespaces, $function($contentType, $feedType, $feedVersion, $topic, $fid));
1834 * Get meta tag extensions for a feed. Add extended tags to the meta
1837 * @param string $contentType Type of feed content, article or a plugin specific type
1838 * @param string $feedType Type of feed format (RSS/Atom/etc)
1839 * @param string $feedVersion Type of feed version (RSS 1.0 etc)
1840 * @param string $topic The topic for the feed.
1841 * @param string $fid The ID of the feed being fetched.
1842 * @return array list of meta tag extensions
1845 function PLG_getFeedExtensionTags($contentType, $feedType, $feedVersion, $topic, $fid)
1850 foreach( $_PLUGINS as $plugin )
1852 $function = 'plugin_feedExtensionTags_'.$plugin;
1853 if (function_exists($function))
1855 $tags = array_merge($tags, $function($contentType, $feedType, $feedVersion, $topic, $fid));
1859 $function = 'CUSTOM_feedExtensionTags';
1860 if (function_exists($function))
1862 $tags = array_merge($tags, $function($contentType, $feedType, $feedVersion, $topic, $fid));
1869 * The plugin is expected to check if the feed content needs to be updated.
1871 * This is called from COM_rdfUpToDateCheck() every time Geeklog's index.php
1872 * is displayed - it should try to be as efficient as possible ...
1874 * NOTE: The presence of non-empty $updated_XXX parameters indicates that an
1875 * existing entry has been changed. The plugin may therefore apply a
1876 * different method to check if its feed has to be updated.
1878 * @param string $plugin plugin name
1879 * @param int $feed feed id
1880 * @param string $topic "topic" of the feed - plugin specific
1881 * @param string $update_data comma-sep. list of updated ids
1882 * @param string $limit number of entries or number of hours
1883 * @param string $updated_type (optional) type of feed to update
1884 * @param string $updated_topic (optional) topic to update
1885 * @param string $updated_id (optional) entry id to update
1886 * @return boolean false = feed has to be updated, true = ok
1889 function PLG_feedUpdateCheck($plugin, $feed, $topic, $update_data, $limit, $updated_type = '', $updated_topic = '', $updated_id = '')
1895 if ($plugin == 'custom') {
1896 $function = 'CUSTOM_feedupdatecheck';
1897 if (function_exists($function)) {
1898 $is_current = $function ($feed, $topic, $update_data, $limit,
1899 $updated_type, $updated_topic, $updated_id);
1902 if (in_array($plugin, $_PLUGINS)) {
1903 $function = 'plugin_feedupdatecheck_' . $plugin;
1904 if (function_exists($function)) {
1905 $is_current = $function($feed, $topic, $update_data, $limit,
1906 $updated_type, $updated_topic, $updated_id);
1915 * Ask plugins if they want to add something to Geeklog's What's New block.
1917 * @return array array($headlines[], $bylines[], $content[$entries[]])
1920 function PLG_getWhatsNew()
1924 $newheadlines = array();
1925 $newbylines = array();
1926 $newcontent = array();
1928 foreach ($_PLUGINS as $pi_name) {
1929 $fn_head = 'plugin_whatsnewsupported_' . $pi_name;
1930 if (function_exists($fn_head)) {
1931 $supported = $fn_head();
1932 if (is_array($supported)) {
1933 list($headline, $byline) = $supported;
1935 $fn_new = 'plugin_getwhatsnew_' . $pi_name;
1936 if (function_exists($fn_new)) {
1937 $whatsnew = $fn_new ();
1938 $newcontent[] = $whatsnew;
1939 $newheadlines[] = $headline;
1940 $newbylines[] = $byline;
1946 $fn_head = 'CUSTOM_whatsnewsupported';
1947 if (function_exists($fn_head)) {
1948 $supported = $fn_head();
1949 if (is_array($supported)) {
1950 list($headline, $byline) = $supported;
1952 $fn_new = 'CUSTOM_getwhatsnew';
1953 if (function_exists($fn_new)) {
1954 $whatsnew = $fn_new ();
1955 $newcontent[] = $whatsnew;
1956 $newheadlines[] = $headline;
1957 $newbylines[] = $byline;
1962 return array($newheadlines, $newbylines, $newcontent);
1966 * Allows plugins and Core Geeklog Components to filter out spam.
1968 * The Spam-X Plugin is now part of the Geeklog Distribution
1969 * This plugin API will call the main function in the Spam-X plugin
1970 * but can also be used to call other plugins or custom functions
1971 * if available for filtering spam or content.
1973 * The caller should check for return values > 0 in which case spam has been
1974 * detected and the poster should be told, either via
1976 * echo COM_refresh($_CONF['site_url'] . '/index.php?msg=' . $result
1977 * . '&plugin=spamx');
1981 * COM_displayMessageAndAbort($result, 'spamx', 403, 'Forbidden');
1983 * Where the former will only display a "spam detected" message while the latter
1984 * will also send an HTTP status code 403 with the message.
1986 * @param string $content Text to be filtered or checked for spam
1987 * @param int $action what to do if spam found
1988 * @return int > 0: spam detected, == 0: no spam detected
1989 * @link http://wiki.geeklog.net/index.php/Filtering_Spam_with_Spam-X
1992 function PLG_checkforSpam($content, $action = -1)
1996 foreach ($_PLUGINS as $pi_name) {
1997 $function = 'plugin_checkforSpam_' . $pi_name;
1998 if (function_exists($function)) {
1999 $result = $function($content, $action);
2000 if ($result > 0) { // Plugin found a match for spam
2002 $result = PLG_spamAction($content, $action);
2009 $function = 'CUSTOM_checkforSpam';
2010 if (function_exists($function)) {
2011 $result = $function($content, $action);
2012 if ($result > 0) { // Plugin found a match for spam
2014 $result = PLG_spamAction($content, $action);
2026 * This is normally called from PLG_checkforSpam (see above) automatically when
2027 * spam has been detected. There may however be situations where spam has been
2028 * detected by some other means, in which case you may want to trigger the
2029 * spam action explicitly.
2031 * @param string $content Text to be filtered or checked for spam
2032 * @param int $action what to do if spam found
2033 * @return int > 0: spam detected, == 0: no spam detected
2034 * @see PLG_checkforSpam
2035 * @since Geeklog 1.4.1
2038 function PLG_spamAction($content, $action = -1)
2044 foreach ($_PLUGINS as $pi_name) {
2045 $function = 'plugin_spamaction_' . $pi_name;
2046 if (function_exists($function)) {
2047 $res = $function($content, $action);
2048 $result = max($result, $res);
2052 $function = 'CUSTOM_spamaction';
2053 if (function_exists($function)) {
2054 $res = $function($content, $action);
2055 $result = max($result, $res);
2062 * Ask plugin for information about one of its items
2064 * Item properties that can be requested:
2065 * - 'date-created' - creation date, if available
2066 * - 'date-modified' - date of last modification, if available
2067 * - 'description' - full description of the item
2068 * - 'excerpt' - short description of the item
2069 * - 'id' - ID of the item, e.g. sid for articles
2070 * - 'title' - title of the item
2071 * - 'url' - URL of the item
2073 * 'excerpt' and 'description' may return the same value. Properties should be
2074 * returned in the order they are listed in $what. Properties that are not
2075 * available should return an empty string.
2076 * Return false for errors (e.g. access denied, item does not exist, etc.).
2078 * @param string $type plugin type (incl. 'article' for stories)
2079 * @param string $id ID of an item under the plugin's control or '*'
2080 * @param string $what comma-separated list of item properties
2081 * @param int $uid user ID or 0 = current user
2082 * @param array $options (reserved for future extensions)
2083 * @return mixed string or array of strings with the information
2084 * @link http://wiki.geeklog.net/index.php/PLG_getItemInfo
2087 function PLG_getItemInfo($type, $id, $what, $uid = 0, $options = array())
2089 if ($type == 'article') {
2093 require_once $_CONF['path_system'] . 'lib-story.php';
2095 return STORY_getItemInfo($id, $what, $uid, $options);
2102 $args[4] = $options;
2104 $function = 'plugin_getiteminfo_' . $type;
2106 return PLG_callFunctionForOnePlugin($function, $args);
2111 * Geeklog is about to perform an operation on a trackback or pingback comment
2112 * to one of the items under the plugin's control and asks for the plugin's
2113 * permission to continue.
2115 * Geeklog handles receiving and deleting trackback comments and pingbacks
2116 * for the plugin but since it doesn't know about the plugin's access control,
2117 * it has to ask the plugin to approve / reject such an operation.
2119 * $operation can be one of the following:
2120 * - 'acceptByID': accept a trackback comment on item with ID $id
2121 * returns: true for accept, false for reject
2122 * - 'acceptByURI': accept a pingback comment on item at URL $id
2123 * returns: the item's ID for accept, false for reject
2124 * - 'delete': is the current user allowed to delete item with ID $id?
2125 * returns: true for accept, false for reject
2127 * @param string $type plugin type
2128 * @param string $id an ID or URL, depending on the operation
2129 * @param string $operation operation to perform
2130 * @return mixed depends on $operation
2133 function PLG_handlePingComment($type, $id, $operation)
2136 $args[2] = $operation;
2138 $function = 'plugin_handlepingoperation_' . $type;
2140 return PLG_callFunctionForOnePlugin ($function, $args);
2145 * Check if plugins have a scheduled task they want to run
2146 * The interval between runs is determined by $_CONF['cron_schedule_interval']
2151 function PLG_runScheduledTask()
2155 foreach ($_PLUGINS as $pi_name) {
2156 $function = 'plugin_runScheduledTask_' . $pi_name;
2157 if (function_exists ($function)) {
2162 if (function_exists('CUSTOM_runScheduledTask')) {
2163 CUSTOM_runScheduledTask();
2168 * "Generic" plugin API: Save item
2170 * To be called (eventually) whenever Geeklog saves an item into the database.
2171 * Plugins can define their own 'itemsaved' function to be notified whenever
2172 * an item is saved or modified.
2174 * NOTE: The behaviour of this API function changed in Geeklog 1.6.0
2176 * @param string $id unique ID of the item
2177 * @param string $type type of the item, e.g. 'article'
2178 * @param string $old_id (optional) old ID when the ID was changed
2179 * @return void (actually: false, for backward compatibility)
2180 * @link http://wiki.geeklog.net/index.php/PLG_itemSaved
2183 function PLG_itemSaved($id, $type, $old_id = '')
2187 $t = explode('.', $type);
2190 $plugins = count($_PLUGINS);
2191 for ($save = 0; $save < $plugins; $save++) {
2192 if ($_PLUGINS[$save] != $plg_type) {
2193 $function = 'plugin_itemsaved_' . $_PLUGINS[$save];
2194 if (function_exists($function)) {
2195 $function($id, $type, $old_id);
2200 if (function_exists('CUSTOM_itemsaved')) {
2201 CUSTOM_itemsaved($id, $type, $old_id);
2204 return false; // for backward compatibility
2208 * "Generic" plugin API: Delete item
2210 * To be called (eventually) whenever Geeklog removes an item from the database.
2211 * Plugins can define their own 'itemdeleted' function to be notified whenever
2212 * an item is deleted.
2214 * @param string $id ID of the item
2215 * @param string $type type of the item, e.g. 'article'
2217 * @since Geeklog 1.6.0
2220 function PLG_itemDeleted($id, $type)
2224 $t = explode('.', $type);
2227 $plugins = count($_PLUGINS);
2228 for ($del = 0; $del < $plugins; $del++) {
2229 if ($_PLUGINS[$del] != $plg_type) {
2230 $function = 'plugin_itemdeleted_' . $_PLUGINS[$del];
2231 if (function_exists($function)) {
2232 $function($id, $type);
2237 if (function_exists('CUSTOM_itemdeleted')) {
2238 CUSTOM_itemdeleted($id, $type);
2243 * "Generic" plugin API: Display item
2245 * To be called (eventually) whenever Geeklog displays an item.
2246 * Plugins can hook into this and add content to the displayed item, in the form
2247 * of an array (true, string1, string2...).
2249 * The object that called can then display one or several items with a
2250 * object-defined layout.
2252 * Plugins can signal an error by returning an array (false, 'Error Message')
2253 * In case of an error, the error message will be written to the error.log and
2254 * nothing will be displayed on the output.
2256 * @param string $id unique ID of the item
2257 * @param string $type type of the item, e.g. 'article'
2258 * @return array array with a status and one or several strings
2261 function PLG_itemDisplay($id, $type)
2264 $result_arr = array();
2266 $plugins = count($_PLUGINS);
2267 for ($display = 0; $display < $plugins; $display++) {
2268 $function = 'plugin_itemdisplay_' . $_PLUGINS[$display];
2269 if (function_exists($function)) {
2270 $result = $function($id, $type);
2271 if ($result[0] == false) {
2272 // plugin reported a problem - do not add and continue
2273 COM_errorLog($result[1], 1);
2275 array_shift($result);
2276 $result_arr = array_merge($result_arr,$result);
2281 $function = 'CUSTOM_itemdisplay';
2282 if (function_exists ($function)) {
2283 $result = $function ($id, $type);
2284 if ($result[0] == false) {
2285 // plugin reported a problem - do not add and continue
2286 COM_errorLog( $result[1], 1);
2288 array_shift($result);
2289 $result_arr = array_merge($result_arr,$result);
2298 * Gets Geeklog blocks from plugins
2300 * Returns data for blocks on a given side and, potentially, for
2303 * @param string $side Side to get blocks for (right or left for now)
2304 * @param string $topic Only get blocks for this topic
2305 * @return array array of block data
2306 * @link http://wiki.geeklog.net/index.php/Dynamic_Blocks
2309 function PLG_getBlocks($side, $topic='')
2314 foreach ($_PLUGINS as $pi_name) {
2315 $function = 'plugin_getBlocks_' . $pi_name;
2316 if (function_exists($function)) {
2317 $items = $function($side, $topic='');
2318 if (is_array($items)) {
2319 $ret = array_merge($ret, $items);
2324 if (function_exists('CUSTOM_getBlocks')) {
2325 $cust_items .= CUSTOM_getBlocks($side, $topic='');
2326 if (is_array($cust_items)) {
2327 $ret = array_merge($ret, $cust_items);
2335 * Get the URL of a plugin's icon
2337 * @param string $type plugin name
2338 * @return string URL of the icon
2341 function PLG_getIcon($type)
2347 // try the "geticon" function first
2348 $function = 'plugin_geticon_' . $type;
2349 if (function_exists($function)) {
2350 $retval = $function ();
2353 // if that didn't work, try the "cclabel" function
2354 if (empty($retval)) {
2355 $function = 'plugin_cclabel_' . $type;
2356 if (function_exists($function)) {
2357 $cclabel = $function ();
2358 if (is_array($cclabel)) {
2359 if (!empty($cclabel[2])) {
2360 $retval = $cclabel[2];
2366 // lastly, search for the icon (assuming it's a GIF)
2367 if (empty($retval)) {
2368 $icon = $_CONF['site_url'] . '/' . $type . '/images/' . $type . '.gif';
2369 $fh = @fopen ($icon, 'r');
2370 if ($fh === false) {
2371 $icon = $_CONF['site_admin_url'] . '/plugins/' . $type . '/images/'
2373 $fh = @fopen ($icon, 'r');
2374 if ($fh === false) {
2375 // give up and use a generic icon
2376 $retval = $_CONF['site_url'] . '/images/icons/plugins.gif';
2393 * @param string $type The plugin type whose service is to be called
2394 * @param string $action The service action to be performed
2395 * @param array $args The arguments to be passed to the service invoked
2396 * @param array &$output The output variable that will contain the output after invocation
2397 * @param array &$svc_msg The output variable that will contain the service messages
2398 * @return int The result of the invocation
2399 * @link http://wiki.geeklog.net/index.php/Webservices_API
2402 function PLG_invokeService($type, $action, $args, &$output, &$svc_msg)
2406 $retval = PLG_RET_ERROR;
2408 if ($type == 'story') {
2409 // ensure we can see the service_XXX_story functions
2410 require_once $_CONF['path_system'] . 'lib-story.php';
2416 // Check if the plugin type and action are valid
2417 $function = 'service_' . $action . '_' . $type;
2419 if (function_exists($function) && PLG_wsEnabled($type)) {
2420 if (!isset($args['gl_svc'])) {
2421 $args['gl_svc'] = false;
2423 $retval = $function($args, $output, $svc_msg);
2430 * Returns true if the plugin supports webservices
2432 * @param string $type The plugin type that is to be checked
2433 * @return boolean true: enabled, false: disabled
2434 * @link http://wiki.geeklog.net/index.php/Webservices_API
2437 function PLG_wsEnabled($type)
2441 if ($type == 'story') {
2442 // ensure we can see the service_XXX_story functions
2443 require_once $_CONF['path_system'] . 'lib-story.php';
2446 $function = 'plugin_wsEnabled_' . $type;
2447 if (function_exists($function)) {
2455 * Forward the user depending on config setting after saving something
2457 * @param string $target where to redirect to
2458 * @param string $item_url the url of the item saved
2459 * @param string $plugin the name of the plugin that saved the item
2460 * @param string $message (optional) message number to attach to url
2461 * @return string the url where the user will be forwarded to
2464 function PLG_afterSaveSwitch($target, $item_url, $plugin, $message = '')
2468 if (isset($message) && (!empty($message) || is_numeric($message))) {
2469 $msg = "msg=$message";
2477 if (!empty($msg) && ($plugin != 'story')) {
2478 if (strpos($url, '?') === false) {
2481 $url .= '&' . $msg;
2487 $url = $_CONF['site_url'] . '/index.php';
2490 if (($plugin != 'story') && ($plugin != 'user')) {
2491 $url .= '&plugin=' . $plugin;
2497 $url = $_CONF['site_admin_url'] . '/moderation.php';
2500 if (($plugin != 'story') && ($plugin != 'user')) {
2501 $url .= '&plugin=' . $plugin;
2507 $url = $_CONF['site_url'] . "/$plugin/index.php";
2515 if ($plugin == 'story') {
2516 $url = $_CONF['site_admin_url'] . "/$plugin.php";
2517 } elseif ($plugin == 'user') {
2518 $url = $_CONF['site_admin_url'] . "/user.php";
2520 $url = $_CONF['site_admin_url'] . "/plugins/$plugin/index.php";
2528 return COM_refresh($url);
2532 * Inform plugins of configuration changes
2534 * NOTE: Plugins will only be notified of details of changes in 'Core' and in
2535 * their own configuration. For other plugins, they will only be notified
2536 * of the fact that something in the other plugin's config changed.
2538 * @param string $group plugin name or 'Core' for $_CONF changes
2539 * @param array $changes names of config values that changed
2541 * @link http://wiki.geeklog.net/index.php/PLG_configChange
2542 * @since Geeklog 1.6.0
2545 function PLG_configChange($group, $changes)
2549 foreach ($_PLUGINS as $pi_name) {
2553 if (($group == 'Core') || ($group == $pi_name)) {
2554 $args[2] = $changes;
2557 PLG_callFunctionForOnePlugin('plugin_configchange_' . $pi_name, $args);
2560 $function = 'CUSTOM_configchange';
2561 if (function_exists($function)) {
2562 if ($group == 'Core') {
2563 $function($group, $changes);
2571 * Ask plugin for the URL to its documentation
2573 * @param string $type plugin name
2574 * @param string $file documentation file being requested, e.g. 'config'
2575 * @return mixed URL or false / empty string when not available
2576 * @link http://wiki.geeklog.net/index.php/PLG_getDocumentationUrl
2577 * @since Geeklog 1.6.0
2580 function PLG_getDocumentationUrl($type, $file)
2583 $function = 'plugin_getdocumentationurl_' . $type;
2585 return PLG_callFunctionForOnePlugin($function, $args);
2589 * Inform plugins when another plugin's state changed
2591 * Unlike PLG_enableStateChange, this function is called after the state
2594 * NOTE: You can not rely on being informed of state changes for 'installed',
2595 * 'uninstalled', and 'upgraded', as these may happen in the plugin's install
2596 * script, outside of Geeklog's control.
2598 * @param string $type plugin name
2599 * @param string $status new status: 'enabled', 'disabled', 'installed', 'uninstalled', 'upgraded'
2601 * @see PLG_enableStateChange
2602 * @since Geeklog 1.6.0
2605 function PLG_pluginStateChange($type, $status)
2611 foreach ($_PLUGINS as $pi_name) {
2612 if ($pi_name != $type) {
2613 $function = 'plugin_pluginstatechange_' . $pi_name;
2614 PLG_callFunctionForOnePlugin($function, $args);
2618 $function = 'CUSTOM_pluginstatechange';
2619 if (function_exists($function)) {
2620 $function($type, $status);