Wordpress - Front end post editing using a form

Here is a basic solutions for updating a post/page. I added a quick demo of custom meta fields. This is pretty basic, but will point you in the direction of plugin-less editing of posts on the front-end. This isn't super flexible, but you can add whatever you need to it.

Add this code into your loop:

<form id="post" class="post-edit front-end-form" method="post" enctype="multipart/form-data">

    <input type="hidden" name="post_id" value="<?php the_ID(); ?>" />
    <?php wp_nonce_field( 'update_post_'. get_the_ID(), 'update_post_nonce' ); ?>

    <p><label for="post_title">Title</label>
    <input type="text" id="post_title" name="post_title" value="<?php echo $post->post_title; ?>" /></p>

    <p><?php wp_editor( $post->post_content, 'postcontent' ); ?></p>

    <p><label for="post_title">Test</label>
    <?php $value = get_post_meta(get_the_ID(), 'edit_test', true); ?>
    <input type="text" id="edit_test" name="edit_test" value="<?php echo $value; ?>" /></p>

    <p><label for="post_title">Test 2</label>
    <?php $value = get_post_meta(get_the_ID(), 'edit_test2', true); ?>
    <input type="text" id="edit_test2" name="edit_test2" value="<?php echo $value; ?>" /></p>

    <input type="submit" id="submit" value="Update" />

</form>

Then add this code at the top of the page to process the form:

if ( 'POST' == $_SERVER['REQUEST_METHOD'] && ! empty($_POST['post_id']) && ! empty($_POST['post_title']) && isset($_POST['update_post_nonce']) && isset($_POST['postcontent']) )
{
    $post_id   = $_POST['post_id'];
    $post_type = get_post_type($post_id);
    $capability = ( 'page' == $post_type ) ? 'edit_page' : 'edit_post';
    if ( current_user_can($capability, $post_id) && wp_verify_nonce( $_POST['update_post_nonce'], 'update_post_'. $post_id ) )
    {
        $post = array(
            'ID'             => esc_sql($post_id),
            'post_content'   => esc_sql($_POST['postcontent']),
            'post_title'     => esc_sql($_POST['post_title'])
        );
        wp_update_post($post);

        if ( isset($_POST['edit_test']) ) update_post_meta($post_id, 'edit_test', esc_sql($_POST['edit_test']) );
        if ( isset($_POST['edit_test2']) ) update_post_meta($post_id, 'edit_test2', esc_sql($_POST['edit_test2']) );
    }
    else
    {
        wp_die("You can't do that");
    }
}

I use Advanced Custom Fields for lots of front end post editing with meta boxes. ACF allows you to build lots of advanced meta box fields and adds them automatically to the back end post panel.

But there is a front end function as well.

This method is completely free. The only way it costs anything is if you want to use any of their more complex field type add-ons like repeater, flexible, or gallery. Which all work great here.

The first drawback is that it doesn't include the post title and description... but that can be fixed pretty easily by adding this to your functions.php:

/**
 * Deregister admin styles on the front end when using ACF forms
 *
 * ACF makes sure that admin styles are queued when it loads its head, this almost always causes problems with front end forms and isn't needed for our purpose
 */
add_action( 'wp_print_styles', 'custom_acf_deregister_styles', 100 );
function custom_acf_deregister_styles()
{
    if (! is_admin() )
    {
        wp_deregister_style( 'wp-admin' );
    }
}

/**
 * Save ACF field as post_content / post_title for front-end posting
 */
add_action( 'acf/save_post', 'custom_acf_save_post' );
function custom_acf_save_post( $post_id )
{
    if (! is_admin() && 'acf' != get_post_type( $post_id ) ) // Don't run if adding/updated fields/field-groups in wp-admin
    {
        $post_title   = get_post_meta( $post_id, 'form_post_title', true );
        $post_content = get_post_meta( $post_id, 'form_post_content', true );
        $post         = get_post($post_id);
        if ( ($post_title && $post_title != $post->post_title) || ($post_content && $post_content != $post->post_content) )
        {
            $post_data = array(
                'ID' => $post_id,
            );
            if ( $post_content ) $post_data['post_content'] = $post_content;
            if ( $post_title )   $post_data['post_title']   = $post_title;

            remove_action( 'acf/save_post', 'custom_acf_save_post' );
            wp_update_post( $post_data );
            add_action( 'acf/save_post', 'custom_acf_save_post' );
        }
    }
}

/**
 * Load existing post_title
 */
add_filter( 'acf/load_value/name=form_post_title', 'custom_acf_load_value_form_post_title', 10, 3 );
function custom_acf_load_value_form_post_title( $value, $post_id, $field )
{
    $value   = get_the_title($post_id);
    return $value;
}

/**
 * Load existing post_content
 */
add_filter( 'acf/load_value/name=form_post_content', 'custom_acf_load_value_form_post_content', 10, 3 );
function custom_acf_load_value_form_post_content( $value, $post_id, $field )
{
    $post    = get_post($post_id);
    $value   = $post->post_content;
    return $value;
}

/**
 *  Install Add-ons (This adds two field groups that you can use to edit title and content)
 *  
 *  The following code will include all 4 premium Add-Ons in your theme.
 *  Please do not attempt to include a file which does not exist. This will produce an error.
 *  
 *  All fields must be included during the 'acf/register_fields' action.
 *  Other types of Add-ons (like the options page) can be included outside of this action.
 *  
 *  The following code assumes you have a folder 'add-ons' inside your theme.
 *
 *  IMPORTANT
 *  Add-ons may be included in a premium theme as outlined in the terms and conditions.
 *  However, they are NOT to be included in a premium / free plugin.
 *  For more information, please read http://www.advancedcustomfields.com/terms-conditions/
 */ 

// Fields 
add_action('acf/register_fields', 'my_register_fields');

/**
 *  Register Field Groups
 *
 *  The register_field_group function accepts 1 array which holds the relevant data to register a field group
 *  You may edit the array as you see fit. However, this may result in errors if the array is not compatible with ACF
 */

if(function_exists("register_field_group"))
{
    register_field_group(array (
        'id' => 'acf_form-post-title',
        'title' => 'Form Post Title',
        'fields' => array (
            array (
                'key' => 'field_25',
                'label' => 'Title',
                'name' => 'form_post_title',
                'type' => 'text',
                'default_value' => '',
                'formatting' => 'html',
            ),
        ),
        'location' => array (
            array (
                array (
                    'param' => 'post_type',
                    'operator' => '==',
                    'value' => 'course',
                    'order_no' => 0,
                    'group_no' => 0,
                ),
            ),
        ),
        'options' => array (
            'position' => 'normal',
            'layout' => 'no_box',
            'hide_on_screen' => array (
            ),
        ),
        'menu_order' => -2,
    ));
    register_field_group(array (
        'id' => 'acf_form-post-content',
        'title' => 'Form Post Content',
        'fields' => array (
            array (
                'key' => 'field_13',
                'label' => 'Content',
                'name' => 'form_post_content',
                'type' => 'wysiwyg',
                'default_value' => '',
                'toolbar' => 'full',
                'media_upload' => 'yes',
            ),
        ),
        'location' => array (
            array (
                array (
                    'param' => 'post_type',
                    'operator' => '==',
                    'value' => 'course',
                    'order_no' => 0,
                    'group_no' => 0,
                ),
            ),
        ),
        'options' => array (
            'position' => 'normal',
            'layout' => 'no_box',
            'hide_on_screen' => array (
            ),
        ),
        'menu_order' => -1,
    ));
}

That will add all the code to support a title and content field that can be added to the front end forms like this:

// Add this above get_header()
// This loads styles/scripts, but it also processes the form, so pretty important
acf_form_head();

get_header();

// Where 51 is the id of the ACF field group of meta box fields that I want to add
acf_form( array(
    'field_groups' => array('acf_form-post-title', 'acf_form-post-content', 51)
) );

I use this method on most of the sites I work on these days. I tend to use Gravity Forms to create a basic post and then I control everything with ACF on the front and back end. The best thing is that you manage it all from one place for both. It is worth noting, however, that ACF can be used to create a post as well. I haven't used it, but will be giving it a try on my next project, so that I can create with full meta access.

ACF is, personally, the only plugin I can't live without with Gravity Forms as a close second.


If you want to edit an existing post, try my Front-end Editor plugin.

If you want to create new posts, try one of these:

  • http://wordpress.org/extend/plugins/sidebar-post/
  • http://wordpress.org/extend/plugins/tdo-mini-forms/
  • http://www.deliciousdays.com/cforms-plugin/
  • http://wordpress.org/extend/plugins/posthaste