In this new tutorial, I’ll explain how to use Carbon Fields, a WordPress custom fields library, to create a Theme Options/Settings page.
What is Carbon Fields?
Carbon Fields is a free WordPress library developed by 2create. It helps WordPress theme and plugin developers create additional fields for post types, navigation menus, widgets, etc., or even register custom Gutenberg blocks without touching JavaScript.
As we’ll see, along the way, it comes with various fields like checkboxes, repeaters (complex), texts, etc.
So, at this point, if you want to follow this tutorial, first install Composer, then install Carbon Fields by running this command:
1 |
composer require htmlburger/carbon-fields |
What is a WordPress Theme Options Page?
A theme options page is an admin page, located outside the default WordPress pages, where developers store global settings which affect the functionality of their WordPress site or plugin.
For example, there might be options for managing things like:
- Header behavior—whether it should be sticky or not.
- Typography settings—the global font size, the global font, the colors of the headings, etc.
Carbon Fields Underscore
The data are usually stored in the *_options
table and available on any site page.
It’s worth noting that the Carbon Fields library automatically prefixes all fields with an underscore when stored in the database (e.g. the footer_text
field becomes _footer_text
).
Implementation
For this demonstration, we’ll create an options page that will hold information for the header layout, footer layout, contact info, and social channels of a demo site.
Please note that the main focus will be to create the page structure in the admin and only show the fields on the front end without adding any styles. All the theme files will be available on this GitHub repo.
As usual, I’ll work with my custom Playground theme—I’ll leave it as barebone as possible and only add the required functionality for the Carbon Fields.
With that in mind, following the docs, I’ll add this code inside the functions.php
:
1 |
use Carbon_Fields\Container; |
2 |
use Carbon_Fields\Field; |
3 |
|
4 |
function crb_attach_theme_options() { |
5 |
Container::make( 'theme_options', __( 'Theme Settings', 'playground' ) ) |
6 |
->set_page_menu_position( 4 ) |
7 |
->set_icon( 'dashicons-admin-settings' ) |
8 |
->add_tab( |
9 |
__( 'Header', 'playground' ), |
10 |
array(...), |
11 |
)
|
12 |
->add_tab( |
13 |
__( 'Contact', 'playground' ), |
14 |
array(...) |
15 |
)
|
16 |
->add_tab( |
17 |
__( 'Socials', 'playground' ), |
18 |
array(...) |
19 |
)
|
20 |
->add_tab( |
21 |
__( 'Footer', 'playground' ), |
22 |
array(...) |
23 |
);
|
24 |
}
|
25 |
add_action( 'carbon_fields_register_fields', 'crb_attach_theme_options' ); |
26 |
|
27 |
function crb_load() { |
28 |
require_once( 'vendor/autoload.php' ); |
29 |
\Carbon_Fields\Carbon_Fields::boot(); |
30 |
}
|
31 |
add_action( 'after_setup_theme', 'crb_load' ); |
This code will wrap all the fields inside a container and create a new menu item called Theme Settings underneath the Dashboard menu item. Of course, you can customize the item’s location and the rendered icon.
Plus, the add_tab
method will give a better organization, as it’ll group all our options page fields into four tabbed sections.
Let’s now have a closer look at these tabs!
Header Tab
The header tab will include fields related to the header functionality. More specifically:
- A checkbox field will manage whether a ribbon will appear above the main header.
- Three fields (one rich text and two color fields) will set the ribbon’s appearance. However, these will appear and be functional only if the previous checkbox field is selected.
- A header scripts field will allow us to embed the Font Awesome 6 icon library in the
head
tag. We’ll use that library for printing the social icons—we’ll get back to it in an upcoming section.
We’ll create all the fields through the make
method like this:
1 |
Field::make( 'header_scripts', 'header_scripts', __( 'Header Scripts', 'playground' ) ), |
2 |
Field::make( 'rich_text', 'header_ribbon', __( 'Ribbon', 'playground' ) ) |
3 |
->set_conditional_logic( |
4 |
array( |
5 |
array( |
6 |
'field' => 'show_header_ribbon', |
7 |
'value' => true, |
8 |
),
|
9 |
)
|
10 |
),
|
11 |
Field::make( 'color', 'header_ribbon_text_color', __( 'Ribbon Text Color', 'playground' ) ) |
12 |
->set_conditional_logic( |
13 |
array( |
14 |
array( |
15 |
'field' => 'show_header_ribbon', |
16 |
'value' => true, |
17 |
),
|
18 |
)
|
19 |
),
|
20 |
Field::make( 'color', 'header_ribbon_bg_color', __( 'Ribbon Background Color', 'playground' ) ) |
21 |
->set_conditional_logic( |
22 |
array( |
23 |
array( |
24 |
'field' => 'show_header_ribbon', |
25 |
'value' => true, |
26 |
),
|
27 |
)
|
28 |
),
|
29 |
Field::make( 'checkbox', 'show_header_ribbon', __( 'Show Ribbon (Top Header)?', 'playground' ) )->set_option_value( 'yes' ), |
Then, wherever we want to display them, we’ll use the carbon_get_theme_option
method and pass as an argument the field name like this:
1 |
<?php
|
2 |
$show_header_ribbon = carbon_get_theme_option( 'show_header_ribbon' ); |
3 |
?>
|
4 |
|
5 |
<header class="site-header"> |
6 |
<nav>
|
7 |
<?php
|
8 |
if ( $show_header_ribbon ) : |
9 |
$header_ribbon = carbon_get_theme_option( 'header_ribbon' ); |
10 |
$header_ribbon_text_color = carbon_get_theme_option( 'header_ribbon_text_color' ) ? carbon_get_theme_option( 'header_ribbon_text_color' ) : '#000'; |
11 |
$header_ribbon_bg_color = carbon_get_theme_option( 'header_ribbon_bg_color' ) ? carbon_get_theme_option( 'header_ribbon_bg_color' ) : 'transparent'; |
12 |
?>
|
13 |
<div class="header-top" style="color: <?php echo esc_attr( $header_ribbon_text_color ); ?>; background: <?php echo esc_attr( $header_ribbon_bg_color ); ?>"> |
14 |
<?php echo wp_kses_post( $header_ribbon ); ?> |
15 |
</div>
|
16 |
<?php endif; ?> |
17 |
<div class="header-bottom">A nice header here</div> |
18 |
</nav>
|
19 |
</header>
|
Contact Tab
The contact tab will include contact-related fields that will be present across different page sections (e.g. on the header, footer, contact pages, sidebars, etc.). More specifically, there will be:
- A textarea field for adding the company address.
- A text field for linking to a Google Maps location.
- A text field for adding the company phone.
- A text field for adding the company mail.
- A select field with dynamic options for allowing users to pick the appropriate Contact Form 7 (CF7) form as a newsletter form.
Imagine that our site contains the following forms:
We should make them all available to the admin users. But here’s the challenge: we won’t hardcode them but instead make all the options of the select field dynamic.
To accomplish this, we’ll define the custom get_all_forms
function and pass it as a parameter of the add_options
method of our select field. This function will return all the site forms in an array format.
Here’s how we create the fields of this tab:
1 |
Field::make( 'textarea', 'address', __( 'Address', 'playground' ) ), |
2 |
Field::make( 'text', 'address_directions', __( 'Address Directions', 'playground' ) )->set_attribute( 'type', 'url' ), |
3 |
Field::make( 'text', 'phone', __( 'Phone', 'playground' ) )->set_attribute( 'type', 'tel' ), |
4 |
Field::make( 'text', 'email', __( 'Email', 'playground' ) )->set_attribute( 'type', 'email' ), |
5 |
Field::make( 'select', 'newsletter_form', __( 'Select Newsletter Form', 'playground' ) ) |
6 |
->add_options( 'get_all_forms' ), // or set |
And here’s the get_all_forms()
declaration:
1 |
function get_all_forms() { |
2 |
$all_forms_array = array(); |
3 |
$all_forms = get_posts( |
4 |
array( |
5 |
'post_type' => 'wpcf7_contact_form', |
6 |
'posts_per_page' => -1, |
7 |
)
|
8 |
);
|
9 |
|
10 |
foreach ( $all_forms as $form ) : |
11 |
$all_forms_array[ $form->ID ] = esc_html( $form->post_title ); |
12 |
endforeach; |
13 |
return $all_forms_array; |
14 |
}
|
Next, we output the fields in the location we want like this:
1 |
<?php
|
2 |
$address = carbon_get_theme_option( 'address' ); |
3 |
$directions = carbon_get_theme_option( 'address_directions' ); |
4 |
$phone = carbon_get_theme_option( 'phone' ); |
5 |
$email = carbon_get_theme_option( 'email' ); |
6 |
$newsletter_form = carbon_get_theme_option( 'newsletter_form' ); |
7 |
?>
|
8 |
|
9 |
<address>
|
10 |
<?php echo wp_kses_post( $address ); ?> |
11 |
<a href="<?php echo esc_url( $directions ); ?>" target="_blank"> |
12 |
<?php esc_html_e( 'See Map', 'playground' ); ?> |
13 |
</a>
|
14 |
<a href="<?php echo esc_url( 'tel:' . $phone ); ?>"> |
15 |
<?php echo esc_html( $phone ); ?> |
16 |
</a>
|
17 |
<a href="<?php echo esc_url( 'mailto:' . $email ); ?>"> |
18 |
<?php echo esc_html( $email ); ?> |
19 |
</a>
|
20 |
</address>
|
21 |
|
22 |
<div>
|
23 |
<?php echo do_shortcode( '[contact-form-7 id="' . esc_attr( $newsletter_form ) . '"]' ); ?> |
24 |
</div>
|
Socials Tab
The socials tab will include a complex field for adding an infinite number of socials. Each social will have three text fields:
- A text field for the social title (e.g. Facebook).
- A text field for the social URL.
- A text field for placing Font Awesome classes (e.g. Facebook classes).
For those of you coming from the ACF world, the complex field is equivalent to ACF’s repeater field.
Here’s how we create the complex field in terms of code:
1 |
<?php
|
2 |
Field::make( 'complex', 'socials' ) |
3 |
->set_layout( 'tabbed-horizontal' ) |
4 |
->add_fields( |
5 |
array( |
6 |
Field::make( 'text', 'social_title', __( 'Social Title', 'playground' ) ), |
7 |
Field::make( 'text', 'social_url', __( 'Social URL', 'playground' ) )->set_attribute( 'type', 'url' ), |
8 |
Field::make( 'text', 'social_icon', __( 'Social Icon', 'playground' ) ) |
9 |
->set_attribute( 'placeholder', 'Add a class from the Font Awesome library' ), |
10 |
)
|
11 |
),
|
And here’s how we print their data wherever we want:
1 |
<?php
|
2 |
$socials = carbon_get_theme_option( 'socials' ); |
3 |
?>
|
4 |
|
5 |
<ul>
|
6 |
<?php
|
7 |
foreach ( $socials as $social ) : |
8 |
//https://github.com/WordPress/WordPress-Coding-Standards/issues/1029
|
9 |
/* translators: %s: social channel */
|
10 |
$title = sprintf( __( 'Find us on %s', 'playground' ), $social['social_title'] ); |
11 |
?>
|
12 |
<li>
|
13 |
<a href="<?php echo esc_url( $social['social_url'] ); ?>" aria-label="<?php echo esc_attr( $title ); ?>" title="<?php echo esc_attr( $title ); ?>" target="_blank"> |
14 |
<i class="<?php echo esc_attr( $social['social_icon'] ); ?>" aria-hidden="true"></i> |
15 |
</a>
|
16 |
</li>
|
17 |
<?php endforeach; ?> |
18 |
</ul>
|
Footer Tab
Similar to the header tab, the footer tab will include fields related to the footer functionality. More specifically:
- A text field will output the footer text.
- Two color fields will set the footer’s foreground and background colors.
As usual, we create them with the make
method:
1 |
Field::make( 'rich_text', 'footer_text', __( 'Footer Text', 'playground' ) ), |
2 |
Field::make( 'color', 'footer_text_color', __( 'Footer Text Color', 'playground' ) ), |
3 |
Field::make( 'color', 'footer_bg_color', __( 'Footer Background Color', 'playground' ) ), |
And we display them in the target file:
1 |
<?php
|
2 |
$footer_text = carbon_get_theme_option( 'footer_text' ); |
3 |
$footer_text_color = carbon_get_theme_option( 'footer_text_color' ) ? carbon_get_theme_option( 'footer_text_color' ) : '#000'; |
4 |
$footer_bg_color = carbon_get_theme_option( 'footer_bg_color' ) ? carbon_get_theme_option( 'footer_bg_color' ) : 'transparent'; |
5 |
?>
|
6 |
|
7 |
<footer class="site-footer" style="color: <?php echo esc_attr( $footer_text_color ); ?>; background: <?php echo esc_attr( $footer_bg_color ); ?>"> |
8 |
<div class="container"> |
9 |
<?php echo wp_kses_post( $footer_text ); ?> |
10 |
</div>
|
11 |
</footer>
|
Conclusion
In this tutorial, we went through the Carbon Fields WordPress custom fields toolkit and explored many of its field types by building a Theme Options page. I hope you now have enough material to decide whether this library can suit your needs for your next WordPress project.
In short, go with it if:
- You want something free and aren’t a big fan of extending the WordPress Customizer.
- You can work without an administration interface.
- You build a plugin/theme that requires a small number of fields.
On the other hand, you might have second thoughts of using it if:
- You don’t have a problem paying for a WordPress plugin that provides more type options and layout styling like ACF PRO.
- You prefer to manage your fields through a UI and feel overwhelmed managing them through code.
- Besides not mandatory, if you’re building a multilingual site/plugin, you might want to pick solutions that are officially supported by the translation tool you choose. For example, although Carbon Fields seems to work fine with WPML according to their docs and my local tests, this tool isn’t officially compatible with WPML.
But without any doubt, this is a handy tool that every WordPress developer should try at least once. What about you? Have you ever used that? Let us know on X!
As always, thanks a lot for reading!
No comments:
Post a Comment