<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://docs.moodle.org/dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Charlesverge</id>
	<title>MoodleDocs - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://docs.moodle.org/dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Charlesverge"/>
	<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/Special:Contributions/Charlesverge"/>
	<updated>2026-06-21T12:55:23Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Navigation_API&amp;diff=47154</id>
		<title>Navigation API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Navigation_API&amp;diff=47154"/>
		<updated>2015-01-13T21:46:40Z</updated>

		<summary type="html">&lt;p&gt;Charlesverge: /* Settings navigation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Overview==&lt;br /&gt;
The Navigation API allows for the manipulation of the navigation system used in Moodle.&lt;br /&gt;
&lt;br /&gt;
==What the navigation is==&lt;br /&gt;
It&#039;s very important to understand what the navigation is exactly within Moodle. One of the goals for Moodle 2.0 was to standardise navigation throughout Moodle and try to bring order to the structure of a Moodle site.  Navigation is available through the page object &#039;&#039;&#039;$PAGE&#039;&#039;&#039;, against which you set the heading for the page, the title, any JavaScript requirements, etc.  The navigation structure uses the information $PAGE contains to generate a navigation structure for the site.  The navigation or settings [[blocks]] are interpretations of the navigation structure Moodle creates.&lt;br /&gt;
&lt;br /&gt;
This navigation structure is available through three variables:&lt;br /&gt;
&lt;br /&gt;
; $PAGE-&amp;gt;navigation : This is the main navigation structure, it will contain items that will allow the user to browse to the other available pages.&lt;br /&gt;
; $PAGE-&amp;gt;settingsnav : This is the settings navigation structure contains items that will allow the user to edit settings.&lt;br /&gt;
; $PAGE-&amp;gt;navbar : The navbar is a special structure for page breadcrumbs.&lt;br /&gt;
&lt;br /&gt;
==What the navigation is not==&lt;br /&gt;
The navigation is &#039;&#039;&#039;NOT&#039;&#039;&#039; the navigation block or the settings block!  These two blocks were created to display the navigation structure. The navigation block looks at &#039;&#039;$PAGE-&amp;gt;navigation&#039;&#039;, and the settings block looks at &#039;&#039;$PAGE-&amp;gt;settingsnav&#039;&#039;.  Both blocks interpret their data into an HTML structure and render it.&lt;br /&gt;
&lt;br /&gt;
# The navigation is a back-end structure that is built behind the scenes and has no immediate method of display.&lt;br /&gt;
# The navigation and settings blocks display the back-end navigation structure but add nothing to it at all.&lt;br /&gt;
::In the [[model-view-controller pattern]], $PAGE-&amp;gt;navigation, $PAGE-&amp;gt;settingsnav, and $PAGE-&amp;gt;navbar are the models, and the blocks are views.&lt;br /&gt;
&lt;br /&gt;
The navbar is just the path to the active navigation or settings item. The navbar is not displayed by a block; instead it is added into the theme&#039;s layout files and displayed by the core renderer. &lt;br /&gt;
&lt;br /&gt;
==How the navigation works==&lt;br /&gt;
&lt;br /&gt;
The main navigation structure can be accessed through &#039;&#039;&#039;$PAGE-&amp;gt;navigation&#039;&#039;&#039;.  The navigation and settings are contextual in that they will relate to the page that the user is viewing. This is determined by other $PAGE object properties:&lt;br /&gt;
* &#039;&#039;&#039;$PAGE-&amp;gt;context&#039;&#039;&#039; is a Moodle context that immediately outlines the nature of the page the user is viewing.&lt;br /&gt;
* &#039;&#039;&#039;$PAGE-&amp;gt;course&#039;&#039;&#039; is the course the user is viewing.  This is essential if the context is CONTEXT_COURSE or greater.  However, it is also useful in other contexts such as CONTEXT_USER.&lt;br /&gt;
* &#039;&#039;&#039;$PAGE-&amp;gt;cm&#039;&#039;&#039; is the course module instance.  This is essential if the context is CONTEXT_MODULE or greater.&lt;br /&gt;
* &#039;&#039;&#039;$PAGE-&amp;gt;url&#039;&#039;&#039; is used to match the active navigation item. &lt;br /&gt;
&lt;br /&gt;
Nearly every page sets $PAGE-&amp;gt;url through a call to &#039;&#039;&#039;$PAGE-&amp;gt;set_url&#039;&#039;&#039; however not many explicitly set the context, course, or cm. When you call &#039;&#039;&#039;require_login&#039;&#039;&#039; with a course or cm it automatically calls the following:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if ($cm) {&lt;br /&gt;
    $PAGE-&amp;gt;set_cm($cm, $course); // sets up global $COURSE&lt;br /&gt;
} else {&lt;br /&gt;
    $PAGE-&amp;gt;set_course($course);// sets up global $COURSE&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A page will only be required to explicitly set a context, course, or cm under one of these conditions:&lt;br /&gt;
# &#039;&#039;&#039;require_login&#039;&#039;&#039; is NOT being called correctly&lt;br /&gt;
# The page is using CONTEXT_SYSTEM, CONTEXT_COURSECAT, or CONTEXT_USER (call &#039;&#039;&#039;$PAGE-&amp;gt;set_context&#039;&#039;&#039; ).&lt;br /&gt;
# The page is using a course or cm but it is also using one of the above contexts (call &#039;&#039;&#039;$PAGE-&amp;gt;set_course&#039;&#039;&#039; or &#039;&#039;&#039;$PAGE-&amp;gt;set_cm&#039;&#039;&#039; ).&lt;br /&gt;
&lt;br /&gt;
The navigation structure cannot be generated before the $PAGE object is configured. It is only generated when it is first used, either when something tries to access the structure or when code tries to add to it.  The navigation is initialised in a specific order:&lt;br /&gt;
# Main navigation structure&lt;br /&gt;
# Settings navigation&lt;br /&gt;
# Navbar (does not need to be generated because of its simple contents and rendering)&lt;br /&gt;
&lt;br /&gt;
==Extending the navigation==&lt;br /&gt;
&lt;br /&gt;
===Code extension===&lt;br /&gt;
This method of extending is when the code arbitrarily extends the navigation during its execution. Extending the navigation through this means allows you to extend the navigation anywhere easily, however it will only be shown on pages where your extending code gets called (you should probably put it in a function within lib.php).&lt;br /&gt;
&lt;br /&gt;
These examples are taken from the [http://moodle.org/mod/forum/discuss.php?d=152391 General Developer Forum: Moodle 2 - how to set up breadcrumbs for a module page]. It has further information that is well worth reading.&lt;br /&gt;
====Navigation====&lt;br /&gt;
This is extending the main navigation structure.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$previewnode = $PAGE-&amp;gt;navigation-&amp;gt;add(get_string(&#039;preview&#039;), new moodle_url(&#039;/a/link/if/you/want/one.php&#039;), navigation_node::TYPE_CONTAINER);&lt;br /&gt;
$thingnode = $previewnode-&amp;gt;add(get_string(&#039;name of thing&#039;), new moodle_url(&#039;/a/link/if/you/want/one.php&#039;));&lt;br /&gt;
$thingnode-&amp;gt;make_active();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The above lines of code adds a preview node to the bottom of the navigation and then adds a thingnode to the previewnode (adding a leaf to our tree).&lt;br /&gt;
The final line of code makes the thingnode active so that the navbar finds it however if the URL you give it is the same as the url you set for the page it will automatically be marked active and you won&#039;t need this call.&lt;br /&gt;
&lt;br /&gt;
Next extending the navigation for the course.&lt;br /&gt;
For this you will need to know the course id and have called require_login($courseorid); so that the navigation is loaded for the course.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$coursenode = $PAGE-&amp;gt;navigation-&amp;gt;find($courseid, navigation_node::TYPE_COURSE);&lt;br /&gt;
$thingnode = $coursenode-&amp;gt;add(get_string(&#039;Name of thing&#039;), new moodle_url(&#039;/a/link/if/you/want/one.php&#039;));&lt;br /&gt;
$thingnode-&amp;gt;make_active();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The new bit of code here really is the first line which simply finds the course node, to do this we give it the course id and the node type in this case TYPE_COURSE.&lt;br /&gt;
What we are doing here is relying on the navigation to generate the navigation up to the course and then just adding to the course.&lt;br /&gt;
&lt;br /&gt;
Note that Moodle loads plugins in alphabetical order. Therefore plugin_b can find a node added by plugin_a but not the other way around.&lt;br /&gt;
====Settings navigation====&lt;br /&gt;
Adding to the settings navigation is very similar to navigation&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$settingnode = $PAGE-&amp;gt;settingsnav-&amp;gt;add(get_string(&#039;setting&#039;), new moodle_url(&#039;/a/link/if/you/want/one.php&#039;), navigation_node::TYPE_CONTAINER);&lt;br /&gt;
$thingnode = $settingnode-&amp;gt;add(get_string(&#039;Name of thing&#039;), new moodle_url(&#039;/a/link/if/you/want/one.php&#039;));&lt;br /&gt;
$thingnode-&amp;gt;make_active();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Add Settings folder to navigation====&lt;br /&gt;
&lt;br /&gt;
An example of a settings folder in a module can be see by navigating to Site administration / Plugins / Activity modules / Assignment. &lt;br /&gt;
&lt;br /&gt;
[[File:assignmentmenu.png]]&lt;br /&gt;
&lt;br /&gt;
An example of adding a navigation folder to a settings.php for a block with a link to the settings page and a external page is bellow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die;&lt;br /&gt;
&lt;br /&gt;
// Create folder / submenu in block menu, modsettings for activity modules, localplugins for Local plugins. &lt;br /&gt;
// The default folders are defined in admin/settings/plugins.php.&lt;br /&gt;
$ADMIN-&amp;gt;add(&#039;blocksettings&#039;, new admin_category(&#039;blocksamplefolder&#039;,&lt;br /&gt;
        get_string(&#039;pluginname&#039;, &#039;mod_sample&#039;)));&lt;br /&gt;
&lt;br /&gt;
// Create settings block.&lt;br /&gt;
$settings = new admin_settingpage($section, get_string(&#039;settings&#039;, &#039;block_sample&#039;));&lt;br /&gt;
if ($ADMIN-&amp;gt;fulltree) {&lt;br /&gt;
    $settings-&amp;gt;add(new admin_setting_configcheckbox(&#039;block_sample_checkbox&#039;, get_string(&#039;checkbox&#039;, &#039;block_sample&#039;),&lt;br /&gt;
        get_string(&#039;checkboxdescription&#039;, &#039;block_kronoshtml&#039;), 0));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// This adds the settings link to the folder/submenu.&lt;br /&gt;
$ADMIN-&amp;gt;add(&#039;blocksamplefolder&#039;, $settings);&lt;br /&gt;
// This adds a link to an external page.&lt;br /&gt;
$ADMIN-&amp;gt;add(&#039;blocksamplefolder&#039;, new admin_externalpage(&#039;block_sample_page&#039;, get_string(&#039;externalpage&#039;, &#039;block_sample&#039;),&lt;br /&gt;
        $CFG-&amp;gt;wwwroot.&#039;/blocks/sample/sample.php&#039;));&lt;br /&gt;
// Prevent Moodle from adding settings block in standard location.&lt;br /&gt;
$settings = null;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Navbar====&lt;br /&gt;
This is extending the settings navigation.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;navbar-&amp;gt;ignore_active();&lt;br /&gt;
$PAGE-&amp;gt;navbar-&amp;gt;add(get_string(&#039;preview&#039;), new moodle_url(&#039;/a/link/if/you/want/one.php&#039;));&lt;br /&gt;
$PAGE-&amp;gt;navbar-&amp;gt;add(get_string(&#039;name of thing&#039;), new moodle_url(&#039;/a/link/if/you/want/one.php&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The above code tells the navbar to ignore what ever the active page was and just use what you add, at which point we add two items as shown.&lt;br /&gt;
===Plugin Callbacks===&lt;br /&gt;
These are specific functions that the navigation looks for and calls if they exist for the plugin, presently only three plugin types can extend the navigation through these call-backs.&lt;br /&gt;
&lt;br /&gt;
Ideally all entries in &amp;quot;Administration / Site administration&amp;quot; tree should be done via settings.php files but sometimes it may be easier to directly modify the navigation structure created from the admin settings tree (such as when adding links to external pages).&lt;br /&gt;
&lt;br /&gt;
====Module====&lt;br /&gt;
Modules have two call-back methods, first to extend the navigation, and second to extend the settings. These call-backs get called when ever the user is viewing a page within the module and should only extend the navigation for the module.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function {modulename}_extend_navigation(${modulename}node, $course, $module, $cm)&lt;br /&gt;
function {modulename}_extend_settings_navigation($settings, ${modulename}node)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Course Formats====&lt;br /&gt;
Course formats are able to completely redefine the way in which navigation is generated for a course, as well as this they also have several methods to ensure the navigation is generated correctly.&lt;br /&gt;
&lt;br /&gt;
====Course Reports====&lt;br /&gt;
By default reports don&#039;t add themselves or anything else to the navigation however there is a call-back that can be implemented to allow them to do so.&lt;br /&gt;
&lt;br /&gt;
====Local Plugins====&lt;br /&gt;
Local plugins have two call-back methods, first to extend the navigation, and second to extend the settings.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function local_{pluginname}_extends_navigation(global_navigation $nav)&lt;br /&gt;
function local_{pluginname}_extends_settings_navigation(settings_navigation $nav, context $context)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==FAQ&#039;s and troubleshooting==&lt;br /&gt;
&#039;&#039;&#039;Q.&#039;&#039;&#039; My page is on the navigation but it doesn&#039;t find it?&lt;br /&gt;
&lt;br /&gt;
The first thing to do here is check the URL you are setting for the page. It should match the URL your page has within the navigation. If it doesn&#039;t you have two options, first change your &#039;&#039;&#039;$PAGE-&amp;gt;set_url&#039;&#039;&#039; call, or second override the URL the navigation is using to find the active node as shown below:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
navigation_node::override_active_url(new moodle_url(&#039;/your/url/here.php&#039;, array(&#039;param&#039;=&amp;gt;&#039;value&#039;)));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Core APIs]]&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=170325&amp;amp;parent=753095 Forum discussion - adding navigation to local plugins]&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;/div&gt;</summary>
		<author><name>Charlesverge</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=File:assignmentmenu.png&amp;diff=47153</id>
		<title>File:assignmentmenu.png</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=File:assignmentmenu.png&amp;diff=47153"/>
		<updated>2015-01-13T21:46:03Z</updated>

		<summary type="html">&lt;p&gt;Charlesverge: Screen shot of assignment activity settings navigation.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Screen shot of assignment activity settings navigation.&lt;/div&gt;</summary>
		<author><name>Charlesverge</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=jQuery&amp;diff=46953</id>
		<title>jQuery</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=jQuery&amp;diff=46953"/>
		<updated>2014-11-28T18:02:15Z</updated>

		<summary type="html">&lt;p&gt;Charlesverge: /* Frequently asked questions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.5}}&lt;br /&gt;
&lt;br /&gt;
[[YUI]] is the recommended library for development of Moodle plugins or customisations. However due to significant demand it will be possible to use also jQuery in Moodle add-ons.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
&lt;br /&gt;
===Basic jQuery in add-on theme===&lt;br /&gt;
&lt;br /&gt;
# create /theme/sometheme/lib.php file if it does not exist yet&lt;br /&gt;
# add new function theme_sometheme_page_init to the lib.php file (replace &#039;sometheme&#039; with real name of your theme)&lt;br /&gt;
# use jQuery JavaScript in theme layout files&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// file: /theme/sometheme/lib.php&lt;br /&gt;
function theme_sometheme_page_init(moodle_page $page) {&lt;br /&gt;
    $page-&amp;gt;requires-&amp;gt;jquery();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
// near the end of file: /theme/sometheme/layout/general.php&lt;br /&gt;
&amp;lt;script&amp;gt;&lt;br /&gt;
  $(&#039;.headermain&#039;).mouseover(function() {&lt;br /&gt;
    alert(&#039;grrr&#039;);&lt;br /&gt;
  });&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===jQuery UI in add-on activity module===&lt;br /&gt;
# optionally add more jQuery plugins (not recommended because the same plugins in different add-ons may collide)&lt;br /&gt;
# add necessary $PAGE-&amp;gt;requires&lt;br /&gt;
# use jQuery&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
require(&#039;../../config.php&#039;);&lt;br /&gt;
&lt;br /&gt;
// ... normal PAGE setup and access control&lt;br /&gt;
&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;jquery();&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;jquery_plugin(&#039;ui&#039;);&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;jquery_plugin(&#039;ui-css&#039;);&lt;br /&gt;
&lt;br /&gt;
echo $OUTPUT-&amp;gt;header();&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
    &amp;lt;button&amp;gt;A button element&amp;lt;/button&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;dialog&amp;quot; title=&amp;quot;Basic dialog&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;p&amp;gt;This is the default dialog which is useful for displaying information. The dialog window can be moved, resized and closed with the &#039;x&#039; icon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        $(function() {&lt;br /&gt;
            $( &amp;quot;#dialog&amp;quot; ).dialog();&lt;br /&gt;
        });&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
echo $OUTPUT-&amp;gt;footer();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===jQuery UI in add-on block===&lt;br /&gt;
# add necessary requires in get_required_javascript() method in your block, do not forget to call it in parent too&lt;br /&gt;
# use jQuery in blok html output&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class block_html extends block_base {&lt;br /&gt;
&lt;br /&gt;
    function get_required_javascript() {&lt;br /&gt;
        parent::get_required_javascript();&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;page-&amp;gt;requires-&amp;gt;jquery();&lt;br /&gt;
        $this-&amp;gt;page-&amp;gt;requires-&amp;gt;jquery_plugin(&#039;ui&#039;);&lt;br /&gt;
        $this-&amp;gt;page-&amp;gt;requires-&amp;gt;jquery_plugin(&#039;ui-css&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function get_content() {&lt;br /&gt;
&lt;br /&gt;
        // ....&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;content-&amp;gt;text .= &#039;&lt;br /&gt;
&amp;lt;div id=&amp;quot;progressbar&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;script&amp;gt;&lt;br /&gt;
  $(function() {&lt;br /&gt;
    $( &amp;quot;#progressbar&amp;quot; ).progressbar({&lt;br /&gt;
      value: 37&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
&amp;lt;/script&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        // ....&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Including your own plugins ===&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; Your plugin your have a filename which includes its version number. This is the same as in the core jQuery project. This enables you to increment the version of your plugin when you make changes to it.&lt;br /&gt;
&lt;br /&gt;
# Place your jQuery plugin into mod/yourplugin/jquery/jquerymodule/&lt;br /&gt;
# Add the plugin information to the plugins.php file&lt;br /&gt;
# Use the plugin in your code&lt;br /&gt;
&lt;br /&gt;
==== Add the plugin information to the plugins.php file ====&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// file: mod/yourplugin/jquery/plugins.php&lt;br /&gt;
$plugins = array(&lt;br /&gt;
    &#039;yourplugin-jquerymodule&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;files&#039; =&amp;gt; array(&lt;br /&gt;
            &#039;jquerymodule/jquery-somefilename-1.0.1.min.js&#039;,&lt;br /&gt;
        ),&lt;br /&gt;
     ),&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Use the plugin in your code ====&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// file: /mod/yourplugin/lib.php&lt;br /&gt;
// ... rest of file ...&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;jquery_plugin(&#039;yourplugin-jquerymodule&#039;, &#039;mod_yourplugin&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Overriding base jQuery UI theme===&lt;br /&gt;
# download new jQuery UI theme and extract it into theme/sometheme/jquery/custom-1.0&lt;br /&gt;
# define new jQuery theme ui css plugin in theme/sometheme/jquery/plugins.php&lt;br /&gt;
# overrider core &#039;ui-css&#039; with &#039;yourtheme-ui-css&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// file: theme/sometheme/jquery/plugins.php&lt;br /&gt;
$plugins = array(&lt;br /&gt;
    &#039;sometheme-ui-css&#039; =&amp;gt; array(&#039;files&#039; =&amp;gt; array(&#039;custom-1.0/jquery-ui-1.10.2.custom.min.css&#039;)),&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// file: /theme/sometheme/lib.php&lt;br /&gt;
function theme_sometheme_page_init(moodle_page $page) {&lt;br /&gt;
    // There is no need to $page-&amp;gt;requires-&amp;gt;jquery() if the theme does not use jQuery.&lt;br /&gt;
    $page-&amp;gt;requires-&amp;gt;jquery_plugin(&#039;sometheme-ui-css&#039;, &#039;theme_sometheme&#039;);&lt;br /&gt;
    $page-&amp;gt;requires-&amp;gt;jquery_override_plugin(&#039;ui-css&#039;, &#039;sometheme-ui-css&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Backwards compatibility for scripts written for legacy jQuery versions===&lt;br /&gt;
&lt;br /&gt;
See [https://github.com/jquery/jquery-migrate/ jQuery Migrate plugin]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;jquery();&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;jquery_plugin(&#039;migrate&#039;);&lt;br /&gt;
&lt;br /&gt;
// Incompatible code designed for 1.8.x jQuery should work now...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===mymobile theme===&lt;br /&gt;
&lt;br /&gt;
See mymobile theme for more examples including custom jQuery plugin and integration with jQuery Mobile.&lt;br /&gt;
&lt;br /&gt;
==More information==&lt;br /&gt;
&lt;br /&gt;
===Bundled plugins===&lt;br /&gt;
&lt;br /&gt;
Official Moodle distribution contains jQuery, jQuery UI and jQuery Migrate plugins.&lt;br /&gt;
&lt;br /&gt;
===jQuery plugin collisions===&lt;br /&gt;
&lt;br /&gt;
The loading order of plugins is defined by order of $PAGE-&amp;gt;requires. If there are plugins with the same name the first $PAGE-&amp;gt;require wins.&lt;br /&gt;
&lt;br /&gt;
It is recommended to use plugin overrides only in themes because multiple overrides of the same plugin result in undefined behaviour. In general themes should have more freedom to add extra jQuery plugins, other Moodle plugins should ideally use only basic jQuery or jQuery UI.&lt;br /&gt;
&lt;br /&gt;
===jQuery plugin modifications===&lt;br /&gt;
&lt;br /&gt;
Files in jQuery plugins MUST NOT be changed, always create a new file with different name and update CSS and plugins.php if necessary and delete the old file.&lt;br /&gt;
&lt;br /&gt;
===jQuery versions===&lt;br /&gt;
&lt;br /&gt;
Only minor jQuery version updates can be done in STABLE branches. Add-on developers must revalidate compatibility after every major upgrade. Use official &#039;migrate&#039; plugin if necessary, see example above.&lt;br /&gt;
&lt;br /&gt;
==Frequently asked questions==&lt;br /&gt;
&lt;br /&gt;
; Can I serve jQuery from CDN? : No, because CDNs do not include all plugins and some do not support https. Use proxy caching such as Cloudflare instead.&lt;br /&gt;
&lt;br /&gt;
; I edited some file but the change is ignored, why? : Moodle and your browser caches Javascript, to circumvent this rename your Javascript file as shown [https://docs.moodle.org/dev/jQuery#Including_your_own_plugins here]. Additionally you can use the developer console on [https://developer.chrome.com/devtools/docs/settings Chrome] or [https://developer.mozilla.org/en-US/docs/Tools/Tools_Toolbox Firefox] to disable caching for Javascript.&lt;br /&gt;
&lt;br /&gt;
See above, files MUST NOT be updated in jQuery plugins, always create new files or directories. Moodle cache purging does not have any effect on jQuery plugins.&lt;br /&gt;
&lt;br /&gt;
; Can we remove YUI now? : No! YUI is the only recommended JS library in Moodle add-ons and core.&lt;br /&gt;
&lt;br /&gt;
; Can I use different jQuery version? : No. (Theoretically you might try jQuery plugin override to include some later minor revision.)&lt;br /&gt;
&lt;br /&gt;
; Could we have jQuery plugin dependencies? : No, order your $PAGE-&amp;gt;requires manually.&lt;br /&gt;
&lt;br /&gt;
; Are there any performance costs when using jQuery? : Yes. Please consider using SimpleYUI for simple DOM manipulations or standard YUI widgets.&lt;br /&gt;
&lt;br /&gt;
; Can I use YUI loader to include jQuery? : No. Moodle jQuery support is not compatible with sandboxing.&lt;br /&gt;
&lt;br /&gt;
; Moodle complains when I disable slasharguments setting, why? : Please fix your server to be compatible with slasharguments, even IIS can support it now!&lt;br /&gt;
&lt;br /&gt;
; Why is jQuery UI split into two plugins? : This allows Moodle themes to override the jQuery UI CSS and images.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
* [http://jquery.com jQuery]&lt;br /&gt;
* [http://jqueryui.com jQuery User Interface]&lt;br /&gt;
&lt;br /&gt;
[[Category:Javascript]]&lt;/div&gt;</summary>
		<author><name>Charlesverge</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=lib/tablelib.php&amp;diff=46861</id>
		<title>lib/tablelib.php</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=lib/tablelib.php&amp;diff=46861"/>
		<updated>2014-11-18T00:45:48Z</updated>

		<summary type="html">&lt;p&gt;Charlesverge: Added complete example extending the table_sql class.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Status of this doc==&lt;br /&gt;
&lt;br /&gt;
This doc is a description of proposed additions to the api for using tablelib. It has not yet been agreed on. Seemed a good idea to create it at this url rather than some development notes page for instance so that the history of this page will include the changes made to the original proposal.&lt;br /&gt;
&lt;br /&gt;
==What changes in the new api?==&lt;br /&gt;
&lt;br /&gt;
* Currently the code for creating table often involves a lot of duplication of code. New api can improve things.&lt;br /&gt;
* New API handles downloads&lt;br /&gt;
** download export formats are seperated into classes and it is simple to add more formats. Added two more formats. Unpaged XHTML format and comma seperated values format.&lt;br /&gt;
* No longer have to make sure that column data is added to the table in the same order as columns are declared. Can have the logic for choosing what columns to include in the table in one place.&lt;br /&gt;
* New mechanism in table_sql allows appropriate code to be automatically called to format data before putting it into the table.&lt;br /&gt;
&lt;br /&gt;
==Skeleton Usage==&lt;br /&gt;
&lt;br /&gt;
In order to check your sql query is working as expected when developing a page it can be useful just to output all the data from the query in the table before going on to work out how you want to format data. The code below will output all the data from your query in a collapsible, sortable table. It automatically displays all columns returned from the db.&lt;br /&gt;
&lt;br /&gt;
You should go on to :&lt;br /&gt;
*specify what columns to include in the table and what names to display for the columns using define_columms and define_headers&lt;br /&gt;
*use your own child class of easy_table and define methods col_{columnname} to add hyperlinks etc to the table. You can also use method other_cols.&lt;br /&gt;
&lt;br /&gt;
See below for examples of typical usage.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php  // $Id$&lt;br /&gt;
/**&lt;br /&gt;
 * Simple file test.php to drop into root of Moodle installation.&lt;br /&gt;
 * This is the skeleton code to print a downloadable, paged, sorted table of&lt;br /&gt;
 * data from a sql query.&lt;br /&gt;
 */&lt;br /&gt;
require &amp;quot;config.php&amp;quot;;&lt;br /&gt;
require &amp;quot;$CFG-&amp;gt;libdir/tablelib.php&amp;quot;;&lt;br /&gt;
$context = context_system::instance();&lt;br /&gt;
$PAGE-&amp;gt;set_context($context);&lt;br /&gt;
$PAGE-&amp;gt;set_url(&#039;/test.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$download = optional_param(&#039;download&#039;, &#039;&#039;, PARAM_ALPHA);&lt;br /&gt;
&lt;br /&gt;
$table = new table_sql(&#039;uniqueid&#039;);&lt;br /&gt;
$table-&amp;gt;is_downloading($download, &#039;test&#039;, &#039;testing123&#039;);&lt;br /&gt;
&lt;br /&gt;
if (!$table-&amp;gt;is_downloading()) {&lt;br /&gt;
    // Only print headers if not asked to download data&lt;br /&gt;
    // Print the page header&lt;br /&gt;
    $PAGE-&amp;gt;set_title(&#039;Testing&#039;);&lt;br /&gt;
    $PAGE-&amp;gt;set_heading(&#039;Testing table class&#039;);&lt;br /&gt;
    $PAGE-&amp;gt;navbar-&amp;gt;add(&#039;Testing table class&#039;, new moodle_url(&#039;/test.php&#039;));&lt;br /&gt;
    echo $OUTPUT-&amp;gt;header();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Work out the sql for the table.&lt;br /&gt;
$table-&amp;gt;set_sql(&#039;*&#039;, &amp;quot;{user}&amp;quot;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
$table-&amp;gt;define_baseurl(&amp;quot;$CFG-&amp;gt;wwwroot/test.php&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$table-&amp;gt;out(40, true);&lt;br /&gt;
&lt;br /&gt;
if (!$table-&amp;gt;is_downloading()) {&lt;br /&gt;
    $OUTPUT-&amp;gt;footer();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==The Next Step : Typical Usage==&lt;br /&gt;
&lt;br /&gt;
===Define table===&lt;br /&gt;
&lt;br /&gt;
Define table class in file somethingsomthing_table.php&lt;br /&gt;
&lt;br /&gt;
In the file define a child class of &#039;table_sql&#039;. Mostly this child class will just contain methods to format data for display.&lt;br /&gt;
&lt;br /&gt;
====Format data for display====&lt;br /&gt;
&lt;br /&gt;
Define methods col_{colmname} to process data from db and to add it to table. Eg. Here is an example from table class quiz_report_overview_table&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function col_timefinish($attempt){&lt;br /&gt;
        if ($attempt-&amp;gt;attempt) {&lt;br /&gt;
            if ($attempt-&amp;gt;timefinish) {&lt;br /&gt;
                $timefinish = userdate($attempt-&amp;gt;timefinish, $this-&amp;gt;strtimeformat);&lt;br /&gt;
                if (!$this-&amp;gt;is_downloading()) {&lt;br /&gt;
                    return &#039;&amp;lt;a href=&amp;quot;review.php?q=&#039;.$this-&amp;gt;quiz-&amp;gt;id.&#039;&amp;amp;amp;attempt=&#039;.$attempt-&amp;gt;attempt.&#039;&amp;quot;&amp;gt;&#039;.$timefinish.&#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
                } else {&lt;br /&gt;
                    return $timefinish;&lt;br /&gt;
                }&lt;br /&gt;
            } else {&lt;br /&gt;
                return  &#039;-&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        } else {&lt;br /&gt;
            return  &#039;-&#039;;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where you do not know the names of the columns at the time of writing the class definition then you can use other_cols method. Eg.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function other_cols($colname, $attempt){&lt;br /&gt;
        if (preg_match(&#039;/^qsgrade([0-9]+)$/&#039;, $colname, $matches)){&lt;br /&gt;
            $questionid = $matches[1];&lt;br /&gt;
            $question = $this-&amp;gt;questions[$questionid];&lt;br /&gt;
            $state = new object();&lt;br /&gt;
            $state-&amp;gt;event = $attempt-&amp;gt;{&#039;qsevent&#039;.$questionid};&lt;br /&gt;
            if (question_state_is_graded($state)) {&lt;br /&gt;
                $grade = quiz_rescale_grade($attempt-&amp;gt;{&#039;qsgrade&#039;.$questionid}, $this-&amp;gt;quiz);&lt;br /&gt;
            } else {&lt;br /&gt;
                $grade = &#039;--&#039;;&lt;br /&gt;
            }&lt;br /&gt;
            if (!$this-&amp;gt;is_downloading()) {&lt;br /&gt;
                $grade = $grade.&#039;/&#039;.quiz_rescale_grade($question-&amp;gt;grade, $this-&amp;gt;quiz);&lt;br /&gt;
                return link_to_popup_window(&#039;/mod/quiz/reviewquestion.php?state=&#039;.&lt;br /&gt;
                        $attempt-&amp;gt;{&#039;qsid&#039;.$questionid}.&#039;&amp;amp;amp;number=&#039;.$question-&amp;gt;number,&lt;br /&gt;
                        &#039;reviewquestion&#039;, $grade, 450, 650, get_string(&#039;reviewresponse&#039;, &#039;quiz&#039;),&lt;br /&gt;
                        &#039;none&#039;, true);&lt;br /&gt;
            } else {&lt;br /&gt;
                return $grade;&lt;br /&gt;
            }     &lt;br /&gt;
        } else {&lt;br /&gt;
            return NULL;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If there is no method col_{column name} and other_cols returns NULL then the column data is put straight in the table unprocessed.&lt;br /&gt;
&lt;br /&gt;
===Use your table class===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        // Start page&lt;br /&gt;
        $download = optional_param(&#039;download&#039;, &#039;&#039;, PARAM_ALPHA);&lt;br /&gt;
&lt;br /&gt;
        $table = new name_of_your_table(&#039;uniqueid&#039;);&lt;br /&gt;
        $table-&amp;gt;is_downloading($download, $filenamefordownload, $sheettitle);&lt;br /&gt;
        if (!$table-&amp;gt;is_downloading()) {&lt;br /&gt;
            // Only print headers if not asked to download data&lt;br /&gt;
            $this-&amp;gt;print_header_and_tabs($cm, $course, $quiz, &amp;quot;overview&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
        // Various page set up stuff&lt;br /&gt;
        if (!$table-&amp;gt;is_downloading()) { //do not print notices when downloading&lt;br /&gt;
            // Wrap output of html in these if conditions&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        // Work out the sql for the table.&lt;br /&gt;
&lt;br /&gt;
        // Use this method only if you want to specify some sql with less joins for &lt;br /&gt;
        // counting the total records.&lt;br /&gt;
        $table-&amp;gt;set_count_sql(&amp;quot;SELECT COUNT(1) FROM $from WHERE $where&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if ($something) {&lt;br /&gt;
            // Add some more joins&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        $table-&amp;gt;set_sql($fields, $from, $where);&lt;br /&gt;
        // Define table columns.&lt;br /&gt;
        $columns = array();&lt;br /&gt;
        $headers = array();&lt;br /&gt;
        &lt;br /&gt;
&lt;br /&gt;
        if (!$table-&amp;gt;is_downloading() &amp;amp;&amp;amp; $candelete) {&lt;br /&gt;
            $columns[]= &#039;checkbox&#039;;&lt;br /&gt;
            $headers[]= NULL;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        if (!$table-&amp;gt;is_downloading() &amp;amp;&amp;amp; $CFG-&amp;gt;grade_report_showuserimage) {&lt;br /&gt;
            $columns[]= &#039;picture&#039;;&lt;br /&gt;
            $headers[]= &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
        if (!$table-&amp;gt;is_downloading()){&lt;br /&gt;
            $columns[]= &#039;fullname&#039;;&lt;br /&gt;
            $headers[]= get_string(&#039;name&#039;);&lt;br /&gt;
        } else {&lt;br /&gt;
            $columns[]= &#039;lastname&#039;;&lt;br /&gt;
            $headers[]= get_string(&#039;lastname&#039;);&lt;br /&gt;
            $columns[]= &#039;firstname&#039;;&lt;br /&gt;
            $headers[]= get_string(&#039;firstname&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($CFG-&amp;gt;grade_report_showuseridnumber) {&lt;br /&gt;
            $columns[]= &#039;idnumber&#039;;&lt;br /&gt;
            $headers[]= get_string(&#039;idnumber&#039;);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        $columns[]= &#039;timestart&#039;;&lt;br /&gt;
        $headers[]= get_string(&#039;startedon&#039;, &#039;quiz&#039;);&lt;br /&gt;
&lt;br /&gt;
        $columns[]= &#039;timefinish&#039;;&lt;br /&gt;
        $headers[]= get_string(&#039;timecompleted&#039;,&#039;quiz&#039;);&lt;br /&gt;
&lt;br /&gt;
        $columns[]= &#039;duration&#039;;&lt;br /&gt;
        $headers[]= get_string(&#039;attemptduration&#039;, &#039;quiz&#039;);&lt;br /&gt;
&lt;br /&gt;
        if ($detailedmarks) {&lt;br /&gt;
            foreach ($questions as $id =&amp;gt; $question) {&lt;br /&gt;
                // Ignore questions of zero length&lt;br /&gt;
                $columns[] = &#039;qsgrade&#039;.$id;&lt;br /&gt;
                $headers[] = &#039;#&#039;.$question-&amp;gt;number;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($showgrades) {&lt;br /&gt;
            $columns[] = &#039;sumgrades&#039;;&lt;br /&gt;
            $headers[] = get_string(&#039;grade&#039;, &#039;quiz&#039;).&#039;/&#039;.$quiz-&amp;gt;grade;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($hasfeedback) {&lt;br /&gt;
            $columns[] = &#039;feedbacktext&#039;;&lt;br /&gt;
            $headers[] = get_string(&#039;feedback&#039;, &#039;quiz&#039;);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        $table-&amp;gt;define_columns($columns);&lt;br /&gt;
        $table-&amp;gt;define_headers($headers);&lt;br /&gt;
        $table-&amp;gt;sortable(true, &#039;uniqueid&#039;);&lt;br /&gt;
        &lt;br /&gt;
        // Set up the table some of these settings will be ignored for downloads&lt;br /&gt;
        $table-&amp;gt;define_baseurl($reporturl-&amp;gt;out(false, $displayoptions));&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        $table-&amp;gt;column_suppress(&#039;picture&#039;);&lt;br /&gt;
        $table-&amp;gt;column_suppress(&#039;fullname&#039;);&lt;br /&gt;
        $table-&amp;gt;column_suppress(&#039;idnumber&#039;);&lt;br /&gt;
        &lt;br /&gt;
        $table-&amp;gt;no_sorting(&#039;feedbacktext&#039;);&lt;br /&gt;
&lt;br /&gt;
        $table-&amp;gt;column_class(&#039;picture&#039;, &#039;picture&#039;);&lt;br /&gt;
        $table-&amp;gt;column_class(&#039;fullname&#039;, &#039;bold&#039;);&lt;br /&gt;
        $table-&amp;gt;column_class(&#039;sumgrades&#039;, &#039;bold&#039;);&lt;br /&gt;
&lt;br /&gt;
        $table-&amp;gt;set_attribute(&#039;id&#039;, &#039;attempts&#039;);&lt;br /&gt;
&lt;br /&gt;
        $table-&amp;gt;out($pagesize, $useinitialsbar);&lt;br /&gt;
        &lt;br /&gt;
        if (!$table-&amp;gt;is_downloading()) {&lt;br /&gt;
            // Footer and other html stuff to display.&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Complete sql table class example==&lt;br /&gt;
&lt;br /&gt;
The following two scripts demonstrate how you can customize which table columns to show, table columns names and process values for table rows.&lt;br /&gt;
&lt;br /&gt;
Put the following script into test_table.php&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
 * Test table class to be put in test_table.php of root of Moodle installation.&lt;br /&gt;
 *  for defining some custom column names and proccessing&lt;br /&gt;
 * Username and Password feilds using custom and other column methods.&lt;br /&gt;
 */&lt;br /&gt;
class test_table extends table_sql {&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Constructor&lt;br /&gt;
     * @param int $uniqueid all tables have to have a unique id, this is used&lt;br /&gt;
     *      as a key when storing table properties like sort order in the session.&lt;br /&gt;
     */&lt;br /&gt;
    function __construct($uniqueid) {&lt;br /&gt;
        parent::__construct($uniqueid);&lt;br /&gt;
        // Define the list of columns to show.&lt;br /&gt;
        $columns = array(&#039;username&#039;, &#039;password&#039;, &#039;firstname&#039;, &#039;lastname&#039;);&lt;br /&gt;
        $this-&amp;gt;define_columns($columns);&lt;br /&gt;
&lt;br /&gt;
        // Define the titles of columns to show in header.&lt;br /&gt;
        $headers = array(&#039;Username&#039;, &#039;Password&#039;, &#039;First name&#039;, &#039;Last name&#039;);&lt;br /&gt;
        $this-&amp;gt;define_headers($headers);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * This function is called for each data row to allow processing of the&lt;br /&gt;
     * username value.&lt;br /&gt;
     *&lt;br /&gt;
     * @param object $values Contains object with all the values of record.&lt;br /&gt;
     * @return $string Return username with link to profile or username only&lt;br /&gt;
     *     when downloading.&lt;br /&gt;
     */&lt;br /&gt;
    function col_username($values) {&lt;br /&gt;
        // If the data is being downloaded than we don&#039;t want to show HTML.&lt;br /&gt;
        if ($this-&amp;gt;is_downloading()) {&lt;br /&gt;
            return $values-&amp;gt;username;&lt;br /&gt;
        } else {&lt;br /&gt;
            return &#039;&amp;lt;a href=&amp;quot;/user/profile.php?id=&#039;.$values-&amp;gt;id.&#039;&amp;quot;&amp;gt;&#039;.$values-&amp;gt;username.&#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * This function is called for each data row to allow processing of&lt;br /&gt;
     * columns which do not have a *_cols function.&lt;br /&gt;
     * @return string return processed value. Return NULL if no change has&lt;br /&gt;
     *     been made.&lt;br /&gt;
     */&lt;br /&gt;
    function other_cols($colname, $value) {&lt;br /&gt;
        // For security reasons we don&#039;t want to show the password hash.&lt;br /&gt;
        if ($colname == &#039;password&#039;) {&lt;br /&gt;
            return &amp;quot;****&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Put the following script into test_custom.php, the difference between test.php is the inclusion of test_custom.php and changing table_sql to new test_table.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
 * Simple file test_custom.php to drop into root of Moodle installation.&lt;br /&gt;
 * This is an example of using a sql_table class to format data.&lt;br /&gt;
 */&lt;br /&gt;
require &amp;quot;config.php&amp;quot;;&lt;br /&gt;
require &amp;quot;$CFG-&amp;gt;libdir/tablelib.php&amp;quot;;&lt;br /&gt;
require &amp;quot;test_table.php&amp;quot;;&lt;br /&gt;
$context = context_system::instance();&lt;br /&gt;
$PAGE-&amp;gt;set_context($context);&lt;br /&gt;
$PAGE-&amp;gt;set_url(&#039;/test_custom.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$download = optional_param(&#039;download&#039;, &#039;&#039;, PARAM_ALPHA);&lt;br /&gt;
&lt;br /&gt;
$table = new test_table(&#039;uniqueid&#039;);&lt;br /&gt;
$table-&amp;gt;is_downloading($download, &#039;test&#039;, &#039;testing123&#039;);&lt;br /&gt;
&lt;br /&gt;
if (!$table-&amp;gt;is_downloading()) {&lt;br /&gt;
    // Only print headers if not asked to download data.&lt;br /&gt;
    // Print the page header.&lt;br /&gt;
    $PAGE-&amp;gt;set_title(&#039;Testing&#039;);&lt;br /&gt;
    $PAGE-&amp;gt;set_heading(&#039;Testing table class&#039;);&lt;br /&gt;
    $PAGE-&amp;gt;navbar-&amp;gt;add(&#039;Testing table class&#039;, new moodle_url(&#039;/test_custom.php&#039;));&lt;br /&gt;
    echo $OUTPUT-&amp;gt;header();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Work out the sql for the table.&lt;br /&gt;
$table-&amp;gt;set_sql(&#039;*&#039;, &amp;quot;{user}&amp;quot;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
$table-&amp;gt;define_baseurl(&amp;quot;$CFG-&amp;gt;wwwroot/test_custom.php&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$table-&amp;gt;out(10, true);&lt;br /&gt;
&lt;br /&gt;
if (!$table-&amp;gt;is_downloading()) {&lt;br /&gt;
    $OUTPUT-&amp;gt;footer();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Adding download capability to existing tables==&lt;br /&gt;
&lt;br /&gt;
To add download to existing tables. You must :&lt;br /&gt;
&lt;br /&gt;
Add :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $download = optional_param(&#039;download&#039;, &#039;&#039;, PARAM_ALPHA);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To top of page.&lt;br /&gt;
&lt;br /&gt;
Probably more table instantiation to top of page.&lt;br /&gt;
&lt;br /&gt;
Add just after table object instantiation :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$table-&amp;gt;is_downloading($download, &#039;test&#039;,&lt;br /&gt;
                    &#039;testing123&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wrap all html output with condition :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        if (!$table-&amp;gt;is_downloading()) {&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Make sure you have this method call somewhere :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $table-&amp;gt;define_baseurl($reporturl-&amp;gt;out(false, $displayoptions));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Replace :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $table-&amp;gt;print_html();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $table-&amp;gt;finish_output();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Download buttons will automagically appear.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* The phpdoc comments on the class flexible_table and table_sql in tablelib.php&lt;br /&gt;
* [http://tracker.moodle.org/browse/MDL-14187 Discussion in tracker]&lt;/div&gt;</summary>
		<author><name>Charlesverge</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=lib/tablelib.php&amp;diff=46860</id>
		<title>lib/tablelib.php</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=lib/tablelib.php&amp;diff=46860"/>
		<updated>2014-11-17T22:46:55Z</updated>

		<summary type="html">&lt;p&gt;Charlesverge: /* Skeleton Usage */ Removed code comment.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Status of this doc==&lt;br /&gt;
&lt;br /&gt;
This doc is a description of proposed additions to the api for using tablelib. It has not yet been agreed on. Seemed a good idea to create it at this url rather than some development notes page for instance so that the history of this page will include the changes made to the original proposal.&lt;br /&gt;
&lt;br /&gt;
==What changes in the new api?==&lt;br /&gt;
&lt;br /&gt;
* Currently the code for creating table often involves a lot of duplication of code. New api can improve things.&lt;br /&gt;
* New API handles downloads&lt;br /&gt;
** download export formats are seperated into classes and it is simple to add more formats. Added two more formats. Unpaged XHTML format and comma seperated values format.&lt;br /&gt;
* No longer have to make sure that column data is added to the table in the same order as columns are declared. Can have the logic for choosing what columns to include in the table in one place.&lt;br /&gt;
* New mechanism in table_sql allows appropriate code to be automatically called to format data before putting it into the table.&lt;br /&gt;
&lt;br /&gt;
==Skeleton Usage==&lt;br /&gt;
&lt;br /&gt;
In order to check your sql query is working as expected when developing a page it can be useful just to output all the data from the query in the table before going on to work out how you want to format data. The code below will output all the data from your query in a collapsible, sortable table. It automatically displays all columns returned from the db.&lt;br /&gt;
&lt;br /&gt;
You should go on to :&lt;br /&gt;
*specify what columns to include in the table and what names to display for the columns using define_columms and define_headers&lt;br /&gt;
*use your own child class of easy_table and define methods col_{columnname} to add hyperlinks etc to the table. You can also use method other_cols.&lt;br /&gt;
&lt;br /&gt;
See below for examples of typical usage.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php  // $Id$&lt;br /&gt;
/**&lt;br /&gt;
 * Simple file test.php to drop into root of Moodle installation.&lt;br /&gt;
 * This is the skeleton code to print a downloadable, paged, sorted table of&lt;br /&gt;
 * data from a sql query.&lt;br /&gt;
 */&lt;br /&gt;
require &amp;quot;config.php&amp;quot;;&lt;br /&gt;
require &amp;quot;$CFG-&amp;gt;libdir/tablelib.php&amp;quot;;&lt;br /&gt;
$context = context_system::instance();&lt;br /&gt;
$PAGE-&amp;gt;set_context($context);&lt;br /&gt;
$PAGE-&amp;gt;set_url(&#039;/test.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$download = optional_param(&#039;download&#039;, &#039;&#039;, PARAM_ALPHA);&lt;br /&gt;
&lt;br /&gt;
$table = new table_sql(&#039;uniqueid&#039;);&lt;br /&gt;
$table-&amp;gt;is_downloading($download, &#039;test&#039;, &#039;testing123&#039;);&lt;br /&gt;
&lt;br /&gt;
if (!$table-&amp;gt;is_downloading()) {&lt;br /&gt;
    // Only print headers if not asked to download data&lt;br /&gt;
    // Print the page header&lt;br /&gt;
    $PAGE-&amp;gt;set_title(&#039;Testing&#039;);&lt;br /&gt;
    $PAGE-&amp;gt;set_heading(&#039;Testing table class&#039;);&lt;br /&gt;
    $PAGE-&amp;gt;navbar-&amp;gt;add(&#039;Testing table class&#039;, new moodle_url(&#039;/test.php&#039;));&lt;br /&gt;
    echo $OUTPUT-&amp;gt;header();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Work out the sql for the table.&lt;br /&gt;
$table-&amp;gt;set_sql(&#039;*&#039;, &amp;quot;{$CFG-&amp;gt;prefix}user&amp;quot;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
$table-&amp;gt;define_baseurl(&amp;quot;$CFG-&amp;gt;wwwroot/test.php&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$table-&amp;gt;out(40, true);&lt;br /&gt;
&lt;br /&gt;
if (!$table-&amp;gt;is_downloading()) {&lt;br /&gt;
    $OUTPUT-&amp;gt;footer();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==The Next Step : Typical Usage==&lt;br /&gt;
&lt;br /&gt;
===Define table===&lt;br /&gt;
&lt;br /&gt;
Define table class in file somethingsomthing_table.php&lt;br /&gt;
&lt;br /&gt;
In the file define a child class of &#039;table_sql&#039;. Mostly this child class will just contain methods to format data for display.&lt;br /&gt;
&lt;br /&gt;
====Format data for display====&lt;br /&gt;
&lt;br /&gt;
Define methods col_{colmname} to process data from db and to add it to table. Eg. Here is an example from table class quiz_report_overview_table&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function col_timefinish($attempt){&lt;br /&gt;
        if ($attempt-&amp;gt;attempt) {&lt;br /&gt;
            if ($attempt-&amp;gt;timefinish) {&lt;br /&gt;
                $timefinish = userdate($attempt-&amp;gt;timefinish, $this-&amp;gt;strtimeformat);&lt;br /&gt;
                if (!$this-&amp;gt;is_downloading()) {&lt;br /&gt;
                    return &#039;&amp;lt;a href=&amp;quot;review.php?q=&#039;.$this-&amp;gt;quiz-&amp;gt;id.&#039;&amp;amp;amp;attempt=&#039;.$attempt-&amp;gt;attempt.&#039;&amp;quot;&amp;gt;&#039;.$timefinish.&#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
                } else {&lt;br /&gt;
                    return $timefinish;&lt;br /&gt;
                }&lt;br /&gt;
            } else {&lt;br /&gt;
                return  &#039;-&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        } else {&lt;br /&gt;
            return  &#039;-&#039;;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where you do not know the names of the columns at the time of writing the class definition then you can use other_cols method. Eg.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function other_cols($colname, $attempt){&lt;br /&gt;
        if (preg_match(&#039;/^qsgrade([0-9]+)$/&#039;, $colname, $matches)){&lt;br /&gt;
            $questionid = $matches[1];&lt;br /&gt;
            $question = $this-&amp;gt;questions[$questionid];&lt;br /&gt;
            $state = new object();&lt;br /&gt;
            $state-&amp;gt;event = $attempt-&amp;gt;{&#039;qsevent&#039;.$questionid};&lt;br /&gt;
            if (question_state_is_graded($state)) {&lt;br /&gt;
                $grade = quiz_rescale_grade($attempt-&amp;gt;{&#039;qsgrade&#039;.$questionid}, $this-&amp;gt;quiz);&lt;br /&gt;
            } else {&lt;br /&gt;
                $grade = &#039;--&#039;;&lt;br /&gt;
            }&lt;br /&gt;
            if (!$this-&amp;gt;is_downloading()) {&lt;br /&gt;
                $grade = $grade.&#039;/&#039;.quiz_rescale_grade($question-&amp;gt;grade, $this-&amp;gt;quiz);&lt;br /&gt;
                return link_to_popup_window(&#039;/mod/quiz/reviewquestion.php?state=&#039;.&lt;br /&gt;
                        $attempt-&amp;gt;{&#039;qsid&#039;.$questionid}.&#039;&amp;amp;amp;number=&#039;.$question-&amp;gt;number,&lt;br /&gt;
                        &#039;reviewquestion&#039;, $grade, 450, 650, get_string(&#039;reviewresponse&#039;, &#039;quiz&#039;),&lt;br /&gt;
                        &#039;none&#039;, true);&lt;br /&gt;
            } else {&lt;br /&gt;
                return $grade;&lt;br /&gt;
            }     &lt;br /&gt;
        } else {&lt;br /&gt;
            return NULL;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If there is no method col_{column name} and other_cols returns NULL then the column data is put straight in the table unprocessed.&lt;br /&gt;
&lt;br /&gt;
===Use your table class===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        //start page&lt;br /&gt;
        $download = optional_param(&#039;download&#039;, &#039;&#039;, PARAM_ALPHA);&lt;br /&gt;
&lt;br /&gt;
        $table = new name_of_your_table(&#039;uniqueid&#039;);&lt;br /&gt;
        $table-&amp;gt;is_downloading($download, $filenamefordownload, $sheettitle);&lt;br /&gt;
        if (!$table-&amp;gt;is_downloading()) {&lt;br /&gt;
            // Only print headers if not asked to download data&lt;br /&gt;
            $this-&amp;gt;print_header_and_tabs($cm, $course, $quiz, &amp;quot;overview&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
        //various page set up stuff&lt;br /&gt;
        if (!$table-&amp;gt;is_downloading()) { //do not print notices when downloading&lt;br /&gt;
            //wrap output of html in these if conditions&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        //work out the sql for the table.&lt;br /&gt;
&lt;br /&gt;
        //use this method only if you want to specify some sql with less joins for &lt;br /&gt;
        //counting the total records&lt;br /&gt;
        $table-&amp;gt;set_count_sql(&amp;quot;SELECT COUNT(1) FROM $from WHERE $where&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if ($something) {&lt;br /&gt;
            // Add some more joins&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        $table-&amp;gt;set_sql($fields, $from, $where);&lt;br /&gt;
        // Define table columns&lt;br /&gt;
        $columns = array();&lt;br /&gt;
        $headers = array();&lt;br /&gt;
        &lt;br /&gt;
&lt;br /&gt;
        if (!$table-&amp;gt;is_downloading() &amp;amp;&amp;amp; $candelete) {&lt;br /&gt;
            $columns[]= &#039;checkbox&#039;;&lt;br /&gt;
            $headers[]= NULL;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        if (!$table-&amp;gt;is_downloading() &amp;amp;&amp;amp; $CFG-&amp;gt;grade_report_showuserimage) {&lt;br /&gt;
            $columns[]= &#039;picture&#039;;&lt;br /&gt;
            $headers[]= &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
        if (!$table-&amp;gt;is_downloading()){&lt;br /&gt;
            $columns[]= &#039;fullname&#039;;&lt;br /&gt;
            $headers[]= get_string(&#039;name&#039;);&lt;br /&gt;
        } else {&lt;br /&gt;
            $columns[]= &#039;lastname&#039;;&lt;br /&gt;
            $headers[]= get_string(&#039;lastname&#039;);&lt;br /&gt;
            $columns[]= &#039;firstname&#039;;&lt;br /&gt;
            $headers[]= get_string(&#039;firstname&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($CFG-&amp;gt;grade_report_showuseridnumber) {&lt;br /&gt;
            $columns[]= &#039;idnumber&#039;;&lt;br /&gt;
            $headers[]= get_string(&#039;idnumber&#039;);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        $columns[]= &#039;timestart&#039;;&lt;br /&gt;
        $headers[]= get_string(&#039;startedon&#039;, &#039;quiz&#039;);&lt;br /&gt;
&lt;br /&gt;
        $columns[]= &#039;timefinish&#039;;&lt;br /&gt;
        $headers[]= get_string(&#039;timecompleted&#039;,&#039;quiz&#039;);&lt;br /&gt;
&lt;br /&gt;
        $columns[]= &#039;duration&#039;;&lt;br /&gt;
        $headers[]= get_string(&#039;attemptduration&#039;, &#039;quiz&#039;);&lt;br /&gt;
&lt;br /&gt;
        if ($detailedmarks) {&lt;br /&gt;
            foreach ($questions as $id =&amp;gt; $question) {&lt;br /&gt;
                // Ignore questions of zero length&lt;br /&gt;
                $columns[] = &#039;qsgrade&#039;.$id;&lt;br /&gt;
                $headers[] = &#039;#&#039;.$question-&amp;gt;number;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($showgrades) {&lt;br /&gt;
            $columns[] = &#039;sumgrades&#039;;&lt;br /&gt;
            $headers[] = get_string(&#039;grade&#039;, &#039;quiz&#039;).&#039;/&#039;.$quiz-&amp;gt;grade;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($hasfeedback) {&lt;br /&gt;
            $columns[] = &#039;feedbacktext&#039;;&lt;br /&gt;
            $headers[] = get_string(&#039;feedback&#039;, &#039;quiz&#039;);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        $table-&amp;gt;define_columns($columns);&lt;br /&gt;
        $table-&amp;gt;define_headers($headers);&lt;br /&gt;
        $table-&amp;gt;sortable(true, &#039;uniqueid&#039;);&lt;br /&gt;
        &lt;br /&gt;
        // Set up the table some of these settings will be ignored for downloads&lt;br /&gt;
        $table-&amp;gt;define_baseurl($reporturl-&amp;gt;out(false, $displayoptions));&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        $table-&amp;gt;column_suppress(&#039;picture&#039;);&lt;br /&gt;
        $table-&amp;gt;column_suppress(&#039;fullname&#039;);&lt;br /&gt;
        $table-&amp;gt;column_suppress(&#039;idnumber&#039;);&lt;br /&gt;
        &lt;br /&gt;
        $table-&amp;gt;no_sorting(&#039;feedbacktext&#039;);&lt;br /&gt;
&lt;br /&gt;
        $table-&amp;gt;column_class(&#039;picture&#039;, &#039;picture&#039;);&lt;br /&gt;
        $table-&amp;gt;column_class(&#039;fullname&#039;, &#039;bold&#039;);&lt;br /&gt;
        $table-&amp;gt;column_class(&#039;sumgrades&#039;, &#039;bold&#039;);&lt;br /&gt;
&lt;br /&gt;
        $table-&amp;gt;set_attribute(&#039;id&#039;, &#039;attempts&#039;);&lt;br /&gt;
&lt;br /&gt;
        $table-&amp;gt;out($pagesize, $useinitialsbar);&lt;br /&gt;
        &lt;br /&gt;
        if (!$table-&amp;gt;is_downloading()) {&lt;br /&gt;
            //footer and other html stuff to display&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Adding download capability to existing tables==&lt;br /&gt;
&lt;br /&gt;
To add download to existing tables. You must :&lt;br /&gt;
&lt;br /&gt;
Add :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $download = optional_param(&#039;download&#039;, &#039;&#039;, PARAM_ALPHA);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To top of page.&lt;br /&gt;
&lt;br /&gt;
Probably more table instantiation to top of page.&lt;br /&gt;
&lt;br /&gt;
Add just after table object instantiation :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$table-&amp;gt;is_downloading($download, &#039;test&#039;,&lt;br /&gt;
                    &#039;testing123&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wrap all html output with condition :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        if (!$table-&amp;gt;is_downloading()) {&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Make sure you have this method call somewhere :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $table-&amp;gt;define_baseurl($reporturl-&amp;gt;out(false, $displayoptions));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Replace :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $table-&amp;gt;print_html();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $table-&amp;gt;finish_output();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Download buttons will automagically appear.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* The phpdoc comments on the class flexible_table and table_sql in tablelib.php&lt;br /&gt;
* [http://tracker.moodle.org/browse/MDL-14187 Discussion in tracker]&lt;/div&gt;</summary>
		<author><name>Charlesverge</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=lib/tablelib.php&amp;diff=46859</id>
		<title>lib/tablelib.php</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=lib/tablelib.php&amp;diff=46859"/>
		<updated>2014-11-17T22:43:40Z</updated>

		<summary type="html">&lt;p&gt;Charlesverge: /* The Next Step : Typical Usage */ class name correction&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Status of this doc==&lt;br /&gt;
&lt;br /&gt;
This doc is a description of proposed additions to the api for using tablelib. It has not yet been agreed on. Seemed a good idea to create it at this url rather than some development notes page for instance so that the history of this page will include the changes made to the original proposal.&lt;br /&gt;
&lt;br /&gt;
==What changes in the new api?==&lt;br /&gt;
&lt;br /&gt;
* Currently the code for creating table often involves a lot of duplication of code. New api can improve things.&lt;br /&gt;
* New API handles downloads&lt;br /&gt;
** download export formats are seperated into classes and it is simple to add more formats. Added two more formats. Unpaged XHTML format and comma seperated values format.&lt;br /&gt;
* No longer have to make sure that column data is added to the table in the same order as columns are declared. Can have the logic for choosing what columns to include in the table in one place.&lt;br /&gt;
* New mechanism in table_sql allows appropriate code to be automatically called to format data before putting it into the table.&lt;br /&gt;
&lt;br /&gt;
==Skeleton Usage==&lt;br /&gt;
&lt;br /&gt;
In order to check your sql query is working as expected when developing a page it can be useful just to output all the data from the query in the table before going on to work out how you want to format data. The code below will output all the data from your query in a collapsible, sortable table. It automatically displays all columns returned from the db.&lt;br /&gt;
&lt;br /&gt;
You should go on to :&lt;br /&gt;
*specify what columns to include in the table and what names to display for the columns using define_columms and define_headers&lt;br /&gt;
*use your own child class of easy_table and define methods col_{columnname} to add hyperlinks etc to the table. You can also use method other_cols.&lt;br /&gt;
&lt;br /&gt;
See below for examples of typical usage.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php  // $Id$&lt;br /&gt;
/**&lt;br /&gt;
 * Simple file test.php to drop into root of Moodle installation.&lt;br /&gt;
 * This is the skeleton code to print a downloadable, paged, sorted table of&lt;br /&gt;
 * data from a sql query.&lt;br /&gt;
 */&lt;br /&gt;
require &amp;quot;config.php&amp;quot;;&lt;br /&gt;
require &amp;quot;$CFG-&amp;gt;libdir/tablelib.php&amp;quot;;&lt;br /&gt;
$context = context_system::instance();&lt;br /&gt;
$PAGE-&amp;gt;set_context($context);&lt;br /&gt;
$PAGE-&amp;gt;set_url(&#039;/test.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$download = optional_param(&#039;download&#039;, &#039;&#039;, PARAM_ALPHA);&lt;br /&gt;
&lt;br /&gt;
$table = new table_sql(&#039;uniqueid&#039;);&lt;br /&gt;
$table-&amp;gt;is_downloading($download, &#039;test&#039;, &#039;testing123&#039;);&lt;br /&gt;
&lt;br /&gt;
if (!$table-&amp;gt;is_downloading()) {&lt;br /&gt;
    // Only print headers if not asked to download data&lt;br /&gt;
    /// Print the page header&lt;br /&gt;
    $PAGE-&amp;gt;set_title(&#039;Testing&#039;);&lt;br /&gt;
    $PAGE-&amp;gt;set_heading(&#039;Testing table class&#039;);&lt;br /&gt;
    $PAGE-&amp;gt;navbar-&amp;gt;add(&#039;Testing table class&#039;, new moodle_url(&#039;/test.php&#039;));&lt;br /&gt;
    echo $OUTPUT-&amp;gt;header();&lt;br /&gt;
    //print_header_simple(&#039;Testing &#039;, &#039;Testing table class&#039;, $navigation);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//work out the sql for the table.&lt;br /&gt;
$table-&amp;gt;set_sql(&#039;*&#039;, &amp;quot;{$CFG-&amp;gt;prefix}user&amp;quot;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
$table-&amp;gt;define_baseurl(&amp;quot;$CFG-&amp;gt;wwwroot/test.php&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$table-&amp;gt;out(40, true);&lt;br /&gt;
&lt;br /&gt;
if (!$table-&amp;gt;is_downloading()) {&lt;br /&gt;
    $OUTPUT-&amp;gt;footer();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==The Next Step : Typical Usage==&lt;br /&gt;
&lt;br /&gt;
===Define table===&lt;br /&gt;
&lt;br /&gt;
Define table class in file somethingsomthing_table.php&lt;br /&gt;
&lt;br /&gt;
In the file define a child class of &#039;table_sql&#039;. Mostly this child class will just contain methods to format data for display.&lt;br /&gt;
&lt;br /&gt;
====Format data for display====&lt;br /&gt;
&lt;br /&gt;
Define methods col_{colmname} to process data from db and to add it to table. Eg. Here is an example from table class quiz_report_overview_table&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function col_timefinish($attempt){&lt;br /&gt;
        if ($attempt-&amp;gt;attempt) {&lt;br /&gt;
            if ($attempt-&amp;gt;timefinish) {&lt;br /&gt;
                $timefinish = userdate($attempt-&amp;gt;timefinish, $this-&amp;gt;strtimeformat);&lt;br /&gt;
                if (!$this-&amp;gt;is_downloading()) {&lt;br /&gt;
                    return &#039;&amp;lt;a href=&amp;quot;review.php?q=&#039;.$this-&amp;gt;quiz-&amp;gt;id.&#039;&amp;amp;amp;attempt=&#039;.$attempt-&amp;gt;attempt.&#039;&amp;quot;&amp;gt;&#039;.$timefinish.&#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
                } else {&lt;br /&gt;
                    return $timefinish;&lt;br /&gt;
                }&lt;br /&gt;
            } else {&lt;br /&gt;
                return  &#039;-&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        } else {&lt;br /&gt;
            return  &#039;-&#039;;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where you do not know the names of the columns at the time of writing the class definition then you can use other_cols method. Eg.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function other_cols($colname, $attempt){&lt;br /&gt;
        if (preg_match(&#039;/^qsgrade([0-9]+)$/&#039;, $colname, $matches)){&lt;br /&gt;
            $questionid = $matches[1];&lt;br /&gt;
            $question = $this-&amp;gt;questions[$questionid];&lt;br /&gt;
            $state = new object();&lt;br /&gt;
            $state-&amp;gt;event = $attempt-&amp;gt;{&#039;qsevent&#039;.$questionid};&lt;br /&gt;
            if (question_state_is_graded($state)) {&lt;br /&gt;
                $grade = quiz_rescale_grade($attempt-&amp;gt;{&#039;qsgrade&#039;.$questionid}, $this-&amp;gt;quiz);&lt;br /&gt;
            } else {&lt;br /&gt;
                $grade = &#039;--&#039;;&lt;br /&gt;
            }&lt;br /&gt;
            if (!$this-&amp;gt;is_downloading()) {&lt;br /&gt;
                $grade = $grade.&#039;/&#039;.quiz_rescale_grade($question-&amp;gt;grade, $this-&amp;gt;quiz);&lt;br /&gt;
                return link_to_popup_window(&#039;/mod/quiz/reviewquestion.php?state=&#039;.&lt;br /&gt;
                        $attempt-&amp;gt;{&#039;qsid&#039;.$questionid}.&#039;&amp;amp;amp;number=&#039;.$question-&amp;gt;number,&lt;br /&gt;
                        &#039;reviewquestion&#039;, $grade, 450, 650, get_string(&#039;reviewresponse&#039;, &#039;quiz&#039;),&lt;br /&gt;
                        &#039;none&#039;, true);&lt;br /&gt;
            } else {&lt;br /&gt;
                return $grade;&lt;br /&gt;
            }     &lt;br /&gt;
        } else {&lt;br /&gt;
            return NULL;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If there is no method col_{column name} and other_cols returns NULL then the column data is put straight in the table unprocessed.&lt;br /&gt;
&lt;br /&gt;
===Use your table class===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        //start page&lt;br /&gt;
        $download = optional_param(&#039;download&#039;, &#039;&#039;, PARAM_ALPHA);&lt;br /&gt;
&lt;br /&gt;
        $table = new name_of_your_table(&#039;uniqueid&#039;);&lt;br /&gt;
        $table-&amp;gt;is_downloading($download, $filenamefordownload, $sheettitle);&lt;br /&gt;
        if (!$table-&amp;gt;is_downloading()) {&lt;br /&gt;
            // Only print headers if not asked to download data&lt;br /&gt;
            $this-&amp;gt;print_header_and_tabs($cm, $course, $quiz, &amp;quot;overview&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
        //various page set up stuff&lt;br /&gt;
        if (!$table-&amp;gt;is_downloading()) { //do not print notices when downloading&lt;br /&gt;
            //wrap output of html in these if conditions&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        //work out the sql for the table.&lt;br /&gt;
&lt;br /&gt;
        //use this method only if you want to specify some sql with less joins for &lt;br /&gt;
        //counting the total records&lt;br /&gt;
        $table-&amp;gt;set_count_sql(&amp;quot;SELECT COUNT(1) FROM $from WHERE $where&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if ($something) {&lt;br /&gt;
            // Add some more joins&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        $table-&amp;gt;set_sql($fields, $from, $where);&lt;br /&gt;
        // Define table columns&lt;br /&gt;
        $columns = array();&lt;br /&gt;
        $headers = array();&lt;br /&gt;
        &lt;br /&gt;
&lt;br /&gt;
        if (!$table-&amp;gt;is_downloading() &amp;amp;&amp;amp; $candelete) {&lt;br /&gt;
            $columns[]= &#039;checkbox&#039;;&lt;br /&gt;
            $headers[]= NULL;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        if (!$table-&amp;gt;is_downloading() &amp;amp;&amp;amp; $CFG-&amp;gt;grade_report_showuserimage) {&lt;br /&gt;
            $columns[]= &#039;picture&#039;;&lt;br /&gt;
            $headers[]= &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
        if (!$table-&amp;gt;is_downloading()){&lt;br /&gt;
            $columns[]= &#039;fullname&#039;;&lt;br /&gt;
            $headers[]= get_string(&#039;name&#039;);&lt;br /&gt;
        } else {&lt;br /&gt;
            $columns[]= &#039;lastname&#039;;&lt;br /&gt;
            $headers[]= get_string(&#039;lastname&#039;);&lt;br /&gt;
            $columns[]= &#039;firstname&#039;;&lt;br /&gt;
            $headers[]= get_string(&#039;firstname&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($CFG-&amp;gt;grade_report_showuseridnumber) {&lt;br /&gt;
            $columns[]= &#039;idnumber&#039;;&lt;br /&gt;
            $headers[]= get_string(&#039;idnumber&#039;);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        $columns[]= &#039;timestart&#039;;&lt;br /&gt;
        $headers[]= get_string(&#039;startedon&#039;, &#039;quiz&#039;);&lt;br /&gt;
&lt;br /&gt;
        $columns[]= &#039;timefinish&#039;;&lt;br /&gt;
        $headers[]= get_string(&#039;timecompleted&#039;,&#039;quiz&#039;);&lt;br /&gt;
&lt;br /&gt;
        $columns[]= &#039;duration&#039;;&lt;br /&gt;
        $headers[]= get_string(&#039;attemptduration&#039;, &#039;quiz&#039;);&lt;br /&gt;
&lt;br /&gt;
        if ($detailedmarks) {&lt;br /&gt;
            foreach ($questions as $id =&amp;gt; $question) {&lt;br /&gt;
                // Ignore questions of zero length&lt;br /&gt;
                $columns[] = &#039;qsgrade&#039;.$id;&lt;br /&gt;
                $headers[] = &#039;#&#039;.$question-&amp;gt;number;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($showgrades) {&lt;br /&gt;
            $columns[] = &#039;sumgrades&#039;;&lt;br /&gt;
            $headers[] = get_string(&#039;grade&#039;, &#039;quiz&#039;).&#039;/&#039;.$quiz-&amp;gt;grade;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($hasfeedback) {&lt;br /&gt;
            $columns[] = &#039;feedbacktext&#039;;&lt;br /&gt;
            $headers[] = get_string(&#039;feedback&#039;, &#039;quiz&#039;);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        $table-&amp;gt;define_columns($columns);&lt;br /&gt;
        $table-&amp;gt;define_headers($headers);&lt;br /&gt;
        $table-&amp;gt;sortable(true, &#039;uniqueid&#039;);&lt;br /&gt;
        &lt;br /&gt;
        // Set up the table some of these settings will be ignored for downloads&lt;br /&gt;
        $table-&amp;gt;define_baseurl($reporturl-&amp;gt;out(false, $displayoptions));&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        $table-&amp;gt;column_suppress(&#039;picture&#039;);&lt;br /&gt;
        $table-&amp;gt;column_suppress(&#039;fullname&#039;);&lt;br /&gt;
        $table-&amp;gt;column_suppress(&#039;idnumber&#039;);&lt;br /&gt;
        &lt;br /&gt;
        $table-&amp;gt;no_sorting(&#039;feedbacktext&#039;);&lt;br /&gt;
&lt;br /&gt;
        $table-&amp;gt;column_class(&#039;picture&#039;, &#039;picture&#039;);&lt;br /&gt;
        $table-&amp;gt;column_class(&#039;fullname&#039;, &#039;bold&#039;);&lt;br /&gt;
        $table-&amp;gt;column_class(&#039;sumgrades&#039;, &#039;bold&#039;);&lt;br /&gt;
&lt;br /&gt;
        $table-&amp;gt;set_attribute(&#039;id&#039;, &#039;attempts&#039;);&lt;br /&gt;
&lt;br /&gt;
        $table-&amp;gt;out($pagesize, $useinitialsbar);&lt;br /&gt;
        &lt;br /&gt;
        if (!$table-&amp;gt;is_downloading()) {&lt;br /&gt;
            //footer and other html stuff to display&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Adding download capability to existing tables==&lt;br /&gt;
&lt;br /&gt;
To add download to existing tables. You must :&lt;br /&gt;
&lt;br /&gt;
Add :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $download = optional_param(&#039;download&#039;, &#039;&#039;, PARAM_ALPHA);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To top of page.&lt;br /&gt;
&lt;br /&gt;
Probably more table instantiation to top of page.&lt;br /&gt;
&lt;br /&gt;
Add just after table object instantiation :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$table-&amp;gt;is_downloading($download, &#039;test&#039;,&lt;br /&gt;
                    &#039;testing123&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wrap all html output with condition :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        if (!$table-&amp;gt;is_downloading()) {&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Make sure you have this method call somewhere :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $table-&amp;gt;define_baseurl($reporturl-&amp;gt;out(false, $displayoptions));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Replace :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $table-&amp;gt;print_html();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $table-&amp;gt;finish_output();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Download buttons will automagically appear.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* The phpdoc comments on the class flexible_table and table_sql in tablelib.php&lt;br /&gt;
* [http://tracker.moodle.org/browse/MDL-14187 Discussion in tracker]&lt;/div&gt;</summary>
		<author><name>Charlesverge</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=lib/tablelib.php&amp;diff=46858</id>
		<title>lib/tablelib.php</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=lib/tablelib.php&amp;diff=46858"/>
		<updated>2014-11-17T22:06:30Z</updated>

		<summary type="html">&lt;p&gt;Charlesverge: /* Skeleton Usage */ Updated code sample to be compatible with $PAGE-&amp;gt;navbar&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Status of this doc==&lt;br /&gt;
&lt;br /&gt;
This doc is a description of proposed additions to the api for using tablelib. It has not yet been agreed on. Seemed a good idea to create it at this url rather than some development notes page for instance so that the history of this page will include the changes made to the original proposal.&lt;br /&gt;
&lt;br /&gt;
==What changes in the new api?==&lt;br /&gt;
&lt;br /&gt;
* Currently the code for creating table often involves a lot of duplication of code. New api can improve things.&lt;br /&gt;
* New API handles downloads&lt;br /&gt;
** download export formats are seperated into classes and it is simple to add more formats. Added two more formats. Unpaged XHTML format and comma seperated values format.&lt;br /&gt;
* No longer have to make sure that column data is added to the table in the same order as columns are declared. Can have the logic for choosing what columns to include in the table in one place.&lt;br /&gt;
* New mechanism in table_sql allows appropriate code to be automatically called to format data before putting it into the table.&lt;br /&gt;
&lt;br /&gt;
==Skeleton Usage==&lt;br /&gt;
&lt;br /&gt;
In order to check your sql query is working as expected when developing a page it can be useful just to output all the data from the query in the table before going on to work out how you want to format data. The code below will output all the data from your query in a collapsible, sortable table. It automatically displays all columns returned from the db.&lt;br /&gt;
&lt;br /&gt;
You should go on to :&lt;br /&gt;
*specify what columns to include in the table and what names to display for the columns using define_columms and define_headers&lt;br /&gt;
*use your own child class of easy_table and define methods col_{columnname} to add hyperlinks etc to the table. You can also use method other_cols.&lt;br /&gt;
&lt;br /&gt;
See below for examples of typical usage.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php  // $Id$&lt;br /&gt;
/**&lt;br /&gt;
 * Simple file test.php to drop into root of Moodle installation.&lt;br /&gt;
 * This is the skeleton code to print a downloadable, paged, sorted table of&lt;br /&gt;
 * data from a sql query.&lt;br /&gt;
 */&lt;br /&gt;
require &amp;quot;config.php&amp;quot;;&lt;br /&gt;
require &amp;quot;$CFG-&amp;gt;libdir/tablelib.php&amp;quot;;&lt;br /&gt;
$context = context_system::instance();&lt;br /&gt;
$PAGE-&amp;gt;set_context($context);&lt;br /&gt;
$PAGE-&amp;gt;set_url(&#039;/test.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$download = optional_param(&#039;download&#039;, &#039;&#039;, PARAM_ALPHA);&lt;br /&gt;
&lt;br /&gt;
$table = new table_sql(&#039;uniqueid&#039;);&lt;br /&gt;
$table-&amp;gt;is_downloading($download, &#039;test&#039;, &#039;testing123&#039;);&lt;br /&gt;
&lt;br /&gt;
if (!$table-&amp;gt;is_downloading()) {&lt;br /&gt;
    // Only print headers if not asked to download data&lt;br /&gt;
    /// Print the page header&lt;br /&gt;
    $PAGE-&amp;gt;set_title(&#039;Testing&#039;);&lt;br /&gt;
    $PAGE-&amp;gt;set_heading(&#039;Testing table class&#039;);&lt;br /&gt;
    $PAGE-&amp;gt;navbar-&amp;gt;add(&#039;Testing table class&#039;, new moodle_url(&#039;/test.php&#039;));&lt;br /&gt;
    echo $OUTPUT-&amp;gt;header();&lt;br /&gt;
    //print_header_simple(&#039;Testing &#039;, &#039;Testing table class&#039;, $navigation);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//work out the sql for the table.&lt;br /&gt;
$table-&amp;gt;set_sql(&#039;*&#039;, &amp;quot;{$CFG-&amp;gt;prefix}user&amp;quot;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
$table-&amp;gt;define_baseurl(&amp;quot;$CFG-&amp;gt;wwwroot/test.php&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$table-&amp;gt;out(40, true);&lt;br /&gt;
&lt;br /&gt;
if (!$table-&amp;gt;is_downloading()) {&lt;br /&gt;
    $OUTPUT-&amp;gt;footer();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==The Next Step : Typical Usage==&lt;br /&gt;
&lt;br /&gt;
===Define table===&lt;br /&gt;
&lt;br /&gt;
Define table class in file somethingsomthing_table.php&lt;br /&gt;
&lt;br /&gt;
In the file define a child class of &#039;sql_table&#039;. Mostly this child class will just contain methods to format data for display.&lt;br /&gt;
&lt;br /&gt;
====Format data for display====&lt;br /&gt;
&lt;br /&gt;
Define methods col_{colmname} to process data from db and to add it to table. Eg. Here is an example from table class quiz_report_overview_table&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function col_timefinish($attempt){&lt;br /&gt;
        if ($attempt-&amp;gt;attempt) {&lt;br /&gt;
            if ($attempt-&amp;gt;timefinish) {&lt;br /&gt;
                $timefinish = userdate($attempt-&amp;gt;timefinish, $this-&amp;gt;strtimeformat);&lt;br /&gt;
                if (!$this-&amp;gt;is_downloading()) {&lt;br /&gt;
                    return &#039;&amp;lt;a href=&amp;quot;review.php?q=&#039;.$this-&amp;gt;quiz-&amp;gt;id.&#039;&amp;amp;amp;attempt=&#039;.$attempt-&amp;gt;attempt.&#039;&amp;quot;&amp;gt;&#039;.$timefinish.&#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
                } else {&lt;br /&gt;
                    return $timefinish;&lt;br /&gt;
                }&lt;br /&gt;
            } else {&lt;br /&gt;
                return  &#039;-&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        } else {&lt;br /&gt;
            return  &#039;-&#039;;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where you do not know the names of the columns at the time of writing the class definition then you can use other_cols method. Eg.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function other_cols($colname, $attempt){&lt;br /&gt;
        if (preg_match(&#039;/^qsgrade([0-9]+)$/&#039;, $colname, $matches)){&lt;br /&gt;
            $questionid = $matches[1];&lt;br /&gt;
            $question = $this-&amp;gt;questions[$questionid];&lt;br /&gt;
            $state = new object();&lt;br /&gt;
            $state-&amp;gt;event = $attempt-&amp;gt;{&#039;qsevent&#039;.$questionid};&lt;br /&gt;
            if (question_state_is_graded($state)) {&lt;br /&gt;
                $grade = quiz_rescale_grade($attempt-&amp;gt;{&#039;qsgrade&#039;.$questionid}, $this-&amp;gt;quiz);&lt;br /&gt;
            } else {&lt;br /&gt;
                $grade = &#039;--&#039;;&lt;br /&gt;
            }&lt;br /&gt;
            if (!$this-&amp;gt;is_downloading()) {&lt;br /&gt;
                $grade = $grade.&#039;/&#039;.quiz_rescale_grade($question-&amp;gt;grade, $this-&amp;gt;quiz);&lt;br /&gt;
                return link_to_popup_window(&#039;/mod/quiz/reviewquestion.php?state=&#039;.&lt;br /&gt;
                        $attempt-&amp;gt;{&#039;qsid&#039;.$questionid}.&#039;&amp;amp;amp;number=&#039;.$question-&amp;gt;number,&lt;br /&gt;
                        &#039;reviewquestion&#039;, $grade, 450, 650, get_string(&#039;reviewresponse&#039;, &#039;quiz&#039;),&lt;br /&gt;
                        &#039;none&#039;, true);&lt;br /&gt;
            } else {&lt;br /&gt;
                return $grade;&lt;br /&gt;
            }     &lt;br /&gt;
        } else {&lt;br /&gt;
            return NULL;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If there is no method col_{column name} and other_cols returns NULL then the column data is put straight in the table unprocessed.&lt;br /&gt;
&lt;br /&gt;
===Use your table class===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        //start page&lt;br /&gt;
        $download = optional_param(&#039;download&#039;, &#039;&#039;, PARAM_ALPHA);&lt;br /&gt;
&lt;br /&gt;
        $table = new name_of_your_table(&#039;uniqueid&#039;);&lt;br /&gt;
        $table-&amp;gt;is_downloading($download, $filenamefordownload, $sheettitle);&lt;br /&gt;
        if (!$table-&amp;gt;is_downloading()) {&lt;br /&gt;
            // Only print headers if not asked to download data&lt;br /&gt;
            $this-&amp;gt;print_header_and_tabs($cm, $course, $quiz, &amp;quot;overview&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
        //various page set up stuff&lt;br /&gt;
        if (!$table-&amp;gt;is_downloading()) { //do not print notices when downloading&lt;br /&gt;
            //wrap output of html in these if conditions&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        //work out the sql for the table.&lt;br /&gt;
&lt;br /&gt;
        //use this method only if you want to specify some sql with less joins for &lt;br /&gt;
        //counting the total records&lt;br /&gt;
        $table-&amp;gt;set_count_sql(&amp;quot;SELECT COUNT(1) FROM $from WHERE $where&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if ($something) {&lt;br /&gt;
            // Add some more joins&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        $table-&amp;gt;set_sql($fields, $from, $where);&lt;br /&gt;
        // Define table columns&lt;br /&gt;
        $columns = array();&lt;br /&gt;
        $headers = array();&lt;br /&gt;
        &lt;br /&gt;
&lt;br /&gt;
        if (!$table-&amp;gt;is_downloading() &amp;amp;&amp;amp; $candelete) {&lt;br /&gt;
            $columns[]= &#039;checkbox&#039;;&lt;br /&gt;
            $headers[]= NULL;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        if (!$table-&amp;gt;is_downloading() &amp;amp;&amp;amp; $CFG-&amp;gt;grade_report_showuserimage) {&lt;br /&gt;
            $columns[]= &#039;picture&#039;;&lt;br /&gt;
            $headers[]= &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
        if (!$table-&amp;gt;is_downloading()){&lt;br /&gt;
            $columns[]= &#039;fullname&#039;;&lt;br /&gt;
            $headers[]= get_string(&#039;name&#039;);&lt;br /&gt;
        } else {&lt;br /&gt;
            $columns[]= &#039;lastname&#039;;&lt;br /&gt;
            $headers[]= get_string(&#039;lastname&#039;);&lt;br /&gt;
            $columns[]= &#039;firstname&#039;;&lt;br /&gt;
            $headers[]= get_string(&#039;firstname&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($CFG-&amp;gt;grade_report_showuseridnumber) {&lt;br /&gt;
            $columns[]= &#039;idnumber&#039;;&lt;br /&gt;
            $headers[]= get_string(&#039;idnumber&#039;);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        $columns[]= &#039;timestart&#039;;&lt;br /&gt;
        $headers[]= get_string(&#039;startedon&#039;, &#039;quiz&#039;);&lt;br /&gt;
&lt;br /&gt;
        $columns[]= &#039;timefinish&#039;;&lt;br /&gt;
        $headers[]= get_string(&#039;timecompleted&#039;,&#039;quiz&#039;);&lt;br /&gt;
&lt;br /&gt;
        $columns[]= &#039;duration&#039;;&lt;br /&gt;
        $headers[]= get_string(&#039;attemptduration&#039;, &#039;quiz&#039;);&lt;br /&gt;
&lt;br /&gt;
        if ($detailedmarks) {&lt;br /&gt;
            foreach ($questions as $id =&amp;gt; $question) {&lt;br /&gt;
                // Ignore questions of zero length&lt;br /&gt;
                $columns[] = &#039;qsgrade&#039;.$id;&lt;br /&gt;
                $headers[] = &#039;#&#039;.$question-&amp;gt;number;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($showgrades) {&lt;br /&gt;
            $columns[] = &#039;sumgrades&#039;;&lt;br /&gt;
            $headers[] = get_string(&#039;grade&#039;, &#039;quiz&#039;).&#039;/&#039;.$quiz-&amp;gt;grade;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($hasfeedback) {&lt;br /&gt;
            $columns[] = &#039;feedbacktext&#039;;&lt;br /&gt;
            $headers[] = get_string(&#039;feedback&#039;, &#039;quiz&#039;);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        $table-&amp;gt;define_columns($columns);&lt;br /&gt;
        $table-&amp;gt;define_headers($headers);&lt;br /&gt;
        $table-&amp;gt;sortable(true, &#039;uniqueid&#039;);&lt;br /&gt;
        &lt;br /&gt;
        // Set up the table some of these settings will be ignored for downloads&lt;br /&gt;
        $table-&amp;gt;define_baseurl($reporturl-&amp;gt;out(false, $displayoptions));&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        $table-&amp;gt;column_suppress(&#039;picture&#039;);&lt;br /&gt;
        $table-&amp;gt;column_suppress(&#039;fullname&#039;);&lt;br /&gt;
        $table-&amp;gt;column_suppress(&#039;idnumber&#039;);&lt;br /&gt;
        &lt;br /&gt;
        $table-&amp;gt;no_sorting(&#039;feedbacktext&#039;);&lt;br /&gt;
&lt;br /&gt;
        $table-&amp;gt;column_class(&#039;picture&#039;, &#039;picture&#039;);&lt;br /&gt;
        $table-&amp;gt;column_class(&#039;fullname&#039;, &#039;bold&#039;);&lt;br /&gt;
        $table-&amp;gt;column_class(&#039;sumgrades&#039;, &#039;bold&#039;);&lt;br /&gt;
&lt;br /&gt;
        $table-&amp;gt;set_attribute(&#039;id&#039;, &#039;attempts&#039;);&lt;br /&gt;
&lt;br /&gt;
        $table-&amp;gt;out($pagesize, $useinitialsbar);&lt;br /&gt;
        &lt;br /&gt;
        if (!$table-&amp;gt;is_downloading()) {&lt;br /&gt;
            //footer and other html stuff to display&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Adding download capability to existing tables==&lt;br /&gt;
&lt;br /&gt;
To add download to existing tables. You must :&lt;br /&gt;
&lt;br /&gt;
Add :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $download = optional_param(&#039;download&#039;, &#039;&#039;, PARAM_ALPHA);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To top of page.&lt;br /&gt;
&lt;br /&gt;
Probably more table instantiation to top of page.&lt;br /&gt;
&lt;br /&gt;
Add just after table object instantiation :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$table-&amp;gt;is_downloading($download, &#039;test&#039;,&lt;br /&gt;
                    &#039;testing123&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wrap all html output with condition :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        if (!$table-&amp;gt;is_downloading()) {&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Make sure you have this method call somewhere :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $table-&amp;gt;define_baseurl($reporturl-&amp;gt;out(false, $displayoptions));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Replace :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $table-&amp;gt;print_html();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $table-&amp;gt;finish_output();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Download buttons will automagically appear.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* The phpdoc comments on the class flexible_table and table_sql in tablelib.php&lt;br /&gt;
* [http://tracker.moodle.org/browse/MDL-14187 Discussion in tracker]&lt;/div&gt;</summary>
		<author><name>Charlesverge</name></author>
	</entry>
</feed>