Elgg 1.9 Documentation¶
Elgg (/ˈɛlɡ/) helps communities get connected while retaining control of their data and brand. It is a great fit for building any app where users log in and share information.
It has been used to build all kinds of social apps:
- open networks (like Facebook)
- topical (like the Elgg Community)
- private intranets
- dating
- educational
- company blog
- etc.
There is also a demo site running a standard installation of Elgg.
The name comes from a town in Switzerland. It also means “elk” or “moose” in Danish.
This is the canonical documentation for the Elgg project. This aims to replace the wiki, which is out-of-date in many areas.
Getting Started¶
Features¶
For developers:
- Permissive license
- Theme framework
- Internationalization
- Templating engine
- Widgets framework
- Plugin APIs
- Social graph
- Web services API
- jQuery-based JS framework
- Session management
For users:
- User profiles and avatars
- Fine-grained access control lists
- Friends and friends lists (ala G+ circles)
- Responsive, mobile-friendly design
- RSS support
- Activity stream
- Plugins for common content types like blogs, bookmarks, files, microblogging, private messages, documents, message boards, discussion
- User authentication and administration
If you need more functionality than what Elgg offers out-of-the-box there are a couple of options:
- Add more by installing plugins - for example, blogs, forums, social bookmarks
- Develop your own features via plugins
- Hire someone to do the above for you
License¶
A full Elgg package that includes the framework and a core set of plugins is available under version 2 of the GNU General Public (GPLv2). We also make the framework (without the plugins) available under the MIT license.
For questions not answered here, please refer to the official FAQ for the GPLv2.
FAQ¶
The following answers are provided as a convenience to you; they are not legal counsel. Consult with a lawyer to be sure about the answers to these questions. The Elgg Foundation cannot be held responsible for decisions you make based on what you read on this page.
How much does Elgg cost?¶
Elgg is free to download, install, and use. If you’d like to donate, we do appreciate our financial supporters!
Can I remove the Elgg branding/links?¶
Yes.
Can I modify the source code?¶
Yes, but in general we recommend you make your modifications as plugins so that when a new version of Elgg is released, the upgrade process is as painless as possible.
Can I charge my users membership fees?¶
Yes.
If I modify Elgg, do I have to make the changes available?¶
No, if you are using Elgg to provide a service, you do not have to make the source available. If you distribute a modified version of Elgg, than you must include the source code for the changes.
If I use Elgg to host a network, does The Elgg Foundation have any rights over my network?¶
No.
What’s the difference between the MIT and GPL versions?¶
Plugins are not included with the MIT version.
You can distribute a commercial product based on Elgg using the MIT version without making your modifications available.
With the GPL licensed version, you have to include make your modifications of the framework public if you redistribute the framework.
Why are plugins missing from the MIT version?¶
The plugins were developed under the GPL license, so they cannot be released under an MIT license. Also, some plugins include external dependencies that are not compatible with the MIT license.
May I distribute a plugin for Elgg under a commercial license?¶
We believe you can, since plugins typically depend only the core framework and the framework is available under the MIT license. That said, we really recommend you consult with a lawyer on this particular issue to be absolutely sure.
Note that plugins released via the community site repository must be licensed under a GPLv2-compatible license.
Can we build our own tool that uses Elgg and sell that tool to our clients?¶
Yes, but then your clients will be free to redistribute that tool under the terms of the GPLv2.
Requirements + Installation¶
Requirements¶
- MySQL 5+
- PHP 5.2+ with the following extensions:
- GD (for graphics processing)
- Multibyte String support (for i18n)
- Proper configuration and ability to send email through an MTA
- Web server with support for URL rewriting
Official support is provided for the following configuration:
- Apache with the rewrite module enabled
- PHP running as an Apache module
By “official support”, we mean that:
- Most development and testing is performed with this configuration
- Much of the installation documentation is written assuming Apache is used
- Priority on bug reports is given to Apache users if the bug is web server specific (but those are rare).
Installation¶
Upload Elgg¶
- Download the latest version of Elgg
- Upload the ZIP file with an FTP client to your server
- Unzip the files in your domain’s document root (/home/username/www).
Create a data folder¶
Elgg needs a special folder to store uploaded files including profile icons and photos. You will need to create this directory.
Warning
For security reasons, this folder MUST be stored outside of your document root. If you created it under /www/ or /public_html/, you’re doing it wrong.
Once this folder has been created, you’ll need to make sure the web server Elgg is running on has permission to write to and create directories in it. This shouldn’t be a problem on Windows-based servers, but if your server runs Linux, Mac OS X or a UNIX variant, you’ll need to set the permissions on the directory.
TODO: What is the recommended setting? 755? 644?
If you are using a graphical FTP client to upload files, you can usually set permissions by right clicking on the folder and selecting ‘properties’ or ‘Get Info’.
Note
Setting your data directory to 777 will work, but it is insecure and is not recommended. If you are unsure how to correctly set permissions, contact your host for more information.
Create a MySQL database¶
Using your database administration tool of choice (if you’re unsure about this, ask your system administrator), create a new MySQL database for Elgg. You can create a MySQL database with any of the following tools:
Make sure you add a user to the database with all privileges and record the database name, username and password. You will need this information when installing Elgg.
Visit your Elgg site¶
Once you’ve performed these steps, visit your Elgg site in your web browser. Elgg will take you through the rest of the installation process from there. The first account that you create at the end of the installation process will be an administrator account.
A note on settings.php and .htaccess¶
The Elgg installer will try and create two files for you:
- engine/settings.php, which contains the database settings for your installation
- .htaccess, which allows Elgg to generate dynamic URLs
If these files can’t be automatically generated, for example because the web server doesn’t have write permissions in the directories, Elgg will tell you how to create them. You could also temporarily change the permissions on the root directory and the engine directory. Set the permissions on those two directories so that the web server can write those two files, complete the install process, and them change the permissions back to their original settings. If, for some reason, this won’t work, you will need to:
- Copy engine/settings.example.php to engine/settings.php, open it up in a text editor and fill in your database details
- Copy /htaccess_dist to /.htaccess
Other Configurations¶
Lighttpd¶
Have you installed Elgg on a server running lighttpd? We are looking for someone to share any configuration and installation steps involved in setting this up.
Nginx¶
To run Elgg on Nginx, you will need to:
- configure Nginx to talk to a PHP process in either CGI or FPM mode
- Port the rewrite rules
TODO: Add the rewrite rules from the community site.
IIS¶
When installing on IIS, the problem is that the Apache mod_rewrite rules will not be recognized, and this breaks the application. You need to convert the mod_rewrite rules to the IIS URL Rewrite module format.
You can do this using the IIS 7+ management console, and the “Import Rules” feature that will do the conversion, as describe in the tutorial “importing Apache mod_rewrite rules”.
MariaDB¶
This DBMS should be a drop-in replacement for MySQL, if you prefer it.
http://community.elgg.org/discussion/view/1455994/alternative-dbmss
Virtual host (e.g. Rackspace, Amazon EC2)¶
For installation to proceed successfully, modify the .htaccess file in the root, and uncomment:
#RewriteBase /
To be:
RewriteBase /
MAMP¶
On certain versions of MAMP, Elgg will either fail to install or have intermittent problems while running.
This is a known issue with MAMP and is related to the Zend Optimizer. Until Zend/MAMP have resolved this issue it is recommended that you turn off the Zend Optimizer in your PHP settings.
XAMPP¶
These intructions are provided in case you want to test your Elgg installation on your local computer running Windows.
Download and install XAMPP to your computer from http://www.apachefriends.org/en/xampp.html
Once the installation is completed, it will prompt you to start the XAMPP controller panel. Leave it for now.
Open C:\xampp\apache\conf\httpd.conf file with notepad and uncomment these lines:
#LoadModule rewrite_module modules/mod_rewrite.so #LoadModule filter_module modules/mod_filter.so
Edit the php.ini file and change arg_separator.output = & to arg_separator.output = &
Go to C:\xampp and double click on the xampp_start application
Go to http://localhost/
Change your server’s password in the security option
Go to http://localhost/phpmyadmin and login with the username and the password of your server
Create a database called “elgg” in your phpmyadmin panel
Now download Elgg. Unzip it and extract to C:\xampp\htdocs\sites\elgg
Create the Elgg data folder as C:\xampp\htdocs\sites\data
You will be taken to the Elgg installation steps. Install it and enjoy.
A note on XAMPP 1.7.4 and eAccelerator
Elgg is compatible with opcode caches and it is highly recommended that you enable a PHP opcode caching tool for a faster experience. XAMPP comes with support for eAccelerator out of the box, but unfortunately, the 1.7.4 build of XAMPP leaves out the DLL that’s required. To get eAccelerator working, follow these steps:
Download the DLL from http://eac.qme.nl/eAccelerator_v1_0_svn427_for_v5_3_5-VC6.zip
Copy eAccelerator_ts.dll to C:\xampp\php\ext\php_eaccelerator.dll
Uncomment this line in C:\xampp\php\php.ini:
;zend_extension = "C:\xampp\php\ext\php_eaccelerator.dll"
Restart apache
To verify that it is on:
- Go to localhost/xampp
- Click on phpinfo() from the left sidebar
- Ctrl+F for eaccelerator. If you get no results, eAccelerator is not active
EasyPHP¶
- Assuming no MySQL, PHP or Apache installations exist already.
- Best run as a development/test server
Stop IIS running if installed
Download and install the latest Easy PHP from http://www.easyphp.org (16MB download)
Set up the database and point the web server to your Elgg folder (all done from the EasyPHP tray icon) - Right click EasyPHP tray icon, select “Administration” - A new tab is created in your browser for managing Easy PHP - Add your Elgg folder to Apache in “Alias” section - Click “Manage MySQL with PhpMyAdmin”, create a database and account for Elgg
(Ignore this step for v5.3 or later) From the tray icon go Configuration/Apache and uncomment this line:
#LoadModule rewrite_module modules/mod_rewrite.so
(Ignore this step for v5.3 or later) Change AllowOverride None to AllowOverride All in the relevant directory entry in Configuration/Apache
(Ignore this step for v5.3 or later) From the tray icon fo Configuration/PHP and uncomment this line:
;extension=php_curl.dll
A reboot is best Elgg should run via http://127.0.0.1
Ubuntu Linux¶
Install the dependencies:
sudo apt-get install apache2 sudo apt-get install mysql-server sudo apt-get install php5 libapache2-mod-php5 php5-mysql sudo apt-get install phpmyadmin sudo a2enmod rewrite
Edit /etc/apache2/sites_available/default to enable .htaccess processing (set AllowOverride to All)
Restart Apache: sudo /etc/init.d/apache2 restart
Follow the standard installation instructions above
Cloud9IDE¶
1. Create a c9 workspace
- Go to http://c9.io
- Login with GitHub
- On the Dashboard, click “Create new workspace” => “Create a new workspace”
- Choose a project name (e.g. “elgg”)
- Choose “PHP” for project type
- Click “Create”
- Wait... (~1 min for c9 workspace to be ready)
- Click “Start editing” for the workspace
2. Set up the workspace for Elgg
Run the following in cloud9’s terminal:
rm -rf * # Clear out the c9 hello-world stuff
git clone https://github.com/Elgg/Elgg . # the hotness
cp htaccess_dist .htaccess
cp engine/settings.example.php engine/settings.php
mysql-ctl start # start c9's local mysql server
mkdir ../elgg-data # setup data dir for Elgg
Configure engine/settings.php to be like so:
// Must set timezone explicitly!
date_default_timezone_set('America/Los_Angeles');
$CONFIG->dbuser = 'your_username'; // Your c9 username
$CONFIG->dbpass = '';
$CONFIG->dbname = 'c9';
$CONFIG->dbhost = $_SERVER['SERVER_ADDR'];
$CONFIG->dbprefix = 'elgg_';
3. Complete the install process from Elgg’s UI
- Hit “Run” at the top of the page to start Apache.
- Go to http://your-workspace.your-username.c9.io/install.php?step=database
- Change Site URL to http://your-workspace.your-username.c9.io/
- Put in the data directory path. Should be something like /var/..../app-root/data/elgg-data/.
- Click “Next”
- Create the admin account
- Click “Go to site”
- You may have to manually visit http://your-workspace.your-username.c9.io/ and login with the admin credentials you just configured.
Troubleshooting¶
Help! I’m having trouble installing Elgg¶
First:
- Recheck that your server meets the technical requirements for Elgg.
- Follow the environment-specific instructions if need be
- Have you verified that mod_rewrite is being loaded?
- Is the mysql apache being loaded?
Keep notes on steps that you take to fix the install. Sometimes changing some setting or file to try to fix a problem may cause some other problem later on. If you need to start over, just delete all the files, drop your database, and begin again.
I can’t save my settings on installation (I get a 404 error when saving settings)¶
Elgg relies on the mod_rewrite Apache extension in order to simulate certain URLs. For example, whenever you perform an action in Elgg, or when you visit a user’s profile, the URL is translated by the server into something Elgg understands internally. This is done using rules defined in an .htaccess file, which is Apache’s standard way of defining extra configuration for a site.
This error suggests that the mod_rewrite rules aren’t being picked up correctly. This may be for several reasons. If you’re not comfortable implementing the solutions provided below, we strongly recommend that you contact your system administrator or technical support and forward this page to them.
The .htaccess, if not generated automatically (that happens when you have problem with mod_rewrite), you can create it by renaming htaccess_dist file you find with elgg package to .htaccess. Also if you find a .htaccess file inside the installation path, but you are still getting 404 error, make sure the contents of .htaccess are same as that of htaccess_dist.
Instructions for testing mod_rewrite
``mod_rewrite`` isn’t installed.
Check your httpd.conf to make sure that this module is being loaded by Apache. You may have to restart Apache to get it to pick up any changes in configuration. You can also use PHP info to check to see if the module is being loaded.
The rules in ``.htaccess`` aren’t being obeyed.
In your virtual host configuration settings (which may be contained within httpd.conf), change the AllowOverride setting so that it reads:
AllowOverride all
This will tell Apache to pick up the mod_rewrite rules from .htaccess.
Elgg is not installed in the root of your web directory (ex: http://example.org/elgg/ instead of http://example.org/)
The install script redirects me to “action” when it should be “actions”¶
This is a problem with your mod_rewrite setup. DO NOT, REPEAT, DO NOT change any directory names!
I installed in a subdirectory and my install action isn’t working!¶
If you installed Elgg so that it is reached with an address like http://example.org/mysite/ rather than http://example.org/, there is a small chance that the rewrite rules in .htaccess will not be processed correctly. This is usually due to using an alias with Apache. You may need to give mod_rewrite a pointer to where your Elgg installation is.
- Open up .htaccess in a text editor
- Where prompted, add a line like RewriteBase /path/to/your/elgg/installation/ (Don’t forget the trailing slash)
- Save the file and refresh your browser.
Please note that the path you are using is the web path, minus the host.
For example, if you reach your elgg install at http://example.org/elgg/, you would set the base like this:
RewriteBase /elgg/
Please note that installing in a subdirectory does not require using RewriteBase. There are only some rare circumstances when it is needed due to the set up of the server.
I did everything! mod_rewrite is working fine, but still the 404 error¶
Maybe there is a problem with the file .htaccess. Sometimes the elgg install routine is unable to create one and unable to tell you that. If you are on this point and tried everything that is written above:
- check if it is really the elgg-created .htaccess (not only a dummy provided from the server provider)
- if it is not the elgg provided htaccess file, use the htaccess_dist (rename it to .htaccess)
I get an error message that the rewrite test failed after the requirements check page¶
I get the following messages after the requirements check step (step 2) of the install:
We think your server is running the Apache web server.
The rewrite test failed and the most likely cause is that AllowOverride is not set to All for Elgg’s directory. This prevents Apache from processing the .htaccess file which contains the rewrite rules.
A less likely cause is Apache is configured with an alias for your Elgg directory and you need to set the RewriteBase in your .htaccess. There are further instructions in the .htaccess file in your Elgg directory.
After this error, everinteraction with the web interface results in a error 500 (Internal Server Error)
This is likely caused by not loading the “filter module by un-commenting the
#LoadModule filter_module modules/mod_filter.so
line in the “httpd.conf” file.
the Apache “error.log” file will contain an entry similar to:
... .htaccess: Invalid command ‘AddOutputFilterByType’, perhaps misspelled or defined by a module not included in the server configuration
There is a white page after I submit my database settings¶
Check that the Apache mysql module is installed and is being loaded.
I’m getting a 404 error with a really long url¶
If you see a 404 error during the install or on the creation of the first user with a url like: http://example.com/homepages/26/d147515119/htdocs/elgg/action/register that means your site url is incorrect in your sites_entity table in your database. This was set by you on the second page of the install. Elgg tries to guess the correct value but has difficulty with shared hosting sites. Use phpMyAdmin to edit this value to the correct base url.
I am having trouble setting my data path¶
This is highly server specific so it is difficult to give specific advice. If you have created a directory for uploading data, make sure your http server can access it. The easiest (but least secure) way to do this is give it permissions 777. It is better to give the web server ownership of the directory and limit the permissions.
The top cause of this issue is PHP configured to prevent access to most directories using open_basedir. You may want to check with your hosting provider on this.
Make sure the path is correct and ends with a /. You can check the path in your database in the datalists table.
If you only have ftp access to your server and created a directory but do not know the path of it, you might be able to figure it out from the www file path set in your datalists database table. Asking for help from your hosting help team is recommended at this stage.
I can’t validate my admin account because I don’t have an email server!¶
While it’s true that normal accounts (aside from those created from the admin panel) require their email address to be authenticated before they can log in, the admin account does not.
Once you have registered your first account you will be able to log in using the credentials you have provided!
I have tried all of these suggestions and I still cannot install Elgg¶
It is possible that during the process of debugging your install you have broken something else. Try doing a clean install:
- drop your elgg database
- delete your data directory
- delete the Elgg source files
- start over
If that fails, seek the help of the Elgg community. Be sure to mention what version of Elgg you are installing, details of your server platform, and any error messages that you may have received including ones in the error log of your server.
Administrator Guides¶
These guides teach best practices on effectively managing an Elgg-based network.
Upgrading Elgg¶
How to switch a live site to a new version of Elgg. If you’ve written custom plugins, you should also read the developer guides for information on upgrading plugin code for the latest version of Elgg.
Advice:
- Back up your database and code.
- Mind any version-specific comments below.
- Upgrade only one minor version at a time (1.6 => 1.7, then 1.7 => 1.8).
- Try out the new version on a test site before doing an upgrade
- Report any problems in plugins to the plugin authors.
- If you are a plugin author you can report any backwards-compatibility issues to github.
Basic instructions:
- Back up your database and code.
- Download the new version of Elgg from elgg.org.
- Overwrite your existing Elgg files.
- Visit http://your-elgg-site-URL/upgrade.php
- Copy htaccess_dist over .htaccess.
Note
Any modifications should have been written within plugins, so that they are not lost on overwriting. If this is not the case, take care to maintain your modifications.
Note
If you modified the default .htaccess, be sure to port your modifications over to the new one.
From 1.8 to 1.9¶
TODO
From 1.7 to 1.8¶
Elgg 1.8 is the biggest leap forward in the development of Elgg since version 1.0. As such, there is more work to update core and plugins than with previous upgrades.
Updating core¶
Delete the following core directories (same level as _graphics and engine):
- _css
- account
- admin
- dashboard
- entities
- friends
- search
- settings
- simplecache
- views
Warning
If you do not delete these directories before an upgrade, you will have problems!
From 1.6 to 1.7¶
a User authentication and administration
Plugins¶
Plugins can modify the behavior of and add new features to Elgg.
Where to get plugins¶
Plugins can be obtained from:
- The Elgg Community
- Github
- Third-party sites (typically for a price)
If no existing plugins meet your needs, you can hire a developer or create your own.
Types of plugins¶
Themes¶
Themes are just plugins that modify the look-and-feel of your site, so you’ll typically find them wherever Elgg plugins are available.
Language Packs¶
Language packs are just plugins that provide support for another language. There are language packs for the core and they are usually installed in the languages directory off the elgg root directory. Other language packs are provided for various plugins. Generally, the authors make it easy to copy those files into the languages directory of each plugin under the mod directory.
Installation¶
To install a plugin, unzip the archive and copy the plugin’s main folder to the “mod” directory in your Elgg installation.
You must then activate it from the admin panel:
- Log in to your Elgg site with your administrator account
- Go to Administration -> Configure -> Plugins
- Find your plugin in the list of installed plugins and click on the ‘enable’ button.
Pre-1.8 notes¶
In Elgg 1.7 and below, the interface for managing installed plugins is located at Administration -> Tool Administration.
Developer Guides¶
These docs will help you learn how to get stuff done with an Elgg plugin.
Upgrading Plugins¶
This document is all about preparing your plugin for the next Elgg version. See the administator guides for how to upgrade a live site.
From 1.8 to 1.9¶
TODO
From 1.7 to 1.8¶
Elgg 1.8 is the biggest leap forward in the development of Elgg since version 1.0. As such, there is more work to update core and plugins than with previous upgrades. There were a small number of API changes and following our standard practice, the methods we deprecated have been updated to work with the new API. The biggest changes are in the standardization of plugins and in the views system.
Updating core¶
Delete the following core directories (same level as _graphics and engine):
- _css
- account
- admin
- dashboard
- entities
- friends
- search
- settings
- simplecache
- views
Warning
If you do not delete these directories before an upgrade, you will have problems!
Updating plugins¶
Use standardized routing with page handlers¶
- All: /page_handler/all
- User’s content: /page_handler/owner/:username
- User’s friends’ content: /page_handler/friends/:username
- Single entity: /page_handler/view/:guid/:title
- Added: /page_handler/add/:container_guid
- Editing: /page_handler/edit/:guid
- Group list: /page_handler/group/:guid/all
Include page handler scripts from the page handler¶
Almost every page handler should have a page handler script. (Example: bookmarks/all => mod/bookmarks/pages/bookmarks/all.php)
- Call set_input() for entity guids in the page handler and use get_input() in the page handler scripts.
- Call gatekeeper() and admin_gatekeeper() in the page handler function if required.
- The group URL should use the pages/:handler/owner.php script.
- Page handlers should not contain HTML.
- Update the URLs throughout the plugin. (Don’t forget to remove /pg/!)
Use standardized page handlers and scripts¶
Store page handler scripts in mod/:plugin/pages/:page_handler/:page_name.php
Use the content page layout in page handler scripts:
$content = elgg_view_layout('content', $options);
Page handler scripts should not contain HTML.
Call elgg_push_breadcrumb() in the page handler scripts.
No need to set page owner if the URLs are in the standardized format.
For group content, check the container_guid by using elgg_get_page_owner_entity().
The object/:subtype view¶
- Make sure there are views for $vars['full_view'] == true and $vars['full_view'] == false. $vars['full_view'] replaced $vars['full].
- Check for the object in $vars['entity']. Use elgg_instance_of() to make sure it’s the type of entity you want.
- Return true to short circuit the view if the entity is missing or wrong.
- Use elgg_view(‘object/elements/summary’, array(‘entity’ => $entity)); and elgg_view_menu(‘entity’, array(‘entity’ => $entity)); to help format. You should use very little markup in these views.
Update action structure¶
- Namespace action files and action names (example: mod/blog/actions/blog/save.php => action/blog/save)
- Use the following action URLs:
- Add: action/:plugin/save
- Edit: action/:plugin/save
- Delete: action/:plugin/delete
- Make the delete action accept action/:handler/delete?guid=:guid so the metadata entity menu has the correct URL by default.
Update deprecated functions¶
- Functions deprecated in 1.7 will produce visible errors in 1.8.
- See /engine/lib/deprecated-1.7.php for the full list.
- You can also update functions deprecated in 1.8.
- Many registration functions simply added an elgg_ prefix for consistency, and should be easy to update.
- See /engine/lib/deprecated-1.8.php for the full list.
- You can set the debug level to “warning” to get visual reminders of deprecated functions.
Update the widget views¶
See the blog or file widgets for examples.
Update the group profile module¶
Use the blog or file plugins for examples. This will help with making your plugin themeable by the new CSS framework.
Update forms¶
- Move form bodies to the forms/:action view to use Evan’s new elgg_view_form.
- Use input views in form bodies rather than html. This helps with theming and future-proofing.
- Add a function that prepares the form (see mod/file/lib/file.php for an example)
- Make your forms sticky (see the file plugin’s upload action and form prepare function).
The forms API is discussed in more detail in Forms + Actions.
Clean up CSS/HTML¶
We have added many CSS patterns to the base CSS file (modules, image block, spacing primitives). We encourage you to use these patterns and classes wherever possible. Doing so should:
- Reduce maintenance costs, since you can delete most custom CSS.
- Make your plugin more compatible with community themes.
Look for patterns that can be moved into core if you need significant CSS.
We use hyphens rather than underscores in classes/ids and encourage you do the same for consistency.
If you do need your own CSS, you should use your own namespace, rather than elgg-.
Update manifest.xml¶
- Use http://el.gg/manifest17to18 to automate this.
- Don’t use the “bundled” category with your plugins. That is only for plugins distributed with Elgg.
Update settings and user settings views¶
- The view for settings is now plugins/:plugin/settings (previously settings/:plugin/edit).
- The view for user settings is now plugins/:plugin/usersettings (previously usersettings/:plugin/edit).
Forms + Actions¶
Forms allow users to create, update, or delete content. Each form submits to an action. Actions define the behavior for form submission.
This guide assumes basic familiarity with:
- Plugins
- Views
- I18n
Registering actions¶
Actions must be registered before use. Use elgg_register_action for this:
elgg_register_action(“example”, __DIR__ . “/actions/example.php”);
The mod/example/actions/example.php script will now be run whenever a form is submitted to http://localhost/elgg/action/example.
Permissions¶
By default, actions are only available to logged in users. To make them available to logged out users, pass “public” as the third parameter:
elgg_register_action(“example”, $filepath, “public”);
To restrict an action to only administrators, pass ”admin” for the last parameter:
elgg_register_action(“example”, $filepath, “admin”);
Implementing actions¶
Use the get_input function to get access to request parameters:
$field = get_input('input_field_name', 'default_value');
You can then use the Database api to load entities and perform actions on them accordingly.
To redirect the page once you’ve completed your actions, use the forward function:
forward('url/to/forward/to');
For example, to forward to the user’s profile:
$user = elgg_get_logged_in_user_entity();
forward($user->getURL());
URLs can also be relative to the Elgg root:
$user = elgg_get_logged_in_user_entity();
forward(“/example/$user->username”);
You can also redirect to the referring page by using the REFERRER constant:
forward(REFERRER);
forward(REFERER); // equivalent
To give feedback to the user about the status of the action, use system_message for positive feedback or register_error for warnings and errors:
if ($success) {
system_message(elgg_echo(‘actions:example:success’));
} else {
register_error(elgg_echo(‘actions:example:error’));
}
Customizing actions¶
Before executing any action, Elgg triggers a hook:
$result = elgg_trigger_plugin_hook('action', $action, null, true);
Where $action is the action being called. If the hook returns false then the action will not be executed.
Example: Captcha¶
The captcha module uses this to intercept the register and user/requestnewpassword actions and redirect them to a function which checks the captcha code. This check returns true if valid or false if not (which prevents the associated action from executing).
This is done as follows:
elgg_register_plugin_hook_handler("action", "register", "captcha_verify_action_hook");
elgg_register_plugin_hook_handler("action", "user/requestnewpassword", "captcha_verify_action_hook");
...
function captcha_verify_action_hook($hook, $entity_type, $returnvalue, $params) {
$token = get_input('captcha_token');
$input = get_input('captcha_input');
if (($token) && (captcha_verify_captcha($input, $token))) {
return true;
}
register_error(elgg_echo('captcha:captchafail'));
return false;
}
This lets a plugin extend an existing action without the need to replace the whole action. In the case of the captcha plugin it allows the plugin to provide captcha support in a very loosely coupled way.
To output a form, use the elgg_view_form function like so:
echo elgg_view_form('example');
Doing this should generate something like the following markup:
<form action="http://localhost/elgg/action/example">
<fieldset>
<input type="hidden" name="__elgg_ts" value="1234567890" />
<input type="hidden" name="__elgg_token" value="3874acfc283d90e34" />
</fieldset>
</form>
Elgg does some things automatically for you when you generate forms this way:
- It sets the action to the appropriate url based on the name of the action you pass to it
- It adds some anti-csrf tokens (__elgg_ts and __elgg_token) to help keep your actions secure
- It automatically looks for the body of the form in the forms/example view.
Put the content of your form in your plugin’s forms/example view:
// /mod/example/views/default/forms/example.php
echo elgg_view('input/text', array('name' => 'example'));
echo elgg_view('input/submit');
Now when you call elgg_view_form('example'), Elgg will produce:
<form action="http://localhost/elgg/action/example">
<fieldset>
<input type="hidden" name="__elgg_ts" value="...">
<input type="hidden" name="__elgg_token" value="...">
<input type="text" class="elgg-input-text" name="example">
<input type="submit" class="elgg-button elgg-button-submit" value="Submit">
</fieldset>
</form>
Files and images¶
Use the input/file view in your form’s content view.
// /mod/example/views/default/forms/example.php
echo elgg_view(‘input/file’, array(‘name’ => ‘icon’));
Set the enctype of the form to multipart/form-data:
echo elgg_view_form(‘example’, array(
‘enctype’ => ‘multipart/form-data’
));
In your action file, use the $_FILES global to access the uploaded file:
$icon = $_FILES[‘icon’]
Sticky forms¶
Sticky forms are forms that retain user input if saving fails. They are “sticky” because the user’s data “sticks” in the form after submitting, though it was never saved to the database. This greatly improves the user experience by minimizing data loss. Elgg 1.8 includes helper functions so you can make any form sticky.
Helper functions¶
Sticky forms are implemented in Elgg 1.8 by the following functions:
elgg_make_sticky_form($name) Tells the engine to make all input on a form sticky.
elgg_clear_sticky_form($name) Tells the engine to discard all sticky input on a form.
elgg_is_sticky_form($name) Checks if $name is a valid sticky form.
elgg_get_sticky_values($name) Returns all sticky values saved for $name by elgg_make_sticky_form().
Overview¶
The basic flow of using sticky forms is: Call elgg_make_sticky_form($name) at the top of actions for forms you want to be sticky. Use elgg_is_sticky_form($name) and elgg_get_sticky_values($name) to get sticky values when rendering a form view. Call elgg_clear_sticky_form($name) after the action has completed successfully or after data has been loaded by elgg_get_sticky_values($name).
Example: User registration¶
Simple sticky forms require little logic to determine the input values for the form. This logic is placed at the top of the form body view itself.
The registration form view first sets default values for inputs, then checks if there are sticky values. If so, it loads the sticky values before clearing the sticky form:
// views/default/forms/register.php
$password = $password2 = '';
$username = get_input('u');
$email = get_input('e');
$name = get_input('n');
if (elgg_is_sticky_form('register')) {
extract(elgg_get_sticky_values('register'));
elgg_clear_sticky_form('register');
}
The registration action sets creates the sticky form and clears it once the action is completed:
// actions/register.php
elgg_make_sticky_form('register');
...
$guid = register_user($username, $password, $name, $email, false, $friend_guid, $invitecode);
if ($guid) {
elgg_clear_sticky_form('register');
....
}
Example: Bookmarks¶
The bundled plugin Bookmarks’ save form and action is an example of a complex sticky form.
The form view for the save bookmark action uses elgg_extract() to pull values from the $vars array:
// mod/bookmarks/views/default/forms/bookmarks/save.php
$title = elgg_extract('title', $vars, '');
$desc = elgg_extract('description', $vars, '');
$address = elgg_extract('address', $vars, '');
$tags = elgg_extract('tags', $vars, '');
$access_id = elgg_extract('access_id', $vars, ACCESS_DEFAULT);
$container_guid = elgg_extract('container_guid', $vars);
$guid = elgg_extract('guid', $vars, null);
$shares = elgg_extract('shares', $vars, array());
The page handler scripts prepares the form variables and calls elgg_view_form() passing the correct values:
// mod/bookmarks/pages/add.php
$vars = bookmarks_prepare_form_vars();
$content = elgg_view_form('bookmarks/save', array(), $vars);
Similarly, mod/bookmarks/pages/edit.php uses the same function, but passes the entity that is being edited as an argument:
$bookmark_guid = get_input('guid');
$bookmark = get_entity($bookmark_guid);
...
$vars = bookmarks_prepare_form_vars($bookmark);
$content = elgg_view_form('bookmarks/save', array(), $vars);
The library file defines bookmarks_prepare_form_vars(). This function accepts an ElggEntity as an argument and does 3 things:
- Defines the input names and default values for form inputs.
- Extracts the values from a bookmark object if it’s passed.
- Extracts the values from a sticky form if it exists.
TODO: Include directly from lib/bookmarks.php
// mod/bookmarks/lib/bookmarks.php
function bookmarks_prepare_form_vars($bookmark = null) {
// input names => defaults
$values = array(
'title' => get_input('title', ''), // bookmarklet support
'address' => get_input('address', ''),
'description' => '',
'access_id' => ACCESS_DEFAULT,
'tags' => '',
'shares' => array(),
'container_guid' => elgg_get_page_owner_guid(),
'guid' => null,
'entity' => $bookmark,
);
if ($bookmark) {
foreach (array_keys($values) as $field) {
if (isset($bookmark->$field)) {
$values[$field] = $bookmark->$field;
}
}
}
if (elgg_is_sticky_form('bookmarks')) {
$sticky_values = elgg_get_sticky_values('bookmarks');
foreach ($sticky_values as $key => $value) {
$values[$key] = $value;
}
}
elgg_clear_sticky_form('bookmarks');
return $values;
}
The save action checks the input, then clears the sticky form upon success:
// mod/bookmarks/actions/bookmarks/save.php
elgg_make_sticky_form('bookmarks');
...
if ($bookmark->save()) {
elgg_clear_sticky_form('bookmarks');
}
Ajax¶
To call an action via javascript without actually submitting a form, use elgg.action:
elgg.action(‘example’, { param: 12345 });
This does a few things under the hood:
- Automatically normalizes the request URL to http://localhost/elgg/action/example.
- Adds XSRF tokens to the request body for security
- If the action emits any system messages or errors, they will automatically be displayed when the response comes back.
Often you’ll want to do something in response to a successful action:
elgg.action(‘example’, {
data: { param: 12345 },
success: function() {
// Do something once action completes
}
});
Security¶
For enhanced security, all actions require an XSRF token. Calls to action URLs that do not include security tokens will be ignored and a warning will be generated.
A few views and functions automatically generate security tokens:
elgg_view('output/url', array('is_action' => TRUE));
elgg_view('output/confirmlink');
elgg_view('input/securitytoken');
$url = elgg_add_action_tokens_to_url("http://localhost/elgg/action/example");
In rare cases, you may need to generate tokens manually:
$__elgg_ts = time();
$__elgg_token = generate_action_token($__elgg_ts);
You can also access the tokens from javascript:
elgg.security.token.__elgg_ts;
elgg.security.token.__elgg_token;
These are refreshed periodically so should always be up-to-date.
Database¶
Entities¶
Creating an object¶
To create an object in your code, you need to instantiate an ElggObject. Setting data is simply a matter of adding instance variables or properties. The built-in properties are:
- ``guid`` The entity’s GUID; set automatically
- ``owner_guid`` The owning user’s GUID
- ``site_guid`` The owning site’s GUID. This is set automatically when an instance of ElggObject gets created)
- ``subtype`` A single-word arbitrary string that defines what kind of object it is, for example blog
- ``access_id`` An integer representing the access level of the object
- ``title`` The title of the object
- ``description`` The description of the object
The object subtype is a special property. This is an arbitrary string that describes what the object is. For example, if you were writing a blog plugin, your subtype string might be blog. It’s a good idea to make this unique, so that other plugins don’t accidentally try and use the same subtype. For the purposes of this document, let’s assume we’re building a simple forum. Therefore, the subtype will be forum:
$object = new ElggObject();
$object->subtype = "forum";
$object->access_id = 2;
$object->save();
access_id is another important property. If you don’t set this, your object will be private, and only the creator user will be able to see it. Elgg defines constants for the special values of access_id:
- ACCESS_PRIVATE Only the owner can see it
- ACCESS_FRIENDS Only the owner and his/her friends can see it
- ACCESS_LOGGED_IN Any logged in user can see it
- ACCESS_PUBLIC Even visitors not logged in can see it
Saving the object will automatically populate the $object->guid property if successful. If you change any more base properties, you can call $object->save() again, and it will update the database for you.
You can set metadata on an object just like a standard property. Let’s say we want to set the SKU of a product:
$object->SKU = 62784;
If you assign an array, all the values will be set for that metadata. This is how, for example, you set tags.
Metadata cannot be persisted to the database until the entity has been saved, but for convenience, ElggEntity can cache it internally and save it when saving the entity.
Loading an object¶
By GUID¶
$entity = get_entity($guid);
if (!$entity) {
// The entity does not exist or you're not allowed to access it.
}
But what if you don’t know the GUID? There are several options.
By user, subtype or site¶
If you know the user ID you want to get objects for, or the subtype, or the site, you have several options. The easiest is probably to call the procedural function elgg_get_entities:
$entities = elgg_get_entities(array(
'type' => $entity_type,
'subtype' => $subtype,
'owner_guid' => $owner_guid,
));
This will return an array of ElggEntity objects that you can iterate through. elgg_get_entities paginates by default, with a limit of 10; and offset 0.
You can leave out owner_guid to get all objects and leave out subtype or type to get objects of all types/subtypes.
If you already have an ElggUser – e.g. elgg_get_logged_in_user_entity, which always has the current user’s object when you’re logged in – you can simply use:
$objects = $user->getObjects($subtype, $limit, $offset)
But what about getting objects with a particular piece of metadata?
By metadata¶
The function elgg_get_entities_from_metadata allows fetching entities with metadata in a variety of ways.
Displaying entities¶
In order for entities to be displayed in listing functions you need to provide a view for the entity in the views system.
To display an entity, create a view EntityType/subtype where EntityType is one of the following:
object: for entities derived from ElggObject user: for entities derived from ElggUser site: for entities derived from ElggSite group: for entities derived from ElggGroup
A default view for all entities has already been created, this is called EntityType/default.
Entity Icons¶
Entities all have a method called ->getIcon($size).
This method accepts a $size variable, which can be either ‘large’, ‘medium’, ‘small’ or ‘tiny’.
The method triggers a plugin hook - ‘entity:icon:url’. This is passed the following parameters:
‘entity’ : The entity in question ‘viewtype’ : The type of view e.g. ‘default’ or ‘mobile’. ‘size’ : The size.
The hook should return a url.
Hooks have already been defined, and will look in the following places for default values (in this order):
- views/$viewtype/graphics/icons/$type/$subtype/$size.png
- views/$viewtype/graphics/icons/$type/default/$size.png
- views/$viewtype/graphics/icons/default/$size.png
Where
$viewtype : The type of view e.g. ‘default’ or ‘mobile’. $type : The type of entity - group, site, user, object. $subtype : Subtype of $type, e.g. blog, page. $size : Size - ‘large’, ‘medium’, ‘small’ or ‘tiny’
Adding, reading and deleting annotations¶
Annotations could be used, for example, to track ratings. To annotate an entity you can use the object’s annotate() method. For example, to give a blog post a rating of 5, you could use:
$blog_post->annotate('rating', 5);
To retrieve the ratings on the blog post, use $blogpost->getAnnotations('rating') and if you want to delete an annotation, you can operate on the ElggAnnotation class, eg $annotation->delete().
Retrieving a single annotation can be done with get_annotation() if you have the annotation’s ID. If you delete an ElggEntity of any kind, all its metadata, annotations, and relationships will be automatically deleted as well.
Extending ElggEntity¶
If you derive from one of the Elgg core classes, you’ll need to tell Elgg how to properly instantiate the new type of object so that get_entity() et al. will return the appropriate PHP class. For example, if I customize ElggGroup in a class called “Committee”, I need to make Elgg aware of the new mapping. Following is an example class extension:
// Class source
class Committee extends ElggGroup {
protected function initializeAttributes() {
parent::initializeAttributes();
$this->attributes['subtype'] = 'committee';
}
// more customizations here
}
function committee_init() {
register_entity_type('group', 'committee');
// Tell Elgg that group subtype "committee" should be loaded using the Committee class
// If you ever change the name of the class, use update_subtype() to change it
add_subtype('group', 'committee', 'Committee');
}
register_elgg_event_handler('init', 'system', 'committee_init');
Now if you invoke get_entity() with the GUID of a committee object, you’ll get back an object of type Committee.
This template was extracted from the definition of ElggFile.
Advanced features¶
Entity Icons¶
A url for an icon representing a given entity can be retrieved by the getIcon() method.
This is handy as it provides a generic interface which allows the Elgg framework to draw an icon for your data - it also allows you to override icons for existing data types - for example providing Gravatar support for user icons.
If no icon can be provided for the data type a default one is used, defined either by your current theme or the Elgg default.
To override the icon of a specific instance of an entity in a non-permanent and one off way, you can use the entity’s setIcon() method.
If you want to provide an icon for a new data type, or override an existing one you can do this simply through the views interface.
Views are in the format:
icon/``[TYPE]``/``[SUBTYPE]``/``[SIZE]``
Where:
[TYPE]: is the elgg type of the object - “user”, “group”, “object” or “site”. [SUBTYPE]: is the specific subtype of the object, or “default” for the default icon for the given type. [SIZE]: the size, one of the following “master”, “large”, “medium”, “small”, “topbar” or “tiny”.
This view should contain the URL to the image only.
Overriding icons via a handler¶
The final way to replace icons is via a handler to a plugin hook.
This method lets you perform some additional logic in order to decide better which url to return.
The hook triggered is:
Entity URLs¶
Entity urls are provided by the getURL() interface and provide the Elgg framework with a common way of directing users to the appropriate display handler for any given object.
For example, a profile page in the case of users.
The url is set using the elgg\_register\_entity\_url\_handler() function. The function you register must return the appropriate url for the given type - this itself can be an address set up by a page handler.
The default handler is to use the default export interface.
Pre-1.8 Notes¶
update_subtype(): This function is new in 1.8. In prior versions, you would need to edit the database by hand if you updated the class name associated with a given subtype.
elgg_register_entity_url_handler(): This function is new in 1.8. It deprecates register_entity_url_handler(), which you should use if developing for a pre-1.8 version of Elgg.
elgg_get_entities_from_metadata(): This function is new in 1.8. It deprecates get_entities_from_metadata(), which you should use if developing for a pre-1.8 version of Elgg.
Internationalization¶
Making your UI translatable into many different languages.
If you’d like to contribute translations to Elgg, see the contributors’ guide.
Overview¶
Translations are stored in PHP files in the /languages directory of your plugin. Each file corresponds to a language. The format is /languages/{language-code}.php where {language-code} is the ISO 639-1 short code for the language. For example:
<?php
// mod/example/languages/en.php
return array(
‘example:text’ => ‘Some example text’,
);
The default language is “en” for English.
To change the wording of any phrase, provide a new mapping in your plugin’s {language}.php file for the associated key:
<?php
return array(
‘example:text’ => ‘This is an example’,
);
Note
Unless you are overriding core’s or another plugin’s language strings, it is good practice for the language keys to start with your plugin name. For example: “yourplugin:success,” “yourplugin:title,” etc. This helps avoid conflicts with other language keys.
Server-side API¶
elgg_echo($key, $args, $language)
Output the translation of the key in the current language.
Example:
echo elgg_echo(‘example:text’);
It also supports variable replacement using sprintf syntax:
// ‘welcome’ => ‘Welcome to %s, %s!’
echo elgg_echo(‘welcome’, array(
elgg_get_config(‘sitename’),
elgg_get_logged_in_user_entity()->name,
));
To force which language should be used for translation, set the third parameter:
echo elgg_echo(‘welcome’, array(), ‘es’);
Javascript API¶
elgg.echo(key, args, language)
This function is the exact counterpart to elgg_echo in PHP.
Client-side translations are loaded asynchronously. This means elgg.echo will not be ready until after the system is done initializing.
List of events in core¶
System events¶
- boot, system
- first event triggered. Triggered before plugins have been loaded.
- plugins_boot, system
- triggered just after the plugins are loaded. Rarely used. init, system is used instead.
- init, system
- plugins tend to use this event for initialization (extending views, registering callbacks, etc.)
ready, system
- pagesetup, system
- called just before the first content is produced. Is triggered by elgg_view().
- shutdown, system
- triggered after the page has been sent to the user. Expensive operations could be done here and not make the user wait. Note: Depending upon your server configuration the PHP output might not be shown until after the process is completed. This means that any long-running processes will still delay the page load.
log, systemlog
upgrade, system
upgrade, upgrade
- activate, plugin
- return false to prevent activation of the plugin.
- deactivate, plugin
- return false to prevent deactivation of the plugin.
- init:cookie, <name>
- return false to override setting a cookie.
User events¶
- login, user
- triggered during login. Returning false prevents the user from logging
- logout, user
- triggered during logout. Returning false should prevent the user from logging out.
- validate, user
- when a user registers, the user’s account is disabled. This event is triggered to allow a plugin to determine how the user should be validated (for example, through an email with a validation link).
- profileupdate, user
- user has changed profile
- profileiconupdate, user
- user has changed profile icon
- ban, user
- return true to ban user
- unban, user
- return true to unban user
make_admin, user
remove_admin, user
Relationship events¶
- create, <relationship>
- called after the relationship has been created. Returning false deletes the relationship that was just created.
- delete, <relationship>
- called before the relationship is deleted. Return false to prevent it from being deleted.
- join, group
- user joined a group
- leave, group
- user left a group
Entity events¶
- create, <entity type>
- called for user, group, object, and site entities after creation. Return true or entity is deleted.
- update, <entity type>
- called after group update and return false to delete group. Called after object update and return false to delete the object. Called after site update and return false to delete site. Called after user update and returning false deletes the user. Called before entity update and returning false prevents update.
- delete, <entity type>
- called before entity deletion and returning false prevents deletion.
- disable, <entity type>
- return false to prevent disable
- enable, <entity type>
- return false to prevent enable
Metadata events¶
- create, metadata
- called after the metadata has been created. Return false to delete the metadata that was just created.
- update, metadata
- called after the metadata has been updated. Return false to delete the metadata. (That doesn’t sound like a good idea)
- delete, metadata
- called before metadata is deleted. Return false to prevent deletion.
Annotation events¶
- annotate, <entity type>
- called before the annotation has been created. Return false to prevent annotation of this entity.
- create, annotation
- called after the annotation has been created. Return false to delete the annotation.
- update, annotation
- called after the annotation has been updated. Return false to delete the annotation. (That doesn’t sound like a good idea)
- delete, annotation
- called before annotation is deleted. Return false to prevent deletion.
Notes¶
Because of bugs in the Elgg core, some events may be thrown more than once on the same action. update, object is an example of an event that is thrown twice.
List of plugin hooks in core¶
System hooks¶
index, system
email, system
page_owner, system
siteid, system
gc, system
unit_test, system
diagnostics:report, system
search_types, get_types
cron, <period>
validate, input
geocode, location
diagnostics:report, all
debug, log
format, friendly:title
format, friendly:time
format, strip_tags
- output:before, page
- In elgg_view_page(), this filters $vars before it’s passed to the page shell view (page/*). To stop sending the X-Frame-Options header, unregister the handler _elgg_views_send_header_x_frame_options() from this hook.
- output, page
- In elgg_view_page(), this filters the output return value
register, menu:<menu_name>
prepare, menu:<menu_name>
add, river
User hooks¶
usersettings:save, user
unvalidated_login_attempt, user
unvalidated_requestnewpassword, user
access:collections:write, user
registeruser:validate:username, all
registeruser:validate:password, all
registeruser:validate:email, all
session:get, <key>
register, user
- login:forward, user
- Filters the URL to which the user will be forwarded after login
Permission hooks¶
container_permissions_check, <entity_type>
permissions_check, <entity_type>
permissions_check, widget_layout
permissions_check:metadata, <entity_type>
permissions_check:comment, <entity_type>
permissions_check:annotate
fail, auth
session:get, <key>
api_key, use
access:collections:read, user
access:collections:write, user
access:collections:addcollection, collection
access:collections:deletecollection, collection
access:collections:add_user, collection
access:collections:remove_user, collection
- get_sql, access
- Filters the SQL clauses used in _elgg_get_access_where_sql()
Views¶
- view, <view_name>
- Filters the returned content of views
- layout, page
- In elgg_view_layout(), filters the layout name
- display, view
- Deprecated in 1.8! Use view, (view) instead
- shell, view
- In elgg_view_page(), filters the page shell name
- head, page
- In elgg_view_page(), filters $vars[‘head’]
Other¶
- default, access
- In get_default_access(), filters the return value
entity:icon:url, <entity_type>
file:icon:url, override
entity:annotate, <entity_type>
import, all
export, all
object:notifications, <object_subtype>
notify:entity:message, <entity_type> or is it <object_subtype>
plugin:usersetting, user
plugin:setting, plugin
profile:fields, group
profile:fields, profile
widget_settings, <widget_handler>
get_list, default_widgets
rest, init
public_pages, walled_garden
volatile, metadata
- maintenance:allow, url
- Allows whitelisting URLs to non-admins during maintenance mode
Plugins¶
File¶
- simple_type, file
- In file_get_simple_type(), filters the return value
Members¶
- members:list, <page_segment>
- To handle the page /members/$page_segment, handle this hook and return the HTML of the list.
- members:config, tabs
- This hook is used to assemble an array of tabs to be passed to the navigation/tabs view for the members pages.
Twitter API¶
login, twitter_api
new_twitter_user, twitter_service
first_login, twitter_api
authorize, twitter_api
plugin_list, twitter_service
Reported Content¶
reportedcontent:add, system
reportedcontent:archive, system
reportedcontent:delete, system
reportedcontent:add, <entity_type>
reportedcontent:archive, <entity_type>
reportedcontent:delete, <entity_type>
Search¶
search, <type>:<subtype>
search, tags
search, <type>
search_types, get_types
- search_types, get_queries
- Before a search this filters the types queried. This can be used to reorder the display of search results.
Routing¶
Widgets¶
Widgets are content areas that users can drag around their page to customize the layout. They can typically be customized by their owner to show more/less content and determine who sees the widget. By default Elgg provides plugins for customizing the profile page and dashboard via widgets.
TODO: Screenshot
Structure¶
To create a widget, create two views:
- widgets/:widget/edit
- widgets/:widget/content
content.php is responsible for all the content that will output within the widget. The edit.php file contains any extra edit functions you wish to present to the user. You do not need to add access level as this comes as part of the widget framework.
NOTE: using HTML checkboxes to set widget flags is problematic because if unchecked, the checkbox input is omitted from form submission. The effect is that you can only set and not clear flags. The “input/checkboxes” view will not work properly in a widget’s edit panel.
Initialise the widget¶
Once you have created your edit and view pages, you need to initialize the plugin widget. This is done within the plugins init() function.
// Add generic new file widget
add_widget_type('filerepo', elgg_echo("file:widget"), elgg_echo("file:widget:description"));
Note: it is possible to add multiple widgets for a plugin. You just initialize as many widget directories as you need.
// Add generic new file widget
add_widget_type('filerepo', elgg_echo("file:widget"), elgg_echo("file:widget:description"));
// Add a second file widget
add_widget_type('filerepo2', elgg_echo("file:widget2"), elgg_echo("file:widget:description2"));
// Add a third file widget
add_widget_type('filerepo3', elgg_echo("file:widget3"), elgg_echo("file:widget:description3"));
Multiple widgets¶
Make sure you have the corrosponding directories within your plugin views structure:
‘Plugin’
- /views
- /default
- /widgets
- /filerepo
- /edit.php
- /view.php
- /filerepo2
- /edit.php
- /view.php
- /filerepo3
- /edit.php
- /view.php
- /filerepo
- /widgets
- /default
Elgg 1.8: Default widgets¶
If your plugin uses the widget canvas, you can register default widget support with Elgg core, which will handle everything else.
To announce default widget support in your plugin, register for the get_list, default_widgets plugin hook:
elgg_register_plugin_hook_handler('get_list', 'default_widgets', 'my_plugin_default_widgets');
In the plugin hook handler, push an array into the return value defining your default widget support and when to create default widgets. Arrays require the following keys to be defined:
- name - The name of the widgets page. This is displayed on the tab in the admin interface.
- widget_context - The context the widgets page is called from. (If not explicitly set, this is your plugin’s id.)
- widget_columns - How many columns the widgets page will use.
- event - The Elgg event to create new widgets for. This is usually “create.”
- entity_type - The entity type to create new widgets for.
- entity_subtype - The entity subtype to create new widgets for. The can be ELGG_ENTITIES_ANY_VALUE to create for all entity types.
When an object triggers an event that matches the event, entity_type, and entity_subtype parameters passed, Elgg core will look for default widgets that match the widget_context and will copy them to that object’s owner_guid and container_guid. All widget settings will also be copied.
function my_plugin_default_widgets_hook($hook, $type, $return, $params) {
$return[] = array(
'name' => elgg_echo('my_plugin'),
'widget_context' => 'my_plugin',
'widget_columns' => 3,
'event' => 'create',
'entity_type' => 'user',
'entity_subtype' => ELGG_ENTITIES_ANY_VALUE,
);
return $return;
}
Simple Example¶
Here is a simple Flickr widget that uses Flickr’s JSON output.
Widget edit page:
<p>
<?php echo elgg_echo("flickr:id"); ?>
<input type="text" name="params[title]" value="<?php echo htmlentities($vars['entity']->title); ?>" />
</p>
<p><?php echo elgg_echo("flickr:whatisid"); ?></p>
Widget view page:
<?php
//some required params
$flickr_id = $vars['entity']->title;
// if the flickr id is empty, then do not show any photos
if($flickr_id){
?>
<!-- this script uses the jquery cycle plugin -->
<script type="text/javascript" src="<?php echo $vars['url']; ?>mod/flickr/views/default/flickr/js/cycle.js"></script>
<!-- the Flickr JSON script -->
<script>
$.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?id=
<?php echo $flickr_id;?>&lang=en-us&format=json&jsoncallback=?", function(data){
$.each(data.items, function(i,item){
$("<img/>").attr("src", item.media.m).appendTo("#images")
.wrap("<a href='" + item.link + "'></a>");
});
$('#images').cycle({
fx: 'fade',
speed: 'slow',
timeout: 0,
next: '#next',
prev: '#prev'
});
});
</script>
<!-- some css for display -->
<style type="text/css">
#images {
height: 180px;
width: 100%;
padding:0;
margin:0 0 10px 0;
overflow: hidden;
}
#images img {
border:none;
}
</style>
<!-- div where the images will display -->
<div id="title"></div>
<div id="images" align="center"></div>
<!-- next and prev nav -->
<div class="flickrNav" align="center">
<a id="prev" href="#">« Prev</a> <a id="next" href="#">Next »</a>
</div>
<?php
}else{
//this should go through elgg_echo() - it was taken out for this demo
echo "You have not yet entered your Flickr ID which is required to display your photos.";
}
?>
Views¶
Themes¶
Customizing the look and feel of Elgg
A theme is a type of plugin that overrides display aspects of Elgg.
Building your own theme¶
Before you jump in, it is advisable to familiarise yourself with Plugins and the views system.
Create your plugin¶
Step one is to create your plugin as described in the developer guide.
- Create a new directory under mod/
- Create a new start.php
- Create a manifest file describing your theme.
Customize the CSS¶
As of Elgg 1.8, the css is split into several files based on what aspects of the site you’re theming. This allows you to tackle them one at a time, giving you a chance to make real progress without getting overwhelmed.
Here is a list of the existing CSS views:
- css/elements/buttons: Provides a way to style all the different kinds of buttons your site will use. There are 5 kinds of buttons that plugins will expect to be available: action, cancel, delete, submit, and special.
- css/elements/chrome: This file has some miscellaneous look-and-feel classes.
- css/elements/components: This file contains many “css objects” that are used all over the site: media block, list, gallery, table, owner block, system messages, river, tags, photo, and comments.
- css/elements/forms: This file determines what your forms and input elements will look like.
- css/elements/icons: Contains styles for the sprite icons and avatars used on your site.
- css/elements/layout: Determines what your page layout will look like: sidebars, page wrapper, main body, header, footer, etc.
- css/elements/modules: Lots of content in Elgg is displayed in boxes with a title and a content body. We called these modules. There are a few kinds: info, aside, featured, dropdown, popup, widget. Widget styles are included in this file too, since they are a subset of modules.
- css/elements/navigation: This file determines what all your menus will look like.
- css/elements/typography: This file determines what the content and headings of your site will look like.
- css/ie6: Custom rules for ie6 and below.
- css/ie7: Custom rules for ie7 and below.
- css/rtl: Custom rules for users viewing your site in a right-to-left language.
- css/admin: A completely separate theme for the admin area (usually not overridden).
- css/elgg: Compiles all the core css/elements/* files into one file (DO NOT OVERRIDE).
- css/elements/core: Contains base styles for the more complicated “css objects”. If you find yourself wanting to override this, you probably need to report a bug to Elgg core instead (DO NOT OVERRIDE).
- css/elements/reset: Contains a reset stylesheet that forces elements to have the same default
View extension¶
There are two ways you can modify views:
The first way is to add extra stuff to an existing view via the extend view function from within your start.php’s initialization function.
For example, the following start.php will add mytheme/css to Elgg’s core css file:
<?php
function mytheme_init() {
elgg_extend_view('css/elgg', 'mytheme/css');
}
elgg_register_event_handler('init', 'system', 'mytheme_init');
?>
View overloading¶
Plugins can have a view hierarchy, any file that exists here will replace any files in the existing core view hierarchy... so for example, if my plugin has a file:
/mod/myplugin/views/default/css/elements/typography.php
it will replace:
/views/default/css/elements/typography.php
But only when the plugin is active.
This gives you total control over the way elgg looks and behaves. It gives you the option to either slightly modify or totally replace existing views.
Tools¶
Starting in Elgg 1.8, we’ve provided you with some development tools to help you with theming: Turn on the “Developers” plugin and go to the “Theme Preview” page to start tracking your theme’s progress.
Customizing the front page¶
The main Elgg index page runs a plugin hook called ‘index,system’. If this returns true, it assumes that another front page has been drawn and doesn’t display the default page.
Therefore, you can override it by registering a function to the ‘index,system’ plugin hook and then returning true from that function.
Here’s a quick overview:
- Create your new plugin
- In the start.php you will need something like the following:
<?php
function pluginname_init() {
// Replace the default index page
elgg_register_plugin_hook_handler('index', 'system', 'new_index');
}
function new_index() {
if (!include_once(dirname(dirname(__FILE__)) . "/pluginname/pages/index.php"))
return false;
return true;
}
// register for the init, system event when our plugin start.php is loaded
elgg_register_event_handler('init', 'system', 'pluginname_init');
?>
- Then, create an index page (/pluginname/pages/index.php) and use that to put the content you would like on the front page of your Elgg site.
Javascript¶
This guide assumes basic familiarity with:
To use a third-party library, register it with elgg_register_js:
elgg_register_js(‘jquery’, $cdnjs_url);
This will override any previous URLs registered under this name.
If the library does not natively support AMD, use the ‘exports’ and ‘deps’ arguments to add support:
elgg_register_js(‘backbone’, array(
‘src’ => $cdnjs_url,
‘exports’ => ‘Backbone’,
‘deps’ => array(‘jquery’, ‘underscore’),
));
To load a library on a given page, use elgg_require_js:
elgg_require_js(‘jquery’);
This will asynchronously include and execute the linked code.
To use an inline script, use the async require function:
<script>
require([‘jquery’], function(jquery) {
$(‘#example’).fadeIn();
});
</script>
Warning
- Using inline scripts is strongly discouraged because:
- They are not testable (maintainability)
- They are not cacheable (performance)
- Doing so forces some scripts to be loaded in <head> (performance)
Inline scripts in core or bundled plugins are considered bugs and pull requests that remove them are appreciated.
Defining modules¶
To define your own reusable AMD module, place the code in the js/{module/name}.js view. For example:
// mod/example/views/default/js/example/module.js
define(function(require) {
var elgg = require("elgg");
var $ = require("jquery");
return {
doSomething: function() {
// Some logic in here
}
};
});
You can then depend on the module like so:
define(function(require) {
var exampleModule = require(‘example/module’);
exampleModule.doSomething();
});
Core functions¶
elgg.echo
Translate interface text
elgg.echo(‘example:text’, [‘arg1’]);
elgg.system_message(message)
Display a status message to the user.
elgg.system_message(elgg.echo(‘success’));
elgg.register_error(message)
Display an error message to the user.
elgg.register_error(elgg.echo(‘error’));
elgg.forward()
elgg.normalize_url()
Normalize a URL relative to the elgg root:
elgg.normalize_url(‘/blog’); // “http://localhost/elgg/blog”
Redirect to a new page.
elgg.forward(‘/blog’);
This function automatically normalizes the URL.
elgg.parse_url()
Parse a URL into its component parts:
// returns an object with the properties
// fragment: "fragment"
// host: "community.elgg.org"
// path: "/file.php"
// query: "arg=val"
elgg.parse_url(
'http://community.elgg.org/file.php?arg=val#fragment');
elgg.get_page_owner_guid()
Get the GUID of the current page’s owner.
elgg.security.refreshToken()
Force a refresh of all XSRF tokens on the page.
This is automatically called every 5 minutes by default.
This requires a valid security token in 1.8, but not in 1.9.
The user will be warned if their session has expired.
elgg.security.addToken()
Add a security token to an object, URL, or query string:
// returns an object:
// __elgg_token: "1468dc44c5b437f34423e2d55acfdd87"
// __elgg_ts: 1328143779
// other: "data"
elgg.security.addToken({'other': 'data'});
// returns: "action/add?__elgg_ts=1328144079&__elgg_token=55fd9c2d7f5075d11e722358afd5fde2"
elgg.security.addToken("action/add");
// returns "?arg=val&__elgg_ts=1328144079&__elgg_token=55fd9c2d7f5075d11e722358afd5fde2"
elgg.security.addToken("?arg=val");
elgg.get_logged_in_user_entity()
Returns the logged in user as an JS ElggUser object.
elgg.get_logged_in_user_guid()
Returns the logged in user’s guid.
elgg.is_logged_in()
True if the user is logged in.
elgg.is_admin_logged_in()
True if the user is logged in and is an admin.
elgg.config.get_language()
Get the current page’s language.
There are a number of configuration values set in the elgg object:
elgg.config.wwwroot; // The root of the website. elgg.config.language; // The default site language. elgg.config.viewtype; // The current page’s viewtype elgg.config.version; // The Elgg version (YYYYMMDDXX). elgg.config.release; // The Elgg release (X.Y.Z).
Plugin tutorials¶
These tutorials walk you through all the required steps in order to create your own plugins. The instructions are very detailed so you don’t necessarily need previous experience on plugin development.
Hello world¶
This tutorial shows you how to build a simple plugin that adds a new page and prints the text “Hello world” on it.
In this tutorial we will use the address http://www.mysite.com/ as an example. While developing the plugin you should use the address of your own site instead of the example address.
Required files¶
First of all you need a directory that will hold all the files required by the plugin. Go to the mod directory of your Elgg site and create there a directory with the name hello_world.
- Go to the hello_world directory and create these two files inside it:
- start.php
- manifest.xml
Copy this to the manifest.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<plugin_manifest xmlns="http://www.elgg.org/plugin_manifest/1.8">
<name>Hello world</name>
<id>hello_world</id>
<author>Your name here</author>
<version>1.0</version>
<description>Adds a page that prints "Hello world".</description>
<requires>
<type>elgg_release</type>
<version>1.9</version>
</requires>
</plugin_manifest>
Add your name to the <author></author> element.
The plugin has now the minimum requirements for your site to recognize it. Log in to your site as an administrator and access the plugins page at the administration panel. By default the plugin is at the bottom of the plugins list. Click the “Activate” button to start it.
Initializing the plugin¶
The next step is to add some actual features. Open the start.php and copy this to it:
<?php
elgg_register_event_handler('init', 'system', 'hello_world_init');
function hello_world_init() {
}
This piece of code tells Elgg that it should call the function hello_world_init() when the Elgg core system is initiated.
Registering a page handler¶
The next step is to register a page handler which has the purpose of handling request that users make to the URL http://www.mysite.com/hello/.
Update the start.php to look like this:
<?php
elgg_register_event_handler('init', 'system', 'hello_world_init');
function hello_world_init() {
elgg_register_page_handler('hello', 'hello_world_page_handler');
}
function hello_world_page_handler() {
$params = array(
'title' => 'Hello world!',
'content' => 'This is my first plugin.',
'filter' => '',
);
$body = elgg_view_layout('content', $params);
echo elgg_view_page('Hello', $body);
}
The call to elgg_register_page_handler() tells Elgg that it should call the function hello_world_page_handler() when user goes to your site and has “hello” at the end of the URL.
The hello_world_page_handler() makes it possible for the users to access the actual page. Inside the function we first give an array of parameters to the elgg_view_layout() function.
- The parameters include:
- The title of the page
- The contents of the page
- Filter which is left empty because there’s currently nothing to filter
This creates the basic layout for the page. The layout is then run through elgg_view_page() which assembles and outputs the full page.
You can now go to the address http://www.mysite.com/hello/ and you should see the page.

Elgg is now routing the URL http://www.mysite.com/hello/ to the page you created.
Design Docs¶
These docs aim to give you a deep understanding of how Elgg works and why it’s built the way it is.
Database¶
A thorough discussion of Elgg’s data model design and motivation.
Overview¶
In Elgg, everything runs on a unified data model, based on atomic units of data called entities.
Plugins are strongly discouraged from dealing with database issues themselves, which makes for a more stable system that also has visible benefits for the end user. Content created by different plugins can be mixed together in consistent ways, which are programmed using generic principles - in other words, plugins are faster to develop, and are at the same time much more powerful.
Every entity in the system inherits the ElggEntity class. This class controls access permissions, ownership and so on.
You can extend entities with extra information in two ways:
- Metadata: This is information you can add to an object to
- describe it further. For example, tags, an ISBN number, a file location or language information would fall under metadata.
- Annotations: Information generally added by third parties which
- adds to the information provided by the entity. For example, ratings are annotations (and comments were before 1.9).
Entities¶
ElggEntity is the base class for the Elgg data model.
Users, Objects, Groups, Sites¶
ElggEntity has four main specializations, which provide extra properties and methods to more easily handle different kinds of data.
ElggObject: content like blog posts, uploaded files and bookmarks ElggUser: a system user ElggSite: each Elgg site within an Elgg installation ElggGroup: multi-user collaborative systems (called “Communities” in prior versions of Elgg)
The benefit of such an approach is that, apart from modelling data with greater ease, a common set of functions is available to handle objects, regardless of their (sub)type.
Each of these have their own properties that they bring to the table: ElggObjects have a title and description, ElggUsers have a username and password, and so on. However, because they all inherit ElggEntity, they each have a number of core properties and behaviours in common.
- A numeric Globally Unique IDentifier (See GUIDs).
- Access permissions. (When a plugin requests data, it never gets to touch data that the current user doesn’t have permission to see.)
- An arbitrary subtype. For example, a blog post is an ElggObject with a subtype of “blog”. Subtypes aren’t predefined; they can be any unique way to describe a particular kind of entity. “blog”, “forum”, “foo”, “bar”, “loafofbread” and “pyjamas” are all valid subtypes.
- An owner.
- The site that the entity belongs to.
- A container, usually used to associate a group’s content with the group.
GUIDs¶
A GUID is an integer that uniquely identifies every entity in an Elgg installation (a Globally Unique IDentifier). It’s assigned automatically when the entity is first saved and can never be changed.
Some Elgg API functions work with GUIDs instead of ElggEntity objects.
ElggObject¶
The ElggObject entity type represents arbitrary content within an Elgg install; things like blog posts, uploaded files, etc.
Beyond the standard ElggEntity properties, ElggObjects also support:
- title The title of the object (HTML escaped text)
- description A description of the object (HTML)
Most other data about the object is generally stored via metadata.
ElggUser¶
The ElggUser entity type represents users within an Elgg install. These will be set to disabled until their accounts have been activated (unless they were created from within the admin panel).
Beyond the standard ElggEntity properties, ElggUsers also support:
- name The user’s plain text name. e.g. “Hugh Jackman”
- username Their login name. E.g. “hjackman”
- password A hashed version of their password
- salt The salt that their password has been hashed with
- email Their email address
- language Their default language code.
- code Their session code (moved to a separate table in 1.9).
- last_action The UNIX timestamp of the last time they loaded a page
- prev_last_action The previous value of last_action
- last_login The UNIX timestamp of their last log in
- prev_last_login the previous value of last_login
ElggSite¶
The ElggSite entity type represents sites within your Elgg install. Most installs will have only one.
Beyond the standard ElggEntity properties, ElggSites also support:
- name The site name
- description A description of the site
- url The address of the site
ElggGroup¶
The ElggGroup entity type represents an association of Elgg users. Users can join, leave, and post content to groups.
Beyond the standard ElggEntity properties, ElggGroups also support:
- name The group’s name (HTML escaped text)
- description A description of the group (HTML)
ElggGroup has addition methods to manage content and membership.
The Groups plugin¶
Not to be confused with the entity type ElggGroup, Elgg comes with a plugin called “Groups” that provides a default UI/UX for site users to interact with groups. Each group is given a discussion forum and a profile page linking users to content within the group.
You can alter the user experience via the traditional means of extending plugins or completely replace the Groups plugin with your own.
Because ElggGroup can be subtyped like all other ElggEntities, you can have multiple types of groups running on the same site.
Writing a group-aware plugin¶
Plugin owners need not worry too much about writing group-aware functionality, but there are a few key points:
Adding content¶
By passing along the group as container_guid via a hidden input field, you can use a single form and action to add both user and group content.
Use can_write_to_container to determine whether or not the current user has the right to add content to a group.
Be aware that you will then need to pass the container GUID or username to the page responsible for posting and the accompanying value, so that this can then be stored in your form as a hidden input field, for easy passing to your actions. Within a “create” action, you’ll need to take in this input field and save it as a property of your new element (defaulting to the current user’s container):
$user = elgg_get_logged_in_user_entity();
$container_guid = (int)get_input('container_guid');
if ($container_guid) {
if (!can_write_to_container($user->guid, $container_guid)) {
// register error and forward
}
} else {
$container_guid = elgg_get_logged_in_user_guid();
}
$object = new ElggObject;
$object->container_guid = $container_guid;
...
$container = get_entity($container_guid);
forward($container->getURL());
Usernames and page ownership¶
Groups have a simulated username of the form group:GUID, which you can get the value of by checking $group->username. If you pass this username to a page on the URL line as part of the username variable (i.e., /yourpage?username=group:nnn), Elgg will automatically register that group as being the owner of the page (unless overridden).
Juggling users and groups¶
In fact, [[Engine/DataModel/Entities/ElggGroup|ElggGroup]] simulates most of the methods of [[Engine/DataModel/Entities/ElggUser|ElggUser]]. You can grab the icon, name etc using the same calls, and if you ask for a group’s friends, you’ll get its members. This has been designed specifically for you to alternate between groups and users in your code easily.
Ownership¶
Entities have a owner_guid GUID property, which defines its owner. Typically this refers to the GUID of a user, although sites and users themselves often have no owner (a value of 0).
The ownership of an entity dictates, in part, whether or not you can access or edit that entity.
Containers¶
In order to easily search content by group or by user, content is generally set to be “contained” by either the user who posted it, or the group to which the user posted. This means the new object’s container_guid property will be set to the GUID of the current ElggUser or the target ElggGroup.
E.g., three blog posts may be owned by different authors, but all be contained by the group they were posted to.
Note: This is not always true. Comment entities are contained by the object commented upon, and in some 3rd party plugins the container may be used to model a parent-child relationship between entities (e.g. a “folder” object containing a file object).
Annotations¶
Annotations are pieces of data attached to an entity that allow users to leave ratings, or other relevant feedback. A poll plugin might register votes as annotations. Before Elgg 1.9, comments and group discussion replies were stored as annotations.
Annotations are stored as instances of the ElggAnnotation class.
Each annotation has:
- An internal annotation type (like comment)
- A value (which can be a string or integer)
- An access permission distinct from the entity it’s attached to
- An owner
Adding an annotation¶
The easiest way to annotate is to use the annotate method on an entity, which is defined as:
public function annotate(
$name, // The name of the annotation type (eg 'comment')
$value, // The value of the annotation
$access_id = 0, // The access level of the annotation
$owner_id = 0, // The annotation owner, defaults to current user
$vartype = "" // 'text' or 'integer'
)
For example, to leave a rating on an entity, you might call:
$entity->annotate('rating', $rating_value, $entity->access_id);
Reading annotations¶
To retrieve annotations on an object, you can call the following method:
$annotations = $entity->getAnnotations(
$name, // The type of annotation
$limit, // The number to return
$offset, // Any indexing offset
$order, // 'asc' or 'desc' (default 'asc')
);
If your annotation type largely deals with integer values, a couple of useful mathematical functions are provided:
$averagevalue = $entity->getAnnotationsAvg($name); // Get the average value
$total = $entity->getAnnotationsSum($name); // Get the total value
$minvalue = $entity->getAnnotationsMin($name); // Get the minimum value
$maxvalue = $entity->getAnnotationsMax($name); // Get the maximum value
Metadata¶
Metadata in Elgg allows you to store extra data on an entity beyond the built-in fields that entity supports. For example, ElggObjects only support the basic entity fields plus title and description, but you might want to include tags or an ISBN number. Similarly, you might want users to be able to save a date of birth.
Under the hood, metadata is stored as an instance of the ElggMetadata class, but you don’t need to worry about that in practice (although if you’re interested, see the ElggMetadata class reference). What you need to know is:
- Metadata has an owner and access ID, both of which may be different to the owner of the entity it’s attached to
- You can potentially have multiple items of each type of metadata attached to a single entity
The simple case¶
Adding metadata¶
To add a piece of metadata to an entity, just call:
$entity->metadata_name = $metadata_value;
For example, to add a date of birth to a user:
$user->dob = $dob_timestamp;
Or to add a couple of tags to an object:
$object->tags = array('tag one', 'tag two', 'tag three');
When adding metadata like this:
- The owner is set to the currently logged-in user
- Access permissions are inherited from the entity
- Reassigning a piece of metadata will overwrite the old value
This is suitable for most purposes. Be careful to note which attributes are metadata and which are built in to the entity type that you are working with. You do not need to save an entity after adding or updating metadata. You do need to save an entity if you have changed one of its built in attributes. As an example, if you changed the access id of an ElggObject, you need to save it or the change isn’t pushed to the database.
Reading metadata¶
To retrieve metadata, treat it as a property of the entity:
$tags_value = $object->tags;
Note that this will return the absolute value of the metadata. To get metadata as an ElggMetadata object, you will need to use the methods described in the finer control section below.
If you stored multiple values in this piece of metadata (as in the “tags” example above), you will get an array of all those values back. If you stored only one value, you will get a string or integer back. Storing an array with only one value will return a string back to you. E.g.
$object->tags = array('tag');
$tags = $object->tags;
// $tags will be the string "tag", NOT array('tag')
To always get an array back, simply cast to an array;
$tags = (array)$object->tags;
Finer control¶
Adding metadata¶
If you need more control, for example to assign an access ID other than the default, you can use the create_metadata function, which is defined as follows:
function create_metadata(
$entity_guid, // The GUID of the parent entity
$name, // The name of the metadata (eg 'tags')
$value, // The metadata value
$value_type, // Currently either 'string' or 'integer'
$owner_guid, // The owner of the metadata
$access_id = 0, // The access restriction
$allow_multiple = false // Do we have more than one value?
)
For single values, you can therefore write metadata as follows (taking the example of a date of birth attached to a user):
create_metadata($user_guid, 'dob', $dob_timestamp, 'integer', $_SESSION['guid'], $access_id);
For multiple values, you will need to iterate through and call create_metadata on each one. The following piece of code comes from the profile save action:
$i = 0;
foreach ($value as $interval) {
$i++;
$multiple = ($i != 1);
create_metadata($user->guid, $shortname, $interval, 'text', $user->guid, $access_id, $multiple);
}
Note that the allow multiple setting is set to false in the first iteration and true thereafter.
Reading metadata¶
elgg_get_metadata is the best function for retrieving metadata as ElggMetadata objects:
E.g., to retrieve a user’s DOB
elgg_get_metadata(array(
'metadata_name' => 'dob',
'metadata_owner_guid' => $user_guid,
));
Or to get all metadata objects:
elgg_get_metadata(array(
'metadata_owner_guid' => $user_guid,
'limit' => 0,
));
Common mistakes¶
“Appending” metadata¶
Note that you cannot “append” values to metadata arrays as if they were normal php arrays. For example, the following will not do what it looks like it should do.
$object->tags[] = "tag four";
Trying to store hashmaps¶
Elgg does not support storing ordered maps (name/value pairs) in metadata. For example, the following does not work as you might first expect it to:
// Won't work!! Only the array values are stored
$object->tags = array('one' => 'a', 'two' => 'b', 'three' => 'c');
You can instead store the information like so:
$object->one = 'a';
$object->two = 'b';
$object->three = 'c';
Storing GUIDs in metadata¶
Though there are some cases to store entity GUIDs in metadata, Relationships are a much better construct for relating entities to each other.
Relationships¶
Relationships allow you to bind entities together. Examples: an artist has fans, a user is a member of an organization, etc.
The class ElggRelationship models a directed relationship between two entities, making the statement:
“{subject} is a {noun} of {target}.”
API name | Models | Represents |
---|---|---|
guid_one | The subject | Which entity is being bound |
relationship | The noun | The type of relationship |
guid_two | The target | The entity to which the subject is bound |
The type of relationship may alternately be a verb, making the statement:
“{subject} {verb} {target}.”
E.g. User A “likes” blog post B
Each relationship has direction. Imagine an archer shoots an arrow at a target; The arrow moves in one direction, binding the subject (the archer) to the target.
A relationship does not imply reciprocity. A follows B does not imply that B follows A.
Relationships_ do not have access control. They’re never hidden from view and can be edited with code at any privilege level, with the caveat that the entities in a relationship may be invisible due to access control!
Working with relationships¶
Creating a relationship¶
E.g. to establish that “$user is a fan of $artist” (user is the subject, artist is the target):
// option 1
$success = add_entity_relationship($user->guid, 'fan', $artist->guid);
// option 2
$success = $user->addRelationship($artist->guid, 'fan');
This triggers the event [create, relationship], passing in the created ElggRelationship object. If a handler returns false, the relationship will not be created and $success will be false.
Verifying a relationship¶
E.g. to verify that “$user is a fan of $artist”:
if (check_entity_relationship($user->guid, 'fan', $artist->guid)) {
// relationship exists
}
Note that, if the relationship exists, check_entity_relationship() returns an ElggRelationship object:
$relationship = check_entity_relationship($user->guid, 'fan', $artist->guid);
if ($relationship) {
// use $relationship->id or $relationship->time_created
}
Deleting a relationship¶
E.g. to be able to assert that “$user is no longer a fan of $artist”:
$was_removed = remove_entity_relationship($user->guid, 'fan', $artist->guid);
This triggers the event [delete, relationship], passing in the associated ElggRelationship object. If a handler returns false, the relationship will remain, and $was_removed will be false.
Other useful functions:
- delete_relationship() : delete by ID
- remove_entity_relationships() : delete those relating to an entity (note: in versions before Elgg 1.9, this did not trigger delete events)
Access Control¶
Granular access controls are one of the fundamental design principles in Elgg, and a feature that has been at the centre of the system throughout its development. The idea is simple: a user should have full control over who sees an item of data he or she creates.
Access controls in the data model¶
In order to achieve this, every entity, annotation and piece of metadata contains an access_id property, which in turn corresponds to one of the pre-defined access controls or an entry in the access_collections database table.
Pre-defined access controls¶
- 0 Private.
- 1 Logged in users.
- 2 Public data.
User defined access controls¶
You may define additional access groups and assign them to an entity, annotation or metadata. A number of functions have been defined to assist you; see the access library reference for more information.
How access affects data retrieval¶
All data retrieval functions above the database layer - for example get_entities and its cousins - will only return items that the current user has access to see. It is not possible to retrieve items that the current user does not have access to. This makes it very hard to create a security hole for retrieval.
Write access¶
The following rules govern write access:
- The owner of an entity can always edit it
- The owner of a container can edit anything therein (note that this does not mean that the owner of a group can edit anything therein)
- Admins can edit anything
You can override this behaviour using a plugin hook called permissions_check, which passes the entity in question to any function that has announced it wants to be referenced. Returning true will allow write access; returning false will deny it. See the plugin hook reference for permissions_check for more details.
Schema¶
The database contains a number of primary tables and secondary tables. Its schema table is stored in /engine/schema/mysql.sql.
Each table is prefixed by “prefix_”, this is replaced by the Elgg framework during installation.
Main tables¶
This is a description of the main tables. Keep in mind that in a given Elgg installation, the tables will have a prefix (typically “elgg_”).
Table: entities¶
This is the main Entities table containing Elgg users, sites, objects and groups. When you first install Elgg this is automatically populated with your first site.
It contains the following fields:
- guid An auto-incrementing counter producing a GUID that uniquely identifies this entity in the system.
- type The type of entity - object, user, group or site
- subtype A link to the entity_subtypes table.
- owner_guid The GUID of the owner’s entity.
- site_guid The site the entity belongs to.
- container_guid The GUID this entity is contained by - either a user or a group.
- access_id Access controls on this entity.
- time_created Unix timestamp of when the entity is created.
- time_updated Unix timestamp of when the entity was updated.
- enabled If this is ‘yes’ an entity is accessible, if ‘no’ the entity has been disabled (Elgg treats it as if it were deleted without actually removing it from the database).
Table: entity_subtypes¶
This table contains entity subtype information:
- id A counter.
- type The type of entity - object, user, group or site.
- subtype The subtype name as a string.
- class Optional class name if this subtype is linked with a class
Table: metadata¶
This table contains Metadata, extra information attached to an entity.
- id A counter.
- entity_guid The entity this is attached to.
- name_id A link to the metastrings table defining the name table.
- value_id A link to the metastrings table defining the value.
- value_type The value class, either text or an integer.
- owner_guid The owner GUID of the owner who set this item of metadata.
- access_id An Access controls on this item of metadata.
- time_created Unix timestamp of when the metadata is created.
- enabled If this is ‘yes’ an item is accessible, if ‘no’ the item has been deleted.
Table: annotations¶
This table contains Annotations, this is distinct from Metadata.
- id A counter.
- entity_guid The entity this is attached to.
- name_id A link to the metastrings table defining the type of annotation.
- value_id A link to the metastrings table defining the value.
- value_type The value class, either text or an integer.
- owner_guid The owner GUID of the owner who set this item of metadata.
- access_id An Access controls on this item of metadata.
- time_created Unix timestamp of when the metadata is created.
- enabled If this is ‘yes’ an item is accessible, if ‘no’ the item has been deleted.
Table: relationships¶
This table defines Relationships, these link one entity with another.
- guid_one The GUID of the subject entity.
- relationship The type of the relationship.
- guid_two The GUID of the target entity.
Table: objects_entity¶
Extra information specifically relating to objects. These are split in order to reduce load on the metadata table and make an obvious difference between attributes and metadata.
Table: sites_entity¶
Extra information specifically relating to sites. These are split in order to reduce load on the metadata table and make an obvious difference between attributes and metadata.
Table: users_entity¶
Extra information specifically relating to users. These are split in order to reduce load on the metadata table and make an obvious difference between attributes and metadata.
Table: groups_entity¶
Extra information specifically relating to groups. These are split in order to reduce load on the metadata table and make an obvious difference between attributes and metadata.
Table: metastrings¶
Metastrings contain the actual string of metadata which is linked to by the metadata and annotations tables.
This is to avoid duplicating strings, saving space and making database lookups more efficient.
Core developers will place schema upgrades in /engine/schema/upgrades/*.
Events and Plugin Hooks¶
Overview¶
Elgg has an event system that can be used to replace or extend core functionality.
Plugins influence the system by creating handlers (callables such as functions and methods) and registering them to handle two types of events: Elgg Events and Plugin Hooks.
When an event is triggered, a set of handlers is assembled in order of priority, then each is executed. Each handler is passed arguments and has a chance to influence the process. Finally the “trigger” function returns a value based on the behavior of the handlers.
Elgg Events vs. Plugin Hooks¶
There are a few big differences between Elgg Events and Plugin Hooks:
- Most Elgg events can be cancelled; unless the event is an “after” event, a handler that returns false can cancel the event, and no more handlers are called.
- Plugin hooks cannot be cancelled; all handlers are always called.
- Plugin hooks pass an arbitrary value through the handlers, giving each a chance to alter along the way.
Note: Plugin hooks also allow passing a parameters array to the handlers, though this will eventually come to Elgg events as well.
Elgg Events¶
Elgg Events are triggered when an Elgg object is created, updated, or deleted; and at important milestones while the Elgg framework is loading. Examples: a blog post being created or a user logging in.
Unlike Plugin Hooks, most Elgg events can be cancelled, halting the execution of the handlers, and possibly cancelling or reverting some action in the Elgg core.
Each Elgg event has a name and an object type (system, user, object, relationship name, annotation, group) describing the type of object passed to the handlers.
Before and After Events¶
Some events are split into “before” and “after”. This avoids confusion around the state of the system while in flux. E.g. Should the user be logged in during the [login, user] event?
Before Events have names ending in ”:before” and are triggered before something happens. Like traditional events, handlers can cancel the event by returning false.
After Events, with names ending in ”:after”, are triggered after something happens. Unlike traditional events, handlers cannot cancel these events; all handlers will always be called.
Where before and after events are available, developers are encouraged to transition to them, though older events will be supported for backwards compatibility.
Elgg Event Handlers¶
Elgg event handlers should have the following prototype:
/**
* @param string $event The name of the event
* @param string $object_type The type of $object (e.g. "user", "group")
* @param mixed $object The object of the event
*
* @return bool if false, the handler is requesting to cancel the event
*/
function event_handler($event, $object_type, $object) {
...
}
If the handler returns false, the event is cancelled, preventing execution of the other handlers. All other return values are ignored.
Register to handle an Elgg Event¶
Register your handler to an event using elgg_register_event_handler:
elgg_register_event_handler($event, $object_type, $handler, $priority);
Parameters:
- $event The event name.
- $object_type The object type (e.g. “user” or “object”) or ‘all’ for all types on which the event is fired.
- $handler The callback of the handler function.
- $priority The priority - 0 is first and the default is 500.
Object here does not refer to an ElggObject but rather any object in the framework: system, user, object, relationship, annotation, group.
Example:
// Register the function myPlugin_handle_login() to handle the
// user login event with priority 400.
elgg_register_event_handler('login', 'user', 'myPlugin_handle_login', 400);
Trigger an Elgg Event¶
You can trigger a custom Elgg event using elgg_trigger_event:
if (elgg_trigger_event($event, $object_type, $object)) {
// Proceed with doing something.
} else {
// Event was cancelled. Roll back any progress made before the event.
}
Parameters:
- $event The event name.
- $object_type The object type (e.g. “user” or “object”).
- $object The object (e.g. an instance of ElggUser or ElggGroup)
The function will return false if any of the selected handlers returned false, otherwise it will return true.
Plugin Hooks¶
Plugin Hooks provide a way for plugins to collaboratively determine or alter a value. E.g. this could be to set a configuration array or to decide whether a user has permission to edit an entity.
A plugin hook has a value passed into the trigger function, and each handler has an opportunity to alter the value before it’s passed to the next handler. After the last handler has completed, the current value is returned by the trigger.
Plugin Hook Handlers¶
Plugin hook handlers should have the following prototype:
/**
* @param string $hook The name of the plugin hook
* @param string $type The type of the plugin hook
* @param mixed $value The current value of the plugin hook
* @param mixed $params Data passed from the trigger
*
* @return mixed if not null, this will be the new value of the plugin hook
*/
function plugin_hook_handler($hook, $type, $value, $params) {
...
}
If the handler returns no value (or null explicitly), the plugin hook value is not altered. Otherwise the return value becomes the new value of the plugin hook. It will then be passed to the next handler as $value.
Register to handle a Plugin Hook¶
Register your handler to a plugin hook using elgg_register_plugin_hook_handler:
elgg_register_plugin_hook_handler($hook, $type, $handler, $priority);
Parameters:
- $hook The name of the plugin hook.
- $type The type of the hook or ‘all’ for all types.
- $handler The callback of the handler function.
- $priority The priority - 0 is first and the default is 500.
Type can vary in meaning. It may mean an Elgg entity type or something specific to the plugin hook name.
Example:
// Register the function myPlugin_hourly_job() to be called with priority 400.
elgg_register_plugin_hook_handler('cron', 'hourly', 'myPlugin_hourly_job', 400);
Trigger a Plugin Hook¶
You can trigger a custom plugin hook using elgg_trigger_plugin_hook:
// filter $value through the handlers
$value = elgg_trigger_plugin_hook($hook, $type, $params, $value);
Parameters:
- $hook The name of the plugin hook.
- $type The type of the hook or ‘all’ for all types.
- $params Arbitrary data passed from the trigger to the handlers.
- $value The initial value of the plugin hook.
Caveat! The $params and $value arguments are reversed between the plugin hook handlers and trigger functions!
Internationalization¶
Elgg 1.0+ departs from previous versions in that it uses a custom text array rather than gettext. This improves system performance and reliability of the translation system.
AMD¶
As of Elgg 1.9, we are encouraging all developers to adopt the AMD (Asynchronous Module Definition) standard for writing Javascript code in Elgg.
Usage¶
Defining and loading a module in Elgg 1.9 takes two steps:
- Define your module as asynchronous JavaScript
- Use require or elgg_load_js to asynchronously execute your module in the current page.
Read on for details.
1. Define your module as asynchronous JavaScript¶
You can define a module via a view or an URL.
Define your module in the appropriate view (js/my/module.js)¶
Place the code for “my/module” at “views/default/js/my/module.js”. There is no need to use elgg_register_js() in this case.
A basic module will look like this:
define(function(require) {
var elgg = require("elgg");
var $ = require("jquery");
return function() {
// Some logic in here
};
});
Define your module via an URL¶
You can register an existing AMD module using elgg_register_js() by setting the third parameter to ‘async’.
<?php
// AMD module
elgg_register_js('backbone', '/vendors/backbone/backbone.js', 'async');
Traditional (brower-globals) JavaScript files can also be defined as AMD modules if you shim them.
<?php
// AMD shimed module
elgg_register_js('jquery.form', array(
'src' => '/vendors/jquery/jquery.form.js',
'deps' => array('jquery'),
'exports' => 'jQuery.fn.ajaxForm',
));
Some things to note¶
- Do not use elgg.provide() or elgg.require() anymore. They are fully replaced by define() and require() respectively.
- There is no need to put the name of the module in your code. It is named implicitly based on where you put it in the views system.
- Return the value of the module instead of adding to a global variable.
- Now that Elgg 1.9 supports static files as views, you no longer need a .php extension. Since the view is static, it is automatically minified and cached by Elgg’s simplecache system.
2. Use require or elgg_load_js to load the module on the current page¶
Once an AMD module is defined, you can use require("my/module") from JavaScript to get access to its “exported” value.
Also, calling elgg_load_js("my/module") from PHP tells Elgg to execute the module code on the current page.
I have a lot of JS written for Elgg 1.8. What does this mean for me?¶
First thing’s first: Your current javascript modules will continue to work with Elgg. We do not anticipate any backwards compatibility issues with this new direction and will fix any issues that do come up. We think developing in the AMD format will be great, but we understand that you don’t always have the cycles to convert to The New Way immediately, so we want to give everyone flexibility to switch to the new standard when it’s most convenient for them. For developers ready to make the switch to AMD, read on.
Why AMD?¶
For some time now, we have been working hard to make Elgg’s Javascript more maintainable and useful. We made some strides in 1.8 with the introduction of the “elgg” javascript object and library, but have quickly realized that based on the number of features we’d like to see added to the platform, the approach we were taking was not scalable. The size of JS on the web is growing quickly, and JS in Elgg is growing too. We want Elgg to be able to offer a solution that makes JS development as productive and maintainable as possible for everyone going forward.
The reasons to choose AMD are plenteous and well-documented. Let’s highlight just a few of the most relevant reasons as they relate to Elgg specifically.
1. Simplified dependency management¶
No more “priority” or “location” arguments for your scripts. You don’t even need to call elgg_register_js() for new AMD modules. They load asynchronously and execute as soon as their dependencies are available. Also, you don’t need to worry about explicitly loading your module’s dependencies using elgg_load_js(). The AMD loader (RequireJS in this case) takes care of all that hassle for you. It’s also possible have text dependencies with the RequireJS text plugin, so client-side templating should be a breeze.
2. AMD works in all browsers. Today.¶
Elgg developers are already writing lots of Javascript. We know you want to write more. We cannot accept waiting 5-10 years for a native JS modules solution to be available in all browsers before we can organize our javascript in a maintainable way.
3. You do not need a build step to develop in AMD.¶
We like the edit-refresh cycle of web development. We wanted to make sure everyone developing on Elgg could continue experiencing that joy. Synchronous module formats like Closure or CommonJS just weren’t an option for us. But even though AMD doesn’t require a build step, it is still very build-friendly. Because of the define() wrapper, It’s possible to concatenate multiple modules into a single file and ship them all at once in a production environment. [*]
AMD is a battle-tested and well thought out module loading system for the web today. We’re very thankful for the work that has gone into it, and are excited to offer it as the standard solution for Javascript development in Elgg starting with Elgg 1.9.
[*] | This is not currently supported by Elgg core, but we’ll be looking into it, since reducing round-trips is critical for a good first-view experience, especially on mobile devices. |
Security¶
This document describes Elgg’s approach to the various security issues common to all web applications.
To report a potential vulnerability in Elgg, email security@elgg.org.
Passwords¶
Password validation¶
The only restriction that Elgg places on a password is that it must be at least 6 characters long by default, though this may be changed in /engine/settings.php. Additional criteria can be added by a plugin by registering for the registeruser:validate:password plugin hook.
Password salting¶
- Elgg salts passwords with a unique 8 character random string. The salt is generated each time the password is set. The main security advantages of the salting are:
- preventing anyone with access to the database from conducting a precomputed dictionary attack
- preventing a site administration from noting users with the same password.
Password hashing¶
The hashed password is computed using md5 from the user’s password text and the salt.
Password storage¶
The hashed password and the salt are stored in the users table. Neither are stored in any cookies on a user’s computer.
Password throttling¶
Elgg has a password throttling mechanism to make dictionary attacks from the outside very difficult. A user is only allowed 5 login attempts over a 5 minute period.
Password resetting¶
If a user forgets his password, a new random password can be requested. After the request, an email is sent with a unique URL. When the user visits that URL, a new random password is sent to the user through email.
Sessions¶
Elgg uses PHP’s session handling with custom handlers. Session data is stored in the database. The session cookie contains the session id that links the user to the browser. The user’s metadata is stored in the session including GUID, username, email address. The session’s lifetime is controlled through the server’s PHP configuration.
Session fixation¶
Elgg protects against session fixation by regenerating the session id when a user logs in.
Session hijacking¶
Warning
This section is questionable.
Besides protecting against session fixation attacks, Elgg also has a further check to try to defeat session hijacking if the session identifier is compromised. Elgg stores a hash of the browser’s user agent and a site secret as a session fingerprint. The use of the site secret is rather superfluous but checking the user agent might prevent some session hijacking attempts.
“Remember me” cookie¶
To allow users to stay logged in for a longer period of time regardless of whether the browser has been closed, Elgg uses a cookie (called elggperm) that contains what could be considered a super session identifier. This identifier is stored in a cookies table. When a session is being initiated, Elgg checks for the presence of the elggperm cookie. If it exists and the session code in the cookie matches the code in the cookies table, the corresponding user is automatically logged in.
Alternative authentication¶
Note
This section is very hand-wavy
To replace Elgg’s default user authentication system, a plugin would have to replace the default action with its own through register_action(). It would also have to register its own pam handler using register_pam_handler().
Note
The pam_authenticate() function used to call the different modules has a bug related to the importance variable.
HTTPS¶
Note
You must enable SSL support on your server for any of these techniques to work.
To make the login form submit over https, turn on login-over-ssl from Elgg’s admin panel.
You can also serve your whole site over SSL by simply changing the site URL to include “https” instead of just “http.”
XSS¶
Filtering is used in Elgg to make XSS attacks more difficult. The purpose of the filtering is to remove Javascript and other dangerous input from users.
Filtering is performed through the function filter_tags(). This function takes in a string and returns a filtered string. It triggers a validate, input plugin hook.
By default Elgg comes with the htmLawed filtering code as a plugin. Developers can drop in any additional or replacement filtering code as a plugin.
The filter_tags() function is called on any user input as long as the input is obtained through a call to get_input(). If for some reason a developer did not want to perform the default filtering on some user input, the get_input() function has a parameter for turning off filtering.
XSRF¶
Elgg generates security tokens to prevent XSRF attacks. These are embedded in all forms and state-modifying AJAX requests as long as the correct API is used. Read more in the Forms + Actions developer guide.
About¶
Roadmap¶
We do not publish detailed roadmaps, but it’s possible to get a sense for our general direction by utilizing the following resources:
- Our feedback and planning group is used to host early discussion about what will be worked on next.
- Our Github milestones represent a general direction for the future releases of Elgg. This is the closest thing to a traditional roadmap that we have.
- Github pull requests will give you a good idea of what’s currently being developed, but nothing is sure until the PR is actually checked in.
- We use the developer blog to post announcements of features that have recently been checked in to our development branch, which gives the surest indication of what features will be available in the next release.
Values¶
We have several overarching goals/values that affect the direction of Elgg. Enhancements generally must promote these values in order to be accepted.
Accessibility¶
Elgg-based sites should be usable by anyone anywhere. That means we’ll always strive to make Elgg:
- Device-agnostic – mobile, tablet, desktop, etc. friendly
- Language-agnostic – i18n, RTL, etc.
- Capability-agnostic – touch, keyboard, screen-reader friendly
Testability¶
We want to make manual testing unnecessary for core developers, plugin authors, and site administrators by promoting and enabling fast, automated testing at every level of the Elgg stack.
We think APIs are broken if they require plugin authors to write untestable code. We know there are a lot of violations of this principle in core currently and are working to fix it.
We look forward to a world where the core developers do not need to do any manual testing to verify the correctness of code contributed to Elgg. Similarly, we envision a world where site administrators can upgrade and install new plugins with confidence that everything works well together.
TODO: other goals/values?
FAQ¶
When will feature X be implemented?¶
We cannot promise when features will get implemented because new features are checked into Elgg only when someone is motivated enough to implement the feature and submit a pull request. The best we can do is tell you to look out for what features existing developers have expressed interest in working on.
The best way to ensure a feature gets implemented is to discuss it with the core team and implement it yourself. See our Contributing guide if you’re interested. We love new contributors!
Do not rely on future enhancements if you’re on the fence as to whether to use Elgg. Evaluate it given the current feature set. Upcoming features will almost certainly not materialize within your timeline.
When is version X.Y.Z going to be released?¶
The next version will be released when the core team feels it’s ready and has time to cut the release.
Release Policy¶
What to expect when upgrading Elgg.
In general, we adhere to semantic versioning.
Follow the blog to stay up to date on the latest releases.
Bugfix Releases (1.9.x)¶
Every few weeks.
Bugfix releases are made regularly to make sure Elgg stays stable, secure, and bug-free. The higher the third digit, the more tested and stable the release is. Since bugfix release focus on fixing bugs and not making major changes, themes and plugins should work from bugfix release to bugfix release.
Feature Releases (1.x.0)¶
Every few months.
New features are introduced in Elgg every few months in minor new feature releases. These versions are identified by the second digit (1.**8**.0). These releases aren’t as mature as bugfix release, but are considered stable and useable. Though these releases try to be backward compatible, features are added, unused code removed, and overall improvements are made, so plugins and themes might need to be updated to make use of the new and improved features.
Major Releases (x.0.0)¶
Every few years.
Elgg, as all software, inevitably undergoes serious changes and a major new feature release is made. These releases are opportunities for the core team to make dramatic improvements to the underlying platform. Themes and plugins from older versions are not expected to work without modification on different major releases.
Release Candidates/Betas¶
Before feature releases and major releases, the core team will typically offer a release candidate or beta. These are meant for testing only and should not be considered production quality. The core team makes these releases available to get some real-world testing and feedback on the release. That said, the API in release candidates is considered stable, so once a release candidate is made available, you should feel comfortable writing plugins against any new APIs.
Contributing¶
Participating in making Elgg great.
Report bugs¶
See https://github.com/elgg/elgg/blob/master/CONTRIBUTING.md
Submit Pull Requests¶
See https://github.com/elgg/elgg/blob/master/CONTRIBUTING.md
Write Documentation¶
New documentation should fit stylistically with the rest of Elgg’s docs.
Follow the existing document organization¶
It’s not necessarily the One True Way to organize the docs, but consistency is better than randomness.
intro/*¶
This is everything that brand new users need to know (installation, features, license, etc.)
admin/*¶
Guides for administrators. Task-oriented.
guides/*¶
API guides for plugin developers. Cookbook-style. Example heavy. Code snippet heavy. Broken down by services (actions, i18n, routing, db, etc.). This should only discuss the public API and its behavior, not implementation details or reasoning.
design/*¶
Design docs for people who want to get a better understanding of how/why core is built the way it is. This should discuss internal implementation details of the various services, what tradeoffs were made, and the reasoning behind the final decision. Should be useful for people who want to contribute and for communication b/w core devs.
about/*¶
More detailed/meta/background information about the project (history, roadmap, contributing, etc.)
Use “Elgg” in a grammatically correct way¶
Elgg is not an acronym, so writing it in all caps (ELGG or E-LGG) is incorrect. Please don’t do this.
- In English, Elgg does not take an article when used as a noun. Here are some examples to emulate:
- “I’m using Elgg to run my website”
- “Install Elgg to get your community online”
- When used as an adjective, the article applies to the main noun, so you should use one. For example:
- “Go to the Elgg community website to get help.”
- “I built an Elgg-based network yesterday”
This advice may not apply in languages other than English.
Avoid first person pronouns¶
Refer to the reader as “you.” Do not include yourself in the normal narrative.
Before:
When we’re done installing Elgg, we’ll look for some plugins!
After:
When you’re done installing Elgg, look for some plugins!
To refer to yourself (avoid this if possible), use your name and write in the third person. This clarifies to future readers/editors whose opinions are being expressed.
Before:
I think the best way to do X is to use Y.
After:
Evan thinks the best way to do X is to use Y.
Eliminate fluff¶
Before:
If you want to use a third-party javascript library within the Elgg framework, you should take care to call the elgg_register_js function to register it.
After:
To use a third-party javascript library, call elgg_register_js to register it.
Do not remind the reader to contribute¶
Focus on addressing the topic at hand. Do not solicit bug fixes. If they want to contribute to the project, they will come to this section to learn how. Our users don’t want to be constantly reminded how needy we feel.
Prefer absolute dates over relative ones¶
It is not easy to tell when a particular sentence or paragraph was written, so relative dates quickly become meaningless. Absolute dates also give the reader a good indication of whether a project has been abandoned, or whether some advice might be out of date.
Before:
Recently the foo was barred. Soon, the baz will be barred too.
After:
Recently (as of September 2013), the foo was barred. The baz is expected to be barred by October 2013.
Become a supporter¶
Benefits¶
For only $50 per year for individuals or $150 per year for organizations, you can get listed as a supporter on our supporters page. Elgg supporters are listed there unless they request not to be.
All funds raised via the Elgg supporters network go directly into core Elgg development and infrastructure provision (elgg.org, github, etc.). It is a great way to help with Elgg development!
Supporters are able to put this official logo on their site if they wish:

Disclaimer¶
We operate a no refund policy on supporter subscriptions. If you would like to withdraw your support, go to PayPal and cancel your subscription. You will not be billed the following year.
Being an Elgg Supporter does not give an individual or organization the right to impersonate, trade as or imply they are connected to the Elgg project. They can, however, mention that they support the Elgg project.
If you have any questions about this disclaimer, email info@elgg.org.
We reserve the right to remove or refuse a listing without any prior warning at our complete discretion. There is no refund policy.
If there is no obvious use of Elgg, your site will be linked to with “nofollow” set.
Sign up¶
If you would like to become an Elgg supporter:
- read the disclaimer above
- on the supporters page, subscribe via PayPal
- send an email to info@elgg.org with:
- the date you subscribed
- your name (and organization name, if applicable)
- your website
- your Elgg community profile
Once all the details have been received, we will add you to the appropriate list. Thanks for your support!
History¶
Elgg’s initial funding was by a company called Curverider Ltd, which was started by David Tosh and Ben Werdmuller. In 2010, Curverider was acquired by Thematic Networks and control of the open-source project was turned over to The Elgg Foundation. Today, Elgg is a community-driven open source project and has a variety of contributors and sponsors.