Edición de entradas desde el frontend usando un formulario
Tengo un tipo de contenido personalizado con las metaboxes estándar y algunos campos personalizados. ¿Cómo podría editar una entrada a través de un formulario en el frontend?

Aquí hay soluciones básicas para actualizar una entrada/página. He incluido una demostración rápida de campos meta personalizados. Es bastante básico, pero te orientará sobre cómo editar entradas en el front-end sin necesidad de plugins. No es súper flexible, pero puedes agregar lo que necesites.
Añade este código en tu 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">Título</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">Prueba</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">Prueba 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="Actualizar" />
</form>
Luego añade este código al inicio de la página para procesar el formulario:
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("No tienes permiso para hacer esto");
}
}

Agregué esc_sql(). Se me ocurrió que deberías escapar los datos enviados desde un formulario público (semi-público) como ese.

Utilizo Advanced Custom Fields para mucha edición de publicaciones en el front-end con meta cajas. ACF te permite construir muchos campos avanzados de meta cajas y los añade automáticamente al panel de publicaciones en el back-end.
Pero también hay una función para el front-end.
Este método es completamente gratuito. La única forma en que tiene algún costo es si deseas utilizar cualquiera de sus complementos de tipos de campos más complejos, como repetidor, flexible o galería. Todos funcionan muy bien aquí.
El primer inconveniente es que no incluye el título y la descripción de la publicación... pero eso se puede solucionar bastante fácilmente añadiendo esto a tu functions.php:
/**
* Desregistrar estilos de admin en el front-end al usar formularios ACF
*
* ACF se asegura de que los estilos de admin se carguen cuando carga su head, esto casi siempre causa problemas con formularios en el front-end y no es necesario para nuestro propósito
*/
add_action( 'wp_print_styles', 'custom_acf_deregister_styles', 100 );
function custom_acf_deregister_styles()
{
if (! is_admin() )
{
wp_deregister_style( 'wp-admin' );
}
}
/**
* Guardar campo ACF como post_content / post_title para publicaciones en el front-end
*/
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 ) ) // No ejecutar si se añaden/actualizan campos/grupos de campos en 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' );
}
}
}
/**
* Cargar post_title existente
*/
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;
}
/**
* Cargar post_content existente
*/
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;
}
/**
* Instalar Complementos (Esto añade dos grupos de campos que puedes usar para editar título y contenido)
*
* El siguiente código incluirá los 4 complementos premium en tu tema.
* Por favor, no intentes incluir un archivo que no exista. Esto producirá un error.
*
* Todos los campos deben incluirse durante la acción 'acf/register_fields'.
* Otros tipos de complementos (como la página de opciones) pueden incluirse fuera de esta acción.
*
* El siguiente código asume que tienes una carpeta 'add-ons' dentro de tu tema.
*
* IMPORTANTE
* Los complementos pueden incluirse en un tema premium según los términos y condiciones.
* Sin embargo, NO deben incluirse en un plugin premium/gratuito.
* Para más información, por favor lee http://www.advancedcustomfields.com/terms-conditions/
*/
// Campos
add_action('acf/register_fields', 'my_register_fields');
/**
* Registrar Grupos de Campos
*
* La función register_field_group acepta 1 array que contiene los datos relevantes para registrar un grupo de campos
* Puedes editar el array como consideres. Sin embargo, esto puede resultar en errores si el array no es compatible con ACF
*/
if(function_exists("register_field_group"))
{
register_field_group(array (
'id' => 'acf_form-post-title',
'title' => 'Formulario Título de Publicación',
'fields' => array (
array (
'key' => 'field_25',
'label' => 'Título',
'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' => 'Formulario Contenido de Publicación',
'fields' => array (
array (
'key' => 'field_13',
'label' => 'Contenido',
'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,
));
}
Eso añadirá todo el código para soportar un campo de título y contenido que puede añadirse a los formularios de front-end así:
// Añade esto arriba de get_header()
// Esto carga estilos/scripts, pero también procesa el formulario, así que es bastante importante
acf_form_head();
get_header();
// Donde 51 es el id del grupo de campos ACF de las meta cajas que quiero añadir
acf_form( array(
'field_groups' => array('acf_form-post-title', 'acf_form-post-content', 51)
) );
Utilizo este método en la mayoría de los sitios en los que trabajo actualmente. Tiendo a usar Gravity Forms para crear una publicación básica y luego controlo todo con ACF en el front-end y back-end. Lo mejor es que lo gestionas todo desde un solo lugar para ambos. Vale la pena mencionar, sin embargo, que ACF puede usarse para crear una publicación también. No lo he usado, pero lo probaré en mi próximo proyecto, para poder crear con acceso completo a los metadatos.
Personalmente, ACF es el único plugin sin el que no puedo vivir, con Gravity Forms como un cercano segundo.

Gracias por el TIP, pero estaba buscando una solución sin ningún plugin

Se puede hacer. Es solo un tema realmente complicado. Tengo algo llamado "Catapost" que te permite añadir metaboxes a las entradas y luego crear formularios en el frontend para editar el título/contenido de la entrada con los metaboxes. Es COMO un plugin, pero está incluido en el tema, por lo que puede distribuirse con los temas. ¿Es ese el tipo de solución que buscas?

Bueno. Una solución flexible es compleja... Si solo quieres editar una entrada básica... Eso podría no ser tan malo.

Agregué una solución muy básica en otra respuesta que muestra cómo hacerlo sin plugins. No es muy flexible, pero funciona bien para un uso puntual.

Si deseas editar una publicación existente, prueba mi plugin Editor Front-end.
Si quieres crear nuevas publicaciones, prueba uno de estos:

Gracias Scribu. Tu plugin es fantástico, pero no se ajusta a mis necesidades. Estoy intentando editar una publicación existente con un formulario. Hice una pregunta similar sobre editar el perfil de un usuario con un formulario en el frontend y recibí esta respuesta: http://wordpress.stackexchange.com/questions/9775/how-to-edit-a-user-profile-on-the-front-end Esto funcionó perfectamente para mí. Si existe una solución similar para editar publicaciones estaría muy agradecido.

@nickfancis.me usa los comentarios para este tipo de cosas - ¡para eso están!

La forma más fácil sería usar algo como Ninja Forms con la siguiente extensión de pago:
http://wpninjas.com/downloads/front-end-posting/
También podrías codificarlo tú mismo. Básicamente crearás un formulario y luego usarás wp_insert_post()
para crear una publicación completa.
Un formulario de ejemplo:
<form action="" id="primaryPostForm" method="POST">
<fieldset>
<label for="postTitle"><?php _e('Título de la publicación:', 'framework') ?></label>
<input type="text" name="postTitle" id="postTitle" class="required" />
</fieldset>
<fieldset>
<label for="postContent"><?php _e('Contenido de la publicación:', 'framework') ?></label>
<textarea name="postContent" id="postContent" rows="8" cols="30" class="required"></textarea>
</fieldset>
<fieldset>
<input type="hidden" name="submitted" id="submitted" value="true" />
<button type="submit"><?php _e('Añadir publicación', 'framework') ?></button>
</fieldset>
Y luego al enviar, lo procesarías algo así:
if ( isset( $_POST['submitted'] ) && isset( $_POST['post_nonce_field'] ) && wp_verify_nonce( $_POST['post_nonce_field'], 'post_nonce' ) ) {
if ( trim( $_POST['postTitle'] ) === '' ) {
$postTitleError = 'Por favor ingresa un título.';
$hasError = true;
}
$post_information = array(
'post_title' => wp_strip_all_tags( $_POST['postTitle'] ),
'post_content' => $_POST['postContent'],
'post_type' => 'post',
'post_status' => 'pending'
);
wp_insert_post( $post_information );
}
El código completo y el tutorial están en: http://wp.tutsplus.com/tutorials/creative-coding/posting-via-the-front-end-inserting/
