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:
- launch a function that run on that filter, and manually retreive the meta data
- after retrieveing, trigger a custom filter to be able to filter the just retrieved data
- store the so filtered value in a static variable, to avoid run again db query on subsequent calls
- 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.