Creating a Page Template ======================== In Sulu, each page has a *page template*. The page template controls two things: * the structure of the page * how that structure is rendered The structure of a page consists of *properties*, each of which has a *(content) type*. The default page template, for example, defines the following properties: * **title** of type **text_line** * **url** of type **resource_locator** * **article** of type **text_editor** When a content manager opens a page in the administration interface, they can change the values of these properties. At last, frontend designers can access these values and render them according to the desired design. Each page template is defined by two files: * an **XML file** that contains the page structure * a **Twig file** that contains the HTML code For example, the default template -- named "default" -- is defined by the files ``config/templates/pages/default.xml`` and ``templates/pages/default.html.twig``. The Sulu Skeleton also contains a second template named "homepage", which you can find in the same directories. This guide focuses on the configuration of the page structure in the XML file. If you want to learn more about rendering the pages in Twig, read :doc:`twig`. Choosing the Template of a Page ------------------------------- The template of a page can be selected in the admin interface: .. figure:: ../img/templates-selection.png .. Caution:: A template is shown in the dropdown only if both the XML and the Twig file exist! If you can't see your template, double-check the directories ``config/templates/pages`` and ``templates/pages``. The name displayed in the dropdown is configured in the ```` section of the XML: .. code-block:: xml You can customize the text by changing this property. Creating a Custom Template -------------------------- In your projects, you will need several templates for different parts of your website. The easiest way is to copy and adjust the default template. The first thing you need to adjust is the ````. This is the unique identifier of the template: .. code-block:: xml .. caution:: Currently the ```` has to be identical to the filename of the template minus the ``.xml`` suffix. The second thing you have to customize is the ````. This element stores the Twig file that is used to render the template: .. code-block:: xml .. Note:: Sulu automatically adds the ``..twig`` suffix to the view string, depending on the format requested by the client (HTML, JSON, XML, ...). Instead of the folder notation with the ``/`` you can use the `Symfony's naming convention`_ without the file extension for Twig templates. We'll talk more about the Twig file itself in :doc:`twig`. Let's continue with adding properties to our page template. Properties ---------- Properties make up the structure of a page. They are defined in the element ````: .. code-block:: xml A property has three essential attributes: * a ``name`` that is unique within a template * a ``type`` that defines what kind of content can be stored * a ``title`` that is shown in the administration interface Here is a table with the content types shipped in Sulu core: +------------------------------+---------------------------------------------+ | Key | Appearance in the administration | +==============================+=============================================+ | |text_line| | simple text input | +------------------------------+---------------------------------------------+ | |text_area| | multiline text area | +------------------------------+---------------------------------------------+ | |text_editor| | text editor with formatting capabilities | +------------------------------+---------------------------------------------+ | |checkbox| | checkbox | +------------------------------+---------------------------------------------+ | |single_select| | dropdown with options | +------------------------------+---------------------------------------------+ | |select| | dropdown with multiple options | +------------------------------+---------------------------------------------+ | |color| | color picker | +------------------------------+---------------------------------------------+ | |date| | date picker | +------------------------------+---------------------------------------------+ | |time| | text input with time validation | +------------------------------+---------------------------------------------+ | |url| | text input with URL validation | +------------------------------+---------------------------------------------+ | |email| | text input with email validation | +------------------------------+---------------------------------------------+ | |phone| | text input for a phone number | +------------------------------+---------------------------------------------+ | |page_selection| | widget for selecting pages | +------------------------------+---------------------------------------------+ | |single_page_selection| | widget for selecting a single page | +------------------------------+---------------------------------------------+ | |smart_content| | widget for configuring a data source | +------------------------------+---------------------------------------------+ | |resource_locator| | widget for entering the URL of a page | +------------------------------+---------------------------------------------+ | |tag_selection| | autocomplete input for entering and adding | | | tags | +------------------------------+---------------------------------------------+ | |category_selection| | widget for selecting categories | +------------------------------+---------------------------------------------+ | |media_selection| | widget for selecting media (images, | | | documents) | +------------------------------+---------------------------------------------+ | |single_media_selection| | widget for a single media item (image, | | | document) | +------------------------------+---------------------------------------------+ | |contact_account_selection| | widget for selecting contacts and accounts | +------------------------------+---------------------------------------------+ | |teaser_selection| | widget for displaying content teasers | +------------------------------+---------------------------------------------+ | |snippet_selection| | widget for selecting multiple snippets | +------------------------------+---------------------------------------------+ | |single_snippet_selection| | widget for selecting a single snippet | +------------------------------+---------------------------------------------+ | |contact_selection| | widget for selecting multiple contacts | +------------------------------+---------------------------------------------+ | |single_contact_selection| | widget for selecting a single contact | +------------------------------+---------------------------------------------+ | |account_selection| | widget for selecting multiple accounts | +------------------------------+---------------------------------------------+ | |single_account_selection| | widget for selecting a single account | +------------------------------+---------------------------------------------+ .. tip:: Use the command ``sulu:content:types:dump`` to list all the content types available in your project: .. code-block:: bash bin/adminconsole sulu:content:types:dump Many content types can be configured by passing parameters in the element ````. For a single select, for example, you need to set the possible choices: .. code-block:: xml More detail about the content types and their parameters can be found in the :doc:`../reference/content-types/index`. Mandatory/Optional Properties ----------------------------- Properties are optional by default. If a content manager *must* fill out a property, set the attribute ``mandatory`` to ``true``: .. code-block:: xml .. _templates-properties-visible-disabled-conditions: Visible/Disabled Conditions --------------------------- It is possible to hide or disable specific properties based on the current values of the template by setting the ``visibleCondition`` and ``disabledCondition`` attribute. Inside of these attributes, you can utilize the `jexl`_ syntax for expressing your conditions. .. code-block:: xml The ``isCode`` variable in these conditions is relative to the root of the form. If you want to check a property relative from your position, you can use the nestable ``__parent`` variable. This is especially useful when working from within a block. .. code-block:: xml .. note:: Mind that you can call the ``__parent`` (something like ``__parent.__parent.hasImage``) variable multiple times if you use nested blocks. .. note:: Because the ``&`` character needs to be escaped inside of XML files, you have to use ``AND`` instead of ``&&`` if you want to connect conditions using a logical and. Additionally, you can use ``OR`` instead of ``||``. Language Independent Properties ------------------------------- Some content like article numbers or other metadata might be the same for every language. In that case, you can mark properties as not multilingual using ``multilingual="false"``: .. code-block:: xml .. note:: Changing the ``multilingual`` attribute of a property is similar to renaming the property. If you want to keep existing data for the property, you need to migrate it. Multilingual properties are saved with a name like ``i18n:de-article_number``, while non-multilingual properties use a name like ``article_number``. Sections -------- Properties can be grouped together in *sections*. Sections are visible in the administration interface only and have no other effect on the data model: .. figure:: ../img/templates-section.png A section is identified by its ``name``. This name is used for the anchor tag in the administration interface. As for properties, the label of the section goes into its ```` tag: .. code-block:: xml The properties in the sections are nested in a separate element below the section: .. code-block:: xml Content Blocks -------------- Similar to sections, content blocks contain a list of fields. In content blocks, however, the content managers themselves can add blocks of different types and order them as they want: .. figure:: ../img/templates-content-blocks.png Content blocks are defined with the ```` element. Like properties, they have a name that is used to access their content in Twig. The label of the content block is set in the ```` element: .. code-block:: xml The content managers can choose the type of each individual block from a dropdown. Attention, we're not talking about content types! The users of the administration interface don't even know what the quite technical concept of a content type is. Instead, you should think about your own types that make sense in your case. In this particular example, we want to provide the following types to our users: * "Text" for formatted text * "Image Gallery" for a gallery of images * "Quote" for a quote from an artist We'll define these types in the ```` element and set the default type in the ``default-type`` attribute: .. code-block:: xml Each of our types can be mapped to one or multiple properties. These properties are shown in the administration interface when the content manager selects the type: .. code-block:: xml .. note:: The challenge here is to mentally separate *block types* from *content types*. You define *block types* yourself in the ```` element and set the default selection in ``default-type``. Only from the ````, we reference a *content type*. .. note:: More details about blocks, such as the available parameters, can be found on the :doc:`reference <../reference/content-types/block>` page. Aligning Fields on the Grid --------------------------- Sulu's administration interface uses a basic twelve-column grid for the properties. By default, each property is all the twelve columns wide. If you reduce that width, properties automatically float next to each other if they fit within the twelve columns: .. figure:: ../img/templates-aligned-fields.png The width of a property is configured in the ``colspan`` attribute: .. code-block:: xml Displaying Additional Information for a Field --------------------------------------------- You can display a help text with additional information for a property. Put the help text into the ```` element in the ```` section: .. code-block:: xml Including Other Templates ------------------------- If you want to reuse a portion of a template in a different template, you can move the portion to a separate file and include it using `XInclude`_. To enable XInclude, we'll first add the namespace ``xmlns:xi="http://www.w3.org/2001/XInclude"`` to our document: .. code-block:: xml Now we can include the fragment in the template with the ```` element: .. code-block:: xml .. note:: The ``href`` contains a relative path to the included file. The fragment itself should use a ``