Save Custom Post Meta – Improving The Code

Comments are closed on this post. See the updated version for more information.

Last week, I was talking to a couple of developers on Twitter about some of the code that’s required to save custom post meta in WordPress when working with plugins or themes.

For the most part, good serialization functions are consistently formatted in the same way:

  • First, we check for security. If the security check fails, then we exit the function.
  • If security passes, then we proceed with our serialization functionality.

The thing is, the security checks are generally the same thing across the board so much so that you may even consider it somewhat of a boilerplate.

This seems like an opportunity to improve developer’s processes a bit by abstracting out some of the code that is used to save custom post meta data.

So let’s try this:

Below, I’ve started a gist of the general boilerplate code that I follow. It includes comments that demonstrate exactly what we’re trying to achieve.

/**
 * An example function used to demonstrate how post meta data is typically saved.
 *
 * The first part of the function is general boilerplate code that is used in most
 * WordPress plugins. After speaking with several developers on Twitter, there's a desire
 * to refactor some of this code into its own private function so that the core
 * serialization function doesn't include so much boilerplate security code.
 *
 * Here, I've provided a sample function that we can use to begin refactoring. It
 * includes the following:
 *
 * - A nonce identified as 'meta_data_nonce.' This is purely for demonstration purposes.
 * - 'save_meta_data' is also an example function name. It's just for demonstration purposes.
 * - I've annotated where the actual serialization functionality would occur.
 * - I've blocked off where the boilerplate security check is concerned
 *
 * Once we receive enough contributions to this particular gist, I'd love to publicize it
 * for the development community in some way so that we can keep our methods smaller, cleaner,
 * and responsible for doing as few things as possible.
 *
 * @param int $post_id  The ID of the post for which the meta data is being saved.
 */
public function save_meta_data( $post_id ) {

  if( isset( $_POST['meta_data_nonce'] ) && isset( $_POST['post_type'] ) ) {

    /* ---------- Begin Security Check ---------- */

		// Don't save if the user hasn't submitted the changes
		if( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
			return;
		} // end if

		// Verify that the input is coming from the proper form
		if( ! wp_verify_nonce( $_POST['meta_data_nonce'], plugin_basename( __FILE__ ) ) ) {
			return;
		} // end if

		// Make sure the user has permissions to post
		if( 'post' == $_POST['post_type'] ) {
			if( ! current_user_can( 'edit_post', $post_id ) ) {
				return;
			} // end if
		} // end if/else

    /* ---------- End Security Check ---------- */

    /* ---------------------------------------- */
    /* -- Actual serialization work occurs here */
    /* ---------------------------------------- */

	} // end if

} // end save_meta_data

Click here to find the gist on GitHub, too. Please refine it as much as possible, too. The things that are most important to me are that:

  • It improves developer’s experience in writing code like this in future projects
  • It maintains the same level of security and performance as the typical boilerplate code
  • It follows the WordPress coding conventions

Finally, I rarely ask for you guys to retweet something, but I’d love to get as many passionate WordPress developers on this as possible, so please get your fellow followers, readers, and so on to contribute.

1 Reply to “Save Custom Post Meta – Improving The Code”

  1. Hi Tom,

    Interesting post – I tend to copy/paste this code across plugins as I need it. A couple of quick comments:

    * The gist embedding seems to be double encoding some characters, so ampersands are showing as a double amp; HTML entity
    * You’re checking to see if the user has permissions to post – I’ve got two comments on this. Firstly – I thought WordPress already handled this check for you? Second – if it doesn’t, then you’re only performing the check if the post_type is “post” and not any other post type (E.g. page, or custom post types) – is there a deliberate reason for that
    * The check for isset( $_POST[‘meta_data_nonce’]) is redundant since you’re calling wp_verify_nonce later anyway?

Comments are closed.