Warning: You are browsing the documentation for PrestaShop 1.7, which is outdated.
You might want to look at the current version, PrestaShop 8. Read the updated version of the documentation
First of all, the submitted addon must pass the validator. Some reports will lead to an automatic decline if found. The following rules are manually checked by the modules team.
The module respected the expected structure.
A module and its dependencies must be compatible with the OSL (core) and AFL (modules and themes) licenses used to manage and distribute the PrestaShop open source project. Compatible licences are:
Additionally, distribution licenses like CC-0 or CC-by-sa are appropriate for artwork (e.g: icons, pictures, fonts, but not only)
Module may create all the table they need in the database. However altering core table is forbidden.
In case you wanted to add columns for an existing table, the workaround is to create a new table with a foreign key targetting the primary key of the core table.
Modifying core or other modules files is not allowed.
Module may add / modify some files on the shop. To avoid issues with file permissions, we recommend storing files in the var/%env%
directory.
The use of iframes is highly discouraged for security reasons, although they are implemented in different part of the core like in Payment Modules.
Using an iframe authorizes to load content from a site that is not controlled by the PrestaShop app. This is the same problem as authorizing to load javascript files from an external source. If the source is being hacked, the attacker could potentially exploit other failures to take control of all the shops that would have installed the module.
Therefore we need to check what your processes are, to ensure the security of the content that will be injected by this iframe into all the shops that will install the module. When submitting your module, the validation team will review the reasons why an iFrame is needed for this business and what are the measures taken by the provider to prevent attacks.
The zip you send to PrestaShop Addons must be totally self-sufficient.
All the content needed by the module to work properly must be present in the archive. No external content should be downloaded by the module after installation.
When a module is published on the marketplace, we provide a unique way for all customer to get new updates and to contact the maintainer of the different modules & themes they bought.
Inserting links to an external platform would probably make things easier for a seller, but it would prevent us to help customers and/or seller in case of dispute.
We examine every SQL request to make sure you did cast your variables. Use (int)
for integers and pSQL()
for strings.
More details:
If you have PHP files to handle ajax or external calls, make sure to secure that file. To do so, create a unique token during the module’s installation and use it during the call verification.
Using serialize()
/ unserialize()
is forbidden, as they are a security risk if you do not control the data going through these methods. They may lead to remote code execution, so we recommend using json_encode()
/ json_decode()
instead.
Module included in another one are difficult to review & can’t have their own release process.
Each module has to be uploaded on the marketplace separately, even if they only work together.
index.php
exists in each folderTo prevent someone to reach the content of a repository without, a file index.php
has to be found in each folder.
As we deal with a security risk on some environments, we strongly recommend you comply with this rule. An “autoindex” tool allows you to add in each folder.
Use Smarty / Twig templates to display HTML code to respect PrestaShop patterns (MVC architecture) and build a code easy to maintain.
PrestaShop provides a e-commerce software ready use in many languages. The code and displayed texts are written in English, then translated if the user switches to another language.
Like for PrestaShop, the code submitted on the marketplace has to be written in English, even if the only user of this code is likely to from only one country or language. A lang unknown by the reviewer would make the validation impossible to do.
Configuration data is shared between the shop and every module installed. This is convenient if your need to get a value from another part of the shop, but include some risks if two modules stores some data in the same key.
Too avoid conflicts, configuration keys must be prefixed by the module name. For instance, using a configuration key in the module TheModule
would be:
<?php
Configuration::get('THE_MODULE_PAYMENT_METHODS_ORDER');
Configuration::updateValue('THE_MODULE_PAYMENT_METHODS_ORDER', [...]);
instead of
<?php
Configuration::get('PAYMENT_METHODS_ORDER');
Configuration::updateValue('PAYMENT_METHODS_ORDER', [...]);
This also applies to classes defined outside a namespace. Having the module name as a prefix will reduce the risk of colision between classes.
All the AJAX and CRON files must be protected with a unique and secured token to avoid any security issues (outside attacks,…). Even the front controllers must be secured with a secured token when you use AJAX in it.
AJAX and CRON scripts must be placed in a controller and not in a separate script to call on its own. For more details:
Several hooks are called on all pages of the back-office or front-office. When a module is registered on one of them, it may impact the page performance on low-end servers if it runs too much code.
We ask to keep the code running in your hooks light, and filter the pages you module runs on if necessary.
Examples:
<?php
/**
* Hook executed at the order confirmation
*/
public function hookOrderConfirmation($params)
{
# If created by another module, return.
if ($params['order']->module !== $this->name) {
return false;
}
// [...]
}
<?php
/**
* Display content ONLY in the admin payment controller
*/
public function hookDisplayAdminAfterHeader()
{
$currentController = $this->context->controller->controller_name;
if ('AdminPayment' !== $currentController) {
return false;
}
// [...]
// return $this->display(...)
}
All the debug tests have to be removed.
Example : var_dump($a)
, dump($a)
, console.log(‘a’)
…
To have a code easier to maintain / review, you must remove the commented lines of code. Code comments are welcome of course!
Commented code to be removed:
<?php
public function hookPaymentOptions($params)
{
// if (false === $this->active) { // <-- never called, to be removed
// return false;
// }
if (false === $this->merchantIsValid()) {
return false;
}
// if (false === $this->checkCurrency($params['cart'])) // {
// return false;
// }
// if (false === $this->isPaymentStep()) {
// return false;
// }
// [...]
return $payment_options;
}
Encouraged code comments:
<?php
/**
* Add payment option at the checkout in the front office
*
* @param array $params return by the hook
*
* @return array|false all payment option available
*/
public function hookPaymentOptions($params)
{
// [...]
return $payment_options;
}
As they have no consequences in the module execution, empty files can be removed before submission. Generated files such as log files, invoice or other documents in PDFs etc. should be removed as well, as they:
Documentation is found in the docs/
folder of the module, and in a format widly used (PDF is recommended, avoid ZIP files which need an additional process of extraction).
A module must be tested on a Prestashop with debug mode enabled in order to spot the slightest mistake. Validation teams always have this mode enabled and if an alert is raised then the module will be rejected.
On production mode, only PHP errors will be detected as they prevent the page to be fully executed. On development mode, all other levels of messages such as notices & warnings are triggered.
We do have extra rules for Payment Modules as this type of modules require higher security. Note that there are some modules which create the Order with a pending order status during the payment processing (1), while others wait for the payment system’s approval to create it (2). But none of them create an order before the customer passed the payment service (bank, PayPal…).
Make sure you double check the id_cart before creating the order.
if (2), make sure the amount you use to validateOrder() comes from the external payment system. Do not use Cart->getOrderTotal();
For (2), when receiving a call to process the payment, make sure you double check the source of the call using a signature or a token. Those values must not be known of all.