Skip to main content

GravityKit\GravityMigrate\Schema\GfComposites

Puts a name or an address back together from the parts a source platform spread across

several fields, and sanitizes the text that goes into them.

Ninja Forms keeps a name as firstname and lastname fields and an address as address, city, zip and more, each its own row. Gravity Forms has one field with sub-inputs, so the import has to recognise the run and fold it back up.

Since: %ver%

Source: src/Schema/GfComposites.php:22

Details​

  • Kind: class
  • Namespace: GravityKit\GravityMigrate\Schema

Methods​

MethodDescription
part_from_label()Which part of a composite field a label names, or null when it names none.
input_suffixes_for()Where each part of a composite of this type is stored.
parts_by_suffix()Which part each input suffix holds, the inverse of the two maps above.
required_parts_of()The parts a required composite of this type would have refused a blank for.
is_single_box_name()Whether a name field is the one-box kind, which has no parts at all.
shown_parts()The parts of a composite the form actually shows.
whole_field_part()The part that stands for the whole composite, given the parts it produced.
part_of_input_id()The part a composite input id holds, or '' when the id names no part of this type.
input_label()The wording Gravity Forms draws above one box of a composite field.
address_type_traits()What the address type a field uses fixes about that field.
address_type_states()The states the address type a field uses offers, where it offers any.
selected_address_type_name()The name of the address type Gravity Forms renders a field as.
hidden_address_parts()The parts of an address field Gravity Forms does not render.
part_defaults()What each box of a composite field arrives already holding.
part_autocomplete()What each box of a composite asks the browser to fill it with, as a visitor receives it.
name_parts_drawn()Which boxes of a name Gravity Forms draws, as its own renderer decides it.
part_choices()The option list one box of a composite field offers, or [] where it offers none.
part_input()The input of a composite field that holds one named part, or null where it has none.
suffix_of_part()Which input of a composite field holds one part, by the suffix Gravity Forms gives it.
input_id_for_part()The input of a field that holds one named part, where the field has such an input.
recompose_composite_fields()Recombines related simple fields into composite Gravity Forms fields.
build_address_field()Builds a composite Address field.
build_composite_label()Builds a composite label from a base label.
build_name_field()Builds a composite Name field.
derive_composite_group_label()Derives a composite group label from a part label.
normalize_composite_group_key()Normalizes a composite group key.
strip_composite_metadata()Removes composite metadata from fields.
sanitize_text()Sanitizes plain text values.
sanitize_textarea()Sanitizes textarea values.
build_address_inputs()Builds inputs for an Address field.
build_name_inputs()Builds inputs for a Name field.

Method Reference​

part_from_label()​

public static function part_from_label( string $text ): ?string

Which part of a composite field a label names, or null when it names none.

The words are matched whole, so "Fastest" is not a first name and "Countryside" is not a country. Everything that is not a letter or a digit becomes a space first, so "First_Name", "first-name" and "First Name" are one question rather than three.

Parameters​

NameTypeDefaultDescription
$textstringA label, a field name, or both joined.

Returns​

  • string | null — The composite part, or null.

Since: %ver%

Source: src/Schema/GfComposites.php:209

input_suffixes_for()​

public static function input_suffixes_for( string $type ): array

Where each part of a composite of this type is stored.

Parameters​

NameTypeDefaultDescription
$typestringUniversal composite type.

Returns​

  • array<string, — string> Part name to input suffix. Empty for a type with no parts.

Since: %ver%

Source: src/Schema/GfComposites.php:247

parts_by_suffix()​

public static function parts_by_suffix( string $type ): array

Which part each input suffix holds, the inverse of the two maps above.

The type has to be given, because the same digit means different things on the two fields: .2 is a name's prefix and an address's second line. An untyped lookup would answer one of them and be silently wrong about the other.

Parameters​

NameTypeDefaultDescription
$typestringUniversal composite type: name or address.

Returns​

  • array<string, — string> Input suffix to part name.

Since: %ver%

Source: src/Schema/GfComposites.php:268

required_parts_of()​

public static function required_parts_of( string $type, array $shown=[] ): array

The parts a required composite of this type would have refused a blank for.

The suffixes are Gravity Forms' answer; which part each one holds is this file's, so the two are joined here rather than every caller writing the part names out again and drifting from the map the rest of the reading uses.

Gravity Forms enforces a required composite twice, and the suffix list is only the second pass. GFFormDisplay::validate_field() refuses a WHOLLY empty required field whatever it shows (form_display.php:2705), and only a field that got something narrows to get_required_inputs_ids() -- which then skips any enforced input the form hides (class-gf-field.php:1193). So a required address showing nothing but its second line, or a required name showing nothing but a middle name, still cannot be left blank: the one box on screen is the only way to answer, and Gravity Forms insists on an answer. Reading the suffix list alone made every one of those export fully optional.

ONE shown part, and only one. Where a required composite shows SEVERAL parts and Gravity Forms enforces none of them -- a name whose first and last boxes are both hidden, leaving a prefix, a middle and a suffix -- what Gravity Forms asks for is "at least one of these", and no destination here has a way to say that. Starring all three is not a translation of it: it refuses the submission holding only a title, which the source form accepts, and this whole file exists to stop a migrated form refusing what the original took. So that case answers with nothing: the loss is a required field that no longer insists, rather than boxes nobody could leave blank.

Parameters​

NameTypeDefaultDescription
$typestringUniversal composite type: name or address.
$shownstring[][]The parts the form actually shows, where the caller knows them. Empty means "do not narrow", and answers exactly as before.

Returns​

  • string[] — Part names, spelled as the suffix maps spell them.

Since: %ver%

Source: src/Schema/GfComposites.php:305

is_single_box_name()​

public static function is_single_box_name( array $field ): bool

Whether a name field is the one-box kind, which has no parts at all.

Gravity Forms draws nameFormat: 'simple' as a single text box posting one value under the field's own id (class-gf-field-name.php:401-408), and such a field carries NO inputs -- its editor never writes any, and one built with them refuses every submission it is given (\GravityKit\GravityMigrate\Tests\Unit\SimpleNameFieldTest).

Asked rather than inferred from the absence of inputs, because those two facts arrive together and reading only the second one gets the answer backwards: a destination that splits a composite sees no inputs, concludes nothing is hidden, and draws every part. Three platforms produce a one-box name, so "no inputs" reaches the splitting adapters routinely, and it means "one box" rather than "all of them".

Parameters​

NameTypeDefaultDescription
$fieldarrayGravity Forms field.

Returns​

  • bool

Since: %ver%

Source: src/Schema/GfComposites.php:350

shown_parts()​

public static function shown_parts( array $field, string $type ): array

The parts of a composite the form actually shows.

One reading, because four adapters each wrote their own and they did not agree on the two questions that matter: an address hides parts on the FIELD as well as on the input (hideAddress2, hideState, hideCountry, and a type that fixes the country), and a part with no input at all is shown rather than hidden -- the renderer reads isHidden off whatever GFFormsModel::get_input() hands back, and gets nothing from an absent one.

A name defers to \self::name_parts_drawn() rather than answering the same question a second time. That reader knows two things this one did not: nameFormat decides how much of the field is drawn at all -- simple draws no parts, and anything but advanced/extended draws at most a first and a last -- and the MIDDLE is the one part Gravity Forms draws only where its input EXISTS and says isHidden is false (class-gf-field-name.php:324, :367), the opposite of the absent-means-shown rule the other four follow. Two functions in one class answering one question is how they drift.

Parameters​

NameTypeDefaultDescription
$fieldarrayGravity Forms field.
$typestringUniversal composite type: name or address.

Returns​

  • string[] — Part names, in the type's own order.

Since: %ver%

Source: src/Schema/GfComposites.php:380

whole_field_part()​

public static function whole_field_part( string $type, array $produced ): string

The part that stands for the whole composite, given the parts it produced.

Parameters​

NameTypeDefaultDescription
$typestringUniversal composite type: name or address.
$producedstring[]The parts the field became, in any order.

Returns​

  • string — The preferred part, or '' where none of them is one this type knows.

Since: %ver%

Source: src/Schema/GfComposites.php:421

part_of_input_id()​

public static function part_of_input_id( string $input_id, string $type ): string

The part a composite input id holds, or '' when the id names no part of this type.

Parameters​

NameTypeDefaultDescription
$input_idstringGravity Forms input id, such as 3.6.
$typestringUniversal composite type: name or address.

Returns​

  • string

Since: %ver%

Source: src/Schema/GfComposites.php:441

input_label()​

public static function input_label( $input ): string

The wording Gravity Forms draws above one box of a composite field.

Two keys hold it and only one of them is the answer. label keeps the stock wording the input was built with; customLabel holds what an author typed over it in the editor, and both renderers read the override first: GF_Field_Address::get_field_input() takes customLabel for every one of its six boxes when it is not empty (class-gf-field-address.php:219-229), and GF_Field_Name::get_field_input() does the same for all five of its own (class-gf-field-name.php:291-295, :413-414). Reading label alone therefore gives back the wording the author replaced, which is how an address asking for a "Nearest town" arrived asking for a "City".

?? is no use for choosing between them, because Gravity Forms writes customLabel as an EMPTY STRING when nothing overrides the default rather than leaving the key out. The test is on the value.

Parameters​

NameTypeDefaultDescription
$inputmixedOne entry of a field's inputs array.

Returns​

  • string — Empty when the input names no wording at all, which is a field Gravity Forms draws with its own defaults.

Since: %ver%

Source: src/Schema/GfComposites.php:476

address_type_traits()​

public static function address_type_traits( array $field ): array

What the address type a field uses fixes about that field.

An address type is more than a label. Choosing "United States" fixes the country, and a fixed country is not rendered as a box at all -- the field emits a hidden input carrying it instead (class-gf-field-address.php:198, :413). The same type supplies a list of states, which turns the state from a text box into a dropdown (:599, :625). Neither is stored on the field: the field stores the type's NAME and nothing else, so a target adapter reading the field alone cannot see either, and exports boxes the source form never showed.

Parameters​

NameTypeDefaultDescription
$fieldarrayGravity Forms address field.

Returns​

  • array{country: — string, has_state_list: bool} country is '' for a type that fixes none, which is what international is.

Since: %ver%

Source: src/Schema/GfComposites.php:503

address_type_states()​

public static function address_type_states( array $field ): array

The states the address type a field uses offers, where it offers any.

The list is the type's own -- "United States" carries the fifty states and "Canadian" the provinces (class-gf-field-address.php:500, :513) -- and a site that has added a type through gform_address_types carries whatever that type named. So the list a migrated dropdown offers is the list the source form drew, rather than a copy of one of them kept here and handed to every address alike.

Gravity Forms prepends an empty entry to the list when it renders it (:500, :513, :1202); that entry is the prompt rather than a state, so it is left out here and each destination writes whatever prompt it words itself.

Parameters​

NameTypeDefaultDescription
$fieldarrayGravity Forms address field.

Returns​

  • string[] — Empty for a type with no list, which is what international is.

Since: %ver%

Source: src/Schema/GfComposites.php:531

selected_address_type_name()​

public static function selected_address_type_name( array $field ): string

The name of the address type Gravity Forms renders a field as.

Two things stand between the addressType a field stores and the type it is drawn as, and both are what GF_Field_Address::get_selected_address_type() does (:556-564):

  • A field naming no type at all is drawn as the site's default.
  • A type this site no longer defines is drawn as the site's default too, so a form built against a gform_address_types filter that has since been removed migrates as it renders.

Parameters​

NameTypeDefaultDescription
$fieldarrayGravity Forms address field.

Returns​

  • string

Since: %ver%

Source: src/Schema/GfComposites.php:571

hidden_address_parts()​

public static function hidden_address_parts( array $field ): array

The parts of an address field Gravity Forms does not render.

Three separate things hide one, and reading only the first exports boxes the source form never showed:

  • isHidden on the part's own input, which is what the current editor writes.
  • hideCountry, hideState and hideAddress2 on the field itself. The editor rewrites these as isHidden the first time it opens such a field and then deletes them (form_editor.js:1782-1802), but a form nobody has re-saved since still carries them and the renderer still honours them (class-gf-field-address.php:198, :268, :322).
  • An address type that fixes the country, which hides the country box whatever the input says (:198). "United States" and "Canadian" both do, and a form built through GFAPI rather than the editor carries no isHidden to say so.

Parameters​

NameTypeDefaultDescription
$fieldarrayGravity Forms address field.

Returns​

  • string[] — Part names, spelled as {@see self::ADDRESS_INPUT_SUFFIXES} spells them.

Since: %ver%

Source: src/Schema/GfComposites.php:656

part_defaults()​

public static function part_defaults( array $field, string $type='' ): array

What each box of a composite field arrives already holding.

Gravity Forms keeps a composite's defaults per INPUT rather than per field, and the field's own defaultValue is not read at all: GF_Field::get_value_default() branches on is_array( $this-&gt;inputs ) and, for a field that has them, builds its answer from defaultValue on each entry of that array (class-gf-field.php:2822-2838). So the reading every other field type here uses -- the field's own defaultValue -- finds nothing on a name or an address, and a form pre-filling five boxes exported eleven empty ones.

An address keeps two of its parts in a second place as well. defaultCountry and defaultState are field-level settings, and the renderer reads them only where the input carried nothing: if ( empty( $country_value ) ) { $country_value = $this-&gt;defaultCountry; } (class-gf-field-address.php:200-206), the $country_value there having come from the per-input array above. The same order is kept here, so a field carrying both migrates as the form it draws rather than as the other one.

Parameters​

NameTypeDefaultDescription
$fieldarrayGravity Forms composite field.
$typestring''Universal composite type: name or address. Given by a caller that already knows it, because a field reaches a type-specific mapper through a branch on its type and need not carry the key itself.

Returns​

  • array<string, — string> Part name to the value that box opens holding, for the parts that open holding one, in the order the field draws them. A part with no default is left out rather than given an empty string, so a caller can write only the keys it was given.

Since: %ver%

Source: src/Schema/GfComposites.php:713

part_autocomplete()​

public static function part_autocomplete( array $field, string $type='' ): array

What each box of a composite asks the browser to fill it with, as a visitor receives it.

Gravity Forms keeps this per INPUT on both composites and never on the field: GF_Field::get_input_autocomplete_attribute() reads autocompleteAttribute off the entry in the field's inputs array (class-gf-field.php:2364-2372), and the name and the address each call it once per box (class-gf-field-name.php:275-279, :546; class-gf-field-address.php:233-237, :615). The field's OWN autocompleteAttribute -- the one key that appears in this plugin's captured field defaults -- belongs to the flat fields that have a single box, so a reader of it finds nothing on either composite.

Three things decide whether an author's value reaches anybody, and all three are read here rather than by each caller:

  • enableAutocomplete gates every one of those calls (:2347, and again at each call site): an address whose inputs all carry a value renders none of them with the switch off, which is the whole point of the switch.
  • A NAME draws the attribute under advanced and extended only. The default branch, which is what an ordinary first-and-last name uses, computes $first_autocomplete and $last_autocomplete and then interpolates neither (class-gf-field-name.php:414-445); the simple branch has one box and no autocomplete at all (:401-407). That is Gravity Forms' actual behavior, not a regression to route around. An address has no such branch and draws all six.
  • A comma is REMOVED rather than turned into a separator: parse_autocomplete_attributes() is implode( '', explode( ',', $value ) ) (class-gf-field.php:2386-2389), so an author who wrote shipping,given-name sends shippinggiven-name, which fills nothing. Carrying the author's spelling instead of Gravity Forms' would make a migrated form autofill where the source form did not.

Which of the parts answered here a given form actually DRAWS is a separate question, and the callers already ask it -- \self::name_parts_drawn() and \self::hidden_address_parts() -- so a part they skip is simply never looked up, the same arrangement \self::part_defaults() has.

Parameters​

NameTypeDefaultDescription
$fieldarrayGravity Forms composite field.
$typestring''Universal composite type: name or address. Given by a caller that already knows it, the same as \self::part_defaults().

Returns​

  • array<string, — string> Part name to the token list its box carries, for the parts that carry one, in the order the field draws them. A part whose box carries nothing is left out rather than given an empty string.

Since: %ver%

Source: src/Schema/GfComposites.php:802

name_parts_drawn()​

public static function name_parts_drawn( array $field ): array

Which boxes of a name Gravity Forms draws, as its own renderer decides it.

Not the same question as "which inputs does the field have", and the two disagree in both directions. An input that is ABSENT is drawn, not hidden: GF_Field_Name::get_field_input() asks ! rgar( $input, 'isHidden' ) of whatever GFFormsModel::get_input() hands back, and that is falsy for a missing input, so a name stored with three inputs still draws a suffix box (class-gf-field-name.php:306, :316, :332, :340). Measured: a field saved through GFAPI with inputs .2, .3 and .6 rendered a Suffix box beside them.

The MIDDLE is the exception, and the only one: it is drawn only where the input exists AND says isHidden is false (:324, :367), so an absent middle input draws nothing. The same field rendered no Middle box.

The format decides which branch is used at all. advanced and extended draw all five (:283-284); simple draws ONE box that is no part of anything (:401); anything else, an absent nameFormat included, draws a first and a last and nothing more (:414-445).

Parameters​

NameTypeDefaultDescription
$fieldarrayGravity Forms name field.

Returns​

  • string[] — Part names, in the order the field draws them. Empty for a simple name, whose single box holds a whole name rather than a part of one.

Since: %ver%

Source: src/Schema/GfComposites.php:886

part_choices()​

public static function part_choices( array $field, string $type, string $part ): array

The option list one box of a composite field offers, or [] where it offers none.

A Gravity Forms name's PREFIX is the one box of either composite that can carry its own list: GF_Field_Name::get_name_prefix_field() draws a &lt;select&gt; when the input has a choices array and a text box otherwise (class-gf-field-name.php:550-570), and the editor's "Name Prefix Choices" setting is the only place that writes one (form_detail.php:2528-2536, shown by form_editor.js:1505). The SUFFIX carries no list on the page whatever is stored: its choices are read only to add a name_suffix_select class to the wrapper, and the markup underneath is an &lt;input type='text'&gt; in every one of the four branches that build it (:341-345, :384-388). Verified by rendering, not reasoned: choices written onto input .8 drew a text box while the prefix beside it drew its select.

Values are given as Gravity Forms would submit them. enableChoiceValue decides whether a choice's stored value or its text is the value (:556), and a reader that takes value unconditionally writes a stored value into a form whose author never turned values on.

Parameters​

NameTypeDefaultDescription
$fieldarrayGravity Forms composite field.
$typestringUniversal composite type: name or address.
$partstringPart name, as the model spells it.

Returns​

  • array<int, — array{text: string, value: string, isSelected: bool}>

Since: %ver%

Source: src/Schema/GfComposites.php:955

part_input()​

public static function part_input( array $field, string $type, string $part ): ?array

The input of a composite field that holds one named part, or null where it has none.

Parameters​

NameTypeDefaultDescription
$fieldarrayGravity Forms composite field.
$typestringUniversal composite type: name or address.
$partstringPart name, as the model spells it.

Returns​

  • array | null

Since: %ver%

Source: src/Schema/GfComposites.php:1007

suffix_of_part()​

public static function suffix_of_part( string $part ): string

Which input of a composite field holds one part, by the suffix Gravity Forms gives it.

Asked without naming the composite's type, because no part name belongs to both: a name has prefix, first, middle, last and suffix, an address has address, address2, city, state, zip and country. A reader that already knows the type can ask part_of_input_id() instead; this is for one that holds a part name and wants the input, and it exists so that reader does not keep a suffix table of its own to drift from these two.

Parameters​

NameTypeDefaultDescription
$partstringPart name, as the model spells it.

Returns​

  • string — The suffix, or '' for a name no composite uses.

Since: %ver%

Source: src/Schema/GfComposites.php:1088

input_id_for_part()​

public static function input_id_for_part( $field_id, string $part, array $known_ids ): string

The input of a field that holds one named part, where the field has such an input.

A platform whose name field is one field rather than several still lets a sentence ask for one part of it, and that part has to be looked up on the field it landed on rather than assumed: only the parts a form actually shows get an input, so asking a two-part name for its prefix has to come back with nothing rather than with an id that resolves to nothing.

Parameters​

NameTypeDefaultDescription
$field_idint | stringGravity Forms field id.
$partstringPart name, as the model spells it.
$known_idsarrayIds the form actually has, keyed by id.

Returns​

  • string — The input id, or '' when the field has no such part.

Since: %ver%

Source: src/Schema/GfComposites.php:1114

recompose_composite_fields()​

public static function recompose_composite_fields( array $fields, array&$field_id_map=[], array&$warnings=[], array&$origins=[] ): array

Recombines related simple fields into composite Gravity Forms fields.

Parameters​

NameTypeDefaultDescription
$fieldsarrayGravity Forms fields.
&$field_id_maparray[]Source identifier to Gravity Forms field id, by reference. Entries for a part are repointed at the part's input id, not at the composite field, so a reference resolves to the one box.
&$warningsarray[]Warning messages to append, by reference.
&$originsarray[]Assembled field id => the labels of the fields it was assembled from, by reference (its label, for a composite with no id). The assembled field is called something no source field is called -- "First Name" and "Last Name" become "Name" -- so the wizard's field report, which matches the two forms by label, needs telling or it grows a row for a field nobody put on the form. Keyed by id because one form can assemble two fields under one label.

Returns​

  • array

Since: %ver%

Source: src/Schema/GfComposites.php:1176

build_address_field()​

public static function build_address_field( array $base_field, array $parts, string $label ): array

Builds a composite Address field.

Parameters​

NameTypeDefaultDescription
$base_fieldarrayBase field configuration.
$partsarrayGrouped parts.
$labelstringComposite label.

Returns​

  • array

Since: %ver%

Source: src/Schema/GfComposites.php:1445

build_composite_label()​

public static function build_composite_label( string $label, string $type ): string

Builds a composite label from a base label.

Parameters​

NameTypeDefaultDescription
$labelstringBase label.
$typestringComposite type.

Returns​

  • string

Since: %ver%

Source: src/Schema/GfComposites.php:1501

build_name_field()​

public static function build_name_field( array $base_field, array $parts, string $label ): array

Builds a composite Name field.

Parameters​

NameTypeDefaultDescription
$base_fieldarrayBase field configuration.
$partsarrayGrouped parts.
$labelstringComposite label.

Returns​

  • array

Since: %ver%

Source: src/Schema/GfComposites.php:1531

derive_composite_group_label()​

public static function derive_composite_group_label( string $label, string $type, string $part ): string

Derives a composite group label from a part label.

Parameters​

NameTypeDefaultDescription
$labelstringPart label.
$typestringComposite type.
$partstringComposite part.

Returns​

  • string

Since: %ver%

Source: src/Schema/GfComposites.php:1562

normalize_composite_group_key()​

public static function normalize_composite_group_key( string $value ): string

Normalizes a composite group key.

Parameters​

NameTypeDefaultDescription
$valuestringGroup label.

Returns​

  • string

Since: %ver%

Source: src/Schema/GfComposites.php:1646

strip_composite_metadata()​

public static function strip_composite_metadata( array $fields ): array

Removes composite metadata from fields.

Parameters​

NameTypeDefaultDescription
$fieldsarrayField list.

Returns​

  • array

Since: %ver%

Source: src/Schema/GfComposites.php:1665

sanitize_text()​

public static function sanitize_text( $value ): string

Sanitizes plain text values.

Parameters​

NameTypeDefaultDescription
$valuemixedValue to sanitize.

Returns​

  • string

Since: %ver%

Source: src/Schema/GfComposites.php:1683

sanitize_textarea()​

public static function sanitize_textarea( $value ): string

Sanitizes textarea values.

Parameters​

NameTypeDefaultDescription
$valuemixedValue to sanitize.

Returns​

  • string

Since: %ver%

Source: src/Schema/GfComposites.php:1707

build_address_inputs()​

public static function build_address_inputs( int $field_id, array $parts ): array

Builds inputs for an Address field.

Parameters​

NameTypeDefaultDescription
$field_idintField ID.
$partsarrayGrouped parts.

Returns​

  • array

Since: %ver%

Source: src/Schema/GfComposites.php:1728

build_name_inputs()​

public static function build_name_inputs( int $field_id, array $parts ): array

Builds inputs for a Name field.

Parameters​

NameTypeDefaultDescription
$field_idintField ID.
$partsarrayGrouped parts.

Returns​

  • array

Since: %ver%

Source: src/Schema/GfComposites.php:1769