Version Description
- Bug fix: helper function for getting
taxonomy
field type - Bug fix:
multiple
attribute forselect
field type
Download this release
Release Info
Developer | rilwis |
Plugin | Meta Box |
Version | 4.1.11 |
Comparing to | |
See all releases |
Code changes from version 4.1.10 to 4.1.11
- inc/classes/meta-box.php +691 -691
- inc/fields/select.php +1 -1
- inc/helpers.php +1 -1
- js/clone.js +129 -129
- js/thickbox-image.js +12 -12
- js/validate.js +22 -24
- meta-box.php +1 -1
- readme.md +0 -211
- 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 |
-
|
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">' . __( '–', '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">' . __( '–', '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 =
|
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 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
|
|
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 |
-
|
4 |
-
|
5 |
-
//
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
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.
|
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.
|
7 |
-
Stable tag: 4.1.
|
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
|