# Table of Contents - [PrestaShop 8 Documentation :: PrestaShop Developer Documentation](#prestashop-8-documentation-prestashop-developer-documentation) - [Introduction :: PrestaShop Developer Documentation](#introduction-prestashop-developer-documentation) - [Interacting with APIs :: PrestaShop Developer Documentation](#interacting-with-apis-prestashop-developer-documentation) - [Getting Started :: PrestaShop Developer Documentation](#getting-started-prestashop-developer-documentation) - [Extension concepts :: PrestaShop Developer Documentation](#extension-concepts-prestashop-developer-documentation) - [Shops configuration :: PrestaShop Developer Documentation](#shops-configuration-prestashop-developer-documentation) - [Configuration forms :: PrestaShop Developer Documentation](#configuration-forms-prestashop-developer-documentation) - [Shops context :: PrestaShop Developer Documentation](#shops-context-prestashop-developer-documentation) - [Adding a configuration page (Legacy architecture) :: PrestaShop Developer Documentation](#adding-a-configuration-page-legacy-architecture-prestashop-developer-documentation) - [Testing :: PrestaShop Developer Documentation](#testing-prestashop-developer-documentation) - [Modern configuration page :: PrestaShop Developer Documentation](#modern-configuration-page-prestashop-developer-documentation) - [Asset management :: PrestaShop Developer Documentation](#asset-management-prestashop-developer-documentation) - [How to add a layout in a theme from a module :: PrestaShop Developer Documentation](#how-to-add-a-layout-in-a-theme-from-a-module-prestashop-developer-documentation) - [Webpack :: PrestaShop Developer Documentation](#webpack-prestashop-developer-documentation) - [Changes in PrestaShop 8.1 :: PrestaShop Developer Documentation](#changes-in-prestashop-8-1-prestashop-developer-documentation) - [Theme development reference :: PrestaShop Developer Documentation](#theme-development-reference-prestashop-developer-documentation) - [New password policy based on zxcvbn :: PrestaShop Developer Documentation](#new-password-policy-based-on-zxcvbn-prestashop-developer-documentation) - [How to add an email theme from a module :: PrestaShop Developer Documentation](#how-to-add-an-email-theme-from-a-module-prestashop-developer-documentation) - [How to add layout variables from a module :: PrestaShop Developer Documentation](#how-to-add-layout-variables-from-a-module-prestashop-developer-documentation) - [Email Protection | Cloudflare](#email-protection-cloudflare) - [Optimize your Apache httpd configuration :: PrestaShop Developer Documentation](#optimize-your-apache-httpd-configuration-prestashop-developer-documentation) - [The Hook component :: PrestaShop Developer Documentation](#the-hook-component-prestashop-developer-documentation) - [Frequently Asked Questions :: PrestaShop Developer Documentation](#frequently-asked-questions-prestashop-developer-documentation) - [Tutorials :: PrestaShop Developer Documentation](#tutorials-prestashop-developer-documentation) - [Internationalization :: PrestaShop Developer Documentation](#internationalization-prestashop-developer-documentation) - [Writing a good commit message :: PrestaShop Developer Documentation](#writing-a-good-commit-message-prestashop-developer-documentation) --- # PrestaShop 8 Documentation :: PrestaShop Developer Documentation [Improve this page](https://github.com/PrestaShop/docs/edit/8.x/_index.md "Improve this page") [How](https://devdocs.prestashop-project.org/9/contribute/documentation/how) **Warning:** You are browsing the documentation for PrestaShop 8, which is outdated. You might want to read an updated version of this page for the current version, PrestaShop 9. [Read the updated version of this page](https://devdocs.prestashop-project.org/9/) [Learn how to update to the latest version.](https://devdocs.prestashop-project.org/9/basics/keeping-up-to-date/update) PrestaShop 8 Documentation[](https://devdocs.prestashop-project.org/8/#prestashop-8-documentation) =================================================================================================== * [Basics](https://devdocs.prestashop-project.org/8/basics/) * [Core Development Reference](https://devdocs.prestashop-project.org/8/development/) * [Testing](https://devdocs.prestashop-project.org/8/testing/) * [PrestaShop modules](https://devdocs.prestashop-project.org/8/modules/) * [Themes](https://devdocs.prestashop-project.org/8/themes/) * [The PrestaShop Webservice API](https://devdocs.prestashop-project.org/8/webservice/) * [Contribute](https://devdocs.prestashop-project.org/8/contribute/) * [Scale](https://devdocs.prestashop-project.org/8/scale/) * [The PrestaShop Project](https://devdocs.prestashop-project.org/8/project/) * [Frequently Asked Questions](https://devdocs.prestashop-project.org/8/faq/) [Next: Basics ›](https://devdocs.prestashop-project.org/8/basics/ "Basics") --- # Introduction :: PrestaShop Developer Documentation [Improve this page](https://github.com/PrestaShop/docs/edit/9.x/basics/introduction.md "Improve this page") [How](https://devdocs.prestashop-project.org/9/contribute/documentation/how) Table of Contents [Next article](https://devdocs.prestashop-project.org/9/basics/installation/ "Installation") Fundamentals of PrestaShop Development[](https://devdocs.prestashop-project.org/9/basics/introduction/#fundamentals-of-prestashop-development) =============================================================================================================================================== PrestaShop was conceived so that third-party modules could easily build upon its foundations, making it an extremely customizable e-commerce software. PrestaShop’s customization is based on four possibilities: * Themes, * Modules, * Hooks, * Overriding. Themes are explored in full in the [Themes](https://devdocs.prestashop-project.org/9/themes/) section. Modules, hooks and the override system are explored in this page and in the [Modules](https://devdocs.prestashop-project.org/9/modules/) section. By default, PrestaShop is provided with more than 50 modules, enabling you to launch your online business quickly and for free. Concepts[](https://devdocs.prestashop-project.org/9/basics/introduction/#concepts) ----------------------------------------------------------------------------------- You should be familiar with PHP and Object-Oriented Programming before attempting to write your own module. You can learn PHP here: * [Getting started on PHP documentation](https://www.php.net/manual/en/getting-started.php) * [Learning PHP on CodeCademy](https://www.codecademy.com/catalog/language/php) You can learn Object-Oriented programming here: * [Object-oriented programming on Wikipedia](https://en.wikipedia.org/wiki/Object-oriented_programming) * [Object oriented php for beginners on Tuts+](https://net.tutsplus.com/tutorials/php/object-oriented-php-for-beginners/) A module is an extension to PrestaShop that enables any developer to add the following: * Provide additional functionality to PrestaShop. * View additional items on the site (product selection, etc.). * Communicate with other e-commerce services (buying guides, payment platforms, logistics, etc.). Overriding is a system in itself. PrestaShop uses completely object-oriented code. One of the advantages of this is that, with the right code architecture, you can easily replace or extend parts of the core code with your own custom code, without having to touch the core code. Your code thus overrides the core code, making PrestaShop behave as you prefer it to. It is however not recommended to use an override in a module that you intend to distribute (for instance through the PrestaShop Addons marketplace), and they are forbidden in partner modules. Keep them for your own shop. PrestaShop’s technical architecture[](https://devdocs.prestashop-project.org/9/basics/introduction/#prestashops-technical-architecture) ---------------------------------------------------------------------------------------------------------------------------------------- MVC as the root[](https://devdocs.prestashop-project.org/9/basics/introduction/#mvc-as-the-root) ------------------------------------------------------------------------------------------------- Until PrestaShop 1.6, PrestaShop was based on a 3-tier architecture: * Object/data. Database access is controlled through files in the “classes” folder. * Data control. User-provided content is controlled by files in the root folder. * Design. All of the theme’s files are in the “themes” folder. This is the same principle as the [Model>View>Controller (MVC) architecture](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) , only in a simpler and more accessible way. A 3-tier architecture has many advantages: * It’s easier to read the software’s code. * Developers can add and edit code faster. * Graphic designer and HTML integrators can work with the confines of the `/themes` folder without having to understand or even read a single line of PHP code. * Developers can work on additional data and modules that the HTML integrators can make use of. #### Model[](https://devdocs.prestashop-project.org/9/basics/introduction/#model) A model represents the application’s behavior: data processing, database interaction, etc. It describes or contains the data that have been processed by the application. It manages this data and guarantees its integrity. #### View[](https://devdocs.prestashop-project.org/9/basics/introduction/#view) A view is the interface with which the user interacts. Its first role is to display the data that has been provided by the model. Its second role is to handle all the actions from the user (mouse click, element selection, buttons, etc.), and send these events to the controller. The view does not do any processing; it only displays the result of the processing performed by the model, and interacts with the user. #### Controller[](https://devdocs.prestashop-project.org/9/basics/introduction/#controller) The Controller manages synchronization events between the Model and the View, and updates both as needed. It receives all the user events and triggers the actions to perform. If an action requires the modification of data, the Controller “asks” the Model to modify the data and, in return, the Model informs the View that the data has been changed, so that the View can update itself. Moving forward with Symfony[](https://devdocs.prestashop-project.org/9/basics/introduction/#moving-forward-with-symfony) ------------------------------------------------------------------------------------------------------------------------- While all versions of PrestaShop up to 1.6 took pride in only using a custom architecture, it was decided to incorporate the [Symfony PHP framework](https://symfony.com/) starting with PrestaShop 1.7. The driving idea is that we want our code to be more robust, more modular, and fully testable. The 1.6 architecture, inherited from version 1.5 and years of PrestaShop development, is not getting any younger, and its age is really starting to show. Using a proven and popular open-source framework will allow us to focus on our core business code (managing a cart, handling orders, calculating prices and taxes, generating invoices, etc.) with greater efficiency, while enjoying the stability of a globally recognized framework. In the documentation, we will refer to the 1.6 framework as the “legacy” framework, as this is a popular [designation](https://en.wikipedia.org/wiki/Legacy_system) used in the software world. How it is built inside[](https://devdocs.prestashop-project.org/9/basics/introduction/#how-it-is-built-inside) --------------------------------------------------------------------------------------------------------------- Here is a small guide to help you navigate the software. ### Front office MVC[](https://devdocs.prestashop-project.org/9/basics/introduction/#front-office-mvc) The Front Office is an application being powered by PHP and Smarty. The frontend relies on controllers you can find in the directory `controllers/front` and PrestaShop classes that contain the business logic, mainly from the `classes` folder. The views and the Javascript come from the installed theme that you will find in `themes/`. You can have multiple themes available on a shop but only one is enabled and in use. If the Multistore feature is enabled, each shop can use a different theme. ### Visit a Front controller[](https://devdocs.prestashop-project.org/9/basics/introduction/#visit-a-front-controller) When you visit `/` on your shop, you are being returned to the Homepage. The HTTP request you sent was received by the _Dispatcher_ which found the right Front controller (the `IndexController` for Homepage). This `IndexController` returned an HTTP response containing an HTML document rendered by Smarty. Back office MVC[](https://devdocs.prestashop-project.org/9/basics/introduction/#back-office-mvc) ------------------------------------------------------------------------------------------------- The Back Office is a large application powered by PHP and Smarty for the legacy part and by PHP, Symfony, and Twig for the migrated part. The legacy backend relies on controllers which you can find in the directory `controllers/admin`. It also relies on PrestaShop classes that contain the business logic, mainly from the `classes` folder. For legacy pages, the views and the Javascript can be found in `admin-dev/themes/default`. The Symfony backend relies on the controllers you can find in `src/PrestaShopBundle/Controller/Admin` and PrestaShop logic that mostly comes from the `src` folder, and also some `classes` files. For migrated pages, you can find the views in `src/PrestaShopBundle/Resources/views/Admin`. The Javascript can be found in `admin-dev/themes/new-theme/js`. ### Visit a legacy Back Office controller[](https://devdocs.prestashop-project.org/9/basics/introduction/#visit-a-legacy-back-office-controller) When you visit `/admin{x}/index.php?controller=AdminCarriers&token={y}` on your shop, you are being returned to the Carriers Back Office page. The HTTP request you sent was received by the Back Office _Dispatcher_ which found the right Admin controller (the `AdminCarriersController`). This `AdminCarriersController` returned an HTTP response containing an HTML document rendered by Smarty. The Admin controllers use a generic system to choose what Smarty template to use. Generic templates to display forms and listings are available and the controller provides the structure configuration (for example it controls what columns and rows are displayed). ### Visit a Symfony Back Office controller[](https://devdocs.prestashop-project.org/9/basics/introduction/#visit-a-symfony-back-office-controller) When you visit `/admin-{xxx}/index.php/configure/shop/preferences/preferences?_token={yyy}` on your shop, you are being returned to the Preferences Back Office page. The HTTP request you sent was received by Symfony and the kernel that handled your request. Symfony found the right Back Office controller, matching your URL, the `PreferencesController`. The `PreferencesController` returned an HTTP response containing an HTML document rendered by Twig. --- # Interacting with APIs :: PrestaShop Developer Documentation [Improve this page](https://github.com/PrestaShop/docs/edit/1.7.x/modules/creation/external-services.md "Improve this page") [How](https://devdocs.prestashop-project.org/9/contribute/documentation/how) Table of Contents [Next article](https://devdocs.prestashop-project.org/1.7/modules/concepts/ "Extension concepts") **Warning:** You are browsing the documentation for PrestaShop 1.7, which is outdated. You might want to read an updated version of this page for the current version, PrestaShop 9. [Read the updated version of this page](https://devdocs.prestashop-project.org/9/modules/creation/external-services/) [Learn how to update to the latest version.](https://devdocs.prestashop-project.org/9/basics/keeping-up-to-date/update) Interacting with APIs[](https://devdocs.prestashop-project.org/1.7/modules/creation/external-services/#interacting-with-apis) ============================================================================================================================== There are different options to transfer data between your shop and any external service. The method you choose will depend on the usecase: * if data must be pulled or pushed to the shop, * if one specific application (the shop or an external service) must initiate the calls, * if there are constraints on the implementation (i.e a cron job scheduler is required). Requests to a shop[](https://devdocs.prestashop-project.org/1.7/modules/creation/external-services/#requests-to-a-shop) ------------------------------------------------------------------------------------------------------------------------ You may retrieve and update data from a shop using different methods: ### The native webservice[](https://devdocs.prestashop-project.org/1.7/modules/creation/external-services/#the-native-webservice) The webservice is a REST API allowing you to interact with most of the database tables used by the core. It uses Basic access authentication to allow requests. **Resources:** * [About the webservice](https://devdocs.prestashop-project.org/1.7/webservice/) * [Enable & add users to the webservice](https://devdocs.prestashop-project.org/1.7/webservice/tutorials/creating-access/) **Adding a module ObjectModel to the list of resources available** The hook `addWebserviceResources` must be registered by your module. Then an array containing all the ressources (= Object Model subclasses) you want to add should be returned. For instance, in the module blockreassurance we have an ObjectModel class, called `reassuranceClass`. If we wanted to make it available in the webservice, it would look like this: array( 'description' => 'Module Reassurance example', 'class' => 'reassuranceClass', 'forbidden_method' => array('PUT', 'POST', 'DELETE')), ); } This will add the resource `reassurance` available into the permissions list, based on the key. ### Module controllers[](https://devdocs.prestashop-project.org/1.7/modules/creation/external-services/#module-controllers) As the webservice is only an interface to get and update objects on the database, it does not allow to run complex actions. Module controller may be implemented to allow any external service to reach your shop, then trigger specific actions or retrieve content. You should implement a method that filters non-authenticated calls. This prevents guests accessing private content, or trigger actions on your behalf. This can be done by generating your own token and checking it everytime the controller is called. `Tools::encrypt($token)` may be useful. **Resources:** * [About the controllers](https://devdocs.prestashop-project.org/1.7/modules/concepts/controllers/front-controllers/) * [Example with Faceted Search module (Outside a controller)](https://github.com/PrestaShop/ps_facetedsearch/blob/6f7b97e77b0fca30c0acf74316996cfc82a263a9/ps_facetedsearch-clear-cache.php#L6-L8) Requests from a shop[](https://devdocs.prestashop-project.org/1.7/modules/creation/external-services/#requests-from-a-shop) ---------------------------------------------------------------------------------------------------------------------------- HTTP requests can be triggered from a shop to an external service. Several methods allows requests to be sent (in order of preference): * [Guzzle](https://github.com/guzzle/guzzle) . The version 5 is included from PrestaShop 1.7.0 , but can be included in your module as well for older PS versions. * Loading in memory another version of guzzle in the same namespace will trigger errors on the shop. * Example with PS Checkout module: [Inclusion in composer.json](https://github.com/PrestaShopCorp/ps_checkout/blob/578135d8bef2d99b8056ebc0bd709e9a87d661e6/composer.json#L28) & [implementation](https://github.com/PrestaShopCorp/ps_checkout/blob/ef48da09735e6e64b42364a703b5a74d41cd24d9/classes/Api/Payment/Dispute.php) * [\\Tools::file\_get\_contents(…)](https://github.com/PrestaShop/PrestaShop/blob/a07a569b45ab6afc777f25aba505997004e5f70a/classes/Tools.php#L2212-L2223) * Will rely on `cURL` or `fopen()`, depending on what is available on the shop. * Exists from PrestaShop 1.4 * [cURL](https://www.php.net/manual/en/book.curl.php) * cURL is mandatory for PrestaShop 1.7 . For older versions, the extension must be checked first to avoid fatal errors. --- # Getting Started :: PrestaShop Developer Documentation [Improve this page](https://github.com/PrestaShop/docs/edit/8.x/modules/creation/_index.md "Improve this page") [How](https://devdocs.prestashop-project.org/9/contribute/documentation/how) Table of Contents [Next article](https://devdocs.prestashop-project.org/8/modules/creation/tutorial/ "Tutorial: Creating your first module") **Warning:** You are browsing the documentation for PrestaShop 8, which is outdated. You might want to read an updated version of this page for the current version, PrestaShop 9. [Read the updated version of this page](https://devdocs.prestashop-project.org/9/modules/creation/) [Learn how to update to the latest version.](https://devdocs.prestashop-project.org/9/basics/keeping-up-to-date/update) Getting Started[](https://devdocs.prestashop-project.org/8/modules/creation/#getting-started) ============================================================================================== If you want to get started quickly with a ready-to-use module template, you can use [PrestaShop Validator’s Module Generator](https://validator.prestashop.com/generator) . It provides an easy way to generate a module, including the basic structure, customized default properties, and most common use cases covered (hook, upgrade…). Other skeletons have been created to help you create specific modules: * [Skeleton of a Payment module for PrestaShop 1.7](https://github.com/PrestaShop/paymentexample) * [Skeleton of a module using CQRS feature](https://github.com/friends-of-presta/demo-cqrs-hooks-usage-module) ([More details about CQRS](https://devdocs.prestashop-project.org/8/development/architecture/domain/) ) In this section[](https://devdocs.prestashop-project.org/8/modules/creation/#in-this-section) ---------------------------------------------------------------------------------------------- * [Tutorial: Creating your first module](https://devdocs.prestashop-project.org/8/modules/creation/tutorial/) * [Folder structure](https://devdocs.prestashop-project.org/8/modules/creation/module-file-structure/) * [Adding a configuration page (Legacy architecture)](https://devdocs.prestashop-project.org/8/modules/creation/adding-configuration-page/) * [Modern configuration page](https://devdocs.prestashop-project.org/8/modules/creation/adding-configuration-page-modern/) * [Displaying content on the front office](https://devdocs.prestashop-project.org/8/modules/creation/displaying-content-in-front-office/) * [Enabling the Auto-Update](https://devdocs.prestashop-project.org/8/modules/creation/enabling-auto-update/) * [Module translation](https://devdocs.prestashop-project.org/8/modules/creation/module-translation/) * [Good practices for developing modules](https://devdocs.prestashop-project.org/8/modules/creation/good-practices/) * [Interacting with APIs](https://devdocs.prestashop-project.org/8/modules/creation/external-services/) --- # Extension concepts :: PrestaShop Developer Documentation [Improve this page](https://github.com/PrestaShop/docs/edit/1.7.x/modules/concepts/_index.md "Improve this page") [How](https://devdocs.prestashop-project.org/9/contribute/documentation/how) **Warning:** You are browsing the documentation for PrestaShop 1.7, which is outdated. You might want to read an updated version of this page for the current version, PrestaShop 9. [Read the updated version of this page](https://devdocs.prestashop-project.org/9/modules/concepts/) [Learn how to update to the latest version.](https://devdocs.prestashop-project.org/9/basics/keeping-up-to-date/update) Extension concepts[](https://devdocs.prestashop-project.org/1.7/modules/concepts/#extension-concepts) ====================================================================================================== * [Hooks](https://devdocs.prestashop-project.org/1.7/modules/concepts/hooks/) * [Widgets](https://devdocs.prestashop-project.org/1.7/modules/concepts/widgets/) * [Controllers](https://devdocs.prestashop-project.org/1.7/modules/concepts/controllers/) * [Forms](https://devdocs.prestashop-project.org/1.7/modules/concepts/forms/) * [Templating](https://devdocs.prestashop-project.org/1.7/modules/concepts/templating/) * [Doctrine](https://devdocs.prestashop-project.org/1.7/modules/concepts/doctrine/) * [Overrides](https://devdocs.prestashop-project.org/1.7/modules/concepts/overrides/) * [External dependencies & autoload with Composer](https://devdocs.prestashop-project.org/1.7/modules/concepts/composer/) * [Services](https://devdocs.prestashop-project.org/1.7/modules/concepts/services/) * [Symfony extension concepts](https://devdocs.prestashop-project.org/1.7/modules/concepts/symfony/) * [Commands](https://devdocs.prestashop-project.org/1.7/modules/concepts/commands/) * [Pdf Files](https://devdocs.prestashop-project.org/1.7/modules/concepts/pdf/) * [Mail Templates](https://devdocs.prestashop-project.org/1.7/modules/concepts/mail-templates/) * [Module class reference](https://devdocs.prestashop-project.org/1.7/modules/concepts/module-class/) * [Multistore](https://devdocs.prestashop-project.org/1.7/modules/concepts/multistore/) * [Webservice](https://devdocs.prestashop-project.org/1.7/modules/concepts/webservice/) [Next: Hooks ›](https://devdocs.prestashop-project.org/1.7/modules/concepts/hooks/ "Hooks") --- # Shops configuration :: PrestaShop Developer Documentation [Improve this page](https://github.com/PrestaShop/docs/edit/9.x/development/multistore/shops-configuration/_index.md "Improve this page") [How](https://devdocs.prestashop-project.org/9/contribute/documentation/how) Table of Contents [Next article](https://devdocs.prestashop-project.org/9/development/multistore/configuration-forms/ "Configuration forms") Fetching shop configuration values in multistore context[](https://devdocs.prestashop-project.org/9/development/multistore/shops-configuration/#fetching-shop-configuration-values-in-multistore-context) ========================================================================================================================================================================================================== When multistore is disabled and you fetch a configuration value, you are in a **single store context**, so you are fetching configuration values of your only store. All you have to do is use the **legacy configuration adapter** (more on that later). But what if you want to fetch a configuration value with more than one activated shop? This is where the **ShopConstraint** value object (VO) comes in handy, this is what you will use in order to specify which store(s) configuration value you are targeting. If you don’t know what is a value object, you will find out about it and its use in the [value objects](https://devdocs.prestashop-project.org/9/development/architecture/domain/value_objects/) documentation. Usage[](https://devdocs.prestashop-project.org/9/development/multistore/shops-configuration/#usage) ---------------------------------------------------------------------------------------------------- In order to fetch a configuration value in multistore context, you will need the legacy configuration adapter service `prestashop.adapter.legacy.configuration` and a ShopConstraint instance `PrestaShop\PrestaShop\Core\Domain\Shop\ValueObject\ShopConstraint`. Example: get('prestashop.adapter.legacy.configuration'); // Instantiate a ShopConstraint value object $shopConstraint = new ShopConstraint( (int) $order->id_shop, (int) $order->id_shop_group ); // Get the needed configuration value, passing your ShopConstraint object as a third parameter $roundType = (int) $configuration->get('PS_ROUND_TYPE', null, $shopConstraint); // ... } } Note that the ShopConstraint VO is not solely dedicated to being used with the configuration service. If you write a method/function that should have different behaviors depending on a given shop / shop group, then using the ShopConstraint VO is a good idea. Fetched configuration values depending on context[](https://devdocs.prestashop-project.org/9/development/multistore/shops-configuration/#fetched-configuration-values-depending-on-context) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- This is how configuration values are stored in database, depending on the current shop context (in the table `ps_configuration`): | Current context | configuration name | id\_shop | id\_shop\_group | value | | --- | --- | --- | --- | --- | | All shops context | PS\_SHOP\_ENABLE | NULL | NULL | ‘all shops value’ | | Group shop context (ex: shop group’s id is 2) | PS\_SHOP\_ENABLE | NULL | 2 | ‘group shop value’ | | Single shop context (ex: shop’s id is 3 and its group id is 2 ) | PS\_SHOP\_ENABLE | 3 | 2 | ‘single shop value’ | Note that setting the value of a parent context does not override the values for children contexts that were set before. For example, if a configuration value is set for a **single shop**, setting a configuration value in **all shops context** will not override it. When fetching a configuration value, the configuration service will look for the corresponding value for the current context, if there is none, you will get the configuration value for the next parent context having a configuration value, it goes from the most precise to the most generic context: **Single shop => Group shop => All shops** For example, if you are in single shop context but no configuration value is set for this shop, then if there is a configuration value for the shop group, you will get it, otherwise you will get the “all shops” value as a default. --- # Configuration forms :: PrestaShop Developer Documentation [Improve this page](https://github.com/PrestaShop/docs/edit/9.x/development/multistore/configuration-forms/_index.md "Improve this page") [How](https://devdocs.prestashop-project.org/9/contribute/documentation/how) Table of Contents [Next article](https://devdocs.prestashop-project.org/9/testing/ "Testing") Configuration forms in multistore context[](https://devdocs.prestashop-project.org/9/development/multistore/configuration-forms/#configuration-forms-in-multistore-context) ============================================================================================================================================================================ The Back Office contains multiple configuration forms that control settings of the shop. When multistore is enabled, Back Office user must be able to modify these settings either for all shops, for a group of shop or for a single shop. Migrated configuration forms can display a checkbox before fields in order to specify if the configuration value is set for the current context shop/group, or if it is a value inherited from all contexts, or from a shop group. It will also display a dropdown at the right of the field, telling you whether this field is customized or inherits its value from its parent context. Here is how it looks like:  #### Multistore configuration form dropdown If you are building a configuration form and you want the form to be aware of the current multistore context, then you must make your form compatible with multistore checkboxes. This is made possible thanks to [Symfony’s form extensions mechanism](https://symfony.com/doc/4.4/form/create_form_type_extension.html) . Creating a multistore compatible configuration form[](https://devdocs.prestashop-project.org/9/development/multistore/configuration-forms/#creating-a-multistore-compatible-configuration-form) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ You will find a concrete example of how a configuration form is made multistore-compatible [on this github pull-request](https://github.com/PrestaShop/PrestaShop/pull/24393) . A Symfony form extension called `MultistoreConfigurationTypeExtension` has been created in order to make it easy to add multistore checkboxes to a configuration form. In order to extend this form extension, your Symfony form type must implement a `getParent()` method returning `MultistoreConfigurationType::class`. add( 'my_field', SwitchType::class, [\ 'required' => true,\ // Here we add the multistore_configuration_key option with the configuration key it is linked to.\ 'multistore_configuration_key' => 'THE_CONFIGURATION_KEY',\ // ...\ ] ) // ... Last but not least, you must make the frontend aware of these state modifications, you need to add the `MultistoreConfigField` in your javascript: window.prestashop.component.initComponents( [\ 'MultistoreConfigField',\ ], ); Doing this will have several effects: * Each field having the `multistore_configuration_key` option will have a multistore checkbox on its left and a multistore dropdown on its right; * Checkboxes will automatically be checked or not depending on the configuration for the current shop context; * When the configuration value is inherited, the checkbox will be unchecked, and the field will be disabled and greyed out; * Thanks to the javascript component, checking or unchecking a checkbox will enable/disable the field for the current shop context. Saving data from a multistore configuration form[](https://devdocs.prestashop-project.org/9/development/multistore/configuration-forms/#saving-data-from-a-multistore-configuration-form) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ When receiving the data from the form, you will also receive values from the multistore checkboxes that were added to your form: * When a multistore checkbox is pushed unchecked, we want to delete the configuration value for the current context (so that it inherits its value from parent contexts). * When a multistore checkbox is pushed checked, we want to save the configuration value for the current context. When your configuration form is multistore compatible, your configuration class should extend the `AbstractMultistoreConfiguration` abstract class instead of directly implementing the `DataConfigurationInterface` interface. This will give you access to helper methods that will make it easy to store the right configuration values at the right place and for the right context. The two helper methods are * **`getShopConstraint()`:** this will give you a ShopConstraint object reflecting the current context or null public function getShopConstraint(): ?ShopConstraint * **`updateConfigurationValue()`:** this will save or delete the configuration value for the given configuration key, and is aware of the multistore checkbox and the current shop context. Note that this helper method is fully compatible with not-multistore fields. public function updateConfigurationValue(string $configurationKey, string $fieldName, array $input, ?ShopConstraint $shopConstraint, array $options = []): void As an example, see how it is used in the `MaintenanceConfiguration` class getShopConstraint(); // note that $configurationInputValues is an associative array where keys are field names and values are field values, it's the data coming from the form $this->updateConfigurationValue('PS_SHOP_ENABLE', 'enable_shop', $configurationInputValues, $shopConstraint); $this->updateConfigurationValue('PS_MAINTENANCE_IP', 'maintenance_ip', $configurationInputValues, $shopConstraint); $this->updateConfigurationValue('PS_MAINTENANCE_TEXT', 'maintenance_text', $configurationInputValues, $shopConstraint, ['html' => true]); return []; } } As you can see, by using these two helper methods you can easily store your configuration values in a multistore context. --- # Shops context :: PrestaShop Developer Documentation [Improve this page](https://github.com/PrestaShop/docs/edit/9.x/development/multistore/shop-context/_index.md "Improve this page") [How](https://devdocs.prestashop-project.org/9/contribute/documentation/how) Table of Contents [Next article](https://devdocs.prestashop-project.org/9/development/multistore/shops-configuration/ "Shops configuration") Shop context[](https://devdocs.prestashop-project.org/9/development/multistore/shop-context/#shop-context) =========================================================================================================== In many cases, your code will need to know if the multistore mode is enabled, if there are more than one shop activated, and if yes, what is the current shop context. This is where the shop context and multistore feature adapters will come in handy. The multistore feature adapter[](https://devdocs.prestashop-project.org/9/development/multistore/shop-context/#the-multistore-feature-adapter) ----------------------------------------------------------------------------------------------------------------------------------------------- **Service identifier:** `prestashop.adapter.feature.multistore` (it takes the legacy configuration adapter as a parameter) **Class:** `PrestaShop\PrestaShop\Adapter\Feature\MultistoreFeature` The multistore feature adapter can be used to: * detect if multistore was enabled in the configuration, * detect if multistore is active (if it is enabled, and if there are more than one active shop), * enable/disable the multistore feature. Example: get('prestashop.adapter.feature.multistore'); // Is the multistore feature enabled? $isMultistoreEnabled = $multistoreFeature->isActive(); // This will check that multistore is enabled AND that there are at least two active shops $isMultistoreUsed = $multistoreFeature->isUsed(); // Disable / enable multistore feature $multistoreFeature->disable(); $multistoreFeature->enable(); The shop context adapter[](https://devdocs.prestashop-project.org/9/development/multistore/shop-context/#the-shop-context-adapter) ----------------------------------------------------------------------------------------------------------------------------------- **Service identifier:** `prestashop.adapter.shop.context` **Class:** `PrestaShop\PrestaShop\Adapter\Shop\Context` When the multistore feature is enabled, at the top of all Back Office pages, a dropdown is displayed. It allows selecting the shop context we want (all shops, a group shop, a single shop). The shop context adapter will tell you in what context your code is operating. Here are some examples of commonly used functions in the shop context adapter: get('prestashop.adapter.shop.context'); // Get a list of all active shops $shopList = $shopContext->getShops(false, true); // Is the current context a group of shops? $isShopGroupContext = $shopContext->isShopGroupContext(); // Is the current context a single shop? $isSingleShopContext = $shopContext->isSingleShopContext(); // Is "all shops" context $isAllShopContext = $shopContext->isAllContext(); // Get a list of IDs for all shops belonging to the current context (useful is the current context is a group) $shopList = $shopContext->getContextListShopID(); // Get the id of the shop in the current context (useful if the current context is a single shop) $currentIdShop = $shopContext->getContextShopID(); The shop context adapter class has many functions with self-explanatory naming and helpful comments, feel free to [explore it by yourself](https://github.com/PrestaShop/PrestaShop/blob/8.0.x/src/Adapter/Shop/Context.php) . --- # Adding a configuration page (Legacy architecture) :: PrestaShop Developer Documentation [Improve this page](https://github.com/PrestaShop/docs/edit/8.x/modules/creation/adding-configuration-page.md "Improve this page") [How](https://devdocs.prestashop-project.org/9/contribute/documentation/how) Table of Contents [Next article](https://devdocs.prestashop-project.org/8/modules/creation/adding-configuration-page-modern/ "Modern configuration page") **Warning:** You are browsing the documentation for PrestaShop 8, which is outdated. You might want to read an updated version of this page for the current version, PrestaShop 9. [Read the updated version of this page](https://devdocs.prestashop-project.org/9/modules/creation/adding-configuration-page/) [Learn how to update to the latest version.](https://devdocs.prestashop-project.org/9/basics/keeping-up-to-date/update) Adding a configuration page[](https://devdocs.prestashop-project.org/8/modules/creation/adding-configuration-page/#adding-a-configuration-page) ================================================================================================================================================ Learn [how to create a configuration page with Symfony forms](https://devdocs.prestashop-project.org/8/modules/creation/adding-configuration-page-modern/) . This guide is about the legacy way of creating configuration pages for modules using `HelperForm`. Modules usually provide a dedicated configuration page, accessible through a “Configure” button in the Module Manager list, that allows the shop’s administrator to set up any options provided by the module. In difference with other [controllers](https://devdocs.prestashop-project.org/8/modules/concepts/controllers/) , the content of configuration page is handled directly in the module’s main class by the `getContent()` public method. PrestaShop will check if this method exists and will only display the “Configure” button if this method is declared. In the following example we will implement a minimalistic configuration page that displays a form allowing the user to edit the content of the `MYMODULE_CONFIG` [Configuration](https://devdocs.prestashop-project.org/8/development/components/configuration/) variable. The `getContent()` method[](https://devdocs.prestashop-project.org/8/modules/creation/adding-configuration-page/#the-getcontent-method) ---------------------------------------------------------------------------------------------------------------------------------------- First, let’s have a look at our `getContent()` method: /** * This method handles the module's configuration page * @return string The page's HTML content */ public function getContent() { $output = ''; // this part is executed only when the form is submitted if (Tools::isSubmit('submit' . $this->name)) { // retrieve the value set by the user $configValue = (string) Tools::getValue('MYMODULE_CONFIG'); // check that the value is valid if (empty($configValue) || !Validate::isGenericName($configValue)) { // invalid value, show an error $output = $this->displayError($this->l('Invalid Configuration value')); } else { // value is ok, update it and display a confirmation message Configuration::updateValue('MYMODULE_CONFIG', $configValue); $output = $this->displayConfirmation($this->l('Settings updated')); } } // display any message, then the form return $output . $this->displayForm(); } The `getContent()` method is called when the configuration page is loaded. Therefore, we use it to both display a form and handle the action behind that form. Here is a step by step explanation: * `Tools::isSubmit()` is a PrestaShop-specific method that checks if a given form has been submitted. In this case, if the configuration form has not yet been sent, the whole `if()` block is skipped and PrestaShop will only use the last line, which displays the configuration form using current values, as generated by the `displayForm()` method. * `Tools::getValue()` is another PrestaShop-specific method that retrieves the specified parameter from either POST or GET. In this case, we retrieve the value of the `MYMODULE_CONFIG` form field, turn its value into a text string using `(string)`, then store it in the `$configValue` variable. * We then check that `$configValue` is not empty and valid. In this case, we decided that the configuration should not accept special characters, so we use `Validate::isGenericName()`. The `Validate` object contains many data validation methods, among which is `isGenericName()`, a method that helps you keep only strings that are valid PrestaShop names – meaning, a string that does not contain special characters. * If any of these checks fail, the configuration will display an error message, indicating that the form validation failed. The `$output` variable, which contains the final rendition of the HTML code that makes the configuration page, will begin with an error message, that we create using PrestaShop’s `displayError()` method. This method returns the correct HTML code for our need, and since that code is first in `$output`, this means the configuration will be displayed before any other content. * If the checks are successful, this means we can store the value in our database. The `Configuration::updateValue()` method will store the new value for `MYMODULE_CONFIG` in the configuration database. After that, we want to add a friendly message to the user, indicating that the value has indeed been saved. To that end, we use PrestaShop’s `displayConfirmation()` method to add that message as the first data in the `$output` variable – and therefore, at the top of the page. * Finally, we use the custom `displayForm()` method (explained in the next section) in order to build the form, that we want to render whether if it is submitted or not. Then we will send the resulting HTML code into `$output` so that we can render the page. Note that we could have included the code for `displayForm()` right within `getContent()`, but chose to separate the two for readability and separation of concerns. This form-validation code is nothing new for PHP developers, but uses some of the PrestaShop methods that you will regularly use. Displaying the form[](https://devdocs.prestashop-project.org/8/modules/creation/adding-configuration-page/#displaying-the-form) -------------------------------------------------------------------------------------------------------------------------------- The configuration form itself is displayed with the `displayForm()` method. Here is its code, which we are going to explain after the jump: /** * Builds the configuration form * @return string HTML code */ public function displayForm() { // Init Fields form array $form = [\ 'form' => [\ 'legend' => [\ 'title' => $this->l('Settings'),\ ],\ 'input' => [\ [\ 'type' => 'text',\ 'label' => $this->l('Configuration value'),\ 'name' => 'MYMODULE_CONFIG',\ 'size' => 20,\ 'required' => true,\ ],\ ],\ 'submit' => [\ 'title' => $this->l('Save'),\ 'class' => 'btn btn-default pull-right',\ ],\ ],\ ]; $helper = new HelperForm(); // Module, token and currentIndex $helper->table = $this->table; $helper->name_controller = $this->name; $helper->token = Tools::getAdminTokenLite('AdminModules'); $helper->currentIndex = AdminController::$currentIndex . '&' . http_build_query(['configure' => $this->name]); $helper->submit_action = 'submit' . $this->name; // Default language $helper->default_form_language = (int) Configuration::get('PS_LANG_DEFAULT'); // Load current value into the form $helper->fields_value['MYMODULE_CONFIG'] = Tools::getValue('MYMODULE_CONFIG', Configuration::get('MYMODULE_CONFIG')); return $helper->generateForm([$form]); } While this might look like a huge block of code for a single form field, this block actually uses some of PrestaShop’s methods that make it easier to build forms, most notably the `HelperForm` object. Let’s run down this method: * In preparation for the generation of the form, we create the `$form` variable, which contains the definition of the various elements (fields, labels, etc) the form will contain. From this variable, PrestaShop will render the HTML form as it is described. In this example, we define three sections (`legend`, `input` and `submit`) and their properties using arrays. The format is quite straightforward: the `legend` and `submit` arrays simply contain the attributes to each tag, while the `input` array contains as many input elements as needed, each being in turn an array containing the necessary attributes. For instance: 'input' => [\ [\ 'type' => 'text',\ 'label' => $this->l('Configuration value'),\ 'name' => 'MYMODULE_CONFIG',\ 'size' => 20,\ 'required' => true,\ ]\ ] …generates the following HTML: