Pass all custom fields through the same filter on post load?

Internally post meta are handled via object cache that is hardly filterable.

The only chance to filter post metadata is to use the 'get_post_metadata', but that filter is triggered when meta data are not available, so there is nothing to filter, it was intended to short-circuit the result more than to filter them.

So the solution I propose is:

  1. launch a function that run on that filter, and manually retreive the meta data
  2. after retrieveing, trigger a custom filter to be able to filter the just retrieved data
  3. store the so filtered value in a static variable, to avoid run again db query on subsequent calls
  4. finally add a callback to our custom hook (added at point #2) and filter data

So, first add the filter:

add_filter( 'get_post_metadata', 'my_post_meta_filters', 0, 4 );

Then write the hooking callback

function my_post_meta_filters( $null, $pid, $key, $single ) {
  if ( ! in_array( $key, array( 'author', 'ISBN', 'quote', '' ), TRUE ) || is_admin() ) {
    return $null;
  };
  static $filtered_values = NULL;
  if ( is_null( $filtered_values ) ) {
    $cache = update_meta_cache( 'post', array( $pid ) );
    $values = $cache[$pid];
    $raw = array(
      'author' => isset( $values['author'] ) ? $values['author'] : NULL,
      'ISBN'   => isset( $values['ISBN'] )   ? $values['ISBN']   : NULL,
      'quote'  => isset( $values['quote'] )  ? $values['quote']  : NULL,
    );
    // this is the filter you'll use to filter your values
    $filtered = (array) apply_filters( 'my_post_meta_values', $raw, $pid );
    foreach ( array( 'author', 'ISBN', 'quote' ) as $k ) {
      if ( isset( $filtered[$k] ) ) $values[$k] = $filtered[$k];
    }
    $filtered_values = $values;
  }
  if ( $key === '' )
     $filtered_values;
  if ( ! isset( $filtered_values[$key] ) )
     return;
  return $single
    ? maybe_unserialize( $filtered_values[$key][0] )
    : array_map( 'maybe_unserialize', $filtered_values[$key] );
}

Having this function in your code you’ll be able to filter your custom fields using the custom 'my_post_meta_values' filter.

Just an example:

add_filter( 'my_post_meta_values', function( $values, $post_id ) {

  // append '123456' to all values

  if ( is_array( $values['author'] ) ) {
    $values['author'][0] .= ' 123456';
  }
  if ( is_array( $values['ISBN'] ) ) {
    $values['ISBN'][0] .= ' 123456';
  }
  if ( is_array( $values['quote'] ) ) {
    $values['quote'][0] .= ' 123456';
  }

  return $values;

}, 10, 2 );

With this filter active, if you do:

echo get_post_meta( $post_id, 'author', TRUE );

and your “author” custom field is set to “Shawn” than the output is “Shawn 123456”.

Note that my_post_meta_filters is also compatible with get_post_custom with no additional effort.

Leave a Comment