public
Last active

Repeating Custom Fields in a Metabox

  • Download Gist
repeatable-fields-metabox.php
PHP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
<?
/**
* Repeatable Custom Fields in a Metabox
* Author: Helen Hou-Sandi
*
* From a bespoke system, so currently not modular - will fix soon
* Note that this particular metadata is saved as one multidimensional array (serialized)
*/
function hhs_get_sample_options() {
$options = array (
'Option 1' => 'option1',
'Option 2' => 'option2',
'Option 3' => 'option3',
'Option 4' => 'option4',
);
return $options;
}
 
add_action('admin_init', 'hhs_add_meta_boxes', 1);
function hhs_add_meta_boxes() {
add_meta_box( 'repeatable-fields', 'Repeatable Fields', 'hhs_repeatable_meta_box_display', 'post', 'normal', 'default');
}
 
function hhs_repeatable_meta_box_display() {
global $post;
 
$repeatable_fields = get_post_meta($post->ID, 'repeatable_fields', true);
$options = hhs_get_sample_options();
 
wp_nonce_field( 'hhs_repeatable_meta_box_nonce', 'hhs_repeatable_meta_box_nonce' );
?>
<script type="text/javascript">
jQuery(document).ready(function( $ ){
$( '#add-row' ).on('click', function() {
var row = $( '.empty-row.screen-reader-text' ).clone(true);
row.removeClass( 'empty-row screen-reader-text' );
row.insertBefore( '#repeatable-fieldset-one tbody>tr:last' );
return false;
});
$( '.remove-row' ).on('click', function() {
$(this).parents('tr').remove();
return false;
});
});
</script>
<table id="repeatable-fieldset-one" width="100%">
<thead>
<tr>
<th width="40%">Name</th>
<th width="12%">Select</th>
<th width="40%">URL</th>
<th width="8%"></th>
</tr>
</thead>
<tbody>
<?php
if ( $repeatable_fields ) :
foreach ( $repeatable_fields as $field ) {
?>
<tr>
<td><input type="text" class="widefat" name="name[]" value="<?php if($field['name'] != '') echo esc_attr( $field['name'] ); ?>" /></td>
<td>
<select name="select[]">
<?php foreach ( $options as $label => $value ) : ?>
<option value="<?php echo $value; ?>"<?php selected( $field['select'], $value ); ?>><?php echo $label; ?></option>
<?php endforeach; ?>
</select>
</td>
<td><input type="text" class="widefat" name="url[]" value="<?php if ($field['url'] != '') echo esc_attr( $field['url'] ); else echo 'http://'; ?>" /></td>
<td><a class="button remove-row" href="#">Remove</a></td>
</tr>
<?php
}
else :
// show a blank one
?>
<tr>
<td><input type="text" class="widefat" name="name[]" /></td>
<td>
<select name="select[]">
<?php foreach ( $options as $label => $value ) : ?>
<option value="<?php echo $value; ?>"><?php echo $label; ?></option>
<?php endforeach; ?>
</select>
</td>
<td><input type="text" class="widefat" name="url[]" value="http://" /></td>
<td><a class="button remove-row" href="#">Remove</a></td>
</tr>
<?php endif; ?>
<!-- empty hidden one for jQuery -->
<tr class="empty-row screen-reader-text">
<td><input type="text" class="widefat" name="name[]" /></td>
<td>
<select name="select[]">
<?php foreach ( $options as $label => $value ) : ?>
<option value="<?php echo $value; ?>"><?php echo $label; ?></option>
<?php endforeach; ?>
</select>
</td>
<td><input type="text" class="widefat" name="url[]" value="http://" /></td>
<td><a class="button remove-row" href="#">Remove</a></td>
</tr>
</tbody>
</table>
<p><a id="add-row" class="button" href="#">Add another</a></p>
<?php
}
 
add_action('save_post', 'hhs_repeatable_meta_box_save');
function hhs_repeatable_meta_box_save($post_id) {
if ( ! isset( $_POST['hhs_repeatable_meta_box_nonce'] ) ||
! wp_verify_nonce( $_POST['hhs_repeatable_meta_box_nonce'], 'hhs_repeatable_meta_box_nonce' ) )
return;
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE)
return;
if (!current_user_can('edit_post', $post_id))
return;
$old = get_post_meta($post_id, 'repeatable_fields', true);
$new = array();
$options = hhs_get_sample_options();
$names = $_POST['name'];
$selects = $_POST['select'];
$urls = $_POST['url'];
$count = count( $names );
for ( $i = 0; $i < $count; $i++ ) {
if ( $names[$i] != '' ) :
$new[$i]['name'] = stripslashes( strip_tags( $names[$i] ) );
if ( in_array( $selects[$i], $options ) )
$new[$i]['select'] = $selects[$i];
else
$new[$i]['select'] = '';
if ( $urls[$i] == 'http://' )
$new[$i]['url'] = '';
else
$new[$i]['url'] = stripslashes( $urls[$i] ); // and however you want to sanitize
endif;
}
 
if ( !empty( $new ) && $new != $old )
update_post_meta( $post_id, 'repeatable_fields', $new );
elseif ( empty($new) && $old )
delete_post_meta( $post_id, 'repeatable_fields', $old );
}
?>
  • stripslashes() your $_POST values.
  • esc_attr() for anything that echoes in an HTML attribute. Especially on line 72!

thanks for the code i was wondering, how can i add another custom fields so that i can save video and audio in two different custom fields

it would be possible to make the rows sortable?

forget it, i've done it :)

How to use radio buttons instead of select box ?

Where I need to put the code? in functions.php?

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.