• Resolved Erin Bell

    (@ebellempire)


    Hi, I’m creating a simple plugin to handle all the CMS stuff (custom post types, taxonomies, metaboxes, etc) on a site redesign. For the sake of simplifying future maintenance, I’m keeping all the custom data configurations in a series of simple arrays. For example…

    function custom_metaboxes_array(){
    	return array(
    		array(
    			'name'=>'post_subtitle',
    			'label'=>'Subtitle',
    			'description'=>'A subtitle for the post',
    			'post_type'=>'post',
    			'type'=>'text',
    		),
    		array(
    			'name'=>'post_lede',
    			'label'=>'Lede',
    			'description'=>'A short paragraph of teaser text',
    			'post_type'=>'post',
    			'type'=>'text',
    		),
    		// etc...
    	);
    }

    Most everything is displaying and working fine, but I’m unable to save the custom meta boxes. Here’s the code I’m working with, based on the WP documentation

    <?php
    // Helpers
    function as_nonce($str){
    	return $str.'_nonce';
    }
    
    function as_fieldname($str){
    	return $str.'-meta';
    }
    
    function as_key($str){
    	return '_'.$str;
    }
    
    // Register the Metaboxes
    function custom_metaboxes() {
    
    	$metaboxes=custom_metaboxes_array();
    	foreach($metaboxes as $m){
    		$context= ($m['type']=='checkbox') ? 'side' : 'normal';
    		$priority= ($m['type']=='checkbox') ? 'default' : 'high';
    		add_meta_box(
    			as_fieldname($m['name']),
    			__( $m['label'], 'eb_plugin_textdomain' ),
    			'custom_metaboxes_callback',
    			$m['post_type'],
    			$context,
    			$priority,
    			array('metadata'=>$m)
    		);
    	}
    
    }
    add_action( 'add_meta_boxes', 'custom_metaboxes' );
    
    // Build the Metabox Forms
    function custom_metaboxes_callback( $post, $metabox ) {
    
    	$m=$metabox['args']['metadata'];
    	$nonce_name=as_nonce($m['name']);
    	$fieldname=as_fieldname($m['name']);
    	$description=$m['description'];
    	$label=$m['label'];
    	$box_type=$m['type'];
    	$key=as_key($m['name']);
    
    	wp_nonce_field( 'eb_plugin_meta_box', $nonce_name );
    
    	$value = get_post_meta( $post->ID, $key , true );
    
        // Text
        if($box_type=='text'){
    	    ?>
    	    <div class="custom-metabox">
    	        <label for="<?php echo $fieldname;?>" class="meta-row-title hidden"><?php _e( $label , 'eb_plugin_textdomain' )?></label>
    	        <input style="min-width:20em;" type="text" name="<?php echo $fieldname;?>" id="<?php echo $fieldname;?>" value="<?php esc_attr($value);?>" />
    	        <div class="description <?php echo $fieldname;?>"><em><?php echo $description?></em></div>
    	    </div>
    	    <?php
    	// Textarea
    	}elseif($box_type=='textarea'){
    		?>
    		<div class="custom-metabox">
    		    <label for="<?php echo $fieldname;?>" class="hidden"><?php _e( $label , 'eb_plugin_textdomain' )?></label>
    		    <textarea style="width:98%;min-height:4em;" name="<?php echo $fieldname;?>" id="<?php echo $fieldname;?>"> <?php esc_attr($value);?> </textarea>
    		    <div class="description <?php echo $fieldname;?>"><em><?php echo $description;?></em></div>
    		</div>
    		<?php
    	// Checkbox
    	}elseif($box_type=='checkbox'){
    		?>
    		<div class="custom-metabox">
    		    <span class="hidden"><?php _e( $label , 'eb_plugin_textdomain' )?></span>
    		    <div class="row-content">
    		        <label for="<?php echo $fieldname;?>">
    		            <input type="checkbox" name="<?php echo $fieldname;?>" id="<?php echo $fieldname;?>" value="1" <?php checked( $value, '1' ); ?> />
    		            <?php _e( $label , 'eb_plugin_textdomain' )?>
    		        </label>
    		    </div>
    		    <div style="margin-top:.75em;" class="description <?php echo $fieldname;?>"><em><?php echo $description;?></em></div>
    		</div>
    		<?php
    
    	}else{
    		echo 'Oops! Something went wrong. Make sure the type listed in custom_metaboxes_array() is valid (text, texarea, checkbox, radio, select).';
    	}
    }
    
    function custom_metaboxes_save( $post_id ) {
    
    	global $post;
    
    	$post_id=$post_id ? $post_id : $post->ID;
    
    	$metaboxes=custom_metaboxes_array();
    	foreach($metaboxes as $m){
    
    		$nonce_name=as_nonce($m['name']);
    		$fieldname=as_fieldname($m['name']);
    		$description=$m['description'];
    		$label=$m['label'];
    		$box_type=$m['type'];
    		$key=as_key($m['name']);
    
    		// Check if our nonce is set.
    		if ( ! isset( $_POST[$nonce_name] ) ) {
    			return;
    		}
    
    		// Verify that the nonce is valid.
    		if ( ! wp_verify_nonce( $_POST[$nonce_name], 'eb_plugin_meta_box' ) ) {
    			return;
    		}
    
    		// If this is an autosave, our form has not been submitted, so we don't want to do anything.
    		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
    			return;
    		}
    
    		// Check the user's permissions.
    		if ( isset( $_POST['post_type'] ) && 'page' == $_POST['post_type'] ) {
    
    			if ( ! current_user_can( 'edit_page', $post_id ) ) {
    				return;
    			}
    
    		} else {
    
    			if ( ! current_user_can( 'edit_post', $post_id ) ) {
    				return;
    			}
    		}
    
    		/* OK, it's safe for us to save the data now. */
    
    		// Make sure that it is set.
    		if ( ! isset( $_POST[$fieldname] ) ) {
    			return;
    		}
    
    		// Sanitize user input.
    		$sanitized = sanitize_text_field( $_POST[$fieldname] );
    
    		// Update the meta field in the database.
    		update_post_meta( $post_id, $key , $sanitized );		
    
    	}
    
    }
    add_action( 'save_post', 'custom_metaboxes_save' );

    Not sure what I’m missing but any help would be greatly appreciated.

    Cheers — Erin

Viewing 2 replies - 1 through 2 (of 2 total)
  • Thread Starter Erin Bell

    (@ebellempire)

    UPDATE: I notice that my custom meta does save for default post types, just not the custom ones.

    Thread Starter Erin Bell

    (@ebellempire)

    FYI, I did some tooling around and found that this is what worked best. For what it’s worth, I think it was only saving when an auto-save has been instantiated first. Not sure what that’s about.

    <?php
    // Helpers
    function as_nonce($str){
    	return $str.'_nonce';
    }
    
    function as_fieldname($str){
    	return $str.'_meta';
    }
    
    /* Fire our meta box setup function on the post editor screen. */
    add_action( 'load-post.php', 'eb_post_meta_boxes_setup' );
    add_action( 'load-post-new.php', 'eb_post_meta_boxes_setup' );
    
    /* Meta box setup function. */
    function eb_post_meta_boxes_setup() {
    
      /* Add meta boxes on the 'add_meta_boxes' hook. */
      add_action( 'add_meta_boxes', 'custom_metaboxes' );
    
      /* Save post meta on the 'save_post' hook. */
      add_action( 'save_post', 'custom_metaboxes_save', 10, 2 );
    
    }
    
    // Register the Metaboxes
    function custom_metaboxes() {
    
    	$metaboxes=custom_metaboxes_array();
    	foreach($metaboxes as $m){
    		$context= ($m['type']=='checkbox') ? 'side' : 'normal';
    		$priority= ($m['type']=='checkbox') ? 'default' : 'high';
    		add_meta_box(
    			as_fieldname($m['name']),
    			__( $m['label'], 'ccms_plugin_textdomain' ),
    			'custom_metaboxes_callback',
    			$m['post_type'],
    			$context,
    			$priority,
    			array('metadata'=>$m)
    		);
    	}
    
    }
    
    // Build the Metabox Forms
    function custom_metaboxes_callback( $post, $metabox ) {
    
    	$m=$metabox['args']['metadata'];
    	$nonce_name=as_nonce($m['name']);
    	$fieldname=as_fieldname($m['name']);
    	$description=$m['description'];
    	$label=$m['label'];
    	$box_type=$m['type'];
    
    	$post_id=$post->ID;
    
    	wp_nonce_field( basename( __FILE__ ), $nonce_name );
    
    	$value = get_post_custom( $post->ID );
    
        // Text
        if($box_type=='text'){
    	    ?>
    	    <div class="custom-metabox">
    	        <label for="<?php echo $fieldname;?>" class="hidden">
    	        	<?php echo $label; ?>
    	        </label>
    
    	        <input style="min-width:20em;" type="text" name="<?php echo $fieldname;?>" id="<?php echo $fieldname;?>" value="<?php echo isset($value[$fieldname][0]) ? esc_attr($value[$fieldname][0]) : '';?>" />
    
    	        <div class="description <?php echo $fieldname;?>">
    		        <em><?php echo $description?></em>
    		    </div>
    	    </div>
    	    <?php
    	// Textarea
    	}elseif($box_type=='textarea'){
    		?>
    		<div class="custom-metabox">
    		    <label for="<?php echo $fieldname;?>" class="hidden">
    		    	<?php echo $label; ?>
    		    </label>
    
    		    <textarea style="width:98%;min-height:4em;" name="<?php echo $fieldname;?>" id="<?php echo $fieldname;?>">
    		    	<?php echo isset($value[$fieldname][0]) ? esc_attr($value[$fieldname][0]) : '';?>
    		    </textarea>
    
    		    <div class="description <?php echo $fieldname;?>">
    			    <em><?php echo $description;?></em>
    			</div>
    		</div>
    		<?php
    	}else{
    		echo 'Oops! Something went wrong. Make sure the type listed in custom_metaboxes_array() is valid (currently only text and textarea are supported).';
    	}
    }
    
    function custom_metaboxes_save( $post_id ) {
    
    	$metaboxes=custom_metaboxes_array();
    	foreach($metaboxes as $m){	
    
    		$nonce_name=as_nonce($m['name']);
    		$fieldname=as_fieldname($m['name']);
    
    	    // Checks save status
    	    $is_autosave = wp_is_post_autosave( $post_id );
    	    $is_revision = wp_is_post_revision( $post_id );
    	    $is_valid_nonce = ( isset( $_POST[ $nonce_name ] ) && wp_verify_nonce( $_POST[ $nonce_name ], basename( __FILE__ ) ) ) ? 'true' : 'false';
    
    	    // Exits script depending on save status
    	    if ( $is_autosave || $is_revision || !$is_valid_nonce ) {
    	        return;
    	    }
    
    	    // Checks for input and sanitizes/saves if needed
    	    if( isset( $_POST[ $fieldname ] ) ) {
    	        update_post_meta( $post_id, $fieldname, sanitize_text_field( $_POST[ $fieldname ] ) );
    	    }
    
    	}
    
    }
Viewing 2 replies - 1 through 2 (of 2 total)
  • The topic ‘Saving Multiple Custom Meta Boxes’ is closed to new replies.