Skip to content
This repository was archived by the owner on Dec 16, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions php/class-wp-customize-featured-image-controller.php
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Loading