Skip to content

Instantly share code, notes, and snippets.

@notomato
Created October 7, 2015 15:45
Show Gist options
  • Save notomato/6f719276a0ec137f8e19 to your computer and use it in GitHub Desktop.
Save notomato/6f719276a0ec137f8e19 to your computer and use it in GitHub Desktop.
CMB2 front end forms - shortcode takes id of any metabox registered and outputs the appropriate frontend form.
<?php
// @todo post editing
/**
* Gets the cmb instance
*
* @param string $metabox_id The id of the metabox as it is registered with `new_cmb2_box` e.g. `architect`
* @return CMB2 object
*/
function th_get_frontend_form($metabox_id) {
$object_id = 'fake-oject-id';
return cmb2_get_metabox($metabox_id, $object_id);
}
/**
* This function will output a front-end CMB2 form on any page. The shortcode should be entered as below:
*
* [frontend-form id="architect"]
*
* where `id` is the id of the metabox is it is registered with the `new_cmb2_box` function.
*
* @param array $atts Array of shortcode attributes
* @return string Form html
*/
function th_frontend_form_shortcode( $atts = array() ) {
// Check we have the id attribute and it's a valid
if (!$atts['id'] && $cmb = th_get_frontend_form($atts['id'])) {
return false;
}
// Get CMB2 metabox object
$cmb = th_get_frontend_form($atts['id']);
// Get $cmb object_types
$post_types = $cmb->prop( 'object_types' );
// Current user
$user_id = get_current_user_id();
// Parse attributes
$atts = shortcode_atts( array(
'post_author' => $user_id ? $user_id : 1, // Current user, or admin
'post_status' => 'pending',
'metabox_id' => $atts['id'],
'post_type' => reset( $post_types ), // Only use first object_type in array
), $atts, 'frontend-form' );
/*
* Let's add these attributes as hidden fields to our cmb form
* so that they will be passed through to our form submission
*/
foreach ( $atts as $key => $value ) {
$cmb->add_hidden_field( array(
'field_args' => array(
'id' => "atts[$key]",
'type' => 'hidden',
'default' => $value,
),
) );
}
// Initiate our output variable
$output = '';
// Get any submission errors
if ( ( $error = $cmb->prop( 'submission_error' ) ) && is_wp_error( $error ) ) {
// If there was an error with the submission, add it to our ouput.
$output .= '<h3>' . sprintf( __( 'There was an error in the submission: %s', 'wds-post-submit' ), '<strong>'. $error->get_error_message() .'</strong>' ) . '</h3>';
}
// If the post was submitted successfully, notify the user.
if ( isset( $_GET['post_submitted'] ) && ( $post = get_post( absint( $_GET['post_submitted'] ) ) ) ) {
// Get submitter's name
$name = get_post_meta( $post->ID, 'submitted_author_name', 1 );
$name = $name ? ' '. $name : '';
// Add notice of submission to our output
$output .= '<h3>' . sprintf( __( 'Thank you%s, your new post has been submitted and is pending review by a site administrator.', 'wds-post-submit' ), esc_html( $name ) ) . '</h3>';
}
// Get our form
$output .= cmb2_get_metabox_form( $cmb, 'fake-oject-id', array( 'save_button' => __( 'Submit', 'wds-post-submit' ) ) );
return $output;
}
add_shortcode('frontend-form', 'th_frontend_form_shortcode');
/**
* Handles form submission on save. Redirects if save is successful, otherwise sets an error message as a cmb property
*
* @return void
*/
function th_handle_frontend_submission() {
// var_dump($_POST); die;
// If no form submission, bail
if ( empty( $_POST ) || ! isset( $_POST['submit-cmb'], $_POST['object_id'] ) ) {
return false;
}
// Get CMB2 metabox object
$cmb = th_get_frontend_form($_POST['atts']['metabox_id']);
$post_data = array();
// Get our shortcode attributes and set them as our initial post_data args
if ( isset( $_POST['atts'] ) ) {
foreach ( (array) $_POST['atts'] as $key => $value ) {
$post_data[ $key ] = sanitize_text_field( $value );
}
unset( $_POST['atts'] );
}
// Check security nonce
if ( ! isset( $_POST[ $cmb->nonce() ] ) || ! wp_verify_nonce( $_POST[ $cmb->nonce() ], $cmb->nonce() ) ) {
return $cmb->prop( 'submission_error', new WP_Error( 'security_fail', __( 'Security check failed.' ) ) );
}
// Check title submitted
if ( empty( $_POST['title'] ) ) {
return $cmb->prop( 'submission_error', new WP_Error( 'post_data_missing', __( 'New post requires a title.' ) ) );
}
// And that the title is not the default title
if ( $cmb->get_field( 'title' )->default() == $_POST['title'] ) {
return $cmb->prop( 'submission_error', new WP_Error( 'post_data_missing', __( 'Please enter a new title.' ) ) );
}
/**
* Fetch sanitized values
*/
$sanitized_values = $cmb->get_sanitized_values( $_POST );
// Set our post data arguments
$post_data['post_title'] = $sanitized_values['title'];
unset( $sanitized_values['title'] );
$post_data['post_content'] = $sanitized_values['submitted_post_content'];
unset( $sanitized_values['submitted_post_content'] );
// Create the new post
$new_submission_id = wp_insert_post( $post_data, true );
// If we hit a snag, update the user
if ( is_wp_error( $new_submission_id ) ) {
return $cmb->prop( 'submission_error', $new_submission_id );
}
/**
* Other than post_type and post_status, we want
* our uploaded attachment post to have the same post-data
*/
unset( $post_data['post_type'] );
unset( $post_data['post_status'] );
// Try to upload the featured image
$img_id = th_frontend_form_photo_upload( $new_submission_id, $post_data );
// If our photo upload was successful, set the featured image
if ( $img_id && ! is_wp_error( $img_id ) ) {
set_post_thumbnail( $new_submission_id, $img_id );
}
// Loop through remaining (sanitized) data, and save to post-meta
foreach ( $sanitized_values as $key => $value ) {
if ( is_array( $value ) ) {
$value = array_filter( $value );
if( ! empty( $value ) ) {
update_post_meta( $new_submission_id, $key, $value );
}
} else {
update_post_meta( $new_submission_id, $key, $value );
}
}
/*
* Redirect back to the form page with a query variable with the new post ID.
* This will help double-submissions with browser refreshes
*/
wp_redirect( esc_url_raw( add_query_arg( 'post_submitted', $new_submission_id ) ) );
exit;
}
add_action( 'cmb2_after_init', 'th_handle_frontend_submission' );
/**
* Handles uploading a file to a WordPress post
*
* @param int $post_id Post ID to upload the photo to
* @param array $attachment_post_data Attachement post-data array
*/
function th_frontend_form_photo_upload( $post_id, $attachment_post_data = array() ) {
// Make sure the right files were submitted
if (
empty( $_FILES )
|| ! isset( $_FILES['submitted_post_thumbnail'] )
|| isset( $_FILES['submitted_post_thumbnail']['error'] ) && 0 !== $_FILES['submitted_post_thumbnail']['error']
) {
return;
}
// Filter out empty array values
$files = array_filter( $_FILES['submitted_post_thumbnail'] );
// Make sure files were submitted at all
if ( empty( $files ) ) {
return;
}
// Make sure to include the WordPress media uploader API if it's not (front-end)
if ( ! function_exists( 'media_handle_upload' ) ) {
require_once( ABSPATH . 'wp-admin/includes/image.php' );
require_once( ABSPATH . 'wp-admin/includes/file.php' );
require_once( ABSPATH . 'wp-admin/includes/media.php' );
}
// Upload the file and send back the attachment post ID
return media_handle_upload( 'submitted_post_thumbnail', $post_id, $attachment_post_data );
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment