meta_box = self::normalize( $meta_box );
$this->fields = &$this->meta_box['fields'];
// List of meta box field types
$this->types = array_unique( wp_list_pluck( $this->fields, 'type' ) );
// Load translation file
// Call directly because we define meta boxes in 'admin_init' hook (@see demo/demo.php)
// So the function won't run if we use 'add_action' to load textdomain here
self::load_textdomain();
// Enqueue common styles and scripts
add_action( 'admin_enqueue_scripts', array( &$this, 'admin_enqueue_scripts' ) );
foreach ( $this->types as $type )
{
$class = self::get_class_name( $type );
// Add additional actions for fields
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' ) );
}
/**
* Load plugin translation
*
* @link http://wordpress.stackexchange.com/a/33314 Translation Tutorial by the author
* @return void
*/
static function load_textdomain()
{
// l18n translation files
$locale = get_locale();
$dir = trailingslashit( RWMB_DIR . 'lang' );
$mofile = "{$dir}{$locale}.mo";
// In themes/plugins/mu-plugins directory
load_textdomain( 'rwmb', $mofile );
}
/**
* 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', RWMB_VER );
// Load clone script conditionally
$has_clone = false;
foreach ( $this->fields as $field )
{
if ( self::is_cloneable( $field ) )
$has_clone = true;
// Enqueue scripts and styles for fields
$class = self::get_class_name( $field['type'] );
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 );
}
/**************************************************
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 );
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 )
{
$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 clonable and non-cloneable fields to make easy to maintain
// Cloneable fields
if ( self::is_cloneable( $field ) )
{
$field_html = '';
$meta = (array) $meta;
foreach ( $meta as $meta_data )
{
add_filter( "rwmb_{$id}_html", array( &$this, 'add_delete_clone_button' ), 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( $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
$class = 'rwmb-field';
if ( isset( $field['class'] ) )
$class = $this->add_cssclass( $field[ 'class' ], $class );
// If the 'hidden' argument is set and TRUE, the div will be hidden
if ( isset( $field['hidden'] ) && $field['hidden'] )
$class = $this->add_cssclass( 'hidden', $class );
echo "
{$html}
";
}
// 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']}" );
}
/**
* Show begin HTML markup for fields
*
* @param string $html
* @param mixed $meta
* @param array $field
*
* @return string
*/
static function begin_html( $html, $meta, $field )
{
$class = 'rwmb-label';
if ( ! empty( $field['class'] ) )
$class = self::add_cssclass( $field['class'], $class );
if ( empty( $field['name'] ) )
return '