Working with an instance
Install the module, create or open an instance, give it a readable name, select a file template, complete settings and language tabs, then bind the instance to a page label. For example, one Menu module can supply header, mobile, and footer navigation through separate instances. For a native instance, the CMS discovers editor fields from %field% variables in the selected template: shared fields are in @wrapper and repeating-item fields in @item.
Menus and breadcrumbs
Menu builds items automatically from the site tree, respecting language, SEO URL mode, page visibility, and the active item. Configure the starting page, tree depth, and file template. Use separate instances for top, mobile, and footer menus if their markup or scope differs.
Breadcrumbs builds a trail from the root to the current page. Settings control inclusion of the home and current pages, whether to display the trail on home, the default delimiter, and the file template. In Schema.org BreadcrumbList, every step must be a separate ListItem with name and position; the link has itemprop=item. Google permits the final step to omit item.
Content and repeating blocks
A single Content Block contains named fields such as title, text, link, image, or other template-specific data. A title field resolves as %title%; translated values are entered in separate tabs. Repeating Blocks work for services, team members, and benefits. Items can be added, ordered, disabled, and deleted, and can have translated fields and images.
Put %items% in @wrapper: it is the completed HTML of all active items. @item describes one card, which needs its own article or div container so that its parts do not become separate CSS Grid cells. Lower Order values appear first. A disabled item remains editable but is hidden publicly. Delete takes effect after saving. Removing %email% from @item hides its field in the editor but retains its saved value; restoring the variable reveals it again.
Slider, gallery, and image variants
A slide has an image, title, description, button, link, order, and status; each slide's translations are in language tabs. Basic variables include %image%, %image_large%, %image_small%, %link_big_image%, %title%, %description%, and %text%. Imported sliders can also expose their original keys through the compatibility layer. Gallery supports translated titles and descriptions and its own wrapper and item sections.
For Gallery, Blog, and Slider, the CMS keeps the original image and creates two proportional variants. Configure widths on the instance: %image_large% is for full-size display and %image_small% for cards and lists. The older %image% remains for compatibility.
Social Buttons
Edit an instance under Site Modules → Social Buttons. Each button can have a name, URL, icon CSS class or media-library image, order, active state, new-window setting, and nofollow. Internal links and HTTP/HTTPS external URLs are allowed. New-window links automatically receive noopener noreferrer. Network names are often language-independent, but the container label is localized for UK, RU, and EN. Template variables are %items%, %aria_label%, %network%, %url%, %title%, %media%, %target%, and %rel%.
Blog
Each modular Blog instance has its own posts. A post has a slug, date, active state, shared image, and translated title, summary, full HTML, author, and link labels. A future date postpones publication; a post without a title in the current language is hidden. Configure posts per page and date format on the instance; pagination is automatic. Feed and detail use one file template with @wrapper, @item, @detail, @empty, @item_image, @detail_image, @pagination, @page, and @page_current sections. Key variables include %items%, %pagination%, %url%, %title%, %summary%, %content%, %image%, %image_large%, %image_small%, %image_block%, %author%, %date%, %published_at%, %read_more%, %back_label%, and %back_url%.
Feedback and code injections
Use the unified feedback module for new forms. One instance represents one form. Each language has its own heading, labels, hints, list options, button, and messages. Email and Telegram are enabled independently. With Save submissions in CMS enabled, no external channel is required: requests go to the private log storage/modules/feedback/submissions/<instance>.jsonl. After success, the form can show a modal message or redirect to a selected site page.
The public handler uses CSRF, a honeypot, rate limiting, and server-side validation. Pages with a form, even one inside a modal, are excluded from HTML cache so the token and verification question belong to the current session. Older feedback_email and feedback_telegram packages remain only for compatibility. The standard template's accent can be overridden using --primo-feedback-accent.
Code Injections places trusted analytics scripts, pixels, meta tags, and other snippets in the head, the start of body, or the end of body. Review public pages after a change. Create a new file template from the instance editor; it stays in the current module's directory. Select it and check all languages afterward.
A module is a type of functionality; an instance is one concrete configuration. For example, the Menu module can have separate instances for the header, mobile navigation, and footer. The usual workflow is to install the module, create an instance, choose a file template, enter settings and translated fields, and bind the instance to a page label.
New instances live in storage/modules/<id>/instances/<instance>.json and uploaded images in uploads/media/modules/<id>/<instance>. Templates are isolated under modules/<id>/templates/. Imported legacy instances use a separate compatibility adapter; their data is not the schema for new ones.
Navigation and content
Menu builds its items from the site tree, respecting language, page visibility, nesting depth, and the active item. Breadcrumbs builds a trail to the current page; a custom template may use BreadcrumbList structured data with a separate ListItem for each step.
Content Blocks stores one set of named fields. Repeating Blocks stores ordered, active or inactive items with images and translations. Shared fields belong to @wrapper and item fields to @item. %items% inserts the rendered active items into the wrapper. Removing a variable from the template hides its field in the editor but does not delete saved data.
Media and publications
Slider has slides with images, text, buttons, ordering, and active status. Gallery supports translated captions. Each Blog instance has its own posts with a slug, publication date, shared image, and translated title, summary, and full text. A future-dated post appears on schedule; a post without a title in the current language is not published. Blog templates support @wrapper, @item, @detail, @empty, and pagination sections.
For Blog, Gallery, and Slider the CMS stores the original image and creates proportional large and small variants. Use %image_large% for full-size display and %image_small% for cards; %image% remains for compatibility.
Contact and external code
Social Buttons store a name, URL, icon class or media image, order, status, new-window choice, and nofollow. External URLs must use HTTP or HTTPS; new-window links receive noopener noreferrer automatically.
Use the feedback module for new forms. It supports Email, Telegram, or a private submissions log only, plus translated fields, CSRF protection, a honeypot, rate limiting, and server-side validation. Pages containing a form are not cached as static HTML. The Code Injections module inserts trusted scripts, pixels, and meta tags into configured page positions.
Create a new module template from the instance editor so the file stays inside that module's directory. Recheck every active language after making changes.

← Documentation