Skip to content

Instantly share code, notes, and snippets.

Last active April 18, 2024 09:23
Show Gist options
  • Star 27 You must be signed in to star a gist
  • Fork 11 You must be signed in to fork a gist
  • Save akshuvo/d3c031bbb2fe89670e70fd3630705cf3 to your computer and use it in GitHub Desktop.
Save akshuvo/d3c031bbb2fe89670e70fd3630705cf3 to your computer and use it in GitHub Desktop.
Creating a “repeater meta-box” without a Plugin in WordPress
add_action('admin_init', 'gpm_add_meta_boxes', 2);
function gpm_add_meta_boxes() {
add_meta_box( 'gpminvoice-group', 'Custom Repeatable', 'Repeatable_meta_box_display', 'page', 'normal', 'default');
function Repeatable_meta_box_display() {
global $post;
$gpminvoice_group = get_post_meta($post->ID, 'customdata_group', true);
wp_nonce_field( 'gpm_repeatable_meta_box_nonce', 'gpm_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() {
return false;
<table id="repeatable-fieldset-one" width="100%">
if ( $gpminvoice_group ) :
foreach ( $gpminvoice_group as $field ) {
<td width="15%">
<input type="text" placeholder="Title" name="TitleItem[]" value="<?php if($field['TitleItem'] != '') echo esc_attr( $field['TitleItem'] ); ?>" /></td>
<td width="70%">
<textarea placeholder="Description" cols="55" rows="5" name="TitleDescription[]"> <?php if ($field['TitleDescription'] != '') echo esc_attr( $field['TitleDescription'] ); ?> </textarea></td>
<td width="15%"><a class="button remove-row" href="#1">Remove</a></td>
else :
// show a blank one
<input type="text" placeholder="Title" title="Title" name="TitleItem[]" /></td>
<textarea placeholder="Description" name="TitleDescription[]" cols="55" rows="5"> </textarea>
<td><a class="button cmb-remove-row-button button-disabled" href="#">Remove</a></td>
<?php endif; ?>
<!-- empty hidden one for jQuery -->
<tr class="empty-row screen-reader-text">
<input type="text" placeholder="Title" name="TitleItem[]"/></td>
<textarea placeholder="Description" cols="55" rows="5" name="TitleDescription[]"></textarea>
<td><a class="button remove-row" href="#">Remove</a></td>
<p><a id="add-row" class="button" href="#">Add another</a></p>
add_action('save_post', 'custom_repeatable_meta_box_save');
function custom_repeatable_meta_box_save($post_id) {
if ( ! isset( $_POST['gpm_repeatable_meta_box_nonce'] ) ||
! wp_verify_nonce( $_POST['gpm_repeatable_meta_box_nonce'], 'gpm_repeatable_meta_box_nonce' ) )
if (!current_user_can('edit_post', $post_id))
$old = get_post_meta($post_id, 'customdata_group', true);
$new = array();
$invoiceItems = $_POST['TitleItem'];
$prices = $_POST['TitleDescription'];
$count = count( $invoiceItems );
for ( $i = 0; $i < $count; $i++ ) {
if ( $invoiceItems[$i] != '' ) :
$new[$i]['TitleItem'] = stripslashes( strip_tags( $invoiceItems[$i] ) );
$new[$i]['TitleDescription'] = stripslashes( $prices[$i] ); // and however you want to sanitize
if ( !empty( $new ) && $new != $old )
update_post_meta( $post_id, 'customdata_group', $new );
elseif ( empty($new) && $old )
delete_post_meta( $post_id, 'customdata_group', $old );
Copy link

this is copy pase code becasue gpm is clinet project . this is written by Me in last 10 yeare ago. i am added in stackflow profile. make your self logic

Hi @vinay123456 , Yes this was copied from stackovflow I guess. I used to use this code in many projects frequently. So I created this gist to find this code quickly. Obviously I was making self logic on top of this code.

Thanks for sharing this code block.

thanks bro !
Data is not saved! How to save them as unserials.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment