0

I figured how to add an input value as a meta key value to a new post from a frontend post form (thanks to @thedeadmedic), but I can't figure how to add two or more meta keys at once. Is this possible with the next code? These meta keys are named 'location2' and 'price', and the input fields are respectively 'postLocation2' and 'postPrice' ('$safe_price' after validation).

My code:

<?php
/*
 * Plugin Name: Submit From Front
 * Plugin URI: 
 * Description: This creates a form so that posts can be submitted from the front end.
 * Version: 0.1
 * Author: 
 * Author URI: 
 * Text Domain: submit-from-front
 */

class WPSE_Submit_From_Front {
    const NONCE_VALUE = 'front_end_new_post';
    const NONCE_FIELD = 'fenp_nonce';

    protected $pluginPath;
    protected $pluginUrl;
    protected $errors = array();
    protected $data = array();

    function __construct() {
        $this->pluginPath = plugin_dir_path( __file__ );
        $this->pluginUrl  = plugins_url( '', __file__ );
    }

    /**
     * Shortcodes should return data, NOT echo it.
     * 
     * @return string
     */
    function shortcode() {
        if ( ! current_user_can( 'publish_posts' ) )
            return sprintf( '<p>Please <a href="%s">login</a> to post adverts.</p>', esc_url( wp_login_url(  get_permalink() ) ) );
        elseif ( $this->handleForm() )
            return '<p class="success">Nice one, post created!</p>';
        else
            return $this->getForm();
    }

    /**
     * Process the form and return true if post successfully created.
     * 
     * @return bool
     */
    function handleForm() {
        if ( ! $this->isFormSubmitted() )
            return false;

        // http://php.net/manual/en/function.filter-input-array.php
        $data = filter_input_array( INPUT_POST, array(
            'postTitle'   => FILTER_DEFAULT,
            'postContent' => FILTER_DEFAULT,
            'postCategory' => FILTER_DEFAULT,
            'postLocation' => FILTER_DEFAULT,
            'postLocation2' => FILTER_DEFAULT,
            'postPrice' => FILTER_DEFAULT,
        ));

        $data = wp_unslash( $data );
        $data = array_map( 'trim', $data );

        // You might also want to more aggressively sanitize these fields
        // By default WordPress will handle it pretty well, based on the current user's "unfiltered_html" capability

        $data['postTitle']   = sanitize_text_field( $data['postTitle'] );
        $data['postContent'] = wp_check_invalid_utf8( $data['postContent'] );
        $data['postCategory'] = sanitize_text_field( $data['postCategory'] );
        $data['postLocation'] = sanitize_text_field( $data['postLocation'] );
        $data['postLocation2'] = sanitize_text_field( $data['postLocation2'] );
        $data['postPrice'] = sanitize_text_field( $data['postPrice'] );

        // Validate the Price field input
        $safe_price = intval( $data['postPrice'] );
        if ( ! $safe_price ) {
            $safe_price = '';
        }

        if ( strlen( $safe_price ) > 10 ) {
            $safe_price = substr( $safe_price, 0, 10 );
        }

        $this->data = $data;

        if ( ! $this->isNonceValid() )
            $this->errors[] = 'Security check failed, please try again.';

        if ( ! $data['postTitle'] )
            $this->errors[] = 'Please enter a title.';

        if ( ! $data['postContent'] )
            $this->errors[] = 'Please enter the content.';

        if ( ! $data['postCategory'] )
            $this->errors[] = 'Please select a category.';

        if ( ! $data['postLocation'] )
            $this->errors[] = 'Please select a location.';

        if ( ! $this->errors ) {
            $post_id = wp_insert_post( array(
                'post_title'   => $data['postTitle'],
                'post_content' => $data['postContent'],
                'post_category' => array( $data['postCategory'] ),
                'tax_input' => array('loc' => array( $data['postLocation'] )),
                'post_status'  => 'publish',
            ));

            // This will add a meta key 'location2' to the post
            // How to add a second (the $safe_price value) meta key named 'price'?
            $post_id = add_post_meta($post_id, 'location2', $data['postLocation2']);

            if ( ! $post_id )
                $this->errors[] = 'Whoops, please try again.';
        } else {
            $post_id = 0;
        }

        return ( bool ) $post_id;
    }

    /**
     * Use output buffering to *return* the form HTML, not echo it.
     * 
     * @return string
     */
    function getForm() {
        ob_start();
        ?>

<div id ="frontpostform">
    <?php foreach ( $this->errors as $error ) : ?>

        <p class="error"><?php echo $error ?></p>

    <?php endforeach ?>

    <form id="formpost" method="post">
        <fieldset>
            <label for="postTitle">Post Title</label>
            <input type="text" name="postTitle" id="postTitle" value="<?php

                // "Sticky" field, will keep value from last POST if there were errors
                if ( isset( $this->data['postTitle'] ) )
                    echo esc_attr( $this->data['postTitle'] );

            ?>" />
        </fieldset>

        <fieldset>
            <label for="postContent">Content</label>
            <textarea name="postContent" id="postContent" rows="10" cols="35" ><?php

                if ( isset( $this->data['postContent'] ) )
                    echo esc_textarea( $this->data['postContent'] );

            ?></textarea>
        </fieldset>

        <!-- Category -->
        <fieldset>
            <label for="postCategory">Category</label>
            <select name="postCategory"> 
                <option value=""><?php echo esc_attr(__('Select Category')); ?></option>
                <?php
                $categories = get_categories( 'hide_empty=0' );
                foreach ($categories as $category) {
                    // keep post category value from last POST if there were errors
                    if ( isset( $this->data['postCategory'] ) && $this->data['postCategory'] == $category->cat_ID ) {
                       $option = '<option value="' . $category->cat_ID . '" selected="selected">';
                    } else {
                       $option = '<option value="' . $category->cat_ID . '">';
                    }
                    $option .= $category->cat_name;
                    $option .= ' ('.$category->category_count.')';
                    $option .= '</option>';
                    echo $option;
                }
                ?>
            </select>
        </fieldset>

        <!-- Location -->
        <fieldset>
            <label for="postLocation">Location</label>
            <select name="postLocation"> 
                <option value=""><?php echo esc_attr(__('Select Location')); ?></option>
                <?php
                $categories = get_terms( 'loc', 'hide_empty=0' );
                foreach ($categories as $category) {
                    if ( isset( $this->data['postLocation'] ) && $this->data['postLocation'] == $category->term_id ) {
                       $option = '<option value="' . $category->term_id . '" selected="selected">';
                    } else {
                       $option = '<option value="' . $category->term_id . '">';
                    }
                    $option .= $category->name;
                    $option .= ' ('.$category->count.')';
                    $option .= '</option>';
                    echo $option;
                }
                ?>
            </select>
        </fieldset>

        <!-- Second Location -->
        <fieldset>
            <label for="postLocation2">Location 2</label>
            <input type="text" name="postLocation2" id="postLocation2" value="<?php

                // "Sticky" field, will keep value from last POST if there were errors
                if ( isset( $this->data['postLocation2'] ) )
                    echo esc_attr( $this->data['postLocation2'] );

            ?>" />
        </fieldset>

        <!-- Price -->
        <fieldset>
            <label for="postPrice">Price</label>
            <input type="text" name="postPrice" id="postPrice" maxlength="10" value="<?php

                // "Sticky" field, will keep value from last POST if there were errors
                if ( isset( $this->data['postPrice'] ) )
                    echo esc_attr( $this->data['postPrice'] );

            ?>" />
        </fieldset>

        <fieldset>
            <button type="submit" name="submitForm" >Create Post</button>
        </fieldset>

        <?php wp_nonce_field( self::NONCE_VALUE , self::NONCE_FIELD ) ?>
    </form>
</div>

        <?php
        return ob_get_clean();
    }

    /**
     * Has the form been submitted?
     * 
     * @return bool
     */
    function isFormSubmitted() {
        return isset( $_POST['submitForm'] );
    }

    /**
     * Is the nonce field valid?
     * 
     * @return bool
     */
    function isNonceValid() {
        return isset( $_POST[ self::NONCE_FIELD ] ) && wp_verify_nonce( $_POST[ self::NONCE_FIELD ], self::NONCE_VALUE );
    }
}

new WPSE_Submit_From_Front;
  • 1
    add another call to add_post_meta with your key and value. I'm not sure I understand what the problem is. – Milo Dec 4 '15 at 21:55
  • 1
    you shouldn't be assigning the result of add_post_meta to $post_id, that function returns the ID of the meta item, not a post ID. – Milo Dec 4 '15 at 23:05
1

As @milo was saying above each value that you wish to save as post meta will need it's own call to update_post_meta. And each usage of update_post_meta will need you to specific a unique name for that meta value.

Since you have all the data in an array and you have already sanitized it you could do something like this:

foreach( $data as $key => $value ) {
  update_post_meta( $post_id, $key, $value );
}

that will loop through the array and save each value and set is meta key/name to the array key you set previously in your code.

So this should work for you, but I would say that it might be worth looking at your code more to ensure all data is present before looping through the data array.

0

As @milo commented above, each value that I wish to save as post meta will need it's own call to update_post_meta. And because the $post_id variable will return the ID of the new post, it was sufficient instead of:

$post_id = add_post_meta($post_id, 'location2', $data['postLocation2']);

to insert, for each needed value:

add_post_meta($post_id, 'location2', $data['postLocation2']);

and then:

add_post_meta($post_id, 'price', $safe_price);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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