Meta Box - Version 4.1.11

Version Description

  • Bug fix: helper function for getting taxonomy field type
  • Bug fix: multiple attribute for select field type
Download this release

Release Info

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

Code changes from version 4.1.10 to 4.1.11

Files changed (9) hide show
  1. inc/classes/meta-box.php +691 -691
  2. inc/fields/select.php +1 -1
  3. inc/helpers.php +1 -1
  4. js/clone.js +129 -129
  5. js/thickbox-image.js +12 -12
  6. js/validate.js +22 -24
  7. meta-box.php +1 -1
  8. readme.md +0 -211
  9. readme.txt +6 -2
inc/classes/meta-box.php CHANGED
@@ -1,692 +1,692 @@
1
- <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- // Meta Box Class
6
- if ( ! class_exists( 'RW_Meta_Box' ) )
7
- {
8
- /**
9
- * A class to rapid develop meta boxes for custom & built in content types
10
- * Piggybacks on WordPress
11
- *
12
- * @author Rilwis
13
- * @author Co-Authors @see https://github.com/rilwis/meta-box
14
- * @license GNU GPL2+
15
- * @package RW Meta Box
16
- */
17
- class RW_Meta_Box
18
- {
19
- /**
20
- * Meta box information
21
- */
22
- var $meta_box;
23
-
24
- /**
25
- * Fields information
26
- */
27
- var $fields;
28
-
29
- /**
30
- * Contains all field types of current meta box
31
- */
32
- var $types;
33
-
34
- /**
35
- * Validation information
36
- */
37
- var $validation;
38
-
39
- /**
40
- * Create meta box based on given data
41
- *
42
- * @see demo/demo.php file for details
43
- *
44
- * @param array $meta_box Meta box definition
45
- *
46
- * @return \RW_Meta_Box
47
- */
48
- function __construct( $meta_box )
49
- {
50
- // Run script only in admin area
51
- if ( ! is_admin() )
52
- return;
53
-
54
- // Assign meta box values to local variables and add it's missed values
55
- $this->meta_box = self::normalize( $meta_box );
56
- $this->fields = &$this->meta_box['fields'];
57
- $this->validation = &$this->meta_box['validation'];
58
-
59
- // List of meta box field types
60
- $this->types = array_unique( wp_list_pluck( $this->fields, 'type' ) );
61
-
62
- // Enqueue common styles and scripts
63
- add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
64
-
65
- foreach ( $this->types as $type )
66
- {
67
- $class = self::get_class_name( $type );
68
-
69
- // Add additional actions for fields
70
- if ( method_exists( $class, 'add_actions' ) )
71
- call_user_func( array( $class, 'add_actions' ) );
72
- }
73
-
74
- // Add meta box
75
- foreach ( $this->meta_box['pages'] as $page )
76
- {
77
- add_action( "add_meta_boxes_{$page}", array( $this, 'add_meta_boxes' ) );
78
- }
79
-
80
- // Save post meta
81
- add_action( 'save_post', array( $this, 'save_post' ) );
82
- }
83
-
84
- /**
85
- * Enqueue common styles
86
- *
87
- * @return void
88
- */
89
- function admin_enqueue_scripts()
90
- {
91
- $screen = get_current_screen();
92
-
93
- // Enqueue scripts and styles for registered pages (post types) only
94
- if ( 'post' != $screen->base || ! in_array( $screen->post_type, $this->meta_box['pages'] ) )
95
- return;
96
-
97
- wp_enqueue_style( 'rwmb', RWMB_CSS_URL . 'style.css', RWMB_VER );
98
-
99
- // Load clone script conditionally
100
- $has_clone = false;
101
- foreach ( $this->fields as $field )
102
- {
103
- if ( self::is_cloneable( $field ) )
104
- $has_clone = true;
105
-
106
- // Enqueue scripts and styles for fields
107
- $class = self::get_class_name( $field['type'] );
108
- if ( method_exists( $class, 'admin_enqueue_scripts' ) )
109
- call_user_func( array( $class, 'admin_enqueue_scripts' ) );
110
- }
111
-
112
- if ( $has_clone ) {
113
- wp_enqueue_script( 'rwmb-clone', RWMB_JS_URL . 'clone.js', array( 'jquery' ), RWMB_VER, true );
114
- }
115
-
116
- if ( $this->validation ) {
117
- wp_enqueue_script( 'jquery-validate', RWMB_JS_URL . 'jquery.validate.min.js', array( 'jquery' ), RWMB_VER, true );
118
- wp_enqueue_script( 'rwmb-validate', RWMB_JS_URL . 'validate.js', array( 'jquery-validate' ), RWMB_VER, true );
119
- }
120
- }
121
-
122
- /**************************************************
123
- SHOW META BOX
124
- **************************************************/
125
-
126
- /**
127
- * Add meta box for multiple post types
128
- *
129
- * @return void
130
- */
131
- function add_meta_boxes()
132
- {
133
- foreach ( $this->meta_box['pages'] as $page )
134
- {
135
- // Allow users to show/hide meta boxes
136
- // 1st action applies to all meta boxes
137
- // 2nd action applies to only current meta box
138
- $show = true;
139
- $show = apply_filters( 'rwmb_show', $show, $this->meta_box );
140
- $show = apply_filters( "rwmb_show_{$this->meta_box['id']}", $show, $this->meta_box );
141
- if ( !$show )
142
- continue;
143
-
144
- add_meta_box(
145
- $this->meta_box['id'],
146
- $this->meta_box['title'],
147
- array( $this, 'show' ),
148
- $page,
149
- $this->meta_box['context'],
150
- $this->meta_box['priority']
151
- );
152
- }
153
- }
154
-
155
- /**
156
- * Callback function to show fields in meta box
157
- *
158
- * @return void
159
- */
160
- public function show()
161
- {
162
- global $post;
163
-
164
- $saved = self::has_been_saved( $post->ID, $this->fields );
165
-
166
- wp_nonce_field( "rwmb-save-{$this->meta_box['id']}", "nonce_{$this->meta_box['id']}" );
167
-
168
- // Allow users to add custom code before meta box content
169
- // 1st action applies to all meta boxes
170
- // 2nd action applies to only current meta box
171
- do_action( 'rwmb_before' );
172
- do_action( "rwmb_before_{$this->meta_box['id']}" );
173
-
174
- foreach ( $this->fields as $field )
175
- {
176
- $group = ""; // Empty the clone-group field
177
- $type = $field['type'];
178
- $id = $field['id'];
179
- $meta = self::apply_field_class_filters( $field, 'meta', '', $post->ID, $saved );
180
- $meta = apply_filters( "rwmb_{$type}_meta", $meta );
181
- $meta = apply_filters( "rwmb_{$id}_meta", $meta );
182
-
183
- $begin = self::apply_field_class_filters( $field, 'begin_html', '', $meta );
184
-
185
- // Apply filter to field begin HTML
186
- // 1st filter applies to all fields
187
- // 2nd filter applies to all fields with the same type
188
- // 3rd filter applies to current field only
189
- $begin = apply_filters( 'rwmb_begin_html', $begin, $field, $meta );
190
- $begin = apply_filters( "rwmb_{$type}_begin_html", $begin, $field, $meta );
191
- $begin = apply_filters( "rwmb_{$id}_begin_html", $begin, $field, $meta );
192
-
193
- // Separate code for clonable and non-cloneable fields to make easy to maintain
194
-
195
- // Cloneable fields
196
- if ( self::is_cloneable( $field ) )
197
- {
198
- if ( isset( $field['clone-group'] ) )
199
- $group = " clone-group='{$field['clone-group']}'";
200
-
201
- if ( ! is_array( $field['field_name'] ) )
202
- $field['field_name'] = (array) $field['field_name'];
203
-
204
- $meta = (array) $meta;
205
-
206
- foreach ( array_keys( $meta ) as $i )
207
- $field['field_name'][$i] = $field['id'] . "[{$i}]";
208
-
209
- $field_html = '';
210
-
211
- $index = 0;
212
- foreach ( $meta as $meta_data )
213
- {
214
- if ( is_array( $field['field_name'] ) )
215
- {
216
- $subfield = $field;
217
- $subfield['field_name'] = $field['field_name'][$index];
218
- }
219
- else
220
- $subfield = $field;
221
-
222
- add_filter( "rwmb_{$id}_html", array( $this, 'add_delete_clone_button' ), 10, 3 );
223
-
224
- // Wrap field HTML in a div with class="rwmb-clone" if needed
225
- $input_html = '<div class="rwmb-clone">';
226
-
227
- // Call separated methods for displaying each type of field
228
- $input_html .= self::apply_field_class_filters( $subfield, 'html', '', $meta_data );
229
-
230
- // Apply filter to field HTML
231
- // 1st filter applies to all fields with the same type
232
- // 2nd filter applies to current field only
233
- $input_html = apply_filters( "rwmb_{$type}_html", $input_html, $field, $meta_data );
234
- $input_html = apply_filters( "rwmb_{$id}_html", $input_html, $field, $meta_data );
235
-
236
- $input_html .= '</div>';
237
-
238
- $field_html .= $input_html;
239
- $index++;
240
- }
241
- }
242
- // Non-cloneable fields
243
- else
244
- {
245
- // Call separated methods for displaying each type of field
246
- $field_html = self::apply_field_class_filters( $field, 'html', '', $meta );
247
-
248
- // Apply filter to field HTML
249
- // 1st filter applies to all fields with the same type
250
- // 2nd filter applies to current field only
251
- $field_html = apply_filters( "rwmb_{$type}_html", $field_html, $field, $meta );
252
- $field_html = apply_filters( "rwmb_{$id}_html", $field_html, $field, $meta );
253
- }
254
-
255
- $end = self::apply_field_class_filters( $field, 'end_html', '', $meta );
256
-
257
- // Apply filter to field end HTML
258
- // 1st filter applies to all fields
259
- // 2nd filter applies to all fields with the same type
260
- // 3rd filter applies to current field only
261
- $end = apply_filters( 'rwmb_end_html', $end, $field, $meta );
262
- $end = apply_filters( "rwmb_{$type}_end_html", $end, $field, $meta );
263
- $end = apply_filters( "rwmb_{$id}_end_html", $end, $field, $meta );
264
-
265
- // Apply filter to field wrapper
266
- // This allow users to change whole HTML markup of the field wrapper (i.e. table row)
267
- // 1st filter applies to all fields with the same type
268
- // 2nd filter applies to current field only
269
- $html = apply_filters( "rwmb_{$type}_wrapper_html", "{$begin}{$field_html}{$end}", $field, $meta );
270
- $html = apply_filters( "rwmb_{$id}_wrapper_html", $html, $field, $meta );
271
-
272
- // Display label and input in DIV and allow user-defined classes to be appended
273
- $class = 'rwmb-field';
274
- if ( isset( $field['required'] ) && $field['required'] )
275
- $class .= ' required';
276
- if ( isset( $field['class'] ) )
277
- $class = $this->add_cssclass( $field['class'], $class );
278
-
279
- // Hide the div if field has 'hidden' type
280
- if ( 'hidden' === $field['type'] )
281
- $class = $this->add_cssclass( 'hidden', $class );
282
- echo "<div class='{$class}'{$group}>{$html}</div>";
283
- }
284
-
285
- // Include validation settings for this meta-box
286
- if ( isset( $this->validation ) && $this->validation )
287
- {
288
- echo '
289
- <script type="text/javascript">
290
- if ( typeof rwmb == "undefined" )
291
- {
292
- var rwmb = {
293
- validationOptions : jQuery.parseJSON( \'' . json_encode( $this->validation ) . '\' ),
294
- summaryMessage : "' . __( 'Please correct the errors highlighted below and try again.', 'rwmb' ) . '"
295
- };
296
- }
297
- else
298
- {
299
- var tempOptions = jQuery.parseJSON( \'' . json_encode( $this->validation ) . '\' );
300
- jQuery.each( tempOptions.rules, function( k, v )
301
- {
302
- rwmb.validationOptions.rules[k] = v;
303
- });
304
- jQuery.each( tempOptions.messages, function( k, v )
305
- {
306
- rwmb.validationOptions.messages[k] = v;
307
- });
308
- };
309
- </script>
310
- ';
311
- }
312
-
313
- // Allow users to add custom code after meta box content
314
- // 1st action applies to all meta boxes
315
- // 2nd action applies to only current meta box
316
- do_action( 'rwmb_after' );
317
- do_action( "rwmb_after_{$this->meta_box['id']}" );
318
- }
319
-
320
- /**
321
- * Show begin HTML markup for fields
322
- *
323
- * @param string $html
324
- * @param mixed $meta
325
- * @param array $field
326
- *
327
- * @return string
328
- */
329
- static function begin_html( $html, $meta, $field )
330
- {
331
- $class = 'rwmb-label';
332
-
333
- if ( ! empty( $field['class'] ) )
334
- $class = self::add_cssclass( $field['class'], $class );
335
-
336
- if ( empty( $field['name'] ) )
337
- return '<div class="rwmb-input">';
338
-
339
- $html = <<<HTML
340
- <div class="{$class}">
341
- <label for="{$field['id']}">{$field['name']}</label>
342
- </div>
343
- <div class="rwmb-input">
344
- HTML;
345
-
346
- return $html;
347
- }
348
-
349
- /**
350
- * Show end HTML markup for fields
351
- *
352
- * @param string $html
353
- * @param mixed $meta
354
- * @param array $field
355
- *
356
- * @return string
357
- */
358
- static function end_html( $html, $meta, $field )
359
- {
360
- $id = $field['id'];
361
-
362
- $button = '';
363
- if ( self::is_cloneable( $field ) )
364
- $button = '<a href="#" class="rwmb-button button-primary add-clone">' . __( '+', 'rwmb' ) . '</a>';
365
-
366
- $desc = ! empty( $field['desc'] ) ? "<p id='{$id}_description' class='description'>{$field['desc']}</p>" : '';
367
-
368
- // Closes the container
369
- $html = "{$button}{$desc}</div>";
370
-
371
- return $html;
372
- }
373
-
374
- /**
375
- * Callback function to add clone buttons on demand
376
- * Hooks on the flight into the "rwmb_{$field_id}_html" filter before the closing div
377
- *
378
- * @param string $html
379
- * @param array $field
380
- * @param mixed $meta_data
381
- *
382
- * @return string $html
383
- */
384
- static function add_delete_clone_button( $html, $field, $meta_data )
385
- {
386
- $id = $field['id'];
387
-
388
- $button = '<a href="#" class="rwmb-button button-secondary remove-clone">' . __( '&#8211;', 'rwmb' ) . '</a>';
389
-
390
- return "{$html}{$button}";
391
- }
392
-
393
- /**
394
- * Standard meta retrieval
395
- *
396
- * @param mixed $meta
397
- * @param int $post_id
398
- * @param array $field
399
- * @param bool $saved
400
- *
401
- * @return mixed
402
- */
403
- static function meta( $meta, $post_id, $saved, $field )
404
- {
405
- $meta = get_post_meta( $post_id, $field['id'], !$field['multiple'] );
406
-
407
- // Use $field['std'] only when the meta box hasn't been saved (i.e. the first time we run)
408
- $meta = ( !$saved && '' === $meta || array() === $meta ) ? $field['std'] : $meta;
409
-
410
- // Escape attributes for non-wysiwyg fields
411
- if ( 'wysiwyg' !== $field['type'] )
412
- $meta = is_array( $meta ) ? array_map( 'esc_attr', $meta ) : esc_attr( $meta );
413
-
414
- return $meta;
415
- }
416
-
417
- /**************************************************
418
- SAVE META BOX
419
- **************************************************/
420
-
421
- /**
422
- * Save data from meta box
423
- *
424
- * @param int $post_id Post ID
425
- *
426
- * @return int|void
427
- */
428
- function save_post( $post_id )
429
- {
430
- global $post_type;
431
- $post_type_object = get_post_type_object( $post_type );
432
-
433
- // Check whether:
434
- // - the post is autosaved
435
- // - the post is a revision
436
- // - current post type is supported
437
- // - user has proper capability
438
- if (
439
- ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
440
- || ( ! isset( $_POST['post_ID'] ) || $post_id != $_POST['post_ID'] )
441
- || ( ! in_array( $post_type, $this->meta_box['pages'] ) )
442
- || ( ! current_user_can( $post_type_object->cap->edit_post, $post_id ) )
443
- )
444
- {
445
- return $post_id;
446
- }
447
-
448
- // Verify nonce
449
- check_admin_referer( "rwmb-save-{$this->meta_box['id']}", "nonce_{$this->meta_box['id']}" );
450
-
451
- foreach ( $this->fields as $field )
452
- {
453
- $name = $field['id'];
454
- $old = get_post_meta( $post_id, $name, !$field['multiple'] );
455
- $new = isset( $_POST[$name] ) ? $_POST[$name] : ( $field['multiple'] ? array() : '' );
456
-
457
- // Allow field class change the value
458
- $new = self::apply_field_class_filters( $field, 'value', $new, $old, $post_id );
459
-
460
- // Use filter to change field value
461
- // 1st filter applies to all fields with the same type
462
- // 2nd filter applies to current field only
463
- $new = apply_filters( "rwmb_{$field['type']}_value", $new, $field, $old );
464
- $new = apply_filters( "rwmb_{$name}_value", $new, $field, $old );
465
-
466
- // Call defined method to save meta value, if there's no methods, call common one
467
- self::do_field_class_actions( $field, 'save', $new, $old, $post_id );
468
- }
469
- }
470
-
471
- /**
472
- * Common functions for saving field
473
- *
474
- * @param mixed $new
475
- * @param mixed $old
476
- * @param int $post_id
477
- * @param array $field
478
- *
479
- * @return void
480
- */
481
- static function save( $new, $old, $post_id, $field )
482
- {
483
- $name = $field['id'];
484
-
485
- delete_post_meta( $post_id, $name );
486
- if ( '' === $new || array() === $new )
487
- return;
488
-
489
- if ( $field['multiple'] )
490
- {
491
- foreach ( $new as $add_new )
492
- {
493
- add_post_meta( $post_id, $name, $add_new, false );
494
- }
495
- }
496
- else
497
- {
498
- update_post_meta( $post_id, $name, $new );
499
- }
500
- }
501
-
502
- /**************************************************
503
- HELPER FUNCTIONS
504
- **************************************************/
505
-
506
- /**
507
- * Normalize parameters for meta box
508
- *
509
- * @param array $meta_box Meta box definition
510
- *
511
- * @return array $meta_box Normalized meta box
512
- */
513
- static function normalize( $meta_box )
514
- {
515
- // Set default values for meta box
516
- $meta_box = wp_parse_args(
517
- $meta_box, array(
518
- 'id' => sanitize_title( $meta_box['title'] ),
519
- 'context' => 'normal',
520
- 'priority' => 'high',
521
- 'pages' => array( 'post' )
522
- )
523
- );
524
-
525
- // Set default values for fields
526
- foreach ( $meta_box['fields'] as &$field )
527
- {
528
- $field = wp_parse_args(
529
- $field, array(
530
- 'multiple' => false,
531
- 'clone' => false,
532
- 'std' => '',
533
- 'desc' => '',
534
- 'format' => '',
535
- )
536
- );
537
-
538
- // Allow field class add/change default field values
539
- $field = self::apply_field_class_filters( $field, 'normalize_field', $field );
540
-
541
- // Allow field class to manually change field_name
542
- // @see taxonomy.php for example
543
- if ( ! isset( $field['field_name'] ) )
544
- $field['field_name'] = $field['id'] . ( $field['multiple'] || $field['clone'] ? '[0]' : '' );
545
- }
546
-
547
- return $meta_box;
548
- }
549
-
550
- /**
551
- * Get field class name
552
- *
553
- * @param string $type Field type
554
- *
555
- * @return bool|string Field class name OR false on failure
556
- */
557
- static function get_class_name( $type )
558
- {
559
- $type = ucwords( $type );
560
- $class = "RWMB_{$type}_Field";
561
-
562
- if ( class_exists( $class ) )
563
- return $class;
564
-
565
- return false;
566
- }
567
-
568
- /**
569
- * Apply filters by field class, fallback to RW_Meta_Box method
570
- *
571
- * @param array $field
572
- * @param string $method_name
573
- * @param mixed $value
574
- *
575
- * @return mixed $value
576
- */
577
- static function apply_field_class_filters( $field, $method_name, $value )
578
- {
579
- $args = array_slice( func_get_args(), 2 );
580
- $args[] = $field;
581
-
582
- // Call: field class method
583
- // Fallback: RW_Meta_Box method
584
- $class = self::get_class_name( $field['type'] );
585
- if ( method_exists( $class, $method_name ) )
586
- {
587
- $value = call_user_func_array( array( $class, $method_name ), $args );
588
- }
589
- elseif ( method_exists( __CLASS__, $method_name ) )
590
- {
591
- $value = call_user_func_array( array( __CLASS__, $method_name ), $args );
592
- }
593
-
594
- return $value;
595
- }
596
-
597
- /**
598
- * Call field class method for actions, fallback to RW_Meta_Box method
599
- *
600
- * @param array $field
601
- * @param string $method_name
602
- *
603
- * @return mixed
604
- */
605
- static function do_field_class_actions( $field, $method_name )
606
- {
607
- $args = array_slice( func_get_args(), 2 );
608
- $args[] = $field;
609
-
610
- // Call: field class method
611
- // Fallback: RW_Meta_Box method
612
- $class = self::get_class_name( $field['type'] );
613
- if ( method_exists( $class, $method_name ) )
614
- {
615
- call_user_func_array( array( $class, $method_name ), $args );
616
- }
617
- elseif ( method_exists( __CLASS__, $method_name ) )
618
- {
619
- call_user_func_array( array( __CLASS__, $method_name ), $args );
620
- }
621
- }
622
-
623
- /**
624
- * Format Ajax response
625
- *
626
- * @param string $message
627
- * @param string $status
628
- *
629
- * @return void
630
- */
631
- static function ajax_response( $message, $status )
632
- {
633
- $response = array( 'what' => 'meta-box' );
634
- $response['data'] = 'error' === $status ? new WP_Error( 'error', $message ) : $message;
635
- $x = new WP_Ajax_Response( $response );
636
- $x->send();
637
- }
638
-
639
- /**
640
- * Check if meta box has been saved
641
- * This helps saving empty value in meta fields (for text box, check box, etc.)
642
- *
643
- * @param int $post_id
644
- * @param array $fields
645
- *
646
- * @return bool
647
- */
648
- static function has_been_saved( $post_id, $fields )
649
- {
650
- $saved = false;
651
- foreach ( $fields as $field )
652
- {
653
- if ( get_post_meta( $post_id, $field['id'], !$field['multiple'] ) )
654
- {
655
- $saved = true;
656
- break;
657
- }
658
- }
659
- return $saved;
660
- }
661
-
662
- /**
663
- * Adds a css class
664
- * Mainly a copy of the core admin menu function
665
- * As the core function is only meant to be used by core internally,
666
- * We copy it here - in case core changes functionality or drops the function.
667
- *
668
- * @param string $add
669
- * @param string $class | Class name - Default: empty
670
- *
671
- * @return string $class
672
- */
673
- static function add_cssclass( $add, $class = '' )
674
- {
675
- $class .= empty( $class ) ? $add : " {$add}";
676
-
677
- return $class;
678
- }
679
-
680
- /**
681
- * Helper function to check for multi/clone field IDs
682
- *
683
- * @param array $field
684
- *
685
- * @return bool False if no cloneable
686
- */
687
- static function is_cloneable( $field )
688
- {
689
- return $field['clone'];
690
- }
691
- }
692
  }
1
+ <?php
2
+ // Prevent loading this file directly
3
+ defined( 'ABSPATH' ) || exit;
4
+
5
+ // Meta Box Class
6
+ if ( ! class_exists( 'RW_Meta_Box' ) )
7
+ {
8
+ /**
9
+ * A class to rapid develop meta boxes for custom & built in content types
10
+ * Piggybacks on WordPress
11
+ *
12
+ * @author Rilwis
13
+ * @author Co-Authors @see https://github.com/rilwis/meta-box
14
+ * @license GNU GPL2+
15
+ * @package RW Meta Box
16
+ */
17
+ class RW_Meta_Box
18
+ {
19
+ /**
20
+ * Meta box information
21
+ */
22
+ var $meta_box;
23
+
24
+ /**
25
+ * Fields information
26
+ */
27
+ var $fields;
28
+
29
+ /**
30
+ * Contains all field types of current meta box
31
+ */
32
+ var $types;
33
+
34
+ /**
35
+ * Validation information
36
+ */
37
+ var $validation;
38
+
39
+ /**
40
+ * Create meta box based on given data
41
+ *
42
+ * @see demo/demo.php file for details
43
+ *
44
+ * @param array $meta_box Meta box definition
45
+ *
46
+ * @return \RW_Meta_Box
47
+ */
48
+ function __construct( $meta_box )
49
+ {
50
+ // Run script only in admin area
51
+ if ( ! is_admin() )
52
+ return;
53
+
54
+ // Assign meta box values to local variables and add it's missed values
55
+ $this->meta_box = self::normalize( $meta_box );
56
+ $this->fields = &$this->meta_box['fields'];
57
+ $this->validation = &$this->meta_box['validation'];
58
+
59
+ // List of meta box field types
60
+ $this->types = array_unique( wp_list_pluck( $this->fields, 'type' ) );
61
+
62
+ // Enqueue common styles and scripts
63
+ add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
64
+
65
+ foreach ( $this->types as $type )
66
+ {
67
+ $class = self::get_class_name( $type );
68
+
69
+ // Add additional actions for fields
70
+ if ( method_exists( $class, 'add_actions' ) )
71
+ call_user_func( array( $class, 'add_actions' ) );
72
+ }
73
+
74
+ // Add meta box
75
+ foreach ( $this->meta_box['pages'] as $page )
76
+ {
77
+ add_action( "add_meta_boxes_{$page}", array( $this, 'add_meta_boxes' ) );
78
+ }
79
+
80
+ // Save post meta
81
+ add_action( 'save_post', array( $this, 'save_post' ) );
82
+ }
83
+
84
+ /**
85
+ * Enqueue common styles
86
+ *
87
+ * @return void
88
+ */
89
+ function admin_enqueue_scripts()
90
+ {
91
+ $screen = get_current_screen();
92
+
93
+ // Enqueue scripts and styles for registered pages (post types) only
94
+ if ( 'post' != $screen->base || ! in_array( $screen->post_type, $this->meta_box['pages'] ) )
95
+ return;
96
+
97
+ wp_enqueue_style( 'rwmb', RWMB_CSS_URL . 'style.css', RWMB_VER );
98
+
99
+ // Load clone script conditionally
100
+ $has_clone = false;
101
+ foreach ( $this->fields as $field )
102
+ {
103
+ if ( self::is_cloneable( $field ) )
104
+ $has_clone = true;
105
+
106
+ // Enqueue scripts and styles for fields
107
+ $class = self::get_class_name( $field['type'] );
108
+ if ( method_exists( $class, 'admin_enqueue_scripts' ) )
109
+ call_user_func( array( $class, 'admin_enqueue_scripts' ) );
110
+ }
111
+
112
+ if ( $has_clone )
113
+ wp_enqueue_script( 'rwmb-clone', RWMB_JS_URL . 'clone.js', array( 'jquery' ), RWMB_VER, true );
114
+
115
+ if ( $this->validation )
116
+ {
117
+ wp_enqueue_script( 'jquery-validate', RWMB_JS_URL . 'jquery.validate.min.js', array( 'jquery' ), RWMB_VER, true );
118
+ wp_enqueue_script( 'rwmb-validate', RWMB_JS_URL . 'validate.js', array( 'jquery-validate' ), RWMB_VER, true );
119
+ }
120
+ }
121
+
122
+ /**************************************************
123
+ SHOW META BOX
124
+ **************************************************/
125
+
126
+ /**
127
+ * Add meta box for multiple post types
128
+ *
129
+ * @return void
130
+ */
131
+ function add_meta_boxes()
132
+ {
133
+ foreach ( $this->meta_box['pages'] as $page )
134
+ {
135
+ // Allow users to show/hide meta boxes
136
+ // 1st action applies to all meta boxes
137
+ // 2nd action applies to only current meta box
138
+ $show = true;
139
+ $show = apply_filters( 'rwmb_show', $show, $this->meta_box );
140
+ $show = apply_filters( "rwmb_show_{$this->meta_box['id']}", $show, $this->meta_box );
141
+ if ( !$show )
142
+ continue;
143
+
144
+ add_meta_box(
145
+ $this->meta_box['id'],
146
+ $this->meta_box['title'],
147
+ array( $this, 'show' ),
148
+ $page,
149
+ $this->meta_box['context'],
150
+ $this->meta_box['priority']
151
+ );
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Callback function to show fields in meta box
157
+ *
158
+ * @return void
159
+ */
160
+ public function show()
161
+ {
162
+ global $post;
163
+
164
+ $saved = self::has_been_saved( $post->ID, $this->fields );
165
+
166
+ wp_nonce_field( "rwmb-save-{$this->meta_box['id']}", "nonce_{$this->meta_box['id']}" );
167
+
168
+ // Allow users to add custom code before meta box content
169
+ // 1st action applies to all meta boxes
170
+ // 2nd action applies to only current meta box
171
+ do_action( 'rwmb_before' );
172
+ do_action( "rwmb_before_{$this->meta_box['id']}" );
173
+
174
+ foreach ( $this->fields as $field )
175
+ {
176
+ $group = ""; // Empty the clone-group field
177
+ $type = $field['type'];
178
+ $id = $field['id'];
179
+ $meta = self::apply_field_class_filters( $field, 'meta', '', $post->ID, $saved );
180
+ $meta = apply_filters( "rwmb_{$type}_meta", $meta );
181
+ $meta = apply_filters( "rwmb_{$id}_meta", $meta );
182
+
183
+ $begin = self::apply_field_class_filters( $field, 'begin_html', '', $meta );
184
+
185
+ // Apply filter to field begin HTML
186
+ // 1st filter applies to all fields
187
+ // 2nd filter applies to all fields with the same type
188
+ // 3rd filter applies to current field only
189
+ $begin = apply_filters( 'rwmb_begin_html', $begin, $field, $meta );
190
+ $begin = apply_filters( "rwmb_{$type}_begin_html", $begin, $field, $meta );
191
+ $begin = apply_filters( "rwmb_{$id}_begin_html", $begin, $field, $meta );
192
+
193
+ // Separate code for clonable and non-cloneable fields to make easy to maintain
194
+
195
+ // Cloneable fields
196
+ if ( self::is_cloneable( $field ) )
197
+ {
198
+ if ( isset( $field['clone-group'] ) )
199
+ $group = " clone-group='{$field['clone-group']}'";
200
+
201
+ if ( ! is_array( $field['field_name'] ) )
202
+ $field['field_name'] = (array) $field['field_name'];
203
+
204
+ $meta = (array) $meta;
205
+
206
+ foreach ( array_keys( $meta ) as $i )
207
+ $field['field_name'][$i] = $field['id'] . "[{$i}]";
208
+
209
+ $field_html = '';
210
+
211
+ $index = 0;
212
+ foreach ( $meta as $meta_data )
213
+ {
214
+ if ( is_array( $field['field_name'] ) )
215
+ {
216
+ $subfield = $field;
217
+ $subfield['field_name'] = $field['field_name'][$index];
218
+ }
219
+ else
220
+ $subfield = $field;
221
+
222
+ add_filter( "rwmb_{$id}_html", array( $this, 'add_delete_clone_button' ), 10, 3 );
223
+
224
+ // Wrap field HTML in a div with class="rwmb-clone" if needed
225
+ $input_html = '<div class="rwmb-clone">';
226
+
227
+ // Call separated methods for displaying each type of field
228
+ $input_html .= self::apply_field_class_filters( $subfield, 'html', '', $meta_data );
229
+
230
+ // Apply filter to field HTML
231
+ // 1st filter applies to all fields with the same type
232
+ // 2nd filter applies to current field only
233
+ $input_html = apply_filters( "rwmb_{$type}_html", $input_html, $field, $meta_data );
234
+ $input_html = apply_filters( "rwmb_{$id}_html", $input_html, $field, $meta_data );
235
+
236
+ $input_html .= '</div>';
237
+
238
+ $field_html .= $input_html;
239
+ $index++;
240
+ }
241
+ }
242
+ // Non-cloneable fields
243
+ else
244
+ {
245
+ // Call separated methods for displaying each type of field
246
+ $field_html = self::apply_field_class_filters( $field, 'html', '', $meta );
247
+
248
+ // Apply filter to field HTML
249
+ // 1st filter applies to all fields with the same type
250
+ // 2nd filter applies to current field only
251
+ $field_html = apply_filters( "rwmb_{$type}_html", $field_html, $field, $meta );
252
+ $field_html = apply_filters( "rwmb_{$id}_html", $field_html, $field, $meta );
253
+ }
254
+
255
+ $end = self::apply_field_class_filters( $field, 'end_html', '', $meta );
256
+
257
+ // Apply filter to field end HTML
258
+ // 1st filter applies to all fields
259
+ // 2nd filter applies to all fields with the same type
260
+ // 3rd filter applies to current field only
261
+ $end = apply_filters( 'rwmb_end_html', $end, $field, $meta );
262
+ $end = apply_filters( "rwmb_{$type}_end_html", $end, $field, $meta );
263
+ $end = apply_filters( "rwmb_{$id}_end_html", $end, $field, $meta );
264
+
265
+ // Apply filter to field wrapper
266
+ // This allow users to change whole HTML markup of the field wrapper (i.e. table row)
267
+ // 1st filter applies to all fields with the same type
268
+ // 2nd filter applies to current field only
269
+ $html = apply_filters( "rwmb_{$type}_wrapper_html", "{$begin}{$field_html}{$end}", $field, $meta );
270
+ $html = apply_filters( "rwmb_{$id}_wrapper_html", $html, $field, $meta );
271
+
272
+ // Display label and input in DIV and allow user-defined classes to be appended
273
+ $class = 'rwmb-field';
274
+ if ( isset( $field['required'] ) && $field['required'] )
275
+ $class .= ' required';
276
+ if ( isset( $field['class'] ) )
277
+ $class = $this->add_cssclass( $field['class'], $class );
278
+
279
+ // Hide the div if field has 'hidden' type
280
+ if ( 'hidden' === $field['type'] )
281
+ $class = $this->add_cssclass( 'hidden', $class );
282
+ echo "<div class='{$class}'{$group}>{$html}</div>";
283
+ }
284
+
285
+ // Include validation settings for this meta-box
286
+ if ( isset( $this->validation ) && $this->validation )
287
+ {
288
+ echo '
289
+ <script type="text/javascript">
290
+ if ( typeof rwmb == "undefined" )
291
+ {
292
+ var rwmb = {
293
+ validationOptions : jQuery.parseJSON( \'' . json_encode( $this->validation ) . '\' ),
294
+ summaryMessage : "' . __( 'Please correct the errors highlighted below and try again.', 'rwmb' ) . '"
295
+ };
296
+ }
297
+ else
298
+ {
299
+ var tempOptions = jQuery.parseJSON( \'' . json_encode( $this->validation ) . '\' );
300
+ jQuery.each( tempOptions.rules, function( k, v )
301
+ {
302
+ rwmb.validationOptions.rules[k] = v;
303
+ });
304
+ jQuery.each( tempOptions.messages, function( k, v )
305
+ {
306
+ rwmb.validationOptions.messages[k] = v;
307
+ });
308
+ };
309
+ </script>
310
+ ';
311
+ }
312
+
313
+ // Allow users to add custom code after meta box content
314
+ // 1st action applies to all meta boxes
315
+ // 2nd action applies to only current meta box
316
+ do_action( 'rwmb_after' );
317
+ do_action( "rwmb_after_{$this->meta_box['id']}" );
318
+ }
319
+
320
+ /**
321
+ * Show begin HTML markup for fields
322
+ *
323
+ * @param string $html
324
+ * @param mixed $meta
325
+ * @param array $field
326
+ *
327
+ * @return string
328
+ */
329
+ static function begin_html( $html, $meta, $field )
330
+ {
331
+ $class = 'rwmb-label';
332
+
333
+ if ( ! empty( $field['class'] ) )
334
+ $class = self::add_cssclass( $field['class'], $class );
335
+
336
+ if ( empty( $field['name'] ) )
337
+ return '<div class="rwmb-input">';
338
+
339
+ $html = <<<HTML
340
+ <div class="{$class}">
341
+ <label for="{$field['id']}">{$field['name']}</label>
342
+ </div>
343
+ <div class="rwmb-input">
344
+ HTML;
345
+
346
+ return $html;
347
+ }
348
+
349
+ /**
350
+ * Show end HTML markup for fields
351
+ *
352
+ * @param string $html
353
+ * @param mixed $meta
354
+ * @param array $field
355
+ *
356
+ * @return string
357
+ */
358
+ static function end_html( $html, $meta, $field )
359
+ {
360
+ $id = $field['id'];
361
+
362
+ $button = '';
363
+ if ( self::is_cloneable( $field ) )
364
+ $button = '<a href="#" class="rwmb-button button-primary add-clone">' . __( '+', 'rwmb' ) . '</a>';
365
+
366
+ $desc = ! empty( $field['desc'] ) ? "<p id='{$id}_description' class='description'>{$field['desc']}</p>" : '';
367
+
368
+ // Closes the container
369
+ $html = "{$button}{$desc}</div>";
370
+
371
+ return $html;
372
+ }
373
+
374
+ /**
375
+ * Callback function to add clone buttons on demand
376
+ * Hooks on the flight into the "rwmb_{$field_id}_html" filter before the closing div
377
+ *
378
+ * @param string $html
379
+ * @param array $field
380
+ * @param mixed $meta_data
381
+ *
382
+ * @return string $html
383
+ */
384
+ static function add_delete_clone_button( $html, $field, $meta_data )
385
+ {
386
+ $id = $field['id'];
387
+
388
+ $button = '<a href="#" class="rwmb-button button-secondary remove-clone">' . __( '&#8211;', 'rwmb' ) . '</a>';
389
+
390
+ return "{$html}{$button}";
391
+ }
392
+
393
+ /**
394
+ * Standard meta retrieval
395
+ *
396
+ * @param mixed $meta
397
+ * @param int $post_id
398
+ * @param array $field
399
+ * @param bool $saved
400
+ *
401
+ * @return mixed
402
+ */
403
+ static function meta( $meta, $post_id, $saved, $field )
404
+ {
405
+ $meta = get_post_meta( $post_id, $field['id'], !$field['multiple'] );
406
+
407
+ // Use $field['std'] only when the meta box hasn't been saved (i.e. the first time we run)
408
+ $meta = ( !$saved && '' === $meta || array() === $meta ) ? $field['std'] : $meta;
409
+
410
+ // Escape attributes for non-wysiwyg fields
411
+ if ( 'wysiwyg' !== $field['type'] )
412
+ $meta = is_array( $meta ) ? array_map( 'esc_attr', $meta ) : esc_attr( $meta );
413
+
414
+ return $meta;
415
+ }
416
+
417
+ /**************************************************
418
+ SAVE META BOX
419
+ **************************************************/
420
+
421
+ /**
422
+ * Save data from meta box
423
+ *
424
+ * @param int $post_id Post ID
425
+ *
426
+ * @return int|void
427
+ */
428
+ function save_post( $post_id )
429
+ {
430
+ global $post_type;
431
+ $post_type_object = get_post_type_object( $post_type );
432
+
433
+ // Check whether:
434
+ // - the post is autosaved
435
+ // - the post is a revision
436
+ // - current post type is supported
437
+ // - user has proper capability
438
+ if (
439
+ ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
440
+ || ( ! isset( $_POST['post_ID'] ) || $post_id != $_POST['post_ID'] )
441
+ || ( ! in_array( $post_type, $this->meta_box['pages'] ) )
442
+ || ( ! current_user_can( $post_type_object->cap->edit_post, $post_id ) )
443
+ )
444
+ {
445
+ return $post_id;
446
+ }
447
+
448
+ // Verify nonce
449
+ check_admin_referer( "rwmb-save-{$this->meta_box['id']}", "nonce_{$this->meta_box['id']}" );
450
+
451
+ foreach ( $this->fields as $field )
452
+ {
453
+ $name = $field['id'];
454
+ $old = get_post_meta( $post_id, $name, !$field['multiple'] );
455
+ $new = isset( $_POST[$name] ) ? $_POST[$name] : ( $field['multiple'] ? array() : '' );
456
+
457
+ // Allow field class change the value
458
+ $new = self::apply_field_class_filters( $field, 'value', $new, $old, $post_id );
459
+
460
+ // Use filter to change field value
461
+ // 1st filter applies to all fields with the same type
462
+ // 2nd filter applies to current field only
463
+ $new = apply_filters( "rwmb_{$field['type']}_value", $new, $field, $old );
464
+ $new = apply_filters( "rwmb_{$name}_value", $new, $field, $old );
465
+
466
+ // Call defined method to save meta value, if there's no methods, call common one
467
+ self::do_field_class_actions( $field, 'save', $new, $old, $post_id );
468
+ }
469
+ }
470
+
471
+ /**
472
+ * Common functions for saving field
473
+ *
474
+ * @param mixed $new
475
+ * @param mixed $old
476
+ * @param int $post_id
477
+ * @param array $field
478
+ *
479
+ * @return void
480
+ */
481
+ static function save( $new, $old, $post_id, $field )
482
+ {
483
+ $name = $field['id'];
484
+
485
+ delete_post_meta( $post_id, $name );
486
+ if ( '' === $new || array() === $new )
487
+ return;
488
+
489
+ if ( $field['multiple'] )
490
+ {
491
+ foreach ( $new as $add_new )
492
+ {
493
+ add_post_meta( $post_id, $name, $add_new, false );
494
+ }
495
+ }
496
+ else
497
+ {
498
+ update_post_meta( $post_id, $name, $new );
499
+ }
500
+ }
501
+
502
+ /**************************************************
503
+ HELPER FUNCTIONS
504
+ **************************************************/
505
+
506
+ /**
507
+ * Normalize parameters for meta box
508
+ *
509
+ * @param array $meta_box Meta box definition
510
+ *
511
+ * @return array $meta_box Normalized meta box
512
+ */
513
+ static function normalize( $meta_box )
514
+ {
515
+ // Set default values for meta box
516
+ $meta_box = wp_parse_args(
517
+ $meta_box, array(
518
+ 'id' => sanitize_title( $meta_box['title'] ),
519
+ 'context' => 'normal',
520
+ 'priority' => 'high',
521
+ 'pages' => array( 'post' )
522
+ )
523
+ );
524
+
525
+ // Set default values for fields
526
+ foreach ( $meta_box['fields'] as &$field )
527
+ {
528
+ $field = wp_parse_args(
529
+ $field, array(
530
+ 'multiple' => false,
531
+ 'clone' => false,
532
+ 'std' => '',
533
+ 'desc' => '',
534
+ 'format' => '',
535
+ )
536
+ );
537
+
538
+ // Allow field class add/change default field values
539
+ $field = self::apply_field_class_filters( $field, 'normalize_field', $field );
540
+
541
+ // Allow field class to manually change field_name
542
+ // @see taxonomy.php for example
543
+ if ( ! isset( $field['field_name'] ) )
544
+ $field['field_name'] = $field['id'] . ( $field['multiple'] || $field['clone'] ? '[0]' : '' );
545
+ }
546
+
547
+ return $meta_box;
548
+ }
549
+
550
+ /**
551
+ * Get field class name
552
+ *
553
+ * @param string $type Field type
554
+ *
555
+ * @return bool|string Field class name OR false on failure
556
+ */
557
+ static function get_class_name( $type )
558
+ {
559
+ $type = ucwords( $type );
560
+ $class = "RWMB_{$type}_Field";
561
+
562
+ if ( class_exists( $class ) )
563
+ return $class;
564
+
565
+ return false;
566
+ }
567
+
568
+ /**
569
+ * Apply filters by field class, fallback to RW_Meta_Box method
570
+ *
571
+ * @param array $field
572
+ * @param string $method_name
573
+ * @param mixed $value
574
+ *
575
+ * @return mixed $value
576
+ */
577
+ static function apply_field_class_filters( $field, $method_name, $value )
578
+ {
579
+ $args = array_slice( func_get_args(), 2 );
580
+ $args[] = $field;
581
+
582
+ // Call: field class method
583
+ // Fallback: RW_Meta_Box method
584
+ $class = self::get_class_name( $field['type'] );
585
+ if ( method_exists( $class, $method_name ) )
586
+ {
587
+ $value = call_user_func_array( array( $class, $method_name ), $args );
588
+ }
589
+ elseif ( method_exists( __CLASS__, $method_name ) )
590
+ {
591
+ $value = call_user_func_array( array( __CLASS__, $method_name ), $args );
592
+ }
593
+
594
+ return $value;
595
+ }
596
+
597
+ /**
598
+ * Call field class method for actions, fallback to RW_Meta_Box method
599
+ *
600
+ * @param array $field
601
+ * @param string $method_name
602
+ *
603
+ * @return mixed
604
+ */
605
+ static function do_field_class_actions( $field, $method_name )
606
+ {
607
+ $args = array_slice( func_get_args(), 2 );
608
+ $args[] = $field;
609
+
610
+ // Call: field class method
611
+ // Fallback: RW_Meta_Box method
612
+ $class = self::get_class_name( $field['type'] );
613
+ if ( method_exists( $class, $method_name ) )
614
+ {
615
+ call_user_func_array( array( $class, $method_name ), $args );
616
+ }
617
+ elseif ( method_exists( __CLASS__, $method_name ) )
618
+ {
619
+ call_user_func_array( array( __CLASS__, $method_name ), $args );
620
+ }
621
+ }
622
+
623
+ /**
624
+ * Format Ajax response
625
+ *
626
+ * @param string $message
627
+ * @param string $status
628
+ *
629
+ * @return void
630
+ */
631
+ static function ajax_response( $message, $status )
632
+ {
633
+ $response = array( 'what' => 'meta-box' );
634
+ $response['data'] = 'error' === $status ? new WP_Error( 'error', $message ) : $message;
635
+ $x = new WP_Ajax_Response( $response );
636
+ $x->send();
637
+ }
638
+
639
+ /**
640
+ * Check if meta box has been saved
641
+ * This helps saving empty value in meta fields (for text box, check box, etc.)
642
+ *
643
+ * @param int $post_id
644
+ * @param array $fields
645
+ *
646
+ * @return bool
647
+ */
648
+ static function has_been_saved( $post_id, $fields )
649
+ {
650
+ $saved = false;
651
+ foreach ( $fields as $field )
652
+ {
653
+ if ( get_post_meta( $post_id, $field['id'], !$field['multiple'] ) )
654
+ {
655
+ $saved = true;
656
+ break;
657
+ }
658
+ }
659
+ return $saved;
660
+ }
661
+
662
+ /**
663
+ * Adds a css class
664
+ * Mainly a copy of the core admin menu function
665
+ * As the core function is only meant to be used by core internally,
666
+ * We copy it here - in case core changes functionality or drops the function.
667
+ *
668
+ * @param string $add
669
+ * @param string $class | Class name - Default: empty
670
+ *
671
+ * @return string $class
672
+ */
673
+ static function add_cssclass( $add, $class = '' )
674
+ {
675
+ $class .= empty( $class ) ? $add : " {$add}";
676
+
677
+ return $class;
678
+ }
679
+
680
+ /**
681
+ * Helper function to check for multi/clone field IDs
682
+ *
683
+ * @param array $field
684
+ *
685
+ * @return bool False if no cloneable
686
+ */
687
+ static function is_cloneable( $field )
688
+ {
689
+ return $field['clone'];
690
+ }
691
+ }
692
  }
inc/fields/select.php CHANGED
@@ -54,7 +54,7 @@ if ( ! class_exists( 'RWMB_Select_Field' ) )
54
  */
55
  static function normalize_field( $field )
56
  {
57
- $field['multiple'] = false;
58
  return $field;
59
  }
60
  }
54
  */
55
  static function normalize_field( $field )
56
  {
57
+ $field['multiple'] = empty( $field['multiple'] ) ? false : $field['multiple'];
58
  return $field;
59
  }
60
  }
inc/helpers.php CHANGED
@@ -71,7 +71,7 @@ function rwmb_meta( $key, $args = array(), $post_id = null )
71
  // Get post terms
72
  elseif ( 'taxonomy' == $args['type'] )
73
  {
74
- $meta = emtpy( $args['taxonomy'] ) ? array() : wp_get_post_terms( $post_id, $args['taxonomy'] );
75
  }
76
 
77
  return $meta;
71
  // Get post terms
72
  elseif ( 'taxonomy' == $args['type'] )
73
  {
74
+ $meta = empty( $args['taxonomy'] ) ? array() : wp_get_post_terms( $post_id, $args['taxonomy'] );
75
  }
76
 
77
  return $meta;
js/clone.js CHANGED
@@ -1,130 +1,130 @@
1
- jQuery( document ).ready( function ($)
2
- {
3
- /**
4
- * Hide remove buttons when there's only 1 of them
5
- *
6
- * @param $el jQuery element. If not supplied, the function will applies for all fields
7
- *
8
- * @return void
9
- */
10
- function toggle_remove_buttons( $el )
11
- {
12
- if ( ! $el )
13
- $el = $( '.rwmb-field' );
14
- $el.each( function()
15
- {
16
- var $remove_buttons = $( this ).find( '.remove-clone' );
17
- if ( $remove_buttons.length < 2 )
18
- $remove_buttons.hide();
19
- else
20
- $remove_buttons.show();
21
- } );
22
- }
23
-
24
- // Call it on first run
25
- toggle_remove_buttons();
26
-
27
- function add_cloned_fields( $input )
28
- {
29
- var $clone_last = $input.find( '.rwmb-clone:last' ),
30
- $clone = $clone_last.clone( true );
31
-
32
- $clone.insertAfter( $clone_last );
33
-
34
- // Reset value
35
- $clone.find( ':input' ).val( '' );
36
-
37
- // Get the field name, and increment
38
- var $index = $clone.find( ':input' ).attr("name").replace(/\[([0-9]+)\]$/,
39
- function(str, p1, p2, p3)
40
- {
41
- return mystr = '[' + (parseInt(p1) +1) + ']';
42
- });
43
-
44
- // Update the "name" attribute
45
- $clone.find( ':input' ).attr("name", $index);
46
-
47
- // Toggle remove buttons
48
- toggle_remove_buttons( $input );
49
-
50
- // Fix color picker
51
- if ( 'function' === typeof rwmb_update_color_picker )
52
- rwmb_update_color_picker();
53
-
54
- // Fix date picker
55
- if ( 'function' === typeof rwmb_update_date_picker )
56
- rwmb_update_date_picker();
57
-
58
- // Fix time picker
59
- if ( 'function' === typeof rwmb_update_time_picker )
60
- rwmb_update_time_picker();
61
-
62
- // Fix datetime picker
63
- if ( 'function' === typeof rwmb_update_datetime_picker )
64
- rwmb_update_datetime_picker();
65
- }
66
-
67
- // Add more clones
68
- $( '.add-clone' ).click( function ()
69
- {
70
- var $input = $( this ).parents( '.rwmb-input' );
71
- var $clone_group = $( this ).parents( '.rwmb-field' ).attr("clone-group");
72
-
73
- // If the field is part of a clone group, get all fields in that
74
- // group and itterate over them
75
- if ( $clone_group )
76
- {
77
- // Get the parent metabox and then find the matching
78
- // clone-group elements inside
79
- var $metabox = $( this ).parents( '.inside' );
80
- var $clone_group_list = $metabox.find( 'div[clone-group="' + $clone_group + '"]' );
81
-
82
- $.each($clone_group_list.find( '.rwmb-input' ),
83
- function(key, value) {
84
- add_cloned_fields( $(value) );
85
- });
86
- }
87
- else
88
- add_cloned_fields( $input );
89
-
90
- return false;
91
- } );
92
-
93
- // Remove clones
94
- $( '.rwmb-input' ).delegate( '.remove-clone', 'click', function()
95
- {
96
- var $this = $( this ),
97
- $input = $this.parents( '.rwmb-input' );
98
- var $clone_group = $( this ).parents( '.rwmb-field' ).attr("clone-group");
99
-
100
- // Remove clone only if there're 2 or more of them
101
- if ( $input.find( '.rwmb-clone' ).length > 1 )
102
- {
103
- if ( $clone_group )
104
- {
105
- // Get the parent metabox and then find the matching
106
- // clone-group elements inside
107
- var $metabox = $( this ).parents( '.inside' );
108
- var $clone_group_list = $metabox.find( 'div[clone-group="' + $clone_group + '"]' );
109
- var $index = $this.parent().index();
110
-
111
- $.each($clone_group_list.find( '.rwmb-input' ),
112
- function(key, value) {
113
- $(value).children( '.rwmb-clone' ).eq($index).remove();
114
-
115
- // Toggle remove buttons
116
- toggle_remove_buttons( $(value) );
117
- });
118
- }
119
- else
120
- {
121
- $this.parent().remove();
122
-
123
- // Toggle remove buttons
124
- toggle_remove_buttons( $input );
125
- }
126
- }
127
-
128
- return false;
129
- } );
130
  } );
1
+ jQuery( document ).ready( function ($)
2
+ {
3
+ /**
4
+ * Hide remove buttons when there's only 1 of them
5
+ *
6
+ * @param $el jQuery element. If not supplied, the function will applies for all fields
7
+ *
8
+ * @return void
9
+ */
10
+ function toggle_remove_buttons( $el )
11
+ {
12
+ if ( ! $el )
13
+ $el = $( '.rwmb-field' );
14
+ $el.each( function()
15
+ {
16
+ var $remove_buttons = $( this ).find( '.remove-clone' );
17
+ if ( $remove_buttons.length < 2 )
18
+ $remove_buttons.hide();
19
+ else
20
+ $remove_buttons.show();
21
+ } );
22
+ }
23
+
24
+ // Call it on first run
25
+ toggle_remove_buttons();
26
+
27
+ function add_cloned_fields( $input )
28
+ {
29
+ var $clone_last = $input.find( '.rwmb-clone:last' ),
30
+ $clone = $clone_last.clone( true );
31
+
32
+ $clone.insertAfter( $clone_last );
33
+
34
+ // Reset value
35
+ $clone.find( ':input' ).val( '' );
36
+
37
+ // Get the field name, and increment
38
+ var $index = $clone.find( ':input' ).attr("name").replace(/\[([0-9]+)\]$/,
39
+ function(str, p1, p2, p3)
40
+ {
41
+ return mystr = '[' + (parseInt(p1) +1) + ']';
42
+ });
43
+
44
+ // Update the "name" attribute
45
+ $clone.find( ':input' ).attr("name", $index);
46
+
47
+ // Toggle remove buttons
48
+ toggle_remove_buttons( $input );
49
+
50
+ // Fix color picker
51
+ if ( 'function' === typeof rwmb_update_color_picker )
52
+ rwmb_update_color_picker();
53
+
54
+ // Fix date picker
55
+ if ( 'function' === typeof rwmb_update_date_picker )
56
+ rwmb_update_date_picker();
57
+
58
+ // Fix time picker
59
+ if ( 'function' === typeof rwmb_update_time_picker )
60
+ rwmb_update_time_picker();
61
+
62
+ // Fix datetime picker
63
+ if ( 'function' === typeof rwmb_update_datetime_picker )
64
+ rwmb_update_datetime_picker();
65
+ }
66
+
67
+ // Add more clones
68
+ $( '.add-clone' ).click( function ()
69
+ {
70
+ var $input = $( this ).parents( '.rwmb-input' );
71
+ var $clone_group = $( this ).parents( '.rwmb-field' ).attr("clone-group");
72
+
73
+ // If the field is part of a clone group, get all fields in that
74
+ // group and itterate over them
75
+ if ( $clone_group )
76
+ {
77
+ // Get the parent metabox and then find the matching
78
+ // clone-group elements inside
79
+ var $metabox = $( this ).parents( '.inside' );
80
+ var $clone_group_list = $metabox.find( 'div[clone-group="' + $clone_group + '"]' );
81
+
82
+ $.each($clone_group_list.find( '.rwmb-input' ),
83
+ function(key, value) {
84
+ add_cloned_fields( $(value) );
85
+ });
86
+ }
87
+ else
88
+ add_cloned_fields( $input );
89
+
90
+ return false;
91
+ } );
92
+
93
+ // Remove clones
94
+ $( '.rwmb-input' ).delegate( '.remove-clone', 'click', function()
95
+ {
96
+ var $this = $( this ),
97
+ $input = $this.parents( '.rwmb-input' );
98
+ var $clone_group = $( this ).parents( '.rwmb-field' ).attr("clone-group");
99
+
100
+ // Remove clone only if there're 2 or more of them
101
+ if ( $input.find( '.rwmb-clone' ).length > 1 )
102
+ {
103
+ if ( $clone_group )
104
+ {
105
+ // Get the parent metabox and then find the matching
106
+ // clone-group elements inside
107
+ var $metabox = $( this ).parents( '.inside' );
108
+ var $clone_group_list = $metabox.find( 'div[clone-group="' + $clone_group + '"]' );
109
+ var $index = $this.parent().index();
110
+
111
+ $.each($clone_group_list.find( '.rwmb-input' ),
112
+ function(key, value) {
113
+ $(value).children( '.rwmb-clone' ).eq($index).remove();
114
+
115
+ // Toggle remove buttons
116
+ toggle_remove_buttons( $(value) );
117
+ });
118
+ }
119
+ else
120
+ {
121
+ $this.parent().remove();
122
+
123
+ // Toggle remove buttons
124
+ toggle_remove_buttons( $input );
125
+ }
126
+ }
127
+
128
+ return false;
129
+ } );
130
  } );
js/thickbox-image.js CHANGED
@@ -1,18 +1,18 @@
1
- jQuery( document ).ready( function($)
2
  {
3
- // Reorder images
4
  $( '.rwmb-thickbox-upload' ).click( function()
5
  {
6
- var $this = $(this),
7
  $holder = $this.siblings( '.rwmb-images' ),
8
- post_id = $('#post_ID').val(),
9
- field_id = $this.attr('rel'),
10
  backup = window.send_to_editor;
11
- window.send_to_editor = function(html) {
12
- var $img = $('<div />').append(html).find('img'),
13
- url = $img.attr('src'),
14
- img_class = $img.attr('class'),
15
- id = parseInt(img_class.replace(/\D/g, ''), 10);
 
16
 
17
  html = '<li id="item_' + id + '">';
18
  html += '<img src="' + url + '" />';
@@ -22,12 +22,12 @@ jQuery( document ).ready( function($)
22
  html += '<input type="hidden" name="' + field_id + '[]" value="' + id + '" />';
23
  html += '</li>';
24
 
25
- $holder.append($(html)).removeClass('hidden');
26
 
27
  tb_remove();
28
  window.send_to_editor = backup;
29
  }
30
- tb_show('', 'media-upload.php?post_id=' + post_id + '&TB_iframe=true');
31
 
32
  return false;
33
  } );
1
+ jQuery( document ).ready( function( $ )
2
  {
 
3
  $( '.rwmb-thickbox-upload' ).click( function()
4
  {
5
+ var $this = $( this ),
6
  $holder = $this.siblings( '.rwmb-images' ),
7
+ post_id = $( '#post_ID' ).val(),
8
+ field_id = $this.attr( 'rel' ),
9
  backup = window.send_to_editor;
10
+
11
+ window.send_to_editor = function( html ) {
12
+ var $img = $( '<div />' ).append( html ).find( 'img' ),
13
+ url = $img.attr( 'src' ),
14
+ img_class = $img.attr( 'class' ),
15
+ id = parseInt( img_class.replace( /\D/g, '' ), 10 );
16
 
17
  html = '<li id="item_' + id + '">';
18
  html += '<img src="' + url + '" />';
22
  html += '<input type="hidden" name="' + field_id + '[]" value="' + id + '" />';
23
  html += '</li>';
24
 
25
+ $holder.append( $( html ) ).removeClass( 'hidden' );
26
 
27
  tb_remove();
28
  window.send_to_editor = backup;
29
  }
30
+ tb_show( '', 'media-upload.php?post_id=' + post_id + '&TB_iframe=true' );
31
 
32
  return false;
33
  } );
js/validate.js CHANGED
@@ -1,25 +1,23 @@
1
- jQuery(function ($) {
 
 
 
 
 
 
 
 
 
 
 
2
 
3
- $(document).ready(function() {
4
-
5
- // required field styling
6
- $.each(rwmb.validationOptions.rules, function(k, v) {
7
- if (v['required']) {
8
- var label = $('#' + k).parent().siblings('.rwmb-label');
9
- $(label).find('label').css('font-weight','bold');
10
- $(label).append('<span class="required">*</span>');
11
- }
12
- });
13
-
14
- rwmb.validationOptions.invalidHandler = function(form, validator) {
15
- // re-enable the submit (publish/update) button and hide the ajax indicator
16
- $('#publish').removeClass('button-primary-disabled');
17
- $('#ajax-loading').attr('style','');
18
- $('form#post').siblings('#message').remove();
19
- $('form#post').before('<div id="message" class="error"><p>' + rwmb.summaryMessage + '</p></div>');
20
- };
21
- $('form#post').validate(rwmb.validationOptions);
22
-
23
- });
24
-
25
- });
1
+ jQuery( document ).ready( function ( $ )
2
+ {
3
+ // Required field styling
4
+ $.each( rwmb.validationOptions.rules, function( k, v )
5
+ {
6
+ if ( v['required'] )
7
+ {
8
+ var $label = $( '#' + k ).parent().siblings( '.rwmb-label' );
9
+ $label.find( 'label' ).css( 'font-weight','bold' );
10
+ $label.append( '<span class="required">*</span>' );
11
+ }
12
+ } );
13
 
14
+ rwmb.validationOptions.invalidHandler = function( form, validator )
15
+ {
16
+ // Re-enable the submit ( publish/update ) button and hide the ajax indicator
17
+ $( '#publish' ).removeClass( 'button-primary-disabled' );
18
+ $( '#ajax-loading' ).attr( 'style','' );
19
+ $( 'form#post' ).siblings( '#message' ).remove();
20
+ $( 'form#post' ).before( '<div id="message" class="error"><p>' + rwmb.summaryMessage + '</p></div>' );
21
+ };
22
+ $( 'form#post' ).validate( rwmb.validationOptions );
23
+ } );
 
 
 
 
 
 
 
 
 
 
 
 
 
meta-box.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Meta Box
4
  Plugin URI: http://www.deluxeblogtips.com/meta-box
5
  Description: Create meta box for editing pages in WordPress. Compatible with custom post types since WP 3.0
6
- Version: 4.1.10
7
  Author: Rilwis
8
  Author URI: http://www.deluxeblogtips.com
9
  License: GPL2+
3
  Plugin Name: Meta Box
4
  Plugin URI: http://www.deluxeblogtips.com/meta-box
5
  Description: Create meta box for editing pages in WordPress. Compatible with custom post types since WP 3.0
6
+ Version: 4.1.11
7
  Author: Rilwis
8
  Author URI: http://www.deluxeblogtips.com
9
  License: GPL2+
readme.md DELETED
@@ -1,211 +0,0 @@
1
- [Project Page](http://www.deluxeblogtips.com/meta-box/) | [Getting Started](http://www.deluxeblogtips.com/meta-box/getting-started/) | [Support Forums](http://www.deluxeblogtips.com/forums/) | [Donate](http://www.deluxeblogtips.com/donate/)
2
-
3
- ***
4
-
5
- ## Plugin Information
6
-
7
- Meta Box plugin provides an API to easily implement custom meta boxes in editing pages (add new/edit post) in WordPress. It works with custom post types and supports various field types.
8
-
9
- ### Features
10
-
11
- * Easily registers multiple custom meta boxes for posts, pages or custom post types
12
- * Has built-in hooks which allow you to change the appearance and behavior of meta boxes
13
- * Easily integrated with themes
14
-
15
- ### Supported fields
16
-
17
- - checkbox_list
18
- - checkbox
19
- - color
20
- - date
21
- - datetime
22
- - file
23
- - hidden
24
- - image
25
- - password
26
- - plupload_image
27
- - radio
28
- - select
29
- - slider
30
- - taxonomy
31
- - text
32
- - textarea
33
- - thickbox_image
34
- - time
35
- - wysiwyg
36
-
37
- ***
38
-
39
- ## Installation
40
-
41
- 1. Unzip the download package
42
- 1. Upload `meta-box` to the `/wp-content/plugins/` directory
43
- 1. Activate the plugin through the 'Plugins' menu in WordPress
44
-
45
- To getting started with the plugin API, please read [this tutorial](http://www.deluxeblogtips.com/meta-box/getting-started/).
46
-
47
- ***
48
-
49
- ## Contributors
50
-
51
- - [Tran Ngoc Tuan Anh a.k.a Rilwis](http://www.deluxeblogtips.com/) - Initial & lead developer
52
- - [Franz Josef Kaiser](http://unserkaiser.com)
53
- - Omnicia
54
- - ruanmer
55
- - PerWiklander
56
- - funkedgeek
57
-
58
- [See full list of angels!](https://github.com/rilwis/meta-box/contributors)
59
-
60
- ***
61
-
62
- ## Changelog
63
-
64
- #### 4.1.10
65
- * Allow helper functions can be used in admin area
66
- * Allow cloned fields to have a uniquely indexed `name` attribute
67
- * Add Swedish translation
68
- * Allow hidden field has its own value
69
- * Taxonomy field now supported by `rwmb_meta` function
70
- * Improvement in code format and field normalizing
71
-
72
- #### 4.1.9
73
- * Add helper function to retrieve meta values
74
- * Add basic validation (JS based)
75
- * Fix image reorder bug
76
- * Fix `select_tree` option for taxonomy field
77
- * Fix not showing loading image for 1st image using plupload
78
-
79
- #### 4.1.8
80
- * Add missed JS file for thickbox image
81
-
82
- #### 4.1.7
83
- * Quick fix for thickbox image
84
-
85
- #### 4.1.6
86
- * Quick fix for checkbox list and multiple/clonable fields
87
-
88
- #### 4.1.5
89
- * Taxonomy field is now in core
90
- * Add demo for including meta boxes for specific posts based on IDs or page templates
91
- * Meta box ID is now optional
92
- * Add `thickbox_image` field for uploading image with WP style
93
- * Fix `guid` for uploaded images
94
-
95
- #### 4.1.4
96
- * Fix taxonomy field
97
-
98
- #### 4.1.3
99
- * Support max_file_uploads for plupload_image
100
- * Better enqueue styles and scripts
101
- * Store images in correct order after re-order
102
- * Fix cloning color, date, time, datetime fields
103
-
104
- #### 4.1.2
105
- * Improve taxonomy field
106
- * Add filter to wp_editor
107
- * Add more options for time field
108
- * Improve plupload_image field
109
- * Fix translation, use string for textdomain
110
-
111
- #### 4.1.1
112
- * Fix translation
113
- * Change jQueryUI theme to 'smoothness'
114
- * Add more demos in the `demo` folder
115
-
116
- #### 4.1
117
- * Added jQuery UI slider field
118
- * Added new Plupload file uploader
119
- * Added new checkbox list
120
- * Fix empty jQuery UI div seen in FF in admin footer area
121
- * Fix style for 'side' meta box
122
-
123
- #### 4.0.2
124
- * Reformat code to make more readable
125
- * Fix bugs of checkbox field and date field
126
-
127
- #### 4.0.1
128
- * Change `format_response()` to `ajax_response()` and use WP_Ajax_Response class to control the ajax response
129
- * Use `wp_editor()` built-in with WP 3.3 (with fallback)
130
-
131
- #### 4.0
132
- * strongly refactor code
133
- * create/check better nonce for each meta box
134
- * use local JS/CSS libs instead of remote files for better control if conflict occurs
135
- * separate field functions (enqueue scripts and styles, add actions, show, save) into separated classes
136
- * use filters to let user change HTML of fields
137
- * use filters to validate/change field values instead of validation class
138
- * don't use Ajax on image upload as it's buggy and complicated. Revert to default upload
139
-
140
- #### 3.2.2
141
- * fix WYSIWYG field for custom post type without 'editor' support. Thanks Jamie, Eugene and Selin Online. [link](http://disq.us/2hzgsk)
142
- * change some helper function to static as they're shared between objects
143
-
144
- #### 3.2.1
145
- * fix code for getting script's url in Windows
146
- * make meta box id is optional
147
-
148
- #### 3.2
149
- * move js and css codes to separated files (rewrite js code for fields, too)
150
- * allow to add multiple images to image meta field with selection, modified from "Fast Insert Image" plugin
151
- * remove 'style' attibutes for fields as all CSS rules now can be put in the 'meta=box.css' file. All fields now has the class 'rw=$type', and table cells have class 'rwmb=label' and 'rwmb=field'
152
- * allow to use file uploader for images as well, regarding [link](http://disq.us/1k2lwf)
153
- * when delete uploaded images, they're not deleted from the server (in case you insert them from the media, not the uploader). Also remove hook to delete all attachments when delete post. Regarding [link](http://disq.us/1nppyi)
154
- * change hook for adding meta box to 'add_meta_boxes', according Codex. Required WP 3.0+
155
- * fix image uploading when custom post type doesn't support "editor"
156
- * fix show many alerts when delete files, regarding [link](http://disq.us/1lolgb)
157
- * fix js comma missing bug when implement multiple fields with same type
158
- * fix order of uploaded images, thank Onur
159
- * fix deleting new uploaded image
160
- * fix bug when save meta value = zero (0), regarding [link](http://disq.us/1tg008)
161
- * some minor changes such as = add 'id' attribute to fields, show uploaded images as thumbnail, add script to header of post.php and post=new.php only
162
-
163
- #### 3.1
164
- * use thickbox for image uploading, allow user edit title, caption or crop, rotate image (credit to Stewart Duffy, idea from Jaace http =//disq.us/1bu64d)
165
- * allow to reorder uploaded images (credit to Kai)
166
- * save attach ID instead of url (credit to Stewart Duffy)
167
- * escape fields value (credit to Stewart Duffy)
168
- * add 'style' attribute to fields, allow user quick style fields (like height, width, etc.) (credit to Anders Larsson [link](http://disq.us/1eg4kp))
169
- * wrap ajax callbacks into the class
170
- * fix jquery UI conflict (for time picker, color picker, contextual help)
171
- * fix notice error for checking post type
172
-
173
- #### 3.0.1
174
- * save uploaded images and files' urls in meta fields
175
- * fix date picker bug to not show saved value [link](http://disq.us/1cg6mx)
176
- * fix check_admin_referer for non=supported post types [link](http://goo.gl/B6cah)
177
- * refactor code for showing fields
178
-
179
- #### 3.0
180
- * separate functions for checking, displaying and saving each type of field; allow developers easily extend the class
181
- * add 'checkbox_list' (credit to Jan Fabry [link](http://goo.gl/9sDAx)), 'color', 'date', 'time' types. The 'taxonomy' type is added as an example of extending class (credit to Manny Fresh [link](http://goo.gl/goGfm))
182
- * show uploaded files as well as allow to add/delete attached files
183
- * delete attached files when post is deleted (credit to Kai [link](http://goo.gl/9gfvd))
184
- * validation function MUST return the value instead of true, false
185
- * change the way of definition 'radio', 'select' field type to make it more simpler, allow multiple selection of select box
186
- * improved some codes, fix code to not show warnings when in debugging mode
187
-
188
- #### 2.4.1
189
- * fix bug of not receiving value for select box
190
-
191
- #### 2.4
192
- * (image upload features are credit to Kai [link](http://twitter.com/ungestaltbar))
193
- * change image upload using meta fields to using default WP gallery
194
- * add delete button for images, using ajax
195
- * allow to upload multiple images
196
- * add validation for meta fields
197
-
198
- #### 2.3
199
- * add wysiwyg editor type, improve check for upload fields, change context and priority attributes to optional
200
-
201
- #### 2.2
202
- * add enctype to post form (fix upload bug), thanks to [link](http://goo.gl/PWWNf)
203
-
204
- #### 2.1
205
- * add file upload, image upload support
206
-
207
- #### 2.0
208
- * oop code, support multiple post types, multiple meta boxes
209
-
210
- #### 1.0
211
- * procedural code
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
readme.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: rilwis, franz-josef-kaiser, Omnicia, funkedgeek, PerWiklander, rua
3
  Donate link: http://www.deluxeblogtips.com/donate
4
  Tags: meta-box, custom-fields, custom-field, meta, meta-boxes
5
  Requires at least: 3.0
6
- Tested up to: 3.4.1
7
- Stable tag: 4.1.10
8
 
9
  Meta Box plugin helps you easily implement multiple meta boxes in editing pages in WordPress. Works with custom post types and various field types.
10
 
@@ -58,6 +58,10 @@ To getting started with the plugin API, please read [this tutorial](http://www.d
58
 
59
  == Changelog ==
60
 
 
 
 
 
61
  = 4.1.10 =
62
  * Allow helper functions can be used in admin area
63
  * Allow cloned fields to have a uniquely indexed `name` attribute
3
  Donate link: http://www.deluxeblogtips.com/donate
4
  Tags: meta-box, custom-fields, custom-field, meta, meta-boxes
5
  Requires at least: 3.0
6
+ Tested up to: 3.4.2
7
+ Stable tag: 4.1.11
8
 
9
  Meta Box plugin helps you easily implement multiple meta boxes in editing pages in WordPress. Works with custom post types and various field types.
10
 
58
 
59
  == Changelog ==
60
 
61
+ = 4.1.11 =
62
+ * Bug fix: helper function for getting `taxonomy` field type
63
+ * Bug fix: `multiple` attribute for `select` field type
64
+
65
  = 4.1.10 =
66
  * Allow helper functions can be used in admin area
67
  * Allow cloned fields to have a uniquely indexed `name` attribute