Meta Box - Version 4.7

Version Description

  • Improvement: add attributes for all input fields (text, number, email, ...) so users can add any custom attributes for them. Also added default attributes required, disabled, readonly, maxlength and pattern for those fields as well. These attributes will be merged into the attributes.
  • Improvement: add js_options for color field which allows users to define custom color palettes and other attributes for color picker. See the options in Iris page.
  • Fix: fix for file and image uploaded via file_advanced and image_advanced not showing up.
Download this release

Release Info

Developer rilwis
Plugin Icon 128x128 Meta Box
Version 4.7
Comparing to
See all releases

Code changes from version 4.6 to 4.7

inc/field.php CHANGED
@@ -397,7 +397,33 @@ if ( ! class_exists( 'RWMB_Field ' ) )
397
  */
398
  static function normalize_field( $field )
399
  {
400
- return $field;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
401
  }
402
 
403
  /**
397
  */
398
  static function normalize_field( $field )
399
  {
400
+ return wp_parse_args( $field, array(
401
+ 'attributes' => array()
402
+ ) );
403
+ }
404
+
405
+ /**
406
+ * Renders an attribute array into an html attributes string
407
+ *
408
+ * @param array $attributes
409
+ *
410
+ * @return string
411
+ */
412
+ static function render_attributes( $attributes )
413
+ {
414
+ $attr_string = '';
415
+ foreach ( $attributes as $key => $value )
416
+ {
417
+ if ( $value )
418
+ {
419
+ $attr_string .= sprintf(
420
+ ' %s="%s"',
421
+ $key,
422
+ esc_attr( $value )
423
+ );
424
+ }
425
+ }
426
+ return $attr_string;
427
  }
428
 
429
  /**
inc/fields/checkbox.php CHANGED
@@ -2,9 +2,12 @@
2
  // Prevent loading this file directly
3
  defined( 'ABSPATH' ) || exit;
4
 
 
 
 
5
  if ( ! class_exists( 'RWMB_Checkbox_Field' ) )
6
  {
7
- class RWMB_Checkbox_Field extends RWMB_Field
8
  {
9
  /**
10
  * Enqueue scripts and styles
@@ -26,14 +29,32 @@ if ( ! class_exists( 'RWMB_Checkbox_Field' ) )
26
  */
27
  static function html( $meta, $field )
28
  {
 
 
29
  return sprintf(
30
- '<input type="checkbox" class="rwmb-checkbox" name="%s" id="%s" value="1" %s>',
31
- $field['field_name'],
32
- $field['id'],
33
  checked( ! empty( $meta ), 1, false )
34
  );
35
  }
36
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  /**
38
  * Set the value of checkbox to 1 or 0 instead of 'checked' and empty string
39
  * This prevents using default value once the checkbox has been unchecked
2
  // Prevent loading this file directly
3
  defined( 'ABSPATH' ) || exit;
4
 
5
+ // Make sure "input" field is loaded
6
+ require_once RWMB_FIELDS_DIR . 'input.php';
7
+
8
  if ( ! class_exists( 'RWMB_Checkbox_Field' ) )
9
  {
10
+ class RWMB_Checkbox_Field extends RWMB_Input_Field
11
  {
12
  /**
13
  * Enqueue scripts and styles
29
  */
30
  static function html( $meta, $field )
31
  {
32
+ $attributes = $field['attributes'];
33
+ $attributes['value'] = 1;
34
  return sprintf(
35
+ '<input %s value="1" %s>',
36
+ self::render_attributes( $attributes ),
 
37
  checked( ! empty( $meta ), 1, false )
38
  );
39
  }
40
 
41
+ /**
42
+ * Normalize parameters for field
43
+ *
44
+ * @param array $field
45
+ *
46
+ * @return array
47
+ */
48
+ static function normalize_field( $field )
49
+ {
50
+ $field = parent::normalize_field( $field );
51
+ $field['attributes']['list'] = false;
52
+ $field['attributes']['type'] = 'checkbox';
53
+ $field['attributes']['class'] = 'rwmb-checkbox';
54
+
55
+ return $field;
56
+ }
57
+
58
  /**
59
  * Set the value of checkbox to 1 or 0 instead of 'checked' and empty string
60
  * This prevents using default value once the checkbox has been unchecked
inc/fields/color.php CHANGED
@@ -2,9 +2,12 @@
2
  // Prevent loading this file directly
3
  defined( 'ABSPATH' ) || exit;
4
 
 
 
 
5
  if ( ! class_exists( 'RWMB_Color_Field' ) )
6
  {
7
- class RWMB_Color_Field extends RWMB_Field
8
  {
9
  /**
10
  * Enqueue scripts and styles
@@ -17,25 +20,6 @@ if ( ! class_exists( 'RWMB_Color_Field' ) )
17
  wp_enqueue_script( 'rwmb-color', RWMB_JS_URL . 'color.js', array( 'wp-color-picker' ), RWMB_VER, true );
18
  }
19
 
20
- /**
21
- * Get field HTML
22
- *
23
- * @param mixed $meta
24
- * @param array $field
25
- *
26
- * @return string
27
- */
28
- static function html( $meta, $field )
29
- {
30
- return sprintf(
31
- '<input class="rwmb-color" type="text" name="%s" id="%s" value="%s" size="%s">',
32
- $field['field_name'],
33
- empty( $field['clone'] ) ? $field['id'] : '',
34
- $meta,
35
- $field['size']
36
- );
37
- }
38
-
39
  /**
40
  * Don't save '#' when no color is chosen
41
  *
@@ -61,9 +45,26 @@ if ( ! class_exists( 'RWMB_Color_Field' ) )
61
  static function normalize_field( $field )
62
  {
63
  $field = wp_parse_args( $field, array(
64
- 'size' => 7,
 
 
 
 
 
 
 
 
 
65
  ) );
66
 
 
 
 
 
 
 
 
 
67
  return $field;
68
  }
69
  }
2
  // Prevent loading this file directly
3
  defined( 'ABSPATH' ) || exit;
4
 
5
+ // Make sure "text" field is loaded
6
+ require_once RWMB_FIELDS_DIR . 'text.php';
7
+
8
  if ( ! class_exists( 'RWMB_Color_Field' ) )
9
  {
10
+ class RWMB_Color_Field extends RWMB_Text_Field
11
  {
12
  /**
13
  * Enqueue scripts and styles
20
  wp_enqueue_script( 'rwmb-color', RWMB_JS_URL . 'color.js', array( 'wp-color-picker' ), RWMB_VER, true );
21
  }
22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  /**
24
  * Don't save '#' when no color is chosen
25
  *
45
  static function normalize_field( $field )
46
  {
47
  $field = wp_parse_args( $field, array(
48
+ 'size' => 7,
49
+ 'maxlength' => 7,
50
+ 'pattern' => '^#+([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$',
51
+ 'js_options' => array(),
52
+ ) );
53
+
54
+ $field['js_options'] = wp_parse_args( $field['js_options'], array(
55
+ 'defaultColor' => false,
56
+ 'hide' => true,
57
+ 'palettes' => true,
58
  ) );
59
 
60
+ $field = parent::normalize_field( $field );
61
+
62
+ $field['attributes'] = wp_parse_args( $field['attributes'], array(
63
+ 'data-options' => wp_json_encode( $field['js_options'] ),
64
+ ) );
65
+
66
+ $field['attributes']['class'] = 'rwmb-color';
67
+
68
  return $field;
69
  }
70
  }
inc/fields/date.php CHANGED
@@ -2,9 +2,12 @@
2
  // Prevent loading this file directly
3
  defined( 'ABSPATH' ) || exit;
4
 
 
 
 
5
  if ( ! class_exists( 'RWMB_Date_Field' ) )
6
  {
7
- class RWMB_Date_Field extends RWMB_Field
8
  {
9
  /**
10
  * Enqueue scripts and styles
@@ -16,7 +19,7 @@ if ( ! class_exists( 'RWMB_Date_Field' ) )
16
  $url = RWMB_CSS_URL . 'jqueryui';
17
  wp_register_style( 'jquery-ui-core', "{$url}/jquery.ui.core.css", array(), '1.8.17' );
18
  wp_register_style( 'jquery-ui-theme', "{$url}/jquery.ui.theme.css", array(), '1.8.17' );
19
- wp_register_style( 'wp-datepicker', RWMB_CSS_URL ."datepicker.css", array( 'jquery-ui-core', 'jquery-ui-theme' ), '1.8.17' );
20
  wp_enqueue_style( 'jquery-ui-datepicker', "{$url}/jquery.ui.datepicker.css", array( 'wp-datepicker' ), '1.8.17' );
21
 
22
  // Load localized scripts
@@ -39,25 +42,6 @@ if ( ! class_exists( 'RWMB_Date_Field' ) )
39
  wp_enqueue_script( 'rwmb-date', RWMB_JS_URL . 'date.js', $deps, RWMB_VER, true );
40
  }
41
 
42
- /**
43
- * Get field HTML
44
- *
45
- * @param mixed $meta
46
- * @param array $field
47
- *
48
- * @return string
49
- */
50
- static function html( $meta, $field )
51
- {
52
- return sprintf(
53
- '<input type="text" class="rwmb-date" name="%s" value="%s" id="%s" size="%s" data-options="%s" />',
54
- $field['field_name'],
55
- $meta,
56
- isset( $field['clone'] ) && $field['clone'] ? '' : $field['id'],
57
- $field['size'],
58
- esc_attr( wp_json_encode( $field['js_options'] ) )
59
- );
60
- }
61
 
62
  /**
63
  * Normalize parameters for field
@@ -69,7 +53,6 @@ if ( ! class_exists( 'RWMB_Date_Field' ) )
69
  static function normalize_field( $field )
70
  {
71
  $field = wp_parse_args( $field, array(
72
- 'size' => 30,
73
  'js_options' => array(),
74
  ) );
75
 
@@ -80,6 +63,14 @@ if ( ! class_exists( 'RWMB_Date_Field' ) )
80
  'showButtonPanel' => true,
81
  ) );
82
 
 
 
 
 
 
 
 
 
83
  return $field;
84
  }
85
  }
2
  // Prevent loading this file directly
3
  defined( 'ABSPATH' ) || exit;
4
 
5
+ // Make sure "text" field is loaded
6
+ require_once RWMB_FIELDS_DIR . 'text.php';
7
+
8
  if ( ! class_exists( 'RWMB_Date_Field' ) )
9
  {
10
+ class RWMB_Date_Field extends RWMB_Text_Field
11
  {
12
  /**
13
  * Enqueue scripts and styles
19
  $url = RWMB_CSS_URL . 'jqueryui';
20
  wp_register_style( 'jquery-ui-core', "{$url}/jquery.ui.core.css", array(), '1.8.17' );
21
  wp_register_style( 'jquery-ui-theme', "{$url}/jquery.ui.theme.css", array(), '1.8.17' );
22
+ wp_register_style( 'wp-datepicker', RWMB_CSS_URL . 'datepicker.css', array( 'jquery-ui-core', 'jquery-ui-theme' ), '1.8.17' );
23
  wp_enqueue_style( 'jquery-ui-datepicker', "{$url}/jquery.ui.datepicker.css", array( 'wp-datepicker' ), '1.8.17' );
24
 
25
  // Load localized scripts
42
  wp_enqueue_script( 'rwmb-date', RWMB_JS_URL . 'date.js', $deps, RWMB_VER, true );
43
  }
44
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
 
46
  /**
47
  * Normalize parameters for field
53
  static function normalize_field( $field )
54
  {
55
  $field = wp_parse_args( $field, array(
 
56
  'js_options' => array(),
57
  ) );
58
 
63
  'showButtonPanel' => true,
64
  ) );
65
 
66
+ $field['attributes'] = wp_parse_args( $field['attributes'], array(
67
+ 'data-options' => wp_json_encode( $field['js_options'] ),
68
+ ) );
69
+
70
+ $field = parent::normalize_field( $field );
71
+
72
+ $field['attributes']['class'] = 'rwmb-date';
73
+
74
  return $field;
75
  }
76
  }
inc/fields/datetime.php CHANGED
@@ -2,9 +2,12 @@
2
  // Prevent loading this file directly
3
  defined( 'ABSPATH' ) || exit;
4
 
 
 
 
5
  if ( ! class_exists( 'RWMB_Datetime_Field' ) )
6
  {
7
- class RWMB_Datetime_Field extends RWMB_Field
8
  {
9
  /**
10
  * Translate date format from jQuery UI datepicker to PHP date()
@@ -39,7 +42,7 @@ if ( ! class_exists( 'RWMB_Datetime_Field' ) )
39
  wp_register_style( 'jquery-ui-core', "{$url}/jquery.ui.core.css", array(), '1.8.17' );
40
  wp_register_style( 'jquery-ui-theme', "{$url}/jquery.ui.theme.css", array(), '1.8.17' );
41
  wp_register_style( 'jquery-ui-datepicker', "{$url}/jquery.ui.datepicker.css", array( 'jquery-ui-core', 'jquery-ui-theme' ), '1.8.17' );
42
- wp_register_style( 'wp-datepicker', RWMB_CSS_URL ."datepicker.css", array( 'jquery-ui-core', 'jquery-ui-theme' ), '1.8.17' );
43
  wp_register_style( 'jquery-ui-slider', "{$url}/jquery.ui.slider.css", array( 'jquery-ui-core', 'jquery-ui-theme' ), '1.8.17' );
44
  wp_enqueue_style( 'jquery-ui-timepicker', "{$url}/jquery-ui-timepicker-addon.min.css", array( 'jquery-ui-datepicker', 'jquery-ui-slider', 'wp-datepicker' ), '1.5.0' );
45
 
@@ -53,7 +56,7 @@ if ( ! class_exists( 'RWMB_Datetime_Field' ) )
53
  *
54
  * Note: we use full locale (de-DE) and fallback to short locale (de)
55
  */
56
- $locale = str_replace( '_', '-', get_locale() );
57
  $locale_short = substr( $locale, 0, 2 );
58
 
59
  wp_register_script( 'jquery-ui-timepicker-i18n', "{$url}/jquery-ui-timepicker-addon-i18n.min.js", array( 'jquery-ui-timepicker' ), '1.5.0', true );
@@ -83,27 +86,6 @@ if ( ! class_exists( 'RWMB_Datetime_Field' ) )
83
  ) );
84
  }
85
 
86
- /**
87
- * Get field HTML
88
- *
89
- * @param mixed $meta
90
- * @param array $field
91
- *
92
- * @return string
93
- */
94
- static function html( $meta, $field )
95
- {
96
- $meta = $field['timestamp'] && $meta ? date( self::translate_format( $field ), intval( $meta ) ) : $meta;
97
- return sprintf(
98
- '<input type="text" class="rwmb-datetime" name="%s" value="%s" id="%s" size="%s" data-options="%s">',
99
- $field['field_name'],
100
- $meta,
101
- $field['clone'] ? '' : $field['id'],
102
- $field['size'],
103
- esc_attr( wp_json_encode( $field['js_options'] ) )
104
- );
105
- }
106
-
107
  /**
108
  * Calculates the timestamp from the datetime string and returns it
109
  * if $field['timestamp'] is set or the datetime string if not
@@ -125,6 +107,32 @@ if ( ! class_exists( 'RWMB_Datetime_Field' ) )
125
  return $d ? $d->getTimestamp() : 0;
126
  }
127
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  /**
129
  * Normalize parameters for field
130
  *
@@ -135,20 +143,20 @@ if ( ! class_exists( 'RWMB_Datetime_Field' ) )
135
  static function normalize_field( $field )
136
  {
137
  $field = wp_parse_args( $field, array(
138
- 'size' => 30,
139
- 'js_options' => array(),
140
- 'timestamp' => false,
141
  ) );
142
 
143
  // Deprecate 'format', but keep it for backward compatible
144
  // Use 'js_options' instead
145
  $field['js_options'] = wp_parse_args( $field['js_options'], array(
146
- 'dateFormat' => empty( $field['format'] ) ? 'yy-mm-dd' : $field['format'],
147
- 'timeFormat' => 'HH:mm',
148
- 'showButtonPanel' => true,
149
- 'separator' => ' ',
150
  ) );
151
 
 
 
 
 
152
  return $field;
153
  }
154
 
2
  // Prevent loading this file directly
3
  defined( 'ABSPATH' ) || exit;
4
 
5
+ // Make sure "text" field is loaded
6
+ require_once RWMB_FIELDS_DIR . 'date.php';
7
+
8
  if ( ! class_exists( 'RWMB_Datetime_Field' ) )
9
  {
10
+ class RWMB_Datetime_Field extends RWMB_Input_Field
11
  {
12
  /**
13
  * Translate date format from jQuery UI datepicker to PHP date()
42
  wp_register_style( 'jquery-ui-core', "{$url}/jquery.ui.core.css", array(), '1.8.17' );
43
  wp_register_style( 'jquery-ui-theme', "{$url}/jquery.ui.theme.css", array(), '1.8.17' );
44
  wp_register_style( 'jquery-ui-datepicker', "{$url}/jquery.ui.datepicker.css", array( 'jquery-ui-core', 'jquery-ui-theme' ), '1.8.17' );
45
+ wp_register_style( 'wp-datepicker', RWMB_CSS_URL . 'datepicker.css', array( 'jquery-ui-core', 'jquery-ui-theme' ), '1.8.17' );
46
  wp_register_style( 'jquery-ui-slider', "{$url}/jquery.ui.slider.css", array( 'jquery-ui-core', 'jquery-ui-theme' ), '1.8.17' );
47
  wp_enqueue_style( 'jquery-ui-timepicker', "{$url}/jquery-ui-timepicker-addon.min.css", array( 'jquery-ui-datepicker', 'jquery-ui-slider', 'wp-datepicker' ), '1.5.0' );
48
 
56
  *
57
  * Note: we use full locale (de-DE) and fallback to short locale (de)
58
  */
59
+ $locale = str_replace( '_', '-', get_locale() );
60
  $locale_short = substr( $locale, 0, 2 );
61
 
62
  wp_register_script( 'jquery-ui-timepicker-i18n', "{$url}/jquery-ui-timepicker-addon-i18n.min.js", array( 'jquery-ui-timepicker' ), '1.5.0', true );
86
  ) );
87
  }
88
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  /**
90
  * Calculates the timestamp from the datetime string and returns it
91
  * if $field['timestamp'] is set or the datetime string if not
107
  return $d ? $d->getTimestamp() : 0;
108
  }
109
 
110
+ /**
111
+ * Get meta value
112
+ *
113
+ * @param int $post_id
114
+ * @param bool $saved
115
+ * @param array $field
116
+ *
117
+ * @return mixed
118
+ */
119
+ static function meta( $post_id, $saved, $field )
120
+ {
121
+ $meta = parent::meta( $post_id, $saved, $field );
122
+ if ( is_array( $meta ) )
123
+ {
124
+ foreach ( $meta as $key => $value )
125
+ {
126
+ $meta[$key] = $field['timestamp'] && $value ? date( self::translate_format( $field ), intval( $value ) ) : $value;
127
+ }
128
+ }
129
+ else
130
+ {
131
+ $meta = $field['timestamp'] && $meta ? date( self::translate_format( $field ), intval( $meta ) ) : $meta;
132
+ }
133
+ return $meta;
134
+ }
135
+
136
  /**
137
  * Normalize parameters for field
138
  *
143
  static function normalize_field( $field )
144
  {
145
  $field = wp_parse_args( $field, array(
146
+ 'timestamp' => false,
 
 
147
  ) );
148
 
149
  // Deprecate 'format', but keep it for backward compatible
150
  // Use 'js_options' instead
151
  $field['js_options'] = wp_parse_args( $field['js_options'], array(
152
+ 'timeFormat' => 'HH:mm',
153
+ 'separator' => ' ',
 
 
154
  ) );
155
 
156
+ $field = RWMB_Date_Field::normalize_field( $field );
157
+
158
+ $field['attributes']['class'] = 'rwmb-datetime';
159
+
160
  return $field;
161
  }
162
 
inc/fields/email.php CHANGED
@@ -10,23 +10,20 @@ if ( ! class_exists( 'RWMB_Email_Field' ) )
10
  class RWMB_Email_Field extends RWMB_Text_Field
11
  {
12
  /**
13
- * Get field HTML
14
  *
15
- * @param mixed $meta
16
  * @param array $field
17
  *
18
- * @return string
19
  */
20
- static function html( $meta, $field )
21
  {
22
- return sprintf(
23
- '<input type="email" class="rwmb-email" name="%s" id="%s" value="%s" size="%s" placeholder="%s"/>',
24
- $field['field_name'],
25
- $field['id'],
26
- $meta,
27
- $field['size'],
28
- $field['placeholder']
29
- );
30
  }
31
 
32
  /**
10
  class RWMB_Email_Field extends RWMB_Text_Field
11
  {
12
  /**
13
+ * Normalize parameters for field
14
  *
 
15
  * @param array $field
16
  *
17
+ * @return array
18
  */
19
+ static function normalize_field( $field )
20
  {
21
+ $field = parent::normalize_field( $field );
22
+
23
+ $field['attributes']['type'] = 'email';
24
+ $field['attributes']['class'] = 'rwmb-email';
25
+
26
+ return $field;
 
 
27
  }
28
 
29
  /**
inc/fields/hidden.php CHANGED
@@ -2,26 +2,28 @@
2
  // Prevent loading this file directly
3
  defined( 'ABSPATH' ) || exit;
4
 
 
 
 
5
  if ( ! class_exists( 'RWMB_Hidden_Field' ) )
6
  {
7
- class RWMB_Hidden_Field extends RWMB_Field
8
  {
9
  /**
10
- * Get field HTML
11
  *
12
- * @param mixed $meta
13
  * @param array $field
14
  *
15
- * @return string
16
  */
17
- static function html( $meta, $field )
18
  {
19
- return sprintf(
20
- '<input type="hidden" class="rwmb-hidden" name="%s" id="%s" value="%s">',
21
- $field['field_name'],
22
- $field['id'],
23
- $meta
24
  );
 
 
25
  }
26
  }
27
  }
2
  // Prevent loading this file directly
3
  defined( 'ABSPATH' ) || exit;
4
 
5
+ // Make sure "input" field is loaded
6
+ require_once RWMB_FIELDS_DIR . 'input.php';
7
+
8
  if ( ! class_exists( 'RWMB_Hidden_Field' ) )
9
  {
10
+ class RWMB_Hidden_Field extends RWMB_Input_Field
11
  {
12
  /**
13
+ * Normalize parameters for field
14
  *
 
15
  * @param array $field
16
  *
17
+ * @return array
18
  */
19
+ static function normalize_field( $field )
20
  {
21
+ $field['attributes'] = array(
22
+ 'name' => $field['field_name'],
23
+ 'id' => $field['clone'] ? false : $field['id']
 
 
24
  );
25
+
26
+ return $field;
27
  }
28
  }
29
  }
inc/fields/input.php ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // Prevent loading this file directly
3
+ defined( 'ABSPATH' ) || exit;
4
+
5
+ if ( ! class_exists( 'RWMB_Input_Field' ) )
6
+ {
7
+ class RWMB_Input_Field extends RWMB_Field
8
+ {
9
+ /**
10
+ * Get field HTML
11
+ *
12
+ * @param mixed $meta
13
+ * @param array $field
14
+ *
15
+ * @return string
16
+ */
17
+ static function html( $meta, $field )
18
+ {
19
+ $attributes = $field['attributes'];
20
+ $attributes['value'] = $meta;
21
+ return sprintf(
22
+ '<input %s>%s',
23
+ self::render_attributes( $attributes ),
24
+ self::datalist_html( $field )
25
+ );
26
+ }
27
+
28
+ /**
29
+ * Normalize parameters for field
30
+ *
31
+ * @param array $field
32
+ *
33
+ * @return array
34
+ */
35
+ static function normalize_field( $field )
36
+ {
37
+ $field = parent::normalize_field( $field );
38
+ $field = wp_parse_args( $field, array(
39
+ 'datalist' => false,
40
+ 'disabled' => false,
41
+ 'required' => false,
42
+ 'readonly' => false
43
+ ) );
44
+ if ( $field['datalist'] )
45
+ {
46
+ $field['datalist'] = wp_parse_args( $field['datalist'], array(
47
+ 'id' => $field['id'] . '_list',
48
+ 'options' => array()
49
+ ) );
50
+ }
51
+
52
+ $field['attributes'] = wp_parse_args( $field['attributes'], array(
53
+ 'disabled' => $field['disabled'],
54
+ 'list' => $field['datalist'] ? $field['datalist']['id'] : false,
55
+ 'readonly' => $field['readonly'],
56
+ 'required' => $field['required'],
57
+ 'name' => $field['field_name'],
58
+ 'id' => $field['clone'] ? false : $field['id']
59
+ ) );
60
+
61
+ return $field;
62
+ }
63
+
64
+ /**
65
+ * Create datalist, if any
66
+ *
67
+ * @param array $field
68
+ *
69
+ * @return array
70
+ */
71
+ static function datalist_html( $field )
72
+ {
73
+ if ( ! $field['datalist'] )
74
+ return '';
75
+
76
+ $datalist = $field['datalist'];
77
+ $html = sprintf(
78
+ '<datalist id="%s">',
79
+ $datalist['id']
80
+ );
81
+
82
+ foreach ( $datalist['options'] as $option )
83
+ {
84
+ $html .= sprintf( '<option value="%s"></option>', $option );
85
+ }
86
+
87
+ $html .= '</datalist>';
88
+
89
+ return $html;
90
+ }
91
+ }
92
+ }
inc/fields/number.php CHANGED
@@ -2,31 +2,13 @@
2
  // Prevent loading this file directly
3
  defined( 'ABSPATH' ) || exit;
4
 
 
 
 
5
  if ( ! class_exists( 'RWMB_Number_Field' ) )
6
  {
7
- class RWMB_Number_Field extends RWMB_Field
8
  {
9
- /**
10
- * Get field HTML
11
- *
12
- * @param mixed $meta
13
- * @param array $field
14
- *
15
- * @return string
16
- */
17
- static function html( $meta, $field )
18
- {
19
- return sprintf(
20
- '<input type="number" class="rwmb-number" name="%s" id="%s" value="%s" step="%s" min="%s" placeholder="%s"/>',
21
- $field['field_name'],
22
- empty( $field['clone'] ) ? $field['id'] : '',
23
- $meta,
24
- $field['step'],
25
- $field['min'],
26
- $field['placeholder']
27
- );
28
- }
29
-
30
  /**
31
  * Normalize parameters for field
32
  *
@@ -36,11 +18,23 @@ if ( ! class_exists( 'RWMB_Number_Field' ) )
36
  */
37
  static function normalize_field( $field )
38
  {
 
 
39
  $field = wp_parse_args( $field, array(
40
  'step' => 1,
41
  'min' => 0,
 
42
  ) );
43
 
 
 
 
 
 
 
 
 
 
44
  return $field;
45
  }
46
  }
2
  // Prevent loading this file directly
3
  defined( 'ABSPATH' ) || exit;
4
 
5
+ // Make sure "input" field is loaded
6
+ require_once RWMB_FIELDS_DIR . 'input.php';
7
+
8
  if ( ! class_exists( 'RWMB_Number_Field' ) )
9
  {
10
+ class RWMB_Number_Field extends RWMB_Input_Field
11
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  /**
13
  * Normalize parameters for field
14
  *
18
  */
19
  static function normalize_field( $field )
20
  {
21
+ $field = parent::normalize_field( $field );
22
+
23
  $field = wp_parse_args( $field, array(
24
  'step' => 1,
25
  'min' => 0,
26
+ 'max' => false,
27
  ) );
28
 
29
+ $field['attributes'] = wp_parse_args( $field['attributes'], array(
30
+ 'step' => $field['step'],
31
+ 'max' => $field['max'],
32
+ 'min' => $field['min'],
33
+ ) );
34
+
35
+ $field['attributes']['type'] = 'number';
36
+ $field['attributes']['class'] = 'rwmb-number';
37
+
38
  return $field;
39
  }
40
  }
inc/fields/password.php CHANGED
@@ -10,22 +10,20 @@ if ( ! class_exists( 'RWMB_Password_Field' ) )
10
  class RWMB_Password_Field extends RWMB_Text_Field
11
  {
12
  /**
13
- * Get field HTML
14
  *
15
- * @param mixed $meta
16
  * @param array $field
17
  *
18
- * @return string
19
  */
20
- static function html( $meta, $field )
21
  {
22
- return sprintf(
23
- '<input type="password" class="rwmb-password" name="%s" id="%s" value="%s" size="%s" />',
24
- $field['field_name'],
25
- $field['id'],
26
- $meta,
27
- $field['size']
28
- );
29
  }
30
  }
31
  }
10
  class RWMB_Password_Field extends RWMB_Text_Field
11
  {
12
  /**
13
+ * Normalize parameters for field
14
  *
 
15
  * @param array $field
16
  *
17
+ * @return array
18
  */
19
+ static function normalize_field( $field )
20
  {
21
+ $field = parent::normalize_field( $field );
22
+
23
+ $field['attributes']['type'] = 'password';
24
+ $field['attributes']['class'] = 'rwmb-password';
25
+
26
+ return $field;
 
27
  }
28
  }
29
  }
inc/fields/post.php CHANGED
@@ -139,7 +139,7 @@ if ( ! class_exists( 'RWMB_Post_Field' ) )
139
  $post = $query->next_post();
140
  $title = apply_filters( 'rwmb_post_field_title', $post->post_title, $post );
141
  $title = apply_filters( "rwmb_{$field['id']}_field_title", $title, $post );
142
- $options[$post->ID] = $post->post_title;
143
  }
144
  }
145
 
139
  $post = $query->next_post();
140
  $title = apply_filters( 'rwmb_post_field_title', $post->post_title, $post );
141
  $title = apply_filters( "rwmb_{$field['id']}_field_title", $title, $post );
142
+ $options[$post->ID] = $title;
143
  }
144
  }
145
 
inc/fields/radio.php CHANGED
@@ -2,9 +2,12 @@
2
  // Prevent loading this file directly
3
  defined( 'ABSPATH' ) || exit;
4
 
 
 
 
5
  if ( ! class_exists( 'RWMB_Radio_Field' ) )
6
  {
7
- class RWMB_Radio_Field extends RWMB_Field
8
  {
9
  /**
10
  * Get field HTML
@@ -16,15 +19,16 @@ if ( ! class_exists( 'RWMB_Radio_Field' ) )
16
  */
17
  static function html( $meta, $field )
18
  {
19
- $html = array();
20
- $tpl = '<label><input type="radio" class="rwmb-radio" name="%s" value="%s"%s> %s</label>';
 
21
 
22
  foreach ( $field['options'] as $value => $label )
23
  {
24
- $html[] = sprintf(
 
25
  $tpl,
26
- $field['field_name'],
27
- $value,
28
  checked( $value, $meta, false ),
29
  $label
30
  );
@@ -33,6 +37,25 @@ if ( ! class_exists( 'RWMB_Radio_Field' ) )
33
  return implode( ' ', $html );
34
  }
35
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  /**
37
  * Output the field value
38
  * Display option name instead of option value
2
  // Prevent loading this file directly
3
  defined( 'ABSPATH' ) || exit;
4
 
5
+ // Make sure "input" field is loaded
6
+ require_once RWMB_FIELDS_DIR . 'input.php';
7
+
8
  if ( ! class_exists( 'RWMB_Radio_Field' ) )
9
  {
10
+ class RWMB_Radio_Field extends RWMB_Input_Field
11
  {
12
  /**
13
  * Get field HTML
19
  */
20
  static function html( $meta, $field )
21
  {
22
+ $html = array();
23
+ $tpl = '<label><input %s %s> %s</label>';
24
+ $attributes = $field['attributes'];
25
 
26
  foreach ( $field['options'] as $value => $label )
27
  {
28
+ $attributes['value'] = $value;
29
+ $html[] = sprintf(
30
  $tpl,
31
+ self::render_attributes( $attributes ),
 
32
  checked( $value, $meta, false ),
33
  $label
34
  );
37
  return implode( ' ', $html );
38
  }
39
 
40
+ /**
41
+ * Normalize parameters for field
42
+ *
43
+ * @param array $field
44
+ *
45
+ * @return array
46
+ */
47
+ static function normalize_field( $field )
48
+ {
49
+ $field = parent::normalize_field( $field );
50
+
51
+ $field['attributes']['list'] = false;
52
+ $field['attributes']['id'] = false;
53
+ $field['attributes']['type'] = 'radio';
54
+ $field['attributes']['class'] = 'rwmb-radio';
55
+
56
+ return $field;
57
+ }
58
+
59
  /**
60
  * Output the field value
61
  * Display option name instead of option value
inc/fields/range.php CHANGED
@@ -2,9 +2,12 @@
2
  // Prevent loading this file directly
3
  defined( 'ABSPATH' ) || exit;
4
 
 
 
 
5
  if ( ! class_exists( 'RWMB_Range_Field' ) )
6
  {
7
- class RWMB_Range_Field extends RWMB_Field
8
  {
9
  /**
10
  * Enqueue styles
@@ -16,27 +19,6 @@ if ( ! class_exists( 'RWMB_Range_Field' ) )
16
  wp_enqueue_style( 'rwmb-range', RWMB_CSS_URL . 'range.css', array(), RWMB_VER );
17
  }
18
 
19
- /**
20
- * Get field HTML
21
- *
22
- * @param mixed $meta
23
- * @param array $field
24
- *
25
- * @return string
26
- */
27
- static function html( $meta, $field )
28
- {
29
- return sprintf(
30
- '<input type="range" class="rwmb-range" name="%s" id="%s" value="%s" min="%s" max="%s" step="%s" />',
31
- $field['field_name'],
32
- $field['id'],
33
- $meta,
34
- $field['min'],
35
- $field['max'],
36
- $field['step']
37
- );
38
- }
39
-
40
  /**
41
  * Normalize parameters for field.
42
  *
@@ -52,6 +34,11 @@ if ( ! class_exists( 'RWMB_Range_Field' ) )
52
  'step' => 1,
53
  ) );
54
 
 
 
 
 
 
55
  return $field;
56
  }
57
 
2
  // Prevent loading this file directly
3
  defined( 'ABSPATH' ) || exit;
4
 
5
+ // Make sure "number" field is loaded
6
+ require_once RWMB_FIELDS_DIR . 'number.php';
7
+
8
  if ( ! class_exists( 'RWMB_Range_Field' ) )
9
  {
10
+ class RWMB_Range_Field extends RWMB_Number_Field
11
  {
12
  /**
13
  * Enqueue styles
19
  wp_enqueue_style( 'rwmb-range', RWMB_CSS_URL . 'range.css', array(), RWMB_VER );
20
  }
21
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  /**
23
  * Normalize parameters for field.
24
  *
34
  'step' => 1,
35
  ) );
36
 
37
+ $field = parent::normalize_field( $field );
38
+
39
+ $field['attributes']['type'] = 'range';
40
+ $field['attributes']['class'] = 'rwmb-range';
41
+
42
  return $field;
43
  }
44
 
inc/fields/text.php CHANGED
@@ -2,32 +2,13 @@
2
  // Prevent loading this file directly
3
  defined( 'ABSPATH' ) || exit;
4
 
 
 
 
5
  if ( ! class_exists( 'RWMB_Text_Field' ) )
6
  {
7
- class RWMB_Text_Field extends RWMB_Field
8
  {
9
- /**
10
- * Get field HTML
11
- *
12
- * @param mixed $meta
13
- * @param array $field
14
- *
15
- * @return string
16
- */
17
- static function html( $meta, $field )
18
- {
19
- return sprintf(
20
- '<input type="text" class="rwmb-text" name="%s" id="%s" value="%s" placeholder="%s" size="%s" %s>%s',
21
- $field['field_name'],
22
- $field['id'],
23
- $meta,
24
- $field['placeholder'],
25
- $field['size'],
26
- $field['datalist'] ? "list='{$field['datalist']['id']}'" : '',
27
- self::datalist_html( $field )
28
- );
29
- }
30
-
31
  /**
32
  * Normalize parameters for field
33
  *
@@ -37,41 +18,26 @@ if ( ! class_exists( 'RWMB_Text_Field' ) )
37
  */
38
  static function normalize_field( $field )
39
  {
 
 
40
  $field = wp_parse_args( $field, array(
41
  'size' => 30,
42
- 'datalist' => false,
 
43
  'placeholder' => '',
44
  ) );
45
 
46
- return $field;
47
- }
48
-
49
- /**
50
- * Create datalist, if any
51
- *
52
- * @param array $field
53
- *
54
- * @return array
55
- */
56
- static function datalist_html( $field )
57
- {
58
- if ( ! $field['datalist'] )
59
- return '';
60
-
61
- $datalist = $field['datalist'];
62
- $html = sprintf(
63
- '<datalist id="%s">',
64
- $datalist['id']
65
- );
66
-
67
- foreach ( $datalist['options'] as $option )
68
- {
69
- $html .= sprintf( '<option value="%s"></option>', $option );
70
- }
71
 
72
- $html .= '</datalist>';
 
73
 
74
- return $html;
75
  }
76
  }
77
  }
2
  // Prevent loading this file directly
3
  defined( 'ABSPATH' ) || exit;
4
 
5
+ // Make sure "input" field is loaded
6
+ require_once RWMB_FIELDS_DIR . 'input.php';
7
+
8
  if ( ! class_exists( 'RWMB_Text_Field' ) )
9
  {
10
+ class RWMB_Text_Field extends RWMB_Input_Field
11
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  /**
13
  * Normalize parameters for field
14
  *
18
  */
19
  static function normalize_field( $field )
20
  {
21
+ $field = parent::normalize_field( $field );
22
+
23
  $field = wp_parse_args( $field, array(
24
  'size' => 30,
25
+ 'maxlength' => 30,
26
+ 'pattern' => false,
27
  'placeholder' => '',
28
  ) );
29
 
30
+ $field['attributes'] = wp_parse_args( $field['attributes'], array(
31
+ 'size' => $field['size'],
32
+ 'maxlength' => $field['maxlength'],
33
+ 'pattern' => $field['pattern'],
34
+ 'placeholder' => $field['placeholder'],
35
+ ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
+ $field['attributes']['type'] = 'text';
38
+ $field['attributes']['class'] = 'rwmb-text';
39
 
40
+ return $field;
41
  }
42
  }
43
  }
inc/fields/time.php CHANGED
@@ -2,9 +2,12 @@
2
  // Prevent loading this file directly
3
  defined( 'ABSPATH' ) || exit;
4
 
 
 
 
5
  if ( ! class_exists( 'RWMB_Time_Field' ) )
6
  {
7
- class RWMB_Time_Field extends RWMB_Field
8
  {
9
  /**
10
  * Enqueue scripts and styles
@@ -30,7 +33,7 @@ if ( ! class_exists( 'RWMB_Time_Field' ) )
30
  *
31
  * Note: we use full locale (de-DE) and fallback to short locale (de)
32
  */
33
- $locale = str_replace( '_', '-', get_locale() );
34
  $locale_short = substr( $locale, 0, 2 );
35
  wp_register_script( 'jquery-ui-timepicker-i18n', "{$url}/jquery-ui-timepicker-addon-i18n.min.js", array( 'jquery-ui-timepicker' ), '1.5.0', true );
36
 
@@ -41,26 +44,6 @@ if ( ! class_exists( 'RWMB_Time_Field' ) )
41
  ) );
42
  }
43
 
44
- /**
45
- * Get field HTML
46
- *
47
- * @param mixed $meta
48
- * @param array $field
49
- *
50
- * @return string
51
- */
52
- static function html( $meta, $field )
53
- {
54
- return sprintf(
55
- '<input type="text" class="rwmb-time" name="%s" value="%s" id="%s" size="%s" data-options="%s">',
56
- $field['field_name'],
57
- $meta,
58
- isset( $field['clone'] ) && $field['clone'] ? '' : $field['id'],
59
- $field['size'],
60
- esc_attr( wp_json_encode( $field['js_options'] ) )
61
- );
62
- }
63
-
64
  /**
65
  * Normalize parameters for field
66
  *
@@ -71,7 +54,6 @@ if ( ! class_exists( 'RWMB_Time_Field' ) )
71
  static function normalize_field( $field )
72
  {
73
  $field = wp_parse_args( $field, array(
74
- 'size' => 30,
75
  'js_options' => array(),
76
  ) );
77
 
@@ -82,6 +64,14 @@ if ( ! class_exists( 'RWMB_Time_Field' ) )
82
  'timeFormat' => empty( $field['format'] ) ? 'HH:mm' : $field['format'],
83
  ) );
84
 
 
 
 
 
 
 
 
 
85
  return $field;
86
  }
87
  }
2
  // Prevent loading this file directly
3
  defined( 'ABSPATH' ) || exit;
4
 
5
+ // Make sure "text" field is loaded
6
+ require_once RWMB_FIELDS_DIR . 'text.php';
7
+
8
  if ( ! class_exists( 'RWMB_Time_Field' ) )
9
  {
10
+ class RWMB_Time_Field extends RWMB_Text_Field
11
  {
12
  /**
13
  * Enqueue scripts and styles
33
  *
34
  * Note: we use full locale (de-DE) and fallback to short locale (de)
35
  */
36
+ $locale = str_replace( '_', '-', get_locale() );
37
  $locale_short = substr( $locale, 0, 2 );
38
  wp_register_script( 'jquery-ui-timepicker-i18n', "{$url}/jquery-ui-timepicker-addon-i18n.min.js", array( 'jquery-ui-timepicker' ), '1.5.0', true );
39
 
44
  ) );
45
  }
46
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  /**
48
  * Normalize parameters for field
49
  *
54
  static function normalize_field( $field )
55
  {
56
  $field = wp_parse_args( $field, array(
 
57
  'js_options' => array(),
58
  ) );
59
 
64
  'timeFormat' => empty( $field['format'] ) ? 'HH:mm' : $field['format'],
65
  ) );
66
 
67
+ $field['attributes'] = wp_parse_args( $field['attributes'], array(
68
+ 'data-options' => wp_json_encode( $field['js_options'] ),
69
+ ) );
70
+
71
+ $field = parent::normalize_field( $field );
72
+
73
+ $field['attributes']['class'] = 'rwmb-time';
74
+
75
  return $field;
76
  }
77
  }
inc/fields/url.php CHANGED
@@ -10,24 +10,20 @@ if ( ! class_exists( 'RWMB_URL_Field' ) )
10
  class RWMB_URL_Field extends RWMB_Text_Field
11
  {
12
  /**
13
- * Get field HTML
14
  *
15
- * @param mixed $meta
16
  * @param array $field
17
  *
18
- * @return string
19
  */
20
- static function html( $meta, $field )
21
  {
22
- return sprintf(
23
- '<input type="url" class="rwmb-url" name="%s" id="%s" value="%s" size="%s" placeholder="%s" %s/>',
24
- $field['field_name'],
25
- $field['id'],
26
- $meta,
27
- $field['size'],
28
- $field['placeholder'],
29
- $field['pattern'] ? 'pattern="' .$field['pattern'] . '"' : ''
30
- );
31
  }
32
 
33
  /**
10
  class RWMB_URL_Field extends RWMB_Text_Field
11
  {
12
  /**
13
+ * Normalize parameters for field
14
  *
 
15
  * @param array $field
16
  *
17
+ * @return array
18
  */
19
+ static function normalize_field( $field )
20
  {
21
+ $field = parent::normalize_field( $field );
22
+
23
+ $field['attributes']['type'] = 'url';
24
+ $field['attributes']['class'] = 'rwmb-url';
25
+
26
+ return $field;
 
 
 
27
  }
28
 
29
  /**
js/color.js CHANGED
@@ -24,7 +24,7 @@ jQuery( function ( $ )
24
  }
25
 
26
  // Show color picker
27
- $this.wpColorPicker();
28
  }
29
 
30
  $( ':input.rwmb-color' ).each( initColorPicker );
24
  }
25
 
26
  // Show color picker
27
+ $this.wpColorPicker( $this.data( 'options' ) );
28
  }
29
 
30
  $( ':input.rwmb-color' ).each( initColorPicker );
js/media.js CHANGED
@@ -5,40 +5,49 @@ jQuery( function ( $ )
5
  'use strict';
6
 
7
  var views = rwmb.views = rwmb.views || {},
8
- MediaField,MediaList, MediaItem, ImageField, ImageList, ImageItem, MediaButton, MediaStatus, UploadButton;
9
-
10
  MediaList = views.MediaList = Backbone.View.extend( {
11
- tagName: 'ul',
12
- className: 'rwmb-media-list',
13
- createItemView: function( options ){
 
14
  return new MediaItem( options );
15
  },
16
-
17
- addItemView: function( item ){
18
- this.itemViews[item.cid] = this.createItemView( { model: item, collection: this.collection, props: this.props } );
19
- this.$el.append( this.itemViews[item.cid].el );
 
 
 
 
 
20
  },
21
-
22
- render: function(){
 
23
  this.$el.empty();
24
  this.collection.each( this.addItemView );
25
  },
26
-
27
- initialize: function( options ) {
 
28
  var that = this;
29
  this.itemViews = {};
30
  this.props = options.props;
31
-
32
  this.listenTo( this.collection, 'add', this.addItemView );
33
 
34
- this.listenTo( this.collection, 'remove', function( item, collection ) {
 
35
  if ( this.itemViews[item.cid] )
36
  {
37
  this.itemViews[item.cid].remove();
38
  delete this.itemViews[item.cid];
39
  }
40
  } );
41
-
42
  //Sort media using sortable
43
  this.$el.sortable( {
44
  stop : function ( event, ui )
@@ -60,57 +69,61 @@ jQuery( function ( $ )
60
  },
61
  delay: 150
62
  } );
63
-
64
  this.render();
65
  }
66
  } );
67
-
68
  ImageList = views.ImageList = MediaList.extend( {
69
- createItemView: function( options ){
 
70
  return new ImageItem( options );
71
- },
72
  } );
73
-
74
  MediaField = views.MediaField = Backbone.View.extend( {
75
- events : {
76
- 'destroy' : function(){
77
- if( this.forceDelete ) {
78
- _.each( _.clone( this.collection.models ), function( model ) {
 
 
 
79
  model.destroy();
80
- });
81
  }
82
  }
83
  },
84
-
85
  initialize: function ( options )
86
  {
87
  var that = this;
88
  this.input = $( options.input );
89
  this.values = this.input.val().split( ',' );
90
  this.props = this.$el.data();
91
-
92
  //Create collection
93
  this.collection = new wp.media.model.Attachments();
94
-
95
  //Render
96
  this.render();
97
-
98
  //Update input
99
  this.listenTo( this.collection, 'add remove reset', _.debounce( function ()
100
  {
101
- var ids = this.collection.pluck( 'id' );
102
- this.input.val( ids.join( ',' ) );
103
  }, 500 ) );
104
-
105
  //Limit max files
106
- this.listenTo( this.collection, 'add', function( item, collection )
107
  {
108
  if ( this.props.maxFiles > 0 && this.collection.length > this.props.maxFiles )
109
  {
110
  this.collection.pop();
111
  }
112
  } );
113
-
114
  //Load initial media
115
  if ( !_.isEmpty( this.values ) )
116
  {
@@ -125,8 +138,9 @@ jQuery( function ( $ )
125
  this.collection.more();
126
  }
127
  },
128
-
129
- render: function() {
 
130
  //Empty then add parts
131
  this.$el.empty();
132
  this.$el.append( new MediaList( { collection: this.collection, props: this.props } ).el );
@@ -134,83 +148,84 @@ jQuery( function ( $ )
134
  this.$el.append( new MediaStatus( { collection: this.collection, props: this.props } ).el );
135
  }
136
  } );
137
-
138
  ImageField = views.ImageField = MediaField.extend( {
139
- render: function() {
 
140
  this.$el.empty();
141
  this.$el.append( new ImageList( { collection: this.collection, props: this.props } ).el );
142
  this.$el.append( new MediaButton( { collection: this.collection, props: this.props } ).el );
143
  this.$el.append( new MediaStatus( { collection: this.collection, props: this.props } ).el );
144
- }
145
  } );
146
-
147
  MediaStatus = views.MediaStatus = Backbone.View.extend( {
148
- tagName: 'span',
149
- className: 'rwmb-media-status',
150
- template: wp.template( 'rwmb-media-status' ),
151
- initialize: function( options )
152
  {
153
  this.props = options.props;
154
  this.listenTo( this.collection, 'add remove reset', this.render );
155
- this.render();
156
  },
157
-
158
- render: function(){
 
159
  var data = {
160
- items: this.collection.length,
161
  maxFiles: this.props.maxFiles
162
- };
163
  this.$el.html( this.template( data ) );
164
  }
165
  } );
166
-
167
  MediaButton = views.MediaButton = Backbone.View.extend( {
168
  className: 'rwmb-add-media button',
169
- tagName: 'a',
170
- template: wp.template( 'rwmb-add-media' ),
171
- events:
172
- {
173
- 'click': function(){
174
- var ids = this.collection.pluck( 'id' );
 
175
  // Destroy the previous collection frame.
176
  if ( this._frame )
177
  {
178
  this.stopListening( this._frame );
179
  this._frame.dispose();
180
  }
181
-
182
  this._frame = wp.media( {
183
  className: 'media-frame rwmb-media-frame',
184
  multiple : true,
185
  title : 'Select Media',
 
186
  library : {
187
- type : this.props.mimeType,
188
- exclude: ids
189
  }
190
  } );
191
-
192
  this.listenTo( this._frame, 'select', function ()
193
  {
194
  var selection = this._frame.state().get( 'selection' );
195
- selection.each( function ( item )
196
- {
197
- this.collection.add( item );
198
- }, this );
199
  } );
200
-
201
  this._frame.open();
202
- },
203
- },
204
- render: function()
205
  {
206
  this.$el.html( this.template( {} ) );
207
  return this;
208
  },
209
-
210
- initialize: function( options )
211
  {
212
  this.props = options.props;
213
- this.listenTo( this.collection, 'add remove reset', function(){
 
214
  if ( this.props.maxFiles > 0 && this.collection.length >= this.props.maxFiles )
215
  {
216
  this.$el.hide();
@@ -220,16 +235,17 @@ jQuery( function ( $ )
220
  this.$el.show();
221
  }
222
  } );
223
-
224
  this.render();
225
  }
226
  } );
227
-
228
  UploadButton = views.UploadButton = Backbone.View.extend( {
229
- initialize: function( options )
230
  {
231
  this.props = options.props;
232
- this.listenTo( this.collection, 'add remove reset', function(){
 
233
  if ( this.props.maxFiles > 0 && this.collection.length >= this.props.maxFiles )
234
  {
235
  this.$el.hide();
@@ -241,17 +257,18 @@ jQuery( function ( $ )
241
  } );
242
  }
243
  } );
244
-
245
  MediaItem = views.MediaItem = Backbone.View.extend( {
246
  tagName : 'li',
247
- className: 'rwmb-media-item',
248
  template : wp.template( 'rwmb-media-item' ),
249
  initialize: function ( options )
250
  {
251
  this.props = options.props;
252
  this.render();
253
  this.$el.data( 'cid', this.model.cid );
254
- this.listenTo( this.model, 'destroy', function( model ) {
 
255
  this.collection.remove( this.model );
256
  } );
257
  },
@@ -260,10 +277,11 @@ jQuery( function ( $ )
260
  'click .rwmb-remove-media': function ( e )
261
  {
262
  this.collection.remove( this.model );
263
- if( this.props.forceDelete ) {
264
- this.model.destroy();
 
265
  }
266
-
267
  return false;
268
  }
269
  },
@@ -275,10 +293,10 @@ jQuery( function ( $ )
275
  return this;
276
  }
277
  } );
278
-
279
  ImageItem = views.ImageItem = MediaItem.extend( {
280
  className: 'rwmb-image-item',
281
- template : wp.template( 'rwmb-image-item' ),
282
  } );
283
 
284
  /**
@@ -287,23 +305,25 @@ jQuery( function ( $ )
287
  */
288
  function initMediaField()
289
  {
290
- new MediaField( { input: this, el: $( this ).siblings( 'div.rwmb-media-view' )} );
291
  }
292
-
293
  function initImageField()
294
  {
295
- new ImageField( { input: this, el: $( this ).siblings( 'div.rwmb-media-view' )} );
296
  }
297
 
298
  $( ':input.rwmb-media' ).each( initMediaField );
299
- $( '.rwmb-input' ).on( 'clone', ':input.rwmb-media', initMediaField );
300
- $( '.rwmb-input' ).on( 'remove', '.rwmb-media-clone', function(){
301
- $( this ).find( 'div.rwmb-media-view' ).trigger( 'destroy' );
302
- } );
303
-
304
  $( ':input.rwmb-image-advanced' ).each( initImageField );
305
- $( '.rwmb-input' ).on( 'clone', ':input.rwmb-image-advanced', initImageField );
306
- $( '.rwmb-input' ).on( 'remove', '.rwmb-image_advanced-clone', function(){
307
- $( this ).find( 'div.rwmb-media-view' ).trigger( 'destroy' );
308
- } );
 
 
 
 
 
 
 
309
  } );
5
  'use strict';
6
 
7
  var views = rwmb.views = rwmb.views || {},
8
+ MediaField, MediaList, MediaItem, ImageField, ImageList, ImageItem, MediaButton, MediaStatus, UploadButton;
9
+
10
  MediaList = views.MediaList = Backbone.View.extend( {
11
+ tagName : 'ul',
12
+ className : 'rwmb-media-list',
13
+ createItemView: function ( options )
14
+ {
15
  return new MediaItem( options );
16
  },
17
+
18
+ addItemView: function ( item )
19
+ {
20
+ this.itemViews[item.cid] = this.createItemView( {
21
+ model : item,
22
+ collection: this.collection,
23
+ props : this.props
24
+ } );
25
+ this.$el.append( this.itemViews[item.cid].el );
26
  },
27
+
28
+ render: function ()
29
+ {
30
  this.$el.empty();
31
  this.collection.each( this.addItemView );
32
  },
33
+
34
+ initialize: function ( options )
35
+ {
36
  var that = this;
37
  this.itemViews = {};
38
  this.props = options.props;
39
+
40
  this.listenTo( this.collection, 'add', this.addItemView );
41
 
42
+ this.listenTo( this.collection, 'remove', function ( item, collection )
43
+ {
44
  if ( this.itemViews[item.cid] )
45
  {
46
  this.itemViews[item.cid].remove();
47
  delete this.itemViews[item.cid];
48
  }
49
  } );
50
+
51
  //Sort media using sortable
52
  this.$el.sortable( {
53
  stop : function ( event, ui )
69
  },
70
  delay: 150
71
  } );
72
+
73
  this.render();
74
  }
75
  } );
76
+
77
  ImageList = views.ImageList = MediaList.extend( {
78
+ createItemView: function ( options )
79
+ {
80
  return new ImageItem( options );
81
+ }
82
  } );
83
+
84
  MediaField = views.MediaField = Backbone.View.extend( {
85
+ events: {
86
+ destroy: function ()
87
+ {
88
+ if ( this.forceDelete )
89
+ {
90
+ _.each( _.clone( this.collection.models ), function ( model )
91
+ {
92
  model.destroy();
93
+ } );
94
  }
95
  }
96
  },
97
+
98
  initialize: function ( options )
99
  {
100
  var that = this;
101
  this.input = $( options.input );
102
  this.values = this.input.val().split( ',' );
103
  this.props = this.$el.data();
104
+
105
  //Create collection
106
  this.collection = new wp.media.model.Attachments();
107
+
108
  //Render
109
  this.render();
110
+
111
  //Update input
112
  this.listenTo( this.collection, 'add remove reset', _.debounce( function ()
113
  {
114
+ var ids = that.collection.pluck( 'id' );
115
+ that.input.val( ids.join( ',' ) );
116
  }, 500 ) );
117
+
118
  //Limit max files
119
+ this.listenTo( this.collection, 'add', function ( item, collection )
120
  {
121
  if ( this.props.maxFiles > 0 && this.collection.length > this.props.maxFiles )
122
  {
123
  this.collection.pop();
124
  }
125
  } );
126
+
127
  //Load initial media
128
  if ( !_.isEmpty( this.values ) )
129
  {
138
  this.collection.more();
139
  }
140
  },
141
+
142
+ render: function ()
143
+ {
144
  //Empty then add parts
145
  this.$el.empty();
146
  this.$el.append( new MediaList( { collection: this.collection, props: this.props } ).el );
148
  this.$el.append( new MediaStatus( { collection: this.collection, props: this.props } ).el );
149
  }
150
  } );
151
+
152
  ImageField = views.ImageField = MediaField.extend( {
153
+ render: function ()
154
+ {
155
  this.$el.empty();
156
  this.$el.append( new ImageList( { collection: this.collection, props: this.props } ).el );
157
  this.$el.append( new MediaButton( { collection: this.collection, props: this.props } ).el );
158
  this.$el.append( new MediaStatus( { collection: this.collection, props: this.props } ).el );
159
+ }
160
  } );
161
+
162
  MediaStatus = views.MediaStatus = Backbone.View.extend( {
163
+ tagName : 'span',
164
+ className : 'rwmb-media-status',
165
+ template : wp.template( 'rwmb-media-status' ),
166
+ initialize: function ( options )
167
  {
168
  this.props = options.props;
169
  this.listenTo( this.collection, 'add remove reset', this.render );
170
+ this.render();
171
  },
172
+
173
+ render: function ()
174
+ {
175
  var data = {
176
+ items : this.collection.length,
177
  maxFiles: this.props.maxFiles
178
+ };
179
  this.$el.html( this.template( data ) );
180
  }
181
  } );
182
+
183
  MediaButton = views.MediaButton = Backbone.View.extend( {
184
  className: 'rwmb-add-media button',
185
+ tagName : 'a',
186
+ template : wp.template( 'rwmb-add-media' ),
187
+ events : {
188
+ click: function ()
189
+ {
190
+ var models = this.collection.models;
191
+
192
  // Destroy the previous collection frame.
193
  if ( this._frame )
194
  {
195
  this.stopListening( this._frame );
196
  this._frame.dispose();
197
  }
198
+
199
  this._frame = wp.media( {
200
  className: 'media-frame rwmb-media-frame',
201
  multiple : true,
202
  title : 'Select Media',
203
+ editing : true,
204
  library : {
205
+ type: this.props.mimeType
 
206
  }
207
  } );
208
+
209
  this.listenTo( this._frame, 'select', function ()
210
  {
211
  var selection = this._frame.state().get( 'selection' );
212
+ this.collection.add( selection.models );
 
 
 
213
  } );
214
+
215
  this._frame.open();
216
+ }
217
+ },
218
+ render : function ()
219
  {
220
  this.$el.html( this.template( {} ) );
221
  return this;
222
  },
223
+
224
+ initialize: function ( options )
225
  {
226
  this.props = options.props;
227
+ this.listenTo( this.collection, 'add remove reset', function ()
228
+ {
229
  if ( this.props.maxFiles > 0 && this.collection.length >= this.props.maxFiles )
230
  {
231
  this.$el.hide();
235
  this.$el.show();
236
  }
237
  } );
238
+
239
  this.render();
240
  }
241
  } );
242
+
243
  UploadButton = views.UploadButton = Backbone.View.extend( {
244
+ initialize: function ( options )
245
  {
246
  this.props = options.props;
247
+ this.listenTo( this.collection, 'add remove reset', function ()
248
+ {
249
  if ( this.props.maxFiles > 0 && this.collection.length >= this.props.maxFiles )
250
  {
251
  this.$el.hide();
257
  } );
258
  }
259
  } );
260
+
261
  MediaItem = views.MediaItem = Backbone.View.extend( {
262
  tagName : 'li',
263
+ className : 'rwmb-media-item',
264
  template : wp.template( 'rwmb-media-item' ),
265
  initialize: function ( options )
266
  {
267
  this.props = options.props;
268
  this.render();
269
  this.$el.data( 'cid', this.model.cid );
270
+ this.listenTo( this.model, 'destroy', function ( model )
271
+ {
272
  this.collection.remove( this.model );
273
  } );
274
  },
277
  'click .rwmb-remove-media': function ( e )
278
  {
279
  this.collection.remove( this.model );
280
+ if ( this.props.forceDelete )
281
+ {
282
+ this.model.destroy();
283
  }
284
+
285
  return false;
286
  }
287
  },
293
  return this;
294
  }
295
  } );
296
+
297
  ImageItem = views.ImageItem = MediaItem.extend( {
298
  className: 'rwmb-image-item',
299
+ template : wp.template( 'rwmb-image-item' )
300
  } );
301
 
302
  /**
305
  */
306
  function initMediaField()
307
  {
308
+ new MediaField( { input: this, el: $( this ).siblings( 'div.rwmb-media-view' ) } );
309
  }
310
+
311
  function initImageField()
312
  {
313
+ new ImageField( { input: this, el: $( this ).siblings( 'div.rwmb-media-view' ) } );
314
  }
315
 
316
  $( ':input.rwmb-media' ).each( initMediaField );
 
 
 
 
 
317
  $( ':input.rwmb-image-advanced' ).each( initImageField );
318
+ $( '.rwmb-input' )
319
+ .on( 'clone', ':input.rwmb-media', initMediaField )
320
+ .on( 'remove', '.rwmb-media-clone', function ()
321
+ {
322
+ $( this ).find( 'div.rwmb-media-view' ).trigger( 'destroy' );
323
+ } )
324
+ .on( 'clone', ':input.rwmb-image-advanced', initImageField )
325
+ .on( 'remove', '.rwmb-image_advanced-clone', function ()
326
+ {
327
+ $( this ).find( 'div.rwmb-media-view' ).trigger( 'destroy' );
328
+ } );
329
  } );
meta-box-loader.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class RWMB_Loader
4
+ {
5
+ static function load( $url, $dir )
6
+ {
7
+ define( 'RWMB_VER', '4.7' );
8
+
9
+ define( 'RWMB_URL', $url );
10
+ define( 'RWMB_DIR', $dir );
11
+
12
+ define( 'RWMB_JS_URL', trailingslashit( RWMB_URL . 'js' ) );
13
+ define( 'RWMB_CSS_URL', trailingslashit( RWMB_URL . 'css' ) );
14
+
15
+ define( 'RWMB_INC_DIR', trailingslashit( RWMB_DIR . 'inc' ) );
16
+ define( 'RWMB_FIELDS_DIR', trailingslashit( RWMB_INC_DIR . 'fields' ) );
17
+ }
18
+ }
meta-box.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: Meta Box
4
  * Plugin URI: https://metabox.io
5
  * Description: Create custom meta boxes and custom fields for any post type in WordPress.
6
- * Version: 4.6
7
  * Author: Rilwis
8
  * Author URI: http://www.deluxeblogtips.com
9
  * License: GPL2+
@@ -15,7 +15,7 @@
15
  defined( 'ABSPATH' ) || exit;
16
 
17
  // Script version, used to add version for scripts and styles
18
- define( 'RWMB_VER', '4.6' );
19
 
20
  // Define plugin URLs, for fast enqueuing scripts and styles
21
  if ( ! defined( 'RWMB_URL' ) )
3
  * Plugin Name: Meta Box
4
  * Plugin URI: https://metabox.io
5
  * Description: Create custom meta boxes and custom fields for any post type in WordPress.
6
+ * Version: 4.7
7
  * Author: Rilwis
8
  * Author URI: http://www.deluxeblogtips.com
9
  * License: GPL2+
15
  defined( 'ABSPATH' ) || exit;
16
 
17
  // Script version, used to add version for scripts and styles
18
+ define( 'RWMB_VER', '4.7' );
19
 
20
  // Define plugin URLs, for fast enqueuing scripts and styles
21
  if ( ! defined( 'RWMB_URL' ) )
readme.txt CHANGED
@@ -4,7 +4,7 @@ Donate link: http://www.deluxeblogtips.com/donate
4
  Tags: meta-box, custom fields, custom field, meta, meta-boxes, admin, advanced, custom, edit, field, file, image, magic fields, matrix, more fields, Post, repeater, simple fields, text, textarea, type, cms, fields post
5
  Requires at least: 3.5
6
  Tested up to: 4.3.1
7
- Stable tag: 4.6
8
  License: GPLv2 or later
9
 
10
  Meta Box plugin is a powerful, professional solution to create custom meta boxes and custom fields for WordPress websites.
@@ -75,6 +75,12 @@ To getting started with the plugin API, please read [this tutorial](https://meta
75
 
76
  == Changelog ==
77
 
 
 
 
 
 
 
78
  = 4.6 =
79
 
80
  * Improvement: the plugin translation is now handled in translate.wordpress.org. While the plugin keeps old translation as backward compatibility, it's recommended to translate everything in translate.wordpress.org. Language packs will be automatically updated by WordPress.
4
  Tags: meta-box, custom fields, custom field, meta, meta-boxes, admin, advanced, custom, edit, field, file, image, magic fields, matrix, more fields, Post, repeater, simple fields, text, textarea, type, cms, fields post
5
  Requires at least: 3.5
6
  Tested up to: 4.3.1
7
+ Stable tag: 4.7
8
  License: GPLv2 or later
9
 
10
  Meta Box plugin is a powerful, professional solution to create custom meta boxes and custom fields for WordPress websites.
75
 
76
  == Changelog ==
77
 
78
+ = 4.7 =
79
+
80
+ * Improvement: add `attributes` for all input fields (text, number, email, ...) so users can add any custom attributes for them. Also added default attributes `required`, `disabled`, `readonly`, `maxlength` and `pattern` for those fields as well. These attributes will be merged into the `attributes`.
81
+ * Improvement: add `js_options` for color field which allows users to define custom color palettes and other attributes for color picker. See the options in [Iris page](http://automattic.github.io/Iris/).
82
+ * Fix: fix for file and image uploaded via `file_advanced` and `image_advanced` not showing up.
83
+
84
  = 4.6 =
85
 
86
  * Improvement: the plugin translation is now handled in translate.wordpress.org. While the plugin keeps old translation as backward compatibility, it's recommended to translate everything in translate.wordpress.org. Language packs will be automatically updated by WordPress.