Search by

digitaledinge / contao-company

zoglo

Manage company information globally and display it across one or more domains using Twig templates or insert tags.

Package info

github.com/Digitale-Dinge/contao-company

Issues

Forum

Type:contao-bundle

pkg:composer/digitaledinge/contao-company

Statistics

Installs: 19

Dependents: 1

Suggesters: 0

Stars: 0

0.1.0.2 2026-09-17 08:19 UTC

This package is auto-updated.

Last update: 2026-09-18 15:23:13 UTC


README

github version amount of downloads minimum php version

Description

Manage companies and render company information across multiple domains.

Setup

  1. Create a company

    Navigate to Content → Companies and create your company, filling in the details you want to make available across your site.

  2. Assign to a root page

    For the company Twig global and insert tags to resolve automatically based on the current page context, assign your company to the respective root page under Layout → Site Structure → Edit root page → Company.

  3. Use in templates, RTE or as content elements

    Company data is available in Twig via the company global and in text via insert tags. Additional content elements for Opening times and schema.org exist.

  4. Optional: time zone

    Opening times are values in the company's time zone. Leave the field empty to use the time zone from the Contao system settings. Set it when a company sits in a different zone than the app.

Insert Tags

Your company information can be displayed using the following insert tags.

There are two available insert tag prefixes. Use {{company::...}} to display the company associated with the current page context, or {{company_id::ID::...}} to target a specific company by its ID.

Examples

{{company::name}}
{{company::phone}}
{{company_id::5::name}}
{{company_id::5::phone}}

Company Details

These insert tags return raw field values directly from the company record.

Insert tag Description
{{company::logo}} Renders the company logo (company/logo.html.twig)
{{company::name}} Displays the company name
{{company::street}} Displays the street
{{company::postal}} Displays the postal code
{{company::city}} Displays the city
{{company::state}} Displays the state
{{company::country}} Displays the country

Any field on the company model can be accessed this way via {{company::FIELD_NAME}}.

Phone Numbers

Phone numbers are stored as a list and can be accessed by their position (1-based index) as configured in the backend.

Insert tag Description
{{company::phone}} Displays the first phone number
{{company::phone::2}} Displays the second phone number
{{company::tel}} Renders the first phone number as a <a href="tel:..."> link
{{company::tel::2}} Renders the second phone number as a tel: link

Fax Numbers

Insert tag Description
{{company::fax}} Displays the first fax number
{{company::fax::2}} Displays the second fax number

E-mail Addresses

Insert tag Description
{{company::mail}} Displays the first e-mail address
{{company::mail::2}} Displays the second e-mail address
{{company::mailto}} Renders the first e-mail address as a <a href="mailto:..."> link
{{company::mailto::2}} Renders the second e-mail address as a mailto: link

Websites

Insert tag Description
{{company::website}} Displays the first website URL
{{company::website::2}} Displays the second website URL

Address

Insert tag Description
{{company::address}} Renders the full address block (company/component/_address.html.twig)
{{company::address::name}} Renders the full address block including the company name

Logo

Insert tag Description
{{company::logo}} Renders the company logo
{{company::logo::my-class}} Renders the company logo with an additional CSS class

Social Media

Insert tag Description
{{company::socials}} Renders the full social media list (company/social_media.html.twig)
{{company::social::facebook}} Renders a link for the social media entry with the key facebook

Additional Fields

Insert tag Description
{{company::additional}} Displays the first additional field value
{{company::additional::2}} Displays the second additional field value

Opening Status

Insert tag Description
{{company::is_open}} Renders the current open/closed status (company/component/_opening_status.html.twig)

The status is computed in the browser against the company's time zone.

Targeting a Specific Company by ID

All of the above insert tags are also available with company_id, passing the company ID as the first parameter:

{{company_id::5::name}}
{{company_id::5::tel}}
{{company_id::5::tel::2}}
{{company_id::5::mailto::2}}
{{company_id::5::address::name}}
{{company_id::5::logo::my-class}}
{{company_id::5::social::facebook}}
{{company_id::5::is_open}}

Content Elements

Leave the company selection empty to use the company assigned to the current root page, or pick one explicitly.

Opening times

Renders the weekly schedule as a table, the closing periods as a list, and the live open/closed status. Options:

Option Description
Company Explicit company, or empty for the current root page's company
Abbreviated weekdays Mon instead of Monday, localized via ICU

Template variants, selectable in the element's template dropdown:

Template Output
content_element/company_opening_times All seven days, closed days read "Closed"
content_element/company_opening_times/open_only Days without opening times are left out
content_element/company_opening_times/grouped Consecutive days with identical times collapse: Mon–Fri 08:00–17:00

The templates work on a spatie/opening-hours object.

{% for day, hours in opening_times.openingHours.forWeek %}
    {{ day|format_datetime(pattern: 'EEEE') }}:
    {% for range in hours %}{{ range.start }}–{{ range.end }}{% else %}closed{% endfor %}
{% endfor %}

Overlapping ranges entered in the backend are merged, so 08:00–13:00 and 12:00–17:00 become 08:00–17:00.

Structured data

Adds a schema.org LocalBusiness or Organization node to the page's JSON-LD and renders nothing visible. Options:

Option Description
Company Explicit company, or empty for the current root page's company
Type LocalBusiness (default) or Organization
URL Used as url and @id. Empty uses the absolute URL of the current root page

Mapped fields: name, url, @id, logo, address as PostalAddress, first telephone, first faxNumber, first email, vatID, all socials as sameAs. Opening hours (openingHoursSpecification) and closing periods (specialOpeningHoursSpecification, closed days as 00:0000:00) are added for LocalBusiness only, since they are not Organization properties. Multiple elements for the same company on one page merge into one schema org node.

Twig Global

The company variable is available globally in all Twig templates. It provides access to the company associated with the current page context, or to a specific company by ID.

Get the company model

In some cases you want to access one value like company.name. If you want to use more values of the company, you can get the full company model by using company.get and access the values directly.

{# Current page context #}
{% set company_model = company.get %}

{# Specific company by ID #}
{% set company_model = company.get(5) %}

Simple fields

Simple fields are accessed directly as properties on the model:

{% set company_model = company.get %}

{{ company_model.name }}
{{ company_model.street }}
{{ company_model.postal }}
{{ company_model.city }}
{{ company_model.state }}
{{ company_model.country }}
{{ company_model.logo }}

Serialized lists

The following properties return serialized strings on the model and must be deserialized first. When accessing lists directly via the company global, deserialization is handled automatically.

{% set company_model = company.get %}

{% for row in company_model.emails|deserialize|default([]) %}
    {{ row.email }}
{% endfor %}

{% for row in company_model.phone_numbers|deserialize|default([]) %}
    {{ row.phone }}
{% endfor %}

{% for row in company_model.fax_numbers|deserialize|default([]) %}
    {{ row.fax }}
{% endfor %}

{% for row in company_model.websites|deserialize|default([]) %}
    {{ row.website }}
{% endfor %}

{% for row in company_model.socials|deserialize|default([]) %}
    {{ row.social }} {# platform label #}
    {{ row.url }}
{% endfor %}

{% for row in company_model.additional|deserialize|default([]) %}
    {{ row.key }}
    {{ row.value }}
{% endfor %}

Alternatively, the company global exposes these directly as pre-deserialized arrays — without needing a model instance:

{% set emails = company.emails %}
{% set phone_numbers = company.phone_numbers %}
{% set fax_numbers = company.fax_numbers %}
{% set websites = company.websites %}
{% set socials = company.socials %}
{% set additional = company.additional %}

For a specific company by ID, get the model first and then deserialize:

{% set company_model = company.get(5) %}
{% set emails = company_model.emails|deserialize %}
{% set socials = company_model.socials|deserialize %}

Accessing entries of a list

Lists are arrays, so the first item is at index 0, the second at 1, and so on. Note that direct index access works on the pre-deserialized company.* properties. When using company_model.*, deserialize first.

{# Via company global (already deserialized) #}
{% set first_email = company.emails[0].email ?? null %}
{% set third_email = company.emails[2].email ?? null %}

{# Via company model (deserialize first) #}
{% set first_email = company_model.emails|deserialize[0].email ?? null %}
{% set third_email = company_model.emails|deserialize[2].email ?? null %}

Alternatively, use the |first Twig filter as a shorthand for the first entry:

{% set first_email = company.emails|first?.email ?? null %}
{% set first_phone = company.phone_numbers|first?.phone ?? null %}

Social media

Each social media entry exposes social (platform label) and url.

{% for row in company.socials %}
    {{ include('@Contao/company/component/_link.html.twig', {
        link: row.social,
        href: row.url,
        title: row.social,
        target_blank: true,
    }) }}
{% endfor %}

Events

AddSocialMediaOptionsEvent

This event is dispatched whenever the social media options are built — both in the backend select field and when resolving insert tags. It allows you to replace the default social media options with your own.

The following platforms are available by default:

Group Platforms
General Facebook, Instagram, LinkedIn, Xing, Threads, Mastodon
Video YouTube, Vimeo, TikTok, Twitch
Creative Pinterest, Behance, Reddit
Development GitHub, GitLab

To add or replace platforms, create an event listener and call setSocialMedia() with your own grouped array:

<?php

declare(strict_types=1);

namespace App\EventListener;

use DigitaleDinge\CompanyBundle\Event\AddSocialMediaOptionsEvent;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;

#[AsEventListener]
class CustomSocialMediaListener
{
    public function __invoke(AddSocialMediaOptionsEvent $event): void
    {
        $event->setSocialMedia([
            'General' => [
                'facebook'  => 'Facebook',
                'instagram' => 'Instagram',
            ],
            'Custom' => [
                'myplatform' => 'My Platform',
            ],
        ]);
    }
}

Note that calling setSocialMedia() replaces all defaults. If you want to keep the existing platforms, retrieve them first via getSocialMedia() and merge your additions in.

public function __invoke(AddSocialMediaOptionsEvent $event): void
{
    $existing = $event->getSocialMedia();

    $event->setSocialMedia(array_merge($existing, [
        'Custom' => [
            'myplatform' => 'My Platform',
        ],
    ]));
}