field = $field; } /** * Default fallback. Allows rendering fields via "cmb_render_$name" hook * @since 1.0.0 * @param string $name Non-existent method name * @param array $arguments All arguments passed to the method */ public function __call( $name, $arguments ) { // When a non-registered field is called, send it through an action. do_action( "cmb_render_$name", $this->field->args(), $this->field->escaped_value(), $this->field->object_id, $this->field->object_type, $this ); } /** * Render a field (and handle repeatable) * @since 1.1.0 */ public function render() { if ( $this->field->args( 'repeatable' ) ) { $this->render_repeatable_field(); } else { $this->_render(); } } /** * Render a field type * @since 1.1.0 */ protected function _render() { echo $this->{$this->field->type()}(); } /** * Checks if we can get a post object, and if so, uses `get_the_terms` which utilizes caching * @since 1.0.2 * @return mixed Array of terms on success */ public function get_object_terms() { $object_id = $this->field->object_id; $taxonomy = $this->field->args( 'taxonomy' ); if ( ! $post = get_post( $object_id ) ) { $cache_key = 'cmb-cache-'. $taxonomy .'-'. $object_id; // Check cache $cached = $test = get_transient( $cache_key ); if ( $cached ) return $cached; $cached = wp_get_object_terms( $object_id, $taxonomy ); // Do our own (minimal) caching. Long enough for a page-load. $set = set_transient( $cache_key, $cached, 60 ); return $cached; } // WP caches internally so it's better to use return get_the_terms( $post, $taxonomy ); } /** * Determine a file's extension * @since 1.0.0 * @param string $file File url * @return string|false File extension or false */ public function get_file_ext( $file ) { $parsed = @parse_url( $file, PHP_URL_PATH ); return $parsed ? strtolower( pathinfo( $parsed, PATHINFO_EXTENSION ) ) : false; } /** * Determines if a file has a valid image extension * @since 1.0.0 * @param string $file File url * @return bool Whether file has a valid image extension */ public function is_valid_img_ext( $file ) { $file_ext = $this->get_file_ext( $file ); $this->valid = empty( $this->valid ) ? (array) apply_filters( 'cmb_valid_img_types', array( 'jpg', 'jpeg', 'png', 'gif', 'ico', 'icon' ) ) : $this->valid; return ( $file_ext && in_array( $file_ext, $this->valid ) ); } /** * Handles parsing and filtering attributes while preserving any passed in via field config. * @since 1.1.0 * @param array $args Override arguments * @param string $element Element for filter * @param array $defaults Default arguments * @return array Parsed and filtered arguments */ public function parse_args( $args, $element, $defaults ) { return wp_parse_args( apply_filters( "cmb_{$element}_attributes", $this->field->maybe_set_attributes( $args ), $this->field, $this ), $defaults ); } /** * Combines attributes into a string for a form element * @since 1.1.0 * @param array $attrs Attributes to concatenate * @param array $attr_exclude Attributes that should NOT be concatenated * @return string String of attributes for form element */ public function concat_attrs( $attrs, $attr_exclude = array() ) { $attributes = ''; foreach ( $attrs as $attr => $val ) { if ( ! in_array( $attr, (array) $attr_exclude, true ) ) $attributes .= sprintf( ' %s="%s"', $attr, $val ); } return $attributes; } /** * Generates html for an option element * @since 1.1.0 * @param string $opt_label Option label * @param string $opt_value Option value * @param mixed $selected Selected attribute if option is selected * @return string Generated option element html */ public function option( $opt_label, $opt_value, $selected ) { return sprintf( "\t".'', $opt_value, selected( $selected, true, false ), $opt_label )."\n"; } /** * Generates options html * @since 1.1.0 * @param array $args Optional arguments * @param string $method Method to generate individual option item * @return string Concatenated html options */ public function concat_options( $args = array(), $method = 'list_input' ) { $options = (array) $this->field->args( 'options' ); $saved_value = $this->field->escaped_value(); $value = $saved_value ? $saved_value : $this->field->args( 'default' ); $_options = ''; $i = 1; foreach ( $options as $option_key => $option ) { // Check for the "old" way $opt_label = is_array( $option ) && array_key_exists( 'name', $option ) ? $option['name'] : $option; $opt_value = is_array( $option ) && array_key_exists( 'value', $option ) ? $option['value'] : $option_key; // Check if this option is the value of the input $is_current = $value == $opt_value; if ( ! empty( $args ) ) { // Clone args & modify for just this item $this_args = $args; $this_args['value'] = $opt_value; $this_args['label'] = $opt_label; if ( $is_current ) $this_args['checked'] = 'checked'; $_options .= $this->$method( $this_args, $i ); } else { $_options .= $this->option( $opt_label, $opt_value, $is_current ); } $i++; } return $_options; } /** * Generates html for list item with input * @since 1.1.0 * @param array $args Override arguments * @param int $i Iterator value * @return string Gnerated list item html */ public function list_input( $args = array(), $i ) { $args = $this->parse_args( $args, 'list_input', array( 'type' => 'radio', 'class' => 'cmb_option', 'name' => $this->_name(), 'id' => $this->_id( $i ), 'value' => $this->field->escaped_value(), 'label' => '', ) ); return sprintf( "\t".'
%s', $this->textarea( array( 'class' => 'cmb_textarea_code' ) ) ); } public function wysiwyg( $args = array() ) { extract( $this->parse_args( $args, 'input', array( 'id' => $this->_id(), 'value' => $this->field->escaped_value( 'stripslashes' ), 'desc' => $this->_desc( true ), 'options' => $this->field->args( 'options' ), ) ) ); wp_editor( $value, $id, $options ); echo $desc; } public function text_date_timestamp() { $meta_value = $this->field->escaped_value(); $value = ! empty( $meta_value ) ? date( $this->field->args( 'date_format' ), $meta_value ) : ''; return $this->input( array( 'class' => 'cmb_text_small cmb_datepicker', 'value' => $value ) ); } public function text_datetime_timestamp( $meta_value = '' ) { $desc = ''; if ( ! $meta_value ) { $meta_value = $this->field->escaped_value(); // This will be used if there is a select_timezone set for this field $tz_offset = $this->field->field_timezone_offset(); if ( ! empty( $tz_offset ) ) { $meta_value -= $tz_offset; } $desc = $this->_desc(); } $inputs = array( $this->input( array( 'class' => 'cmb_text_small cmb_datepicker', 'name' => $this->_name( '[date]' ), 'id' => $this->_id( '_date' ), 'value' => ! empty( $meta_value ) ? date( $this->field->args( 'date_format' ), $meta_value ) : '', 'desc' => '', ) ), $this->input( array( 'class' => 'cmb_timepicker text_time', 'name' => $this->_name( '[time]' ), 'id' => $this->_id( '_time' ), 'value' => ! empty( $meta_value ) ? date( $this->field->args( 'time_format' ), $meta_value ) : '', 'desc' => $desc, ) ) ); return implode( "\n", $inputs ); } public function text_datetime_timestamp_timezone() { $meta_value = $this->field->escaped_value(); $datetime = unserialize( $meta_value ); $meta_value = $tzstring = false; if ( $datetime && $datetime instanceof DateTime ) { $tz = $datetime->getTimezone(); $tzstring = $tz->getName(); $meta_value = $datetime->getTimestamp() + $tz->getOffset( new DateTime( 'NOW' ) ); } $inputs = $this->text_datetime_timestamp( $meta_value ); $inputs .= ''. $this->_desc(); return $inputs; } public function select_timezone() { $this->field->args['default'] = $this->field->args( 'default' ) ? $this->field->args( 'default' ) : cmb_Meta_Box::timezone_string(); $meta_value = $this->field->escaped_value(); return ''; } public function colorpicker() { $meta_value = $this->field->escaped_value(); $hex_color = '(([a-fA-F0-9]){3}){1,2}$'; if ( preg_match( '/^' . $hex_color . '/i', $meta_value ) ) // Value is just 123abc, so prepend #. $meta_value = '#' . $meta_value; elseif ( ! preg_match( '/^#' . $hex_color . '/i', $meta_value ) ) // Value doesn't match #123abc, so sanitize to just #. $meta_value = "#"; return $this->input( array( 'class' => 'cmb_colorpicker cmb_text_small', 'value' => $meta_value ) ); } public function title() { extract( $this->parse_args( array(), 'title', array( 'tag' => $this->field->object_type == 'post' ? 'h5' : 'h3', 'class' => 'cmb_metabox_title', 'name' => $this->field->args( 'name' ), 'desc' => $this->_desc( true ), ) ) ); return sprintf( '<%1$s class="%2$s">%3$s%1$s>%4$s', $tag, $class, $name, $desc ); } public function select( $args = array() ) { $args = $this->parse_args( $args, 'select', array( 'class' => 'cmb_select', 'name' => $this->_name(), 'id' => $this->_id(), 'desc' => $this->_desc( true ), 'options' => $this->concat_options(), ) ); $attrs = $this->concat_attrs( $args, array( 'desc', 'options' ) ); return sprintf( '%s', $attrs, $args['options'], $args['desc'] ); } public function taxonomy_select() { $names = $this->get_object_terms(); $saved_term = is_wp_error( $names ) || empty( $names ) ? $this->field->args( 'default' ) : $names[0]->slug; $terms = get_terms( $this->field->args( 'taxonomy' ), 'hide_empty=0' ); $options = ''; foreach ( $terms as $term ) { $selected = $saved_term == $term->slug; $options .= $this->option( $term->name, $term->slug, $selected ); } return $this->select( array( 'options' => $options ) ); } public function radio( $args = array(), $type = 'radio' ) { extract( $this->parse_args( $args, $type, array( 'class' => 'cmb_radio_list cmb_list', 'options' => $this->concat_options( array( 'label' => 'test' ) ), 'desc' => $this->_desc( true ), ) ) ); return sprintf( '