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.

Container position

More information about the position options can be found in the add_meta_box() function.

Context

The part of the page where the container should be shown ('normal' (default), 'advanced', or 'side')

->set_context('normal')

Priority

The priority within the context where the container should show ('high' (default), 'core', 'default' or 'low')

->set_priority('high')

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:

add_action('carbon_after_save_custom_fields', 'crb_after_save_event');
function crb_after_save_event($post_id) {
	if ( get_post_type($post_id) !== 'crb_event' ) {
		return false;
	}

	$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)

Custom menu icon

To change the icon of your Theme Options page, you use set_icon($icon), where:

$icon
This can be one of the values, supported in the $icon_url parameter of the add_menu_page function.

Below you see an example for setting up the icon of the theme options page:

Carbon_Container::factory('theme_options', 'Basic Options')
	->set_icon('dashicons-carrot')
	->add_fields(array(
		Carbon_Field::factory('text', 'crb_test_field'),
	));

NB! You can specify custom icons only to parent theme options pages.

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')
	->show_on_taxonomy('category')
	->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

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:

Level

To display a container on hierarchical terms 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_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->term_id, 'crb_editor'); ?></p>

<!-- Complex field -->
<?php 
$authors = carbon_get_term_meta($category->term_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.


Comment meta Container

Comment meta containers add extra fields to the comment edit screens. Field data is stored separately for each comment as comment meta (see add_comment_meta).

Carbon_Container::factory('comment_meta', 'Comment Information')
	->add_fields(array(
		Carbon_Field::factory('text', 'crb_comment_rating', 'Comment Rating'),
		Carbon_Field::factory('text', 'crb_comment_additional_info', 'Additional Comment Information'),
	));

Accessing field values

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

$comment_id
Comment 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".
<?php $comments = get_comments(array(
	'post_id' => get_the_ID(),
));

foreach ( $comments as $comment ) {
	$comment_additional_info = carbon_get_comment_meta($comment->comment_ID, 'crb_comment_info');
	$comment_rating	= carbon_get_comment_meta($comment->comment_ID, 'crb_comment_rating');

	if ( !empty($comment_additional_info) ) {
		echo $comment->comment_ID . ' info: '. $comment_additional_info;
	}

	if ( !empty($comment_rating) ) {
		echo 'Rating: ' . $comment_rating;
	}
}
?>

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;
}

Nav Menu containers are used to extend the Nav Menu edit screens with additional fields. Field data is stored separately for each post as post meta.

Carbon_Container::factory('nav_menu', 'Menu Settings')
	->add_fields(array(
		Carbon_Field::factory('color', 'crb_color'),
	));

Visibility options

Custom Nav Menu containers does not support any visibility options. All containers are visible in all menu items.

Container position

Containers are rendered in the order they are initialized.

Accessing field values

Since each menu entry is a post from post type "nav_menu_item" with status "published", the values can be accessed with the function carbon_get_post_meta($nav_menu_item_ID, $name), where:

$nav_menu_item_ID
Nav Menu Item Post ID where your value was entered.
$name
The name of the field to be retrieved.
$type (optional)
Complex fields are not yet supported.

Custom Walkers or Walker Filters

In order to use the values setup from Nav Menus, you need to use a custom Menu Walker or a filter from the default walker located in wp-includes/nav-menu-template.php.

Here is a Walker example:

/**
 * Location:
 * 	wp-includes/nav-menu-template.php
 * 	source: Walker_Nav_Menu
 */
class Crb_Main_Menu_Walker extends Walker_Nav_Menu {
	public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
		$indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';

		$classes = empty( $item->classes ) ? array() : (array) $item->classes;
		$classes[] = 'menu-item-' . $item->ID;

		$class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args, $depth ) );
		$class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';

		$id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args, $depth );
		$id = $id ? ' id="' . esc_attr( $id ) . '"' : '';

		$output .= $indent . '';

		$atts = array();
		$atts['title']  = ! empty( $item->attr_title ) ? $item->attr_title : '';
		$atts['target'] = ! empty( $item->target )     ? $item->target     : '';
		$atts['rel']    = ! empty( $item->xfn )        ? $item->xfn        : '';
		$atts['href']   = ! empty( $item->url )        ? $item->url        : '';


		// Adding a custom color to the links
		$crb_color = carbon_get_post_meta($item->ID, 'crb_color');
		$atts['style'] = ! empty( $crb_color ) ? 'color: ' . $crb_color . '; ' : '';
		// --- END --- "Adding a custom color to the links"

		$atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args, $depth );

		$attributes = '';
		foreach ( $atts as $attr => $value ) {
			if ( ! empty( $value ) ) {
				$value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
				$attributes .= ' ' . $attr . '="' . $value . '"';
			}
		}

		$item_output = $args->before;
		$item_output .= '';

		$item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
		$item_output .= '';
		$item_output .= $args->after;

		$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
	}

} // Walker_Nav_Menu

Here is a Filter example, doing the same thing:

// Adding a custom color to the links
add_filter('nav_menu_link_attributes', 'crb_nav_menu_link_attributes', 10, 4);
function crb_nav_menu_link_attributes($atts, $item, $args, $depth) {
	$crb_color = carbon_get_post_meta($item->ID, 'crb_color');
	$atts['style'] = ! empty( $crb_color ) ? 'color: ' . $crb_color . '; ' : '';

	return $atts;
}

Both examples will result in:

<div class="menu-main-menu-container">
	<ul id="menu-main-menu" class="menu">
		<li id="menu-item-23" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-23">
			<a href="#" style="color: #2020f3; ">Sample Page</a>
		</li>
		<li id="menu-item-24" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-24">
			<a href="#" style="color: #f94c4c; ">Sample Page</a>
		</li>
		<li id="menu-item-26" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-26">
			<a href="#" style="color: #81d742; ">Sample Page</a>
		</li>
	</ul>
</div>

Tabs

The tabs allow you to group multiple fields under different tab panels using the Container method add_tab. Tabs can be used on every container type. Example:

Carbon_Container::factory('custom_fields', __('User Settings', 'crb'))
	->add_tab(__('Profile', 'crb'), array(
		Carbon_Field::factory('text', '_crb_first_name', 'First Name'),
		Carbon_Field::factory('text', '_crb_last_name', 'Last Name'),
		Carbon_Field::factory('text', '_crb_position', 'Position'),
	))
	->add_tab(__('Notification', 'crb'), array(
		Carbon_Field::factory('text', '_crb_email', 'Notification Email'),
		Carbon_Field::factory('text', '_crb_phone', 'Phone Number'),
	));

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)

Width

You can set the width to fields that are next to each other and they will align on one row. To set the field width %, use:

Carbon_Field::factory(...)->set_width(50)

This feature does nothing in term meta container due to the table layout used by WordPress term editing screen.

Classes

Custom field classes can be added using the add_class method, for example:

Carbon_Field::factory(...)->add_class('my-custom-class')

Conditional Logic

You can apply conditional logic to a field, using set_conditional_logic($rules), to show or hide it based on other field(s) in the same container. The syntax is similar to meta_query.

The conditional rules are passed in a two-dimensional array and each rule can have the following arguments as key=>value pairs:

Key Description Value Required
field The field name to which the rule is applied. The name should be the same as defined in the container. (string) Yes
value The value of the field. It can be an array only when compare is IN or NOT IN. (string|array), defaults to '' No
compare Operator to test. Possible values are: =, <, >, <=, >=, IN, NOT IN. (string), defaults to = No

You can optionally pass the relation key and set it to either AND (default) or OR. It defines the relation, when there is more than one rule.

Example:

Carbon_Field::factory('select', 'crb_show_socials', 'Show Socials')
	->add_options(array(
		'yes' => 'Yes',
		'no' => 'No',
	)),

Carbon_Field::factory('text', 'crb_facebook', 'Facebook URL')
	->set_conditional_logic(array(
		'relation' => 'AND', // Optional, defaults to "AND"
		array(
			'field' => 'crb_show_socials',
			'value' => 'yes', // Optional, defaults to "". Should be an array if "IN" or "NOT IN" operators are used.
			'compare' => '=', // Optional, defaults to "=". Available operators: =, <, >, <=, >=, IN, NOT IN
		)
	)),

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");
Setup methods
set_options($options)
Set an array with the Datepicker options.

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 or a callback.
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 or a callback.
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 or a callback.
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 or a callback.
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 or a callback.
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 or a callback.
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 and reorder posts of any post type. Useful for creating links between any of the post type entries.

Setup methods
set_post_type($type)
It allows you to specify the post type types you want to have available in this relationship field. Defaults to post
set_max($max)
Allows you to limit the maximum number of selected items in a relationship field. By default, there is no limit.
Carbon_Field::factory('relationship', 'crb_relationship')
	->set_max(5);
allow_duplicates($allow)
If enabled will allow the same item to be selected more than once. By default, duplicates are not allowed.
Carbon_Field::factory('relationship', 'crb_relationship')
	->allow_duplicates(true);
Example

The example below registers a relationship field with all posts from the post post type:

Carbon_Field::factory('relationship', 'crb_relationship')
	->set_post_type('post');

Association association

This field allows to select and reorder multiple post type posts, taxonomy terms, users or comments. Useful for creating links between any of these items.

Setup methods
set_types($types)
It allows you to specify the types of data that you want to have available in this association field.
In this context:
  • type is the data type - post, term, user, comment, or a custom value (if implemented).
  • subtype clarifies the exact type to be used.
    For the post_type type, you can use post, page or any other registered custom post type.
    For the taxonomy type, you can use category, post_tag or any other registered custom taxonomy.
    The subtype is not used for the user and comments types.
Defaults to array('type' => 'post', 'post_type' => 'post')
set_max($max)
Allows you to limit the maximum number of selected items in a association field. By default, there is no limit.
Carbon_Field::factory('association', 'crb_association')
	->set_max(5);
allow_duplicates($allow)
If enabled will allow the same item to be selected more than once. By default, duplicates are not allowed.
Carbon_Field::factory('association', 'crb_association')
	->allow_duplicates(true);

NB! To get all the association data (each entry containing id, type, subtype) array, you can set the association type in the retrieval functions. Example:

/* Get the association data as an array */
carbon_get_post_meta($id, $name, 'association'); // array( 0 => array('id' => 20, 'type' => 'post', 'post_type' => 'page'), 1 => array('id' => 16, 'type' => 'term', 'taxonomy' => 'category')

/* Get the association data as plain array with IDs */
carbon_get_post_meta($id, $name); // array( 0 => 20, 1 => 16 )

Example

The example below registers the following options for the association field:

  • Post Type: Page
  • Post Type: Post
  • Taxonomy: Category
  • Taxonomy: Post Tag
  • Users
  • Comments
Carbon_Field::factory('association', 'crb_association')
	->set_types(array(
		array(
			'type' => 'post',
			'post_type' => 'page',
		),
		array(
			'type' => 'post',
			'post_type' => 'post',
		),
		array(
			'type' => 'term',
			'taxonomy' => 'category',
		),
		array(
			'type' => 'term',
			'taxonomy' => 'post_tag',
		),
		array(
			'type' => 'user',
		),
		array(
			'type' => 'comment',
		),
	));

File file

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

Setup methods
set_type($mime_type)
Set the allowed files type. Short mime types are also supported (audio, video, image).
Carbon_Field::factory("file", "crb_price_list", "Price list (PDF)");

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

Setup methods
set_type($mime_type) defaults to 'image'
Set the allowed files type. Short mime types are also supported (audio, video, image).
Carbon_Field::factory("image", "crb_employee_photo", "Photo");

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.

Setup methods
set_type($mime_type)
Set the allowed files type. Short mime types are also supported (audio, video, image).
Carbon_Field::factory("attachment", "crb_related_file", "Related File");

Map map

Creates a Google-powered map with an address search field.

The location data is saved in multiple meta entries:

Meta Key Description Value Type Value
$field_name Latitude & Longitude (string) 40.74866,-73.97982
$field_name . '-lat' Latitude (float) 40.74866
$field_name . '-lng' Longitude (float) -73.97982
$field_name . '-address' Address (string) 45 Park Avenue, New York, NY 10016
$field_name . '-zoom' Zoom level (int) 8
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');
Usage

NB! To get all the location data as an array, you can set the map type in the retrieval functions. Example:

/* Get the location data as an array */
carbon_get_post_meta($id, $name, 'map'); // array('lat' => 40.74866, 'lng' => -73.97982, 'address' => '45 Park Avenue,  New York, NY 10016', 'zoom' => 8)

/* Get the location latitude and longitude */
carbon_get_post_meta($id, $name); // '40.74866,-73.97982'

Separator separator

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

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

Sidebar sidebar

Adds a drop-down field that lists existing sidebars and provides the ability to add new sidebars to the site. Sidebars registered through this field can be removed from the Widgets panel using the "x" icon that will appear next to the sidebar name.

Setup methods
disable_add_new()
Remove the ability to add new sidebars to the site.
exclude_sidebars($sidebars)
Add the ability to exclude one or more sidebars from the select menu. $sidebars parameter can be an array ( of sidebar IDs or sidebar names) or a single sidebar ( ID or name ).
Helper functions
crb_dynamic_sidebar($id, $sidebar_options)
This function overwrites the sidebar options and prints the sidebar with the specified id.

Choose Sidebar choose_sidebar

Deprecated in favor of the Sidebar field.

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) Deprecated
There are two layouts available for displaying a complex field:
  • Carbon_Field_Complex::LAYOUT_TABLE(default) - lists groups as rows. Each field in the group is displayed in a new line with the label first and the user control after it.
  • Carbon_Field_Complex::LAYOUT_LIST - lists groups as rows and their fields as a columns.
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 PHP classes.

On the JavaScript side, the library is designed to be lightweight and flexible and sits on top of Backbone, providing the framework for building a scalable application.

To get a better understanding of how the library works, checkout our step-by-step guide of how to create a new custom Carbon Field.

Templates

Carbon Fields use Underscore template engine. Each field has a template method that prints the Underscore template code.

class Carbon_Field_Example extends Carbon_Field {
	// Main template
	function template() {
		?>
		<input id="{{{ id }}}" type="text" name="{{{ name }}}" value="{{ value }}" class="regular-text" />
		<span>This is an example field. </span>
		<?php
	}
}
Some fields have more than one template - in those cases the extra templates should be printed in separate methods and registered via add_template($name, $callback) method.
class Carbon_Field_Example extends Carbon_Field {
	function admin_init() {
		// Add the description template
		$this->add_template($this->get_type() . '-Description', array($this, 'template_description'));
	}
	...
	// Description template
	function template_description() {
		?>
		<div class="carbon-description {{{ value ? '' : 'hidden' }}}">
			<p>Some really helpful description.</p>
		</div>
		<?php
	}
}

Template Syntax

<# ... #>

Execute arbitrary JavaScript code.

{{ ... }}

Interpolate a value.

{{{ ... }}}

Interpolate a value, and have it be HTML-escaped.

Template Variables

The variables that can be used inside a template are added by the to_json() PHP method. Here is an example of adding two new variables (rows & height):

// Textarea Field PHP Class
class Carbon_Field_Textarea extends Carbon_Field {
	protected $height = 170;
	protected $rows = 0;
	...
	function to_json($load) {
		$field_data = parent::to_json($load);

		$field_data = array_merge($field_data, array(
			'rows'   => $this->rows,
			'height' => $this->height,
		));

		return $field_data;
	}
}

Template variables can also be added using JavaScript, by extending the templateVariables object. This should be done on the field:beforeRender event. For example:

// File Field Backbone View
carbon.fields.View.File = carbon.fields.View.extend({
	initialize: function() {
		carbon.fields.View.prototype.initialize.apply(this);

		this.on('field:beforeRender', this.loadDescriptionTemplate);
	},
	...
	/**
	 * Loads the description template and sets it as a variable ("description") for the base template
	 */
	loadDescriptionTemplate: function() {
		var type = this.model.get('type');
		var descTemplate = carbon.template(type + '-Description');

		_.extend(this.templateVariables, {
			description: descTemplate(this.templateVariables)
		});
	}
});

Hooks

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

General
(action) carbon_before_include

Called before including the main classes and functions.

(action) carbon_after_include

Called after including the main classes and functions.

(action) carbon_register_fields

Called prior to registering the Carbon Fields

(action) carbon_after_register_fields

Called after all Carbon Fields have been registered

Templates
(filter) carbon_template ($hmtl, $name)

Applied to the template html before putting it into the admin footer.

(filter) carbon_template_{template-name} ($hmtl)

Same as carbon_template, but you can specify a template name.

Relationship & Association Fields
(filter) carbon_relationship_title ($title, $name, $id, $type, $subtype)
Allows you to modify the title of the relationship / association items. Helpful when implementing custom relationship / association items. Passes the following parameters:
  • string $title The unfiltered item title.
  • string $name Name of the relationship / association field.
  • int $id The database ID of the item.
  • string $type Item type (post, term, user, comment, or a custom one).
  • string $subtype Subtype - "page", "post", "category", etc.
(filter) carbon_relationship_label ($label, $name, $id, $type, $subtype)
Allows you to modify the label of the relationship / association items. Helpful when implementing custom relationship / association items, or when you want to change the default label. Passes the following parameters:
  • string $label The unfiltered item label.
  • string $name Name of the relationship / association field.
  • int $id The database ID of the item.
  • string $type Item type (post, term, user, comment, or a custom one).
  • string $subtype Subtype - "page", "post", "category", etc.
(filter) carbon_relationship_comment_length ($number, $name)
Allows you to change the number of characters, visible from the comment text in an item. Passes the following parameters:
  • int $number Number of characters. Default: 30
  • string $name Name of the relationship / association field.
(filter) carbon_relationship_options_{name}_post_{post_type} ($options)
Allows you to modify the available options of the relationship / association field with name {name} from the {post_type} post type.
For example, if you want to filter the page post type options of the crb_relationship field, you would use the following filter: carbon_relationship_options_crb_relationship_post_page
(filter) carbon_relationship_options_{name}_taxonomy_{taxonomy} ($options)
Allows you to modify the available options of the relationship / association field with name {name} from the {taxonomy} taxonomy.
For example, if you want to filter the category taxonomy options of the crb_relationship field, you would use the following filter: carbon_relationship_options_crb_relationship_taxonomy_category
(filter) carbon_relationship_options_{name}_user ($options)
Allows you to modify the available options of the relationship / association field with name {name} that are users.
For example, if you want to filter the users options of the crb_relationship field, you would use the following filter: carbon_relationship_options_crb_relationship_user
(filter) carbon_relationship_options_{name}_comment ($options)
Allows you to modify the available options of the relationship / association field with name {name} that are comments.
For example, if you want to filter the comments options of the crb_relationship field, you would use the following filter: carbon_relationship_options_crb_relationship_comment
(filter) carbon_relationship_options ($options, $name)
Allows you to filter the available options of a relationship / association field. Passes the following parameters:
  • array $options Unfiltered options.
  • string $name Name of the relationship / association field.
Gravity Form Field
(filter) crb_gravity_form_options ($options)
Applied to the gravity form options.