x

Main chapters

  1. LimeSurvey Cloud vs LimeSurvey CE
  2. LimeSurvey Cloud - Quick start guide
  3. LimeSurvey CE - Installation
  4. How to design a good survey (Guide)
  5. Getting started
  6. LimeSurvey configuration
  7. Introduction - Surveys
  8. View survey settings
  9. View survey menu
  10. View survey structure
  11. Introduction - Questions
  12. Introduction - Question Groups
  13. Introduction - Surveys - Management
  14. Survey toolbar options
  15. Multilingual survey
  16. Quick start guide - ExpressionScript
  17. Advanced features
  18. General FAQ
  19. Troubleshooting
  20. Workarounds
  21. License
  22. Version change log
  23. Plugins - Advanced
 Actions

Coding guidelines

From LimeSurvey Manual

General

This is a free development, everything you do can be useful for others. If the feature is very personal there is a way to turn it into a universal solution. This is the challenge!

"The difficulty within a solution is to solve it in a simple way" (Lance Burton, magician)

Some general rules:

  • Be efficient and save resources (memory and runtime). Things might work for a small survey but also try out your new feature with a survey that has 400 question, 5 languages and 20,000 responses (Yes, there are surveys like this out there).
  • Keep a fluid dialog with the others coders, they have their own thoughts about what you are doing.
  • Ask if you are in doubt.

Documentation

Please document your source code - see this introduction: How to document your source code.

Coding Standards and MVC Architecture in LimeSurvey Development

LimeSurvey is built on the Yii framework, which provides the foundation for its Model-View-Controller (MVC) structure. Yii has its own conventions and tools that influence how models, views, and controllers are implemented. While some areas of the LimeSurvey codebase predate the adoption of Yii or use older approaches, new development should always align with Yii’s MVC principles and the guidelines described below.

As you probably know it is an open-source survey platform with contributions from developers around the world. Like many long-lived open-source projects, its codebase has evolved over time, and you may encounter different approaches to structuring the code. Some older parts of the system may not follow modern best practices or the Model-View-Controller (MVC) architecture as strictly as newer code.

While this variety reflects the project’s history, new development should follow the current standards. Staying focused on the recommended guidelines helps keep LimeSurvey maintainable, testable, and easier to extend in the future—without being distracted by legacy approaches.

Understanding MVC in LimeSurvey

The MVC pattern divides an application into three interconnected layers, each with a clear responsibility:

  • Models – Represent the data and contain business rules related to that data. Models handle database interactions, validations, and data transformations.
  • Views – Manage the presentation layer. They are responsible for displaying information to the user and should not contain business logic.
  • Controllers – Act as intermediaries, handling incoming requests, coordinating with models, and choosing the correct views to render.

By keeping these responsibilities separate, developers can more easily test, extend, and debug their code.

Where Business Logic Belongs

One of the most common pitfalls in MVC development is misplacing business logic. In LimeSurvey development, the recommended approach is:

  • Models: Store business rules and perform operations directly related to the data, such as validations and relationships.
  • Service Classes: Handle more complex operations that span across multiple models or involve higher-level application logic. For example see: \LimeSurvey\Models\Services\QuestionAggregateService

Controllers should remain as thin as possible. Their main role is to receive requests, pass data to the appropriate services or models, and return responses via the correct views.

Best Practices for Clean Code

To keep your LimeSurvey contributions maintainable and consistent with the project’s standards, follow these practices:

  • Keep controllers lightweight – They should primarily manage request/response flow and delegate logic to models or services.
  • Move complex logic into service classes – If a piece of functionality requires multiple steps or involves multiple models, encapsulate it in a dedicated service.
  • Use models for data operations – Models should clearly represent data structures and provide methods for interacting with the database.
  • Keep views presentation-only – Views should focus on displaying data. They should not contain calculations, validations, or business rules.
  • Apply dependency injection – This improves testability and flexibility by avoiding hard-coded dependencies.

Twig Templates in LimeSurvey

LimeSurvey uses the Twig templating engine for rendering much of the survey-taking interface. Twig provides a clean separation between logic and presentation, making it easier to customize themes and maintain a consistent look and feel across surveys.

What is Twig?

Twig is a fast, secure, and flexible templating language for PHP. It allows developers and theme designers to write templates that are easy to read and extend, without mixing in raw PHP code.

Where LimeSurvey Uses Twig

Twig is primarily used in the survey-taking portion of LimeSurvey:

  • Survey themes – Layout, structure, and style of the survey pages
  • Question rendering – How individual questions and groups are displayed
  • Template overrides – Custom themes can override core Twig templates for tailored designs

Best Practices for Twig in LimeSurvey

When working with Twig templates in LimeSurvey, follow these guidelines:

  • Keep logic out of templates – Use Twig for presentation only, not business rules
  • Test in multiple themes – Ensure your changes work across different devices and survey layouts

Developer Tips

  • Default Twig templates for survey-taking are located in the `application/views/survey/` and theme directories.
  • Custom survey themes should include a `twig` folder for template overrides.
  • Always clear LimeSurvey’s cache after making changes to Twig files to see updates.
  • Review the official Twig documentation for the full syntax and feature set.

JavaScript Packages in LimeSurvey

LimeSurvey includes several JavaScript packages that provide functionality for the administration interface as well as the survey-taking environment. These packages are organized under the `assets/packages/` directory and are built to keep front-end code modular, maintainable, and consistent.

Overview

JavaScript in LimeSurvey is mostly organized into packages that can include:

  • JavaScript source files
  • Stylesheets (CSS/SCSS)
  • Build configuration (Webpack, npm/yarn dependencies)

When developing new js this package approach should be followed. This ensures that front-end code can be bundled, minified, and versioned properly, while avoiding duplication and conflicts.

Building JavaScript Packages

When a new feature requires JavaScript functionality, it is typically developed inside a dedicated package folder under `assets/packages/`. Each package can define:

  • An `src/` directory for source files
  • A `dist/` or `build/` output for the compiled files
  • Dependencies declared in `package.json`

The build system (commonly Webpack or a similar bundler) compiles modern JavaScript (ES6+) and frameworks like Vue into browser-ready files. These are then registered in LimeSurvey’s asset manager to be loaded when needed.

Example: adminbasics

The package `assets/packages/adminbasics` contains JavaScript and styles used across the LimeSurvey administration interface.

Typical functionality includes:

  • General UI helpers
  • Event handlers for common actions in the admin panel

This package acts as a foundation layer for other admin UI features.

The dependencies for adminbasics package need to be installed with the command yarn.

There are the following commands available:

  • dev to build a non minified version of the assets with rollup
  • prod to build a minified version of the assets with rollup
  • build to build a non minified and a minified version of the assets with rollup in one step
  • test to run the test cases

Example: adminsidepanel (Vue.js)

The package `assets/packages/adminsidepanel` provides the code for the collapsible side panel in the administration interface. Unlike other parts of LimeSurvey, this package is built with the Vue.js framework.

Key points:

  • The side panel is a Vue single-page component embedded into the admin UI
  • Vue allows the panel to be reactive, updating its content dynamically without reloading the whole page
  • The build process compiles `.vue` files and JavaScript modules into a single bundle served by LimeSurvey

For building this package, you need to have node version 14 installed (not higher!) The dependencies for adminsidepanel package need to be installed with the command yarn.

There are the following commands:

   * serve to run the component with hot-reloading (all changes are visible without compiling again)
   * build to build a non minified and a minified version of the assets in one step
   * prod to build a minified version of the assets
   * dev to build a minified version of the assets with the development mode

Best Practices for Developing New Packages

When adding or updating JavaScript functionality in LimeSurvey:

  • Place your code inside a new or existing `assets/packages/` folder
  • Keep code modular and organized under `src/`
  • Use the build system (npm/yarn + Webpack) to compile assets into distributable bundles
  • Avoid inline JavaScript in views whenever possible
  • For complex interactive features, consider using modern frameworks like Vue (as with `adminsidepanel`)

Bootstrap 5 and Gulp Build System in LimeSurvey Themes

LimeSurvey has upgraded to Bootstrap 5 for both its administration and survey themes. This modern framework enhances consistency, responsiveness, and maintainability across the UI.

To manage and generate theme-specific stylesheets and scripts, LimeSurvey uses a Gulp build system — defined in a `gulpfile.js` — that handles CSS/JS compilation, theme variations, and RTL support.

Gulp Tasks Overview

The `gulpfile.js` orchestrates four main build areas:

  1. Bootstrap 5 Assets – Compiles and minifies Bootstrap 5 JavaScript and SCSS files. Outputs both standard and RTL (Right-to-Left) versions.

Commands

  • `gulp build` – Builds all Bootstrap 5 assets
  • `gulp watch` – Watches for changes and rebuilds automatically
  1. Admin Theme ("Sea Green") – Processes SCSS files of the admin theme into CSS.

Commands:

  • `gulp build_theme` – Builds the admin theme
  • `gulp watch_theme` – Watches for changes in admin theme files
  1. Fruity Survey Theme (Legacy) – Generates multiple color variations of the original Fruity survey theme.

Commands:

  • `gulp build_survey_theme_fruity` – Builds all Fruity theme variations
  • `gulp watch_survey_theme_fruity` – Watches for changes to Fruity theme files
  1. LS6 Survey Theme ("Fruity TwentyThree") – Builds the newer LS6 survey theme (Fruity TwentyThree) along with its variations, including JavaScript processing.

Commands:

  • `gulp build_survey_theme_ls6` – Builds all LS6 theme assets
  • `gulp watch_survey_theme_ls6` – Watches for changes to LS6 theme files

SCSS File Locations & Component-Based Structure

SCSS files in LimeSurvey are organized to keep styling modular and maintainable.

  • Admin Theme – Sea Green
 Located under:  
 `assets/admin_themes/Sea_Green/`  
 This directory contains SCSS source files arranged in components (e.g., `_variables.scss`, `_buttons.scss`, `_layout.scss`) and a main entry point SCSS file that brings them together for compilation.
  • Survey Theme – Fruity TwentyThree (LS6)
 Located under:  
 `assets/survey_themes/fruity_twentythree/`  
 SCSS files here are similarly split into component files (e.g., typography, colors, forms), along with CSS or JS files as needed. The main SCSS file imports these components and is picked up by the Gulp task for building.

This component-based approach allows for easier styling, overrides, and theme variation without duplicating code.

Why This Matters

Using Bootstrap 5 along with Gulp-driven build automation ensures:

  • Consistent and responsive design across admin and survey interfaces.
  • Streamlined workflows for theme development and maintenance.
  • Flexibility to generate color variations and handle RTL languages cleanly.
  • Easier updates to design components — change one SCSS component, rebuild, and it's applied globally.

How to Contribute or Customize

1. Navigate to the relevant theme folder (e.g. `assets/admin_themes/Sea_Green/` or `assets/survey_themes/fruity_twentythree/`). 2. Modify or add SCSS components as needed. 3. Run one of the Gulp build commands above to compile:

  * For example:  
    ```bash
    gulp build_survey_theme_ls6
    ```

4. Clear LimeSurvey’s asset cache (from the admin interface or manually) to see your changes live in the UI.

Important: when you have to define sizes (fonts, margins, paddings, etc), use the variables we defined in the ...variables.scss (e.g.: assets/admin_themes/Sea_Green/sea_green_variables.scss) file.

HTML

  • As you will notice, a very customized HTML element can take a lot of lines (very expensive if you paid each one (:wink:) ) to avoid that, use 'CSS classes'. In general, use classes to aesthetic related stuff: color, borders, backgrounds, font faces, sizes, etc.
  • Respect W3C standards, and try to use the HTML understandable for all browsers. If one of them has a special feature, think if this feature is so special to break down the HTML in other browsers.
  • Do not use PHP short tags <? ?>. Always use full PHP tags <?php ?>. Excluded from this is the echo shorthand <?=. Which is allowed as per PSR standard.
  • Any rules of the mentioned before: about CSS, well closed HTML tags and JS respect XHTML standards. Give it a try!.

Localization

Moved to https://manual.limesurvey.org/Code_quality_guide#Localization

Bug tracker

  1. First consider if the reported issue is really a bug. If it is a feature request please move it to the feature tracker.
  2. If you would like to work on a bug assign it to yourself.
  3. Try to reproduce the issue.
    1. If you cannot reproduce ask the user to provide a small example survey to demonstrate the issue. Then set the issue to 'Feedback'. After the user added the necessary information it will automatically be set to 'Assigned' again.
    2. If the user does not responds for more than a week ask once again for feedback by adding a comment. After a further week without feedback close the issue.
  4. After you resolved the issue set the status to resolved AND provide the 'Fixed in version' information.
  5. After you committed a fix and use the proper GIt commit message naming the commit will be automatically assigned to your bug report.
  6. After a release the release technician will set all issues to 'Closed' that were fixed for this release. That signals to the reporter that a fix is available in the version and it was just released. The release technicial will also add a comment to the close issue: 'Fixed in <Version> <Build number>'

Cross-DB compatibility

LimeSurvey targets several database types it can run on: MySQL, Postgres and Microsoft SQL Server. This demands certain precautions when coding

Parameter binding

Yii/PDO supports parameter binding - use it. Don't inject variables directly into the query or into conditions because this might create a security issue.

Example:

<?php
$oResult = Yii::app()->db
                    ->createCommand()
                    ->select('somefield')
                    ->where("sid = :sid")
                    ->from('{{sometable}}')
                    ->bindParam(":sid", $surveyid, PDO::PARAM_INT);
?>

If you bind the same value several times do NOT use the same parameter name, instead use a different named parameter for each bind:

WRONG:

<?php
$oResult = Yii::app()->db
                    ->createCommand()
                    ->select('somefield')
                    ->where("sid = :sid and parent_sid= :sid ")
                    ->from('{{sometable}}')
                    ->bindParam(":sid", $surveyid, PDO::PARAM_INT);
?>

RIGHT:

<?php
$oResult = Yii::app()->db
                    ->createCommand()
                    ->select('somefield')
                    ->where("sid = :sid1 and parent_sid= :sid2 ")
                    ->from('{{sometable}}')
                    ->bindParam(":sid1", $surveyid, PDO::PARAM_INT)
                    ->bindParam(":sid2", $surveyid, PDO::PARAM_INT);
?>


Quote column name

Some column name must be quoted for DB compatibility. You can use App()->db->quoteColumnName.

Know column needed to be quoted :

  • Column name statring with number( column in survey database)
  • Reserved key word column name

Code complexity

  • If using an auxiliary variable makes clear the code or process, just do it. If you are coding a very complex expression, calling to functions with parameters that are other functions:
WRONG:

iAResult= fa(fb(p1,p2),fc(fd(p3),p4),p5)

It will be more readable:

iAuxB = fb(p1,p2)
iAuxD = fd(p3)
iAuxC = fc(iAuxD,p4)
iAResult = fa(iAuxB, iAuxC, p5)

Anyway, if you are in doubt about someone missing the point or you are afraid that your expression is obscure, take the chance of writing it in a more simple way, even if that involves the use of one or more auxiliary variables.

Checklist for new features

If you implement a new feature please make sure that you checked the following things before you create a pull request/commit your new feature:

  • Localization: Do all texts (that are usually visible to the user) use the localization/translation system (gT, eT, etc.)?
  • Permissions: Does the feature obey the permission system (global permissions, survey permissions)?
  • Backward-compatibility: Does the feature still work when updating from any old version? Does it maybe break the update?
  • Database compatibility: Does it work on all database types (MySQL, MSSQL, Postgres)?
  • Scaling: Does your feature scale? For example; It will work fine with 10 surveys, does it still work performant with 10000?
  • Performance: Does your feature use the minimal possible number of SQL queries (see also Scaling).
  • QA: Did you test your code for all scenarios? Did you let someone else test or read your code?
  • Acceptance tests: Did you write automatic acceptance tests for your specification?
  • Discussions: Did you discuss the new feature with the team for feedback?

Also see How_to_contribute_new_features.