/** * 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"> </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 ); }
/** * 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"> </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 ); }