Run a scheduled task immediately

To run a scheduled task immediately, navigate to Site administration, Server, Scheduled Tasks.

Edit the relevant task and adjust the Minute / Hour to * so that the Next run changes to ASAP.

When the cron is next run the scheduled task will also be run. You might also need to manually trigger the cron depending on how that is set up.


Moodle versions in git

All versions of Moodle are appropriately tagged in the Moodle git repository (git:// so you can use the following to show the commits that relate to each version. Just a note too that major versions are branched using the convention MOODLE_XX_STABLE where XX is the version e.g. MOODLE_36_STABLE for Moodle 3.6.

git show-ref --tags

This gives you something like this:

30e069a061296bef321b31b791a4366a953cae23 refs/tags/v3.6.1
008baea92aa20ee7ff619d37cc6568b076cda00c refs/tags/v3.6.2
ec902921430745139548095e45380ed017acd770 refs/tags/v3.6.3

Here you can see that the v3.6.1 tag has the commit hash 30e069a061296bef321b31b791a4366a953cae23 (the tag is just an alias for that hash).

Use the version.php file to find out the details of that version using the tag as a shortcut e.g.

git show v3.6.1:version.php

Sometimes you want to know what files changed between versions, you can use git diff with the --stat option for that:

git diff v3.6.2 v3.6.3 --stat

If you use a diff/merge tool (e.g. Araxis Merge) you can use the --dir-diff to get a full directory comparison of changes between tags as well. Very handy.

git difftool --dir-diff v3.6.1 v3.6.2

One other useful thing is to look at the log between two tags like so:

git log --oneline v3.6.1..v3.6.2

Handy to see what Moodle fixes were added between tags (MDL-) which you can check against the Moodle Tracker


Query the grade scale value for a grade (MySQL)

Grade scales are stored in the mdl_scale table, however they are stored as a comma-separated list in the scale column, which makes them quite difficult to query directly from the database. Because the grade is just a number (e.g. 1, 2, 3), it is far more useful to show the corresponding grade scale grade description.

For example, the grade scale might have the following value stored in the scale column (formatted for readability with index):

(1) Mostly separate knowing,
(2) Separate and connected,
(3) Mostly connected knowing

So a final grade of 2 would translate to “Separate and connected” if using this grade scale.

You can use the substring_index function in MySQL to perform a look up of the corresponding grade scale value (grade description) using the grade value.

Here’s the SQL:

scale, trim(substring_index(substring_index(scale, ',', 2), ',', -1))
from mdl_scale where id = 1;

Simply, replace the index in the inner substring_index call with the appropriate grade value (e.g. 1, 2, or 3) for this scale and it will give you corresponding grade scale grade description.


Plugin Dependencies

Plugin dependencies can be added using the $plugin->dependencies attribute in version.php.

There are quite a few examples in the code base, for example:

filter_data depends on mod_data so the following appears in the filter/data/version.php:

$plugin->dependencies = array('mod_data' => 2014050800);

Move download button and select below table

If you are working with flexibile tables (lib/tablelib.php) in Moodle and have table download enabled, you can move the “Download table data as” select and button below the table by adding the following line before finishing your table setup:


By default they appear above the table but this doesn’t always look so good and takes up screen space.


Working with dates before epoch

If you use a custom user profile field with a date and want to store a date that falls before epoch, 01/01/1970 (e.g. a date of birth), the data will be stored as a negative number
e.g. 20/11/1959 is stored as -319284000 which means 319, 284, 000 seconds BEFORE 01/01/1970.

With MySQL you can convert these with the following SQL which works for both scenarios (before and after epoch, 01/01/1970):

select date_add(from_unixtime(0), interval data second) from mdl_user_info_field

Where in the above “data” is the column that returns the stored user profile field value e.g. date of birth from the mdl_user_info_field record.

If you just want the date (no timestamp):

select date(date_add(from_unixtime(0), interval data second)) from mdl_user_info_field

Display SQL generated by $DB methods

If you need to debug the SQL generated by any of the $DB methods (DML API), you can use the following around the statement(s) to display the SQL:




Getting the Moodle base / root directory

The moodle root directory $CFG->dirroot is established in the file lib/setup.php along with other values in the global $CFG object which combines configuraton from config.php as well as the entries in the database table mdl_config.

The value is set as follows:

$CFG->dirroot = dirname(dirname(__FILE__));

And you can use it reliably establish the base/root moodle directory absolute path and use it for things like file requires in your plugin.

Some other useful entries in lib/setup.php from the code:

$CFG->wwwroot  - Path to moodle index directory in url format.
$CFG->dataroot - Path to moodle data files directory on server's filesystem.
$CFG->dirroot  - Path to moodle's library folder on server's filesystem.
$CFG->libdir   - Path to moodle's library folder on server's filesystem.
$CFG->tempdir  - Path to moodle's temp file directory on server's filesystem.
$CFG->cachedir - Path to moodle's cache directory on server's filesystem (shared by cluster nodes).
$CFG->localcachedir - Path to moodle's local cache directory (not shared by cluster nodes).

Lots more in there have a dig around in lib/setup.php.


Make a select form field required

When adding a form rule for select (or multiple select) fields, these need to be applied on the client side (not server side). Here’s an example of how to add a rule for a select field:

            get_string("selectfieldrequiredmessage", "local_yourplugin"), 

The key is the 5th parameter above which is set to client instead of the default of server.

For more help, see the Moodle Forms library developer documentation.


Can’t create a new XMLDB file

The Moodle XMLDB plugin does some checks of the db/ folder in your plugin to ensure it has read/write access before allowing certain permissions (e.g. create and load). If it doesn’t find this, the text will appear but it won’t be a hyperlink.

Have a look in admin/tool/xmldb/actions/main_view/main_view.class.php

For example for the create button it will have:

 // The create button
                if ($dbdir->path_exists &&
                    !file_exists($key . '/install.xml') &&
                    is_writeable($key)) {                                       

So the db directory needs to exist and be writable by the user running the Moodle instance (e.g. if using apache the user that apache runs as).


Scheduled Tasks: A lock was created but not released

Schedule tasks can use two types of locks:
* Database locks — lock_db table
* File locks — dirroot/lock

The follow error can occur when running a cron through the CLI for example:

!!! Coding error detected, it must be fixed by a programmer: A lock was created but not released at:
[dirroot]/lib/classes/task/manager.php on line 483

 Code should look like:

 $factory = \core\lock\lock_config::get_lock_factory('type');
 $lock = $factory->get_lock(Resource id #585);
 $lock->release();  // Locks must ALWAYS be released like this.

As a starting point, trying disabling the schedule task causing the error and see if you can get the cron to run successfully.

You can try clearing out the locks as well from the database/filestore (whichever is relevant) and running the cron again.


Setting up a Moodle Development Environment with Cloud9 IDE

Cloud9 is a cloud based development environment. Behind the scenes it uses Docker containers to provide an awesome IDE together with a Workspace using Ubuntu. What this means it that you can you set up a fully integrated Moodle development environment on Cloud9!

This tutorial uses Moodle 3.1 for because as of May 2017 Cloud9 ships by default with PHP 5.5.9 which doesn’t meet the minimum requirements for Moodle 3.2 ( You can work around this but it is more involved so for now, lets stick with Moodle 3.1.

To start with, signup for a new (free account). Note while the account is free, it will require you to enter a credit card just to verify your identity.

Once you have an account and have logged in, add a new Workspace.

  • Enter your workspace name (e.g. Moodle)
  • A description e.g. Moodle 3.1 Development Environment
  • Choose Private (you get one free private workspace) or public
  • Choose a template and select PHP, APache & MySQL
  • Create your workspace

Note most of the steps that follow are just regular linux commands and set up instructions for installing Moodle.
Nothing particularly specific to Cloud9, but there are a few instances where the commands vary slighly e.g. for accessing the MySQL CLI.

Cloning Moodle via Git

Once you see your IDE, go to the terminal at the bottom. The first step is to clone moodle via git.

You should be in ~/workspace (if not cd ~/workspace).

git clone git:// moodle

This will clone it to ~/workspace/moodle

Once finished, checkout the MOODLE_31_STABLE branch

git checkout MOODLE_31_STABLE

Now we want to move everything in moodle to the ~/workspace folder as that is the base directory used when you choose Run Project.

cd ~/workspace/moodle
mv * ../
mv .* ../
cd ..
rmdir moodle

Note you will see the following message which can be ignored. Its just to get all the .* files into the workspace folder.

mv: cannot move ‘.’ to ‘../.’: Device or resource busy
mv: cannot move ‘..’ to ‘../..’: Device or resource busy

Now you have everything that was cloned in~/workspace/moodle in the ~/workspace folder and it should show you are in the MOODLE_31_STABLE branch

<user>~/workspace (MOODLE_31_STABLE) $ 

Setting up the Database

Next we need to set up a MySQL database. In the terminal type:

mysql-ctl cli

Note you may need to type mysql-ctl install if it is not already installed

Create your moodle database, user and give the user full access to the database.

mysql> create database moodle character set utf8 collate utf8_general_ci;
mysql> create user moodle@localhost identified by 'moodle';
mysql> grant all on moodle.* to moodle@localhost;

mysql> exit

Setting up the data directory

We’ll put this under ~/moodledata
Create this directory:

mkdir ~/moodledata

( Note you could do this via the file manager on the left hand side of the IDE if you click on the small cog in the left pane and choose “Show Home in Favourites”. )

Install Moodle

Ok, you are ready to hit “Run Project” to fire up Apache & PHP.
This will open in a new tab and give you a URL to where it is serving e.g.

Go ahead and visit that page or click on the link and choose open. Hopefully you see the Moodle installation screen. Note on the first few screens before the license the stylesheet/layout won’t look great, but it will sort itself out later on.

Follow the prompts:

  • Pick your language
  • Your web address, Moodle directory (workspace) and Data directory (moodledata) should all default
  • Database drive is MySQL (native/mysqli)
  • Database host is localhost (default) name is moodle (default) enter user as moodle and password as moodle and choose next (prefix/port/socket all stay at defaults).
  • You should see the installation screen and license, choose continue.
  • All server checks should pass, so choose continue
  • The installation will take a while, let it run through. When finished you will see a continue button on the bottom of the page (may need to scroll to the end).
  • When finished you should see a screen where you can set up your admin user account. Make sure you enter a valid email here.
  • Finally you can enter your front page settings; the full site name e.g. Moodle 3.1 Development Environment and short name e.g. moodle31dev. Update your timezone and save.

That’s it, you have a working Moodle 3.1.x environment that you can now development against with the Cloud 9 IDE!


Unknown Error Upgrading Plugin to Version

If you are getting an error like this when attempting to upgrade a plugin:

!!! Unknown error upgrading <pluginname> to version 2017042400, can not continue. !!!
Error code: upgradeerror !!
!! Stack trace: * line 340 of /lib/upgradelib.php: upgrade_exception thrown
* line 549 of /lib/upgradelib.php: call to upgrade_plugin_savepoint()
* line 1630 of /lib/upgradelib.php: call to upgrade_plugins()
* line 171 of /admin/cli/upgrade.php: call to upgrade_noncore()

Then it might be simply due to a missing line in your db/upgrade.php file.

Check that in your function xmldb_<type>_<pluginname>_upgrade($oldversion) function you have a final line that returns a true value.
That is: return true at the end of the function.


XMLDB Editor and Reserved Names

One (of the many) good reasons to use the XMLDB editor in Moodle rather than hacking the db/install.xml file directly is that it warns you if you use a reserved name. For example:

XMLDB Reserved name error

The red Reserved text after [XML] in the screenshot is indicating that the word “column” is reserved and shouldn’t be used. It would be nice if it stopped you from saving such a change (it doesn’t) but at least it indicates a problem.

The Reserved link points to the following location if you ever want to look up the currently used reserved words:


This link also shows you potential existing problems in your XMLDB that may need to be fixed.


Site stuck at upgrade running

For example you might see this message:

!!! Site is being upgraded, please retry later. !!!

Whenever a site upgrade is triggered, an entry is added into the database in the mdl_config table:

name=upgraderunning value=unixtimestamp that the upgrade was started

This is by design and deliberate to prevent changes to the site while things are being upgraded.

However if you ever have a site stuck indefinitely on upgrade, you might need to clear this out of the DB. At least check for the value in mdl_config but be careful here, you may break things if you clear out an upgrade that is still running somewhere in the background.

Don’t forget to clear your moodle cache if you do make a change to the mdl_config table.


Replacing strings in the database through the CLI

There is a tool provided with Moodle to replace strings in your database with another value. This is very useful for things such as site address or domain name changes, and changes from non-SSL (http) to SSL (https).

The tool can be accessed via the following relative URL as a site administrator.

While you can certainly run it from the browser / site, it can timeout and cause problems to do so. Therefore the CLI version is a far better option and available in the moodle code tree under:


php admin/tool/replace/cli/replace.php

Search and replace text throughout the whole database.

--search=STRING       String to search for.
--replace=STRING      String to replace with.
--shorten             Shorten result if necessary.
--non-interactive     Perform the replacement without confirming.
-h, --help            Print out this help.

Note you might need sudo above. So lets say you change your site form to you could run it like so:

php admin/tool/replace/cli/replace.php 
--search= --replace=  --non-interactive

This will scan through tables and give you results in the console as it is going. The non-interactive flag prevents prompting (assuming you are comfortable with the change). If you aren’t you probably shouldn’t use the tool or at least use it on a test site first. The shorten result flag shouldn’t be necessary in most cases.


Resetting a user’s password through the CLI

If you have access to the Moodle server, you can use the admin/cli/reset_password.php script to reset passwords for users with the manual authentication method.

To run this script (from the moodle root code directory), note you may need to sudo as a user with write privileges to the $CFG->dataroot directory.

php admin/cli/reset_password.php

== Password reset ==
Enter username (manual authentication only)
: moodletips
Enter new password
: moodletips

Note the password you specified has to match the password rules configured in Moodle for example the above password moodletips by default would throw:

Passwords must have at least 1 digit(s).
Passwords must have at least 1 upper case letter(s).
Passwords must have at least 1 non-alphanumeric character(s) such as as *, -, or #.

Very handy if you are unable to get into the Moodle site for any reason, or need a quick way to reset a user’s password.


Set User IDs that will always see debug messages

There’s a handy feature in Moodle configuration called $CFG->debugusers = '<moodle_user_ids>' that allows you to set certain user IDs to always see debug messages regardless fo the Site administration > Development > Debugging settings for the site. This can be a comma separated list of Moodle User Ids (from the user table). Set this in the config.php or see config-dist.php for more details.

Useful if you need to troubleshoot an error but don’t want to increase debug level for the entire system and catch messages for the other users in the system too.


Course file system space usage query

The following query provides a summary of the file space usage (in bytes) and number of files used by each course in the system from the mdl_files meta table for the data directory. This is just for the space used in the data directory (not the database).

    c.fullname as course_full_name,
    c.shortname as course_short_name,
    sum(f.filesize) as size_in_bytes,
    sum(case when (f.filesize > 0) then 1 else 0 end) as number_of_files
    mdl_files f inner join mdl_context x
    on f.contextid =
    and x.contextlevel = 50
    inner join mdl_course c
    on = x.instanceid
group by 
    f.contextid, x.instanceid
order by 
    sum(filesize) desc

It may need some refinement. Context level 50 refers to courses.


Overriding PHP Settings

There are a few ways to override global PHP (php.ini) settings with local settings. For example you can use a .htaccess file or local php.ini file depending on what options exist for your site hosting.

Another way to do it, is to override the settings in config.php. This has the benefit of being part of the standard moodle code configuration setup. All you need to do is use the ini_set() function. For example, to increase the max_execution_time from 30s to 60s you can do this in config.php:

ini_set('max_execution_time', 60);

The best place for a change like this is towards the end of the config.php, and perhaps wrapped in comments indicating custom configuration.


Getting PHP Info for your Moodle Site

There is a handy link under Site adminstration > Server > PHP Info ( or browse to ) that will return the standard PHP Info phpinfo() results for your server.

Very handy for checking things like installed modules and core parameters if you are overriding them ( e.g. error_log, max_execution_time, post_max_size, upload_max_size etc )


Moodle Debug Log Level Values

These are the values you can set for the debug level under Site administration > Development > Debugging for Debug message (debug).
You can also query this from the mdl_config table looking at the key debug.

  • 0 = NONE: Do not show any errors or warnings
  • 5 = MINIMAL: Show only fatal errors
  • 15 = NORMAL: Show errors, warnings and notices
  • 30719 = ALL: Show all reasonable PHP debug messages
  • 32767 = DEVELOPER: extra Moodle debug messages for developers

Those are values you can set in the database for the debug entry in mdl_config if you need to check or change this on the database. Good idea to purge the cache when you do too.

These are defined with PHP error constants in lib/setuplib.php as follows (note this might change depending on versions):


Extended characters in moodle usernames

If you need to use extended characters in usernames, there is a setting under Site Administration > Security > Site Policies called Allow extended characters in usernames extendedusernamechars.

By default moodle usernames must be lowercase and are restricted to alphanumeric characters, the underscore, hypen, period and @ symbol.

You don’t need this if you are using email addresses as usernames (as the @ symbol is allowed) but you might run into a few other edge cases with email addresses:

  • Emails that are mixed case e.g. need to be lowercased to
  • Emails can have other characters such as an apostrophe (e.g. jack.o’ and if you want to preserve such characters you’ll need to turn this setting on. Alternatively you can remove such characters from the username.
  • Emails might have extended language characters in them which required this setting to be turned on as well if you want to match the username to the email addresse exactly.

Also worth noting is that the lib/classes/user.php definition uses PARAM_USERNAME (not PARAM_RAW) anymore in recent versions of moodle. This is used for things like the core user web services. So you will hit invalid parameter exceptions if you specify a username in say mixed case format or with extended characters (and the extendedusernamechars setting is off). This can be confusing it seems like you have specified the wrong parameters but what’s happening is that your parameter does not follow the definition of PARAM_USERNAME. To see the code used to test PARAM_USERNAME have a look in lib/moodlelib.php -> clean_param()


Query blocks instances and positions through the database

The following query gives you an idea of all the moodle blocks that have been added to various pages on your site and where they are positioned:

select bi.*, bp.*, x.*
from mdl_block_instances bi inner join mdl_block_positions bp
on = bp.blockinstanceid
inner join mdl_context x
on = bp.contextid
order by bi.blockname;

Very handy if you have a block that is causing you problems e.g. not fully uninstalled or visible to users.

The pagetypepattern e.g. *, site_index, my-index, course-view-* tells you which page types the block will be shown on, while the pagetype gives you the specific instances where it appears.

The context information at the end can also tell you the contextlevel (e.g. 50 = course, 70 = module) and the instance of that context (e.g. x.instanceid = 2 means course id 2 if the contextlevel is 50 (course context).


Verify your Moodle Database Schema against XMLDB

There is a very handy CLI tool admin/cli/check_database_schema.php which compares the structure of your Moodle database against the XMLDB metadata and looks for any issues.

These might includes issues such as:

  • Missing tables – they exist in XMLDB but not in your DB (not good!)
  • Unexpected tables – tables in your database not defined in XMLDB (e.g. created outside of Moodle)
  • Mismatches between table column definitions in the database and XMLDB

Some things may be acceptable to ignore, but it pays to do a check, particularly after an upgrade to make sure the upgrade process worked correctly and in particular you aren’t missing any core or plugin database tables that are defined in XMLDB, as these will pop up as database errors in your application sooner or later (e.g. “Error reading from database”).

If you need to build any missing core tables, remember they are defined under Developer > XMLDB Editor. From here find lib/db (core database tables) and choose Load, followed by Edit. Find the table you need and choose Edit. You can then use View SQL code to get the relevant SQL commands to create the table if it is missing from your database.

Also as a developer, make sure you are correctly utilising XMLDB for defining your plugin’s database tables. Taking shortcuts such as directly creating tables in the database without defining them in XMLDB will mean that they will pop up as unexpected when checking the database schema.


MySQL query to get a list of Site Admin users

The following SQL will help you see which users are site admins in a MySQL (or MariaDB) database using the find_in_set function to query the values listed in the mdl_config siteadmins key-value.

    mdl_user u
    find_in_set(, (select value from mdl_config where name = 'siteadmins'))

Note you need to use find_in_set and NOT in as it doesn’t handle the commas returned to separate each siteadmin’s user ID.


CLI Maintenance Mode

Newer versions of Moodle now provide the ability to put a site into maintenance mode through the CLI:

This can be found under the standard admin CLI location

php admin/cli/maintenance.php

Options include

php admin/cli/maintenance.php --enable
php admin/cli/maintenance.php --disable

NOTE this disables all web access to the site and can only be restored by disabling maintenance mode through the CLI again. This is exactly what you want if you need to take a proper site backup. The message displayed will be the maintenance mode message set up under Site Administration > Server > Maintenance Mode > Optional maintenance message (maintenance_message).

There is also a cool feature to enable it later e.g.

php admin/cli/maintenance.php --enablelater=60

Which would enable it after 60 minutes. This will tell exactly when maintenance mode will be enabled too. Good for making sure the site is in maintenance mode when you are ready to start an upgrade for example.

Finally there is an option called “enableold”

php admin/cli/maintenance.php --enableold

This is meant to do the same thing as the user interface Site Administration > Server > Maintenance Mode > Maintenance mode setting. That is site admins still have access to the site but the site is otherwise in maintenance mode for everyone else. This works in Moodle 3.2 but I’ve had problems with it in prior versions of moodle. It could possibly be around caching and might be important to also clear the moodle cache at the same time.


Web service Access control exception

If you are creating or using a web service in Moodle and see the following message:

    "exception": "webservice_access_exception",
    "errorcode": "accessexception",
    "message": "Access control exception"

It can be a bit hard to troubleshoot. Generally there is a 4th item with debugging info, but this will only appear if you have the correct Moodle debugging level set in Site administration > Development > Debugging.

At minimum you’ll need to set Debug messages to NORMAL: Show errors, warnings and notices. That is, it won’t apear if you have it set to NONE or MINIMAL.

Once you do that you should get that 4th parameter:

    "exception": "webservice_access_exception",
    "errorcode": "accessexception",
    "message": "Access control exception",
    "debuginfo": "You are not allowed to use the {$a} protocol (missing capability: webservice/rest:use)"

In this instance, user that is associated with the web service token didn’t have the capability webservice/rest:use in their system role. Adding the capability to the role fixed the issue.


Plugin is defective or outdated, Self test failed

You may see an error like this when upgrading a block:

Default exception handler: Plugin "{block name}" is defective or outdated, can not continue, sorry. Debug: Self test failed.
Error code: detectedbrokenplugin
* line 833 of /lib/upgradelib.php: plugin_defective_exception thrown
* line 425 of /lib/upgradelib.php: call to upgrade_plugins_blocks()
* line 1639 of /lib/upgradelib.php: call to upgrade_plugins()
* line 465 of /admin/index.php: call to upgrade_noncore()

To see what self tests are occuring check the blocks/moodleblock.class.php file at the _self_test() function and check that hte block matches the criteria for having a title, appropriate content, applicable formats, preferred width etc.


Finding specific Moodle versions in the Moodle Git Repository

The key to working with the Moodle git repository ( is to look at changes to the version.php file in the main moodle directory which tells you the moodle version.

You can use the whatchanged git command to get a summary of all changes and tags.

git whatchanged -p version.php

But more than likely if you are upgrading or patching you want to find a specific Moodle version. For example, I want to find the commit that relates to “Moodle release 3.1.2” which has the following in the version variable:


To find that use whatchanged to search for that value like so:

git whatchanged -p -S2016052302.00 version.php

This gets you the results that revolve around that version change, e.g. perhaps you want the change from version v3.1.1 to v3.1.2.
Once you have the commit hash e.g. f851201 you can then checkout that hash for example to see that specific version. Make sure you confirm you have what you need by looking at version.php first.

git checkout f851201-B moodle

Table formats from Antelope to Barracuda

On your environments page, as of around Moodle 2.6 you might see a message like this:

unsupported_db_table_row_format if this test fails, it indicates a potential problem

Your database has tables using Antelope as the file format. You are recommended to convert the tables to the Barracuda file format. See the documentation Administration via command line for details of a tool for converting InnoDB tables to Barracuda.

If you are running MySQL/MariaDB, this message is advising you should move to the better InnoDB Barracuda format.

To perform the table upgrades, you use the Moodle cli (i.e. admin/cli) and run the following commands (prefix with sudo if relevant):

php admin/cli/mysql_compressed_rows.php -l

This lists tables that need compacting/compressing e.g.

mdl_data                        Compact     (needs fixing)
mdl_data_fields                 Compact     (needs fixing)
mdl_enrol_paypal                Compact     (needs fixing)
mdl_lti                         Compact     (needs fixing)
mdl_user                        Compact     (needs fixing)
mdl_user_info_field             Compact     (needs fixing)

To fix, run the following. Note this can be database intensive so avoid running during high load periods or when there are a lot of active users on the site.

php admin/cli/mysql_compressed_rows.php -f

mdl_data                         ... Compressed
mdl_data_fields                  ... Compressed
mdl_enrol_paypal                 ... Compressed
mdl_lti                          ... Compressed
mdl_user                         ... Compressed
mdl_user_info_field              ... Compressed

To confirm all is well, run the first info command again or check the admin/environment.php page again.


Updating the Moodle Frontpage Summary through the database

You might have the need to update the Moodle front page summary through the database rather than through the UI. For example you might get an error editing the summary after a clone, or you might want to script the cloning process and change the frontpage text through the database.

Here are the steps:

Update the moodle course sections summary field for the relevant course and summary (you might need to find these first) for your frontpage.
The course ID is probably 1 for your frontpage, but you’ll need to confirm this. You can find the section id by looking at the URL that is used to edit the section (e.g. http://localhost/course/editsection.php?id=xxx).

update mdl_course_sections 
set summary = 'Your text/HTML' 
where course = x 
and section = y;

You’ll probably find that even after you purge the moodle cache this doesn’t take effect. You’ll need to also clear your course section cache with the following SQL.

update mdl_course set sectioncache = '' where id = x;

Alternatively with newer versions of moodle you may also need to purge your moodle cache.


Upgrading database schema using upgrade.php

If you need to upgrade your database schema for a custom plugin, e.g. adding a new table or changing the properties of an existing table, you should do it through db/upgrade.php per the suggestions in the MoodleDocs UpgradeAPI.

This isn’t a bad idea to do even when iterating through development as it isn’t a lot of work to keep things synchronised through the XMLDB editor and you won’t miss something later.

These are the basic steps involved:

  • Use the Moodle XMLDB editor to adjust your schema: Site adminstration > Development > XMLDB editor
  • Copy the relevant changes into your install.xml and upgrade.php straight from the editor
  • Update your plugin version and test.

The Moodle XMLDB editor actually makes this very easy.

  • Open the XMLDB editor
  • Find your plugin (assuming it is already installed etc). If you haven’t managed to get this far, at least install what you have so it will show up in XMLDB editor. Note you do not need to have anything DB related defined for this to work.
    Load the DB for you plugin or if nothing is defined using Create.
  • Follow the UI to create your table, fields, keys and indexes
  • When you are ready use View PHP code to get the code to go into db/upgrade.php
  • Go all the way back to the main XMLDB editor screen (where you can see all plugin databases) and use save to save the XML to db/install.xml as well.

How to get a list of the Moodle Core Git Branches

Use the following git command to get a list of all the Moodle core git branches.

git ls-remote git:// | grep head

This returns a bunch of hashes and the refs/heads/[MOODLE_XX_STABLE] branches. You can guess these, so this is just to check what they are without having to clone the entire repository. Plus you’ll know when a new stable branch is available in the repository.

To clone a specific branch (e.g. say I only want Moodle 2.2), use this command in the relevant target directory (note the -t to include tags so you can go to specific tags like v2.2.2):

git clone -b MOODLE_22_STABLE git://

Disable plugin installation

A really simple way to disable the installation of a plugin is to set the value:

$plugin->version = 0;

In the plugin’s version.php file.


$DB->get_record_sql only returning a single row

So you’ve written a query, passed it to $DB->get_records_sql() and, what’s this – only one row? What’s going on, where’s the rest of the query data?

First off, make sure you are using the plural form (get_records_sql() and not get_record_sql()).

If that’s not the issue then read on.

The reason this can happen is that Moodle uses the first column in your query as a unique id and then filters results down to that id field. However, if your first column isn’t unique across your data set, you won’t get every row.

For example, your query may select user enrolments for a course. But if you put your course id as the first column, you’ll only get one row, even if there are 30 enrolments in that course, because all of those enrolments belong to that one course id and that is the unique identifier used.

The fix is simple, find (or if you need to, create) a unique id so that the first column is unique for every row in your query. In the user enrolments example you might use the user ID or the user_enrolments ID.


Moodle User Management URLs

Some handy user management and search URLs, particularly if the site admin block is hidden.

User search

Note a %20=means a blank space, encoded to work in a URL.


Create a new user


Edit a user if you know their moodle internal id


Delete an existing user

This requires a session key (which is a godo thing!) so you need to do this once in the user edit area.


If you don’t see a delete action for a user it usually means they are a site admin so you need to take them out of site admin first.

Assigning site administrators



Hide My Profile -> Forum Posts from Navigation

To hide the navigation: My Profile > Forum Posts for all users:

1. This is set by the configuration value navadduserpostslinks
2. You can either update the value of this in the database (config table) from 1 to 0 OR you can add an entry in config.php where you set $CFG->navadduserpostslinks = 0;
3. Clear you moodle cache


Uninstalling a Moodle Plugin and forcing reinstallation

The easiest way to get moodle to re-run installation is to update the version in version.php. However, if you want to be sure it makes any schema changes etc then remove the plugin version from the mdl_config_plugins table. Note you can leave the other configuration there if required to save re-setting up the plugin.

The SQL to do this:

delete from mdl_config_plugins 
where plugin = 'plugin_name' 
and name = 'version';

For schema changes, you may need to drop the table and have it rebuild it just to ensure that the changes are made correctly.

For production deployments you should use an upgrade.php script, but this is a handy shortcut if you are developing a plugin as you really just want to iterate to the final schema version which you would then put into upgrade.php.


Access the WSDL for a Moodle SOAP service

When you enable SOAP based web services through Moodle:

Site administration > Plugins > Web Services > Overview (follow the steps)

You can access the WSDL for the SOAP based service by passing the flag &wsdl=1 in your URL e.g.


Moodle and Timezones

Moodle timezone information in the first instance is loaded from:

This returns a text file which is stored in the lib directory as timezone.txt

The data is stored in the table mdl_timezone (adjust to suit your db prefix).


Themes and Page Layouts

The types of page layouts – which determine how your moodle page is rendered via:


These are defined in the base theme (and can be extended by custom themes): Have a look in theme/base/config.php in the $THEME->layouts array for options.


Convert a Moodle URL object to string

There’s a method in the moodle_url class in lib/weblib.php called __toString which will convert a Moodle URL object back to a string if you just need the URL string itself.


Hide Navigation for My Profile > Messages

To hide the navigation: My Profile > Messages for all users:

1. This is set by the configuration value messaging
2. You can either update the value of this in the database (config table) from 1 to 0 OR you can add an entry in config.php where you set $CFG->messaging = 0;
3. Clear the moodle cache


Assign site admins through the database

The following steps can be used to add your user as a siteadmin in the database if required.

Step 1: Find your moodle user ID

select id from mdl_user where username = '{username}';

Step 2: Get the list of current siteadmin IDs

select value from mdl_config where name = 'siteadmins';

This gives you a list of Moodle user ids in a list that are siteadmins. What you want to do is append your Moodle user ID to the end of the list (assuming it isn’t there already!).

Step 3: Add your moodle user id to the list

You can do this manually, simple add ‘,{your_moodle_userid}’ to the text or you can use a query like this:

select concat(value, ',', (select id from mdl_user where username = '{username}'))
from mdl_config
where name = 'siteadmins';

Step 4: Update the siteadmin list

The following SQL does the deed of updating the list of siteadmins so be very careful. Ues the results from step 3 to perform this update. If anything goes wrong use the results from step 2 to revert the changes.

update mdl_config
set value = '{list_of_siteadmins_with_your_moodle_userid}'
where name = 'siteadmins';

Undefined Property $webserviceprotocols

When this occurs, there is no result from a web service call and undefined property $webserviceprotocols.

In the PHP error log the following appears:

Undefined property: stdClass::$webserviceprotocols

Check your web service protocols and ensure that the appropriate protocol is enabled.

Site administration > Plugins > Web services > Manage protocols.


Adding a local plugin to site admin navigation

If you want to add a local plugin navigation under the Site Administration block (under Plugins > Local Plugins) add the following to your local plugin settings.php file:

// Add the settings page to the navigation block

$settings = new admin_settingpage(
    get_string('pluginname', 'local_yourplugin')

$ADMIN->add('localplugins', $settings);

Custom email signup registration page

You can modify the custom auth/email signup registration page with the following steps (note this is a minor customisation to core code):

In auth/email/auth.php add the following code to call a custom signup form file:

function signup_form() {
	global $CFG;

	return new login_signup_form(null, null, 'post', '', array('autocomplete'=>'on'));

Copy signup_form.php from login/ into auth/email. Note you could put this file anywhere, but it seems logical to keep it with the auth/email plugin that will be using it.

Modify auth/email/signup_form.php to suit your needs.