Skip to content
This repository has been archived by the owner on Dec 16, 2022. It is now read-only.

Commit

Permalink
Add support for registering customize post meta via register_meta()
Browse files Browse the repository at this point in the history
  • Loading branch information
westonruter committed Aug 29, 2016
1 parent 805bf0c commit f0c2837
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 23 deletions.
9 changes: 6 additions & 3 deletions php/class-wp-customize-featured-image-controller.php
Expand Up @@ -376,13 +376,16 @@ public function sanitize_value( $attachment_id ) {
}

/**
* Sanitize (and validate) an input for a specific setting instance.
* Validate the value that has been sanitized by the `sanitize_value` method.
*
* Since the `sanitize_callback` used by `sanitize_meta()` cannot return
* any `WP_Error` to represent invalidity, a secondary
*
* @see update_metadata()
*
* @param string $attachment_id The value to sanitize.
* @param WP_Customize_Postmeta_Setting $setting Setting.
* @return mixed|WP_Error Sanitized value or `WP_Error` if invalid.
* @return mixed|WP_Error|null Sanitized value or `WP_Error` if invalid (or `null` if before WP 4.6).
*/
public function sanitize_setting( $attachment_id, WP_Customize_Postmeta_Setting $setting ) {
unset( $setting );
Expand All @@ -398,7 +401,7 @@ public function sanitize_setting( $attachment_id, WP_Customize_Postmeta_Setting

/*
* Note that at this point, sanitize_meta() has already been called in WP_Customize_Postmeta_Setting::sanitize(),
* and the meta is registered wit WP_Customize_Featured_Image_Controller::sanitize_value() as the sanitize_callback().
* and the meta is registered with WP_Customize_Featured_Image_Controller::sanitize_value() as the sanitize_callback().
* So $attachment_id is either a valid attachment ID, -1, or false.
*/
if ( ! $is_valid ) {
Expand Down
8 changes: 8 additions & 0 deletions php/class-wp-customize-page-template-controller.php
Expand Up @@ -84,7 +84,15 @@ public function get_page_template_choices() {
/**
* Apply rudimentary sanitization of a file path for a generic setting instance.
*
* The sanitization is rudimentary because `sanitize_meta()` fails to pass the
* associated post ID, so we cannot get the list of page templates to check
* against. Additionally, the callback used in `sanitize_meta()` cannot return
* `WP_Error` to indicate invalidity, so for these reasons we also have a
* `sanitize_setting` callback which is used when saving the customizer
* setting.
*
* @see sanitize_meta()
* @see WP_Customize_Page_Template_Controller::sanitize_setting()
*
* @param string $raw_path Path.
* @return string Path.
Expand Down
4 changes: 4 additions & 0 deletions php/class-wp-customize-postmeta-controller.php
Expand Up @@ -135,6 +135,7 @@ public function register_meta( WP_Customize_Posts $posts_component ) {
$post_types = $this->post_types;
}

// Note that if post_type_supports is defined, it support is missing, the post types will have already been excluded at this point.
foreach ( $post_types as $post_type ) {
$setting_args = array(
'sanitize_callback' => $this->sanitize_callback,
Expand Down Expand Up @@ -205,8 +206,11 @@ public function sanitize_value( $meta_value ) {
* Sanitize an input.
*
* Callback for `customize_sanitize_post_meta_{$meta_key}` filter.
* Note that this is redundant and unnecessary due to the `sanitize_value`
* method is used in the underlying `register_meta()` call.
*
* @see update_metadata()
* @see WP_Customize_Postmeta_Controller::sanitize_value()
*
* @param string $meta_value The value to sanitize.
* @param WP_Customize_Postmeta_Setting $setting Setting.
Expand Down
85 changes: 66 additions & 19 deletions php/class-wp-customize-posts.php
Expand Up @@ -92,6 +92,7 @@ public function __construct( WP_Customize_Manager $manager ) {

add_filter( 'customize_refresh_nonces', array( $this, 'add_customize_nonce' ) );
add_action( 'customize_register', array( $this, 'register_constructs' ), 20 );
remove_filter( 'register_meta_args', '_wp_register_meta_args_whitelist' ); // Break warranty seal so additional args can be used in register_meta().
add_action( 'init', array( $this, 'register_meta' ), 100 );
add_filter( 'customize_dynamic_setting_args', array( $this, 'filter_customize_dynamic_setting_args' ), 10, 2 );
add_filter( 'customize_dynamic_setting_class', array( $this, 'filter_customize_dynamic_setting_class' ), 5, 3 );
Expand Down Expand Up @@ -191,9 +192,12 @@ public function set_builtin_post_type_descriptions() {
/**
* Register post meta for a given post type.
*
* Please note that a sanitize_callback is intentionally excluded because the
* meta sanitization logic should be re-used with the global register_meta()
* function, which includes a `$sanitize_callback` param.
* Note that the `sanitize_callback` here is for the customizer setting and
* it is normally redundant to supply because `register_meta()` should have
* been already called with its own `sanitize_callback` supplied. A warning
* will be raised if this was not done. Similarly the `capability` parameter
* is not required here because when `register_meta()` was called, an
* `auth_callback` could (and should) be supplied at that point.
*
* @see register_meta()
*
Expand All @@ -202,23 +206,32 @@ public function set_builtin_post_type_descriptions() {
* @param array $setting_args Args.
*/
public function register_post_type_meta( $post_type, $meta_key, $setting_args = array() ) {
$setting_args = array_merge(
array(
'capability' => null,
'theme_supports' => null,
'default' => null,
'transport' => null,
'sanitize_callback' => null,
'sanitize_js_callback' => null,
'validate_callback' => null,
'setting_class' => 'WP_Customize_Postmeta_Setting',
),
$setting_args
$defaults = array(
'theme_supports' => null,
'post_type_supports' => null,

// Setting args.
'capability' => null,
'default' => null,
'transport' => null,
'sanitize_callback' => null,
'sanitize_js_callback' => null,
'validate_callback' => null,

'setting_class' => 'WP_Customize_Postmeta_Setting',
);
$setting_args = array_merge( $defaults, $setting_args );
if ( isset( $setting_args['auth_callback'] ) ) {
_doing_it_wrong( __METHOD__, esc_html__( 'Only pass auth_callback to register_meta() function. Consider the capability param instead.', 'customize-posts' ), '0.7.0' );
}
$setting_args = wp_array_slice_assoc( $setting_args, array_keys( $defaults ) );

if ( ! has_filter( "auth_post_meta_{$meta_key}", array( $this, 'auth_post_meta_callback' ) ) ) {
add_filter( "auth_post_meta_{$meta_key}", array( $this, 'auth_post_meta_callback' ), 10, 4 );
}
if ( ! has_filter( "sanitize_post_meta_{$meta_key}" ) ) {
_doing_it_wrong( __METHOD__, sprintf( __( 'Expected previous call to register_meta( "post", "%s" ) with a sanitize_callback.', 'customize-posts' ), $meta_key ), '0.7.0' ); // WPCS: xss ok.
}

// Filter out null values, aka array_filter with ! is_null.
foreach ( array_keys( $setting_args ) as $key => $value ) {
Expand All @@ -234,7 +247,9 @@ public function register_post_type_meta( $post_type, $meta_key, $setting_args =
}

/**
* Allow editing post meta in Customizer if user can edit_post for registered post meta.
* Filter auth_post_meta_{$meta_key} according to the capability for the registered meta.
*
* Note that this filter will only apply when the customizer is bootstrapped.
*
* @param bool $allowed Whether the user can add the post meta. Default false.
* @param string $meta_key The meta key.
Expand All @@ -243,8 +258,7 @@ public function register_post_type_meta( $post_type, $meta_key, $setting_args =
* @return bool Allowed.
*/
public function auth_post_meta_callback( $allowed, $meta_key, $post_id, $user_id ) {
global $wp_customize;
if ( $allowed || empty( $wp_customize ) ) {
if ( $allowed ) {
return $allowed;
}
$post = get_post( $post_id );
Expand Down Expand Up @@ -274,6 +288,37 @@ public function auth_post_meta_callback( $allowed, $meta_key, $post_id, $user_id
*/
public function register_meta() {

// Recognize meta registered for customizer via register_meta().
if ( function_exists( 'get_registered_meta_keys' ) ) {
foreach ( get_registered_meta_keys( 'post' ) as $meta => $args ) {
if ( empty( $args['show_in_customizer'] ) ) {
continue;
}

if ( ! empty( $args['post_types'] ) && ! empty( $args['post_type_supports'] ) ) {
$post_types = array_intersect( $args['post_types'], get_post_types_by_support( $args['post_type_supports'] ) );
} elseif ( ! empty( $args['post_type_supports'] ) ) {
$post_types = get_post_types_by_support( $args['post_type_supports'] );
} elseif ( ! empty( $args['post_types'] ) ) {
$post_types = $args['post_types'];
} else {
$post_types = array();
}

foreach ( $post_types as $post_type ) {
$register_args = array();
if ( isset( $args['customize_setting_args'] ) ) {
$register_args = array_merge( $register_args, $args['customize_setting_args'] );
}
if ( isset( $args['customize_setting_class'] ) ) {
$register_args['setting_class'] = $args['customize_setting_class'];
}
$register_args = array_merge( $register_args, wp_array_slice_assoc( $args, array( 'theme_supports', 'post_type_supports' ) ) );
$this->register_post_type_meta( $post_type, $meta, $register_args );
}
}
}

/**
* Allow plugins to register meta.
*
Expand Down Expand Up @@ -350,7 +395,9 @@ public function filter_customize_dynamic_setting_args( $args, $setting_id ) {
}
$registered = $this->registered_post_meta[ $matches['post_type'] ][ $matches['meta_key'] ];
if ( isset( $registered['theme_supports'] ) && ! current_theme_supports( $registered['theme_supports'] ) ) {
// We don't really need this because theme_supports will already filter it out of being exported.
return $args;
}
if ( isset( $registered['post_type_supports'] ) && ! post_type_supports( $matches['post_type'], $registered['post_type_supports'] ) ) {
return $args;
}
if ( false === $args ) {
Expand Down
18 changes: 18 additions & 0 deletions tests/php/test-class-wp-customize-posts-preview.php
Expand Up @@ -386,6 +386,16 @@ public function test_get_previewed_posts_for_query() {
$this->assertEquals( array( $post->ID, $page->ID ), $this->posts_component->preview->get_previewed_posts_for_query( $query ) );
}

/**
* Pass through a value with out modification.
*
* @param mixed $x Value
* @return mixed Value.
*/
public function pass_through( $x ) {
return $x;
}

/**
* Test querying posts based on meta queries.
*
Expand All @@ -395,6 +405,7 @@ public function test_get_previewed_posts_for_query() {
public function test_get_previewed_post_for_meta_query() {
$meta_key = 'index';
$post_type = 'post';
register_meta( 'post', $meta_key, array( $this, 'pass_through' ) );
$this->posts_component->register_post_type_meta( $post_type, $meta_key );

$post_data = array();
Expand Down Expand Up @@ -578,12 +589,14 @@ public function test_filter_preview_pings_open() {
public function test_register_post_type_meta_settings() {
$post = get_post( $this->post_id );

register_meta( 'post', 'foo', array( $this, 'pass_through' ) );
$this->posts_component->register_post_type_meta( 'post', 'foo' );
$foo_setting_id = WP_Customize_Postmeta_Setting::get_post_meta_setting_id( $post, 'foo' );
$this->assertEmpty( $this->posts_component->manager->get_setting( $foo_setting_id ) );
$this->posts_component->register_post_type_meta_settings( $post );
$this->assertNotEmpty( $this->posts_component->manager->get_setting( $foo_setting_id ) );

register_meta( 'post', 'bar', array( $this, 'pass_through' ) );
$this->posts_component->register_post_type_meta( 'post', 'bar' );
$bar_setting_id = WP_Customize_Postmeta_Setting::get_post_meta_setting_id( $post, 'bar' );
$this->assertEmpty( $this->posts_component->manager->get_setting( $bar_setting_id ) );
Expand All @@ -599,6 +612,8 @@ public function test_register_post_type_meta_settings() {
public function test_filter_get_post_meta_to_preview() {
$preview = $this->posts_component->preview;
$meta_key = 'foo_key';
register_meta( 'post', $meta_key, array( $this, 'pass_through' ) );
register_meta( 'post', 'other', array( $this, 'pass_through' ) );
$this->posts_component->register_post_type_meta( 'post', $meta_key );
$this->posts_component->register_post_type_meta( 'post', 'other' );
$this->posts_component->register_post_type_meta_settings( get_post( $this->post_id ) );
Expand Down Expand Up @@ -673,6 +688,7 @@ public function test_previewing_empty_array() {
$meta_key = 'foo_ids';
$initial_value = array( 1, 2, 3 );
update_post_meta( $this->post_id, $meta_key, $initial_value );
register_meta( 'post', $meta_key, array( $this, 'pass_through' ) );
$this->posts_component->register_post_type_meta( 'post', $meta_key );
$this->posts_component->register_post_type_meta_settings( get_post( $this->post_id ) );

Expand Down Expand Up @@ -856,6 +872,7 @@ public function test_export_preview_data() {
$this->assertEquals( $this->post_id, $data['queriedPostId'] );

update_post_meta( $this->post_id, 'foo', 'bar' );
register_meta( 'post', 'foo', array( $this, 'pass_through' ) );
$this->posts_component->register_post_type_meta( 'post', 'foo' );
$this->do_customize_boot_actions();
query_posts( array( 'p' => $this->post_id, 'preview' => true ) );
Expand All @@ -878,6 +895,7 @@ public function test_export_preview_data() {
public function test_amend_with_queried_post_ids() {
$preview = $this->posts_component->preview;
$preview->customize_preview_init();
register_meta( 'post', 'foo', array( $this, 'pass_through' ) );
$this->posts_component->register_post_type_meta( 'post', 'foo' );
query_posts( 'p=' . $this->post_id );
update_post_meta( $this->post_id, 'foo', 'bar' );
Expand Down

0 comments on commit f0c2837

Please sign in to comment.