Document everything!
{{include page="!/Changes"}}
{{toc numerate=1}}
- DRAFT -
=== Wacko API for version 5.0 ===
[//Note//: This list actually describes the ((/Dev/API/TomsApi API for TomG's much-hacked personal version of Wakka 0.1.2)), with additions as indicated by the markers ##[*]## (function added) and ##[=]## (functionality and/or API extended). The purpose for these additions was to make Wakka more usable as a general-purpose 'site engine' rather than solely as a (very good) wiki. Unlike the (also good) Wacko variant of Wakka, it's still compact and fast; and perhaps importantly, the additions require //no changes// to the Wakka 0.1.2 database structure.]
==== Main (index.php)====
These functions are in the file classes/wacko.php, listed in the same order as in the file.
==== DB ====
//int// **sql_query**(//string// query) -- general-purpose Mysql query
##query## - query-string in Mysql syntax
//array// **load_single**(//string// query) -- single-record select
##query## - query-string in Mysql syntax
array is one-dimension indexed by fieldname
returns empty array if record not found
//array// **load_all**(//string// query) -- multi-record select
##query## - query-string in Mysql syntax
array is two-dimension 0-indexed list of records with each record-array indexed by field
==== Misc ====
//float// **get_microtime**() -- return system micro-time
//string// **include_buffered**(//string// filename, //string// notfoundtext=""''"", //string/array// vars=""''"", //string// path=""''"") -- return result of embedded code-fragment
##notfoundtext## - returned if file is not found
##vars## - optional array of variables to be passed (via ##extract()##) to the fragment
##path## - ':'-separated list of directories to be searched
returns result of all print/echo statements in included fragment
//note// includebuffered is called by action(), method(), format()
==== Variables ====
//string// **get_page_tag**() -- return page-tag [shorthand for ##get_page_value('tag')##]
//string// **get_page_time**() -- return page save-date [shorthand for ##get_page_value('time')##]
[*] //mixed// **get_page_value**(//string// id) -- return page-property stored in ##$page## array (usally a string)
[*] //null// **set_page_value**(//string// id, //mixed// value) -- set page-property in ##$page## array
[*] //mixed// **altvalue**(//mixed// main, //mixed// default) -- return main if non-empty, default if main is empty
is a possibly-easier 'shorthand' for the ##( ? : )## construct
//string// **get_method**() -- return method for current page
//mixed// **get_config_value**(//string// id) -- return configuration property in ##$config## array
//string// **get_wacko_name**() -- return site-name [shorthand for ##get_config_value('wakka_name')##]
//string// **get_wacko_version**() -- return current code-version id
==== Pages ====
//array// **load_page**(//string// tag, //timestamp// time=""''"", //bool// cache=1) -- load page-data
##tag## - page-tag
##time## - if set, gets specific version of page, else most recent version (default)
##cache## - if set, tries page-cache first (default)
returns ##$page## array, [=] including page-properties from ACLS table
//note// if ##time## is not set (i.e. not an old version), stores result in page-cache
[=] search for tag is case-independent (i.e. need not be strict wiki-name); tag may include underscores
[*] //array// **load_page_options**(//string// tag=""''"") -- returns array of extended page-properties for ##tag## from ACLS table
##tag## - page-tag, or current page if absent
returns single-dimension array indexed by property-name, to merge into ##$page## array
effectively, provides arbitrary extension of ##$page## fields
//array// **get_cached_page**(//string// tag) -- retrieve page-array from page-cache
//null// **cache_page**(//array// page) -- store page-array in page-cache
//note// - uses 'tag' member in page-array as index in cache
//null// **set_page**(//array// page) -- sets the page as the current 'this-page'
//note// - will not change the current-page if tag (presumably whole array) is empty
//array// **load_page_by_id**(//int// id) -- get page-array (without extra page-properties) for selected page-record
id - unique id for page-record
//array// **load_revisions**(//string// tag) -- get array of page-arrays (without extra page-properties) for all versions of this page, sorted in reverse date-order
//array// **load_pages_linking**(//string// tag) -- get array of array of page-tags linking to this page
returns 0-index array of record-arrays each with single field ##'tag'##
//array// **load_recently_changed**() -- get array of **all** current pages, sorted in reverse date-order
returns array of page-record arrays
page-record arrays are also stored in cache
//warning// - this is likely to be //very// resource-intensive
//array// **load_wanted_pages**() -- get array of (intended) tags for links to non-existent pages
returns 0-index array of record-arrays with fields ##'tag'## (missing page) and ##'count'## (no. of references)
//array// **load_orphaned_pages**() - get array of tags for pages without links to any other page
returns 0-index array of record-arrays with single field ##'tag'##
//array// **load_page_titles**() - get array of tags for all pages
returns 0-index array of record-arrays with single field ##'tag'##
//note// tag is page-'title' (as per Wakka) - see also ##load_page_options()## function
//array// **load_allpages**() - get array of latest versions of **all** page-records
returns 0-index array of record-arrays with all standard Wakka page-fields (but not extended page-properties)
//warning// - this is likely to be //very// resource-intensive
//array// **fulltext_search**(//string// phrase) - get array of current versions of pages with tag or body containing the search-phrase
returns 0-index array of page-record arrays with all standard Wakka page-fields (but not extended page-properties), sorted in reverse date-order
//warning// - this is likely to be resource-intensive
[=] //null// **save_page**(//string// tag, //string// body, comment_on=""''"", //array// extra=""''"") -- store new/edited page-content
##tag## - page-tag to use (may or may not already exist)
##body## - Wakka-format text for page-body
##comment_on## - if set, body is a comment on the page with this field as tag
[=] ##extra## - optional field-name indexed array of extended page-properties for non-comment pages
extended page-properties are stored in ACLS table
if ##'parent'## property exists, also updates ##'parents'##, ##'siblings'## and ##'children'## properties for self and related pages
[=] this function also triggers optional flushing of outdated page-revisions as per ##'pages_purge_time'## config-parameter (moved from ##maintenance()## function - same as in Wakka 0.1.2, but triggered on each save-page rather than each page-view)
[*] //array// **get_parent_list**(//string// tag=""''"", //string// parent=""''"") -- get array of tags in 'parent' tree, sorted highest-parent-first
##tag## - page-tag of end-point of parent-child tree (i.e. usually self) - default is self
##parent## - page-tag of this tag's parent, if known
returns 0-index array of page-tags
[*] //array// **get_sibling_list**(//string// tag, //string// parent) -- get array of 'sibling' tags, sorted in tag order
##tag## - page-tag to be //excluded// from sibling-list (i.e. usually self)
##parent## - tag of 'parent' for siblings of this tag
returns 0-index array of page-tags
[*] //array// **get_child_list**(//string// tag) -- get array of 'child' tags, sorted in tag order
##tag## - page-tag as 'parent' (i.e. usually self) to identify 'children'
returns 0-index array of page-tags
[*] //string// **make_tree**(//array// taglist, //string// fieldsep='|', //string// rowsep='~') - return serialised version of tag and shortname, for tags in taglist
##taglist## - 0-index array of tags (i.e. as returned by ##get_parent_list()## etc.)
##fieldsep## - field-separator in output string
##rowsep## - row-separator in output string
(with default fieldsep/rowsep, output is compatible with default settings of menu handlers - see ##menu_item()## function)
if ##'shortname'## property is absent for a page, standard ##'tag'## property is used as default (i.e. backward-compatible with Wakka)
==== Cookies ====
//null// **set_session_cookie**(//string// name, //mixed// value) -- store a session-value
stored as root-value for the domain; expires when the browser closes
also stored in the local COOKIE array
//null// **set_persistent_cookie**(//string// name, //mixed// value) -- store a persistent client-value
stored as root-value for the domain; expires in 90 days
also stored in the local COOKIE array
//null// **delete_cookie**(//string// name) -- delete a session/client value
stored as null value, 1-second expiry, for the current session
also stored as empty (not unset) in the local COOKIE array
//mixed// **get_cookie**(//string// name) -- retrieve a session/client value from the local COOKIE array
==== HTTP / request / link related ====
//null// **set_message**(//string// message) -- set content for a popup message to be shown on opening the next Wakka page
(actually just stores the session-value 'message')
//note// - because it's displayed via a Javascript alert-box, the message can only be around 10-20 words maximum
//warning// - because it's eventually embedded in Javascript in the page tag, the string cannot include " characters, and must not end with a ' character
//string// **get_message**() -- retrieve and clear the session-value 'message'
//null// **redirect**(//string// url) -- immediate redirect to the specified URL
//note// - even though it's output as an HTTP Header, Wakka's output-buffering means that this function still works anywhere in a page
[=] //string// **mini_href**(//string// method=""''"", //string// tag=""''"", //string// anchor=""''"") -- return value for page 'wakka' parameter, in tag[/method][#anchor] format
##method## - optional Wakka method (default ##'show'## method added in ##run()## function)
##tag## - optional tag - returns current-page tag if empty
[=] ##anchor## - optional HTTP anchor-fragment (i.e. backward-compatible with Wakka 0.1.2)
[=] //string// **href**(//string// method=""''"", //string// tag=""''"", //string// params=""''"", //string// anchor=""''"") -- return the full URL for a page/method, including any additional URL-parameters and/or anchor
##method## - optional Wakka method (default ##'show'## method added in ##run()## function)
##tag## - optional tag - returns current-page tag if empty
##params## - optional URL parameters in HTTP ##name=value[&name=value][...]## format
[=] ##anchor## - optional HTTP anchor-fragment (i.e. backward-compatible with Wakka 0.1.2)
returns HREF string adjusted for Apache rewrite_method setting (i.e. Wakka ##'rewrite_method'## config-parameter)
[=] Wakka ##'base_url'## config-parameter stays the same regardless of ##'rewrite_method'## setting
[=] script-name can be set via ##'script_name'## config-parameter (defaults to self, i.e. ##index.php##)
[=] page-var can be set via ##'page_var'## config-parameter (defaults to ##page##)
[=] //string// **link**(//string// pagetag, //string// method=""''"", //string// text=""''"", //bool// track=1) -- return full <A href="https://example.com/"> or <IMG/> HTML-tag
##pagetag## - link content - may be Wakka //tag//, interwiki //wikiname:page// tag, ##http/ftp/https/mailto## URL, [=] local or remote image-file for <IMG/> link, or [=] local or remote doc-file; if pagetag is for an external link but not protocol is specified, ##""http://""## is prepended
##method## - optional Wakka method (default ##'show'## method added in ##run()## function)
##text## - optional text or [=] image-file for HREF link (defaults to same as ##pagetag##)
##track## - link-tracking used by Wakka's internal link-tracking (inter-page cross-references in LINK table)
[=] //credits// - some extension ideas and code adapted from Wacko R3.5 variant of Wakka
[=] pagetag may include a '#' anchor-fragment
[=] if pagetag begins with '#' and text is empty, link is an <A name=".."> tag (i.e. page-anchor)
[=] if pagetag begins with '#' and text is non-empty, link is an intra-page link with text as content (text may be an image-file, for an intra-page image-link - e.g. for 'return to top')
[=] if pagetag is an image- or doc-file and text is not an image-link (see next), text is content for link ALT parameter
[=] text may be name of local or remote image-file - results in image-link
[=] image- and document-files are identified by filetypes listed in ##'image_types'## and ##'doc_types'## config-parameters respectively
[=] local image- or document-files are identified by no '/' in the filename, and must be in the folder pointed to by the config-parameter ##'image_path'## (defaults to ##/images##) or ##'doc_path'## (defaults to ##download##) respectively
[=] if link-class separator (defined by config-parameter ##'link_class'##, defaults to ##""||""##) is found in text, text is split into text (before separator) and class-info (after); class-info is inserted into <IMG/> tag (if either pagetag or text is an image-file) or <A> tag (all other cases), must be HTML-appropriate content (e.g. ALT, HEIGHT, WIDTH, ALIGN etc) and cannot include < or > (to minimise hacking...); class-info may also include ##useicon## or ##noicon## directive (see next)
[=] doc-file links optionally preceded by an icon for the respective doc-type; icons must be in folder pointed to by ##'icon_path'## (defaults to same as ##'image_path'##) and in GIF format with same name as doc-type (e.g. ##pdf.gif##); will be shown for all doc-files if ##'use_icons'## config-parameter is set (defaults to ##Y## - i.e. icon-display on); can be overruled by ##useicon## or ##noicon## directive in class-info
//bool// **is_wiki_name**(//string// text) -- return true if text conforms to Wakka's 'camel-case' page-name convention
//null// **track_link**(//string// tag) -- add tag (i.e. page-reference) to current list stored in SESSION link-table
//note// - used by Wakka's internal link-tracking - is effectively a private-function
//array// **get_link_table**() -- return current content of SESSION link-table
array is 0-index array of page-tags
//note// - used by Wakka's internal link-tracking - is effectively a private-function
//null// **clear_link_table**() -- clear and reset the current content of SESSION link-table
//note// - used by Wakka's internal link-tracking - is effectively a private-function
//null// **start_link_tracking**() -- switch on Wakka's internal link-tracking
//note// - used by Wakka's internal link-tracking - is effectively a private-function
//null// **stop_link_tracking**() -- switch off Wakka's internal link-tracking
//note// - used by Wakka's internal link-tracking - is effectively a private-function
//null// **write_link_table**() -- update (clear and refresh) the content of the LINK table for the current page-tag
//note// - used by Wakka's internal link-tracking - is effectively a private-function
in the LINKS table, the ##from_tag## field is the current page-tag (i.e. from ##get_page_tag()## function), the ##to_tag## field is a reference from the SESSION link-table
//string// **theme_header**() -- return the buffered output for the page-header
header-content is derived from the file pointed to by the 'header_action' config-parameter
[=] link-tracking is disabled for the header (otherwise any page referenced in the header is listed as linked to //every// page)
[=] header-action may be set individually for each sub-site or section, as selected by additional page-properties (see **//Configuration//** section)
[=] header is now processed //after// the page-body (see ##run()## function), so header-action may be selected in page-code (e.g. to output different headers for popup help-pages, or no header at all)
//string// **theme_footer**() -- return the buffered output for the page-footer
footer-content is derived from the file pointed to by the 'footer_action' config-parameter
[=] link-tracking is disabled for the footer (otherwise any page referenced in the footer is listed as linked to //every// page)
[=] footer-action may be set individually for each sub-site or section, as selected by additional page-properties (see Configuration section)
[=] footer is processed after the page-body, so footer-action may be selected in page-code (e.g. to output different footers for popup help-pages, or no header at all)
==== Forms ====
//string// **form_open**(//string// method=""''"", //string// tag=""''"", //string// formmethod='POST') -- return a <FORM> HTML-tag for the selected method and tag
##method## - optional (if empty, defaults to ##'show'## in ##run()## function)
##tag## - optional, defaults to current page-tag
FORM 'action' parameter is adjusted for Apache rewrite_method setting (i.e. Wakka ##'rewrite_method'## config-parameter)
[=] page-var for use when 'rewrite_method' is disabled can be set via ##'page_var'## config-parameter (defaults to ##wakka##)
//string// **form_close**() -- return a </FORM> HTML-tag
==== Interwiki stuff ====
//null// **read_interwiki**() -- read and store the content of the 'interwiki.conf' file, for use in interwiki links
//note// - the ##interwiki.conf## file, if present, must be in the root-directory
//null// **add_interwiki**(//string// name, //string// url) -- add an interwiki reference to this page's interwiki list
//note// - this list persists only for the duration of the processing for this page
//string// **get_interwiki_url**(//string// name, //string// tag) -- return a full interwiki URL
##name## - name of interwiki reference
##tag## - text to be appended to the interwiki URL
//warning// - returns nothing if the interwiki reference is not found - if so, this will result in null (and possibly invisible) HREF links
==== Referrers ====
//null// **log_referrers**(//string// tag=""''"", //string// referrer=""''"") -- if page-referrer is from outside this wiki, add it to the page's entries in the REFERRERS table
##tag## - optional Wakka page-tag (defaults to current page)
##referrer## - page-referrer (defaults to value of HTTP-server 'REFERER' (sic) parameter)
[=] this function also triggers optional flushing of outdated page-referrers as per ##'referrers_purge_time'## config-parameter (moved from ##maintenance()## function - same as in Wakka 0.1.2, but now triggered on each external-referrer reference rather than each page-view)
//array// **load_referrers**(//string// tag=""''"") -- return array of external referrers for this page-tag, sorted by number of references from each referrer, highest-first
##tag## - optional Wakka page-tag (defaults to current page)
returns 0-index array of record-arrays, each field-indexed as ##'referrer'## (URL) and ##'num'## (number of references)
====Plug-ins====
//string// **action**(//string// action, //bool// forcelinktracking=true) -- return buffered output of a ##""{{..}}""## page-action
##action## - name of action-file followed by optional arbitrary-length list of parameters in ##parameter=".."## format
action-file is name of file (//without// ##.php## - that's added automatically here) in any directory listed in the ##'action_path'## config-parameter (see Includebuffered() function)
parameter-names are case-sensitive and must be alphanumeric (i.e. '##_##' is not allowed); each parameter and its value is added to the symbol-table available to the action's code
//string// **method**(//string// method) -- return buffered output of (usually) processing the current page with the selected method
##method## - name of method-file (//without// ##.php## - that's added automatically here)
the directory pointed to by the ##'handler'## config-parameter (defaults to ##page##) is prepended as part of the method, as the 'method-location'
the 'method-location' (with '.php') may be in any directory listed in the ##'handler_path'## config-parameter (see ##Includebuffered()## function)
//string// **format**(//string// text, //string// formatter='wacko') -- return buffered output of processing the 'text' parameter with the selected formatter
##text## - text to be processed (formatted)
##formatter## - name of formatter-file (//without// ##.php## - that's added automatically here)
the file must be in the ##./formatter## directory
the ##text## parameter and its value are added to the symbol-table available to the formatter's code
==== Users ====
//array// **load_user**(//string// name, //bool/string// password=0) -- return user-record for selected user, with optional password check
##name## - user-name in USERS table
##password## - optional; if non-zero, only return values if both user-name and password match
returns fieldname-indexed array of all matching fields in USERS table, or empty array if user not found or if password provided but does not match
//array// **load_users**() -- return array of all current user-records, sorted by user-name
returns 0-index array of user-records, each record as fieldname-indexed array of all matching fields in USERS table
//warning// - this may be resource-intensive
//string// **get_user_name**() -- return name of or identifier for current user
returns user-name if user is logged-on, otherwise extracts a host-name or IP address from the HTTP 'SERVER_ADDR' parameter
//warning// - on a closed intranet or local server, change the ##gethostbyaddr()## function in the code to a simple copy from 'SERVER_ADDR', as the failed ##gethostbyaddr()## search may add //many seconds// to the page runtime
//string// **user_name**() -- same as get_user_name() (//deprecated//)
//array// **get_user**() -- return the user-info (if any) from the current session
//null// **set_user**(//array// user) -- store the user-info for the current user in the current session
//note// - adds the user-name and password to the user-info as ##'name'## and ##'password'## fields respectively
//warning// - storing the password in a session-parameter may be a security issue where sessions are stored in cookies
//null// **logout_user**() -- logs out the current user by deleting the user-info from the current session
//warning// - the current password is stored in a separate session-cookie - this may be a security issue
//bool// **user_wants_comments**() -- return true if the user is logged-on and has set their default ##'wants_comments'## user-info parameter to ##Y##
==== Comments ====
[=] //array// **load_comments**(//string// tag, //bool// reverse=false, //int// limit=0) -- return array of comment-'pages' associated with selected tag
##tag## - name of page for which to search for associated comments
[=] ##reverse## - optional sort-order selector: if false, sorts earliest-first (default, as per Wakka 0.1.2), if true, sorts most-recent-first
[=] ##limit## - optional limit on number of comments - if non-zero, limits the comment-count as per the specified order
combined, these two additions also support a simple weblog mechanism, with entries as 'comments' to a base-page sorted in reverse date-order and limited to the selected number of entries
returns 0-indexed array of page-records, without additional page-properties (see ##load_page()## function)
//array// **load_recent_comments**() -- return array of all comments, in reverse date-order
//note// - the time used for the sort-order is that of the comment, not the base-page
//warning// - this function returns all content of **all** comments, and may be resource-intensive
//array// **load_recently_commented**(//int// limit=50) -- return array of page-records sorted by most-recent-comment
##limit## - optional limit on number of comments processed
returns 0-indexed array of page-records, without additional page-properties (see ##load_page()## function), but with extra fields ##'comment_user'##, ##'comment_time'##, ##'comment_tag'## (respectively the user, time and page-tag of the respective comment-'page')
[*] //bool// **allows_comments**() -- returns false if no user can write comments to the current page
//note// - is used by a modified ##'show'## method to prevent the view/edit comments section of the footer from being displayed if no user can write comments
==== Access control ====
//bool// **is_owner**(//string// tag) -- return true if the current user is the 'owner' of the selected page
##tag## - optional page-tag - defaults to current page
//note// - returns false if the current user is not logged on
[*] //bool// **is_admin**() -- return true if the current user is a system administrator
system-admins are identified in the (additional) config-parameter ##'sysadmin_acl'## (comma-separated list of user-ids and/or user-groups - see ##has_access()## function)
//string// **get_page_owner**(//string// tag, //string// time=""''"") -- return user-id of selected page or page-revision
##tag## - optional page-tag - defaults to current page
##time## - optional revision-version time
//null// **set_page_owner**(//string// tag, //string// user) -- set selected user as the 'owner' of the selected page (i.e. user 'claims' the page)
##tag## - page-tag of page 'claimed'
##user## - user-id of user 'claiming' the page
[=] //array// **load_acl**(//string// tag, //string// privilege, //bool// usedefaults=true, //bool// forceload=false) -- return access-control/page-property record for selected page-privilege/property
##tag## - page-tag for requested privilege/property
##privilege## - name of privilege/property requested
##usedefaults## - if true and respective page-privilege record not found, use respective default privilege from ##'default_read_acl'##, ##'default_write_acl'## or ##'default_comment_acl'## config-parameter ([=] not used for extended page-properties)
[=] ##forceload## - if false, attempt to read from current page-properties (including privileges) first; if true, force privilege/property to be loaded from ACLS table (as per Wakka 0.1.2)
returns fieldname-indexed array of ##'page'## (tag), ##'privilege'## and ##'list'## - latter is newline-separated list of names ([=] and/or user-groups) for access-control rights ([=] or page-property value for other 'privilege' labels)
[=] //note// - extended page-properties are stored in the ACLS table, as for ACL access-control privileges
//null// **save_acl**(//string// tag, //string// privilege, //string// list=""''"") -- save selected page-privilege/property in ACLS table
##tag## - page-tag for requested privilege/property
##privilege## - name of privilege/property to be stored
##list## - access-control list ([=] or extended page-property) to be stored
[*] //null// **delete_acl**(//string/array// tag, //string/array// privilege, //string/array// list=""''"") -- delete page-properties for specified tag(s) and/or property-type(s) and/or content
##tag## - page-tag or 0-indexed array of page-tags
##privilege## - extended page-property name or 0-indexed array of page-property names
##list## - property content or 0-indexed array of content-values
//note// - this function is mainly used internally to keep the ACLS table free of empty or unused extended page-property records, and also by the added ##'delete'## method to delete a complete page
[*] //string// **mysql_quote_str**(//string/array// value) - return a string suitable for use in a Mysql 'IN' clause
##value## - string or array of string to which the PHP ##mysql_escape_string()## function is to be applied
//note// - for consistency with other code, the string returned does //not// include the outermost '..' characters needed in the final Mysql query
[*] //bool// **has_rights**(//string// rights) -- return true if current user has any of the specified access-rights
##rights## - comma-separated list user-ids and/or user-groups (see ##has_access()## function)
//note// - returns false if current user is not logged on (use less resource-intensive ##get_user()## function to test for logged-on status)
//bool// **has_access**(//string// privilege, //string// tag=""''"", //string// user=""''"") -- return true if the specified user has the specified access-rights to the specified page
##privilege## - type of access-right to be tested - either ##'read'##, ##'write'## or ##'comment'##
##tag## - page-tag on which to test for rights (defaults to current page)
##user## - user-id if user for access-rights test (defaults to current user)
always returns true if the user-id matches the page-'owner' (see ##is_owner()## function) or [=] belongs to a system-administrator group (see ##is_admin()## function)
returns true if the user-id matches any of the wildcard keys ##'*'## any-user, or ##'$'## any logged-on user, or any of the specific user-ids (or, [=] recursively, any user-groups), listed in the ##list## parameter for this tag and privilege in the ACLS table or, if no record is found in ACLS, in the respective ##'default_read_acl'##, ##'default_write_acl'## or ##'default_comment_acl'## config-parameter
returns false if the user-id does not match, is explicitly blocked by a ##'!'## prefix, or the list is present and empty
[*] //bool// **test_access**(//string// list, //string// user, //bool// is_registered) -- provides recursive support for access-rights checks
//note// - this is effectively a private support-function for ##is_admin()##, ##has_rights()## and ##has_access()##
[*] //array// **load_groups**() -- return array of names of all user-groups
array is 0-indexed list of user-groups
==== XML support ====
//null// **write_recent_changes_xml**() - generate RSS 0.92-spec XML file summarising recent changes
//note// - generates/overwrites a single hardwired ##recentchanges_//name//.xml## file in the ##/xml## directory, where ##//name//## is derived from the sites ##'wakka_name'##' config-parameter
==== Templates ====
This new [*] section provides support for templates, to separate visual code (HTML/CSS) from logic code (PHP).
Templates are standard HTML files, or just PHP strings, with substitution-markers in the form ##{//marker//}##, and optional blocks to extract and replace - recursively if required - in the form ##//content//##. Blocks and substitution markers may be nested as required. For a simple example, see the ##menu_out()## function in the //Menu// section below.
Handles and markers are case-independent.
The following additional config-parameters are used:
- ##'tpl_unknowns'## - substitution of 'undefined' marker-blocks (see ##tpl_getundefined()## function): either ##'keep'## (leave unchanged - default), ##'remove'## (delete from the output) or ##'comment'## (replace with a #### HTML comment)
- ##'tpl_halt_on_error'## - action on error: either ##'yes'## (halt on error - default), ##'report'## (insert a warning-message in the output stream) or ##'ignore'## (ignore the error and try to continue)
- ##'tpl_path'## - directory-path for templates: default to ##./templates##
//Credits// - this section is based on Kristian Koehntopp's Template library for ""PHPLib""
[*] //bool// **tpl_setfile**(//string/array// handle, //string// filename=""''"") -- associate a filename with a matching template-handle (or filenames with handles)
##handle## - template-handle or, if array, array of handle=>filename pairs
##filename## - name of template file (should be blank if ##handle## is an array)
returns ##false## if any filename is blank or any file is not found
//note// - this only assigns filenames to handles - file-loading does not take place until a ##tpl_setblock()##, ##tpl_subst()## (usually via ##tpl_parse()##) or ##tpl_getundefined()## function is called
[*] //bool// **tpl_setblock**(//string// parent, //string// handle, //string// name=""''"") -- extract a named block from the template-handle
##parent## - template-handle of parent-block (will attempt to load associated file if not yet loaded)
##handle## - template-handle in which to store extracted block
##name## - optional handle-name to insert in parent-block in place of extracted block (if not present, ##handle## value will be used as name)
markers for blocks to extract take the form ##//content//##, where //handle// is the name to use here as the value of the ##handle## parameter, and //content// is the block to be associated with //handle//
when the function completes, the extracted block is replaced in the parent-block with ##{//handle//}## or ##{//name//}##
the ##name## parameter is used when the content will be constructed repeatedly, such as in a table-output loop, and the resultant content finally copied back to ##handle## - see ##Tpl_parse()## function
[*] //null// **tpl_setvar**(//string/array// handle, //string// value=""''"") -- assign content for a template-handle or a set of template-handles
##handle## - template-handle or, if array, array of handle=>value pairs
##value## - content to assign (should be blank if ##handle## is an array)
[*] //string// **tpl_subst**(//string/array// handle) -- return result of substituting content for the respective markers in the block(s) specified by //handle//
##handle## - template-handle, or 0-indexed array of template-handles, for block(s) in which to perform substitution
will perform substitution for any markers found in ##handle##'s block(s)
//note// - the key difference between this function and ##Tpl_parse()## is that this does //not// change the content stored in ##handle##'s block(s) - the result of the substitution is returned but not stored by this function
[*] //string// **tpl_parse**(//string// target, //string/array// handle, //bool// append=false) -- return result of performing marker/content substitution in //handle//, also storing the result in //target//
##target## - destination-handle to store the result
##handle## - source-handle for content in which marker-substitution will take place
##append## - if true, append the result to any existing content held by ##target##
//note// - ##append## is typically used when markers in content pointed to by ##handle## are to be substituted with new content repeatedly in a loop, such as when processing a recordset from a query; the content held by ##handle## is //not// changed in the substitution, but the content of target is
//note// - if ##append## is true, ##handle## must be a string, not an array
[*] //string// **tpl_getvar**(//string// handle) -- return content held by //handle//
[*] //array// **tpl_getvars**(//array// handles=""''"") -- return array of content-strings content held by //handles//, or all content
##handles## -- 0-indexed array of handles for which to return content (if empty, returns content of all current handles)
returns handle-indexed array of strings
[*] //array// **tpl_getundefined**() -- return array of apparent handles in template for which no content has been defined
returns handle-indexed array of apparent-handle names
returns false if no 'undefineds' are found
//note// - 'undefineds' will occur if the text contains any arbitrary ##{..}## blocks
[*] //string// **tpl_out**(//string// handle) -- return content held by //handle// after processing of any 'unknowns'
//note// - 'unknowns' (i.e. un-substituted apparent markers) will occur if the text contains any arbitrary ##{..}## blocks: if any part of your template includes code or other probable occurrences of ##{..}## (such as providing a summary of Wakka formatting on a template for an edit-form), you should ensure that the ##'tpl_unknowns'## config-parameter is set to ##'keep'##
[*] //null// **tpl_print**(//string// handle) -- print content held by //handle// after processing of any 'unknowns'
//note// - this is just a shorthand for ##print($this->tpl_out($handle))##
==== Menus ====
This new [*] section supports automated generation of code for various types of menus, using the Template section above. For example, using the default parameters, the final menu-output call
##$out=$this->menu_out('{NAME}=new Array("{TEXT}","{LINK}","////",{COUNT},{HEIGHT},{WIDTH});'."\n",""''"",true);##
generates Javascript code compatible with Ger Versluis' well-known ##""HVMenu""## package for nested popout menus (see http://www.dynamicdrive.com ).
Template parameters for each menu-item are:
- ##{NAME}## - assigned name, or ""HVMenu""-compatible default of ##Menu## followed by the auto-generated item-handle
- ##{TEXT}## - text for the link, or copy of the original link (e.g. Wakka tag) as default
- ##{LINK}## - URL for the menu-item, including any Wakka method defined as default in the menu-initialisation
- ##{COUNT}## - auto-generated count of any 'child'-items in a sub-menu attached to this item
- ##{HEIGHT}## - common height-value for all items in this menu or sub-menu (may be different for each sub-menu)
- ##{WIDTH}## - common width-value for all items in this menu or sub-menu, as for ##{HEIGHT}##
A minimum menu using an item-string ##$menu## returned by ##make_tree()## (see ##menu_item()## function) and using the template-string above (as ##$tpl##) would be as follows:
##$this->menu_init();## ""//""initialise menu using standard defaults
##$menuhandle=$this->menu_set(20,120);## ""//""set typical default cell-sizes for ""HVMenu""
##$itemhandle=$this->menu_item($menu);## ""//""generate menu-items from make_tree list
##$out=$this->menu_out($tpl,""''"");## ""//""generate single-layer menu without recursion##
The handles ##menuhandle## and ##lastitemhandle## returned from the ##menu_set()## and ##menu_item()## functions respectively are not used in this simple example, but would be used to keep track of nesting in multi-layered menus.
[*] //null// **menu_init**(//string// method=""''"", //string// fsep='|', //string// rsep="~") -- initialise the menu-data store
##method## - Wakka 'method' to be used for all output links
##fsep## - field-separator for multi-link strings (see ##menu_item()## function)
##rsep## - record-separator for multi-link strings
[*] //string// **menu_set**(//string// height, //string// width, //string// parent=""''"", //string// name=""''"") -- return handle for new sub-menu attached to the //parent// item
##height## - height for all entries in this sub-menu (required for ""HVMenu"", not required for some other menu-types - will be substituted for any ##{HEIGHT}## marker in the output-template)
##width## - width for all entries in this sub-menu (required for ""HVMenu"", not required for some other menu-types - will be substituted for any ##{WIDTH}## marker in the output-template)
##parent## - handle for parent-item to which this menu will be attached; if blank, most-recent menu-item will be used as parent
##name## - name to be used as menu-descriptor (not used at present, reserved for future use)
returns a menu-id in the form ##//i//_//j//_//k//...##, representing the parent item (see ##menu_item()## function), or the string ##:root:## for the root-level menu
[*] //string// **menu_item**(//string// text, //string// link=""''"", //string// parent=""''"", //string// name=""''"") -- return handle for new menu-item(s) attached to the //parent// menu
##text## - text to be shown for the menu-item (but note special ase described below)
##link## - tag or other URL content for the link, to be output through the ##href()## function
##parent## - handle for parent-menu to which this item will be attached; if blank, most-recent menu will be used as parent
##name## - content for the ##{NAME}## output-parameter; if absent, default of ##Menu## followed by the auto-generated item-handle will be used
returns an item-id in the form ##//i//_//j//_//k//..## (e.g. ##2_5_3##), where //i//, //j//, //k// and so on are the respective item-numbers of the items in this menu-tree, with the last number representing this item
//special case// - if ##link## is blank and ##text## contains at least one match to the ##fsep## field-separator string defined in the menu-initialisation, the string is 'unpacked' as a set of menu-item records, separated by the ##rsep## record-separator, and with each record in the form //link// //fsep// //text// (e.g. ##""HomePage|Home page""##); this is compatible with the output from the ##make_tree()## function
[*] //string// **menu_out**(//string// tpl, //string// id=":root:", //bool// recurse=false) -- return the result of processing the menu-data with the specified template
##tpl## - template-string (as described at the start of this section)
##id## - menu-id of the sub-menu to which this template will be applied; if blank, applies (or starts) at the root-level menu
##recurse## - if false, applies the template to this menu only; if true, applies the template recursively to this template and all of its 'children'
[*] //array// **menu_get**(//string// id=""''"", //bool// type) -- return stored content for a menu or menu-item
##id## - menu-id or item-id, dependent on ##type##; if empty, return the menu-data array for the root-level menu
##type## - if false, return menu-data array (default); if true, return item-data array
//note// - for further details, see the code; this is effectively a private function but may be useful in some cases where direct manipulation is needed
[*] //int// **menu_count**(//string// id=""''"") -- return the item-count for the selected menu
##id## - menu-id; defaults to ##:root:##, for the root-level menu
//note// - for compatibility with ""HVMenu"", output the Javascript string
"var NoOffFirstLineMenus=".$this->menu_count();
==== Run (and support for Run) ====
[*] //null// **page_init**() -- ensure that absolute defaults are applied to any undefined essential config-parameters
//note// - see the code for details of these config-parameters - mostly for the amended ##link()## function
//null// **maintenance**() -- do basic database housekeeping ([=] //deprecated//, does nothing)
//note// - in the original Wakka 0.1.2 code, this does housekeeping for outdated page-versions and referrers; whilst it's necessary that this be done regularly, it's //not// necessary to do so on every page-view; in this Wakka variant housekeeping for outdated page-versions is handled more appropriately by ##save_page()##, and for referrers by ##log_referrer()##
//null// **run**(//string// tag, //string// method=""''"") -- generate the output page for the specified tag and method
##tag## - page-tag for page-content to be output
##method## - processing method for page-content (see ##method()## function), defaults to ##'show'## method
[=] a number of minor but significant changes:
- loads config-parameters in cascaded form, overlaying the basic ##wacko_config## parameters (already defined by this point) with config-parameters for a subsite (if any) specified by a ##'section'## extended page-property for the current-page, and then overlaying any parameters defined for the section (if any); this provides flexibility to allow directories, menus, templates, layouts, headers, footers all to change on a per-section and per-subsite basis (and also on a per-page basis, in some cases)
- default show, edit and print methods can also change on a per-subsite/section basis, as defined by optional ##'show_method'##, ##'edit_method'## and ##'print_method'## config-parameters respectively
- the horrible 'method ending in ##.xml##' kludge for outputting null-header pages is bypassed by a cleaner process of setting header- and footer-action to the string ##'null'## (though the original process is still supported for backward compatibility)
- although still output in the same header/main/footer sequence, the main content is processed //before// the header, allowing page-content code to select the output header and footer dependent on run-time context
==== Extended page-properties ====
Although in principle any number of properties could be defined, the following are some typical examples which I've used in my (TomG's) own code, and which I edit through a modified ##'edit'## page-method:
- ##headline## - substitute for page-tag as page-headline (defaults to Wakka page-tag)
- ##shortname## - shorter (usually) version of headline for use in menus and breadcrumb-trails (defaults to Wakka page-tag)
- ##title## - content for HTML tag
- ##description## - content for HTML tag
- ##parent## - tag of 'parent' in a parent/child trail, e.g. for a menu or breadcrumb-trail (default is blank, i.e. a standard Wakka 'everything is at root-level' page)
- ##section## - specifies the member of the ##sections## config-parameter array to use to overlay the standard config-parameters; this in turn may include a ##'site'## config-parameter to select the respective member from the ##sites## config-parameter array
The optional ##sites## and ##sections## arrays in the config-parameters contain arrays of overlays for higher-level config-parameters; if absent, the result is exactly the same as the Wakka 0.1.2 standard configuration-file. In principle the ##sites## and ##sections## arrays could contain overlays for //any// config-parameters, though in practice they will not affect the start-up parameters (Mysql configuration) and should not change key parameters such as ##'base_url'##, ##'table_prefix'## and ##'rewrite_mode'## (though there's nothing to stop them from doing so should the need arise!)
=== To Do ===
* adaption for WackoWiki API -> core developers