show_menu2, version 4.9.x
=========================
A code snippet for WBCE CMS. All menu data is retrieved using 
a single database query, all types of menu styles (lists, breadcrums, sitemaps) 
can be generated with extensive customisation of the resulting HTML.



INSTALLATION
============
There is no installation necessary since the module is a built-in core module.
   
   
USING SHOW_MENU2
================
You need to modify the PHP files of your template to call show_menu2 where you 
wish to have the menu displayed. Remember when you replace calls to the old
menu functions to use the new parameters that show_menu2 requires. 

Please note that the old, outdated show_menu() call is no longer supported!

In some cases the default menu generated by show_menu2 is all that you need.
This menu shows the current page and children of the current page. It is
generated by just calling show_menu2 with no parameters. For example:

    show_menu2();
    
Note that the call to show_menu2 is PHP, so you usually need to wrap it in the
PHP code brackets so that it will execute. Like this:

    <?php show_menu2(); ?>

This default menu generates a complete list based menu with many classes that
allow  CSS styling. For example, the current menu item will have the
"menu-current" class added to the <li> tag. Additionally, every menu item with
a sub-menu will have the "menu-expand" class added to the <li> tag. This allows 
you to create CSS rules to style those menu items differently. For example:

    li.menu-expand  { font-weight: bold; }
    li.menu-current { background: red; }

See the "Output" section for details of exactly what classes are added to each 
element. More elaborate and different menu structures are able to be created by 
supplying different parameters to the show_menu2 function call. For example, 
to show only menu items from the top level of the menu you use:

    show_menu2(0, SM2_ROOT, SM2_START);
    
Alternatively, to show up to two levels of the child menus of the current page:

    show_menu2(0, SM2_CURR+1, SM2_CURR+2);

There are many more possible menus that can be generated by show_menu2. See the
demonstration website at https://sm2.wbce-cms.org/ for more examples. 



COMMON QUESTIONS
================

Q:  I'm not a programmer. Do you have simpler documentation? 
A:  Nup. This is it. Go hard. Gambarre.


Q:  How do I create a drop-down menu?
A:  This is not directly related to show_menu2. Basically you need to change 
    the template CSS code to display the menu as a drop-down. 


Q:  Why does the menu disappear after I do a search on my multilingual site?
A:  You're missing some required lines in your template.

    1.  Log into administration, and go to Settings -> Show advanced settings 
        -> Search Settings -> Header Code and add the following input field 
        after the <form> open tag: 

        <input type="hidden" name="referrer" value="[REFERRER_ID]" />


    2.  In the index.php of your template, add the following input field 
        immediately following the search <form> open tag.

        <input type="hidden" name="referrer" value="<?php echo defined('REFERRER_ID')?REFERRER_ID:PAGE_ID;?>" />


Q:  Multilingual? That sounds cool. How do I do that?
A:  A:  https://addons.wbce.org/pages/addons.php?do=item&item=3


Q:  SM2 is generating a warning every time the page is accessed:
    "show_menu2 error: $aOptions is invalid. No flags from group 1 supplied!"
A:  You are passing the wrong values to the function. Have a closer look at the 
    parameters that you are passing. See the PARAMETERS section below for the 
    correct flag values to pass for the $aOptions parameter.


Q:  How do I use a different class/picture/color/widget for each entry in a menu?
A:  Use the [page_id] format string in the $aItemOpen string. Create a unique 
    class or id for each menu item, then reference that item in your CSS or Javascript
    to do whatever you want.
    
    To add a unique class for each menu item (or similar):
    
        "<li><a href="[url]" target="[target]" class="[class] p[page_id]">[menu_title]</a>"

        ... creating menu items like ...
    
        <li><a href="/pages/foo/bar.php" target="_top" class="menu-top p45">Top Menu</a>

        Reference this in your CSS like:
        
        a.p45 { color: red; }
    
    To add a unique ID for each menu item (or similar):
    
        "<li><a id="p[page_id]" href="[url]" target="[target]" class="[class]">[menu_title]</a>"
    
        ... creating menu items like ...
    
        <li><a id="p45" href="/pages/foo/bar.php" target="_top" class="menu-top">Top Menu</a>

        Reference this in your CSS like:
        
        a#p45 { color: red; }
        
        Note that the ID can only be used if that menu is generated and displayed one time
        only on the page (because HTML ID's must be unique within a page). 
    


FUNCTION
========

The complete call signature and default parameter value for show_menu2 is:

    show_menu2(
        $aMenu          = 0,
        $aStart         = SM2_ROOT,
        $aMaxLevel      = SM2_CURR+1,
        $aOptions       = SM2_TRIM,
        $aItemOpen      = '[li][a][menu_title]</a>',
        $aItemClose     = '</li>',
        $aMenuOpen      = '[ul]',
        $aMenuClose     = '</ul>',
        $aTopItemOpen   = false,
        $aTopMenuOpen   = false
        )

See the "Parameters" section for detailed descriptions of each parameter.
Ensure that you use each parameter correctly. Use the following rules:

    $aMenu will be 0 for most people.
    
    $aStart must be either a page ID or a value starting with "SM2_".
    
    $aMaxLevel must be only values that start with "SM2_".
    
    $aOptions must be only values that start with "SM2_" (unless you are 
    in a very small minority of users).
    
    All other parameters are the HTML tag templates that will be 
    output for menus and menu items.
    
Note that every parameter from $aItemOpen can be supplied as false to get 
the default value.



HTML OUTPUT
===========
The menu is output differently depending on what parameters have been 
supplied to the function, however in general the following classes are used 
for each menu. Note that items will have multiple classes when relevant.

    CLASS           ATTACHED TO
    ------------    -------------------------------------------------------
    menu-top        First menu tag only
    menu-parent     Every parent menu item of the current page.
    menu-current    Only the menu item for the current page.
    menu-sibling    Every sibling of the current page.
    menu-child      Every sub-menu of the current page.
    menu-expand     Every menu item with children.
    menu-first      First item in any menu or sub-menu.
    menu-last       Last item in any menu or sub-menu.

    The following classes are added only if SM2_NUMCLASS flag has been used.

    menu-N          Every menu item. The N is replaced with the ABSOLUTE 
                    menu depth of the item starting with 0. The root level 
                    menu is always menu-0, the next level is menu-1, etc.
    menu-child-N    Every sub-menu of the current page, the N is replaced 
                    with the relative depth of the submenu starting at 0.


<ul class="menu-top menu-0">
  <li class="menu-0 menu-first">  ... </li>
  <li class="menu-0 menu-expand menu-parent">  ...
  <ul class="menu-1">
    <li class="menu-1 menu-expand menu-first">  ...
    <ul class="menu-2">
      <li class="menu-2 menu-first">  ...
      <li class="menu-2 menu-last">  ...
    </ul>
    </li>
    <li class="menu-1 menu-expand menu-parent">  ...
    <ul class="menu-2">
      <li class="menu-2 menu-expand menu-current menu-first">  ...      ** CURRENT PAGE **
      <ul class="menu-3">
        <li class="menu-3 menu-child menu-child-0 menu-first">  ...
        <ul class="menu-4">
          <li class="menu-4 menu-child menu-child-1 menu-first">  ... </li>
          <li class="menu-4 menu-child menu-child-1 menu-last">  ... </li>
        </ul>
        </li>
        <li class="menu-3 menu-child menu-child-0 menu-last">  ... </li>
      </ul>
      </li>
      <li class="menu-2 menu-sibling menu-last">  ... </li>
    </ul>
    </li>
    <li class="menu-1">  ... </li>
    <li class="menu-1 menu-expand menu-last">  ...
    <ul class="menu-2">
      <li class="menu-2 menu-first menu-last">  ... </li>
    </ul>
    </li>
  </ul>
  </li>
  <li class="menu-0 menu-last">  ... </li>
</ul>



PARAMETERS
==========
$aMenu      
    Menu number to use. This is useful when you are using multiple menus. 
    Supplying a menu number of 0 will use the default menu for the current 
    page. Supplying SM2_ALLMENU will return all menus in the system.

$aStart  
    Specify where the menu generation should start from. This is most
    times the parent item of the menu to display. It must be one of the 
    following values:
        SM2_ROOT+N  Start N levels down from the root. e.g.
                      SM2_ROOT      Starting at the root menu 
                      SM2_ROOT+1    Start 1 level below the root
                      SM2_ROOT+2    Start 2 levels below the root
        SM2_CURR+N  Start N levels down from the current page level. e.g.
                      SM2_CURR      Starts at the current page level. All
                                    sibling menus to the current page.
                      SM2_CURR+1    Starts 1 level down from the current
                                    page with the children menus.
        page_id     Display using the specific page as the parent. All
                    child menus of that page will be displayed. The 
                    page_id can be found by editing the page in WB admin 
                    interface. The page_id is included in the URL like: 
                        http://SITE/admin/pages/modify.php?page_id=35

$aMaxLevel   
    Maximum menu level to display. Menus are displayed from the start
    level down to this level.
        SM2_ALL     No limit, all levels are displayed
        SM2_CURR+N  Always show to the current page + N levels. 
                      SM2_CURR      Current (no children)
                      SM2_CURR+3    All parents + current + 3 children
        SM2_START+N Always show from the starting level + N levels. The
                    levels of menu will always be displayed regardless of
                    what level the current page is.
                      SM2_START     Single level of menus from starting level
                      SM2_START+1   Starting level and 1 level down
        SM2_MAX+N   Show at most N levels from the starting level. Levels 
                    won't be shown if they are below the current level.
                      SM2_MAX       Starting level only (same as SM2_START)
                      SM2_MAX+1     Maximum of starting level and 1 level.

$aOptions  
    Specify flags for different generation options for the menu. The flags
    may be combined together using bitwise OR (|). For example, to specify
    both TRIM and PRETTY you should use, (SM2_TRIM | SM2_PRETTY).

    GROUP 1
    -------
    Exactly one flag from this group must always be supplied. These flags 
    affect how the siblings in the tree are removed from the output. 

    SM2_ALL         Show all branches of the menu tree
                        A-1 -> B-1 
                            -> B-2 -> C-1
                                   -> C-2 (CURRENT)
                                          -> D-1
                                          -> D-2
                                   -> C-3
                        A-2 -> B-3
                            -> B-4
    SM2_TRIM        Show all sibling menus of pages on the current path. 
                    All sub-menus of elements that are not on the path 
                    are removed.
                        A-1 -> B-1 
                            -> B-2 -> C-1
                                   -> C-2 (CURRENT)
                                          -> D-1
                                          -> D-2
                                   -> C-3
                        A-2 
    SM2_CRUMB       Show only the breadcrumb trail, i.e. the current
                    menu and all of it's ancestor menus.
                        A-1 -> B-2 -> C-2 (CURRENT)
    SM2_SIBLING     The same as SM2_TRIM however only sibling menus of 
                    the current page are displayed. All other menus are 
                    trimmed to show only the path.
                        A-1 -> B-2 -> C-1
                                   -> C-2 (CURRENT)
                                          -> D-1
                                          -> D-2
                                   -> C-3

    GROUP 2
    -------
    All of these flags are optional. Any number of them may be combined.

    SM2_NUMCLASS    Add the numbered menu classes to the menu. If this 
                    flag is supplied, the "menu-N" and "menu-child-N" 
                    classes will be added.
                    
    SM2_ALLINFO     Load all fields from the page table of the database.
                    This will result in quite a lot of memory being used
                    and is not recommended, however it will make keywords,
                    descriptions, and other fields available. This data
                    is not loaded by default.
                    NOTE: This flag must be used on the *FIRST* call to
                    show_menu2 *for this menu ID*, or in combination with
                    SM2_NOCACHE otherwise it will have no effect.
                    
    SM2_NOCACHE     Do not reuse or store the data read from the database
                    between calls to show_menu2. 
                    
    SM2_PRETTY      Pretty print the menu HTML with spacing and newlines
                    for debugging purposes.
                    
    SM2_BUFFER      Do not output the menu HTML but instead buffer it 
                    internally and return it as a string from show_menu2.
                    
    SM2_CURRTREE    Exclude all other top level menus from being considered. 
                    Only items in the current menu tree will be output.
                    This can be combined with any of the Group 1 flags as
                    necessary.
                    
    SM2_ESCAPE      Call htmlspecialchars on the menu strings. This may be
                    required with older installations of WB. By escaping the
                    raw database strings, it permits menus to have HTML 
                    formatting in them that would cause otherwise cause
                    pages to fail validation. 
    
    SM2_SHOWHIDDEN  Hidden pages are usually hidden all of the time, including 
                    when they are active (i.e. current page or a parent page).
                    Use private pages for time when you want pages to be
                    hidden except when active. However for compatibility with
                    release 4.8, supply this flag to enable hidden pages to
                    become visible when they are active.

    SM2_XHTML_STRICT	From all links, created by [a] or [ac], the 'target' -
					attribute will be removed to preserve the XHTML-Compatibility

	SM2_NO_TITLE	Supress the value of the 'title'-attributes on links which
					are created by [a] or [ac] formatted links.

    This parameter also has an extended mode where an associative array of 
    options is supplied. See the EXTENDED OPTIONS section for details. 
    Most users will NOT need to use this.

$aItemOpen
    Format string to use for creating each individual menu item entry.
    A different format string may be used for the very first entry by 
    supplying a different format string for $aTopItemOpen. When set to 
    false, it uses the default of '[li][a][menu_title]</a>' to maintain
    compatibility with show_menu(). Note however that CSS formatting is
    often easier if the classes are added to the <a> tag. Use the format
    string of '<li>[ac][menu_title]</a>' for this style of tag.

    This parameter may also be specified as an instance of a formatting 
    class for the menu. See the section "Formatter" below for details of
    the API this class must expose. When a formatter is supplied, all 
    arguments after $aItemOpen are ignored.

$aItemClose
    String used to close each item. Note that this is not a format
    string and no keywords will be replaced. When set to false, it uses 
    the default of '</li>'.

$aMenuOpen
    Format string to use for opening a list of menu item entries. A 
    different format string may be used for the very first menu by 
    supplying a different format string for $aTopMenuOpen. When set to 
    false, it uses the default of '[ul]'.

$aMenuClose
    String used to close each menu. Note that this is not a format
    string and no keywords will be replaced. When set to false, it uses 
    the default of '</ul>'.

$aTopItemOpen
    Format string for the first item. When set to false, it uses the same 
    format as $aItemOpen.

$aTopMenuOpen 
    Format string for the first menu. When set to false, it uses the same 
    format as $aMenuOpen.



EXTENDED OPTIONS
================
The $aOptions parameter is a dual mode parameter. For most users, only the
SM2_* flags will be sufficient. However, to access the extra options, it 
must be supplied as an associative array. Note that the SM2_* flags are
still required and must be supplied as 'flags'.

    'flags'     **REQUIRED** These are the flags described in PARAMETERS
                above for the $aOptions parameter. 

    'notrim'    Specify a number of levels relative to the menu level of 
                $aStart that will always be displayed. This will cause the
                SM2_TRIM flag to be ignored for these levels.
                        
To supply one of these options in addition to the flags, the option array 
should be created and passed as the $aOptions parameter:

    $options = array('flags' => (SM2_TRIM|...), 'notrim' => 1);
    show_menu2(0, SM2_ROOT, SM2_CURR+1, $options);
    
    
    
FORMAT STRINGS
==============
The following tags may be included in the format strings for $aItemOpen and 
$aMenuOpen and will be replaced with the appropriate text.

[a]             <a> tag (no class):         '<a href="[url]" target="[target]">'
[ac]            <a> tag including class:    '<a href="[url]" target="[target]" class="[class]">'
[li]            <li> tag including class:   '<li class="[class]">'
[ul]            <ul> tag including class:   '<ul class="[class]">'
[class]         List of classes for that page
[menu_title]    Menu title text (HTML entity escaped unless SM2_NOESCAPE flag is used)
[menu_icon_0]	URL poining to an image for display normal - status
[menu_icon_1]	URL poining to an image for display active/hover - status
[page_title]    Page title text (HTML entity escaped unless SM2_NOESCAPE flag is used)
[page_icon]		URL poining to an image relating to the current page
[url]           Page URL for the <a> tag
[target]        Page target for the <a> tag
[page_id]       Page ID of the current menu item
[parent]        Page ID of the parent menu item
[level]         Page level, the same number as is used for the "menu-N" CSS tag.
[sib]           Current menu sibling number
[sibCount]      Total number of siblings in this menu
[if]            Conditional test (see section CONDITIONAL FORMATTING)

The following tags are only available when the SM2_ALLINFO flag is used.

[description]   Page description
[keywords]      Page keywords



CONDITIONAL FORMATTING
======================
The conditional formatting directive takes one of the following forms:

    [if(A){B}]
    [if(A){B}else{C}]
    
    A   Conditional test. See below for more details.
    
    B   Expression emitted when the if-test is true. This may be any string 
        that does NOT include the '}' character. It may include any of the 
        format strings described in the section FORMAT STRINGS with the 
        exception of the conditional test (because '}' is not permitted).
        
    C   Expression emitted when the if-test is false. This may be any string 
        that does NOT include the '}' character. It may include any of the 
        format strings described in the section FORMAT STRINGS with the 
        exception of the conditional test (because '}' is not permitted).
    
The conditional test is a combination of one or more boolean tests.
If more than one test is supplied, it must be combined with other tests
using either || (boolean OR) or && (boolean AND). 

A single test is made up of the left operand, operator and right operand.
e.g. X == Y where X is the left operand, == is the operator and Y is the
right operand.
    
    Left operand. It must be one of the following keywords:
        class       Test for existence of one of the classes. Only the
                    "==" and "!=" operators are permitted. In this case
                    these operators have the meaning of "includes" 
                    instead of "equals".
        level       Test against the page level.
        sib         Test against the current page sibling number.
        sibCount    Test against the number of siblings in the menu.
        id          Test against the page id.
		target		Test against the target attribute
    
    Operator. It must be one of the following:
        <           Less Than
        <=          Less Than Equals
        ==          Equals
        !=          Not Equal
        >=          Greater Than Equals
        >           Greater Than
    
    Right operand. The type of this operand depends on the keyword used
    for the left operand:
        class       One of the "menu-*" class names as listed in the 
                    section "OUTPUT".
        level       Test the page level against the following values:
                      <number>  absolute page level
                      root      the root page level
                      granny    the grand-parent page level
                      parent    the parent page level
                      current   the current page level
                      child     the child page level
        id          Test the page id against the following values:
                      <number>  absolute page id
                      parent    the parent page id
                      current   the current page id
        sib         A positive integer, or "sibCount" to test against
                    the count of siblings in this menu.
        sibCount    A positive integer.
		target		A string, containing a possible target
        
For example, valid tests are expression "exp" is emitted only when the menu item:
    
    [if(class==menu-expand){exp}]   has a sub-menu
    [if(class==menu-first){exp}]    is first item in a menu
    [if(class!=menu-first){exp}]    is NOT first item in a menu
    [if(class==menu-last){exp}]     is last item in a menu
    [if(level==0){exp}]             is at the root
    [if(level>0){exp}]              is not at the root
    [if(sib==2){exp}]               is the second item in a menu
    [if(sibCount>1){exp}]           is in a menu with more than 1 entry
    [if(sibCount!=2){exp}]          is in a menu which doesn't have exactly
    [if(level>parent){exp}]         is in a sibling menu or child of a sibling
    [if(id==parent){exp}]           is the parent of the current page
	[if(target==_self){exp}]		if value of target-attribute is '_self'

If an else-clause was added, then the expression for the else would be 
emitted in all other cases. For example the expression "foo" is emitted
whenever the if-test is false, so therefore:

    [if(sib==2){exp}else{foo}]          is NOT the second item in a menu
    [if(sibCount>2){exp}else{foo}]      is NOT in a menu with more than 2 entries

For multiple tests, the expression "exp" is emitted only when the menu item:

    [if(sib == 1 || sib > 3){exp}]      
        [is the first item] OR [is the 4th or larger item] in the menu
        
    [if(id == current && class == menu-expand){exp}
        [is the current item] AND [it has children]

Note that all tests are evaluated in the order listed because:
 * there is no short-circuit evaluation (all individual tests are always evaluated)
 * there is no grouping of tests (i.e. no support for parenthesis)
 * both || and && are considered the same level 



FORMATTER
=========
Note: This is an advanced and rarely needed feature!

If you are capable of extensive PHP programming, it is possible to replace the 
predefined menu formatter that show_menu2 is uses with a custom module. See the
include.php file of show_menu2 for an example of how the menu formatter must be 
written. The API it must use is:

class SM2_Formatter
{
    // called once before any menu is processed to allow object initialization
    function initialize() { }
    
    // called to open the menu list
    function startList($aPage, $aUrl) { }
    
    // called to open the menu item
    function startItem($aPage, $aUrl, $aCurrSib, $aSibCount) { }
    
    // called to close the menu item
    function finishItem() { }
    
    // called to close the menu list
    function finishList() { }
    
    // called once after all menu has been processed to allow object finalization
    function finalize() { }
    
    // called once after finalize() if the SM2_NOOUTPUT flag is used
    function getOutput() { }
};
