I’ve used WPAlchemy for a while now and I must say, it’s one of my favorite tools for WordPress development. If you’ve not used it, check it out. It makes creating custom meta boxes much easier and allows you to create all kinds of magic such as repeatable fields, multiple editors and image uploaders. Really good stuff.

One thing I really struggled with recently was doing a front end post and updating WPAlchemy’s meta values in the database. I wanted to have a form on the front end of a website that allowed a user to create a post in WordPress, automatically save it as a draft and update custom meta boxes such as the name, address and rating provided by the reviewer.

Let’s say I was using normal custom fields, I would simply create the custom field then use the following code on successful form submission to create the post and update the custom fields:

$new_post = array(
    'post_title' => $title,
    'post_content' => $review,
    'post_status' => 'draft',  // publish, preview, future, draft, etc.
    'post_type' => 'reviews'  //post, page or custom post type
);

//Save the post
$pid = wp_insert_post($new_post);

//Add the custom fields
add_post_meta($pid, 'custom_field_key', $value);

Pretty straight forward. Unfortunately, when you create a custom meta box with WPAlchemy it stores all the values associated with it in a single, serialised array which makes it more difficult to update these values directly or run queries based on the values. This is how the values associated to my meta key ‘_reviews_meta_fields’ looked in the postmeta table in WordPress:

a:5:{i:0;s:19:"reviews_what_we_did";i:1;s:19:"reviews_star_rating";i:2;s:12:"reviews_name";i:3;s:13:"reviews_email";i:4;s:20:"reviews_staff_member";}

We can see that trying to update the ‘reviews_what_we_did’ value directly wont work. Luckily WPAlchemy provides a way to make this easier. By specifying ‘WPALCHEMY_MODE_EXTRACT’ when you setup your meta box, the values of the serialised array are extracted and stored as individual keys. Great, so all we need to do now is call ‘add_post_meta’ on those individual keys and it will work nicely. Not quite.

Whilst I found that the values did in fact update properly when I used ‘add_post_meta’ on those individual keys, when I went to the post in the admin area, the fields that should have shown the newly stored values were empty. I could see in the database that the values were correct and that they were applied to the correct post so I did not understand when the fields were empty in the admin area. To make matters more confusing, when I updated the post from WordPress, it worked fine and updated the same values that I had already created via ‘add_post_meta’ from the front end.

It turns out that, even when ‘WPALCHEMY_MODE_EXTRACT’ is specified, the serialised array is still created and it is still very important. When you insert the values via ‘add_post_meta’ you first need to create a serialised array that stores a reference to those individual fields. That is how WordPress determines which values to show in the admin screen. This is best explained with an example:

First we set up our metabox and specify ‘mode’ => WPALCHEMY_MODE_EXTRACT’.

$reviews_metabox = new WPAlchemy_MetaBox(array
(
    'id' => '_reviews_meta',
    'title' => __('Reviews'),
    'context' => 'normal',
    'priority' => 'low',
    'view' => WPALCHEMY_VIEW_START_OPENED,
    'mode' => WPALCHEMY_MODE_EXTRACT,
    'types' => array('reviews'),
    'template' => get_stylesheet_directory() . '/framework/metaboxes/reviews-meta.php',
));

This code will allow us to now update individual fields instead of a single array. This meta box will be applied to a custom post type called ‘reviews’ and the meta boxes themselves will be setup in a template called ‘reviews-meta.php’. If you are unfamiliar with this, then WPAlchemy has plenty of documentation to explain the basics.

My fields within my review-mata.php template specified a number of fields that I wanted to be able to use for reviews. These fields were: what we did, rating, reviewers name, reviewers email and staff member. The default fields provided by WordPress were used for the title and description of the review.

With the fields setup, I created a template with a form on. When the form was submitted I did some basic validation and then created the post, updating the custom fields above at the same time as seen here:

//validation here

if (count($errors) < 1){
        $new_post = array(
        'post_title' => $title,
        'post_content' => $review,
        'post_status' => 'draft',
        'post_type' => 'reviews'
        );

        //SAVE THE POST
        $pid = wp_insert_post($new_post);
        do_action('wp_insert_post', 'wp_insert_post');
        
        //update the individual fields
        add_post_meta($pid, 'reviews_what_we_did', $service);
        add_post_meta($pid, 'reviews_star_rating', $rating);
        add_post_meta($pid, 'reviews_name', $name);
        add_post_meta($pid, 'reviews_email', $email);
        add_post_meta($pid, 'reviews_staff_member', $staff);
        
        //REDIRECT TO THE NEW POST ON SAVE
        $link = get_permalink( $post->ID ) . '?status=success';
        wp_redirect( $link );
    }

After doing a test using the code above I was surprised to see that it did not work. The reason it did not work is that this code does not create the serialised array that is required before the individual fields are saved. Here is the modified working code:

//validation here

if (count($errors) < 1){
        $new_post = array(
        'post_title' => $title,
        'post_content' => $review,
        'post_status' => 'draft',
        'post_type' => 'reviews'
        );

        //SAVE THE POST
        $pid = wp_insert_post($new_post);
        do_action('wp_insert_post', 'wp_insert_post');
        
        //add a serialised array for wpalchemy to work
        $data = array('reviews_what_we_did','reviews_star_rating','reviews_name','reviews_email','reviews_staff_member');
        $str = $data;
        update_post_meta( $pid, '_single_reviews_meta_fields', $str );

        //update the individual fields
        add_post_meta($pid, 'reviews_what_we_did', $service);
        add_post_meta($pid, 'reviews_star_rating', $rating);
        add_post_meta($pid, 'reviews_name', $name);
        add_post_meta($pid, 'reviews_email', $email);
        add_post_meta($pid, 'reviews_staff_member', $staff);
        
        //REDIRECT TO THE NEW POST ON SAVE
        $link = get_permalink( $post->ID ) . '?status=success';
        wp_redirect( $link );
    }

So, this is the bit that was added get WPAlchemy updating posts from the front end properly:

//add a serialised array for wpalchemy to work
$data = array('reviews_what_we_did','reviews_star_rating','reviews_name','reviews_email','reviews_staff_member');
$str = $data;
update_post_meta( $pid, '_single_reviews_meta_fields', $str );

Hopefully this will help you if you have been trying to use WPAlchemy to update WordPress using a form on the front end of your site. If you have any comments then please let me know.