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

Fix post field partial from erroneously selecting nested post placements #355

Merged
merged 5 commits into from
Jul 28, 2017
Merged
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
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
dist: precise
sudo: false

notifications:
Expand Down
17 changes: 17 additions & 0 deletions js/customize-deferred-partial.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,23 @@
}
},

/**
* Create and show the edit shortcut for a given partial placement container.
*
* Prevent multiple edit shortcuts from being created on the same placement.
* This should probably be upstreamed to core.
*
* @param {Placement} placement The placement container element.
* @returns {void}
*/
createEditShortcutForPlacement: function( placement ) {
var partial = this;
if ( placement.container && placement.container.find( '> .customize-partial-edit-shortcut-button:first-child' ).length ) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The selector here wasn't right. Fixed in #356.

return;
}
api.selectiveRefresh.Partial.prototype.createEditShortcutForPlacement.call( partial, placement );
},

/**
* Request the new partial and render it into the placements.
*
Expand Down
20 changes: 20 additions & 0 deletions js/customize-post-field-partial.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,26 @@
api.preview.send( 'focus-control', settingId + '[' + partial.params.field_id + ']' );
},

/**
* Find all placements for this partial in the document.
*
* Fixes issue where selector can match too many elements when post loops are nested inside other posts.
*
* @return {Array.<Placement>} Placements.
*/
placements: function() {
var partial = this, placements;
placements = api.selectiveRefresh.partialConstructor.deferred.prototype.placements.call( this );

// Remove all placements whose closest .hentry is not for this post.
placements = _.filter( placements, function( placement ) {
var closestHentry = placement.container.closest( '.hentry' );
return ! closestHentry.length || closestHentry.hasClass( 'post-' + String( partial.params.post_id ) );
});

return placements;
},

/**
* @inheritdoc
*/
Expand Down
69 changes: 69 additions & 0 deletions js/customize-preview-posts.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,75 @@
}
} );

/**
* Parse the class name for an .hentry element, that is for an element that uses post_class().
*
* @param {string} className Class name.
* @returns {object|null} Object with postType and postId props, or null if no matches.
*/
api.previewPosts.parsePostClassName = function parsePostClassName( className ) {
var matches, postId, postType;
matches = className.match( /(\s|^)post-(\d+)(\s|$)/ );
if ( matches ) {
postId = parseInt( matches[2], 10 );
} else {
return null;
}
matches = className.match( /(\s|^)type-(\S+)(\s|$)/ );
if ( matches ) {
postType = matches[2];
} else {
return null;
}
return {
postId: postId,
postType: postType
};
};

// Add partials when the document is modified and new post hentry elements are added.
if ( 'undefined' !== typeof MutationObserver ) {
api.previewPosts.mutationObserver = new MutationObserver( function( mutations ) {
_.each( mutations, function( mutation ) {
var hentryElements, mutationTarget;
mutationTarget = $( mutation.target );
hentryElements = mutationTarget.find( '.hentry' );
if ( mutationTarget.is( '.hentry' ) ) {
hentryElements = hentryElements.add( mutationTarget );
}

hentryElements.each( function() {
var postInfo, settingId;
postInfo = api.previewPosts.parsePostClassName( $( this ).prop( 'className' ) );
if ( ! postInfo ) {
return;
}
settingId = 'post[' + postInfo.postType + '][' + String( postInfo.postId ) + ']';
api.previewPosts.ensurePartialsForPostSetting( settingId );

// Ensure edit shortcuts are added for all placements inside the mutation target.
_.each( api.previewPosts.partialSchema( settingId ), function( schema ) {
var partial;
partial = api.selectiveRefresh.partial( schema.id );
if ( ! partial ) {
return;
}
_.each( partial.placements(), function( placement ) { // eslint-disable-line max-nested-callbacks
if ( mutationTarget.is( placement.container ) || $.contains( mutation.target, placement.container[0] ) ) {
$( placement.container ).attr( 'title', api.selectiveRefresh.data.l10n.shiftClickToEdit );
partial.createEditShortcutForPlacement( placement );
}
});
});
});
});
});
api.previewPosts.mutationObserver.observe( document.documentElement, {
childList: true,
subtree: true
});
}

/**
* Ensure that each post setting is added and has corresponding partials.
*
Expand Down
10 changes: 10 additions & 0 deletions php/class-wp-customize-posts-preview.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ public function customize_preview_init() {
add_filter( 'customize_dynamic_partial_args', array( $this, 'filter_customize_dynamic_partial_args' ), 10, 2 );
add_filter( 'customize_dynamic_partial_class', array( $this, 'filter_customize_dynamic_partial_class' ), 10, 3 );
add_filter( 'the_posts', array( $this, 'filter_the_posts_to_tally_previewed_posts' ), 1000 );
add_action( 'the_post', array( $this, 'handle_the_post_to_tally_previewed_post' ) );
add_filter( 'the_posts', array( $this, 'filter_the_posts_to_tally_orderby_keys' ), 10, 2 );
add_action( 'wp_footer', array( $this, 'export_preview_data' ), 10 );
add_filter( 'get_edit_post_link', array( $this, 'filter_get_edit_post_link' ), 10, 2 );
Expand Down Expand Up @@ -250,6 +251,15 @@ public function filter_the_posts_to_tally_previewed_posts( array $posts ) {
return $posts;
}

/**
* Tally the set-up post as being previewed in the page.
*
* @param WP_Post $post Post.
*/
public function handle_the_post_to_tally_previewed_post( $post ) {
$this->queried_post_ids[] = $post->ID;
}

/**
* Override post data for previewed settings.
*
Expand Down
14 changes: 14 additions & 0 deletions tests/php/test-class-wp-customize-posts-preview.php
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ public function test_customize_preview_init() {
$this->assertEquals( 10, has_filter( 'customize_dynamic_partial_args', array( $preview, 'filter_customize_dynamic_partial_args' ) ) );
$this->assertEquals( 10, has_filter( 'customize_dynamic_partial_class', array( $preview, 'filter_customize_dynamic_partial_class' ) ) );
$this->assertEquals( 1000, has_filter( 'the_posts', array( $preview, 'filter_the_posts_to_tally_previewed_posts' ) ) );
$this->assertEquals( 10, has_action( 'the_post', array( $preview, 'handle_the_post_to_tally_previewed_post' ) ) );
$this->assertEquals( 10, has_filter( 'the_posts', array( $preview, 'filter_the_posts_to_tally_orderby_keys' ) ) );
$this->assertEquals( 10, has_action( 'wp_footer', array( $preview, 'export_preview_data' ) ) );
$this->assertEquals( 10, has_filter( 'get_edit_post_link', array( $preview, 'filter_get_edit_post_link' ) ) );
Expand Down Expand Up @@ -277,6 +278,19 @@ public function test_filter_the_posts_to_tally_previewed_posts() {
$this->assertEqualSets( $post_ids, $this->posts_component->preview->queried_post_ids );
}

/**
* Test handle_the_post_to_tally_previewed_post().
*
* @covers WP_Customize_Posts_Preview::handle_the_post_to_tally_previewed_post()
*/
public function test_handle_the_post_to_tally_previewed_post() {
$post_id = $this->factory()->post->create();
$this->assertEmpty( $this->posts_component->preview->queried_post_ids );
$this->posts_component->preview->customize_preview_init();
setup_postdata( $post_id );
$this->assertEqualSets( array( $post_id ), $this->posts_component->preview->queried_post_ids );
}

/**
* Test filter_the_posts_to_preview_settings().
*
Expand Down