Ynfinite - Documentation

Ynfinite - Documentation

  • Users
  • Developers

Developer Documenation

Writing templates

Every page that is rendered by Ynfinite is build with a number of templates. Those templates are basic HTML and CSS code which is then injected with an data object containing all the information you gathered in your site, your page and the sections. The templates are rendered using the TWIG template engine. You can find more information about TWIG here.

Ynfinite provides a basic layout template which contains all the basics you need to build your website with Ynfinite. It adds the necessary head meta information and renders the sections.

Layout template

All templates go into the web/templates folder of your website client. The template you selected in your Layout is the index which is rendered first. This template is the starting point for all other page rendering. You can add your javascript and css here as well as other changes that you need for your site to work. To do this you need to extend the basic Ynfinite layout template. After that you can access the blocks of the layout template to add additional code.

{% extends "layout/index.twig" %} // 1

{% block head %}
  {{ parent() }}
  <link href="web/public/css/app.css" rel="stylesheet" />
{% endblock head %}

{% block body %}
    <main class="site__content">
        {{ parent() }} // 2
    </main>
{% endblock body %}

{% block footer_scripts %}
    {{ parent() }}
    <script type="text/javascript" src="web/public/js/app.min.js"></script>
{% endblock footer_scripts %}

AS shown here the first thing you want to do is extending the Ynfinite layout template (1). There are advanced solutions where you might want to render your own template without extending Ynfinites basic template. We recommend not doing this unless you really know what to do. It is also important to mention that you need to call the parent() function in all the blocks you extend (2). In the body block, the parent() function renders all the sections of the current page.

Override standard templates (Ynfinite CMS client)

If you are using the Ynfinite CMS Standard client you can override all the standard templates using the tplConfig.php file. There you can create a varaible called $yn_templateOverrides which is an array with the template identifier as a key and the new template name as a value;

<?php

    $yn_templateOverrides = array(
        "form:fields.dateTime-local" => "forms/fields/dateTime-local.twig"
    );

?>

There are only a few standard templates which can be overriden (the other simple do not need overriding!)

    $this->standardTemplates = array(
      "article:article" => "yn/components/article.twig",
      "article:headline" => "yn/components/article/headline.twig",
      "article:text" => "yn/components/article/text.twig",
      "article:images" => "yn/components/article/images.twig",
      "article:video" => "yn/components/article/video.twig",
      "images:image" => "yn/components/image.twig",
      "images:figure" => "yn/components/figure.twig",
      "form:form" => "yn/components/form.twig",
      "form:fields.select" => "yn/components/form/select.twig",
      "form:fields.radio" => "yn/components/form/radio.twig",
      "form:fields.checkbox" => "yn/components/form/checkbox.twig",
      "form:fields.datetime-local" => "yn/components/form/datetime-local.twig",
      "form:fields.month" => "yn/components/form/month.twig",
      "form:fields.date" => "yn/components/form/date.twig",
      "form:fields.time" => "yn/components/form/time.twig",
      "form:fields.week" => "yn/components/form/week.twig",
      "form:fields.color" => "yn/components/form/color.twig",
      "form:fields.number" => "yn/components/form/number.twig",
      "form:fields.range" => "yn/components/form/range.twig",
      "form:fields.text" => "yn/components/form/text.twig",
      "form:fields.textarea" => "yn/components/form/textarea.twig",
      "form:fields.tel" => "yn/components/form/tel.twig",
      "form:fields.url" => "yn/components/form/url.twig",
      "form:fields.email" => "yn/components/form/email.twig",
      "form:fields.password" => "yn/components/form/password.twig",
      "form:fields.file" => "yn/components/form/file.twig",
      "form:fields.complexFormField" => "yn/components/form/complexFormField.twig",
      "form:fields.hidden" => "yn/components/form/hidden.twig",
      "form:fields.spacer" => "yn/components/form/spacer.twig",
      "form:fields.description" => "yn/components/form/description.twig",
      "form:fields.basic" => "yn/components/form/basic.twig"
    );

Data Object

As mentioned before Ynfinite injects a data object into all templates that are rendered when a given page is called. It contains a lot of information which will be explained step by step in the following chapters.

Basic Usage

To access the data object you need to use TWIG placeholders. A placeholder looks like this {{path.to.the.needed.data}}. You can use those placeholders in whatever part of the template you see fit.

For example, a basic template for a news content could look like this

{% set news = _ynfinite.content %} <!-- 1 -->

<div class="single-news">
    <h3>{{news.data.general_headline}}</h3> <!-- 2 -->
    <figure>
       <img src="{{news.data.general_image[0].path" alt="{{news.data.general_image[0].meta.alt}}" /> <!-- 2 -->
    </figure>
    <div class="news-content">
       {{news.data.general_text|raw}} <!-- 3 -->
    </div>
</div>

In this example we use _ynfinite, which is the source of most data. It is good practice to pull out the information you need in your templates (1) to reduce the amount of writing you need to do. This is totally optional and if you are fine with more writing you can skip this step. After we pulled out the information we need, we use it at several places in the template to place the information we need (2). For the news text (3) we use a TWIG filter to transform the content into a raw form because the text of the news is HTML code.

Now that you know the basic usage, lets go through all the different keys you can find in the _ynfinite object.

Globals

In you site you can add custom fields which are used as global data in every template that is part of the site. It does not matter if it is a page, an email or a notification. As long as the template is used in your site, it will have the global data defined in the site.

A google maps api key would be a good example for global data. And here is a quick example how to use it.

{% set global = _ynfinite.global %}

<div class="google_maps_container">
    <iframe
        width="600"
        height="450"
        frameborder="0" style="border:0"
        src="https://www.google.com/maps/embed/v1/place?key={{global.general_gmaps_api_key}}&q=Overstolzenstr. 2, Köln Deutschland"
        allowfullscreen> <!-- 1 -->
    </iframe>
</div>

As you can see, you can use the placeholders also as part of an attribute in a html tag (1)

Section

Each page is a composition of sections. Each section can have its own custom data which can be created by adding a section type. To access this data you would need to pull the right section out of the page data. This would be unnecessary hard, so Ynfinite provides you with a shortcut to this. section contains all the data of the section you are currently in.

So, for example, if your site contains three sections intro, news and contact each of those sections would access its own data with section. Ynfinite injects the section template with the correct data. Accessing the data is the same as you would do with all other data.

{% set hasImage = section.data.general_image|length %} <!-- 1 -->

<div class="section">
    <div class="inner-container">
        <div class="row">
            {% if hasImage %} <!-- 1 -->
                <div class="col-6">
                    <figure>
                        <img src="{{section.data.general_image[0].path" alt="{{section.data.general_image[0].meta.alt}}" />
                    </figure>
                </div>
            {% endif %}
            <div class="{% if hasImage %}col-6{% else %}col-12{% endif %}"> <!-- 1 -->
                <h2>{{section.data.general_headline}}</h2>
                {{section.data.general_text|raw}}
            </div>
        </div>
    </div>
</div>

In this more complex example of a section we not only use the section data to build our section, we also decide if the section should render with two columns or only one depending on wether the section has an image or not (1). This is a important concept in Ynfinite. If you create your section types right you can build complex websites with very little types and very little templates by reusing them and give your customer the ability to decide how a section should look depending on their choices.

You can also access other section data using the _yfunc::sectionByAlias function.

Functions

Ynfinite provides a TWIG function component called _yfunc. This function provies a hugh amount of helpfull features to enhance your expirience when working with templates in Ynfinite.

The basic usage is to use _yfunc(method_name)

<a href="{{_yfunc("linkPage", "news", "my-news-alias")}}>

Handling images

Images are always a very delicate thing. They need to be responsive, optimized for search engines and they need to be accessible. Ynfinite takes care of this for you.

{{_yfunc("printImage", slide.data.teaser_bild[0], [{"w":454, "screenSize":1024},{"w":390, "screenSize":400},{"w":338}])}}

With the _yfunc("printImage") function, Ynfinite will write the correct markup for an image. It will print the necessary alt tags and descriptions as well as the author of the image. It will use the data you editor put into the Ynfinite filemanager.

Access sections within the page

The sectionByAlias function loads the data of another section on the same page by its alias. You can find the section alias in every section.

{% set mySection= _yfunc("sectionByAlias", "my_section_alias") %}

<h1>{{mySection.data.general_headline}}</h1>

Handle Article fields

Article fields are a number of components which have a type as well as configurations and values. You could just go over the article fields by youself using a for-loop. For an easier access the Ynfinite CMS Client provides a twig render function _yfunc("renderArticle", data.general_articleFieldName) which takes care of the loop for you and renders the article using a number of standard templates.

You can overload the standard template fields using the standard template override array. All article template aliases are found in the article namespace ("article:*")

<div class="my-article-wrapper">
    {{_yfunc("renderArticle", _ynfinite.content.data.general_article)}}
</div>

Listing pages

On listing pages you most likely need a pagination as well as a dropdown with the option to show how many items per page you want to show. While you could build those features by your own using the _ynfinite.pagination data, Ynfinite provides easy _yfunc methodes to create a standard markup which you can use.

Pagination

    {{_yfunc("pagination")}}

Creates a working pagination using the listing data and the pagination information.

PerPageDropdown

    {{_yfunc("perPageDropdown")}}

Creates a drop down with the per page options you definied in the listing page. The standard value is the limit or the first item in the options list.

Forms

Print forms and fields

To print a form template you need to use the _yfunc("form") methode. It will output a form using the form template you provided in the form config in Ynfinite.

<section class="newsletter-contact">
    <div class"inner">
        {{_yfunc("form", section.data.general_form, section)}}
    </div>
</section>

The form template should contain only the content which is directly in the form, not the form tag itself. The form is added by Ynfinite. You can add a form to a section by adding a form field either to the section itself or the template. The form field is given to the _yfunc("form") methode as second paramter.

The section can be added as a third parameter. It will be injected in the form and all notfications sent by this form. The section is optional.

Fields

In the form template you can use the form.fields object where you can access the fields of your form by their respective aliases. You can build whatever markup you want using the data in the field or you can use the _yfunc("formField") method to print the Ynfinite standard markup.

<div class="form-wrapper">
    {{_yfunc("formField", form.fields['general_name'])}}
    {{_yfunc("formField", form.fields['general_firstname'])}}
    {{_yfunc("formField", form.fields['general_e-mail'], false)}} <!-- 2 -->
</div>

The second boolean parameter (1) decides if the _yfunc("formField") method prints a widget markup around the field. False means no widget is printed.

Here is a complete dump of a form field with all data you can use to build your own markup. The field names need to be fields[{{field.alias}}]

array(9) {
  ["label"]=> string(11) "Ich möchte"
  ["alias"]=> string(16) "general_anliegen"
  ["type"]=> string(6) "select"
  ["defaultValue"]=> string(0) ""
  ["value"]=> string(0) "" // The value which is set in the url parameters _y.fields.general_anliegen="kaufen"
  ["placeholder"]=> string(0) ""
  ["attributes"]=> string(19) "class="select2-box""
  ["required"]=> bool(true)
  ["grid"] => {
      ["x"] => number
      ["y"] => number
      ["w"] => number
      ["h"] => number
  }
  ["items"]=> array(2) {
    [0]=> array(2) {
      ["label"]=> string(6) "Kaufen"
      ["value"]=> string(6) "kaufen"
    }
    [1]=> array(2) {
      ["label"]=> string(9) "Verkaufen"
      ["value"]=> string(9) "verkaufen"
    }
  }
}

If you don't want to think about the fields and what you can do with them, Ynfinite can take care of this for you. To use the Ynfinite form renderer, just use _yfunc("renderFields", form, section, [...addData]). The second parameter is the form data of whatever form you want to render. Ynfinite will render a representation of your form that matches the form you built in Ynfinite.

The function takes a third argument which is an object of values which are used to populate the field with the corrosponding key. It is meant for special cases where you need to generate additional data in the frontend which Ynfinite can not know about. We caution you to reduce the amount of those cases to a minimum since it requires you to change the templates when the form changes.

For example:

    {% set domain = _ynfinite.currentDomain %}
    {% set lang = _ynfinite.languages.current %}
    {% set referrer = domain ~ _ynfinite.languages.urls[lang] %}

    {{ _yfunc("renderFields", form, section, {general_referrer: referrer|default(null)}) }}

This would add a referrer taken from the _ynfinite array and add it to the form as a hidden field. The hidden field needs to be present in the form.

You can also render a single group of a form by using the _yfunc("renderGroupByAlias", form, section, "alias", [...addData]). It will do the same as the renderFields function but only for the fields that are included in the given group. The group is defined by its alias.

Consents

To print out the consents for the form you can use the shortcut method _yfunc("consents")

<div class="form-wrapper">
    {{_yfunc("formField", form.fields['general_name'])}}
    {{_yfunc("formField", form.fields['general_firstname'])}}
    {{_yfunc("formField", form.fields['general_e-mail'])}}

    <div class="my-consents-wrapper">
        {{_yfunc("consents", form)}}
    </div>
</div>

You can also build your own consent checkboxes by using the data provided in _ynfinite.consents, in which case you need to make sure the field names are always consent.{{consent.alias}}

Events

Each for execute events. Currently there are onSubmit, which will be fired when the form is submitted and onChange, which will be fired when a field in the form is changing. Every event can be async if you'd like too. To make a event async, just check the corrosponding switch and the Ynfinite Client will handle everything else for you.

Async events have a response template, this is the template that is rendered by the client befor the request is given back to the browser. You can find the result in response.rendered.

It is common to use this content and replace a certain part of the website, like a list or a form. You could, however, also create JSON data from it or do something completly different with the response.

In the response templates you can access all the data the request has:

    {
        request: {} // The formData from the frontend
        form: {} // The form and all its fields
        page: {} // The page the form was sent from
        content: {} // The main content of the page the form was sent from
        section: {} // The section in which the form was placed
        consents: [] // A list of all consents that where given when the form was sent.
        lead: {} // If a lead was created by the form, you can access it here. It has all the data we know about the lead.
        notifications: {} // The responses of all previouse notifications (when RestAPI). You can access them via their aliases.
    }

If the form has the post method, each event can also execute a process. Processes are described in the "Processes" chapter.

Handling async forms in the PHP client

The PHP client provides prebuild features to handle the common problems you need to deal with when you work with async search forms. The form handling of the PHP client triggers a few extra events which you can work with:

  • onPreAsyncChangeData: This event is triggered befor data is collected from the form. You can make last minute changes to the form data in this event.
  • onPreAsyncChange: This event is triggered just befor the data is sent to the server.
  • onAsyncChange: This event is triggered after the server has responded. It contains the data the server responded with. You can access it by using event.detail.response.
// Response of an async form event

{
    rendered: "" // The rendered html string of the asyncTemplate,
    listingForm: {} // The new configuration of the listing form, if present
    pagination: {} // The new pagination of the page, if present
}

To handle common form problems you can use the built-in form handling functions which can be found in the window.$_yn.forms object.

  • updateUrl (window.$_yn.forms.updateUrl(HTMLElement form)): This function updates the current url by adding all form field values using the history API
  • repopulate (window.$_yn.forms.repopulate(HTMLElement form, Mixed data)): This function rebuilds the form using the provided form data. Currently the call is always the same: repopulate(form, response.listingForm)
  • enable (window.$_yn.forms.enable(HTMLElement form)): Enables the given form.
  • disable (window.$_yn.forms.disable(HTMLElement form)): Disables the given form.

Here is a full example of how to handle async forms:

    <!-- forms/search.twig -->
    <div class="form form--filter" id="form_immo_wrapper">
        {{ _yfunc("renderFields", form, section) }}

        <div class="widget__submit text-left">
            <button type="submit" class="button">Ergebnisse anzeigen</button>
            <button type="reset" class="button">Filter aufheben</button>
        </div>
    </div>

    <script>
        (function() {
            const form = document.querySelector("#form_immo_wrapper").closest("form");

            form.addEventListener("onPreAsyncChangeData", function(e) {
                window.$_yn.forms.updateUrl(this)
            })

            form.addEventListener("onPreAsyncChange", function(e) {
                window.$_yn.forms.disable(this)
            })

            form.addEventListener("onAsyncChange", function(e) {
                window.$_yn.forms.repopulate(this, e.detail.response.listingForm)
                window.$_yn.forms.enable(this)
            })
        })()
    </script>

and here an example how to handle the updateing of the entity listing:

<!-- sections/listing.twig -->
<script>
    (function() {
        const form = document.querySelector("#form_immo_wrapper").closest("form");
        form.addEventListener("onAsyncChange", function(e) {
            const response = e.detail.response;

            const listing = document.querySelector("#section--objects-listing");
            if(listing) {
                listing.innerHTML = response.rendered
            }
            
        })
    })()    
</script>

<section class="section--objects" id="section--objects-listing">
    {{ include("_partials/property_listing.twig") }}
</section>

Processes

Processes are Ynfinites way to automate a certain string of actions that need to be done when e.g. a form is submitted.

With this data you can propably build all necessary request templates. If you are working with RestAPI notifications, the provided data looks like this:

    {success: true, data: <<response data of the rest api>>}
    // or
    {success: false: status: 404, message: "The error message provided by the rest api"}

E-Mails / REST actions in processes

Each process can send emails or call rest APIs. To do so a template is rendered which is sent as payload of the action. Those templates have a few special TWIG filters and placeholders which can only be used in there.

Table with data from forms

It is often necessary to send all data from a form in an email. Ynfinite provides the easy to user {{ renderDataTable(request, form) }} placeholder which will then be transformed into a table with all the fields of the form and the given values in the request.

Cookies and Consents

Ynfinite has a integrated consent / cookie manager. It helps you to handle cookies and scripts which are loaded from other sources than your server or Ynfinite itself. You can create the necessary cookie information entries in your Ynfinite backend under "Themes" => "Cookie Information". If the consent / cookie manager is activated in your site, Ynfinite will display the manager window for every user which is visiting your website for the first time. The manager is completly build by a standard script and you don't need to do anything for it to work.

Your code will change, depending on the configuration your visitor will make in the manager so you need to be able to access the configuration data. Ynfinite provides several TWIG Tags to work with this data in an easy and understandable way.

Check if cookie is set

The first thing you might want to do is, checking if a cookie is set and render parts of your page when it is. Do do this there are two tags you need to know. The first tag is the isCookieActive tag which renders its body when a cookie is set.

{% isCookieActive "my-cookie-alias" %} // 1
  <script type="text/javascript" src="http://foreign-domain.com/some-script.js"></script>
{% endIsCookieActive %}

The code above will load the script from the foreign domain only if in the cookie manager the my-cookie-alias was accepted. This is a really easy way to be able to make sure no scripts are loaded when the user does not want them to.

The second tag Ynfinite provides is the getCookieConsent tag which renders its body only if the cookie is accepted. If the cookie information is not accepted, it will render a dialog which asks for the consent to set the cookie information consent and load the body.

{% block head %}
    {{ parent() }}

    {% isCookieActive "my-cookie-alias" %} // 1
        <script type="text/javascript" src="http://foreign-domain.com/some-script.js"></script>
    {% endIsCookieActive %}
{% endblock head %}

{% block body %}
    {{ parent() }}
    {% getCookieConsent "my-cookie-alias" %} // 1
        <div class="google-maps">
            // My google maps application is rendered here if there is a consent for the google maps application.
        </div>
    {% endGetCookieConsent %}
{% endblock %}

Lastly you are obligated by law to give your visitor an easy way to change the decisions he/she made. To do so you can create a button with a specific id.

<a href="#" id="yn-cookies__change-selection">Cookie Settings</a> // 1

{{_yfunc("printCookieSettingsButton")}} // 2

You can create your own button (1), it needs this exact id. The alternative to this is using the _yfunc("printCookieSettingsButton") function (2) which prints a link with the necessary id and the correct translated label.

Additionally you can deactivate the consent manager on pages like your imprint or data protection information. To do this you need to activate the option "Hide consent manager" in the page you want the consent manager not to show.

NEW! - Ynfinite REST API

The Ynfinite REST API can be called directly from the PHP client. To do so, you need to do an HTML post request to the /yn-api routes. Why aPOST request you might ask? Because it is easier to send complicated body data in a POST request, thats all.

The following routes are available, those routes will be extended over timer.

/yn-api/content

This route will query the content database. The result is a JSON of the populated and translated content that matches the sent query. The fields you use in the query are extended to match the fields in the database. You do not need to worry, just use the database names you assigned the content fields in the content type.

The following options are available for the request:

  • type (required) - The alias of the content type you want to query
  • limit: The number of items you want to get.
  • skip: The number of items you want to skip. This one is needed if you want to do something like pagination or infinity scrolling.
  • filter: A MongoDB filter object. It can hold most of the standard MongoDB filters. Some fields will be purged so you can not do stuff you shouldn't ;)
  • sort: A MongoDB sort object.
  • select: A MongoDB select object. It supports adding and removing of fields.
  • publish: Set this value to true if you want only published content.

Example:

This query loads 10 team members, their last names have to start with an A and they are sorted by their last name and first name. Also we are only selecting the last name, first name and image of each team member. The team members need to be published.

function fetchContent = () => {
  const options = {
    type: "mitarbeiter",
    limit: 10,
    filter: {
      general_last_name: {$regex: "/^A.*/"} // Alle Nachnamen die mit A Anfangen
    },
    sort: {
      general_last_name: "asc"
    },
    select: {
      general_first_name: 1,
      general_last_name: 1,
      general_image: 1
    },
    pubslished: true
  }

  const response = await fetch(`/yn-api/content`, { method: 'POST', body: requestOptions })
  if (response.status === 200) {
    const data = await response.json()
    document.querySelector('#fetchResult').innerHTML = JSON.stringify(data)
  }
}

Assets

Assets are all files that are used anywhere on the website. They represent files of any kind, may this be images, pdfs or other stuff you need on your website.

Overlays

Sometimes it is necessary to have an image asset seperated into sections. For example you want to mark specific persons on an image so you can add a mouse over effect when you hover over their faces. To do this you would need some way to identify the coordinates on the image where the person is found. Normally you would try to find a image map generator on the web. But not so in Ynfinite. Ynfinite brings this generator as a part of its image handling.

In the meta data of each image asset you will find a button "Edit Overlays" which brings you to the overlay editor. Here you can add rectangles, circles and polygons as overlays. These overlays can be found in the meta information of the image when you use it on your website.

Overlay editor

The overlay editor is very easy to use. Select the tool you want from the actionbar in the upper left.

  • Circle: To add a circle place the cursor at the center of the place where want to create the circle. Hold the left mouse button and move the mouse to create a circle. As soon as you are okay with the size of the circle release the mouse button.
  • Rectangle: To add a rectangle place the cursor at the upper left corner of the place you want to creat the rectangle. Hold down the left mouse button and move the mouse to create the rectangle. As soon as you are okay with the dimensions of the rectangle release the mouse button.
  • Plygon: To add a polygone place your mouse on the point your polygon should start and do a single click. After that each click will draw a line to your current cursor position. If you are at the last click befor you would close the polygon do a double click to close the polygon. The polygon will be closed by a direct line from the last point you did add to the point where your polygon started.

After you created an object (circle, rectangle, polygon) you can resize it by selecting it with a click and then using the eight resizing ankers around the selected object. The ankers to the left / right / top / bottom will resize the object into the selecte axis. If you use the diagonal ankers the object will resize in both axis at once. The object will contain its dimenstion ratios. If you want to change them you need to hold the LEFT SHIFT key while moving your mouse.

Plugins

Sometimes it is necessary to add some functionallity to the Ynfinite PHP Client. To do this you can add plugin files which are loaded during the building of the container. For some of those it might be necessary to delete the container cache to work. The container cache can be found in tmp/cache/CompiledContainer.php

Twig Filters

To add Twig filters to your Ynfinite PHP Client you need to add a file in the plugin/ folder called twig.php. It needs to include a variable called $twigPlugins


$toUpperFunc = function($string) {
    return 
}

$twigPlugins = array(
    array("name" => "price", "func" => $priceFunc, "options" => ['is_safe' => ['html']])
);

Code examples

Forms

Handle date fields with moment.js and standard html pickers

{% extends "yn/components/form/basic.twig" %}

{% block field %}

    <script>
        window.addEventListener('load', function () {
            var startDate = moment().subtract({{ field.dateRestrictions.from.value }}, '{{ field.dateRestrictions.from.unit }}');
            var endDate = moment().add({{ field.dateRestrictions.to.value }}, '{{ field.dateRestrictions.to.unit }}');
            var value = moment('{{ field.value }}');

            var field = document.getElementById('{{field.uid}}');

            field.setAttribute("min", startDate.format('yyyy-MM-DDThh:mm'))
            field.setAttribute("max", endDate.format('yyyy-MM-DDThh:mm'))
            field.setAttribute("value", value.format("yyyy-MM-DDThh:mm"))
        })
    </script>

    <input id="{{field.uid}}" type="{{field.type}}" name="fields[{{field.alias}}]" placeholder="{{field.placeholder}}" {% if field.required %} required {% endif %} {{field.attributes|raw}}/>
{% endblock field %}
  • Writing templates
    • Layout template
    • Override standard templates (Ynfinite CMS client)
  • Data Object
    • Basic Usage
    • Globals
    • Section
  • Functions
    • Handling images
    • Access sections within the page
    • Handle Article fields
  • Listing pages
  • Forms
    • Print forms and fields
    • Fields
    • Consents
    • Events
    • Handling async forms in the PHP client
  • Processes
    • E-Mails / REST actions in processes
  • Cookies and Consents
    • Check if cookie is set
  • NEW! - Ynfinite REST API
    • /yn-api/content
  • Assets
    • Overlays
  • Plugins
    • Twig Filters
  • Code examples
    • Forms
Ynfinite - Documentation
Docs
Getting Started (or other categories)Guides (or other categories)API Reference (or other categories)
Community
User ShowcaseStack OverflowProject ChatTwitter
More
BlogGitHubStar
Facebook Open Source
Copyright © 2026 ypsolution GmbH