ProFields: Combo field

A single Combo field can have as many other fields in it as you want, but it’s still just one field in ProcessWire, and it consumes no more resources than one field in ProcessWire, making it especially efficient.

The word “Combo” in this case refers to “Combination”. A Combo field lets you have a combination of different fields within it. But unlike other ProFields modules, or other solutions in ProcessWire, the fields in your Combo don’t use other ProcessWire fields, and it doesn’t use other ProcessWire pages. Combo is easy to use, supports numerous input types, is built for use with multiple languages (when enabled in ProcessWire), and is highly efficient and well optimized for searching. Read more about Combo fields in this blog post

Combo is part of the ProcessWire ProFields package available from the ProcessWire Store.

Combo field documentation

Getting started

Versions of Combo released prior to January 2, 2021 are beta versions and may not be fully production ready, so test thoroughly before using outside of a development and/or testing environment. Non beta versions of Combo released after January 1, 2021 are production ready.

Requirements

  • ProcessWire 3.0.164 or newer
  • PHP 5.6 or newer
  • MySQL 5.7 or newer (recommended, though not yet required)

Installation

  1. Unzip the contents of the FieldtypeCombo.zip file into /site/modules/FieldtypeCombo/

  2. In the ProcessWire admin, click: Modules > Refresh.

  3. In the Modules > Site tab, click “Install” for Fieldtype > Combo.

Usage

Creating a Combo field

You can create a new Combo subfield in the ProcessWire admin by navigating to: Setup > Fields > Add New. When it asks for “Type” choose “ProFields: Combo”. After creating the new field, you should be on the “Details” tab of the field editor. This is where most of your work will be done in building your Combo field.

A Combo field has “subfields” which each represent a secondary field within the Combo field. For instance, if your Combo field is named “mailing_address", then you might have these subfields:

  • first_name
  • last_name
  • street
  • city
  • state
  • zip

Each subfield has a “Type”, which can be any one of the following:

  • AsmSelect
  • Checkbox
  • Checkboxes (multiple selection)
  • CKEditor (rich text editor)
  • CKEditorLanguage (multi-language rich text editor)
  • Datetime (date or date and time)
  • Email
  • Float
  • Integer
  • Page (single or multiple selection)
  • Radios (single selection)
  • Select (single selection)
  • SelectMultiple (multiple selection)
  • Text (1 line)
  • TextLanguage (multi-language)
  • Textarea (multiple lines)
  • TextareaLanguage (multi-language)
  • Toggle (yes/no, on/off, etc.)
  • URL

Additional types may also be available, depending on what Inputfield modules you have installed.

Each subfield type has different configuration settings. These will appear after you add a subfield and click Save. Return to your subfield to finish configuring its settings. After configuration, you must click Save again before the subfield will be active.

When creating your Combo field, it's helpful to add it to a Page template early-on, and then edit a page using that template. Keep the page editor open in another tab of your browser so that you can refresh and preview your Combo field as you build it.

Editing a Combo field’s settings in Setup > Fields:

screen_shot_2020-12-04_at_2_27_12_pm_1200x0-is.png

How the mailing_address field above appears in the page editor:

screen_shot_2020-12-04_at_2_29_25_pm_1200x0-is.png

Using your Combo field from template files

For the purposes of this documentation, let’s assume your Combo field is named mailing_address. You would access the value of your Combo field from $page->mailing_address, typically followed by the name of a subfield within it, i.e.

echo $page->mailing_address->city;

If you will be accessing more than one subfield, then it's preferable to get the Combo field value and then access the subfields off of it, like this:

$m = $page->mailing_address;
echo "$m->city, $m->state $m->zip"; // i.e. Atlanta, GA 30307

The value of $page->mailing_address without a subfield is an object of type ComboValue or ComboValueFormatted, depending on the output formatting state of $page.

Formatted vs. unformatted values

A ComboValueFormatted is suitable for front-end output purposes, whereas a ComboValue is suitable for modification and saving from the ProcessWire API. The ComboValueFormatted will contain subfield values that have Textformatter modules applied to them or are in some other output-ready state.

On front-end development, you'll almost always be dealing with a ComboValueFormatted, but if you need an unformatted version, you can get it from $page like this:

$mailing_address = $page->getUnformatted('mailing_address');

Alternatively, you can call $page->of(false); to turn off output formatting, and then access $page->mailing_address and it will be an unformatted version.

If you want to output a table of all subfields and their types, you can do so with the render() method. This is intended just as a developer information tool and not as something you would actually use in production:

echo $page->mailing_address->render();

Output of a Combo field render() method:

Modifying Combo fields from the API

Modifying values in Combo fields is very similar to modifying them on Page fields — it's very simple. The main difference you have to keep in mind is that Combo values come in two flavors: ComboValue and ComboValueFormatted. The formatted variety can't be used for modification, only for output. Below is an example of how we might change a couple of subfields from the API:

$page->of(false); // turn off output formatting (if needed)
$page->mailing_address->street = '123 Atlanta Ave';
$page->mailing_address->city = 'Atlanta';
$page->save('mailing_address');

Searching Combo fields

To find pages based on values in the Combo field, your selector should refer to the subfields by name:

$pages->find("mailing_address.city=Atlanta");

Unlike other fields in ProcessWire, you can also search all subfields at the same time by using only the Combo field name (without the subfield):

$pages->find("mailing_address=Atlanta");

When searching date/datetime fields, you can specify any PHP recognized date string:

$pages->find("mailing_address.arrival_date>=yesterday"); // example 1
$pages->find("mailing_address.arrival_date>=2020-01-01"); // example 2

When searching single or multi-selection fields, if your defined options include separate value and label (value=label, i.e. ga=Georgia) then you should search for the value portion, rather than the label:

$pages->find("mailing_address.state=ga");

When searching single or multi-page reference fields, you can search by page ID or path.

$pages->find('mailing_address.country=4321');  // by ID
$pages->find('mailing_address.country=/countries/usa/'); // by path

It's also fine to use the Page object directly in the selector:

$country = $pages->get('/countries/usa/');
$pages->find("mailing_address.country=$country");

Most text and textarea subfields use a fulltext index and thus can be searched using any of ProcessWire’s partial text and word matching operators:

$pages->find("mailing_address.first_name*=Matt"); // Matt or Matthew

These text matching operators can also be used when searching the Combo field as a whole. For instance, here we are are using the ~|= “Contains any words” operator:

$pages->find("mailing_address~|=Will William Bill Matt Matthew");

When searching multi-language fields, please note that Combo searches all languages at the same time. This is different from the ProcessWire core multi-language fields which search in the current user language.

Using Combo fields in FormBuilder

Unlike other ProFields modules, Combo fields can be used in FormBuilder. In this case, it is the InputfieldCombo module that can be used, as FormBuilder does not use Fieldtype modules. To use a Combo field in FormBuilder, first you'll need to enable it as an allowed Inputfield module in the FormBuilder module configuration. Once you have done that, edit a form in Setup > Forms and add a new field. You should now see the option of "ProFields: Combo" as a field type for your new form field.

FormBuilder opens a modal window when configuring a field, and this window closes when you save. This is usually convenient, but in the case of Combo fields, it's a little annoying because configuring a Combo field often involves saving and returning to your spot for additional settings. I'll be upgrading FormBuilder to provide an alternative to the auto-closing modal window, so stay tuned.

Subfield specific notes

Date/time fields

The value of date/time fields is always in ISO-8601 format (i.e. YYYY-MM-DD HH:MM:SS). This is different from ProcessWire datetime fields where you can choose the output format. So if you want to format a date field differently, use ProcessWire’s wireDate function. For example:

// output: "12/16/2020"
echo wireDate('m/d/Y', $page->combo_field->date_subfield);

// output: "2 days ago"
echo wireDate('relative', $page->combo_field->date_subfield);

While dates are stored and output in ISO-8601 format, note that you do not have to use ISO-8601 format when searching date fields unless you want to.

Float fields

You can optionally use the DECIMAL column type for float fields if you want to. To do this, after creating your Float field, click the “Advanced” tab in the field editor and choose the option to allow database schema customization. Save. Then on the “Details” tab, open the “Database schema” section of your Float field. Choose the “Decimal” type. After doing so, enter the precision and scale in the Schema options that appears. Save.

Single and multiple selection fields

Single and multiple selection fields in Combo include: AsmSelect, Checkboxes, Radios, Select, SelectMultiple, and any others you may have installed. When defining the selectable options for these fields, you have the choice of entering just option values, or value and label. I recommend using the value=label option (separate values and labels). Not only does this enable you to support multi-language options, but it also ensures that any changes to a label need not affect any existing data. Of course, you should avoid making changes to the "value" portion of an option once they are in active use.

When your Combo value came from a page with output formatting on (ComboValueFormatted): the value of a single-selection field is a ComboSelectedValue object. And the value of a multi-selection field is a PHP array of ComboSelectedValue objects. The string value of a ComboSelectedValue is simply the option label in the user’s current language. Meaning, you can output it as if it were a string:

echo $page->mailing_address->country; // i.e. United States

For a multiple-selection value, it will be an array:

foreach($page->mailing_address->favorite_colors as $color) {
  echo "<li>$color</li>"; // i.e. Blue
}

You can also access the value and label independently from a ComboSelectedValue:

echo $page->mailing_address->country->value; // i.e. US
echo $page->mailing_address->country->label; // i.e. United States

Note: for consistency with ProcessWire’s Options field, you can also refer to the "label" as "title", either will work and produce the same output.

When your Combo value came from a page with output formatting OFF (ComboValue): the value of a single-selection field is a regular string containing the selected value only. And the value of a multi-selection field is a PHP array of strings, each containing a selected value. Labels are not present on unformatted values.

echo $page->mailing_address->country; // i.e. US
echo implode(', ', $page->mailing_address->favorite_colors); // i.e. blue, red, green

Support/upgrades and terms

Support and upgrades

The Combo field is part of the ProFields commercial module package and is supported in the dedicated ProFields support board at in the ProcessWire forums (login with active subscription required). If your support/upgrades subscription has expired, send a PM to "ryan" in the forums anytime and we can reset your renewal invoice so that it can be used to restore support and upgrades access.

Terms and conditions

You may not copy or distribute ProFields modules, except on site(s) you have registered it for with Ryan Cramer Design, LLC. It is okay to make copies for use on staging or development servers specific to the site you registered for. This service/software includes 1-year of support through the ProcessWire ProFields Support forum and/or email.

In no event shall Ryan Cramer, Ryan Cramer Design, LLC or ProcessWire be liable for any special, indirect, consequential, exemplary, or incidental damages whatsoever, including, without limitation, damage for loss of business profits, business interruption, loss of business information, loss of goodwill, or other pecuniary loss whether based in contract, tort, negligence, strict liability, or otherwise, arising out of the use or inability to use ProcessWire ProFields, even if Ryan Cramer Design, LLC / ProcessWire has been advised of the possibility of such damages.

ProFields are provided "as-is" without warranty of any kind, either expressed or implied, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose. The entire risk as to the quality and performance of the program is with you. Should the program prove defective, you assume the cost of all necessary servicing, repair or correction. Should you run into any trouble with ProFields, please email for support or visit the ProFields Support forum, we are here to help.

Tips, tricks, pitfalls and more

Combo field phpdoc

When editing a Combo field (Setup > Fields > your_combo_field), see the "Advanced" tab for a custom phpdoc class definition of your Combo field. This is handy if you use an IDE like PhpStorm, as it tells your IDE everything it needs to know about your Combo field so that it can help with code assistance and quality. You can copy/paste this phpdoc definition into your own file and include it from your site template files.

Combo field phpdoc setting:

Be careful with changing subfield type

It’s very easy to change a subfield type in Combo fields. But this is something that you should avoid doing once you have pages storing data for the field. This is because when you change the type, it's literally changing the database schema as well. So if you change a Float field to an Integer field, any values after the decimal are now truncated to be integers. Maybe that's what you want, or maybe not. It's just something to be aware of.

Using verbose column names

Combo uses short ID/number-based column names for its field_* database tables. For example i3 might be a column name. You can optionally tell it to use verbose column names, which make it also include the subfield name, i.e. i3_city. For most users it will make no difference, as you don't typically work directly in the database. But for the few that it might matter to, you can tell Combo to use the verbose column names, so that you can tell what they are outside of ProcessWire, or in backup files. This option can be enabled on the Advanced tab in the field editor.

Optimizing database schema

When configuring your Combo field, the "Advanced" tab has an option to enable custom database schema definition on a subfield-by-subfield basis. All you have to do is enable the option, Save, and then you'll see a "Database schema" setting in search one of your subfields.

This is useful in some cases. For instance, in the "Float fields" section earlier, we discussed how to use a DECIMAL schema for your float field. Below we'll look at another example.

Using our "mailing_address" field example again, let's say that we know our "city" field will never need to be longer than 60 characters. So we could change its database schema from the generic TEXT column type to be a VARCHAR column type. Then we could further optimize it by specifying 60 as the length. Perhaps it's not really necessary here, but it's good to know about, just in case.

When it comes to searching, the VARCHAR column type is indexed for = equals searches, i.e city=Atlanta, whereas the TEXT column types are optimized for partial and word matching searches (FULLTEXT index).

Once you specify a custom database schema for a field, please note that the column type you select stays, even if you later change the subfield "Type". If you want to give the subfield "Type" control over the schema again, select the "Default/auto" option for the database schema column type.

Using backup data

Combo fields keep individual database columns for each field, but also keep a combined index column (the data column). This combined index is used when searching the Combo field as a whole, rather than searching just one subfield. However, it also serves as a backup of your data. Should you make a mistake by changing to an incompatible subfield type, or customizing your database schema, the data in the combined index is unaffected by short term schema changes. You can enable the option to use the combined index (data column) as the source for loading data. When enabled, Combo will load the data in the combined index rather than the data in the database columns. However, it will continue to keep both up-to-date with any changes to page content. This option can be enabled or disabled on the Advanced tab.

Combo field advanced settings tab:

Latest news

  • ProcessWire Weekly #553
    In the 553rd issue of ProcessWire Weekly we'll check out the latest weekly update from Ryan, introduce a new third party module called Text Synthesis, and more. Read on!
    Weekly.pw / 14 December 2024
  • Custom Fields Module
    This week we look at a new ProFields module named Custom Fields. This module provides a way to rapidly build out ProcessWire fields that contain any number of subfields/properties within them.
    Blog / 30 August 2024
  • Subscribe to weekly ProcessWire news

“We were really happy to build our new portfolio website on ProcessWire! We wanted something that gave us plenty of control on the back-end, without any bloat on the front end - just a nice, easy to access API for all our content that left us free to design and build however we liked.” —Castus, web design agency in Sheffield, UK