コード例 #1
0
    /**
     * Render the fields registered to the metabox.
     *
     * The $fields property is an indexed array of fields and their properties.
     * Accepted option for are:
     * 	id (string) The field ID. This value MUST be unique.
     * 	desc (string) [optional] The field description.
     * 	type (string) The type of field which should be registered. This can be any of the supported field types or a custom field type.
     * 		Core supported field types are:
     * 			checkbox
     * 			checkboxgroup
     * 			radio
     * 			radio_inline
     * 			select
     * 			text (input)
     * 			textarea
     * 			datepicker
     * 			slider
     * 			quicktag
     * 			rte
     * 	value (mixed) string | array [optional] The function name or class method to be used retrieve a value for the field.
     * 	size (string) [optional] The size if the text input and textarea field types.
     * 		NOTE: Only used for the `text` field type. Valid options: small', 'regular' or 'large'
     * 		NOTE: Only used for the `textarea` field type. Valid options: small' or 'large'
     * 	options (mixed) string | array [optional] Valid value depends on the field type being rendered.
     * 		Field type / valid value for options
     * 			checkboxgroup (array) An associative array where the key is the checkbox value and the value is the checkbox label.
     * 			radio / radio_inline (array) An associative array where the key is the radio value and the value is the radio label.
     * 			select (array) An associative array where the key is the option value and the value is the option name.
     * 			rte (array) @link http://codex.wordpress.org/Function_Reference/wp_editor#Arguments
     * 			slider (array) The slider options.
     * 				min (int) The minimum slider step.
     * 				max (int) The maximum slider step.
     * 				step (int) The step the slider steps at.
     * 	default	(mixed) The default value to be used.
     *
     * @access private
     * @since 0.8
     * @global $wp_version
     * @param $fields	array 	An indexed array of fields to render..
     *
     * @return string
     */
    private function fields($fields)
    {
        global $wp_version;
        // do_action( 'cn_metabox_table_before', $entry, $meta, $this->metabox );
        foreach ($fields as $field) {
            $defaults = array('before' => '', 'after' => '', 'desc' => '');
            $field = wp_parse_args($field, $defaults);
            // If the meta field has a specific method defined call the method and set the field value.
            // Otherwise, assume pulling from the meta table of the supplied object.
            if (isset($field['value']) && !empty($field['value'])) {
                $value = call_user_func(array($this->object, $field['value']));
            } else {
                $value = $this->object->getMeta(array('key' => $field['id'], 'single' => TRUE));
            }
            if (empty($value)) {
                $value = isset($field['default']) ? $field['default'] : '';
            }
            /**
             * Apply custom classes to a metabox table.
             *
             * @since 8.3.4
             *
             * @param array  $class An indexed array of classes that should applied to the table element.
             * @param string $type  The field type.
             * @param string $id    The field id.
             */
            $class = apply_filters('cn_metabox_table_class', array('cn-metabox-type-' . $field['type']), $field['type'], $field['id']);
            /**
             * Apply a custom id to a metabox table.
             *
             * @since 8.3.4
             *
             * @param string $id The field id.
             */
            $id = apply_filters('cn_metabox_table_id', 'cn-metabox-id-' . $field['id']);
            /**
             * Apply custom classes to a metabox table.
             *
             * @since 8.3.4
             *
             * @param array  $style An associative array of inline style attributes where the array key is the property and the array value is the property value.
             * @param string $type  The field type.
             * @param string $id    The field id.
             */
            $style = apply_filters('cn_metabox_table_style', array(), $field['type'], $field['id']);
            $class = cnHTML::attribute('class', $class);
            $id = cnHTML::attribute('id', $id);
            $style = cnHTML::attribute('style', $style);
            echo '<tr' . $class . $id . $style . '>';
            // For a label to be rendered the $field['name'] has to be supplied.
            // Show the label if $field['show_label'] is TRUE, OR, if it is not supplied assume TRUE and show it anyway.
            // The result will be the label will be shown unless specifically $field['show_label'] is set to FALSE.
            if (isset($field['name']) && !empty($field['name']) && (!isset($field['show_label']) || $field['show_label'] == TRUE)) {
                echo '<th class="cn-metabox-label">' . esc_html($field['name']) . '</th>';
            } elseif (isset($field['name']) && !empty($field['name']) && (isset($field['show_label']) && $field['show_label'] == TRUE)) {
                echo '<th class="cn-metabox-label">' . esc_html($field['name']) . '</th>';
            } elseif (!isset($field['show_label']) || $field['show_label'] == FALSE) {
                echo '<th class="cn-metabox-label-empty">&nbsp;</th>';
            }
            echo '<td>';
            echo empty($field['before']) ? '' : $field['before'];
            /**
             * Apply custom classes to the field type container element.
             *
             * NOTE: The dynamic portion of the hook is the field type.
             *
             * @since 8.3.4
             *
             * @param array  $class An indexed array of classes that should applied to the element.
             * @param string $id    The field id.
             */
            $class = apply_filters("cn_metabox_{$field['type']}_class", array("cn-meta-field-type-{$field['type']}"), $field['id']);
            /**
             * Apply a custom id to the field type container element.
             *
             * NOTE: The dynamic portion of the hook is the field type.
             *
             * @since 8.3.4
             *
             * @param string $id The field id.
             */
            $id = apply_filters("cn_metabox_{$field['type']}_id", '');
            /**
             * Apply custom classes to a field type container element.
             *
             * NOTE: The dynamic portion of the hook is the field type.
             *
             * @since 8.3.4
             *
             * @param array  $style An associative array of inline style attributes
             *                      where the array key is the property and the array value is the property value.
             * @param string $id    The field id.
             */
            $style = apply_filters("cn_metabox_{$field['type']}_style", array(), $field['id']);
            $class = cnHTML::attribute('class', $class);
            $id = cnHTML::attribute('id', $id);
            $style = cnHTML::attribute('style', $style);
            /**
             * Chance to manipulate the field value before rendering the field.
             *
             * NOTE: The dynamic portion of the hook is the field type.
             *
             * @since 0.8
             *
             * @param mixed $value The field value.
             * @param array $field The field attributes array.
             */
            $value = apply_filters("cn_meta_field_value-{$field['type']}", $value, $field);
            switch ($field['type']) {
                case 'checkbox':
                    cnHTML::field(array('type' => 'checkbox', 'prefix' => '', 'class' => 'cn-checkbox', 'id' => $field['id'], 'name' => $field['id'], 'label' => $field['desc'], 'before' => '<div' . $class . $id . $style . '>', 'after' => '</div>'), $value);
                    break;
                case 'checkboxgroup':
                case 'checkbox-group':
                    self::fieldDescription($field['desc']);
                    cnHTML::field(array('type' => 'checkbox-group', 'prefix' => '', 'class' => 'cn-checkbox', 'id' => $field['id'], 'name' => $field['id'] . '[]', 'display' => 'block', 'options' => $field['options'], 'before' => '<div' . $class . $id . $style . '>', 'after' => '</div>'), $value);
                    break;
                case 'radio':
                    self::fieldDescription($field['desc']);
                    cnHTML::field(array('type' => 'radio', 'prefix' => '', 'class' => 'cn-radio-option', 'id' => $field['id'], 'name' => $field['id'] . '[]', 'display' => 'block', 'options' => $field['options'], 'before' => '<div' . $class . $id . $style . '>', 'after' => '</div>'), $value);
                    break;
                case 'radio_inline':
                case 'radio-inline':
                    self::fieldDescription($field['desc']);
                    cnHTML::field(array('type' => 'radio', 'prefix' => '', 'class' => 'cn-radio-option', 'id' => $field['id'], 'name' => $field['id'] . '[]', 'display' => 'inline', 'options' => $field['options'], 'before' => '<div' . $class . $id . $style . '>', 'after' => '</div>'), $value);
                    break;
                case 'select':
                    cnHTML::field(array('type' => 'select', 'prefix' => '', 'class' => 'cn-select', 'id' => $field['id'], 'name' => $field['id'], 'display' => 'inline', 'options' => $field['options'], 'before' => '<div' . $class . $id . $style . '>', 'after' => '</div>'), $value);
                    self::fieldDescription($field['desc']);
                    break;
                case 'text':
                    $sizes = array('small', 'regular', 'large');
                    cnHTML::field(array('type' => 'text', 'prefix' => '', 'class' => isset($field['size']) && !empty($field['size']) && in_array($field['size'], $sizes) ? esc_attr($field['size']) . '-text' : 'large-text', 'id' => $field['id'], 'name' => $field['id'], 'before' => '<div' . $class . $id . $style . '>', 'after' => '</div>'), $value);
                    self::fieldDescription($field['desc']);
                    break;
                case 'textarea':
                    $sizes = array('small', 'large');
                    self::fieldDescription($field['desc']);
                    cnHTML::field(array('type' => 'textarea', 'prefix' => '', 'class' => isset($field['size']) && !empty($field['size']) && in_array($field['size'], $sizes) ? esc_attr($field['size']) . '-text' : 'small-text', 'id' => $field['id'], 'name' => $field['id'], 'rows' => 10, 'cols' => 50, 'before' => '<div' . $class . $id . $style . '>', 'after' => '</div>'), $value);
                    break;
                case 'datepicker':
                    printf('<input type="text" class="cn-datepicker" id="%1$s" name="%1$s" value="%2$s"/>', esc_attr($field['id']), !empty($value) ? date('m/d/Y', strtotime($value)) : '');
                    wp_enqueue_script('jquery-ui-datepicker');
                    wp_enqueue_style('cn-admin-jquery-datepicker');
                    add_action('admin_print_footer_scripts', array(__CLASS__, 'datepickerJS'));
                    add_action('wp_footer', array(__CLASS__, 'datepickerJS'));
                    self::fieldDescription($field['desc']);
                    break;
                case 'colorpicker':
                    self::fieldDescription($field['desc']);
                    printf('<input type="text" class="cn-colorpicker" id="%1$s" name="%1$s" value="%2$s"/>', esc_attr($field['id']), esc_attr($value));
                    wp_enqueue_style('wp-color-picker');
                    if (is_admin()) {
                        wp_enqueue_script('wp-color-picker');
                        add_action('admin_print_footer_scripts', array(__CLASS__, 'colorpickerJS'));
                    } else {
                        /*
                         * WordPress seems to only register the color picker scripts for use in the admin.
                         * So, for the frontend, we must manually register and then enqueue.
                         * @url http://wordpress.stackexchange.com/a/82722/59053
                         */
                        wp_enqueue_script('iris', admin_url('js/iris.min.js'), array('jquery-ui-draggable', 'jquery-ui-slider', 'jquery-touch-punch'), FALSE, 1);
                        wp_enqueue_script('wp-color-picker', admin_url('js/color-picker.min.js'), array('iris'), FALSE, 1);
                        $colorpicker_l10n = array('clear' => __('Clear', 'connections'), 'defaultString' => __('Default', 'connections'), 'pick' => __('Select Color', 'connections'), 'current' => __('Current Color', 'connections'));
                        wp_localize_script('wp-color-picker', 'wpColorPickerL10n', $colorpicker_l10n);
                        add_action('wp_footer', array(__CLASS__, 'colorpickerJS'));
                    }
                    break;
                case 'slider':
                    // Set the slider defaults.
                    $defaults = array('min' => 0, 'max' => 100, 'step' => 1, 'value' => 0);
                    $field['options'] = wp_parse_args(isset($field['options']) ? $field['options'] : array(), $defaults);
                    printf('<div class="cn-slider-container" id="cn-slider-%1$s"></div><input type="text" class="small-text" id="%1$s" name="%1$s" value="%2$s"/>', esc_attr($field['id']), absint($value));
                    self::fieldDescription($field['desc']);
                    $field['options']['value'] = absint($value);
                    self::$slider[$field['id']] = $field['options'];
                    wp_enqueue_script('jquery-ui-slider');
                    add_action('admin_print_footer_scripts', array(__CLASS__, 'sliderJS'));
                    add_action('wp_footer', array(__CLASS__, 'sliderJS'));
                    break;
                case 'quicktag':
                    self::fieldDescription($field['desc']);
                    echo '<div class="wp-editor-container">';
                    printf('<textarea class="wp-editor-area" rows="20" cols="40" id="%1$s" name="%1$s">%2$s</textarea>', esc_attr($field['id']), wp_kses_data($value));
                    echo '</div>';
                    self::$quickTagIDs[] = esc_attr($field['id']);
                    wp_enqueue_script('jquery');
                    add_action('admin_print_footer_scripts', array(__CLASS__, 'quickTagJS'));
                    add_action('wp_print_footer_scripts', array(__CLASS__, 'quickTagJS'));
                    break;
                case 'rte':
                    self::fieldDescription($field['desc']);
                    if ($wp_version >= 3.3 && function_exists('wp_editor')) {
                        // Set the rte defaults.
                        $defaults = array('textarea_name' => sprintf('%1$s', $field['id']));
                        $atts = wp_parse_args(isset($field['options']) ? $field['options'] : array(), $defaults);
                        wp_editor(cnSanitize::html($value), sprintf('%1$s', $field['id']), $atts);
                    } else {
                        /*
                         * If this is pre WP 3.3, lets drop in the quick tag editor instead.
                         */
                        echo '<div class="wp-editor-container">';
                        printf('<textarea class="wp-editor-area" rows="20" cols="40" id="%1$s" name="%1$s">%2$s</textarea>', esc_attr($field['id']), cnSanitize::quicktag($value));
                        echo '</div>';
                        self::$quickTagIDs[] = esc_attr($field['id']);
                        wp_enqueue_script('jquery');
                        add_action('admin_print_footer_scripts', array(__CLASS__, 'quickTagJS'));
                        add_action('wp_print_footer_scripts', array(__CLASS__, 'quickTagJS'));
                    }
                    break;
                case 'repeatable':
                    echo '<table id="' . esc_attr($field['id']) . '-repeatable" class="meta_box_repeatable" cellspacing="0">';
                    echo '<tbody>';
                    $i = 0;
                    // create an empty array
                    if ($meta == '' || $meta == array()) {
                        $keys = wp_list_pluck($field['repeatable'], 'id');
                        $meta = array(array_fill_keys($keys, NULL));
                    }
                    $meta = array_values($meta);
                    foreach ($meta as $row) {
                        echo '<tr>
										<td><span class="sort hndle"></span></td><td>';
                        // foreach ( $field['repeatable'] as $repeatable ) {
                        // 	if ( ! array_key_exists( $repeatable['id'], $meta[ $field['id'] ] ) ) $meta[ $field['id'] ][ $repeatable['id'] ] = NULL;
                        // 	echo '<label>' . $repeatable['label']  . '</label><p>';
                        // 	self::fields( $repeatable, $meta[ $i ][ $repeatable['id'] ], array( $field['id'], $i ) );
                        // 	echo '</p>';
                        // }
                        self::fields($field['repeatable']);
                        echo '</td><td><a class="meta_box_repeatable_remove" href="#"></a></td></tr>';
                        $i++;
                    }
                    // end each row
                    echo '</tbody>';
                    echo '
							<tfoot>
								<tr>
									<th colspan="4"><a class="meta_box_repeatable_add" href="#"></a></th>
								</tr>
							</tfoot>';
                    echo '</table>';
                    break;
                default:
                    do_action('cn_meta_field-' . $field['type'], $field, $value, $this->object);
                    break;
            }
            echo empty($field['after']) ? '' : $field['after'];
            echo '</td>', '</tr>';
        }
        // do_action( 'cn_metabox_table_after', $entry, $meta, $this->metabox );
    }
コード例 #2
0
    /**
     * Render the fields registered to the metabox.
     *
     * The $fields property is an indexed array of fields and their properties.
     * Accepted option for are:
     * 	id (string) The field ID. This value MUST be unique.
     * 	desc (string) [optional] The field description.
     * 	type (string) The type of field which should be registered. This can be any of the supported field types or a custom field type.
     * 		Core supported field types are:
     * 			checkbox
     * 			checkboxgroup
     * 			radio
     * 			radio_inline
     * 			select
     * 			text (input)
     * 			textarea
     * 			datepicker
     * 			slider
     * 			quicktag
     * 			rte
     * 	value (mixed) string | array [optional] The function name or class method to be used retrieve a value for the field.
     * 	size (string) [optional] The size if the text input and textarea field types.
     * 		NOTE: Only used for the `text` field type. Valid options: small', 'regular' or 'large'
     * 		NOTE: Only used for the `textarea` field type. Valid options: small' or 'large'
     * 	options (mixed) string | array [optional] Valid value depends on the field type being rendered.
     * 		Field type / valid value for options
     * 			checkboxgroup (array) An associative array where the key is the checkbox value and the value is the checkbox label.
     * 			radio / radio_inline (array) An associative array where the key is the radio value and the value is the radio label.
     * 			select (array) An associative array where the key is the option value and the value is the option name.
     * 			rte (array) @link http://codex.wordpress.org/Function_Reference/wp_editor#Arguments
     * 			slider (array) The slider options.
     * 				min (int) The minimum slider step.
     * 				max (int) The maximum slider step.
     * 				step (int) The step the slider steps at.
     * 	default	(mixed) The default value to be used.
     *
     * @access private
     * @since 0.8
     * @global $wp_version
     * @param $fields	array 	An indexed array of fields to render..
     *
     * @return string
     */
    private function fields($fields)
    {
        global $wp_version;
        // do_action( 'cn_metabox_table_before', $entry, $meta, $this->metabox );
        foreach ($fields as $field) {
            // If the meta field has a specific method defined call the method and set the field value.
            // Otherwise, assume pulling from the meta table of the supplied object.
            if (isset($field['value']) && !empty($field['value'])) {
                $value = call_user_func(array($this->object, $field['value']));
            } else {
                $value = $this->object->getMeta(array('key' => $field['id'], 'single' => TRUE));
            }
            if (empty($value)) {
                $value = isset($field['default']) ? $field['default'] : '';
            }
            $value = apply_filters('cn_meta_field_value-' . $field['type'], $value, $field);
            echo '<tr class="cn-metabox-type-' . sanitize_html_class($field['type']) . '" id="cn-metabox-id-' . sanitize_html_class($field['id']) . '">';
            // For a label to be rendered the $field['name'] has to be supplied.
            // Show the label if $field['show_label'] is TRUE, OR, if it is not supplied assume TRUE and show it anyway.
            // The result will be the label will be shown unless specifically $field['show_label'] is set to FALSE.
            if (isset($field['name']) && !empty($field['name']) && (!isset($field['show_label']) || $field['show_label'] == TRUE)) {
                echo '<th class="cn-metabox-label">' . esc_html($field['name']) . '</th>';
            } elseif (isset($field['name']) && !empty($field['name']) && (isset($field['show_label']) && $field['show_label'] == TRUE)) {
                echo '<th class="cn-metabox-label">' . esc_html($field['name']) . '</th>';
            } elseif (!isset($field['show_label']) || $field['show_label'] == FALSE) {
                echo '<th class="cn-metabox-label-empty">&nbsp;</th>';
            }
            echo '<td>';
            echo empty($field['before']) ? '' : $field['before'];
            switch ($field['type']) {
                case 'checkbox':
                    printf('<input type="checkbox" class="checkbox" id="%1$s" name="%1$s" value="1" %2$s/>', esc_attr($field['id']), checked('1', $value, FALSE));
                    // For a single checkbox we want to render the description as the label.
                    // Lets render it and unset it so it does not render twice.
                    if (isset($field['desc']) && !empty($field['desc'])) {
                        printf('<label for="%1$s"> %2$s</label>', esc_attr($field['id']), esc_html($field['desc']));
                        unset($field['desc']);
                    }
                    break;
                case 'checkboxgroup':
                    // For input groups we want to render the description before the field.
                    // Lets render it and unset it so it does not render twice.
                    if (isset($field['desc']) && !empty($field['desc'])) {
                        printf('<p class="description">%1$s</p>', esc_html($field['desc']));
                        unset($field['desc']);
                    }
                    echo '<div class="cn-checkbox-group">';
                    foreach ($field['options'] as $key => $label) {
                        echo '<div class="cn-checkbox-option">';
                        printf('<input type="checkbox" class="checkbox" id="%1$s[%2$s]" name="%1$s[]" value="%2$s"%3$s/>', esc_attr($field['id']), esc_attr($key), checked(TRUE, is_array($value) ? in_array($key, $value) : $key == $value, FALSE));
                        printf('<label for="%1$s[%2$s]"> %3$s</label>', esc_attr($field['id']), esc_attr($key), esc_html($label));
                        echo '</div>';
                    }
                    echo '</div>';
                    break;
                case 'radio':
                    // For input groups we want to render the description before the field.
                    // Lets render it and unset it so it does not render twice.
                    if (isset($field['desc']) && !empty($field['desc'])) {
                        printf('<p class="description">%1$s</p>', esc_html($field['desc']));
                        unset($field['desc']);
                    }
                    echo '<div class="cn-radio-group">';
                    foreach ($field['options'] as $key => $label) {
                        echo '<div class="cn-radio-option">';
                        printf('<input type="radio" class="checkbox" id="%1$s[%2$s]" name="%1$s" value="%2$s"%3$s/>', esc_attr($field['id']), esc_attr($key), checked($key, $value = empty($value) ? $key : $value, FALSE));
                        printf('<label for="%1$s[%2$s]"> %3$s</label>', esc_attr($field['id']), esc_attr($key), esc_html($label));
                        echo '</div>';
                    }
                    echo '</div>';
                    break;
                case 'radio_inline':
                    // For input groups we want to render the description before the field.
                    // Lets render it and unset it so it does not render twice.
                    if (isset($field['desc']) && !empty($field['desc'])) {
                        printf('<p class="description">%1$s</p>', esc_html($field['desc']));
                        unset($field['desc']);
                    }
                    echo '<div class="cn-radio-group">';
                    foreach ($field['options'] as $key => $label) {
                        echo '<span class="cn-radio-option">';
                        printf('<input type="radio" class="checkbox" id="%1$s[%2$s]" name="%1$s" value="%2$s"%3$s/>', esc_attr($field['id']), esc_attr($key), checked($key, $value = empty($value) ? $key : $value, FALSE));
                        printf('<label for="%1$s[%2$s]"> %3$s</label>', esc_attr($field['id']), esc_attr($key), esc_html($label));
                        echo '</span>';
                    }
                    echo '</div>';
                    break;
                case 'select':
                    // if ( isset($field['desc']) && ! empty($field['desc']) ) $out .= sprintf( '<span class="description">%1$s</span><br />', $field['desc'] );
                    printf('<select name="%1$s" id="%1$s">', $field['id']);
                    foreach ($field['options'] as $key => $label) {
                        printf('<option value="%1$s" %2$s>%3$s</option>', $key, selected($key, $value = empty($value) ? $key : $value, FALSE), $label);
                    }
                    echo '</select>';
                    break;
                case 'text':
                    $sizes = array('small', 'regular', 'large');
                    printf('<input type="text" class="%1$s-text" id="%2$s" name="%2$s" value="%3$s"/>', isset($field['size']) && !empty($field['size']) && in_array($field['size'], $sizes) ? esc_attr($field['size']) : 'large', esc_attr($field['id']), sanitize_text_field($value));
                    break;
                case 'textarea':
                    $sizes = array('small', 'large');
                    // For text areas we want to render the description before the field.
                    // Lets render it and unset it so it does not render twice.
                    if (isset($field['desc']) && !empty($field['desc'])) {
                        printf('<p class="description">%1$s</p>', esc_html($field['desc']));
                        unset($field['desc']);
                    }
                    printf('<textarea rows="10" cols="50" class="%1$s-text" id="%2$s" name="%2$s">%3$s</textarea>', isset($field['size']) && !empty($field['size']) && in_array($field['size'], $sizes) ? esc_attr($field['size']) : 'small', esc_attr($field['id']), esc_textarea($value));
                    break;
                case 'datepicker':
                    printf('<input type="text" class="cn-datepicker" id="%1$s" name="%1$s" value="%2$s"/>', esc_attr($field['id']), !empty($value) ? date('m/d/Y', strtotime($value)) : '');
                    $min = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '.min';
                    wp_enqueue_script('jquery-ui-datepicker');
                    wp_enqueue_style('cn-public-jquery-ui', CN_URL . "assets/css/jquery-ui-fresh{$min}.css", is_admin() ? array('cn-admin') : array('cn-public'), CN_CURRENT_VERSION);
                    add_action('admin_print_footer_scripts', array(__CLASS__, 'datepickerJS'));
                    add_action('wp_footer', array(__CLASS__, 'datepickerJS'));
                    break;
                case 'colorpicker':
                    // For color picker areas we want to render the description before the field.
                    // Lets render it and unset it so it does not render twice.
                    if (isset($field['desc']) && !empty($field['desc'])) {
                        printf('<p class="description">%1$s</p>', esc_html($field['desc']));
                        unset($field['desc']);
                    }
                    printf('<input type="text" class="cn-colorpicker" id="%1$s" name="%1$s" value="%2$s"/>', esc_attr($field['id']), esc_attr($value));
                    wp_enqueue_style('wp-color-picker');
                    if (is_admin()) {
                        wp_enqueue_script('wp-color-picker');
                        add_action('admin_print_footer_scripts', array(__CLASS__, 'colorpickerJS'));
                    } else {
                        /*
                         * WordPress seems to only register the color picker scripts for use in the admin.
                         * So, for the frontend, we must manually register and then enqueue.
                         * @url http://wordpress.stackexchange.com/a/82722/59053
                         */
                        wp_enqueue_script('iris', admin_url('js/iris.min.js'), array('jquery-ui-draggable', 'jquery-ui-slider', 'jquery-touch-punch'), FALSE, 1);
                        wp_enqueue_script('wp-color-picker', admin_url('js/color-picker.min.js'), array('iris'), FALSE, 1);
                        $colorpicker_l10n = array('clear' => __('Clear', 'connections'), 'defaultString' => __('Default', 'connections'), 'pick' => __('Select Color', 'connections'), 'current' => __('Current Color', 'connections'));
                        wp_localize_script('wp-color-picker', 'wpColorPickerL10n', $colorpicker_l10n);
                        add_action('wp_footer', array(__CLASS__, 'colorpickerJS'));
                    }
                    break;
                case 'slider':
                    // Set the slider defaults.
                    $defaults = array('min' => 0, 'max' => 100, 'step' => 1, 'value' => 0);
                    $field['options'] = wp_parse_args(isset($field['options']) ? $field['options'] : array(), $defaults);
                    printf('<div class="cn-slider-container" id="cn-slider-%1$s"></div><input type="text" class="small-text" id="%1$s" name="%1$s" value="%2$s"/>', esc_attr($field['id']), absint($value));
                    $field['options']['value'] = absint($value);
                    self::$slider[$field['id']] = $field['options'];
                    wp_enqueue_script('jquery-ui-slider');
                    add_action('admin_print_footer_scripts', array(__CLASS__, 'sliderJS'));
                    add_action('wp_footer', array(__CLASS__, 'sliderJS'));
                    break;
                case 'quicktag':
                    // For text areas we want to render the description before the field.
                    // Lets render it and unset it so it does not render twice.
                    if (isset($field['desc']) && !empty($field['desc'])) {
                        printf('<p class="description">%1$s</p>', esc_html($field['desc']));
                        unset($field['desc']);
                    }
                    echo '<div class="wp-editor-container">';
                    printf('<textarea class="wp-editor-area" rows="20" cols="40" id="%1$s" name="%1$s">%2$s</textarea>', esc_attr($field['id']), wp_kses_data($value));
                    echo '</div>';
                    self::$quickTagIDs[] = esc_attr($field['id']);
                    wp_enqueue_script('jquery');
                    add_action('admin_print_footer_scripts', array(__CLASS__, 'quickTagJS'));
                    add_action('wp_print_footer_scripts', array(__CLASS__, 'quickTagJS'));
                    break;
                case 'rte':
                    // For text areas we want to render the description before the field.
                    // Lets render it and unset it so it does not render twice.
                    if (isset($field['desc']) && !empty($field['desc'])) {
                        printf('<p class="description">%1$s</p>', esc_html($field['desc']));
                        unset($field['desc']);
                    }
                    if ($wp_version >= 3.3 && function_exists('wp_editor')) {
                        // Set the rte defaults.
                        $defaults = array('textarea_name' => sprintf('%1$s', $field['id']));
                        $atts = wp_parse_args(isset($field['options']) ? $field['options'] : array(), $defaults);
                        wp_editor(cnSanitize::html($value), sprintf('%1$s', $field['id']), $atts);
                    } else {
                        /*
                         * If this is pre WP 3.3, lets drop in the quick tag editor instead.
                         */
                        echo '<div class="wp-editor-container">';
                        printf('<textarea class="wp-editor-area" rows="20" cols="40" id="%1$s" name="%1$s">%2$s</textarea>', esc_attr($field['id']), cnSanitize::quicktag($value));
                        echo '</div>';
                        self::$quickTagIDs[] = esc_attr($field['id']);
                        wp_enqueue_script('jquery');
                        add_action('admin_print_footer_scripts', array(__CLASS__, 'quickTagJS'));
                        add_action('wp_print_footer_scripts', array(__CLASS__, 'quickTagJS'));
                    }
                    break;
                case 'repeatable':
                    echo '<table id="' . esc_attr($field['id']) . '-repeatable" class="meta_box_repeatable" cellspacing="0">';
                    echo '<tbody>';
                    $i = 0;
                    // create an empty array
                    if ($meta == '' || $meta == array()) {
                        $keys = wp_list_pluck($field['repeatable'], 'id');
                        $meta = array(array_fill_keys($keys, NULL));
                    }
                    $meta = array_values($meta);
                    foreach ($meta as $row) {
                        echo '<tr>
										<td><span class="sort hndle"></span></td><td>';
                        // foreach ( $field['repeatable'] as $repeatable ) {
                        // 	if ( ! array_key_exists( $repeatable['id'], $meta[ $field['id'] ] ) ) $meta[ $field['id'] ][ $repeatable['id'] ] = NULL;
                        // 	echo '<label>' . $repeatable['label']  . '</label><p>';
                        // 	self::fields( $repeatable, $meta[ $i ][ $repeatable['id'] ], array( $field['id'], $i ) );
                        // 	echo '</p>';
                        // }
                        self::fields($field['repeatable']);
                        echo '</td><td><a class="meta_box_repeatable_remove" href="#"></a></td></tr>';
                        $i++;
                    }
                    // end each row
                    echo '</tbody>';
                    echo '
							<tfoot>
								<tr>
									<th colspan="4"><a class="meta_box_repeatable_add" href="#"></a></th>
								</tr>
							</tfoot>';
                    echo '</table>';
                    break;
                default:
                    do_action('cn_meta_field-' . $field['type'], $field, $value, $this->object);
                    break;
            }
            if (isset($field['desc']) && !empty($field['desc'])) {
                printf('<span class="description"> %1$s</span>', esc_html($field['desc']));
            }
            echo empty($field['after']) ? '' : $field['after'];
            echo '</td>', '</tr>';
        }
        // do_action( 'cn_metabox_table_after', $entry, $meta, $this->metabox );
    }