Skip to content

Commit

Permalink
Merge pull request alleyinteractive#467 from alleyinteractive/post-pa…
Browse files Browse the repository at this point in the history
…rent-bugs

Address several bugs with save_to_post_parent
  • Loading branch information
mboynes committed Feb 21, 2016
2 parents 9614022 + 2065fce commit 6c46203
Show file tree
Hide file tree
Showing 6 changed files with 198 additions and 23 deletions.
3 changes: 3 additions & 0 deletions php/class-fieldmanager-autocomplete.php
Expand Up @@ -153,7 +153,10 @@ public function presave_alter_values( $values, $current_values = array() ) {

if ( ! empty( $this->datasource->only_save_to_taxonomy ) ) {
$this->skip_save = true;
} elseif ( ! empty( $this->datasource->only_save_to_post_parent ) ) {
$this->skip_save = true;
}

return $this->datasource->presave_alter_values( $this, $values, $current_values );
}

Expand Down
8 changes: 8 additions & 0 deletions php/class-fieldmanager-field.php
Expand Up @@ -337,6 +337,14 @@ public function form_element( $value ) {
*/
public function __construct( $label = '', $options = array() ) {
$this->set_options( $label, $options );

// A post can only have one parent, so if this saves to post_parent and
// it's repeatable, we're doing it wrong.
if ( $this->datasource && ! empty( $this->datasource->save_to_post_parent ) && $this->is_repeatable() ) {
_doing_it_wrong( 'Fieldmanager_Datasource_Post::$save_to_post_parent', __( 'A post can only have one parent, therefore you cannot store to post_parent in repeatable fields.', 'fieldmanager' ), '1.0.0' );
$this->datasource->save_to_post_parent = false;
$this->datasource->only_save_to_post_parent = false;
}
}

/**
Expand Down
10 changes: 9 additions & 1 deletion php/class-fieldmanager-group.php
Expand Up @@ -148,6 +148,14 @@ public function __construct( $label = '', $options = array() ) {
throw new FM_Developer_Exception( esc_html__( 'You cannot use `serialize_data => false` with `index => true`', 'fieldmanager' ) );
}

// A post can only have one parent, so if this saves to post_parent and
// it's repeatable, we're doing it wrong.
if ( $element->datasource && ! empty( $element->datasource->save_to_post_parent ) && $this->is_repeatable() ) {
_doing_it_wrong( 'Fieldmanager_Datasource_Post::$save_to_post_parent', __( 'A post can only have one parent, therefore you cannot store to post_parent in repeatable fields.', 'fieldmanager' ), '1.0.0' );
$element->datasource->save_to_post_parent = false;
$element->datasource->only_save_to_post_parent = false;
}

// Flag this group as having unserialized descendants to check invalid use of repeatables
if ( ! $this->has_unserialized_descendants && ( ! $element->serialize_data || ( $element->is_group() && $element->has_unserialized_descendants ) ) ) {
$this->has_unserialized_descendants = true;
Expand Down Expand Up @@ -325,7 +333,7 @@ public function presave( $values, $current_values = array() ) {
elseif ( empty( $values[ $element->name ] ) ) unset( $values[ $element->name ] );
}

if ( ! empty( $element->datasource->only_save_to_taxonomy ) ) {
if ( ! empty( $element->datasource->only_save_to_taxonomy ) || ! empty( $element->datasource->only_save_to_post_parent ) ) {
unset( $values[ $element->name ] );
continue;
}
Expand Down
2 changes: 2 additions & 0 deletions php/class-fieldmanager-options.php
Expand Up @@ -239,6 +239,8 @@ public function presave_alter_values( $values, $current_values = array() ) {
if ( !empty( $this->datasource ) ) {
if ( ! empty( $this->datasource->only_save_to_taxonomy ) ) {
$this->skip_save = true;
} elseif ( ! empty( $this->datasource->only_save_to_post_parent ) ) {
$this->skip_save = true;
}
return $this->datasource->presave_alter_values( $this, $values, $current_values );
}
Expand Down
15 changes: 12 additions & 3 deletions php/datasource/class-fieldmanager-datasource-post.php
Expand Up @@ -67,8 +67,14 @@ class Fieldmanager_Datasource_Post extends Fieldmanager_Datasource {
*/
public $only_save_to_post_parent = False;

// constructor not required for this datasource; options are just set to keys,
// which Fieldmanager_Datasource does.
public function __construct( $options = array() ) {
parent::__construct( $options );

// Infer $save_to_post_parent if $only_save_to_post_parent
if ( $this->only_save_to_post_parent ) {
$this->save_to_post_parent = true;
}
}

/**
* Get a post title by post ID
Expand Down Expand Up @@ -263,7 +269,10 @@ public function presave_status_transition( Fieldmanager_Field $field, $value ) {
*/
public function preload_alter_values( Fieldmanager_Field $field, $values ) {
if ( $this->only_save_to_post_parent ) {
return array( wp_get_post_parent_id( $field->data_id ) );
$post_parent = wp_get_post_parent_id( $field->data_id );
if ( $post_parent ) {
return ( 1 == $field->limit && empty( $field->multiple ) ) ? $post_parent : array( $post_parent );
}
}
return $values;
}
Expand Down
183 changes: 164 additions & 19 deletions tests/php/test-fieldmanager-datasource-post.php
Expand Up @@ -39,6 +39,24 @@ public function setUp() {
) );
}

/**
* Helper which returns the post meta box HTML for a given field;
*
* @param object $field Some Fieldmanager_Field object.
* @param object $post A WP_Post object.
* @param array $test_data Data to save (and use when rendering)
* @return string Rendered HTML
*/
private function _get_html_for( $field, $post, $test_data = null ) {
ob_start();
$context = $field->add_meta_box( 'test meta box', $post );
if ( $test_data ) {
$context->save_to_post_meta( $post->ID, $test_data );
}
$context->render_meta_box( $post );
return ob_get_clean();
}

/**
* Set up the request environment values and save the data.
*
Expand Down Expand Up @@ -242,8 +260,8 @@ public function test_alter_child_invalid_publish() {
* Test save_to_post_parent logic
*/
public function test_post_parent() {
$test_data = $this->child_post_a->ID;
$children = new Fieldmanager_Autocomplete( array(
$test_data = $this->parent_post->ID;
$fm = new Fieldmanager_Autocomplete( array(
'name' => 'test_parent',
'datasource' => new Fieldmanager_Datasource_Post( array(
'query_args' => array(
Expand All @@ -252,18 +270,24 @@ public function test_post_parent() {
'save_to_post_parent' => true,
) ),
) );
$this->save_values( $children, $this->parent_post, $test_data );
$parent = get_post( $this->parent_post->ID );
$this->assertEquals( $parent->post_parent, $this->child_post_a->ID );
$this->assertEquals( get_post_meta( $this->parent_post->ID, 'test_parent', true ), $this->child_post_a->ID );
$html = $this->_get_html_for( $fm, $this->child_post_a );
$this->assertContains( '<input class="fm-autocomplete-hidden fm-element" type="hidden" name="test_parent" value="" />', $html );
$html = $this->_get_html_for( $fm, $this->child_post_a, $test_data );
// Reload the post
$this->child_post_a = get_post( $this->child_post_a->ID );
$this->assertEquals( $test_data, $this->child_post_a->post_parent );
$this->assertEquals( $test_data, get_post_meta( $this->child_post_a->ID, 'test_parent', true ) );
$this->assertContains(
sprintf( '<input class="fm-autocomplete-hidden fm-element" type="hidden" name="test_parent" value="%d" />', $test_data ),
$html
);
}

/**
* Test save_to_post_parent logic
*/
public function test_post_parent_nested() {
$test_data = array( 'parent' => $this->child_post_a->ID );
$children = new Fieldmanager_Group( array(
$test_data = array( 'parent' => $this->parent_post->ID );
$fm = new Fieldmanager_Group( array(
'name' => 'test_parent',
'children' => array(
'parent' => new Fieldmanager_Autocomplete( 'Post Parent', array(
Expand All @@ -277,17 +301,24 @@ public function test_post_parent_nested() {
) ),
),
) );
$this->save_values( $children, $this->parent_post, $test_data );
$parent = get_post( $this->parent_post->ID );
$this->assertEquals( $parent->post_parent, $this->child_post_a->ID );
$html = $this->_get_html_for( $fm, $this->child_post_a );
$this->assertContains( '<input class="fm-autocomplete-hidden fm-element" type="hidden" name="test_parent[parent]" value="" />', $html );
$html = $this->_get_html_for( $fm, $this->child_post_a, $test_data );
// Reload the post
$this->child_post_a = get_post( $this->child_post_a->ID );
$this->assertEquals( $this->parent_post->ID, $this->child_post_a->post_parent );
$this->assertEquals( '', get_post_meta( $this->child_post_a->ID, 'test_parent', true ) );
$this->assertContains(
sprintf( '<input class="fm-autocomplete-hidden fm-element" type="hidden" name="test_parent[parent]" value="%d" />', $this->parent_post->ID ),
$html
);
}

/**
* Test save_to_post_parent_only logic
*/
public function test_post_parent_only() {
$test_data = $this->child_post_a->ID;
$children = new Fieldmanager_Autocomplete( array(
$test_data = $this->parent_post->ID;
$fm = new Fieldmanager_Autocomplete( array(
'name' => 'test_parent',
'datasource' => new Fieldmanager_Datasource_Post( array(
'query_args' => array(
Expand All @@ -297,10 +328,17 @@ public function test_post_parent_only() {
'only_save_to_post_parent' => true,
) ),
) );
$this->save_values( $children, $this->parent_post, $test_data );
$parent = get_post( $this->parent_post->ID );
$this->assertEquals( $parent->post_parent, $this->child_post_a->ID );
$this->assertEmpty( get_post_meta( $this->parent_post->ID, 'test_parent', true ) );
$html = $this->_get_html_for( $fm, $this->child_post_a );
$this->assertContains( '<input class="fm-autocomplete-hidden fm-element" type="hidden" name="test_parent" value="" />', $html );
$html = $this->_get_html_for( $fm, $this->child_post_a, $test_data );
// Reload the post
$this->child_post_a = get_post( $this->child_post_a->ID );
$this->assertEquals( $test_data, $this->child_post_a->post_parent );
$this->assertEquals( '', get_post_meta( $this->child_post_a->ID, 'test_parent', true ) );
$this->assertContains(
sprintf( '<input class="fm-autocomplete-hidden fm-element" type="hidden" name="test_parent" value="%d" />', $test_data ),
$html
);
}

/**
Expand All @@ -326,4 +364,111 @@ public function test_alter_child_invalid_reciprocal() {

$this->save_values( $children, $this->parent_post, $test_data );
}

public function test_post_parent_render() {
$fm = new Fieldmanager_Autocomplete( array(
'name' => 'test_parent',
'datasource' => new Fieldmanager_Datasource_Post( array(
'only_save_to_post_parent' => true,
'query_args' => array(
'post_type' => 'post'
),
) ),
) );

ob_start();
$fm->add_meta_box( 'Test Autocomplete', 'post' )->render_meta_box( $this->child_post_a, array() );
$html = ob_get_clean();
$this->assertRegExp( '/<input[^>]+type=[\'"]hidden[\'"][^>]+value=[\'"]{2}/', $html );

$this->save_values( $fm, $this->child_post_a, $this->parent_post->ID );
$child = get_post( $this->child_post_a->ID );
$this->assertEquals( $this->parent_post->ID, $child->post_parent );
$this->assertEquals( '', get_post_meta( $this->child_post_a->ID, 'test_parent', true ) );

ob_start();
$fm->add_meta_box( 'Test Autocomplete', 'post' )->render_meta_box( $this->child_post_a, array() );
$html = ob_get_clean();
$this->assertRegExp( "/<input[^>]+type=['\"]hidden['\"][^>]+value=['\"]{$this->parent_post->ID}['\"]/", $html );
}

public function test_options_post_parent_render() {
$fm = new Fieldmanager_Select( array(
'name' => 'test_parent',
'datasource' => new Fieldmanager_Datasource_Post( array(
'only_save_to_post_parent' => true,
'query_args' => array(
'post_type' => 'post',
'post_status' => 'draft',
),
) ),
) );

ob_start();
$fm->add_meta_box( 'Test Select', 'post' )->render_meta_box( $this->child_post_a, array() );
$html = ob_get_clean();
$this->assertRegExp(
sprintf( '#<option\s*value="%s"\s*>%s</option>#i', $this->parent_post->ID, $this->parent_post->post_title ),
$html
);

$this->save_values( $fm, $this->child_post_a, $this->parent_post->ID );
$child = get_post( $this->child_post_a->ID );
$this->assertEquals( $this->parent_post->ID, $child->post_parent );
$this->assertEquals( '', get_post_meta( $this->child_post_a->ID, 'test_parent', true ) );

ob_start();
$fm->add_meta_box( 'Test Select', 'post' )->render_meta_box( $this->child_post_a, array() );
$html = ob_get_clean();
$this->assertRegExp(
sprintf( '#<option\s*value="%s"\s*selected(?:\s*=\s*"selected")?\s*>%s</option>#i', $this->parent_post->ID, $this->parent_post->post_title ),
$html
);
}

/**
* @expectedIncorrectUsage Fieldmanager_Datasource_Post::$save_to_post_parent
*/
public function test_repeatable_post_parent_invalid() {
$fm = new Fieldmanager_Autocomplete( array(
'name' => 'test_limitless_datasource',
'limit' => 0,
'datasource' => new Fieldmanager_Datasource_Post( array(
'only_save_to_post_parent' => true,
'query_args' => array( 'post_type' => 'post' ),
) ),
) );
}

/**
* @expectedIncorrectUsage Fieldmanager_Datasource_Post::$save_to_post_parent
*/
public function test_repeatable_options_post_parent_invalid() {
$fm = new Fieldmanager_Select( array(
'name' => 'test_limitless_datasource',
'limit' => 0,
'datasource' => new Fieldmanager_Datasource_Post( array(
'only_save_to_post_parent' => true,
'query_args' => array( 'post_type' => 'post' ),
) ),
) );
}

/**
* @expectedIncorrectUsage Fieldmanager_Datasource_Post::$save_to_post_parent
*/
public function test_inherited_repeatable_post_parent_invalid() {
$fm = new Fieldmanager_Group( array(
'name' => 'test_limitless_datasource',
'limit' => 0,
'children' => array(
'field' => new Fieldmanager_Autocomplete( array(
'datasource' => new Fieldmanager_Datasource_Post( array(
'only_save_to_post_parent' => true,
'query_args' => array( 'post_type' => 'post' ),
) ),
) ),
),
) );
}
}

0 comments on commit 6c46203

Please sign in to comment.