3

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:

  • 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
}
6
  • Please, embed all relevant code in the Question itself. If those snippi's go off-line, the Q loses its meaning.
    – brasofilo
    Commented Feb 10, 2013 at 16:28
  • @brasofilo I have update it, give it some nice markup. Hope it's better now up to you!
    – Casper
    Commented Feb 10, 2013 at 21:14
  • +1 well written Q, kudos! That's not my code, just a fork with minor mods.
    – brasofilo
    Commented Feb 10, 2013 at 21:21
  • @brasofilo Thank you for your comment. Hope someone can help me out!
    – Casper
    Commented Feb 10, 2013 at 21:39
  • There's already an Answer, did you tried it? And if there are doubts, comment on it, I'm positive you'll get feedback.
    – brasofilo
    Commented Feb 10, 2013 at 21:41

2 Answers 2

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

1
  • Ok, I have tried several ways with the example above from @david.binda Because I haven't an key=>value pair of fields, I am stuck with the above answer code, as my code shown above, I make use of a multidimensional array and my metabox is separate from it.
    – Casper
    Commented Feb 10, 2013 at 22:12
1

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.

11
  • Thank you very much for your expanded answer it is now for me a lot clearer. One question left for you now, in your array $custom_meta_fields you set the key 'slides'. Why is this so important and I think I should replace 'fields' in your example to 'slides' right? Look out to your answer, I will try your code today!
    – Casper
    Commented Feb 11, 2013 at 9:14
  • I came up to one more question while I try to implement your example code in mine code. The line update_post_meta($post_id, $option_name, $slides); you set a var of $option_name what should that variable does?
    – Casper
    Commented Feb 11, 2013 at 10:10
  • I have also take a better look to my own code that I have post in my Question. When I check my database I see that my caption is saved as an array with multiple values that I've insert in the text input fields, but doesn't show after save the post/page in WordPress, only the word "Array" will filled in then. Maybe you have something on this information..
    – Casper
    Commented Feb 11, 2013 at 12:05
  • For now I came up with the following code, after follow your example: snippi.com/s/jlzd2ju But this will give me a notice error: Notice: Undefined variable: index in cpt-manager.php on line 187
    – Casper
    Commented Feb 11, 2013 at 13:40
  • Yes, you should replace fields with something more descriptive, such as slides, but I'd make it more unique in case someone or something else ever uses slides. $option_name would be any string, also as unique as possible, that you'd use to save/retrieve the contents of your array from the database. get_post_meta returns an array of custom fields (in case you have more than one) and unless you specify true as the third argument e.g. $slides = get_post_meta($post_id, $option_name, true), you'll have to supply the index e.g. $slides[0].
    – NightHawk
    Commented Feb 11, 2013 at 14:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.