Using FieldtypeOptionsFlex

The RepeaterFlex is shipped with a specialized fieldtype OptionsFlex. In contrast to the regular Options fieldtype, which manages available options using the database, the OptionsFlex directly refers to the inputfield specification provided by item plugins. This allows to quickly add usual single or multi option select fields without flooding the installation with single-use option fields. Since OptionsFlex extends FieldtypeMulti, you still may use the regular inputfields like Select, SelectMultiple, Radios, Checkboxes or AsmSelect. Let's just build a plugin for a simple HTML5 video tag I can use on this site.

The OptionsFlex field has to be specified as a virtual field in the array returned from the getFields method like this:

    public static function getFields() {
        return([
        '@Options' => [    // Attribute options for the video object
            'context' => [
                    ],
                ],
            'hint' => __('Select an OptionsFlex field'),
            'fieldtype' => 'OptionsFlex',    // Required fieldtype OptionsFlex
            ],
        ]);
    }

You'll see a new inputfield in your RepeaterFlex field configuration to select an existing OptionsFlex field, if you didn't created one yet, its time to do it now, I've named the first one flex_options:

You do not need to specify anything special in the field definition, since the parameters are injected during runtime from the context specification, which contains the list of available options as well:

            'context' => [
                'columnWidth' => 25,
                'required' => 1,
                'label' => __('Video Tag Attributes'),
                'inputfieldClass' => 'InputfieldAsmSelect',    // We'll use AsmSelect here
                'initValue' => '2|4|5',    // Sequence of indices for default options
                'options' => [
                    1 => 'preload|'.__('Preload'),
                    2 => 'autoplay|'.__('Autoplay'),
                    3 => 'loop|'.__('Loop'),
                    4 => 'muted|'.__('no audio'),
                    5 => 'playsinline|'.__('plays inline'),
                    6 => 'controls|'.__('Controls'),
                    ],
                ],

The array of options is just an associative array with increasing index to use the same syntax as for the options array when defining a setup section for a regular options field. The assigned string as well follows the same conventions and may be a title only or a value followed by a title, separated by a | character. You may already noticed that the titles are translatable, so if you need to adjust the items for different languages, you may do this using the regular site translation files. But that's just a sidenote.

A much more interesting fact about the options list is, that you may assign an associative array as well. So you're free to pack multiple properties into an option which are individually accessible. The only mandatory element would be title, which will be auto-generated from the id if missing. Check out the source below to see how that may look alike.

You may already spotted the required and initValue entries which preselect autoplay, muted and playsinline for any new instance. In this example the inputfieldClass specifies InputfieldAsmSelect, but you may use InputfieldCheckboxes or InputfieldSelectMultiple as well.

By the way: The RepeaterFlex may nicely expand the titles of all selected options in the item's header using {Options*title}. So the video entry will look like this in admin:

The OptionsFlex still is a WireArray from the API, so concatenating all value properties from selected options into a string,combining them along with the optional poster image and the video source into the tag is only few lines:

    public function render(Page $pg) {
        $att = $pg->Options->implode(' ', 'value');    // Concatenate all values of selected options
        if($img = $pg->Image)
            $att .= " poster='{$img->url}'";        // Append image url
        return("<video src='{$pg->TextOnly}' {$att} width='100%'></video>");    // Build video tag
        }

While OptionsFlex may become really handy for any kind of option selection in repeater items, you should be aware that searching for particular settings does not work very well. Not only that you may only search for the option indices in the database, option fields from different item types (and therefore different meanings) are mixed within the database table. If option search is required, better go with page references or a real options field.

plugins/Html5Video.inc

<?php namespace ProcessWire;
/*
 * RepeaterFlex plugin to render a HTML5 Video Object.
 */
class Html5Video extends RepeaterFlexItem {
	public static function getModuleInfo() {
		return array(
			'title' => __('HTML5 Video', __FILE__), // Module Title
			'version' => 1,
			'head' => '{flex_label} [• {Options*title}: {TextOnly} ]',
			'icon' => 'fa fa-film',
			);
	}
	public static function getFields() {
		return([
		'@Options' => RepeaterFlexItem::Options([	// Attribute options for the video object
				'columnWidth' => 25,
				'required' => 1,
				'label' => __('Video Tag Attributes'),
				'inputfieldClass' => 'InputfieldAsmSelect',	// We'll use AsmSelect here
				'initValue' => '2|4|5',	// Sequence of indices for default options
				'options' => [	// Specify options using associative arrays:
					1 => [ 'att' => 'preload', 'title' => __('Preload'), ],
					2 => [ 'att' => 'autoplay', 'title' => __('Autoplay'), ],
					3 => [ 'att' => 'loop', 'title' => __('Loop'), ],
					4 => [ 'att' => 'muted', 'title' => __('no audio'), ],
					5 => [ 'att' => 'playsinline', 'title' => __('plays inline'), ],
					6 => [ 'att' => 'controls', 'title' => __('Controls'), ],
					],
			]),
		'@TextOnly' => RepeaterFlexItem::TextOnly([	// Path to the video, placed manually into a specific location
				'label' => __('Site Path to Video'),
				'notes' => __('relative path like /site/video/clip1.mp4'),
				'columnWidth' => 50,
			]),
		'@Image' => RepeaterFlexItem::Image([	// Preview image, rendered as poster attribute
				'label' => __('Poster Image'),
				'columnWidth' => 25,
			]),
		]);
		}
	public function render(Page $pg) {
		$att = $pg->Options->implode(' ', 'att');	// Concatenate all attributes of selected options
		if($img = $pg->Image)
			$att .= " poster='{$img->url}'";		// Append image url
		return("<video src='{$pg->TextOnly}' {$att} width='100%'></video>");	// Build video tag
		}
}
prepared in 171ms (content 136ms, header 0ms, Menu 22ms, Footer 11ms)