Create PagibleAI Content Elements

To create new content elements, you need to define them within the schemas array in the ./config/cms.php file.

Table of Contents:

Example

Adding a new content element called "Quote" with a text field for the quote and a string field for the author, you would add the following to the content array of the schemas configuration:

'quote' => [
    'group' => 'content',
    'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M6,17H3V3H6V17M8,5H19A2,2 0 0,1 21,7V17A2,2 0 0,1 19,19H8V5Z" /></svg>',
    'fields' => [
        'text' => [
            'type' => 'text',
            'label' => 'Quote',
            'min' => 1,
        ],
        'author' => [
            'type' => 'string',
        ],
    ],
],

This defines a quote element in the content group with a speech bubble icon. It has two fields: text (a required text field) and author (a string field).

Required Properties

Each element definition consists of a key (the element's type) and an array containing the element's configuration. This configuration includes:

  • group: Specifies the group this element belongs to (e.g., 'basic', 'media', 'content', 'forms'). This helps organize elements in the CMS interface.
  • icon: An SVG string used as an icon for the element in the CMS interface. Make sure, the icon contains fill="currentColor" to be dark mode compatible.
  • fields: An associative array defining the fields that make up the content element. The key of each item in the fields array is the name of the field, and the value is an array that describes the field's properties.

Note: Use field names like title, text and file if possible and appropriate. Then, the values of these fields are used in the new content element when its type is changed by the editor in the admin backend.

Available field types

Each field definition requires a type, which determines the type of input the user will see in the CMS. Here's a summary of the available field types, along with configuration examples:

audio

For selecting an audio file.

  • accept: Accepted mime type, e.g. audio/*
  • label: Title displayed in the admin backend for the field
  • required: True/false value if a file must be selected
'audio_file' => [
    'type' => 'audio',
    'label' => 'Select Audio',
    'accept' => 'audio/*',
    'required' => true,
],

autocomplete

For text input with autocomplete suggestions.

  • api-type: GQL or REST depending on the requested API
  • empty-text: Text shown if no items are returned by the API
  • item-title: Key to the attribute containing the item title; can be a path separated by slashes (/)
  • item-value: Key of the attribute containing the item value; can be a path separated by slashes (/)
  • label: Title displayed in the admin backend for the field
  • list-key: Path to the list of items with names separated by a slash (/)
  • multiple: True/false value if selecting multiple items is allowed
  • options: Initial list of option to select from
  • placeholder: Text shown in the empty autocomplete field
  • query: GraphQL query to fetch suggestions (api-type: GQL)
  • required: True/false value if an item must be selected
  • url: JSON API URL to fetch suggestions from (api-type: REST)

REST API example:

{
    "items": [
        {"name": "Aimeos", "url": "https://github.com/aimeos"},
        {"name": "Laravel", "url": "https://github.com/laravel"}
    ],
    "total": 2
}

For a REST API returning JSON content like outlined above, use this configuration:

'autocomplete_field' => [
    'type' => 'autocomplete',
    'api-type' => 'REST',
    'label' => 'Search Items',
    'url' => '/api/repos?filter=_term_', // _term_ is replaced by the user input
    'list-key' => 'items',
    'item-title' => 'name',
    'item-value' => 'url',
    'placeholder' => 'Start typing to search...',
    'empty-text' => 'No items found.',
    'multiple' => false,
    'required' => true,
],

GraphQL API example:

{
    "data": {
        "pages": {
            "data": [
                {
                    "id": "1",
                    "title": "Home page",
                    "latest": {
                        "data": "..."
                    }
                },
                {
                    "id": "2",
                    "title": "Products | Pagible",
                    "latest": {
                        "data": "..."
                    }
                }
            }
        }
    }
}

For a GraphQL API returning content like outlined above, use this configuration:

'autocomplete_field' => [
    'type' => 'autocomplete',
    'api-type' => 'GQL',
    'label' => 'Search Items',
    'url' => '/graphql',
    // _term_ is replaced by the user input
    'query' => 'query {
        pages(filter: {title: _term_}) {
            data {
                id
                title
                latest {
                    data
                }
            }
        }
    }',
    'list-key' => 'pages/data',
    'item-title' => 'title',
    'item-value' => 'id',
    'placeholder' => 'Start typing to search...',
    'empty-text' => 'No items found.',
    'multiple' => false,
    'required' => true,
],

checkbox

A standard checkbox.

  • label: Title displayed in the admin backend for the field
  • off: Value if unchecked
  • on: Value if checked
'agree_terms' => [
    'type' => 'checkbox',
    'label' => 'I agree to the terms and conditions',
    'on' => 'yes',
    'off' => 'no',
],

color

A color picker, value will be a hex string like #FFFFFF.

  • label: Title displayed in the admin backend for the field
  • required: True/false value if a color must be selected
'background_color' => [
    'type' => 'color',
    'label' => 'Background Color',
    'required' => false,
],

combobox

A dropdown list with an associated text input.

  • api-type: GQL or REST depending on the requested API
  • empty-text: Text shown if no items are returned by the API
  • item-title: Key of the attribute containing the item title; can be a path separated by a slash (/)
  • item-value: Key of the attribute containing the item value; can be a path separated by a slash (/)
  • label: Title displayed in the admin backend for the field
  • list-key: Path to the list of items with names separated by a slash (/)
  • multiple: True/false value if selecting multiple items is allowed
  • options: Initial list of option to select from
  • placeholder: Text shown in the empty combobox field
  • query: GraphQL query to fetch suggestions (api-type: GQL)
  • required: True/false value if an item must be selected
  • url: JSON API URL to fetch suggestions from (api-type: REST)
'category' => [
    'type' => 'combobox',
    'label' => 'Category',
    'options' => [
        ['label' => 'Technology', 'value' => 'tech'],
        ['label' => 'Design', 'value' => 'design'],
    ],
    'placeholder' => 'Select or type a category',
    'required' => true,
],

date

For selecting a date.

  • allowed: List of dates in YYYY-MM-DD format to select from
  • label: Title displayed in the admin backend for the field
  • max: Maximum allowed date in YYYY-MM-DD format
  • min: Minimum allowed date in YYYY-MM-DD format
  • multiple: True/false value if selecting multiple dates is allowed
  • placeholder: Text shown in the empty date field
  • required: True/false value if a date must be selected
'event_date' => [
    'type' => 'date',
    'label' => 'Event Date',
    'min' => '2024-01-01',
    'max' => '2024-12-31',
    'required' => true,
],

file

For selecting a generic file.

  • accept: Accepted mime type, e.g. application/pdf
  • label: Title displayed in the admin backend for the field
  • required: True/false value if a file must be selected
'document' => [
    'type' => 'file',
    'label' => 'Upload Document',
    'accept' => 'application/pdf',
    'required' => false,
],

hidden

A hidden field that's not visible in the UI, useful for passing data e.g. to actions.

'action' => [
    'type' => 'hidden',
    'value' => '\Aimeos\Cms\Actions\Blog',
],

html

For HTML input.

  • label: Title displayed in the admin backend for the field
  • placeholder: Text shown in the empty text field
'custom_html' => [
    'type' => 'html',
    'label' => 'Custom HTML',
    'placeholder' => '<p>Enter your HTML content here...</p>',
],

image

For selecting an image file.

  • accept: Accepted mime type, e.g. image/jpeg
  • label: Title displayed in the admin backend for the field
  • required: True/false value if an image must be selected
'profile_image' => [
    'type' => 'image',
    'label' => 'Profile Image',
    'accept' => 'image/jpeg, image/png',
    'required' => true,
],

images

For selecting multiple images in a specific order.

  • accept: Accepted mime type, e.g. image/webp
  • label: Title displayed in the admin backend for the field
  • max: Maximum number of images allowed
  • min: Minimum number of images required
'gallery_images' => [
    'type' => 'images',
    'label' => 'Gallery Images',
    'accept' => 'image/webp, image/jpeg',
    'min' => 2,
    'max' => 5,
],

items

For creating a list of structured items.

  • item: Associative array (key is the data name) defining the item that can contain these settings:
    • type: One of the available field types (required)
    • label: Title displayed in the admin backend for the field
    • max: Maximum number of characters/items allowed
    • min: Minimum number of characters/items required
    • placeholder: Text shown in the empty text field
  • label: Title displayed in the admin backend for the field
  • max: Maximum number of items allowed
  • min: Minimum number of items required
'team_members' => [
    'type' => 'items',
    'label' => 'Team Members',
    'min' => 1,
    'max' => 3,
    'item' => [
        'name' => [
            'type' => 'string',
            'label' => 'Full name',
            'min' => 3,
            'max' => 100,
            'placeholder' => 'Enter full name',
            'class' => 'name-field',
        ],
        'position' => [
            'type' => 'string',
            'label' => 'Position',
            'min' => 2,
            'max' => 50,
            'placeholder' => 'Enter position',
            'class' => 'position-field',
        ],
        'image' => [
            'type' => 'image',
            'label' => 'Team Member Image',
            'accept' => 'image/jpeg, image/png',
            'required' => false,
        ],
        'description' => [
            'type' => 'text',
            'label' => 'Description',
            'placeholder' => 'Enter description',
        ],
    ],
],

markdown

For rich text formatting.

'description' => [
    'type' => 'markdown',
    'label' => 'Description',
],

number

For numeric input.

  • default: Value used by default
  • label: Title displayed in the admin backend for the field
  • max: Maximum number allowed
  • min: Minimum number required
  • placeholder: Text shown in the empty number field
  • required: True/false value if a valid number is required
  • step: Allowed steps when incrementing/decrementing, e.g. "10", "1", "0.1", "0.01" or any number in between
'quantity' => [
    'type' => 'number',
    'label' => 'Quantity',
    'min' => 1,
    'max' => 100,
    'default' => 1,
    'required' => true,
],

plaintext

For plain text input without formatting.

  • class: CSS class to apply to the input field
  • label: Title displayed in the admin backend for the field
  • max: Maximum number of characters allowed in the input field
  • min: Minimum number of characters required in the input field
  • placeholder: Text shown in the empty text field
'username' => [
    'type' => 'plaintext',
    'label' => 'Username',
    'min' => 3,
    'max' => 50,
    'placeholder' => 'Enter your username',
    'class' => 'username-field',
],

radio

A radio button group.

  • label: Title displayed in the admin backend for the field
  • options: List of associative arrays with "label" and "value" keys
  • required: True/false value if a selected option is required
'plan' => [
    'type' => 'radio',
    'label' => 'Choose your plan',
    'options' => [
        ['label' => 'Basic', 'value' => 'basic'],
        ['label' => 'Pro', 'value' => 'pro'],
        ['label' => 'Enterprise', 'value' => 'enterprise'],
    ],
    'required' => true,
],

range

A range slider where start and end value can be selected.

  • label: Title displayed in the admin backend for the field
  • max: Maximum number allowed
  • min: Minimum number required
  • step: Steps available when changing the range slider, e.g. "10", "1", "0.1", "0.01" or any number in between
'price_range' => [
    'type' => 'range',
    'label' => 'Price Range',
    'min' => 0,
    'max' => 1000,
    'step' => 10,
],

select

A dropdown list.

  • label: Title displayed in the admin backend for the field
  • multiple: True/false value if selecting multiple items is allowed
  • options: List of associative arrays with "label" and "value" keys
  • placeholder: Text shown in the empty select field
  • required: True/false value if a selected option is required
'category' => [
    'type' => 'select',
    'label' => 'Category',
    'options' => [
        ['label' => 'Technology', 'value' => 'tech'],
        ['label' => 'Design', 'value' => 'design'],
        ['label' => 'Marketing', 'value' => 'marketing'],
    ],
    'placeholder' => 'Select a category',
    'required' => true,
],

slider

A slider for a single value.

  • label: Title displayed in the admin backend for the field
  • max: Maximum number allowed
  • min: Minimum number required
  • step: Steps available when changing the slider, e.g. "10", "1", "0.1", "0.01" or any number in between
'discount' => [
    'type' => 'slider',
    'label' => 'Discount',
    'min' => 0,
    'max' => 50,
    'step' => 1,
],

string

A simple text field with no formatting options.

  • class: CSS class to apply to the input field
  • label: Title displayed in the admin backend for the field
  • max: Maximum number of characters allowed in the input field
  • min: Minimum number of characters required in the input field
  • placeholder: Text shown in the empty text field
'title' => [
    'type' => 'string',
    'label' => 'Title',
    'min' => 5,
    'max' => 100,
    'placeholder' => 'Enter title',
    'class' => 'title-field',
],

switch

A toggle switch.

  • label: Title displayed in the admin backend for the field
  • off: Value if unchecked
  • on: Value if checked
'is_active' => [
    'type' => 'switch',
    'label' => 'Active',
    'on' => 'true',
    'off' => 'false',
],

table

For creating a table with several rows and columns.

  • label: Title displayed in the admin backend for the field
  • min: Minimum number of columns required
  • placeholder: Text shown in the empty text field
  • required: True/false value if table data is required
'pricing_table' => [
    'type' => 'table',
    'label' => 'Pricing Table',
    'min' => 2,
    'required' => true,
],

text

For text input with limited formatting options (bold, italic, links).

  • label: Title displayed in the admin backend for the field
'body' => [
    'type' => 'text',
    'label' => 'Body',
],

url

For URL input.

  • allowed: URI schemas allowed for URLs (default: "http" and "https")
  • label: Title displayed in the admin backend for the field
  • placeholder: Text shown in the empty text field
  • required: True/false value if URL is required
'website' => [
    'type' => 'url',
    'label' => 'Website URL',
    'placeholder' => 'Enter website URL',
    'required' => false,
],

video

For selecting a video file.

  • accept: Accepted mime type, e.g. "video/mp4"
  • label: Title displayed in the admin backend for the field
  • required: True/false value if a file must be selected
'promo_video' => [
    'type' => 'video',
    'label' => 'Promotional Video',
    'accept' => 'video/mp4, video/webm',
    'required' => true,
],