Carbon Fields

Abstract

Carbon fields is a library for easy creation of custom(meta) fields in WordPress administration panel. It allows theme developer to associate meta-information with various entities in a WordPress site(such as posts, taxonomy terms, widgets and so on).

The main components of the library are:

  • Container - represents group of fields and controls disposition of the fields in the WordPress administration panel.
  • Field - represents single field.
  • Data Storage - controls the underlying data storage for field values.

Containers

Carbon Container is a group of custom fields and display options. Containers are displayed on different parts of the backend, according to their type and display options.

Containers have a title, which must be unique across the whole WordPress instance.

Carbon_Container::factory('custom_fields', 'Custom Data')
	->show_on_post_type('page')
	->add_fields(array(
		Carbon_Field::factory('map', 'crb_location')->set_position(37.423156, -122.084917, 14),
		Carbon_Field::factory('choose_sidebar', 'crb_custom_sidebar'),
		Carbon_Field::factory('image', 'crb_photo'),
	));

To create a new Carbon Container, you just use the container factory methodCarbon_Container::factory($type, $title), where:

$type
Identifier of the container type (accepted values are custom_fields and theme_options)
$title
Unique title of the container

Custom Fields Container

Custom Field containers are used to extend the post edit screens with additional fields. Field data is stored separately for each post as post meta (see add_post_meta).

Carbon_Container::factory('custom_fields', 'Post Properties')
	->add_fields(array(
		Carbon_Field::factory('map', 'crb_location')->set_position(37.423156, -122.084917, 14),
		Carbon_Field::factory('choose_sidebar', 'crb_custom_sidebar'),
	));

Visibility options

Custom fields containers are very flexible in terms of display options. You can select specific post type they show on, as well as category, format, parent, etc. A list of all options is displayed below:

post type

->show_on_post_type('page')

You can also show a single container on multiple post types, as seen below:

->show_on_post_type(array('page', 'my_custom_post_type', 'post'))

categories and custom taxonomies

Containers may be assigned to posts from specific categories or taxonomies:

->show_on_category($category_slug)

->show_on_taxonomy_term($term_slug, $taxonomy)

pages and subpages

Show container on a specific page, identified by path, for example: "parent-page/sub-page":

->show_on_page($page_path)

Show container on all subpages of a specific page, identified by path, for example: "parent-page":

->show_on_page_children($parent_page_path)

page templates

Containers may be assigned to pages using specific template:

->show_on_template($template_path)

The $template_path is the name of the template file (or array of template file names), for example: "about_us.php" or array("templates/contact.php", "about_us.php")

You can also hide the container from pages using specific template:

->hide_on_template($template_path)

where the $template_path is the name of the template file (or array of template file names), as in show_on_template() above.

post formats

To display a container on posts with specific post format, use:

->show_on_post_format($post_format)

level

To display a container on hierarchical posts from a specific level, use:

->show_on_level($level)

where $level is the level of hierarchy depth, starting from 1 and increasing when going into further hierarchy depth.

Accessing field values

To access field values you need to use the function carbon_get_post_meta($id, $name, $type = null), where:

$id
Post ID where your value was entered.
$name
The name of the field to be retrieved.
$type (optional)
If the field you want to retrieve is of type complex, you need to pass "complex".
<!-- Simple field -->
<p>Article was published in: <?php echo carbon_get_post_meta($article->ID, 'crb_location'); ?></p>

<!-- Complex field -->
<?php 
$slides = carbon_get_post_meta($page->ID, 'crb_slides', 'complex');
foreach ($slides as $slide) {
	echo $slide['image'];
}
?>

You can also use carbon_get_the_post_meta($name, $type = null) to access the values for the current post in The Loop.

<p>Article was published in: <?php echo carbon_get_the_post_meta('crb_location'); ?></p>
<?php $slides = carbon_get_the_post_meta('crb_slides', 'complex'); ?>

After saving, the carbon_after_save_custom_fields hook is called, which allows you to hook additional functionality after saving. It accepts the $post_id parameter, which is the ID of the post being updated. Example:

<?php
add_action('carbon_after_save_custom_fields', 'crb_after_save_event');
function crb_after_save_event($post_id) {
	if ( get_post_type() == 'crb_event' ) {
		$event_date = carbon_get_post_meta($post_id, 'crb_event_date');
		if ( $event_date ) {
			$timestamp = strtotime($event_date);
			update_post_meta($post_id, '_crb_event_timestamp', $timestamp);
		}
	}
}
?>						

Theme Options Container

Theme option containers are used to add pages with options in the back-end. Field data is stored as options.

By default, theme options containers automatically create main page in the admin area menu named "Theme Options". In most cases these default settings are sufficient, but if you need to change the title or the location of a page in the menu, read the "Multiple option pages" section below.

Carbon_Container::factory('theme_options', 'Theme Options')
	->add_fields(array(
		Carbon_Field::factory('text', 'crb_facebook_url'),
		Carbon_Field::factory('textarea', 'crb_footer_text')
	));

Multiple option pages

It is sometimes needed to create more than one option page. At other times you need to place different pages in different sections in the admin menu. For example, you might have extensive list of settings for the background that you would want to place on a separate Theme options page under Appearance.

To change the location of your Theme Options page, you use set_page_parent($parent), where:

$parent
This can be either:
- title of a top level Theme Options page. - indentificator of a top level menu section in the admin menu sidebar. This corresponds to the $parent_slug parameter of add_submenu_page. You can see all predefined page parents here.

Below you see sample code for creating three theme option containers:

// Default options page
Carbon_Container::factory('theme_options', 'Basic Options')
	->add_fields(array(
		Carbon_Field::factory('header_scripts', 'crb_header_script'),
		Carbon_Field::factory('footer_scripts', 'crb_footer_script'),
	));

// Add second options page under 'Basic Options'
Carbon_Container::factory('theme_options', 'Social Links')
	->set_page_parent('Basic Options')	// title of a top level Theme Options page
	->add_fields(array(
		Carbon_Field::factory('text', 'crb_facebook_link'),
		Carbon_Field::factory('text', 'crb_twitter_link')
	));

// Add third options page under "Appearance"
Carbon_Container::factory('theme_options', 'Customize Background')
	->set_page_parent('themes.php')	// identificator of the "Appearance" admin section
	->add_fields(array(
		Carbon_Field::factory('color', 'crb_background_color'),
		Carbon_Field::factory('image', 'crb_background_image')
	));

For detailed information on managing admin pages, see Administration_Menus.

Every theme options container requires a level of permission, which by default is set to edit_themes (read more about permissions: Roles & Capabilities).
You can change the permission required to view your options page using set_page_permissions($permission)

Accessing field values

To retrieve field values from a theme options container, you need to use the function carbon_get_theme_option($name, $type = null), where:

$name
The name of the field to be retrieved.
$type (optional)
If the field you want to retrieve is of type complex, you need to pass "complex".
<p>Copyright <?php echo carbon_get_theme_option('crb_copyright'); ?></p>
<p>
	Office locations:
	<?php 
	$address_lines = carbon_get_theme_option('crb_addresses', 'complex');
	foreach ($address_lines as $line) {
		echo $line . '<br/>';
	}
	?>
<p>

After saving, the carbon_after_save_theme_options hook is called, which allows you to hook additional functionality after saving.

Term meta Container

Term meta containers are used to extend the term edit screens with additional fields. Field data is stored separately for each term in a custom table ($wpdb->termmeta).

Carbon_Container::factory('term_meta', 'Category Properties')
	->add_fields(array(
		Carbon_Field::factory('color', 'crb_title_color'),
		Carbon_Field::factory('image', 'crb_thumb'),
	));

By default the term meta containers are displayed on category terms, but you can select specific taxonomies they show on using the method show_on_taxonomy($taxonomy), where:

$taxonomy
Can be either name of a single taxonomy or an array of taxonomy names

Accessing field values

To access field values you need to use the function carbon_get_term_meta($term_id, $name, $type = null), where:

$term_id
Term ID where your value was entered.
$name
The name of the field to be retrieved.
$type (optional)
If the field you want to retrieve is of type complex, you need to pass "complex".
<!-- Simple field -->
<p>Editor of this category: <?php echo carbon_get_term_meta($category->ID, 'crb_editor'); ?></p>

<!-- Complex field -->
<?php 
$authors = carbon_get_term_meta($category->ID, 'crb_authors', 'complex');
foreach ($authors as $author) {
	echo $author['name'];
}
?>

After saving, the carbon_after_save_term_meta hook is called, which allows you to hook additional functionality after saving. It accepts the $term_id parameter, which is the term_id of the taxonomy term that was updated.

User meta Container

User meta containers add extra fields to the user edit screens. Field data is stored separately for each user as user meta (see add_user_meta).

Carbon_Container::factory('user_meta', 'Address')
	->add_fields(array(
		Carbon_Field::factory('text', 'crb_city_and_post', 'City and post code'),
		Carbon_Field::factory('text', 'crb_street', 'Street Name'),
	));

By default the user meta containers are displayed for all users of all roles, but you can select specific user roles they show on using the method show_on_user_role($role), where:

$role
Can be either name of a single role or an array of role names

Accessing field values

To access field values you need to use the function carbon_get_user_meta($user_d, $name, $type = null), where:

$user_d
User ID where your value was entered.
$name
The name of the field to be retrieved.
$type (optional)
If the field you want to retrieve is of type complex, you need to pass "complex".
<!-- Simple field -->
<?php $author = get_the_author(); ?>
<p>Author address: <?php echo carbon_get_user_meta($author->ID, 'crb_street'); ?></p>

<!-- Complex field -->
<?php 
$phone_numbers = carbon_get_user_meta($author->ID, 'crb_phone_numbers', 'complex');
foreach ($phone_numbers as $phone) {
	echo $phone['country_code'] . '-' . $phone['number'];
}
?>

After saving, the carbon_after_save_user_meta hook is called, which allows you to hook additional functionality after saving. It accepts the $user_id parameter, which is the ID of the user that was updated.

Widgets

Widget containers are used to create custom widgets for your theme. Each widget is defined as a PHP class. Widget classes must extend the Carbon_Widget class and must have at least two methods - constructor and front_end method.

The constructor must be named after the class and it must call the method setup($name, $description, $fields, $classname), where:

$name
Name of the widget, used in the back-end
$description
Description of the widget, used in the back-end
$fields
Array of Carbon fields
$classname
optional | Provide a custom class attribute for the widget.

The front_end($args, $instance) method is responsible for rendering your widget in the front-end. Here you have access to all values saved for the fields you defined in the constructor via the $instance parameter.

After you define your class, it is important that you register your new widget during the widgets_init action.

class ThemeWidgetExample extends Carbon_Widget {
	// Register widget function. Must have the same name as the class
	function __construct() {
		$this->setup('Theme Widget - Example', 'Displays a block with title/text', array(
			Carbon_Field::factory('text', 'title', 'Title')->set_default_value('Hello World!'),
			Carbon_Field::factory('textarea', 'content', 'Content')->set_default_value('Lorem Ipsum dolor sit amet')
		));
	}
	
	// Called when rendering the widget in the front-end
	function front_end($args, $instance) {
		echo $args['before_title'] . $instance['title'] . $args['after_title'];
		echo '<p>' . $instance['content'] . '</p>';
	}
}

function load_widgets() {
	register_widget('ThemeWidgetExample');
}
add_action('widgets_init', 'load_widgets');

You can setup control options (like width) of your widget by adding a $form_options definition at beginning of your custom widget class. Example:

protected $form_options = array(
	'width' => 500
);

In case you want to disable the default widget wrappers that come from your sidebar, you can disable $this->print_wrappers in the __construct() method of your widget. Example:

function __construct() {
	$this->setup('Widget Title', __('Widget Description', 'crb'), array(
		Carbon_Field::factory('text', 'title', 'Title')->set_default_value('Hello World!'),
	));

	$this->print_wrappers = false;
}

Fields

Fields are the building block of every container.

New field are created using the factory method Carbon_Field::factory($type, $name, $label=null), where:

$type
The type of the field. This parameter should be valid class name of a field. For example text will create field of class Carbon_Field_Text. For a complete list of field types, see Types.
$name
Name of the field. Used as a key when stored in the database and for you to retrieve it's value. Please note, that all fields in a Custom Field Container have their names automatically prefixed with an underscored (e.g. bgcolor becomes _bgcolor). For more information why, see here
$label (optional)

The label of the field is displayed in the back-end only, where the container is visible. When the parameter is omitted it is automatically derived from the $name

If this parameter is omitted, and the $name starts with crb_, the "Crb " part will not be displayed in the generated label.

The factory greatly simplifies the field creation process, since it returns the field object itself and you don't need to assign it to a variable. The fields API supports method chaining (as seen in the example below).

// Create image field with name "customer_photo" and label "Photo"
Carbon_Field::factory('image', 'crb_customer_photo', 'Photo');

// Here the title is automatically set to "Custom Sidebar"
Carbon_Field::factory('choose_sidebar', 'crb_custom_sidebar');

// Method chaining
Carbon_Field::factory('select', 'crb_color')->add_options(array('red', 'blue', 'green'))->help_text('Pick a color');

All field types originate from a single class named Carbon_Field and inherit the following basic features:

Default Values

You can assign a default value for each field in every container. The default value is used when there is currently no value for the particular field in the database. This is the case for example, when you add a new post, or you add a new theme options field to existing container.

To assign a default value, you use Carbon_Field::factory(...)->set_default_value($default_value)

Required Fields

You can mark any field as required, in which case the user will need to fill it out before submitting. To set a field as required, you use Carbon_Field::factory(...)->set_required(true)

Help Text

Help text is used as a hint to the user, who will use the field. It is usually rendered under the field and contains more information about what it should contain - requirements, examples, links, etc. HTML tags are allowed.

You add help text using Carbon_Field::factory(...)->help_text($text)

Text Field text

The text field is the simplest and most generic field. It renders a text input field.

Carbon_Field::factory('text', 'crb_subtitle')

Textarea textarea

Multiline text input with HTML allowed

Carbon_Field::factory('textarea', 'crb_meta_description')
Setup methods
set_rows($rows = 0)
Sets the number of rows. Must be greater than or equal to 0. Default is 0, which falls back to ->set_height(170)
Carbon_Field::factory("textarea", "crb_services_offered", "Services Offered")->set_rows(4);
set_height($height = 170) (DEPRECATED)
Sets the field height. Deprecated in favor of set_rows()
Carbon_Field::factory("textarea", "crb_related_urls", "Related Links")->set_height(250);

NB! The set_height() method is now deprecated - set_rows() should be used instead due to differences in the visual appearance of the textarea between desktop and mobile devices.

Rich text area rich_text

This field renders the built-in WordPress tinyMCE editor.

Carbon_Field::factory("rich_text", "crb_sidenote", "Sidenote Content");

Date date

Renders a date picker using jQuery UI. The value is stored in YYYY-MM-DD format.

Carbon_Field::factory("date", "crb_event_start_date", "Start");

Color color

Renders color picker using Farbtastic. Colors are represented with six hexadecimal digits prefixed with # (e.g. white is #FFFFFF)

Carbon_Field::factory("color", "crb_box_background", "Background Color");

Checkbox checkbox

The checkbox field create a single tick-able option with a label next to it.

Setup methods
set_option_value($value)
Set the value that will be saved when the option is ticked.
NB! When unticked, the value is not saved in the database.
Carbon_Field::factory("checkbox", "crb_show_content", "Show content")
	->set_option_value('yes');

Select select

Creates a select box with pre-defined options.

Setup methods
add_options($options)

Add an associative array with options.
The method can be called multiple times, in which case the options between the calls will be appended (instead of overwritten).

set_options($options)

Set options as an associative array.
The method is not indented to be called multiple times - each call will overwrite the previous options.

NB! If you provide indexed array with no key values, the default indexes (0, 1, 2 ...) of the elements will be used.

Carbon_Field::factory("select", "crb_content_align", "Text alignment")->add_options(array(
	'left' => 'Left',
	'center' => 'Center',
	'right' => 'Right',
));

Radio radio

Similar to the Select field, but instead of in a select box, options are rendered as a set of radio buttons.

Setup methods
add_options($options)
Add an associative array with options.
The method can be called multiple times, in which case the options between the calls will be appended (instead of overwritten).
set_options($options)

Set options as an associative array.
The method is not indented to be called multiple times - each call will overwrite the previous options.

NB! If you provide indexed array with no key values, the default indexes (0, 1, 2 ...) of the elements will be used.

Carbon_Field::factory("radio", "crb_subtitle_styling", "Subtitle text style")->add_options(array(
	'em' => 'Italic',
	'strong' => 'Bold',
	'del' => 'Strike',
));

Set set

The set field creates a list of tick-able options. This field enables to select multiple options. The value is retrieved as array containing the ticked options.

Setup methods
add_options($options)
Add an associative array with options.
The method can be called multiple times, in which case the options between the calls will be appended (instead of overwritten).
set_options($options)

Set options as an associative array.
The method is not indented to be called multiple times - each call will overwrite the previous options.

limit_options($count)

Shows only the first $count options, while the others are hidden and can be shown by clicking the "Show All Options" link.
This method is useful when there are many options in the Set field.
Must be greater than or equal to 0. Default is 0 (no limit, all options are visible).

NB! If you provide indexed array with no key values, the default indexes (0, 1, 2 ...) of the elements will be used.

Carbon_Field::factory("set", "crb_product_features", "Features")->add_options(array(
	'bluetooth' => 'Bluetooth',
	'gps' => 'GPS navigation',
	'nfc' => 'Near field communication',
));

Relationship relationship

This field allows to select multiple posts, pages or custom post types. Useful for creating links between different posts.

Setup methods
set_post_type($post_type)
Set the type of posts to choose from (or array of post types).
set_max($max)
Maximum number of posts to select. Must be greater than 0. Defaults to -1 (no limit).
Carbon_Field::factory("relationship", "crb_publications", "Publications")->set_post_type('publication');
Carbon_Field::factory("relationship", "crb_artworks", "Artworks")->set_post_type(array('painting', 'sculpture'));

File file

Renders a text input with URL and file upload button. The built-in WordPress file handling interface is used.

Carbon_Field::factory("file", "crb_price_list", "Price list (PDF)");

You can use the carbon_field_file_description filter to modify the description of the field.
The description may contain controls that are important to the field, so please use this filter only if you really know what you're doing.

Image image

Renders a text input with URL and image upload button. The built-in WordPress file handling interface is used.

Supported image formats are: jpg, jpeg, gif, png and bmp

Carbon_Field::factory("image", "crb_employee_photo", "Photo");

You can use the carbon_field_image_description filter to modify the description of the field.
The description may contain controls that are important to the field, so please use this filter only if you really know what you're doing.

Attachment attachment

Renders a button to choose file (attachment) from the Media library. Instead of the URL, the field saves the attachment's ID. This allows you to retrieve additional information such as titles, descriptions, captions and different thumbnail sizes.

Carbon_Field::factory("attachment", "crb_related_file", "Related File");

You can use the carbon_field_attachment_description filter to modify the description of the field.
The description may contain controls that are important to the field, so please use this filter only if you really know what you're doing.

Map map

Creates a Google-powered map. The location is represented as longitude and latitude and is saved in three times in the database - one row for the latitude (with name $field_name . '_lat'), one row for the longitude (with name $field_name . '_lng') and one row as a single string ($latitude . ',' . $longitude with name $field_name)

Setup methods
set_position($lat, $lng, $zoom)
Set the default position on the map specified by $lat and $lng and the default zoom level to $zoom (zoom 0 corresponds to a map of the Earth fully zoomed out).
Carbon_Field::factory("map", "crb_company_location", "Location")->help_text('drag and drop the pin on the map to select location');

Map with Address map_with_address

Map field with additional field for address search.

Carbon_Field::factory("map_with_address", "crb_company_location", "Location")

Since the Map with Address field extends the Map field, the set_position() method can also be used with it.

Separator separator

Creates visual separator between adjacent fields. Has aesthetic function only, no data is saved.

Carbon_Field::factory("separator", "crb_style_options", "Style");

Choose Sidebar choose_sidebar

Adds a drop-down field that lists existing sidebars and provides the ability to add new sidebars to the site.

Setup methods
disable_add_new()
Remove the ability to add new sidebars to the site.
set_sidebar_options($sidebar_options)

Set the options used for sidebars created by this field. See register_sidebar for more information ().

This method can accept an associative array of options, or an array of associative arrays with options for each sidebar.

The default options are:

array(
	'before_widget' => '<li id="%1$s" class="widget %2$s">',
	'after_widget' => '</li>',
	'before_title' => '<h2 class="widgettitle">',
	'after_title' => '</h2>',
)

The example below shows how to create a Choose Sidebar field with custom sidebar options and help text:

Carbon_Field::factory("choose_sidebar", "crb_custom_sidebar", __('Sidebar', 'crb'))
	->help_text('Select which sidebar to show in this page, or click "Add New" to create a new one')
	->set_sidebar_options(array(
		'before_widget' => '<div id="%1$s" class="widget %2$s">',
		'after_widget' => '</div>',
		'before_title' => '<h3 class="widgettitle">',
		'after_title' => '<div class="cl">&nbsp;</div></h3>',
	));

The following example sets different sidebar options for each of the specified sidebars:

Carbon_Field::factory( 'choose_sidebar', 'crb_custom_sidebar', __('Sidebar', 'crb') )
	->set_sidebar_options(array(
		'default' => array(
			'before_widget' => '<li id="%1$s" class="widget %2$s">',
			'after_widget'  => '</li>',
			'before_title'  => '<h2 class="widget-title">',
			'after_title'   => '</h2>',
		),
		'blog-sidebar' => array(
			'before_widget' => '<div id="%1$s" class="widget %2$s">',
			'after_widget'  => '</div>',
			'before_title'  => '<h4 class="blog-widget-title">',
			'after_title'   => '</h4>',
		)
	)),
					

Header scripts header_scripts

Applicable to Theme Options container only. Displays a text area, the contents of which will be automatically printed in the <head> of each page. Useful for printing user-defined javascript, as well as styles, meta tags, etc.

Carbon_Field::factory("header_scripts", "crb_header_script");

Footer scripts footer_scripts

Applicable to Theme Options container only. Displays a text area, the contents of which will be automatically printed before the closing </body> of each page (during wp_footer()). Useful for printing Google Analytics code, or user-defined javascript.

Carbon_Field::factory("footer_scripts", "crb_footer_script");

HTML html

Render custom HTML markup

Setup methods
set_html($html)
Set the HTML markup you would like to show to $html.
Carbon_Field::factory("html", "crb_information_text")->set_html('<h2>Lorem ipsum</h2>
<p>Quisque mattis ligula eget placerat volutpat. Praesent tincidunt ultricies tempor.</p>');

Gravity Form gravity_form

Similar to select field, but automatically populated with all available gravity forms. If the plugin is not installed or not activated, an appropriate message will be displayed to the user.

Carbon_Field::factory("gravity_form", "crb_gravity_form", "Select a Form");

There is a crb_gravity_form_options filter which you can use to override the options that are passed to the select field. Example:

add_filter('crb_gravity_form_options', 'crb_my_gravity_form_options');
function crb_my_gravity_form_options($options) {
	//change the default "No Form" text
	$options[0] = 'Do not show any form';

	return $options;
}

Complex Field

Complex fields act as containers to which you can add multiple groups of fields. It is represented as a table, where each row is a field group. The user is able to add infinite rows of each group. This allows to repeat a set of fields multiple times creating customizable and sortable lists. This is useful when creating image galleries, lists of data or advanced content and layout elements.

Carbon_Field::factory('complex', 'crb_slide')->add_fields(array(
	Carbon_Field::factory('text', 'title'),
	Carbon_Field::factory('image', 'photo'),
)),

The example above shows how to make a slide show. We crated a single complex field named slide, to which we attached one group of fields that represents a single slide - title and photo. The user will be able to add multiple rows of title and photo, thus creating a list of slides for the slide show.

A more advanced usage of the complex field is shown below:

Carbon_Field::factory('complex', 'crb_media_item')
	->add_fields('photograph', array(
		Carbon_Field::factory('image', 'image'),
		Carbon_Field::factory('text', 'caption'),
	))
	->add_fields('movie', array(
		Carbon_Field::factory('file', 'video'),
		Carbon_Field::factory('text', 'title'),
		Carbon_Field::factory('text', 'length'),
	)),

Here we have to create a list of media items, lets say for an art exhibition. There are two types of items - photos (defined by an image and a caption) and movies (having a title, length and the video file itself). Since items have different properties, we need to define separate group for each one. Groups also must have a name, by which they will be recognized later - photograph and movie.

As you can see, depending on their usage, complex fields can either contain a single unnamed group or multiple named groups.

Single group

To add a single group of fields you use add_fields($fields), where:

$fields
Numeric array of fields.
add_fields(array(
	Carbon_Field::factory('text', 'name'),
	Carbon_Field::factory('text', 'job_title'),
)),

Multiple groups

To add multiple groups of fields you use add_fields($name, $fields), where:

$name
Unique name of the group.
$fields
Numeric array of fields.
Carbon_Field::factory('complex', 'crb_job')
	->add_fields('driver', array(
		Carbon_Field::factory('text', 'name'),
		Carbon_Field::factory('text', 'drivers_license_id'),
	))
	->add_fields('teacher', array(
		Carbon_Field::factory('image', 'name'),
		Carbon_Field::factory('image', 'years_of_experience'),
	)),

Each call to add_fields($name, $fields) creates a new group and adds it to the complex field.

You can also give each group a label different from their name using add_fields($name, $label, $fields).

All data stored in a complex field is returned as a two-dimensional array with the following format:

array (
	0 => array (
		'_type' => 'photograph',
		'caption' => 'Lorem Ipsum',
		'image' => 'http://example.com/wp-content/uploads/2012/12/Jellyfish.jpg',
	),
	1 => array (
		'_type' => 'movie',
		'length' => '1:56',
		'title' => 'Dolor sit amet',
		'video' => 'http://example.com/wp-content/uploads/2012/12/video_new.mp4',
	),
	2 => array (
		'_type' => 'photograph',
		'caption' => 'Consectetur adipiscing elit',
		'image' => 'http://example.com/wp-content/uploads/2012/12/Koala.jpg',
	),
)

Each item represents the values stored by a single group. The name of the group is stored in element with key _type. When the complex field contains one group only, it's type will be an empty string - "".

Complex field values are retrieved using either carbon_get_post_meta or carbon_get_theme_option (depending on the container it is added to) and passing the string "complex" as $type argument (see Types).

Nested Complex Fields

Complex fields can be nested. The following will define a container that creates multiple slides and allows positioning of multiple text fragments on each slide:

Carbon_Container::factory('custom_fields', 'Slider Data')
	->show_on_post_type('post')
	->add_fields(array(
		Carbon_Field::factory('complex', 'crb_slides')->add_fields(array(
			Carbon_Field::factory('image', 'image'),
			Carbon_Field::factory('complex', 'slide_fragments')->add_fields(array(
				Carbon_Field::factory('text', 'fragment_text'),
				Carbon_Field::factory('select', 'fragment_position')->add_options(array('Top Left', 'Top Right', "Bottom Left", "Bottom Right")),
			))
		)),
	));

Values are retrieved as usual using either carbon_get_post_meta or carbon_get_theme_option. The format of the returned data is a multi-dimensional array, as follows:

array (
	0 => array (
		'photo' => 'http://example.com/lorem.jpg',
		'people_on_photo' => array (
			0 => array (
				'name' => 'John',
			),
			1 => array (
				'name' => 'Karen',
			),
		)
	),
	1 => array (
		'photo' => 'http://example.com/ipsum.jpg',
		'people_on_photo' => array (
			0 => array (
				'name' => 'Paul',
			),
			1 => array (
				'name' => 'Kasper',
			),
			2 => array (
				'name' => 'Julie',
			),
		)
	),
)

Setup Methods

add_fields
This method is identical to Container add_fields method.
set_layout($layout = table | list)
There are two layouts available for displaying a complex field:
  • Carbon_Field_Complex::LAYOUT_LIST(default) - lists groups as rows and their fields as a columns.
  • Carbon_Field_Complex::LAYOUT_TABLE - lists groups as rows. Each field in the group is displayed in a new line with the label on the left and the user control on the right.
set_min($min)
Minimum number of rows. Must be greater than 0. Defaults to -1 (no limit).
set_max($max)
Maximum number of rows. Must be greater than 0. Defaults to -1 (no limit).
setup_labels($labels)
Allows client code to change labels for this complex field. The following items are accepted:
  • Add Row -- wording of the button for adding new field group.
Example usage:
$employees_labels = array(
	'plural_name'=>'Employees',
	'singular_name'=>'Employee',
);
Carbon_Field::factory('complex', 'crb_employee_data')
	->setup_labels($employees_labels)
	->set_layout(Carbon_Field_Complex::LAYOUT_TABLE)
	->add_fields(array(
		Carbon_Field::factory('text', 'name')->help_text('Name of employee'),
		Carbon_Field::factory('text', 'position')->help_text('Position title'),
		Carbon_Field::factory('image', 'image'),
		Carbon_Field::factory('rich_text', 'description'),
	))

Data Storage

Complex field values are saved in the database in multiple rows - a row per field per group. To be able to distinguish which value for field is, a special format of the keys (meta_key or option_name) is adopted:

{complex_field_name}_{group_name}-{field_name}_{number}, where

complex_field_name
Name of the complex field, as passed to Carbon_Field::factory()
group_name
Name of the group as passed to add_fields(), or "" if only one group is present.
field_name
Name of the field in the group, as passed to Carbon_Field::factory()
number
Identifies the number of the row this value is part of.

NB! When in a Custom Fields container, the name of the complex field is prefixed with an underscore, but the name of the field (field_name) is not. Thus, the key format becomes: _{complex_field_name}_{group_name}-{field_name}_{number}

Advanced Topics

Extending

Carbon Fields can be easily extended. Each of the Carbon_Field classes is optionally declared, and each function is optionally defined. This way early custom declaration and definitions can be made in your theme or plugin. Also, you can create custom Carbon Fields, Carbon Containers, Carbon Exceptions and others by extending the existing classes.

Additionally, there are several hooks that allow you to include your custom classes and functionality at the right time, in the right place:

carbon_before_include

Called before including the main classes and functions.

carbon_after_include

Called after including the main classes and functions.

carbon_register_fields

Called prior to registering the Carbon Fields

carbon_after_register_fields

Called after all Carbon Fields have been registered