How can I save repeatable fields with one value inside an array?

Introduce
I am currently working on a slider plugin to learn a lot of PHP and WordPress.
I have create some repeatable field with javascript.

Some functional details:

Read More
  • When the user is clicking on a button, the last row will cloned and
    all values will reset.
  • Add an increase to the javascript code for create unique ids for my input names and id’s.
  • Add an unique id for my rows that are cloned.

The problem:
I wrote this topic, because I have some issues with saving values from one variable in an array.

When I save the post or page, the first field will overwritten. This is because I loop through one image and one caption, not through the $_POST variable.

Question:
My question now is how I can resolve this problem? I have also looked at the source code that @brasofilo has recommended at Github – Gist. Brasofilo has only used one meta, but I would like to use a multidimensional array to create my fields. And save the values in one row in the database as an array.

I know that I can make use of several other plugins, but as I said before I would like to learn a lot of WordPress and PHP scripting language.

Script PHP:

Here you can see my used code for now, as I said before, it only saves
one image and one caption.

<?php

// Add meta box support
// This registers a function to be called when the WordPress admin interface is visited
add_action("admin_init", "dsslider_manager_add_meta");
function dsslider_manager_add_meta(){

    // Create this cool new meta box for Portfolio Options
    add_meta_box("dsslider-meta", "Brandbox Options", "dsslider_manager_meta_options", "brandbox-slider", "normal", "high");
}

// Create the fields array
$prefix = 'dsmeta_';
$custom_meta_fields = array(
    array(
        'label' => 'Image',
        'desc' => '',
        'id' => $prefix . 'image',
        'type' => 'image',
        'repeatable' => true,
    ),
    array(
        'label' => 'Image caption',
        'desc' => '',
        'id' => $prefix . 'image_caption',
        'type' => 'text',
        'repeatable' => true,
    )
);

// Callback unctions for setting up Brandbox Options
function dsslider_manager_meta_options(){

    global $custom_meta_fields, $post;
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE )
        // (integer) (optional) The post ID whose custom fields will be retrieved. 
        // Default: Current post
        return $post_id;

echo '<div class="dsslider_manager_extras">';

    // Markup for table head
    echo '<table class="meta ds-input-table">';
    echo '<tbody class="ui-sortable">';


    // Use nonce for verification
    echo '<input type="hidden" name="dsmeta_box_nonce" value="', wp_create_nonce(basename(__FILE__)), '" />';

    // Begin a table row
    echo '<tr class="row" id="repeatable-[0]">';
    echo '<td class="order">1</td>';

    foreach ($custom_meta_fields as $field) {
        // Get value of this field if it exists for this post
        $meta = get_post_meta($post->ID, $field['id'], true);
        $type = $field['type'];

        // Each $meta in an table data
        echo '<td>';

        // Check if value repeatable is set
        if ($field['repeatable']) {

            switch ($type) {
                // Image case
                case 'image':

                    $image = get_template_directory_uri() . '/assets/images/default.jpg'; // Default image for the preview
                    echo '<span class="default_image" style="display:none">' . $image . '</span>';

                    // If $meta == (equal to) true
                    if ($meta) {
                        $image = wp_get_attachment_image_src($meta, 'thumbnail');
                        $image = $image[0]; // Get the first key of the array - url
                    } // End if

                    echo '<input type="hidden" name="' . $field['id'] . '" class="upload_image" value="' . $meta . '" />'; // Save the image ID
                    echo '<img src="' . esc_attr( $image ) . '" alt="" class="preview_image" />'; // Preview uploaded image
                    echo '<input type="button" class="button add-image" value="Add image" rel="' . get_the_ID() . '" />'; // Add image
                    echo '<small><a href="#" class="remove-image">Remove image</a></small>'; // Delete image

                break;

                // Text case
                case 'text':
                    echo '<input type="text" name="' . $field['id'] . '[]' . '" id="' . $field['id'] . '" value="' . $meta . '" size="30" /> ';
                break;

            } // End switch statement

        } // End if

        echo '</td>';

    } // End foreach loop

    echo '<td class="remove"><a class="repeatable-remove button" href="#">-</a></td>';
    echo '</tr>'; // End .row


    echo '</tbody>'; // End tbody
    echo '</table>'; // End tbody

    echo '<ul class="hl clearfix ds-repeater-footer"><li class="right">';
    echo '<a href="#" class="repeatable-add ds-button">Add New Slide</a>';
    echo '</li></ul>';

echo '</div>'; // End .dsslider_manager_extras
}

// Save the data
add_action('save_post', 'dsslider_manager_save_extras');
function dsslider_manager_save_extras($post_id) {

    global $custom_meta_fields;

    // Check autosave function
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
        return $post_id;
    } // End if statement

    // Check permissions
    if ('page' == 'post_type') {
        if (!current_user_can('edit_page', $post_id)) {
            return $post_id;
        }
        elseif (!current_user_can('edit_post', $post_id)) {
            return $post_id;
        }
    } // End if statement

    // Loop through fields and save the data  
    foreach ($custom_meta_fields as $field) {
        if (isset($_POST[$field['id']])) {
            $old = get_post_meta($post_id, $field['id'], true);
            $new = $_POST[$field['id']];

            if ($new && $new != $old) {
                update_post_meta($post_id, $field['id'], $new);
            }
            elseif ('' == $new && $old) {
                delete_post_meta($post_id, $field['id'], $old);
            }
        } // End if statement
    } // End foreach loop
}

Related posts

Leave a Reply

2 comments

  1. You are saving only one image and one image caption. Your loop in dsslider_manager_save_extras function loops throught global $custom_meta_fields defined in php file. Not through $_POST variable. Your loop should look something like this:

    foreach ( $_POST['fields'] as $field ) {
    ...
    }
    

    In HTML, the form should look like this

    <input type="hidden" name="fields[$field[ID]]" value=""/>
    

    You can read more on this topic here: https://stackoverflow.com/questions/2433727/submitting-a-multidimensional-array-via-post-with-php

  2. If your form looking something like this:

    <input type="text" name="fields[0]['image']" value="" />
    <input type="text" name="fields[0]['caption']" value="" />
    

    And repeated by incrementing the index:

    <input type="text" name="fields[1]['image']" value="" />
    <input type="text" name="fields[1]['caption']" value="" />
    

    Then what you’ll get later is something like this:

    $_POST['fields'] = array(
      0 => array(
        'image' => (value here)
        'caption' => (value here)
      ),
      1 => array(
        'image' => (value here)
        'caption' => (value here)
      )
    );
    

    Then in save_post you can check to see if:

    isset($_POST['fields']) && is_array($_POST['fields']) && !empty($_POST['fields'])
    

    Then you can loop through your $custom_meta_fields in a while loop:

    $index = 0;
    $slides = array();
    
    while(isset($_POST['fields'][$index])) {
      foreach($custom_meta_fields as $custom_meta_field) {
        // check if isset($_POST['fields'][$index][$custom_meta_fields['id']])
        // and anything else you want to validate
        // and then save field in $slides[$index][$custom_meta_fields['id']]
      }
      $index++;
    }
    

    Once you’ve validated all sides, you can store them in one option field:

    update_post_meta($post_id, $option_name, $slides);
    

    By the way, in terms of $_POST[‘fields’], you could setup your array like so:

    $custom_meta_fields = array(
        'slides' => array(
          array(
            'label' => 'Image',
            'desc' => '',
            'id' => $prefix . 'image',
            'type' => 'image',
            'repeatable' => true,
          ),
          array(
            'label' => 'Image caption',
            'desc' => '',
            'id' => $prefix . 'image_caption',
            'type' => 'text',
            'repeatable' => true,
          )
        )
    );
    

    Then you can still loop.