WordPress.org

Make WordPress Core

Opened 2 years ago

Last modified 2 years ago

#41953 new feature request

Improved Meta Box Save Hook

Reported by: Nenad Obradovic Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version: 4.8.2
Component: Posts, Post Types Keywords:
Focuses: administration Cc:
PR Number:

Description

Hi,

This is suggestion how to reduce some conditionals for saving meta boxes with function for example. Below is code of meta box save function with all conditions for security and inside that function we always write some core condition for security that can be separated in one or more core functions to do that for us, so we can just call that function.

if ( ! function_exists( 'save_admin_meta_boxes' ) ) {
	/**
	 * Saves admin meta box to postmeta table
	 *
	 * @param $post_id int - id of post that meta box is being saved
	 * @param $post WP_Post - current post object
	 */
	function save_admin_meta_boxes( $post_id, $post ) {
		
		// If we're doing an auto save, bail
		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
			return;
		}

                // If default wp nonce isn't there, bail
		if ( ! isset( $_POST['_wpnonce'] ) ) {
			return;
		}
		
		// If current user can't edit this post, bail
		if ( ! current_user_can( 'edit_post', $post_id ) ) {
			return;
		}
		
		// If current post type are not in list, bail
		$post_types = apply_filters( 'wp_allowed_post_types_for_meta_boxes', array( 'post', 'page' ) );
		
		if ( ! in_array( $post->post_type, $post_types ) ) {
			return;
		}
		
		// If our nonce isn't there, or we can't verify it, bail
		$meta_boxes  = apply_filters( 'add_meta_boxes_filter', array() );
		$nonce_array = array();
		
		if ( is_array( $meta_boxes ) && ! empty( $meta_boxes ) ) {
			foreach ( $meta_boxes as $meta_box ) {
				$nonce_array[] = 'extensive_vc_meta_box_' . esc_attr( $meta_box ) . '_save';
			}
		}
		
		if ( is_array( $nonce_array ) && count( $nonce_array ) ) {
			foreach ( $nonce_array as $nonce ) {
				if ( ! isset( $_POST[ $nonce ] ) || ! wp_verify_nonce( $_POST[ $nonce ], $nonce ) ) {
					return;
				}
			}
		}
		
		// Make sure your data is set before trying to save it
                global $meta_boxes_options;

		foreach ( $meta_boxes_options as $key => $value ) {
			$field_key = $_POST[ $key ];
			
			if ( isset( $field_key ) && trim( $field_key !== '' ) ) {
				update_post_meta( $post_id, $key, esc_html( $field_key ) );
			} else {
				delete_post_meta( $post_id, $key );
			}
		}
	}
	
	add_action( 'save_post', 'save_admin_meta_boxes', 10, 2 );
}

Example function with that conditionals

if ( ! function_exists( 'wp_meta_boxes_security_check' ) ) {
	/**
	 * Check is meta box secure and valid for saving
	 *
	 * @param $post_id int - id of post that meta box is being saved
	 * @param $post WP_Post - current post object
	 *
	 * @return boolean
	 */
	function wp_meta_boxes_security_check( $post_id, $post ) {
		$return_value = true;
		
		// If we're doing an auto save, bail
		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
			$return_value = false;
		}
		
		// If default wp nonce isn't there, bail
		if ( ! isset( $_POST['_wpnonce'] ) ) {
			$return_value = false;
		}
		
		// If current user can't edit this post, bail
		if ( ! current_user_can( 'edit_post', $post_id ) ) {
			$return_value = false;
		}
		
		// If current post type are not in list, bail
		$post_types = apply_filters( 'wp_allowed_post_types_for_meta_boxes', array( 'post', 'page' ) );
		
		if ( ! in_array( $post->post_type, $post_types ) ) {
			$return_value = false;
		}
		
		return $return_value;
	}
}

and then finally code for saving meta boxes will be

if ( ! function_exists( 'save_admin_meta_boxes' ) ) {
	/**
	 * Saves admin meta box to postmeta table
	 *
	 * @param $post_id int - id of post that meta box is being saved
	 * @param $post WP_Post - current post object
	 */
	function save_admin_meta_boxes( $post_id, $post ) {
		
		// If meta box doesn't paste check, bail
		if ( ! wp_meta_boxes_security_check( $post_id, $post ) ) {
			return;
		}
		
		// If our nonce isn't there, or we can't verify it, bail
		$meta_boxes  = apply_filters( 'add_meta_boxes_filter', array() );
		$nonce_array = array();
		
		if ( is_array( $meta_boxes ) && ! empty( $meta_boxes ) ) {
			foreach ( $meta_boxes as $meta_box ) {
				$nonce_array[] = 'extensive_vc_meta_box_' . esc_attr( $meta_box ) . '_save';
			}
		}
		
		if ( is_array( $nonce_array ) && count( $nonce_array ) ) {
			foreach ( $nonce_array as $nonce ) {
				if ( ! isset( $_POST[ $nonce ] ) || ! wp_verify_nonce( $_POST[ $nonce ], $nonce ) ) {
					return;
				}
			}
		}
		
		// Make sure your data is set before trying to save it
		global $meta_boxes_options;
		
		foreach ( $meta_boxes_options as $key => $value ) {
			$field_key = $_POST[ $key ];
			
			if ( isset( $field_key ) && trim( $field_key !== '' ) ) {
				update_post_meta( $post_id, $key, esc_html( $field_key ) );
			} else {
				delete_post_meta( $post_id, $key );
			}
		}
	}
	
	add_action( 'save_post', 'save_admin_meta_boxes', 10, 2 );
}

Also I added some filter for allowed post types inside that function

$post_types = apply_filters( 'wp_allowed_post_types_for_meta_boxes', array( 'post', 'page' ) );

which allows authors to easily add their own custom post type with meta boxes for saving.

Best regards,
Nenad

Change History (1)

#1 @SergeyBiryukov
2 years ago

  • Component changed from General to Posts, Post Types
  • Focuses administration added

Related: #30188

Note: See TracTickets for help on using tickets.