Of course, here’s the working example.
This creates a settings page under appearance. To recreate the issue, check both checkboxes and hit save. then uncheck the second one and hit save again. then try to uncheck the first one and hit save. The first one will remain checked after the page reloads.
<?php
/**
* CMB2 Theme Options
* @version 0.1.0
*/
class my_theme_options {
/**
* Option key, and option page slug
* @var string
*/
protected $key = 'my_settings';
/**
* Options page metabox id
* @var string
*/
protected $metabox_id = 'my_option_metabox';
/**
* Options Page title
* @var string
*/
protected $title = '';
/**
* Options Page hook
* @var string
*/
protected $options_page = '';
/**
* Holds an instance of the object
*
* @var my_theme_options
*/
protected static $instance = null;
/**
* Returns the running object
*
* @return my_theme_options
*/
public static function get_instance() {
if ( null === self::$instance ) {
self::$instance = new self();
self::$instance->hooks();
}
return self::$instance;
}
/**
* Constructor
* @since 0.1.0
*/
protected function __construct() {
// Set our title
$this->title = __( 'My Settings', 'textdomain' );
}
/**
* Initiate our hooks
* @since 0.1.0
*/
public function hooks() {
add_action( 'admin_init', array( $this, 'init' ) );
add_action( 'admin_menu', array( $this, 'add_options_page' ) );
add_action( 'cmb2_admin_init', array( $this, 'add_options_page_metabox' ) );
}
/**
* Register our setting to WP
* @since 0.1.0
*/
public function init() {
register_setting( $this->key, $this->key );
}
/**
* Add menu options page
* @since 0.1.0
*/
public function add_options_page() {
$this->options_page = add_theme_page( $this->title, $this->title, 'manage_options', 'my-settings', array( $this, 'admin_page_display' ) );
// Include CMB CSS in the head to avoid FOUC
add_action( "admin_print_styles-{$this->options_page}", array( 'CMB2_hookup', 'enqueue_cmb_css' ) );
}
/**
* Admin page markup. Mostly handled by CMB2
* @since 0.1.0
*/
public function admin_page_display() { ?>
<div class="wrap cmb2-options-page <?php echo $this->key; ?>">
<h2><?php echo esc_html( get_admin_page_title() ); ?></h2>
<?php cmb2_metabox_form( $this->metabox_id, $this->key ); ?>
</div>
<?php
}
/**
* Add the options metabox to the array of metaboxes
* @since 0.1.0
*/
function add_options_page_metabox() {
$prefix = 'prefix_';
// hook in our save notices
add_action( "cmb2_save_options-page_fields_{$this->metabox_id}", array( $this, 'settings_notices' ), 10, 2 );
$cmb = new_cmb2_box( array(
'id' => $this->metabox_id,
'hookup' => false,
'cmb_styles' => false,
'show_on' => array(
// These are important, don't remove
'key' => 'options-page',
'value' => array( $this->key, )
),
) );
// Set our CMB2 fields
$cmb->add_field( array(
'name' => __( 'Global Settings', 'textdomain' ),
'type' => 'title',
'id' => $prefix . 'global_title',
) );
$cmb->add_field( array(
'name' => __( 'Setting one', 'textdomain' ),
'id' => $prefix . 'setting_one',
'type' => 'multicheck_inline',
'select_all_button' => false,
'options' => array(
'page' => 'page',
)
));
$cmb->add_field( array(
'name' => __( 'Setting two', 'textdomain' ),
'id' => $prefix . 'setting_two',
'type' => 'multicheck_inline',
'select_all_button' => false,
'options' => array(
'page' => 'page',
)
));
// uncommenting this would fix the issue. right now I'm hiding this field via css.
// $cmb->add_field( array(
// 'name' => 'Test Text',
// 'default' => 'I am fixing cmb2, nothing else.',
// 'id' => $prefix . 'checkbox_fix',
// 'type' => 'text',
// ) );
}
/**
* Register settings notices for display
*
* @since 0.1.0
* @param int $object_id Option key
* @param array $updated Array of updated fields
* @return void
*/
public function settings_notices( $object_id, $updated ) {
if ( $object_id !== $this->key || empty( $updated ) ) {
return;
}
add_settings_error( $this->key . '-notices', '', __( 'Settings updated.', 'textdomain' ), 'updated' );
settings_errors( $this->key . '-notices' );
}
/**
* Public getter method for retrieving protected/private variables
* @since 0.1.0
* @param string $field Field to retrieve
* @return mixed Field value or exception is thrown
*/
public function __get( $field ) {
// Allowed fields to retrieve
if ( in_array( $field, array( 'key', 'metabox_id', 'title', 'options_page' ), true ) ) {
return $this->{$field};
}
throw new Exception( 'Invalid property: ' . $field );
}
}
/**
* Helper function to get/return the my_theme_options object
* @since 0.1.0
* @return my_theme_options object
*/
function my_theme_options() {
return my_theme_options::get_instance();
}
/**
* Wrapper function around cmb2_get_option
* @since 0.1.0
* @param string $key Options array key
* @param mixed $default Optional default value
* @return mixed Option value
*/
function prefix_get_option( $key = '', $default = array() ) {
if ( function_exists( 'cmb2_get_option' ) ) {
// Use cmb2_get_option as it passes through some key filters.
return cmb2_get_option( my_theme_options()->key, $key, $default );
}
// Fallback to get_option if CMB2 is not loaded yet.
$opts = get_option( my_theme_options()->key, $default );
$val = $default;
if ( 'all' == $key ) {
$val = $opts;
} elseif ( array_key_exists( $key, $opts ) && false !== $opts[ $key ] ) {
$val = $opts[ $key ];
}
return $val;
}
// Get it started
my_theme_options();