Custom fields type: Subfields

From Joomla! Documentation

Note

The feature described on this page is not yet part of the Joomla! core. It is currently being handled as a pull request on GitHub, see https://github.com/joomla/joomla-cms/pull/22446 . This wiki page reflects the current status of that PR. This preliminary note should get removed when the PR got merged.

Introduction

Custom fields in Joomla! is a technology to extend various item types (content articles, contact items, etc.) with custom-made fields, e.g. extending a content article with a text field named fact_checked_by. For a basic introduction into this topic see J3.x:Adding custom fields.

This wiki page is an introduction into a special type for custom fields called subfields. The aim of the subfields custom field type is to provide the user the possibility to create a repeatable custom field for an item with multiple related fields, so e.g. adding a custom field named ingredients with the sub fields description and amount to a content article.

A short note on terminology: We use the term "sub fields" to describe two different things: First, subfields is the type of the custom field that is being added to an item, so the type of the "parent field" - e.g. like other custom fields can be of type text or integer. Second, we call the configured "child fields" of that parent field "sub fields", just because that is comfortable. An attentive reader will note the difference, but the context should always be clear what is meant. If that is not the case, we use other terms.

Adding a custom field to be used as a sub field

Before creating a new subfields instance you will want to create one or more custom fields that serve as child fields for the subfields instance you are about to create. So e.g. when you want to add a repeatable subfields instance to an article called ingredients with the sub fields description (type text) and amount (type integer), you have to first create the two custom fields description and amount as separate custom fields.

Note about subfields-only fields: By default, a newly created custom field will have its "Category" filter set to "All". This means, that custom field will be displayed for items of all categories. If you integrate this custom field into a subfields instance, this basically means you will see the sub field twice: One time as a standalone field as part of that item, and the other time included into the subfields instance as a sub field. You can circumvent this problem by declaring the sub field to be not available for an item directly. To do this, simply set the "Category" of that sub field to "None". By doing this, this custom field will not be part of any item itself.

The subfields field

Provides a possibility to add several (repeatable) sub fields to an item. The sub fields are each rendered by themselves and the result will by default be shown as a comma-separated list (this can be changed, see further down).

Options

  • Repeatable, repeat (mandatory) boolean, default true.
    Whether the sub fields should be repeatable in the backend.
  • Sub fields (mandatory)
    A list of other custom field items that shall be used as sub fields for this item.
    Render values, render_values (mandatory) boolean, default true. Whether the value of this sub field shall get rendered or not (see next chapter).

Disable rendering for a sub field

When creating a subfields instance and selecting which other custom fields should be used as sub fields, you are able to select whether you want Joomla! to render this sub fields' value, when the value of the parent field is being rendered. Normally, this is what you want to do, why the default value is true.

Turning this off will have consequences for sub field types for which the value, which is saved in the database, is not equal to the rendered string which is normally being used in a template: E.g. the media type which stores a path to a media file in the database, but normally renders as an <img>-tag. Turning this option off would mean that the default rendering process of the subfields field will now show the path the file instead of the <img>-tag.

So, why does this option then even exist? Because rendering takes performance, and rendering of many sub fields of many items takes much performance and time. And this is not always what you want, nor what you need. You are basically able to switch this option off and create your own layout override for your subfields (see next chapter) - hence rendering the sub fields the way you want and saving performance by it.

Changing the rendering with a layout override

By default, the value of all individual sub fields will be rendered and the result will be shown as a comma-separated list in the frontend. This default behavior is implemented in the file plugins/fields/subfields/tmpl/subfields.php, please take a look at it to get a first impression on how to change the rendering in general.

The first thing to do to change the rendering is to create a layout override for that template, e.g. by creating a new file templates/$YOUR_TEMPLATE/html/plg_fields_subfields/subfields.php, see Layout Overrides in Joomla for further info.

The next thing to do is to get an idea about the structure of the $field object that is being passed to the template. That object has 2 important properties:

  • $field->name is a string containing the name of the custom field you set.
  • $field->subfields_rows is an array containing arrays, which contain the sub fields. So, basically, $field->subfields_rows contains rows of data, and each row contains a list of sub field instances / objects. Each of those instances is a fully-featured field instance / object itself, and has properties like name, type, etc. amongst value and rawvalue, containing the rendered and unrendered value respectively.

You can use the name property of $field to make distinctions in your template, dependent of which subfields instance is being rendered.

The subfields_rows property might sound a bit complicated in the first place, but when you create your own layout override and play around with it, var_dump() different states etc., you should get a good feeling about how it behaves very quickly.

Example 1

Suppose we have created a custom field named ingredients for an article that contains the sub fields description and image of type text and media respectively. We now want to display those in a nice way when we are asked to render them. We could e.g. do this in the following way, note the different use of rawvalue and value here, which we use to get access to the rendered value of the media field (which is, normally, an <img> HTML tag):

<?php if ($field->name == 'ingredients'): ?>
  <ul>
    <?php foreach ($field->subfields_rows as $row): ?>
      <li>
        Description: <?php echo htmlentities($row['description']->rawvalue); ?><br />
        Image: <?php echo $row['image']->value; ?>
      </li>
    <?php endforeach; ?>
  </ul>
<?php endif; ?>

Additionally, you could disable the rendering of the description sub field in this example (because the rendered value is not being used, only the raw value), see also previous chapter.

Example 2

The subfields_rows object can get a little complicated. The following code will render all sub fields in a comma-separated list, using their rawvalue and prefixing them with their name. This example shows how the subfield_rows object can be used on a more basic-level, not using any rendered values.

<?php
echo '<ul>';
foreach ($field->subfields_rows as $row)
{
  echo '<li>';
  $buffer = array();
  foreach ($row as $subfield)
  {
    $buffer[] = (
      $subfield->name . ': '
      . $subfield->rawvalue
    );
  }
  echo implode(', ', $buffer);
  echo '</li>';
}
echo '</ul>';