meta_box = self::normalize( $meta_box );
$this->fields = &$this->meta_box['fields'];
$this->validation = &$this->meta_box['validation'];
// Allow users to show/hide (e.g. include/exclude) meta boxes
// 1st action applies to all meta boxes
// 2nd action applies to only current meta box
$show = true;
$show = apply_filters( 'rwmb_show', $show, $meta_box );
$show = apply_filters( "rwmb_show_{$this->meta_box['id']}", $show, $this->meta_box );
if ( !$show )
return;
// Enqueue common styles and scripts
add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
// Add additional actions for fields
foreach ( $this->fields as $field )
{
$class = self::get_class_name( $field );
if ( method_exists( $class, 'add_actions' ) )
call_user_func( array( $class, 'add_actions' ) );
}
// Add meta box
foreach ( $this->meta_box['pages'] as $page )
{
add_action( "add_meta_boxes_{$page}", array( $this, 'add_meta_boxes' ) );
}
// Save post meta
add_action( 'save_post', array( $this, 'save_post' ) );
// Attachment uses other hooks
// @see wp_update_post(), wp_insert_attachment()
add_action( 'edit_attachment', array( $this, 'save_post' ) );
add_action( 'add_attachment', array( $this, 'save_post' ) );
}
/**
* Enqueue common styles
*
* @return void
*/
function admin_enqueue_scripts()
{
$screen = get_current_screen();
// Enqueue scripts and styles for registered pages (post types) only
if ( 'post' != $screen->base || ! in_array( $screen->post_type, $this->meta_box['pages'] ) )
return;
wp_enqueue_style( 'rwmb', RWMB_CSS_URL . 'style.css', array(), RWMB_VER );
// Load clone script conditionally
$has_clone = false;
foreach ( $this->fields as $field )
{
if ( $field['clone'] )
$has_clone = true;
// Enqueue scripts and styles for fields
$class = self::get_class_name( $field );
if ( method_exists( $class, 'admin_enqueue_scripts' ) )
call_user_func( array( $class, 'admin_enqueue_scripts' ) );
}
if ( $has_clone )
wp_enqueue_script( 'rwmb-clone', RWMB_JS_URL . 'clone.js', array( 'jquery' ), RWMB_VER, true );
if ( $this->validation )
{
wp_enqueue_script( 'jquery-validate', RWMB_JS_URL . 'jquery.validate.min.js', array( 'jquery' ), RWMB_VER, true );
wp_enqueue_script( 'rwmb-validate', RWMB_JS_URL . 'validate.js', array( 'jquery-validate' ), RWMB_VER, true );
}
// Auto save
if ( $this->meta_box['autosave'] )
wp_enqueue_script( 'rwmb-autosave', RWMB_JS_URL . 'autosave.js', array( 'jquery' ), RWMB_VER, true );
}
/**************************************************
SHOW META BOX
**************************************************/
/**
* Add meta box for multiple post types
*
* @return void
*/
function add_meta_boxes()
{
foreach ( $this->meta_box['pages'] as $page )
{
add_meta_box(
$this->meta_box['id'],
$this->meta_box['title'],
array( $this, 'show' ),
$page,
$this->meta_box['context'],
$this->meta_box['priority']
);
}
}
/**
* Callback function to show fields in meta box
*
* @return void
*/
public function show()
{
global $post;
$saved = self::has_been_saved( $post->ID, $this->fields );
// Container
echo sprintf(
'
',
$this->meta_box['autosave'] ? 'true' : 'false'
);
wp_nonce_field( "rwmb-save-{$this->meta_box['id']}", "nonce_{$this->meta_box['id']}" );
// Allow users to add custom code before meta box content
// 1st action applies to all meta boxes
// 2nd action applies to only current meta box
do_action( 'rwmb_before' );
do_action( "rwmb_before_{$this->meta_box['id']}" );
foreach ( $this->fields as $field )
{
$this->show_field( $field, $post->ID, $saved );
}
// Include validation settings for this meta-box
if ( isset( $this->validation ) && $this->validation )
{
echo '
';
}
// Allow users to add custom code after meta box content
// 1st action applies to all meta boxes
// 2nd action applies to only current meta box
do_action( 'rwmb_after' );
do_action( "rwmb_after_{$this->meta_box['id']}" );
// End container
echo '
';
}
/**
* Callback function to show a field in meta box
*
* @return void
*/
public function show_field( $field, $post_id, $saved = false )
{
$group = ''; // Empty the clone-group field
$type = $field['type'];
$id = $field['id'];
$meta = self::apply_field_class_filters( $field, 'meta', '', $post_id, $saved );
$meta = apply_filters( "rwmb_{$type}_meta", $meta );
$meta = apply_filters( "rwmb_{$id}_meta", $meta );
$begin = self::apply_field_class_filters( $field, 'begin_html', '', $meta );
// Apply filter to field begin HTML
// 1st filter applies to all fields
// 2nd filter applies to all fields with the same type
// 3rd filter applies to current field only
$begin = apply_filters( 'rwmb_begin_html', $begin, $field, $meta );
$begin = apply_filters( "rwmb_{$type}_begin_html", $begin, $field, $meta );
$begin = apply_filters( "rwmb_{$id}_begin_html", $begin, $field, $meta );
// Separate code for cloneable and non-cloneable fields to make easy to maintain
// Cloneable fields
if ( $field['clone'] )
{
if ( isset( $field['clone-group'] ) )
$group = " clone-group='{$field['clone-group']}'";
$meta = (array) $meta;
$field_html = '';
foreach ( $meta as $index => $meta_data )
{
$sub_field = $field;
$sub_field['field_name'] = $field['field_name'] . "[{$index}]";
if ( $field['multiple'] )
$sub_field['field_name'] .= '[]';
add_filter( "rwmb_{$id}_html", array( $this, 'add_clone_buttons' ), 10, 3 );
// Wrap field HTML in a div with class="rwmb-clone" if needed
$input_html = '
';
// Call separated methods for displaying each type of field
$input_html .= self::apply_field_class_filters( $sub_field, 'html', '', $meta_data );
// Apply filter to field HTML
// 1st filter applies to all fields with the same type
// 2nd filter applies to current field only
$input_html = apply_filters( "rwmb_{$type}_html", $input_html, $field, $meta_data );
$input_html = apply_filters( "rwmb_{$id}_html", $input_html, $field, $meta_data );
$input_html .= '
';
$field_html .= $input_html;
}
}
// Non-cloneable fields
else
{
// Call separated methods for displaying each type of field
$field_html = self::apply_field_class_filters( $field, 'html', '', $meta );
// Apply filter to field HTML
// 1st filter applies to all fields with the same type
// 2nd filter applies to current field only
$field_html = apply_filters( "rwmb_{$type}_html", $field_html, $field, $meta );
$field_html = apply_filters( "rwmb_{$id}_html", $field_html, $field, $meta );
}
$end = self::apply_field_class_filters( $field, 'end_html', '', $meta );
// Apply filter to field end HTML
// 1st filter applies to all fields
// 2nd filter applies to all fields with the same type
// 3rd filter applies to current field only
$end = apply_filters( 'rwmb_end_html', $end, $field, $meta );
$end = apply_filters( "rwmb_{$type}_end_html", $end, $field, $meta );
$end = apply_filters( "rwmb_{$id}_end_html", $end, $field, $meta );
// Apply filter to field wrapper
// This allow users to change whole HTML markup of the field wrapper (i.e. table row)
// 1st filter applies to all fields with the same type
// 2nd filter applies to current field only
$html = apply_filters( "rwmb_{$type}_wrapper_html", "{$begin}{$field_html}{$end}", $field, $meta );
$html = apply_filters( "rwmb_{$id}_wrapper_html", $html, $field, $meta );
// Display label and input in DIV and allow user-defined classes to be appended
$classes = array( 'rwmb-field', "rwmb-{$field['type']}-wrapper" );
if ( 'hidden' === $field['type'] )
$classes[] = 'hidden';
if ( !empty( $field['required'] ) )
$classes[] = 'required';
if ( !empty( $field['class'] ) )
$classes[] = $field['class'];
printf(
$field['before'] . '
%s
' . $field['after'],
implode( ' ', $classes ),
$group,
$html
);
}
/**
* Show begin HTML markup for fields
*
* @param string $html
* @param mixed $meta
* @param array $field
*
* @return string
*/
static function begin_html( $html, $meta, $field )
{
if ( empty( $field['name'] ) )
return '