title: Wordpress - Dynamically adding new fields in the administration
body: <p>Im wondering if someone can help me out ... At the moment i have the following code which adds and saves data from a custom meta box in the wordpress admin.</p>
  
  <p>What i want to be able to do, is add a little href that says something like "add more info", which will then render another round of the fields, so i will be able to add as many as i need.</p>
  
  <p>I hope someone can help.</p>
  
  <p>The code i have to render and save just 1 round of fields is as follows:</p>
  
  <pre><code>$new_copy_prefix = 'new_copy_';
  $new_copy_meta_box = array(
  'id' =&gt; 'new_copy_meta_box',
  'title' =&gt; 'Content',
  'page' =&gt; 'post',
  'context' =&gt; 'normal',
  'priority' =&gt; 'high',
  'fields' =&gt; array(
      array(
          'name' =&gt; 'Title:',
          'desc' =&gt; '',
          'id' =&gt; $new_copy_prefix . 'title',
          'type' =&gt; 'text',
          'std' =&gt; ''
      ),
      array(
          'name' =&gt; 'Content:',
          'desc' =&gt; '',
          'id' =&gt; $new_copy_prefix . 'content',
          'type' =&gt; 'textarea',
          'std' =&gt; ''
      ),
  )
  );
  
  function new_copy_meta_box() {
  global $new_copy_meta_box;
  
  add_meta_box($new_copy_meta_box['id'], $new_copy_meta_box['title'], 'display_new_copy_html', $new_copy_meta_box['page'], $new_copy_meta_box['context'], $new_copy_meta_box['priority'] );
  }
  add_action( 'admin_menu', 'new_copy_meta_box' );
  
  function display_new_copy_html() {
  global $new_copy_meta_box, $post;
  
  // Use nonce for verification to check that the person has adequate priveleges
  echo '&lt;input type="hidden" name="new_copy_meta_box_nonce" value="', wp_create_nonce(basename(__FILE__)), '" /&gt;';        
  
  // Create the code to display teh HTML
  echo '&lt;table class="form-table"&gt;';
  
  foreach($new_copy_meta_box['fields'] as $field) {
      $meta = get_post_meta($post-&gt;ID, $field['id'], true);
  
      echo '&lt;tr&gt;';
      echo '  &lt;th style="width:35%"&gt;&lt;label for="', $field['id'], '"&gt;', $field['name'], '&lt;/label&gt;&lt;/th&gt;';
      echo '  &lt;td&gt;';
  
      switch ($field['type']) {
          case 'text': // The html to display for the text type
              echo '&lt;input type="text" name="', $field['id'], '" id="', $field['id'], '" value="', $meta ? $meta : $field['std'], '" size="30" style="width:97%" /&gt;', '&lt;br /&gt;', $field['desc'];
              break;
  
          case 'textarea': // The html to display for the textarea type
              echo '&lt;textarea name="', $field['id'], '" id="', $field['id'], '" cols="60" rows="4" style="width:97%"&gt;', $meta ? $meta : $field['std'], '&lt;/textarea&gt;', '&lt;br /&gt;', $field['desc'];
              break;
      }
  
      echo '  &lt;/td&gt;';
      echo '&lt;/tr&gt;';
  }
  
  echo '&lt;/table&gt;';
  }
  
  function new_copy_meta_box_save_data($post_id) {
  global $new_copy_meta_box;
  
  // Verify nonce -- Checks that the user has access
  if (!wp_verify_nonce($_POST['new_copy_meta_box_nonce'], basename(__FILE__))) {
      return $post_id;
  }
  
  // Check autosave
  if (defined('DOING AUTOSAVE') &amp;&amp; DOING_AUTOSAVE) {
      return $post_id;
  }
  
  // check permissions
  if ('post' == $_POST['post_type']) {
      if (!current_user_can('edit_page', $post_id)) {
          return $post_id;
      }
  } elseif (!current_user_can('edit_post', $post_id)) {
      return $post_id;
  }
  
  foreach ($new_copy_meta_box['fields'] as $field) { // Save each option
      $old = get_post_meta($post_id, $field['id'], true);
      $new = $_POST[$field['id']];
  
      if($new &amp;&amp; $new != $old) { // Compare changes to existing data
          update_post_meta($post_id, $field['id'], $new);
      } elseif ('' == $new &amp;&amp; $old) {
          delete_post_meta($post_id, $field['id'], $old);
      }
  }
  }
  add_action('save_post', 'new_copy_meta_box_save_data' ); // Save the data
  </code></pre>