# Widgets

Project Zero web pages consist of widgets, and these widgets contain components such as text, image uploads, and drop-down menus. Each widget JSON contains **schema** to describe the widget content.

### <mark style="color:red;">Widget Creation​</mark> <a href="#widget-creation" id="widget-creation"></a>

<table><thead><tr><th width="130.515625" align="center">Property</th><th width="136.40625" align="center">Data Type</th><th width="87.73828125" align="center">Required</th><th>Description</th></tr></thead><tbody><tr><td align="center"><code>data_type</code></td><td align="center">string</td><td align="center">*</td><td>Component data type. It could be;<br><strong>text</strong>: Creates standart text component<br><strong>image</strong>: Creates image upload component<br><strong>dropdown</strong>: Creates dropdown selection box. It should used with <code>choices</code> dict.<br><strong>area</strong>: Provides custom field view and is used to create HTML editor. It is mandatory to have a <code>display</code> field with it.<br><strong>nested</strong>: It is mandatory to use in nested structures and <code>data_type</code> value of the outermost(root) object must be nested.</td></tr><tr><td align="center"><code>key</code></td><td align="center">string</td><td align="center">*</td><td>It is used to match the data of the component. It must same as the object name of the component</td></tr><tr><td align="center"><code>label</code></td><td align="center">string</td><td align="center">*</td><td>It determines how the component name displays on the back office panel. It is preferable to be short and understandable</td></tr><tr><td align="center"><code>display</code></td><td align="center">string</td><td align="center"></td><td>It is used when build datepicker or HTML editor component.</td></tr><tr><td align="center"><code>required</code></td><td align="center">boolean (default:True)</td><td align="center"></td><td>This</td></tr><tr><td align="center"><code>multi</code></td><td align="center">boolean (default:True)</td><td align="center"></td><td>It is used when creating more than one the same component. It can't be used inside the <em>multi</em> component.</td></tr><tr><td align="center"><code>is_localizable</code></td><td align="center">boolean</td><td align="center"></td><td>It is used to localize widgets according to languages. For example; Considering that the same store sites in different languages are managed from the same back office panel, the widget where the "is_localizable" parameter is "true" can be added with different languages.</td></tr><tr><td align="center"><code>schema</code></td><td align="center">object</td><td align="center"></td><td>If <code>data_type</code> is <em>nested</em>, schema is required field.</td></tr></tbody></table>

**Example​**

```
{
  "sliders": {
    "multi": true,
    "schema": {
      "name": {
        "data_type": "text",
        "key": "name",
        "label": "Name"
      },
      "slug": {
        "data_type": "text",
        "key": "slug",
        "label": "Slug"
      }
    },
    "data_type": "nested",
    "key": "sliders",
    "label": "Sliders"
  }
}
```

{% hint style="info" %}
`key` value must same as the object name of the component
{% endhint %}

```
{
  "slider": {
    "data_type": "text",
    "key": "slider",
    "label": "slide component"
  }
}
```

**`Choices` example​**

```
{
  "button_alignment": {
    "choices": [
      {
        "value": "block",
        "label": "One under the other"
      },
      {
        "value": "inline",
        "label": "Side by side"
      }
    ],
    "data_type": "dropdown",
    "key": "button_alignment",
    "label": "Buttons appear side by side or one under the other?"
  }
}
```

**`Display` example​**

```
{
  "answer": {
     "data_type": "area",
     "display": "html-editor",
     "key": "answer",
     "label": "Answer"
  }
}
```

***

## <mark style="color:red;">Defining Widget on Omnitron​</mark> <a href="#defining-widget-on-omnitron" id="defining-widget-on-omnitron"></a>

Once the schema is created as desired, go to the Content Management -> Widget Template Management page on Omnitron and click on the "Add Widget Template" button.

<figure><img src="https://2911598027-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlQinVPnOffBiOp126ldR%2Fuploads%2Fgit-blob-b5112a34abfafd78981cbafb0bd4c2554d49d846%2Fimage.png?alt=media" alt=""><figcaption></figcaption></figure>

<figure><img src="https://2911598027-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlQinVPnOffBiOp126ldR%2Fuploads%2Fgit-blob-f993616e9c6032d8515209b177fe50411d8c931b%2Fimage.png?alt=media" alt=""><figcaption></figcaption></figure>

Type in the Widget Type in the following page and insert the created schema.

<figure><img src="https://2911598027-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlQinVPnOffBiOp126ldR%2Fuploads%2Fgit-blob-f28ed4d5fbc760b1941aa14894a57fbce2d270f4%2Fimage.png?alt=media" alt=""><figcaption></figcaption></figure>

Once the schema is successfully inserted, go to the the Content Management -> Widget Management page and click on the "Add New Widget" button.

<figure><img src="https://2911598027-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlQinVPnOffBiOp126ldR%2Fuploads%2Fgit-blob-4e3be5c518a329038f44f6ea250386335ec40077%2Fimage.png?alt=media" alt=""><figcaption></figcaption></figure>

Select the added widget type in the following page. After this step, you will see inserted fields in the schema.

<figure><img src="https://2911598027-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlQinVPnOffBiOp126ldR%2Fuploads%2Fgit-blob-5b9cdc7dcd0b43ba117688f866b76ddc35319e06%2Fimage.png?alt=media" alt=""><figcaption></figcaption></figure>

Widget name refers to the representation of widget on the panel, while widget slug refers to the code representation of the widget. Widget slugs should be in “kebab-case”. The path of the HTML file which contains widget data is inserted in the remaining “Template” field. Generally, these templates are saved in the “template.html” file located in the “templates/widgets/widget-name/” path. When adding this path to the “Template” field, start with the “widgets/” folder.

#### <mark style="color:red;">**Localizable Example​**</mark>

The "is\_localizable" field should be added for all schema items as shown in the example. That means, it should be added not only in the "message" field, but both in the "message" and the "title" fields. If "nested" data\_type is used, then it is sufficient to add only to the "root" object.

```
{
  "message": {
     "required": "true",
     "data_type": "area",
     "key": "message",
     "label": "Description"
  },
  "title": {
     "required": "true",
     "data_type": "text",
     "key": "title",
     "label": "Title"
  }
}
```

Widgets added in this manner will behave differently when language option on Omnitron is changed. For instance, if we add a widget in English language but switch to French language later, then our widget will no longer contain the same data. In this manner, we enable different data management for different languages. It is important to make sure that the correct language option is selected when adding widgets because otherwise, it will rewrite on existing widget data.

## <mark style="color:red;">Widget Integration​</mark> <a href="#widget-integration" id="widget-integration"></a>

Once all data is accurately entered, you need to integrate the widget into a page to test. This can be any page. The created widget is called to the page as follows:

```
{% set extra_widgets = ['my-widget'] %}
...
{% set widget = all_widgets['my-widget'] %}

{% if widget %}
  {% include widget.template ignore missing %}
{% endif %}
```

The first row in the example should appear in the first row of the page where the widget will be called. If it already exists, then a new one should not be created but it should be added into the array.

The lower part is where the widget template will be used. If a template is not required and if only widget data will be used, then:

```
{% set widget = all_widgets['my-widget'].attributes %}
in this way, the assignment can be made and the relevant data can be obtained from it.
```

You can now establish the widget HTML to match the path and folder name we entered in Omnitron.

```
{% set data = widget.attributes %}
{% if data.image.kwargs.url %}
  <div class="image-banner {{ if data.image_width.value == 'yes' %}full-width{% endif %}">
    <a href="{{ data.image_url.value if data.image_url.value else '#'}}">
      <img src="{{ data.image.kwargs.url }}" alt="Banner">
    </a>
  </div>
{% endif %}
```

As widget data is always accessed through **widget.attributes**, it is standard practice to assign as in the first row.

#### <mark style="color:red;">Widget Orders​</mark> <a href="#widget-orders" id="widget-orders"></a>

Sometimes, a page will have its content change frequently, such as a home page. In these scenarios, instead of constantly editing the code, a widget-order widget is used. This is a simple widget with multiple text fields where you can enter widget slugs and re-order them.

To integrate this kind of widgets to your code, you will need to use a special macro called **get\_ordered\_widgets**.

```
{% from 'widgets/widget-generator.html' import get_ordered_widgets with context %}

{% set extra_widgets = ['home-widget-order'] %}

{% block content %}
  {% set order_widget = all_widgets['home-widget-order'] %}

  {{ get_ordered_widgets(order_widget=order_widget) }}
{% endblock %}
```

This macro will loop through the widget slugs you entered in to the widget-order widget and render their templates in order.

#### <mark style="color:red;">Accessing Values​</mark> <a href="#accessing-values" id="accessing-values"></a>

As seen in the example, the “key” values corresponding to the fields in our schema are used to access relevant data. Below methods can be used to view widget data:

```
{{ data|jsonify|safe }} // Page can be viewed from source code
```

```
<pre> {{ data|pprint }} </pre> // Can be viewed on the page
```

```
shop.url/widgets/widget-slug // Outputs JSON via browser
```
