In this WordPress tutorial, we will learn to use the add_meta_box
function to create a settings form for plugins and themes with collapsible meta boxes using postbox.js
. By the end of this tutorial, you’ll be able to easily create forms on the custom admin page, as shown in the following image.
In this tutorial, we will cover the following points:
- Enabling or disabling specific columns using screen options.
- Adjusting the column layout using screen options.
- Implementing collapsible meta boxes.
- Storing and accessing form data with the
update_option
andget_option
functions.
Adding Code to the functions.php File
For simplicity, we’ll use the functions.php
file to create forms for managing SMTP settings and sending emails. To prevent losing changes during theme updates, it’s essential to create a child theme. Once the child theme is set up, you can insert the code into the functions.php
file of the child theme.
Creating an Admin Page
To display our forms in the WordPress Admin panel, we’ll create a custom admin page using the admin_menu
function. Add the following code to your functions.php
file to create a settings page for your plugin or theme.
function init_mail_settings() {
echo "SMTP Settings";
}
function smtp_menu() {
global $smtp_menu_page;
$smtp_menu_page = add_menu_page(__('SMTP', 'theme-name'), __('SMTP', 'theme-name'), 'manage_options', 'setup-smtp', 'init_mail_settings', 'dashicons-email', 110);
// add_menu_page( string $page_title, string $menu_title, string $capability, string $menu_slug, callable $callback = '', string $icon_url = '', int|float $position = null )
}
add_action('admin_menu', 'smtp_menu');
Display Registered Meta Boxes
After creating the custom admin page, we need to render all meta boxes registered to this page. To do this, we’ll call the do_meta_boxes
function within the init_mail_settings
function. Update the init_mail_settings
function with the following code.
function init_mail_settings() {
$screen = get_current_screen(); ?>
<div class="wrap">
<h1 class="wp-heading-inline"><?php _e('SMTP Settings', 'theme-name'); ?></h1>
<div>
<div id="postbox-container-1" class="postbox-container"><?php do_meta_boxes( $screen->id, 'normal', '' ); ?></div>
<div id="postbox-container-2" class="postbox-container"><?php do_meta_boxes( $screen->id, 'side', '' ); ?></div>
</div>
</div>
<?php }
Register Meta Boxes
Next, we need to register our meta boxes using the add_meta_box
function. This function allows you to create custom meta fields for posts and pages. Add the following code to your functions.php
file to register all custom meta boxes.
function smtp_configuration_form() {
echo "SMTP Configuration Form";
}
function wp_mail_form() {
echo "WP Mail Form";
}
function smtp_mail_page_metaboxes() {
global $smtp_menu_page;
$screen = get_current_screen();
if(!is_object($screen) || $screen->id !== $smtp_menu_page) {
return;
}
add_meta_box('smtp-configuration', 'SMTP Configuration', 'smtp_configuration_form', $smtp_menu_page, 'normal', 'default');
add_meta_box('mail-system', 'Mail', 'wp_mail_form', $smtp_menu_page, 'side', 'default');
// add_meta_box( string $id, string $title, callable $callback, string|array|WP_Screen $screen = null, string $context = ‘advanced’, string $priority = ‘default’, array $callback_args = null )
}
add_action('add_meta_boxes_smtp_mail_page','smtp_mail_page_metaboxes');
After refreshing the custom admin page, you might notice that the meta boxes still aren’t rendering. This happens because we haven’t yet created the action hook add_meta_boxes_smtp_mail_page
, which executes the code to register the meta boxes.
Adding Support for Screen Options
To fix this, we’ll create an action hook called add_meta_boxes_smtp_mail_page
using the do_action
function in WordPress. This hook will trigger the code to register the meta boxes.
function smtp_mail_screen_options() {
global $smtp_menu_page;
$screen = get_current_screen();
if(!is_object($screen) || $screen->id !== $smtp_menu_page) {
return;
}
do_action('add_meta_boxes_smtp_mail_page', $smtp_menu_page);
}
Now, update the smtp_menu
function (from the “Create Admin Page” step) with the following code to enable support for screen options.
function smtp_menu() {
global $smtp_menu_page;
$smtp_menu_page = add_menu_page(__('SMTP', 'theme-name'), __('SMTP', 'theme-name'), 'manage_options', 'setup-smtp', 'init_mail_settings', 'dashicons-email', 110);
add_action("load-{$smtp_menu_page}", "smtp_mail_screen_options");
}
Once you refresh the page, you should see two meta boxes: one for the SMTP configuration form and another for the WordPress mail service.
Enable Support for Collapsible Meta Boxes
If you click on the collapsible arrow in your custom meta boxes, you may notice that they don’t collapse. To fix this, we need to enqueue the postbox
library by using the wp_enqueue_script
function and call the add_postbox_toggles
function from the postbox
library. Update the smtp_mail_screen_options
and smtp_menu
functions with the following code to resolve this issue.
function smtp_mail_screen_options() {
global $smtp_menu_page;
$screen = get_current_screen();
if(!is_object($screen) || $screen->id !== $smtp_menu_page) {
return;
}
do_action('add_meta_boxes_smtp_mail_page', $smtp_menu_page);
/* Enqueue postbox script for handling the metaboxes */
wp_enqueue_script('postbox');
}
function smtp_mail_footer_scripts() {
echo '<script>jQuery(document).ready(function(){if(postboxes){postboxes.add_postbox_toggles(pagenow);}});</script>';
}
function smtp_menu() {
global $smtp_menu_page;
$smtp_menu_page = add_menu_page(__('SMTP', 'theme-name'), __('SMTP', 'theme-name'), 'manage_options', 'setup-smtp', 'init_mail_settings', 'dashicons-email', 110);
add_action("load-{$smtp_menu_page}", "smtp_mail_screen_options");
add_action("admin_footer-{$smtp_menu_page}", "smtp_mail_footer_scripts");
}
Add Screen Option to Change Column Layout
If you check the “Screen Options” tab, you might see that the option to toggle the column layout is missing. To enable this feature, use the add_screen_option
function. Update the smtp_mail_screen_options
function with the following code to add the column layout option.
function smtp_mail_screen_options() {
global $smtp_menu_page;
$screen = get_current_screen();
if(!is_object($screen) || $screen->id !== $smtp_menu_page) {
return;
}
do_action('add_meta_boxes_smtp_mail_page', $smtp_menu_page);
/* User can choose between 1 or 2 columns (default 2) */
add_screen_option('layout_columns', array('max' => 2, 'default' => 1) );
/* Enqueue postbox script for handling the metaboxes */
wp_enqueue_script('postbox');
}
Fix Column Layout Setting
When you toggle the column layout setting, you may find that it isn’t working. To fix this, you need to add the dashboard-widgets
ID and metabox-holder$columns_css
class to the parent <div>
tag of the postbox container. Update the init_mail_settings
function with the following code to fix this issue.
function init_mail_settings() {
$screen = get_current_screen();
$columns = absint( $screen->get_columns() );
$columns_css = '';
if ( $columns ) {
$columns_css = " columns-$columns";
} ?>
<div class="wrap">
<h1 class="wp-heading-inline"><?php _e('SMTP Settings', 'theme-name'); ?></h1>
<div id="dashboard-widgets-wrap">
<div id="dashboard-widgets" class="metabox-holder<?php echo $columns_css; ?>">
<div id="postbox-container-1" class="postbox-container"><?php do_meta_boxes( $screen->id, 'normal', '' ); ?></div>
<div id="postbox-container-2" class="postbox-container"><?php do_meta_boxes( $screen->id, 'side', '' ); ?></div>
</div>
</div>
</div>
<?php }
Create Forms Using HTML
To create forms for managing SMTP (Simple Mail Transfer Protocol) settings and WordPress mail sending functionality, update the smtp_configuration_form
and wp_mail_form
functions (defined in the “Register Meta Boxes” step) with the following code.
function smtp_configuration_form() {
if(isset($_POST["submit"])) {
$smtp_config = [
'host' => $_POST['host'],
'port' => $_POST['port'],
'username' => $_POST['username'],
'password' => $_POST['password'],
'security_type' => $_POST['security-type'],
];
update_option( "smtp_config", $smtp_config );
}
$smtp_config = get_option( "smtp_config" ); ?>
<form id="smtp-conf" action="#" method="post">
<div class="textarea-wrap">
<label for="host" style="display: block"><?php _e('SMTP Host', 'theme-name'); ?></label>
<input type="text" name="host" id="host" placeholder="<?php _e('smtp.example.com', 'theme-name'); ?>" value="<?php echo isset($smtp_config['host']) ? $smtp_config['host'] : '' ?>" />
</div>
<div class="textarea-wrap">
<label for="port" style="display: block"><?php _e('SMTP Port', 'theme-name'); ?></label>
<input type="number" name="port" id="port" placeholder="<?php _e('25, 465 or 587', 'theme-name'); ?>" value="<?php echo isset($smtp_config['port']) ? $smtp_config['port'] : '' ?>" />
</div>
<div class="textarea-wrap">
<label for="username" style="display: block"><?php _e('SMTP Username', 'theme-name'); ?></label>
<input type="text" name="username" id="username" value="<?php echo isset($smtp_config['username']) ? $smtp_config['username'] : '' ?>" />
</div>
<div class="textarea-wrap">
<label for="password" style="display: block"><?php _e('SMTP Password', 'theme-name'); ?></label>
<input type="password" name="password" id="password" value="<?php echo isset($smtp_config['password']) ? $smtp_config['password'] : '' ?>" />
</div>
<div class="textarea-wrap">
<label for="security-type" style="display: block"><?php _e('SMTP Security', 'theme-name'); ?></label>
<select name="security-type" id="security-type">
<option><?php _e('None', 'theme-name'); ?></option>
<option value="tls" <?php echo isset($smtp_config['security_type']) && $smtp_config['security_type'] === 'tls' ? 'selected' : ''; ?>><?php _e('TLS', 'theme-name'); ?></option>
<option value="ssl" <?php echo isset($smtp_config['security_type']) && $smtp_config['security_type'] === 'ssl' ? 'selected' : ''; ?>><?php _e('SSL', 'theme-name'); ?></option>
</select>
</div>
<p class="submit" style="margin-top: 1rem">
<input type="submit" name="submit" id="save-conf" class="button button-primary" value="<?php _e('Submit', 'theme-name'); ?>" />
<br class="clear" />
</p>
</form>
<?php }
function wp_mail_form() {
if(isset($_POST["send"])) {
$email = $_POST['sender-email'];
$cc = $_POST['cc-email'];
$bcc = $_POST['bcc-email'];
wp_mail( $_POST['receiver-email'], $_POST['email-subject'], $_POST['message'], array( "From: {$email}", "Cc: {$cc}", "Bcc: {$bcc}" ) );
} ?>
<form id="wp-mail-sender" action="#" method="post">
<div class="textarea-wrap">
<label for="sender-email" style="display: block"><?php _e('From', 'theme-name'); ?></label>
<input type="text" name="sender-email" id="sender-email" />
</div>
<div class="textarea-wrap">
<label for="receiver-email" style="display: block"><?php _e('To', 'theme-name'); ?></label>
<input type="text" name="receiver-email" id="receiver-email" />
</div>
<div class="textarea-wrap">
<label for="cc-email" style="display: block"><?php _e('Cc', 'theme-name'); ?></label>
<input type="text" name="cc-email" id="cc-email" />
</div>
<div class="textarea-wrap">
<label for="bcc-email" style="display: block"><?php _e('Bcc', 'theme-name'); ?></label>
<input type="text" name="bcc-email" id="bcc-email" />
</div>
<div class="textarea-wrap">
<label for="email-subject" style="display: block"><?php _e('Subject', 'theme-name'); ?></label>
<input type="text" name="email-subject" id="email-subject" />
</div>
<div class="textarea-wrap">
<label for="message" style="display: block"><?php _e("Message", 'theme-name'); ?></label>
<textarea name="message" id="message" class="mceEditor" rows="10" cols="15"></textarea>
</div>
<p class="submit" style="margin-top: 1rem">
<input type="submit" name="send-mail" id="send-mail" class="button button-primary" value="<?php _e('Send', 'theme-name'); ?>" />
<br class="clear" />
</p>
</form>
<?php }
In the SMTP settings form, we use the update_option
and get_option
functions to store and retrieve form data. This data can be used to configure your SMTP server. For more information on setting up an SMTP server, refer to our article on How to Set Up SMTP in WordPress.
Complete Code to Create Forms Using Meta Boxes
Here’s the complete code for creating forms on custom admin pages using WordPress Meta Boxes:
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
function init_mail_settings() {
$screen = get_current_screen();
$columns = absint( $screen->get_columns() );
$columns_css = '';
if ( $columns ) {
$columns_css = " columns-$columns";
} ?>
<div class="wrap">
<h1 class="wp-heading-inline"><?php _e('SMTP Settings', 'theme-name'); ?></h1>
<div id="dashboard-widgets-wrap">
<div id="dashboard-widgets" class="metabox-holder<?php echo $columns_css; ?>">
<div id="postbox-container-1" class="postbox-container"><?php do_meta_boxes( $screen->id, 'normal', '' ); ?></div>
<div id="postbox-container-2" class="postbox-container"><?php do_meta_boxes( $screen->id, 'side', '' ); ?></div>
</div>
</div>
</div>
<?php }
function smtp_menu() {
global $smtp_menu_page;
$smtp_menu_page = add_menu_page(__('SMTP', 'theme-name'), __('SMTP', 'theme-name'), 'manage_options', 'setup-smtp', 'init_mail_settings', 'dashicons-email', 110);
add_action("load-{$smtp_menu_page}", "smtp_mail_screen_options");
add_action("admin_footer-{$smtp_menu_page}", "smtp_mail_footer_scripts");
}
add_action('admin_menu', 'smtp_menu');
function smtp_configuration_form() {
if(isset($_POST["submit"])) {
$smtp_config = [
'host' => $_POST['host'],
'port' => $_POST['port'],
'username' => $_POST['username'],
'password' => $_POST['password'],
'security_type' => $_POST['security-type'],
];
update_option( "smtp_config", $smtp_config );
}
$smtp_config = get_option( "smtp_config" ); ?>
<form id="smtp-conf" action="#" method="post">
<div class="textarea-wrap">
<label for="host" style="display: block"><?php _e('SMTP Host', 'theme-name'); ?></label>
<input type="text" name="host" id="host" placeholder="<?php _e('smtp.example.com', 'theme-name'); ?>" value="<?php echo isset($smtp_config['host']) ? $smtp_config['host'] : '' ?>" />
</div>
<div class="textarea-wrap">
<label for="port" style="display: block"><?php _e('SMTP Port', 'theme-name'); ?></label>
<input type="number" name="port" id="port" placeholder="<?php _e('25, 465 or 587', 'theme-name'); ?>" value="<?php echo isset($smtp_config['port']) ? $smtp_config['port'] : '' ?>" />
</div>
<div class="textarea-wrap">
<label for="username" style="display: block"><?php _e('SMTP Username', 'theme-name'); ?></label>
<input type="text" name="username" id="username" value="<?php echo isset($smtp_config['username']) ? $smtp_config['username'] : '' ?>" />
</div>
<div class="textarea-wrap">
<label for="password" style="display: block"><?php _e('SMTP Password', 'theme-name'); ?></label>
<input type="password" name="password" id="password" value="<?php echo isset($smtp_config['password']) ? $smtp_config['password'] : '' ?>" />
</div>
<div class="textarea-wrap">
<label for="security-type" style="display: block"><?php _e('SMTP Security', 'theme-name'); ?></label>
<select name="security-type" id="security-type">
<option><?php _e('None', 'theme-name'); ?></option>
<option value="tls" <?php echo isset($smtp_config['security_type']) && $smtp_config['security_type'] === 'tls' ? 'selected' : ''; ?>><?php _e('TLS', 'theme-name'); ?></option>
<option value="ssl" <?php echo isset($smtp_config['security_type']) && $smtp_config['security_type'] === 'ssl' ? 'selected' : ''; ?>><?php _e('SSL', 'theme-name'); ?></option>
</select>
</div>
<p class="submit" style="margin-top: 1rem">
<input type="submit" name="submit" id="save-conf" class="button button-primary" value="<?php _e('Submit', 'theme-name'); ?>" />
<br class="clear" />
</p>
</form>
<?php }
function wp_mail_form() {
if(isset($_POST["send"])) {
$email = $_POST['sender-email'];
$cc = $_POST['cc-email'];
$bcc = $_POST['bcc-email'];
wp_mail( $_POST['receiver-email'], $_POST['email-subject'], $_POST['message'], array( "From: {$email}", "Cc: {$cc}", "Bcc: {$bcc}" ) );
} ?>
<form id="wp-mail-sender" action="#" method="post">
<div class="textarea-wrap">
<label for="sender-email" style="display: block"><?php _e('From', 'theme-name'); ?></label>
<input type="text" name="sender-email" id="sender-email" />
</div>
<div class="textarea-wrap">
<label for="receiver-email" style="display: block"><?php _e('To', 'theme-name'); ?></label>
<input type="text" name="receiver-email" id="receiver-email" />
</div>
<div class="textarea-wrap">
<label for="cc-email" style="display: block"><?php _e('Cc', 'theme-name'); ?></label>
<input type="text" name="cc-email" id="cc-email" />
</div>
<div class="textarea-wrap">
<label for="bcc-email" style="display: block"><?php _e('Bcc', 'theme-name'); ?></label>
<input type="text" name="bcc-email" id="bcc-email" />
</div>
<div class="textarea-wrap">
<label for="email-subject" style="display: block"><?php _e('Subject', 'theme-name'); ?></label>
<input type="text" name="email-subject" id="email-subject" />
</div>
<div class="textarea-wrap">
<label for="message" style="display: block"><?php _e("Message", 'theme-name'); ?></label>
<textarea name="message" id="message" class="mceEditor" rows="10" cols="15"></textarea>
</div>
<p class="submit" style="margin-top: 1rem">
<input type="submit" name="send-mail" id="send-mail" class="button button-primary" value="<?php _e('Send', 'theme-name'); ?>" />
<br class="clear" />
</p>
</form>
<?php }
function smtp_mail_page_metaboxes() {
global $smtp_menu_page;
$screen = get_current_screen();
if(!is_object($screen) || $screen->id !== $smtp_menu_page) {
return;
}
add_meta_box('smtp-configuration', 'SMTP Configuration', 'smtp_configuration_form', $smtp_menu_page, 'normal', 'default');
add_meta_box('mail-system', 'Mail', 'wp_mail_form', $smtp_menu_page, 'side', 'default');
// add_meta_box( string $id, string $title, callable $callback, string|array|WP_Screen $screen = null, string $context = ‘advanced’, string $priority = ‘default’, array $callback_args = null )
}
add_action('add_meta_boxes_smtp_mail_page','smtp_mail_page_metaboxes');
function smtp_mail_screen_options() {
global $smtp_menu_page;
$screen = get_current_screen();
if(!is_object($screen) || $screen->id !== $smtp_menu_page) {
return;
}
do_action('add_meta_boxes_smtp_mail_page', $smtp_menu_page);
/* User can choose between 1 or 2 columns (default 2) */
add_screen_option('layout_columns', array('max' => 2, 'default' => 1) );
/* Enqueue postbox script for handling the metaboxes */
wp_enqueue_script('postbox');
}
function smtp_mail_footer_scripts() {
echo '<script>jQuery(document).ready(function(){if(postboxes){postboxes.add_postbox_toggles(pagenow);}});</script>';
}
For more advanced information on using the wp_mail
function, refer to our article on how to send emails with wp_mail.