Skip to content

Latest commit

 

History

History
298 lines (249 loc) · 8.89 KB

File metadata and controls

298 lines (249 loc) · 8.89 KB

Columns Field Type

The Columns field type arranges child fields in a responsive multi-column grid layout. Like the Wrapper field type, it is a purely visual container — its children store their values flat at the parent level. The key difference is that Columns uses CSS Grid to place fields side by side instead of stacking them vertically.

The layout is responsive: columns automatically reduce when they would be narrower than 300px, ensuring fields remain usable on smaller screens.

Field Type: columns

array(
	'type'    => 'columns',
	'columns' => 3,
	'items'   => array(
		'first_name' => array(
			'type'  => 'text',
			'label' => 'First Name',
		),
		'last_name' => array(
			'type'  => 'text',
			'label' => 'Last Name',
		),
		'email' => array(
			'type'  => 'email',
			'label' => 'Email Address',
		),
	),
)

Properties

For Default Field Properties, see Field Types Definition.

Specific Properties

  • items (array) — An array of field definitions that make up the columns' content. Each item is a complete field definition with its own type, label, and other properties.
  • columns (integer|array) — The number of columns in the grid layout, or an array of CSS column widths (e.g. array( '1fr', '50px', '2fr' )). When an array, the number of columns is the array length and each entry defines that column's width. When an integer, all columns are equal width (1fr). Defaults to 2. This is the maximum number of columns — the actual number may be lower on narrow containers (see Responsive Behavior).
  • gap (string) — A CSS gap value to override the default spacing between columns and rows. For example, '16px', '1rem', or '8px 16px' (row gap / column gap).
  • class_name (string) — A CSS class name added to the columns container element. This is applied alongside the default wpifycf-field-columns class.

Per-Child Properties

These properties can be set on individual field definitions inside items to control their placement within the grid:

  • column (integer) — A 1-based column index specifying which column the field should start in. When omitted, the field is auto-placed by CSS Grid.
  • column_span (integer) — The number of columns the field should span. Defaults to 1. Useful for fields that need more horizontal space, such as textareas or WYSIWYG editors.

Placement Rules

column column_span Behavior
Set Not set Placed at that column, spans 1
Not set Set Auto-placed, spans N columns
Set Set Placed at column X, spans N columns
Not set Not set Auto-placed, spans 1 (default)

When the container is too narrow and columns collapse (see Responsive Behavior), all explicit column placements are ignored and CSS Grid auto-flow handles the layout.

Responsive Behavior

The Columns field automatically adapts to the available container width:

  1. Each column has a minimum width of 300px
  2. If the container is too narrow for the requested number of columns, columns are reduced: effectiveColumns = floor(containerWidth / 300)
  3. The minimum is always 1 column
  4. When columns collapse below the requested count, all explicit column placements are ignored — fields flow naturally in row order
  5. When using an array of custom widths and columns collapse, the custom widths are replaced with equal-width (1fr) columns

This means a columns: 4 layout on a 900px-wide container will display as 3 columns, and on a 500px container as 1 column.

Stored Value

This field does not store its own value. Children store their values flat at the parent level.

This behavior is identical to the Wrapper field type.

Example Usage

Basic Two-Column Layout

'name_columns' => array(
	'type'    => 'columns',
	'columns' => 2,
	'items'   => array(
		'first_name' => array(
			'type'     => 'text',
			'label'    => 'First Name',
			'required' => true,
		),
		'last_name' => array(
			'type'     => 'text',
			'label'    => 'Last Name',
			'required' => true,
		),
	),
)

Spanning Columns

Use column_span to make a field take up more horizontal space:

'contact_columns' => array(
	'type'    => 'columns',
	'columns' => 3,
	'items'   => array(
		'first_name' => array(
			'type'   => 'text',
			'label'  => 'First Name',
			'column' => 1,
		),
		'last_name' => array(
			'type'   => 'text',
			'label'  => 'Last Name',
			'column' => 2,
		),
		'email' => array(
			'type'   => 'email',
			'label'  => 'Email',
			'column' => 3,
		),
		'bio' => array(
			'type'        => 'textarea',
			'label'       => 'Bio',
			'column_span' => 3,
		),
	),
)

The bio field spans all 3 columns, creating a full-width row beneath the three single-column fields.

Columns Inside a Group

When a columns field is placed inside a group, its children's values stay flat within the group's namespace:

'profile' => array(
	'type'  => 'group',
	'label' => 'Profile',
	'items' => array(
		'avatar' => array(
			'type'  => 'attachment',
			'label' => 'Avatar',
		),
		'details_columns' => array(
			'type'    => 'columns',
			'columns' => 2,
			'items'   => array(
				'bio' => array(
					'type'  => 'textarea',
					'label' => 'Bio',
				),
				'website' => array(
					'type'  => 'url',
					'label' => 'Website',
				),
			),
		),
	),
)

The stored value looks like this — bio and website sit alongside avatar inside the group:

array(
	'profile' => array(
		'avatar'  => 123,
		'bio'     => 'A short bio...',
		'website' => 'https://example.com',
	),
)

With Conditions

Use a columns field to show or hide a block of side-by-side fields together:

'show_social' => array(
	'type'  => 'toggle',
	'label' => 'Show Social Links',
	'title' => 'Display social media links',
),
'social_columns' => array(
	'type'       => 'columns',
	'columns'    => 3,
	'conditions' => array(
		array( 'field' => 'show_social', 'value' => true ),
	),
	'items'      => array(
		'twitter' => array(
			'type'  => 'url',
			'label' => 'Twitter URL',
		),
		'facebook' => array(
			'type'  => 'url',
			'label' => 'Facebook URL',
		),
		'linkedin' => array(
			'type'  => 'url',
			'label' => 'LinkedIn URL',
		),
	),
)

Custom Column Widths

Use an array to define individual column widths instead of equal-width columns:

'sidebar_layout' => array(
	'type'    => 'columns',
	'columns' => array( '1fr', '50px', '2fr' ),
	'items'   => array(
		'sidebar' => array(
			'type'  => 'textarea',
			'label' => 'Sidebar Content',
		),
		'divider' => array(
			'type'  => 'text',
			'label' => 'Divider',
		),
		'main' => array(
			'type'  => 'textarea',
			'label' => 'Main Content',
		),
	),
)

The three columns will be sized 1fr, 50px, and 2fr respectively. When the container is too narrow, the layout collapses to fewer equal-width columns.

Custom Gap

Override the default gap between columns:

'settings_columns' => array(
	'type'    => 'columns',
	'columns' => 2,
	'gap'     => '8px 24px',
	'items'   => array(
		'option_a' => array(
			'type'  => 'toggle',
			'label' => 'Option A',
			'title' => 'Enable option A',
		),
		'option_b' => array(
			'type'  => 'toggle',
			'label' => 'Option B',
			'title' => 'Enable option B',
		),
	),
)

Field Factory

$f = new \Wpify\CustomFields\FieldFactory();

// Equal-width columns
$f->columns(
	columns: 3,
	items: array(
		$f->text( label: 'First Name' ),
		$f->text( label: 'Last Name' ),
		$f->email( label: 'Email' ),
		$f->textarea( label: 'Bio', column_span: 3 ),
	),
);

// Custom column widths
$f->columns(
	columns: array( '200px', '1fr', '1fr' ),
	items: array(
		$f->attachment( label: 'Avatar' ),
		$f->text( label: 'First Name' ),
		$f->text( label: 'Last Name' ),
	),
);

Notes

  • The key difference from the Wrapper field type is the CSS Grid layout — Wrapper stacks fields vertically, while Columns arranges them side by side.
  • Like Wrapper, the Columns field does not nest values. Children store their values flat at the parent level.
  • By default, the columns field sets renderOptions to noLabel: true, noFieldWrapper: true, and noControlWrapper: true, so it renders with no label or extra wrapping markup.
  • Each column item has container-type: inline-size set, so child fields' responsive label/control layout switching uses the column width rather than the full container width.
  • Columns children participate in validation at the parent level. The validation system flattens columns items using flattenWrapperItems() so each child is validated individually.
  • Columns can be nested inside groups, wrappers, or other columns.
  • In PHP, the flatten_items() method hoists columns children to the parent level for meta registration and sanitization, just like wrapper fields.
  • Conditionally hidden fields inside columns are automatically collapsed (no empty grid cells) via CSS :has() selector.