Introducing the plugin cookbook

The plugin cookbook is a collection of recipes for plentymarkets plugin scenarios. On this page, you will find answers to questions that might arise when developing plentymarkets plugins.

Info: The cookbook is just getting started. New recipes are already on the way. If you can’t find an answer to your question, post your requests and feedback in our forum.

Adding content categories in the Ceres navigation

By default, content categories are not displayed in the navigation bar of Ceres. If you want to display a category of the Content type in the navigation bar of the online store, you have to change a parameter in one of the Twig templates. You can do this in your own theme or fork of Ceres, or in the plentymarkets back end when using Ceres from plentyMarketplace.

  1. Go to Plugins » Plugin overview.

  2. Click on Ceres.
    → The plugin will open.

  3. Go to resources/views/PageDesign/PageDesign.twig.

  4. Search for the line of code {% set categories = services.category.getNavigationTree("item", lang, 6) %}.

  5. Replace the line of code with {% set categories = services.category.getNavigationTree("all", lang, 6) %}.

  6. Save the settings.
    → All category types can now be used in the navigation bar of the online store.

To-do on update

Note that these changes will be overwritten when updating the plugin to a higher version. Repeat the steps above in order to make all category types available again.

After enabling the other category types in the Ceres online store, create a category of the Content type. The following steps must be taken into account:

  • Activate this category for your client.

  • Select Display in the In link list drop-down to display the category in the navigation.

  • Open the Template tab and enter the content that you want to display in the online store.
    → You can enter HTML and TWIG code in this tab.

  • Save everything.
    → When content is entered in the Template tab of a category, the CategoryTemplates plugin is created automatically. This plugin contains the HTML/TWIG code of your category.

  • Simply activate this plugin and deploy the plugin set by clicking Save & publish plugins. After a short period of time, the category will be visible in the navigation.

Adding scripts in Ceres

Scripts of your plugin defined using the HTML <script> tag can be added to the scripts of the template plugin Ceres without creating a data provider and linking the content with a template container. Simply extend the ServiceProvider of your plugin and import your script resource into Ceres.

Theme/src/Providers/ThemeServiceProvider.php
<?php

namespace Theme\Providers;

use IO\Helper\TemplateContainer;
use IO\Helper\ResourceContainer;
use Plenty\Plugin\Events\Dispatcher;
use Plenty\Plugin\ServiceProvider;
use Plenty\Plugin\Templates\Twig;

class ThemeServiceProvider extends ServiceProvider
{

    /**
     * Register the service provider.
     */
    public function register()
    {

    }

    /**
     * Boot a template for the basket that will be displayed in the template plugin instead of the original basket.
     */
    public function boot(Twig $twig, Dispatcher $eventDispatcher)
    {
        $eventDispatcher->listen('IO.Resources.Import', function (ResourceContainer $container)
        {
            // The script is imported in the Footer.twig of Ceres
            $container->addScriptTemplate('Theme::content.SingleItemScript');
        }, self::PRIORITY);
    }
}

Add the dependencies for the ResourceContainer, the Dispatcher and Twig classes.

Add the boot() function and use the dispatcher for listening to the resource import event IO.Resources.Import. Use the addScriptTemplate() method and specify the location of your script resource, e.g. a twig template. In this template, use <script> tags to define the scripts to be added to the scripts of Ceres.

Adding style in Ceres

Inline style of your plugin defined using the HTML <style> tag can be added to the style of the template plugin Ceres without creating a data provider and linking the content with a template container. Simply extend the ServiceProvider of your plugin and import your style resource into Ceres.

Theme/src/Providers/ThemeServiceProvider.php
<?php

namespace Theme\Providers;

use IO\Helper\TemplateContainer;
use IO\Helper\ResourceContainer;
use Plenty\Plugin\Events\Dispatcher;
use Plenty\Plugin\ServiceProvider;
use Plenty\Plugin\Templates\Twig;

class ThemeServiceProvider extends ServiceProvider
{

    /**
     * Register the service provider.
     */
    public function register()
    {

    }

    /**
     * Boot a template for the basket that will be displayed in the template plugin instead of the original basket.
     */
    public function boot(Twig $twig, Dispatcher $eventDispatcher)
    {
        $eventDispatcher->listen('IO.Resources.Import', function (ResourceContainer $container)
        {
            // The style is imported in the <head> on the PageDesign.twig of Ceres
            $container->addStyleTemplate('Theme::content.SingleItemStyle');
        }, self::PRIORITY);
    }
}

Add the dependencies for the ResourceContainer, the Dispatcher and Twig classes.

Add the boot() function and use the dispatcher for listening to the resource import event IO.Resources.Import. Use the addStyleTemplate() method and specify the location of your style resource, e.g. a twig template. In this template, use <style> tags to define the style information for your plugin.

Changing contexts in Ceres

Contexts provided by your own theme plugin can overwrite and extend the PHP context classes of the template plugin Ceres without creating a data provider and linking the content with a template container. Simply extend the ServiceProvider of your plugin and import your context resource into Ceres.

Theme/Providers/ThemeServiceProvider.php
namespace Theme\Providers;

use IO\Helper\TemplateContainer;
use Plenty\Plugin\Events\Dispatcher;
use Plenty\Plugin\ServiceProvider;
use Plenty\Plugin\Templates\Twig;
use Theme\Contexts\MyContext;

class ThemeServiceProvider extends ServiceProvider
{

/**
    * Register the service provider.
    */
public function register()
{

}

public function boot(Twig $twig, Dispatcher $eventDispatcher)
    {
        /**
        * Extend the context for the basket template with MyContext.
        */
        $eventDispatcher->listen('IO.ctx.basket', function (TemplateContainer $templateContainer, $templateData = [])
        {
            $templateContainer->setContext( MyContext::class);
            return false;
        }, 0);
    }
}

Add the dependencies for the TemplateContainer, the Dispatcher and Twig classes.

Add the boot() function and use the dispatcher for listening to the context event IO.ctx.TEMPLATENAME. Specify the template for which you want to modify the context, e.g. IO.ctx.basket. Use the setContext() method and specify which context should be used, e.g. MyContext. In your context, define the elements to be added to the PHP context classes of Ceres. You can find an example for how the context class MyContext extends the GlobalContext below.

Theme/src/Contexts/MyContext.php
<?php

namespace Theme\Contexts;

use IO\Helper\ContextInterface;

class MyContext extends GlobalContext implements ContextInterface
{
    public $myVariable;

    public function init($params)
    {
        parent::init($params);

        $this->myVariable = “This is how you extend context classes.“;
    }
}

The context class MyContext now extends the GlobalContext of Ceres, thereby inheriting the data that GlobalContext provides. Additionally, you are now able to transfer new data to the template via MyContext. In order to completely overwrite the context provided by Ceres, simply delete any extends elements in your own context.

Adding a custom address field

If you want to add one or multiple custom address fields to the address form of the template plugin Ceres, you can use the template container Additional address fields. Create a plugin that provides the data to be displayed in the container, e.g. with the help of this tutorial. Then add the following code to the .twig template:

<div class="col-xs-12 col-sm-4">
    <div class="input-unit" data-validate="text">
        <input type="text" name="town" id="txtPackstationNo${_uid}" v-model="addressData.packstationNo">
        <label for="txtPackstationNo${_uid}">Packstation</label>
    </div>
</div>

In the example, we add another input field for the packstation number. Refer to the Address model to find an overview of available fields. We also want to make this field a required field and validate the input. To do so, we add data-validate="text" for the property of the String type.

You can also check out the AddressInputGroupDE.twig file in the Ceres template for further reference.

Validating addresses in template plugins

Template plugins that want to validate address fields using the validators in IO must have a configuration file following certain rules. IO can get the configuration values set in the template plugin and validate addresses based on these settings. The easiest way to do this is to copy part of the config.json file of Ceres and edit the code. Then, the namespace of the template plugin must be specified in IO.

  1. Go to Plugins » Plugin overview.

  2. Click on IO.
    → The plugin will open.

  3. Click on Configuration in the directory tree.
    → The Template tab will open.

  4. Enter the namespace of your template plugin.

  5. Save the settings.

Example code of the configuration

...

{
    "tab"                                   : "Checkout and My account",
    "key"                                   : "billing_address.require",
        "label"                             : "Enable invoice address field validation",
        "type"                              : "multi_select",
        "possibleValues"                    :
            {
                "billing_address.name1"     : "Company",
                "billing_address.vatNumber" : "VAT number",
                "billing_address.birthday"  : "Date of birth",
                "billing_address.name4"     : "Name affix",
                "billing_address.address3"  : "Additional address 1 / Building name",
                "billing_address.address4"  : "Additional address 2",
                "billing_address.stateId"   : "State"

            },
        "default"                           : "billing_address.birthday, billing_address.name4, billing_address.address3, billing_address.address4"
},

...

The values specified under possibleValues will be validated with the help of the BillingAddressValidator of IO.

Example code of the validator

<?php

namespace IO\Validators\Customer;

use Plenty\Validation\Validator;
use IO\Services\TemplateConfigService;

class BillingAddressValidator extends Validator
{
    private $requiredFields;

    public function defineAttributes()
    {
        /**
         * @var TemplateConfigService $templateConfigService
         */
        $templateConfigService = pluginApp(TemplateConfigService::class);
        $requiredFieldsString  = $templateConfigService->get('billing_address.require');
        $this->requiredFields  = explode(', ', $requiredFieldsString);
        foreach ($this->requiredFields as $key => $value)
        {
            $this->requiredFields[$key] = str_replace('billing_address.', '', $value);
        }

        $this->addString('name2',      true);
        $this->addString('name3',      true);
        $this->addString('address1',   true);
        $this->addString('address2',   true);
        $this->addString('postalCode', true);
        $this->addString('town',       true);

        if(count($this->requiredFields))
        {
            $this->addString('name1',     $this->isRequired('name1'));
            $this->addString('vatNumber', $this->isRequired('vatNumber'));
            $this->addString('birthday',  $this->isRequired('birthday'));
            $this->addString('name4',     $this->isRequired('name4'));
            $this->addString('address3',  $this->isRequired('address3'));
            $this->addString('address4',  $this->isRequired('address4'));
            $this->addString('stateId',  $this->isRequired('stateId'));
        }
    }

    private function isRequired($fieldName)
    {
        return in_array($fieldName, $this->requiredFields);
    }
}

Disabling lazy loading in Ceres item lists

If you want to disable the lazy load function in Ceres item lists, simply add a line of code to the <category-image-carousel> block:

<category-image-carousel template="#vue-category-image-carousel"
    :image-urls="itemData.images | itemImages imageUrlAccessor"
    :alt-text="texts | itemName {{ configItemName }}"
    :item-url="itemData | itemURL"
    :show-dots="{{ config("Ceres.item.category_show_dots") | json_encode() }}"
    :show-nav="{{ config("Ceres.item.category_show_nav") | json_encode() }}"
    :disable-lazy-load="true">
</category-image-carousel>

The line :disable-lazy-load="true" has been added.

Adding a custom value to the item sorting

If you want to add one or multiple custom sorting values to the item sorting drop-down menu of the template plugin Ceres, add the following code in the service provider of your plugin:

<?php

namespace Feedback\Providers;

...

use Plenty\Plugin\Events\Dispatcher;

/**
 * @param Dispatcher $dispatcher
 */
public function boot(Dispatcher $dispatcher)
{
    // Add sorting by customer reviews
    $dispatcher->listen('IO.initAdditionalSorting', function (ItemService $itemService) {

        // addAdditionalItemSorting(field name, translation key)
        $itemService->addAdditionalItemSorting('item.feedbackDecimal_desc', 'Feedback::Feedback.customerReviews');
    });
}

In the example, we add another value for sorting items by customer reviews. Simply add an Event dispatcher which listens to the itemService of the plugin IO. For adding a new value, the field name and translation must be provided.

Adding cache busting in Ceres

We created the new helper PHP class BuildHash.php. This class serves to create a hash, which is renewed every time the plugin set is built. That way, the cache can be reset when the plugins are assembled. The global context class in Ceres (/src/Contexts/GlobalContexts.php) provides the global variable buildHash, which can be used as a GET parameter. The "buildHash" variable can also be used as a suffix for ressource URLs for Javascript, CSS, image ressources, etc. which makes it possible that these ressources are removed from the cache when the plugins are saved and published again.