From 5acc5e249f34e440638383bc99d6f03034346d2b Mon Sep 17 00:00:00 2001 From: Will Gladstone Date: Tue, 5 Aug 2014 15:09:35 -0400 Subject: [PATCH 01/23] Save an empty term set for a field that has only_save_to_taxonomy as true and append_taxonomy as false --- php/datasource/class-fieldmanager-datasource-term.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/php/datasource/class-fieldmanager-datasource-term.php b/php/datasource/class-fieldmanager-datasource-term.php index 152361fc84..3f94964956 100644 --- a/php/datasource/class-fieldmanager-datasource-term.php +++ b/php/datasource/class-fieldmanager-datasource-term.php @@ -192,7 +192,12 @@ public function presave_alter_values( Fieldmanager_Field $field, $values, $curre } $this->save_taxonomy( $tax_values, $field->data_id ); } - if ( $this->only_save_to_taxonomy ) return array(); + if ( $this->only_save_to_taxonomy ) { + if ( empty( $values ) && ! ( $this->append_taxonomy ) ) { + $this->save_taxonomy( array(), $field->data_id ); + } + return array(); + } return $values; } From a29595ba175addc5e42a4e96ceee4b8f1c0b101c Mon Sep 17 00:00:00 2001 From: Will Gladstone Date: Tue, 5 Aug 2014 16:04:28 -0400 Subject: [PATCH 02/23] Override options selected function to allow all boxes to be checked by default --- php/class-fieldmanager-checkboxes.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/php/class-fieldmanager-checkboxes.php b/php/class-fieldmanager-checkboxes.php index 2bb11cad20..4a2a7ba4a5 100644 --- a/php/class-fieldmanager-checkboxes.php +++ b/php/class-fieldmanager-checkboxes.php @@ -31,4 +31,19 @@ public function form_element( $value = array() ) { ); } + /** + * Override function to allow all boxes to be checked by default. + * @param string $current_option this option + * @param array $options all valid options + * @param string $attribute + * @return string $attribute on match, empty on failure. + */ + public function option_selected( $current_option, $options, $attribute ) { + if ( ( ( $options != null && !empty( $options ) ) && in_array( $current_option, $options ) ) || ( 'checked' == $this->default_value && in_array( $this->default_value, $options ) ) ) { + return $attribute; + } else { + return ''; + } + } + } \ No newline at end of file From 6237f5151e8de8e66cb0f4c49ee381adeb9dbeb6 Mon Sep 17 00:00:00 2001 From: bcampeau Date: Tue, 23 Dec 2014 18:45:38 -0500 Subject: [PATCH 03/23] Added ability to store data from Fieldmanager_Datasource_User as something other than ID --- .../class-fieldmanager-datasource-user.php | 55 +++++++++++++++---- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/php/datasource/class-fieldmanager-datasource-user.php b/php/datasource/class-fieldmanager-datasource-user.php index f14e5f7dd3..e902a99aa8 100644 --- a/php/datasource/class-fieldmanager-datasource-user.php +++ b/php/datasource/class-fieldmanager-datasource-user.php @@ -34,6 +34,13 @@ class Fieldmanager_Datasource_User extends Fieldmanager_Datasource { * or 'user_nicename' */ public $display_property = 'display_name'; + + /** + * @var string + * Store property. Defaults to ID, but can also be 'user_login', 'user_email', + * or 'user_nicename'. + */ + public $store_property = 'ID'; /** * @var string @@ -49,8 +56,17 @@ class Fieldmanager_Datasource_User extends Fieldmanager_Datasource { */ public $reciprocal = Null; - // constructor not required for this datasource; options are just set to keys, - // which Fieldmanager_Datasource does. + /** + * Constructor. Used for validation. + */ + public function __construct( $options = array() ) { + parent::__construct( $options ); + + // Validate + if ( ! empty( $this->reciprocal ) && 'ID' != $this->store_property ) { + throw new FM_Developer_Exception( __( 'You cannot use reciprocal relationships with FM_Datasource_User if store_property is not set to ID', 'fieldmanager' ) ); + } + } /** * Get a post title by post ID @@ -58,8 +74,23 @@ class Fieldmanager_Datasource_User extends Fieldmanager_Datasource { * @return string post title */ public function get_value( $value ) { - $id = intval( $value ); - $user = get_userdata( $id ); + switch ( $this->store_property ) { + case 'ID': + $field = 'ID'; + $value = intval( $value ); + break; + case 'user_nicename': + $field = 'slug'; + break; + case 'user_email': + $field = 'email'; + break; + case 'user_login': + $field = 'login'; + break; + } + + $user = get_user_by( $field, $value ); return $user ? $user->{$this->display_property} : ''; } @@ -79,7 +110,7 @@ public function get_items( $fragment = Null ) { if ( $fragment ) $user_args['search'] = $fragment; $users = get_users( $user_args ); foreach ( $users as $u ) { - $ret[$u->ID] = $u->{$this->display_property}; + $ret[ $u->{$this->store_property} ] = $u->{$this->display_property}; } return $ret; } @@ -98,12 +129,13 @@ public function get_ajax_action() { } /** - * For post relationships, delete reciprocal post metadata prior to saving (presave will re-add) + * For post relationships, delete reciprocal post metadata prior to saving (presave will re-add). + * Reciprocal relationships are not possible if we are not storing by ID. * @param array $values new post values * @param array $current_values existing post values */ public function presave_alter_values( Fieldmanager_Field $field, $values, $current_values ) { - if ( $field->data_type != 'post' || !$this->reciprocal ) return $values; + if ( $field->data_type != 'post' || ! $this->reciprocal || 'ID' != $this->store_property ) return $values; foreach ( $current_values as $user_id ) { delete_user_meta( $user_id, $this->reciprocal, $field->data_id ); } @@ -111,7 +143,8 @@ public function presave_alter_values( Fieldmanager_Field $field, $values, $curre } /** - * Handle reciprocal postmeta + * Handle reciprocal postmeta. + * Reciprocal relationships are not possible if we are not storing by ID. * @param int $value * @return string */ @@ -123,11 +156,11 @@ public function presave( Fieldmanager_Field $field, $value, $current_value ) { $value = array( $value ); } foreach ( $value as $i => $v ) { - $value[$i] = intval( $v ); - if( !current_user_can( $this->capability, $v ) ) { + $value[$i] = call_user_func( ( 'ID' == $this->store_property ) ? 'intval' : 'sanitize_text_field', $v ); + if( ! current_user_can( $this->capability, $v ) ) { wp_die( esc_html( sprintf( __( 'Tried to refer to user "%s" which current user cannot edit.', 'fieldmanager' ), $v ) ) ); } - if ( $this->reciprocal ) { + if ( $this->reciprocal && 'ID' == $this->store_property ) { add_user_meta( $v, $this->reciprocal, $field->data_id ); } } From cfdd1b99c291ae07d86c4b10a8ea96ac78cfb33e Mon Sep 17 00:00:00 2001 From: bcampeau Date: Wed, 14 Jan 2015 10:27:24 -0500 Subject: [PATCH 04/23] Added extra validation for store property value --- .../class-fieldmanager-datasource-user.php | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/php/datasource/class-fieldmanager-datasource-user.php b/php/datasource/class-fieldmanager-datasource-user.php index e902a99aa8..eb2e8a1179 100644 --- a/php/datasource/class-fieldmanager-datasource-user.php +++ b/php/datasource/class-fieldmanager-datasource-user.php @@ -41,6 +41,12 @@ class Fieldmanager_Datasource_User extends Fieldmanager_Datasource { * or 'user_nicename'. */ public $store_property = 'ID'; + + /** + * @var array + * Allowed store properties for validation. + */ + private $allowed_store_properties = array( 'ID', 'user_login', 'user_email', 'user_nicename' ); /** * @var string @@ -62,9 +68,17 @@ class Fieldmanager_Datasource_User extends Fieldmanager_Datasource { public function __construct( $options = array() ) { parent::__construct( $options ); - // Validate + // Validate improper usage of store property + if ( ! in_array( $this->store_property, $this->allowed_store_properties ) ) { + throw new FM_Developer_Exception( sprintf( + __( 'Store property %s is invalid. Must be one of %s.', 'fieldmanager' ), + $this->store_property, + implode( ', ', $this->allowed_store_properties ) + ) ); + } + if ( ! empty( $this->reciprocal ) && 'ID' != $this->store_property ) { - throw new FM_Developer_Exception( __( 'You cannot use reciprocal relationships with FM_Datasource_User if store_property is not set to ID', 'fieldmanager' ) ); + throw new FM_Developer_Exception( __( 'You cannot use reciprocal relationships with FM_Datasource_User if store_property is not set to ID.', 'fieldmanager' ) ); } } From c9a694a461117a3be84da119637568266d2ec396 Mon Sep 17 00:00:00 2001 From: bcampeau Date: Wed, 14 Jan 2015 10:28:09 -0500 Subject: [PATCH 05/23] Sanitizing email --- php/datasource/class-fieldmanager-datasource-user.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/datasource/class-fieldmanager-datasource-user.php b/php/datasource/class-fieldmanager-datasource-user.php index eb2e8a1179..b74f588d7b 100644 --- a/php/datasource/class-fieldmanager-datasource-user.php +++ b/php/datasource/class-fieldmanager-datasource-user.php @@ -98,6 +98,7 @@ public function get_value( $value ) { break; case 'user_email': $field = 'email'; + $value = sanitize_email( $value ); break; case 'user_login': $field = 'login'; From 16fb9fee58561180f8ba9c64c608ef87f3ea9252 Mon Sep 17 00:00:00 2001 From: bcampeau Date: Wed, 14 Jan 2015 10:29:38 -0500 Subject: [PATCH 06/23] Improved formatting --- .../class-fieldmanager-datasource-user.php | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/php/datasource/class-fieldmanager-datasource-user.php b/php/datasource/class-fieldmanager-datasource-user.php index b74f588d7b..6907e4e91a 100644 --- a/php/datasource/class-fieldmanager-datasource-user.php +++ b/php/datasource/class-fieldmanager-datasource-user.php @@ -119,14 +119,17 @@ public function get_items( $fragment = Null ) { if ( is_callable( $this->query_callback ) ) { return call_user_func( $this->query_callback, $fragment ); } + $default_args = array(); $user_args = array_merge( $default_args, $this->query_args ); $ret = array(); + if ( $fragment ) $user_args['search'] = $fragment; $users = get_users( $user_args ); foreach ( $users as $u ) { $ret[ $u->{$this->store_property} ] = $u->{$this->display_property}; } + return $ret; } @@ -150,10 +153,14 @@ public function get_ajax_action() { * @param array $current_values existing post values */ public function presave_alter_values( Fieldmanager_Field $field, $values, $current_values ) { - if ( $field->data_type != 'post' || ! $this->reciprocal || 'ID' != $this->store_property ) return $values; + if ( $field->data_type != 'post' || ! $this->reciprocal || 'ID' != $this->store_property ) { + return $values; + } + foreach ( $current_values as $user_id ) { delete_user_meta( $user_id, $this->reciprocal, $field->data_id ); } + return $values; } @@ -164,12 +171,16 @@ public function presave_alter_values( Fieldmanager_Field $field, $values, $curre * @return string */ public function presave( Fieldmanager_Field $field, $value, $current_value ) { - if ( empty( $value ) ) return; + if ( empty( $value ) ) { + return; + } + $return_single = False; if ( !is_array( $value ) ) { $return_single = True; $value = array( $value ); } + foreach ( $value as $i => $v ) { $value[$i] = call_user_func( ( 'ID' == $this->store_property ) ? 'intval' : 'sanitize_text_field', $v ); if( ! current_user_can( $this->capability, $v ) ) { @@ -179,6 +190,7 @@ public function presave( Fieldmanager_Field $field, $value, $current_value ) { add_user_meta( $v, $this->reciprocal, $field->data_id ); } } + return $return_single ? $value[0] : $value; } From e0443edf19a325de2a466c04d7002d2a1f2809cf Mon Sep 17 00:00:00 2001 From: bcampeau Date: Wed, 14 Jan 2015 11:08:10 -0500 Subject: [PATCH 07/23] Updated copy pasta phpdoc --- .../class-fieldmanager-datasource-user.php | 44 ++++++++++++++----- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/php/datasource/class-fieldmanager-datasource-user.php b/php/datasource/class-fieldmanager-datasource-user.php index 6907e4e91a..a2812d60ed 100644 --- a/php/datasource/class-fieldmanager-datasource-user.php +++ b/php/datasource/class-fieldmanager-datasource-user.php @@ -4,7 +4,7 @@ */ /** - * Data source for WordPress Posts, for autocomplete and option types. + * Data source for WordPress Users, for autocomplete and option types. * @package Fieldmanager_Datasource */ class Fieldmanager_Datasource_User extends Fieldmanager_Datasource { @@ -57,7 +57,7 @@ class Fieldmanager_Datasource_User extends Fieldmanager_Datasource { /** * @var string|Null - * If not empty, set this post's ID as a value on the user. This is used to + * If not empty, set this object's ID as a value on the user. This is used to * establish two-way relationships. */ public $reciprocal = Null; @@ -83,27 +83,28 @@ public function __construct( $options = array() ) { } /** - * Get a post title by post ID + * Get a user by the specified field. * @param int $value post_id - * @return string post title + * @return WP_User */ public function get_value( $value ) { switch ( $this->store_property ) { case 'ID': $field = 'ID'; - $value = intval( $value ); break; case 'user_nicename': $field = 'slug'; break; case 'user_email': $field = 'email'; - $value = sanitize_email( $value ); break; case 'user_login': $field = 'login'; break; } + + // Sanitize the value + $value = $this->sanitize_value( $value ); $user = get_user_by( $field, $value ); return $user ? $user->{$this->display_property} : ''; @@ -147,7 +148,7 @@ public function get_ajax_action() { } /** - * For post relationships, delete reciprocal post metadata prior to saving (presave will re-add). + * Delete reciprocal user metadata prior to saving (presave will re-add). * Reciprocal relationships are not possible if we are not storing by ID. * @param array $values new post values * @param array $current_values existing post values @@ -165,7 +166,7 @@ public function presave_alter_values( Fieldmanager_Field $field, $values, $curre } /** - * Handle reciprocal postmeta. + * Handle reciprocal usermeta. * Reciprocal relationships are not possible if we are not storing by ID. * @param int $value * @return string @@ -182,7 +183,7 @@ public function presave( Fieldmanager_Field $field, $value, $current_value ) { } foreach ( $value as $i => $v ) { - $value[$i] = call_user_func( ( 'ID' == $this->store_property ) ? 'intval' : 'sanitize_text_field', $v ); + $value[$i] = $this->sanitize_value( $v ); if( ! current_user_can( $this->capability, $v ) ) { wp_die( esc_html( sprintf( __( 'Tried to refer to user "%s" which current user cannot edit.', 'fieldmanager' ), $v ) ) ); } @@ -195,7 +196,7 @@ public function presave( Fieldmanager_Field $field, $value, $current_value ) { } /** - * Get view link for a user + * Get view link for a user. * @param int $value * @return string */ @@ -204,7 +205,7 @@ public function get_view_link( $value ) { } /** - * Get edit link for a user + * Get edit link for a user. * @param int $value * @return string */ @@ -216,4 +217,25 @@ public function get_edit_link( $value ) { esc_html__( 'Edit', 'fieldmanager' ) ); } + + /** + * Sanitize the value based on store_property. + * @param int|string $value + * @return int|string + */ + private function sanitize_value( $value ) { + switch ( $this->store_property ) { + case 'ID': + $value = intval( $value ); + break; + case 'user_email': + $value = sanitize_email( $value ); + break; + default: + $value = sanitize_text_field( $value ); + break; + } + + return $value; + } } \ No newline at end of file From 1e9457b7fd11d491912a42734c22c431f7b4a6ec Mon Sep 17 00:00:00 2001 From: bcampeau Date: Wed, 14 Jan 2015 13:19:57 -0500 Subject: [PATCH 08/23] Added additional error check in datasource, added unit tests --- .../class-fieldmanager-datasource-user.php | 6 +- .../php/test-fieldmanager-datasource-user.php | 163 ++++++++++++++++++ 2 files changed, 167 insertions(+), 2 deletions(-) create mode 100644 tests/php/test-fieldmanager-datasource-user.php diff --git a/php/datasource/class-fieldmanager-datasource-user.php b/php/datasource/class-fieldmanager-datasource-user.php index a2812d60ed..8b49b570da 100644 --- a/php/datasource/class-fieldmanager-datasource-user.php +++ b/php/datasource/class-fieldmanager-datasource-user.php @@ -158,8 +158,10 @@ public function presave_alter_values( Fieldmanager_Field $field, $values, $curre return $values; } - foreach ( $current_values as $user_id ) { - delete_user_meta( $user_id, $this->reciprocal, $field->data_id ); + if ( ! empty( $current_values ) ) { + foreach ( $current_values as $user_id ) { + delete_user_meta( $user_id, $this->reciprocal, $field->data_id ); + } } return $values; diff --git a/tests/php/test-fieldmanager-datasource-user.php b/tests/php/test-fieldmanager-datasource-user.php new file mode 100644 index 0000000000..e8c885099c --- /dev/null +++ b/tests/php/test-fieldmanager-datasource-user.php @@ -0,0 +1,163 @@ +author = $this->factory->user->create( array( 'role' => 'author', 'user_login' => 'author' ) ); + $this->editor = $this->factory->user->create( array( 'role' => 'editor', 'user_login' => 'editor' ) ); + $this->administrator = $this->factory->user->create( array( 'role' => 'administrator', 'user_login' => 'administrator' ) ); + + wp_set_current_user( $this->administrator ); + + $this->post = $this->factory->post->create_and_get( array( + 'post_status' => 'draft', + 'post_content' => rand_str(), + 'post_title' => rand_str(), + 'post_author' => $this->author, + ) ); + } + + /** + * Set up the request environment values and save the data. + * + * @param Fieldmanager_Field $field + * @param WP_Post $post + * @param mixed $values + */ + public function save_values( $field, $post, $values ) { + $_POST = array( + 'post_ID' => $post->ID, + 'action' => 'editpost', + 'post_type' => $post->post_type, + "fieldmanager-{$field->name}-nonce" => wp_create_nonce( "fieldmanager-save-{$field->name}" ), + $field->name => $values, + ); + + $field->add_meta_box( $field->name, $post->post_type )->save_to_post_meta( $post->ID, $values ); + } + + /** + * Test that when configured to do so, child posts will store a reciprocal post ID in user meta. + */ + public function test_reciprocal_meta() { + $reciprocal = new Fieldmanager_Autocomplete( array( + 'name' => 'test_reciprocal', + 'datasource' => new Fieldmanager_Datasource_User( array( + 'reciprocal' => 'reciprocal_post', + ) ), + ) ); + + $this->assertEquals( null, get_user_meta( $this->author, 'reciprocal_post', true ) ); + + $this->save_values( $reciprocal, $this->post, $this->author ); + + $this->assertEquals( $this->author, get_post_meta( $this->post->ID, 'test_reciprocal', true ) ); + $this->assertEquals( $this->post->ID, get_user_meta( $this->author, 'reciprocal_post', true ) ); + } + + /** + * Test that various store properties work + */ + public function test_store_properties() { + $user = get_userdata( $this->author ); + + $store_id = new Fieldmanager_Autocomplete( array( + 'name' => 'test_store_id', + 'datasource' => new Fieldmanager_Datasource_User( array( + 'store_property' => 'ID', + ) ), + ) ); + + $this->save_values( $store_id, $this->post, $user->ID ); + $this->assertEquals( $user->ID, get_post_meta( $this->post->ID, 'test_store_id', true ) ); + + $store_user_login = new Fieldmanager_Autocomplete( array( + 'name' => 'test_store_user_login', + 'datasource' => new Fieldmanager_Datasource_User( array( + 'store_property' => 'user_login', + ) ), + ) ); + + $this->save_values( $store_user_login, $this->post, $user->user_login ); + $this->assertEquals( $user->user_login, get_post_meta( $this->post->ID, 'test_store_user_login', true ) ); + + $store_user_email = new Fieldmanager_Autocomplete( array( + 'name' => 'test_store_user_email', + 'datasource' => new Fieldmanager_Datasource_User( array( + 'store_property' => 'user_email', + ) ), + ) ); + + $this->save_values( $store_user_email, $this->post, $user->user_email ); + $this->assertEquals( $user->user_email, get_post_meta( $this->post->ID, 'test_store_user_email', true ) ); + + $store_user_nicename = new Fieldmanager_Autocomplete( array( + 'name' => 'test_store_user_nicename', + 'datasource' => new Fieldmanager_Datasource_User( array( + 'store_property' => 'user_nicename', + ) ), + ) ); + + $this->save_values( $store_user_nicename, $this->post, $user->user_nicename ); + $this->assertEquals( $user->user_nicename, get_post_meta( $this->post->ID, 'test_store_user_nicename', true ) ); + } + + /** + * Test creating a field with an invalid store property. + * @expectedException FM_Developer_Exception + */ + public function test_save_invalid_store_property() { + $test_invalid = new Fieldmanager_Autocomplete( array( + 'name' => 'test_invalid', + 'datasource' => new Fieldmanager_Datasource_User( array( + 'store_property' => 'invalid', + ) ), + ) ); + + $this->save_values( $test_invalid, $this->post, $this->author ); + } + + /** + * Test that we fail when trying to use reciprocals with something other than ID as a store property. + * @expectedException FM_Developer_Exception + */ + public function test_save_invalid_reciprocal() { + $test_invalid = new Fieldmanager_Autocomplete( array( + 'name' => 'test_invalid', + 'datasource' => new Fieldmanager_Datasource_User( array( + 'store_property' => 'user_login', + 'reciprocal' => 'some_field', + ) ), + ) ); + + $this->save_values( $test_invalid, $this->post, $this->author ); + } + + /** + * Test that this fails when a user doesn't have permission to list users. + * @expectedException WPDieException + */ + public function test_save_permissions() { + wp_set_current_user( $this->author ); + + $test_invalid = new Fieldmanager_Autocomplete( array( + 'name' => 'test_invalid', + 'datasource' => new Fieldmanager_Datasource_User(), + ) ); + + $this->save_values( $test_invalid, $this->post, $this->editor ); + + wp_set_current_user( $this->author ); + + $this->save_values( $test_invalid, $this->post, $this->editor ); + } +} From d32222afda11235e1de006d223fff9511d76317c Mon Sep 17 00:00:00 2001 From: bcampeau Date: Wed, 14 Jan 2015 13:23:45 -0500 Subject: [PATCH 09/23] Fixed phpdoc --- tests/php/test-fieldmanager-datasource-user.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/php/test-fieldmanager-datasource-user.php b/tests/php/test-fieldmanager-datasource-user.php index e8c885099c..43916995f6 100644 --- a/tests/php/test-fieldmanager-datasource-user.php +++ b/tests/php/test-fieldmanager-datasource-user.php @@ -4,7 +4,7 @@ * Tests the Fieldmanager Datasource User * * @group datasource - * @group post + * @group user */ class Test_Fieldmanager_Datasource_User extends WP_UnitTestCase { From 526af5f6289a6356996ffafaa0261b80a51cb045 Mon Sep 17 00:00:00 2001 From: bcampeau Date: Wed, 14 Jan 2015 13:25:46 -0500 Subject: [PATCH 10/23] Fixed phpdoc --- php/datasource/class-fieldmanager-datasource-user.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/datasource/class-fieldmanager-datasource-user.php b/php/datasource/class-fieldmanager-datasource-user.php index 8b49b570da..d1c0a09cf7 100644 --- a/php/datasource/class-fieldmanager-datasource-user.php +++ b/php/datasource/class-fieldmanager-datasource-user.php @@ -85,7 +85,7 @@ public function __construct( $options = array() ) { /** * Get a user by the specified field. * @param int $value post_id - * @return WP_User + * @return int|string */ public function get_value( $value ) { switch ( $this->store_property ) { From 0ab07fe8ef0ea127e0fd07fd1c58068749973130 Mon Sep 17 00:00:00 2001 From: bcampeau Date: Wed, 14 Jan 2015 13:27:51 -0500 Subject: [PATCH 11/23] Switched validation to protected --- php/datasource/class-fieldmanager-datasource-user.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/datasource/class-fieldmanager-datasource-user.php b/php/datasource/class-fieldmanager-datasource-user.php index d1c0a09cf7..c88cca21fd 100644 --- a/php/datasource/class-fieldmanager-datasource-user.php +++ b/php/datasource/class-fieldmanager-datasource-user.php @@ -225,7 +225,7 @@ public function get_edit_link( $value ) { * @param int|string $value * @return int|string */ - private function sanitize_value( $value ) { + protected function sanitize_value( $value ) { switch ( $this->store_property ) { case 'ID': $value = intval( $value ); From e3ab6d3e8a53c743bf1735d3f0e8e8cafb9c64d1 Mon Sep 17 00:00:00 2001 From: bcampeau Date: Wed, 14 Jan 2015 13:31:42 -0500 Subject: [PATCH 12/23] Updated allowed store properties to be protected --- php/datasource/class-fieldmanager-datasource-user.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/datasource/class-fieldmanager-datasource-user.php b/php/datasource/class-fieldmanager-datasource-user.php index c88cca21fd..7f90452697 100644 --- a/php/datasource/class-fieldmanager-datasource-user.php +++ b/php/datasource/class-fieldmanager-datasource-user.php @@ -46,7 +46,7 @@ class Fieldmanager_Datasource_User extends Fieldmanager_Datasource { * @var array * Allowed store properties for validation. */ - private $allowed_store_properties = array( 'ID', 'user_login', 'user_email', 'user_nicename' ); + protected $allowed_store_properties = array( 'ID', 'user_login', 'user_email', 'user_nicename' ); /** * @var string From 59db903a9dd22a60116913a829cf8077497e5a7d Mon Sep 17 00:00:00 2001 From: bcampeau Date: Wed, 14 Jan 2015 13:34:06 -0500 Subject: [PATCH 13/23] Updated indentation --- .../class-fieldmanager-datasource-user.php | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/php/datasource/class-fieldmanager-datasource-user.php b/php/datasource/class-fieldmanager-datasource-user.php index 7f90452697..116e06561c 100644 --- a/php/datasource/class-fieldmanager-datasource-user.php +++ b/php/datasource/class-fieldmanager-datasource-user.php @@ -46,7 +46,7 @@ class Fieldmanager_Datasource_User extends Fieldmanager_Datasource { * @var array * Allowed store properties for validation. */ - protected $allowed_store_properties = array( 'ID', 'user_login', 'user_email', 'user_nicename' ); + private $allowed_store_properties = array( 'ID', 'user_login', 'user_email', 'user_nicename' ); /** * @var string @@ -89,25 +89,25 @@ public function __construct( $options = array() ) { */ public function get_value( $value ) { switch ( $this->store_property ) { - case 'ID': - $field = 'ID'; - break; - case 'user_nicename': - $field = 'slug'; - break; - case 'user_email': - $field = 'email'; - break; - case 'user_login': - $field = 'login'; - break; + case 'ID': + $field = 'ID'; + break; + case 'user_nicename': + $field = 'slug'; + break; + case 'user_email': + $field = 'email'; + break; + case 'user_login': + $field = 'login'; + break; } - // Sanitize the value - $value = $this->sanitize_value( $value ); - - $user = get_user_by( $field, $value ); - return $user ? $user->{$this->display_property} : ''; + // Sanitize the value + $value = $this->sanitize_value( $value ); + + $user = get_user_by( $field, $value ); + return $user ? $user->{$this->display_property} : ''; } /** @@ -154,15 +154,15 @@ public function get_ajax_action() { * @param array $current_values existing post values */ public function presave_alter_values( Fieldmanager_Field $field, $values, $current_values ) { - if ( $field->data_type != 'post' || ! $this->reciprocal || 'ID' != $this->store_property ) { - return $values; - } - - if ( ! empty( $current_values ) ) { - foreach ( $current_values as $user_id ) { - delete_user_meta( $user_id, $this->reciprocal, $field->data_id ); - } - } + if ( $field->data_type != 'post' || ! $this->reciprocal || 'ID' != $this->store_property ) { + return $values; + } + + if ( ! empty( $current_values ) ) { + foreach ( $current_values as $user_id ) { + delete_user_meta( $user_id, $this->reciprocal, $field->data_id ); + } + } return $values; } @@ -227,15 +227,15 @@ public function get_edit_link( $value ) { */ protected function sanitize_value( $value ) { switch ( $this->store_property ) { - case 'ID': - $value = intval( $value ); - break; - case 'user_email': - $value = sanitize_email( $value ); - break; - default: - $value = sanitize_text_field( $value ); - break; + case 'ID': + $value = intval( $value ); + break; + case 'user_email': + $value = sanitize_email( $value ); + break; + default: + $value = sanitize_text_field( $value ); + break; } return $value; From bf755f483c65eeced260d0bed51e1e35483e83d9 Mon Sep 17 00:00:00 2001 From: bcampeau Date: Wed, 14 Jan 2015 13:34:36 -0500 Subject: [PATCH 14/23] Updated allowed store properties to be protected --- php/datasource/class-fieldmanager-datasource-user.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/datasource/class-fieldmanager-datasource-user.php b/php/datasource/class-fieldmanager-datasource-user.php index 116e06561c..213bf27d88 100644 --- a/php/datasource/class-fieldmanager-datasource-user.php +++ b/php/datasource/class-fieldmanager-datasource-user.php @@ -46,7 +46,7 @@ class Fieldmanager_Datasource_User extends Fieldmanager_Datasource { * @var array * Allowed store properties for validation. */ - private $allowed_store_properties = array( 'ID', 'user_login', 'user_email', 'user_nicename' ); + protected $allowed_store_properties = array( 'ID', 'user_login', 'user_email', 'user_nicename' ); /** * @var string From f4948d8677c6f109394c6efd54b28876a8f68b18 Mon Sep 17 00:00:00 2001 From: bcampeau Date: Wed, 14 Jan 2015 14:01:36 -0500 Subject: [PATCH 15/23] Added validation for display property, added tests --- .../class-fieldmanager-datasource-user.php | 20 +++++- .../php/test-fieldmanager-datasource-user.php | 64 ++++++++++++++++++- 2 files changed, 82 insertions(+), 2 deletions(-) diff --git a/php/datasource/class-fieldmanager-datasource-user.php b/php/datasource/class-fieldmanager-datasource-user.php index 213bf27d88..d672d77ef8 100644 --- a/php/datasource/class-fieldmanager-datasource-user.php +++ b/php/datasource/class-fieldmanager-datasource-user.php @@ -35,6 +35,12 @@ class Fieldmanager_Datasource_User extends Fieldmanager_Datasource { */ public $display_property = 'display_name'; + /** + * @var array + * Allowed display properties for validation. + */ + protected $allowed_display_properties = array( 'display_name', 'user_login', 'user_email', 'user_nicename' ); + /** * @var string * Store property. Defaults to ID, but can also be 'user_login', 'user_email', @@ -80,6 +86,15 @@ public function __construct( $options = array() ) { if ( ! empty( $this->reciprocal ) && 'ID' != $this->store_property ) { throw new FM_Developer_Exception( __( 'You cannot use reciprocal relationships with FM_Datasource_User if store_property is not set to ID.', 'fieldmanager' ) ); } + + // Validate improper usage of display property + if ( ! in_array( $this->display_property, $this->allowed_display_properties ) ) { + throw new FM_Developer_Exception( sprintf( + __( 'Display property %s is invalid. Must be one of %s.', 'fieldmanager' ), + $this->display_property, + implode( ', ', $this->allowed_display_properties ) + ) ); + } } /** @@ -125,7 +140,10 @@ public function get_items( $fragment = Null ) { $user_args = array_merge( $default_args, $this->query_args ); $ret = array(); - if ( $fragment ) $user_args['search'] = $fragment; + if ( $fragment ) { + $user_args['search'] = $fragment; + } + $users = get_users( $user_args ); foreach ( $users as $u ) { $ret[ $u->{$this->store_property} ] = $u->{$this->display_property}; diff --git a/tests/php/test-fieldmanager-datasource-user.php b/tests/php/test-fieldmanager-datasource-user.php index 43916995f6..e0b942a908 100644 --- a/tests/php/test-fieldmanager-datasource-user.php +++ b/tests/php/test-fieldmanager-datasource-user.php @@ -12,7 +12,7 @@ public function setUp() { parent::setUp(); Fieldmanager_Field::$debug = true; - $this->author = $this->factory->user->create( array( 'role' => 'author', 'user_login' => 'author' ) ); + $this->author = $this->factory->user->create( array( 'role' => 'author', 'user_login' => 'author', 'user_email' => 'test@test.com' ) ); $this->editor = $this->factory->user->create( array( 'role' => 'editor', 'user_login' => 'editor' ) ); $this->administrator = $this->factory->user->create( array( 'role' => 'administrator', 'user_login' => 'administrator' ) ); @@ -126,6 +126,21 @@ public function test_save_invalid_store_property() { $this->save_values( $test_invalid, $this->post, $this->author ); } + /** + * Test creating a field with an invalid display property. + * @expectedException FM_Developer_Exception + */ + public function test_save_invalid_display_property() { + $test_invalid = new Fieldmanager_Autocomplete( array( + 'name' => 'test_invalid', + 'datasource' => new Fieldmanager_Datasource_User( array( + 'display_property' => 'invalid', + ) ), + ) ); + + $this->save_values( $test_invalid, $this->post, $this->author ); + } + /** * Test that we fail when trying to use reciprocals with something other than ID as a store property. * @expectedException FM_Developer_Exception @@ -160,4 +175,51 @@ public function test_save_permissions() { $this->save_values( $test_invalid, $this->post, $this->editor ); } + + /** + * Test that display property returns the correct value in all reasonable cases. + */ + public function test_display_properties() { + $user = get_userdata( $this->author ); + + $test_display_name = new Fieldmanager_Autocomplete( array( + 'name' => 'test_display_name', + 'datasource' => new Fieldmanager_Datasource_User( array( + 'display_property' => 'display_name', + ) ), + ) ); + + $test_users_display_name = $test_display_name->datasource->get_items( $user->user_login ); + $this->assertEquals( $user->display_name, $test_users_display_name[ $user->ID ] ); + + $test_user_login = new Fieldmanager_Autocomplete( array( + 'name' => 'test_user_login', + 'datasource' => new Fieldmanager_Datasource_User( array( + 'display_property' => 'user_login', + ) ), + ) ); + + $test_users_user_login = $test_user_login->datasource->get_items( $user->user_login ); + $this->assertEquals( $user->user_login, $test_users_user_login[ $user->ID ] ); + + $test_user_email = new Fieldmanager_Autocomplete( array( + 'name' => 'test_user_email', + 'datasource' => new Fieldmanager_Datasource_User( array( + 'display_property' => 'user_email', + ) ), + ) ); + + $test_users_user_email = $test_user_email->datasource->get_items( $user->user_login ); + $this->assertEquals( $user->user_email, $test_users_user_email[ $user->ID ] ); + + $test_user_nicename = new Fieldmanager_Autocomplete( array( + 'name' => 'test_user_nicename', + 'datasource' => new Fieldmanager_Datasource_User( array( + 'display_property' => 'user_nicename', + ) ), + ) ); + + $test_users_user_nicename = $test_user_nicename->datasource->get_items( $user->user_login ); + $this->assertEquals( $user->user_nicename, $test_users_user_nicename[ $user->ID ] ); + } } From f4203b09ef40390a4d69b79e8c57fd83bedeae8e Mon Sep 17 00:00:00 2001 From: bcampeau Date: Wed, 14 Jan 2015 14:15:34 -0500 Subject: [PATCH 16/23] Added tests --- .../php/test-fieldmanager-datasource-term.php | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/php/test-fieldmanager-datasource-term.php b/tests/php/test-fieldmanager-datasource-term.php index 3811257cfa..ab5e759be4 100644 --- a/tests/php/test-fieldmanager-datasource-term.php +++ b/tests/php/test-fieldmanager-datasource-term.php @@ -196,6 +196,39 @@ public function test_datasource_term_save_empty() { $post_terms = wp_get_post_terms( $this->post->ID, $this->term->taxonomy, array( 'fields' => 'names' ) ); $this->assertCount( 0, $post_terms ); } + + /** + * Test behavior when set to save only to taxonomy and not append. + * Ensure that all terms are removed in this case. + * This has a specific use case for Fieldmanager_Checkboxes so testing there. + * However, this applies to all field types that can create this scenario. + */ + public function test_datasource_term_save_to_taxonomy_empty() { + $term_taxonomy = new Fieldmanager_Checkboxes( array( + 'name' => 'test_terms', + 'limit' => 0, + 'datasource' => new Fieldmanager_Datasource_Term( array( + 'taxonomy' => $this->term->taxonomy, + 'only_save_to_taxonomy' => true, + 'append_taxonomy' => false, + ) ), + ) ); + + $term = $this->factory->tag->create_and_get( array( 'name' => rand_str() ) ); + $terms = array( $this->term->term_id, $term->term_id ); + + $this->save_values( $term_taxonomy, $this->post, $terms ); + + $post_terms = wp_get_post_terms( $this->post->ID, $this->term->taxonomy, array( 'fields' => 'ids' ) ); + $this->assertSame( $terms, $post_terms ); + + $terms = array(); + $this->save_values( $term_taxonomy, $this->post, $terms ); + + $post_terms = wp_get_post_terms( $this->post->ID, $this->term->taxonomy, array( 'fields' => 'ids' ) ); + $this->assertSame( $terms, $post_terms ); + + } /** * Test behavior when only saving to taxonomy within a single repeating From 411a49e031de7085b47a04a94d30699ca84b1374 Mon Sep 17 00:00:00 2001 From: bcampeau Date: Wed, 14 Jan 2015 14:26:54 -0500 Subject: [PATCH 17/23] Added test for display of store property --- .../php/test-fieldmanager-datasource-user.php | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tests/php/test-fieldmanager-datasource-user.php b/tests/php/test-fieldmanager-datasource-user.php index e0b942a908..93d0d323b7 100644 --- a/tests/php/test-fieldmanager-datasource-user.php +++ b/tests/php/test-fieldmanager-datasource-user.php @@ -222,4 +222,51 @@ public function test_display_properties() { $test_users_user_nicename = $test_user_nicename->datasource->get_items( $user->user_login ); $this->assertEquals( $user->user_nicename, $test_users_user_nicename[ $user->ID ] ); } + + /** + * Test that store property returns the correct display value in all reasonable cases. + */ + public function test_store_property_display() { + $user = get_userdata( $this->author ); + + $test_id = new Fieldmanager_Autocomplete( array( + 'name' => 'test_display_name', + 'datasource' => new Fieldmanager_Datasource_User( array( + 'store_property' => 'ID', + ) ), + ) ); + + $test_users_id = $test_id->datasource->get_items( $user->user_login ); + $this->assertEquals( $user->display_name, $test_users_id[ $user->ID ] ); + + $test_user_login = new Fieldmanager_Autocomplete( array( + 'name' => 'test_user_login', + 'datasource' => new Fieldmanager_Datasource_User( array( + 'store_property' => 'user_login', + ) ), + ) ); + + $test_users_user_login = $test_user_login->datasource->get_items( $user->user_login ); + $this->assertEquals( $user->display_name, $test_users_user_login[ $user->user_login ] ); + + $test_user_email = new Fieldmanager_Autocomplete( array( + 'name' => 'test_user_email', + 'datasource' => new Fieldmanager_Datasource_User( array( + 'store_property' => 'user_email', + ) ), + ) ); + + $test_users_user_email = $test_user_email->datasource->get_items( $user->user_login ); + $this->assertEquals( $user->display_name, $test_users_user_email[ $user->user_email ] ); + + $test_user_nicename = new Fieldmanager_Autocomplete( array( + 'name' => 'test_user_nicename', + 'datasource' => new Fieldmanager_Datasource_User( array( + 'store_property' => 'user_nicename', + ) ), + ) ); + + $test_users_user_nicename = $test_user_nicename->datasource->get_items( $user->user_login ); + $this->assertEquals( $user->display_name, $test_users_user_nicename[ $user->user_nicename ] ); + } } From a3190eed285fe0c8d1f538da37ca5ac7bff1caed Mon Sep 17 00:00:00 2001 From: Noah Schoenholtz Date: Wed, 14 Jan 2015 14:34:07 -0500 Subject: [PATCH 18/23] added tests --- .../test-fieldmanager-checkboxes-field.php | 172 ++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 tests/php/test-fieldmanager-checkboxes-field.php diff --git a/tests/php/test-fieldmanager-checkboxes-field.php b/tests/php/test-fieldmanager-checkboxes-field.php new file mode 100644 index 0000000000..f7bb0e53d1 --- /dev/null +++ b/tests/php/test-fieldmanager-checkboxes-field.php @@ -0,0 +1,172 @@ +post_id = $this->factory->post->create( array( 'post_title' => rand_str(), 'post_date' => '2009-07-01 00:00:00' ) ); + $this->post = get_post( $this->post_id ); + + $this->custom_datasource = new Fieldmanager_Datasource( array( + 'options' => array( 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ) + ) ); + } + + /** + * Helper which returns the post meta box HTML for a given field; + * + * @param object $field Some Fieldmanager_Field object. + * @param array $test_data Data to save (and use when rendering) + * @return string Rendered HTML + */ + private function _get_html_for( $field, $test_data = null ) { + ob_start(); + $context = $field->add_meta_box( 'test meta box', $this->post ); + if ( $test_data ) { + $context->save_to_post_meta( $this->post_id, $test_data ); + } + $context->render_meta_box( $this->post ); + return ob_get_clean(); + } + + private function _get_input_field_regex( $name, $value, $checked = false ) { + if ( is_array( $value ) ) { + $v = array_keys( $value ); + $v = $v[0]; + $label = $value[ $v ]; + $value = $v; + } else { + $label = $value; + } + + return sprintf( '#' + . '\s*\s*%3$s\s*#si', + $name, $value, $label ); + } + + public function test_basic_render() { + $fm = new Fieldmanager_Checkboxes( array( + 'name' => 'base_field', + 'options' => array( 'one', 'two', 'three' ), + ) ); + + $html = $this->_get_html_for( $fm ); + + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'one' ), $html ); + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'two' ), $html ); + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'three' ), $html ); + } + + public function test_basic_save() { + $fm = new Fieldmanager_Checkboxes( array( + 'name' => 'base_field', + 'options' => array( 'one', 'two', 'three' ), + ) ); + + $html = $this->_get_html_for( $fm, array( 'two' ) ); + + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'one' ), $html ); + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'two', true ), $html ); + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'three' ), $html ); + } + + public function test_associative_render() { + $fm = new Fieldmanager_Checkboxes( array( + 'name' => 'base_field', + 'options' => array( 1 => 'one', 2 => 'two', 3 => 'three' ), + ) ); + + $html = $this->_get_html_for( $fm ); + + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', array( 1 => 'one' ) ), $html ); + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', array( 2 => 'two' ) ), $html ); + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', array( 3 => 'three' ) ), $html ); + + $html = $this->_get_html_for( $fm, array( 2 ) ); + + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', array( 1 => 'one' ) ), $html ); + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', array( 2 => 'two' ), true ), $html ); + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', array( 3 => 'three' ) ), $html ); + } + + public function test_default_value() { + $fm = new Fieldmanager_Checkboxes( array( + 'name' => 'base_field', + 'options' => array( 'one', 'two', 'three' ), + 'default_value' => 'two', + ) ); + + $html = $this->_get_html_for( $fm ); + + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'one' ), $html ); + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'two', true ), $html ); + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'three' ), $html ); + } + + public function test_datasource() { + $fm = new Fieldmanager_Checkboxes( array( + 'name' => 'base_field', + 'datasource' => $this->custom_datasource, + ) ); + + $html = $this->_get_html_for( $fm ); + + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'January' ), $html ); + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'February' ), $html ); + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'December' ), $html ); + } + + public function test_datasource_default_value() { + $fm = new Fieldmanager_Checkboxes( array( + 'name' => 'base_field', + 'default_value' => 'February', + 'datasource' => $this->custom_datasource, + ) ); + + $html = $this->_get_html_for( $fm ); + + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'January' ), $html ); + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'February', true ), $html ); + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'December' ), $html ); + } + + public function test_datasource_save() { + $fm = new Fieldmanager_Checkboxes( array( + 'name' => 'base_field', + 'datasource' => $this->custom_datasource, + ) ); + + $html = $this->_get_html_for( $fm, 'February' ); + + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'January' ), $html ); + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'February', true ), $html ); + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'December' ), $html ); + } + + public function test_datasource_default_value_all() { + $fm = new Fieldmanager_Checkboxes( array( + 'name' => 'base_field', + 'default_value' => 'checked', + 'datasource' => $this->custom_datasource, + ) ); + + $html = $this->_get_html_for( $fm ); + + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'January', true ), $html ); + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'February', true ), $html ); + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'December', true ), $html ); + } + +} From 2ddf9d9db80d1c7c210de167d12e23deefd0b136 Mon Sep 17 00:00:00 2001 From: Noah Schoenholtz Date: Wed, 14 Jan 2015 14:46:12 -0500 Subject: [PATCH 19/23] improved tests --- .../test-fieldmanager-checkboxes-field.php | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/php/test-fieldmanager-checkboxes-field.php b/tests/php/test-fieldmanager-checkboxes-field.php index f7bb0e53d1..381f411b5a 100644 --- a/tests/php/test-fieldmanager-checkboxes-field.php +++ b/tests/php/test-fieldmanager-checkboxes-field.php @@ -18,9 +18,9 @@ public function setUp() { $this->post_id = $this->factory->post->create( array( 'post_title' => rand_str(), 'post_date' => '2009-07-01 00:00:00' ) ); $this->post = get_post( $this->post_id ); - $this->custom_datasource = new Fieldmanager_Datasource( array( - 'options' => array( 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ) - ) ); + $this->months = array( 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ); + + $this->custom_datasource = new Fieldmanager_Datasource( array( 'options' => $this->months ) ); } /** @@ -123,9 +123,9 @@ public function test_datasource() { $html = $this->_get_html_for( $fm ); - $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'January' ), $html ); - $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'February' ), $html ); - $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'December' ), $html ); + foreach ( $this->months as $month ) { + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', $month ), $html ); + } } public function test_datasource_default_value() { @@ -137,9 +137,9 @@ public function test_datasource_default_value() { $html = $this->_get_html_for( $fm ); - $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'January' ), $html ); - $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'February', true ), $html ); - $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'December' ), $html ); + foreach ( $this->months as $month ) { + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', $month, ( 'February' === $month ) ), $html ); + } } public function test_datasource_save() { @@ -150,9 +150,9 @@ public function test_datasource_save() { $html = $this->_get_html_for( $fm, 'February' ); - $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'January' ), $html ); - $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'February', true ), $html ); - $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'December' ), $html ); + foreach ( $this->months as $month ) { + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', $month, ( 'February' === $month ) ), $html ); + } } public function test_datasource_default_value_all() { @@ -164,9 +164,9 @@ public function test_datasource_default_value_all() { $html = $this->_get_html_for( $fm ); - $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'January', true ), $html ); - $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'February', true ), $html ); - $this->assertRegExp( $this->_get_input_field_regex( 'base_field', 'December', true ), $html ); + foreach ( $this->months as $month ) { + $this->assertRegExp( $this->_get_input_field_regex( 'base_field', $month, true ), $html ); + } } } From e20e72a48dd53ce9d1f27b9eea2d00d3d5ba8fe4 Mon Sep 17 00:00:00 2001 From: bcampeau Date: Wed, 14 Jan 2015 14:49:44 -0500 Subject: [PATCH 20/23] Also testing get_value for store_property --- tests/php/test-fieldmanager-datasource-user.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/php/test-fieldmanager-datasource-user.php b/tests/php/test-fieldmanager-datasource-user.php index 93d0d323b7..27b06d26ae 100644 --- a/tests/php/test-fieldmanager-datasource-user.php +++ b/tests/php/test-fieldmanager-datasource-user.php @@ -238,6 +238,7 @@ public function test_store_property_display() { $test_users_id = $test_id->datasource->get_items( $user->user_login ); $this->assertEquals( $user->display_name, $test_users_id[ $user->ID ] ); + $this->assertEquals( $user->display_name, $test_id->datasource->get_value( $user->ID ) ); $test_user_login = new Fieldmanager_Autocomplete( array( 'name' => 'test_user_login', @@ -248,6 +249,7 @@ public function test_store_property_display() { $test_users_user_login = $test_user_login->datasource->get_items( $user->user_login ); $this->assertEquals( $user->display_name, $test_users_user_login[ $user->user_login ] ); + $this->assertEquals( $user->display_name, $test_user_login->datasource->get_value( $user->user_login ) ); $test_user_email = new Fieldmanager_Autocomplete( array( 'name' => 'test_user_email', @@ -258,6 +260,7 @@ public function test_store_property_display() { $test_users_user_email = $test_user_email->datasource->get_items( $user->user_login ); $this->assertEquals( $user->display_name, $test_users_user_email[ $user->user_email ] ); + $this->assertEquals( $user->display_name, $test_user_email->datasource->get_value( $user->user_email ) ); $test_user_nicename = new Fieldmanager_Autocomplete( array( 'name' => 'test_user_nicename', @@ -268,5 +271,6 @@ public function test_store_property_display() { $test_users_user_nicename = $test_user_nicename->datasource->get_items( $user->user_login ); $this->assertEquals( $user->display_name, $test_users_user_nicename[ $user->user_nicename ] ); + $this->assertEquals( $user->display_name, $test_user_nicename->datasource->get_value( $user->user_nicename ) ); } } From a4f2665a59269afb6d62e649ce156f4603d88ae2 Mon Sep 17 00:00:00 2001 From: bcampeau Date: Wed, 14 Jan 2015 14:50:36 -0500 Subject: [PATCH 21/23] Added sorting to prevent failure if array contained same IDs but in a different order --- tests/php/test-fieldmanager-datasource-term.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/php/test-fieldmanager-datasource-term.php b/tests/php/test-fieldmanager-datasource-term.php index ab5e759be4..fc3cc0e3b5 100644 --- a/tests/php/test-fieldmanager-datasource-term.php +++ b/tests/php/test-fieldmanager-datasource-term.php @@ -220,7 +220,7 @@ public function test_datasource_term_save_to_taxonomy_empty() { $this->save_values( $term_taxonomy, $this->post, $terms ); $post_terms = wp_get_post_terms( $this->post->ID, $this->term->taxonomy, array( 'fields' => 'ids' ) ); - $this->assertSame( $terms, $post_terms ); + $this->assertSame( sort( $terms ), sort( $post_terms ) ); $terms = array(); $this->save_values( $term_taxonomy, $this->post, $terms ); From 3ce7b3e470c95df9e527a72662d86be88804875b Mon Sep 17 00:00:00 2001 From: Noah Schoenholtz Date: Wed, 14 Jan 2015 16:06:44 -0500 Subject: [PATCH 22/23] fixed duh error that was breaking test_datasource_save --- tests/php/test-fieldmanager-checkboxes-field.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/php/test-fieldmanager-checkboxes-field.php b/tests/php/test-fieldmanager-checkboxes-field.php index 381f411b5a..15ac1290f1 100644 --- a/tests/php/test-fieldmanager-checkboxes-field.php +++ b/tests/php/test-fieldmanager-checkboxes-field.php @@ -148,7 +148,7 @@ public function test_datasource_save() { 'datasource' => $this->custom_datasource, ) ); - $html = $this->_get_html_for( $fm, 'February' ); + $html = $this->_get_html_for( $fm, array( 'February' ) ); foreach ( $this->months as $month ) { $this->assertRegExp( $this->_get_input_field_regex( 'base_field', $month, ( 'February' === $month ) ), $html ); From 70b16e6fd8fec0f9271c40ff508cb24c0c55905d Mon Sep 17 00:00:00 2001 From: Noah Schoenholtz Date: Wed, 14 Jan 2015 17:38:41 -0500 Subject: [PATCH 23/23] fixed user by id lookup --- .../class-fieldmanager-datasource-user.php | 42 +++++++++--------- .../php/test-fieldmanager-datasource-user.php | 44 +++++++++---------- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/php/datasource/class-fieldmanager-datasource-user.php b/php/datasource/class-fieldmanager-datasource-user.php index d672d77ef8..ffacb71f31 100644 --- a/php/datasource/class-fieldmanager-datasource-user.php +++ b/php/datasource/class-fieldmanager-datasource-user.php @@ -34,20 +34,20 @@ class Fieldmanager_Datasource_User extends Fieldmanager_Datasource { * or 'user_nicename' */ public $display_property = 'display_name'; - + /** * @var array * Allowed display properties for validation. */ protected $allowed_display_properties = array( 'display_name', 'user_login', 'user_email', 'user_nicename' ); - + /** * @var string * Store property. Defaults to ID, but can also be 'user_login', 'user_email', * or 'user_nicename'. */ public $store_property = 'ID'; - + /** * @var array * Allowed store properties for validation. @@ -73,23 +73,23 @@ class Fieldmanager_Datasource_User extends Fieldmanager_Datasource { */ public function __construct( $options = array() ) { parent::__construct( $options ); - + // Validate improper usage of store property if ( ! in_array( $this->store_property, $this->allowed_store_properties ) ) { - throw new FM_Developer_Exception( sprintf( + throw new FM_Developer_Exception( sprintf( __( 'Store property %s is invalid. Must be one of %s.', 'fieldmanager' ), $this->store_property, implode( ', ', $this->allowed_store_properties ) ) ); } - + if ( ! empty( $this->reciprocal ) && 'ID' != $this->store_property ) { throw new FM_Developer_Exception( __( 'You cannot use reciprocal relationships with FM_Datasource_User if store_property is not set to ID.', 'fieldmanager' ) ); } - + // Validate improper usage of display property if ( ! in_array( $this->display_property, $this->allowed_display_properties ) ) { - throw new FM_Developer_Exception( sprintf( + throw new FM_Developer_Exception( sprintf( __( 'Display property %s is invalid. Must be one of %s.', 'fieldmanager' ), $this->display_property, implode( ', ', $this->allowed_display_properties ) @@ -105,7 +105,7 @@ public function __construct( $options = array() ) { public function get_value( $value ) { switch ( $this->store_property ) { case 'ID': - $field = 'ID'; + $field = 'id'; break; case 'user_nicename': $field = 'slug'; @@ -117,7 +117,7 @@ public function get_value( $value ) { $field = 'login'; break; } - + // Sanitize the value $value = $this->sanitize_value( $value ); @@ -135,20 +135,20 @@ public function get_items( $fragment = Null ) { if ( is_callable( $this->query_callback ) ) { return call_user_func( $this->query_callback, $fragment ); } - + $default_args = array(); $user_args = array_merge( $default_args, $this->query_args ); $ret = array(); - + if ( $fragment ) { $user_args['search'] = $fragment; } - + $users = get_users( $user_args ); foreach ( $users as $u ) { $ret[ $u->{$this->store_property} ] = $u->{$this->display_property}; } - + return $ret; } @@ -181,7 +181,7 @@ public function presave_alter_values( Fieldmanager_Field $field, $values, $curre delete_user_meta( $user_id, $this->reciprocal, $field->data_id ); } } - + return $values; } @@ -195,13 +195,13 @@ public function presave( Fieldmanager_Field $field, $value, $current_value ) { if ( empty( $value ) ) { return; } - + $return_single = False; if ( !is_array( $value ) ) { $return_single = True; $value = array( $value ); } - + foreach ( $value as $i => $v ) { $value[$i] = $this->sanitize_value( $v ); if( ! current_user_can( $this->capability, $v ) ) { @@ -211,7 +211,7 @@ public function presave( Fieldmanager_Field $field, $value, $current_value ) { add_user_meta( $v, $this->reciprocal, $field->data_id ); } } - + return $return_single ? $value[0] : $value; } @@ -237,7 +237,7 @@ public function get_edit_link( $value ) { esc_html__( 'Edit', 'fieldmanager' ) ); } - + /** * Sanitize the value based on store_property. * @param int|string $value @@ -255,7 +255,7 @@ protected function sanitize_value( $value ) { $value = sanitize_text_field( $value ); break; } - + return $value; } -} \ No newline at end of file +} diff --git a/tests/php/test-fieldmanager-datasource-user.php b/tests/php/test-fieldmanager-datasource-user.php index 27b06d26ae..11fe5f2702 100644 --- a/tests/php/test-fieldmanager-datasource-user.php +++ b/tests/php/test-fieldmanager-datasource-user.php @@ -63,13 +63,13 @@ public function test_reciprocal_meta() { $this->assertEquals( $this->author, get_post_meta( $this->post->ID, 'test_reciprocal', true ) ); $this->assertEquals( $this->post->ID, get_user_meta( $this->author, 'reciprocal_post', true ) ); } - + /** * Test that various store properties work */ public function test_store_properties() { $user = get_userdata( $this->author ); - + $store_id = new Fieldmanager_Autocomplete( array( 'name' => 'test_store_id', 'datasource' => new Fieldmanager_Datasource_User( array( @@ -79,7 +79,7 @@ public function test_store_properties() { $this->save_values( $store_id, $this->post, $user->ID ); $this->assertEquals( $user->ID, get_post_meta( $this->post->ID, 'test_store_id', true ) ); - + $store_user_login = new Fieldmanager_Autocomplete( array( 'name' => 'test_store_user_login', 'datasource' => new Fieldmanager_Datasource_User( array( @@ -89,7 +89,7 @@ public function test_store_properties() { $this->save_values( $store_user_login, $this->post, $user->user_login ); $this->assertEquals( $user->user_login, get_post_meta( $this->post->ID, 'test_store_user_login', true ) ); - + $store_user_email = new Fieldmanager_Autocomplete( array( 'name' => 'test_store_user_email', 'datasource' => new Fieldmanager_Datasource_User( array( @@ -99,7 +99,7 @@ public function test_store_properties() { $this->save_values( $store_user_email, $this->post, $user->user_email ); $this->assertEquals( $user->user_email, get_post_meta( $this->post->ID, 'test_store_user_email', true ) ); - + $store_user_nicename = new Fieldmanager_Autocomplete( array( 'name' => 'test_store_user_nicename', 'datasource' => new Fieldmanager_Datasource_User( array( @@ -110,7 +110,7 @@ public function test_store_properties() { $this->save_values( $store_user_nicename, $this->post, $user->user_nicename ); $this->assertEquals( $user->user_nicename, get_post_meta( $this->post->ID, 'test_store_user_nicename', true ) ); } - + /** * Test creating a field with an invalid store property. * @expectedException FM_Developer_Exception @@ -125,7 +125,7 @@ public function test_save_invalid_store_property() { $this->save_values( $test_invalid, $this->post, $this->author ); } - + /** * Test creating a field with an invalid display property. * @expectedException FM_Developer_Exception @@ -140,7 +140,7 @@ public function test_save_invalid_display_property() { $this->save_values( $test_invalid, $this->post, $this->author ); } - + /** * Test that we fail when trying to use reciprocals with something other than ID as a store property. * @expectedException FM_Developer_Exception @@ -156,32 +156,32 @@ public function test_save_invalid_reciprocal() { $this->save_values( $test_invalid, $this->post, $this->author ); } - + /** * Test that this fails when a user doesn't have permission to list users. * @expectedException WPDieException */ public function test_save_permissions() { wp_set_current_user( $this->author ); - + $test_invalid = new Fieldmanager_Autocomplete( array( 'name' => 'test_invalid', 'datasource' => new Fieldmanager_Datasource_User(), ) ); - + $this->save_values( $test_invalid, $this->post, $this->editor ); - + wp_set_current_user( $this->author ); $this->save_values( $test_invalid, $this->post, $this->editor ); } - + /** * Test that display property returns the correct value in all reasonable cases. */ public function test_display_properties() { $user = get_userdata( $this->author ); - + $test_display_name = new Fieldmanager_Autocomplete( array( 'name' => 'test_display_name', 'datasource' => new Fieldmanager_Datasource_User( array( @@ -191,7 +191,7 @@ public function test_display_properties() { $test_users_display_name = $test_display_name->datasource->get_items( $user->user_login ); $this->assertEquals( $user->display_name, $test_users_display_name[ $user->ID ] ); - + $test_user_login = new Fieldmanager_Autocomplete( array( 'name' => 'test_user_login', 'datasource' => new Fieldmanager_Datasource_User( array( @@ -201,7 +201,7 @@ public function test_display_properties() { $test_users_user_login = $test_user_login->datasource->get_items( $user->user_login ); $this->assertEquals( $user->user_login, $test_users_user_login[ $user->ID ] ); - + $test_user_email = new Fieldmanager_Autocomplete( array( 'name' => 'test_user_email', 'datasource' => new Fieldmanager_Datasource_User( array( @@ -211,7 +211,7 @@ public function test_display_properties() { $test_users_user_email = $test_user_email->datasource->get_items( $user->user_login ); $this->assertEquals( $user->user_email, $test_users_user_email[ $user->ID ] ); - + $test_user_nicename = new Fieldmanager_Autocomplete( array( 'name' => 'test_user_nicename', 'datasource' => new Fieldmanager_Datasource_User( array( @@ -222,13 +222,13 @@ public function test_display_properties() { $test_users_user_nicename = $test_user_nicename->datasource->get_items( $user->user_login ); $this->assertEquals( $user->user_nicename, $test_users_user_nicename[ $user->ID ] ); } - + /** * Test that store property returns the correct display value in all reasonable cases. */ public function test_store_property_display() { $user = get_userdata( $this->author ); - + $test_id = new Fieldmanager_Autocomplete( array( 'name' => 'test_display_name', 'datasource' => new Fieldmanager_Datasource_User( array( @@ -239,7 +239,7 @@ public function test_store_property_display() { $test_users_id = $test_id->datasource->get_items( $user->user_login ); $this->assertEquals( $user->display_name, $test_users_id[ $user->ID ] ); $this->assertEquals( $user->display_name, $test_id->datasource->get_value( $user->ID ) ); - + $test_user_login = new Fieldmanager_Autocomplete( array( 'name' => 'test_user_login', 'datasource' => new Fieldmanager_Datasource_User( array( @@ -250,7 +250,7 @@ public function test_store_property_display() { $test_users_user_login = $test_user_login->datasource->get_items( $user->user_login ); $this->assertEquals( $user->display_name, $test_users_user_login[ $user->user_login ] ); $this->assertEquals( $user->display_name, $test_user_login->datasource->get_value( $user->user_login ) ); - + $test_user_email = new Fieldmanager_Autocomplete( array( 'name' => 'test_user_email', 'datasource' => new Fieldmanager_Datasource_User( array( @@ -261,7 +261,7 @@ public function test_store_property_display() { $test_users_user_email = $test_user_email->datasource->get_items( $user->user_login ); $this->assertEquals( $user->display_name, $test_users_user_email[ $user->user_email ] ); $this->assertEquals( $user->display_name, $test_user_email->datasource->get_value( $user->user_email ) ); - + $test_user_nicename = new Fieldmanager_Autocomplete( array( 'name' => 'test_user_nicename', 'datasource' => new Fieldmanager_Datasource_User( array(